Index: trunk/phase3/skins/common/ajaxwatch.js |
— | — | @@ -2,17 +2,17 @@ |
3 | 3 | // * ajax.js: |
4 | 4 | /*extern sajax_init_object, sajax_do_call */ |
5 | 5 | // * wikibits.js: |
6 | | - /*extern changeText, akeytt, hookEvent */ |
| 6 | + /*extern changeText, akeytt, hookEvent, alertMsg */ |
7 | 7 | |
8 | 8 | // These should have been initialized in the generated js |
9 | | -/*extern wgAjaxWatch, wgArticleId */ |
| 9 | +/*extern wgAjaxWatch, wgPageName */ |
10 | 10 | |
11 | 11 | if(typeof wgAjaxWatch === "undefined" || !wgAjaxWatch) { |
12 | 12 | var wgAjaxWatch = { |
13 | 13 | watchMsg: "Watch", |
14 | 14 | unwatchMsg: "Unwatch", |
15 | 15 | watchingMsg: "Watching...", |
16 | | - unwatchingMsg: "Unwatching..." |
| 16 | + unwatchingMsg: "Unwatching...", |
17 | 17 | }; |
18 | 18 | } |
19 | 19 | |
— | — | @@ -20,32 +20,52 @@ |
21 | 21 | wgAjaxWatch.watching = false; // currently watching page |
22 | 22 | wgAjaxWatch.inprogress = false; // ajax request in progress |
23 | 23 | wgAjaxWatch.timeoutID = null; // see wgAjaxWatch.ajaxCall |
24 | | -wgAjaxWatch.watchLink1 = null; // "watch"/"unwatch" link |
25 | | -wgAjaxWatch.watchLink2 = null; // second one, for (some?) non-Monobook-based |
26 | | -wgAjaxWatch.oldHref = null; // url for action=watch/action=unwatch |
| 24 | +wgAjaxWatch.watchLinks = []; // "watch"/"unwatch" links |
27 | 25 | |
28 | 26 | wgAjaxWatch.setLinkText = function(newText) { |
29 | | - changeText(wgAjaxWatch.watchLink1, newText); |
30 | | - if (wgAjaxWatch.watchLink2) { |
31 | | - changeText(wgAjaxWatch.watchLink2, newText); |
| 27 | + for (i = 0; i < wgAjaxWatch.watchLinks.length; i++) { |
| 28 | + changeText(wgAjaxWatch.watchLinks[i], newText); |
32 | 29 | } |
33 | 30 | }; |
34 | 31 | |
35 | 32 | wgAjaxWatch.setLinkID = function(newId) { |
36 | | - wgAjaxWatch.watchLink1.id = newId; |
| 33 | + // We can only set the first one |
| 34 | + wgAjaxWatch.watchLinks[0].setAttribute( 'id', newId ); |
37 | 35 | akeytt(newId); // update tooltips for Monobook |
38 | 36 | }; |
39 | 37 | |
| 38 | +wgAjaxWatch.setHref = function( string ) { |
| 39 | + for( i = 0; i < wgAjaxWatch.watchLinks.length; i++ ) { |
| 40 | + if( string == 'watch' ) { |
| 41 | + wgAjaxWatch.watchLinks[i].href = wgAjaxWatch.watchLinks[i].href |
| 42 | + .replace( /&action=unwatch/, '&action=watch' ); |
| 43 | + } else if( string == 'unwatch' ) { |
| 44 | + wgAjaxWatch.watchLinks[i].href = wgAjaxWatch.watchLinks[i].href |
| 45 | + .replace( /&action=watch/, '&action=unwatch' ); |
| 46 | + } |
| 47 | + } |
| 48 | +} |
| 49 | + |
40 | 50 | wgAjaxWatch.ajaxCall = function() { |
41 | | - if(!wgAjaxWatch.supported || wgAjaxWatch.inprogress) { |
42 | | - return; |
| 51 | + if(!wgAjaxWatch.supported) { |
| 52 | + return true; |
| 53 | + } else if (wgAjaxWatch.inprogress) { |
| 54 | + return false; |
43 | 55 | } |
44 | 56 | wgAjaxWatch.inprogress = true; |
45 | | - wgAjaxWatch.setLinkText(wgAjaxWatch.watching ? wgAjaxWatch.unwatchingMsg : wgAjaxWatch.watchingMsg); |
46 | | - sajax_do_call("wfAjaxWatch", [wgArticleId, (wgAjaxWatch.watching ? "u" : "w")], wgAjaxWatch.processResult); |
| 57 | + wgAjaxWatch.setLinkText( wgAjaxWatch.watching |
| 58 | + ? wgAjaxWatch.unwatchingMsg : wgAjaxWatch.watchingMsg); |
| 59 | + sajax_do_call( |
| 60 | + "wfAjaxWatch", |
| 61 | + [wgPageName, (wgAjaxWatch.watching ? "u" : "w")], |
| 62 | + wgAjaxWatch.processResult |
| 63 | + ); |
47 | 64 | // if the request isn't done in 10 seconds, allow user to try again |
48 | | - wgAjaxWatch.timeoutID = window.setTimeout(function() { wgAjaxWatch.inprogress = false; }, 10000); |
49 | | - return; |
| 65 | + wgAjaxWatch.timeoutID = window.setTimeout( |
| 66 | + function() { wgAjaxWatch.inprogress = false; }, |
| 67 | + 10000 |
| 68 | + ); |
| 69 | + return false; |
50 | 70 | }; |
51 | 71 | |
52 | 72 | wgAjaxWatch.processResult = function(request) { |
— | — | @@ -53,20 +73,21 @@ |
54 | 74 | return; |
55 | 75 | } |
56 | 76 | var response = request.responseText; |
57 | | - if(response == "<err#>") { |
58 | | - window.location.href = wgAjaxWatch.oldHref; |
| 77 | + if( response.match(/^<err#>/) ) { |
| 78 | + window.location.href = wgAjaxWatch.watchLink1.href; |
59 | 79 | return; |
60 | | - } else if(response == "<w#>") { |
| 80 | + } else if( response.match(/^<w#>/) ) { |
61 | 81 | wgAjaxWatch.watching = true; |
62 | 82 | wgAjaxWatch.setLinkText(wgAjaxWatch.unwatchMsg); |
63 | 83 | wgAjaxWatch.setLinkID("ca-unwatch"); |
64 | | - wgAjaxWatch.oldHref = wgAjaxWatch.oldHref.replace(/action=watch/, "action=unwatch"); |
65 | | - } else if(response == "<u#>") { |
| 84 | + wgAjaxWatch.setHref( 'unwatch' ); |
| 85 | + } else if( response.match(/^<u#>/) ) { |
66 | 86 | wgAjaxWatch.watching = false; |
67 | 87 | wgAjaxWatch.setLinkText(wgAjaxWatch.watchMsg); |
68 | 88 | wgAjaxWatch.setLinkID("ca-watch"); |
69 | | - wgAjaxWatch.oldHref = wgAjaxWatch.oldHref.replace(/action=unwatch/, "action=watch"); |
| 89 | + wgAjaxWatch.setHref( 'watch' ); |
70 | 90 | } |
| 91 | + jsMsg( response.substr(4), 'watch' ); |
71 | 92 | wgAjaxWatch.inprogress = false; |
72 | 93 | if(wgAjaxWatch.timeoutID) { |
73 | 94 | window.clearTimeout(wgAjaxWatch.timeoutID); |
— | — | @@ -75,6 +96,8 @@ |
76 | 97 | }; |
77 | 98 | |
78 | 99 | wgAjaxWatch.onLoad = function() { |
| 100 | + // This document structure hardcoding sucks. We should make a class and |
| 101 | + // toss all this out the window. |
79 | 102 | var el1 = document.getElementById("ca-unwatch"); |
80 | 103 | var el2 = null; |
81 | 104 | if (!el1) { |
— | — | @@ -103,14 +126,18 @@ |
104 | 127 | |
105 | 128 | // The id can be either for the parent (Monobook-based) or the element |
106 | 129 | // itself (non-Monobook) |
107 | | - wgAjaxWatch.watchLink1 = el1.tagName.toLowerCase() == "a" ? el1 : el1.firstChild; |
108 | | - wgAjaxWatch.watchLink2 = el2 ? el2 : null; |
| 130 | + wgAjaxWatch.watchLinks.push( el1.tagName.toLowerCase() == "a" |
| 131 | + ? el1 : el1.firstChild ); |
109 | 132 | |
110 | | - wgAjaxWatch.oldHref = wgAjaxWatch.watchLink1.getAttribute("href"); |
111 | | - wgAjaxWatch.watchLink1.setAttribute("href", "javascript:wgAjaxWatch.ajaxCall()"); |
112 | | - if (wgAjaxWatch.watchLink2) { |
113 | | - wgAjaxWatch.watchLink2.setAttribute("href", "javascript:wgAjaxWatch.ajaxCall()"); |
| 133 | + if( el2 ) { |
| 134 | + wgAjaxWatch.watchLinks.push( el2 ); |
114 | 135 | } |
| 136 | + |
| 137 | + // I couldn't get for (watchLink in wgAjaxWatch.watchLinks) to work, if |
| 138 | + // you can be my guest. |
| 139 | + for( i = 0; i < wgAjaxWatch.watchLinks.length; i++ ) { |
| 140 | + wgAjaxWatch.watchLinks[i].onclick = wgAjaxWatch.ajaxCall; |
| 141 | + } |
115 | 142 | return; |
116 | 143 | }; |
117 | 144 | |
— | — | @@ -124,4 +151,4 @@ |
125 | 152 | var supportsAjax = request ? true : false; |
126 | 153 | delete request; |
127 | 154 | return supportsAjax; |
128 | | -} |
\ No newline at end of file |
| 155 | +} |
Index: trunk/phase3/skins/common/shared.css |
— | — | @@ -6,4 +6,5 @@ |
7 | 7 | .mw-plusminus-null { color: #aaa; } |
8 | 8 | .texvc { direction: ltr; unicode-bidi: embed; } |
9 | 9 | /* Stop floats from intruding into edit area in previews */ |
10 | | -#toolbar, #wpTextbox1 { clear: both; } |
\ No newline at end of file |
| 10 | +#toolbar, #wpTextbox1 { clear: both; } |
| 11 | +div#mw-js-message { margin: 2em 5%; } |
Index: trunk/phase3/skins/common/wikibits.js |
— | — | @@ -604,8 +604,7 @@ |
605 | 605 | // the original. |
606 | 606 | var ta; |
607 | 607 | if ( doId ) { |
608 | | - ta = new Array; |
609 | | - ta[doId] = window.ta[doId]; |
| 608 | + ta = [doId]; |
610 | 609 | } else { |
611 | 610 | ta = window.ta; |
612 | 611 | } |
— | — | @@ -1214,6 +1213,53 @@ |
1215 | 1214 | * End of table sorting code |
1216 | 1215 | */ |
1217 | 1216 | |
| 1217 | + |
| 1218 | +/** |
| 1219 | + * Add a cute little box at the top of the screen to inform the user of |
| 1220 | + * something, replacing any preexisting message. |
| 1221 | + * |
| 1222 | + * @param String message HTML to be put inside the right div |
| 1223 | + * @param String class Used in adding a class; should be different for each |
| 1224 | + * call to allow CSS/JS to hide different boxes. null = no class used. |
| 1225 | + * @return Boolean True on success, false on failure |
| 1226 | + */ |
| 1227 | +function jsMsg( message, class ) { |
| 1228 | + if ( !document.getElementById ) { |
| 1229 | + return false; |
| 1230 | + } |
| 1231 | + // We special-case skin structures provided by the software. Skins that |
| 1232 | + // choose to abandon or significantly modify our formatting can just define |
| 1233 | + // an mw-js-message div to start with. |
| 1234 | + var messageDiv = document.getElementById( 'mw-js-message' ); |
| 1235 | + if ( !messageDiv ) { |
| 1236 | + messageDiv = document.createElement( 'div' ); |
| 1237 | + if ( document.getElementById( 'column-content' ) |
| 1238 | + && document.getElementById( 'content' ) ) { |
| 1239 | + // MonoBook, presumably |
| 1240 | + document.getElementById( 'content' ).insertBefore( |
| 1241 | + messageDiv, |
| 1242 | + document.getElementById( 'content' ).firstChild |
| 1243 | + ); |
| 1244 | + } else if ( document.getElementById('content') |
| 1245 | + && document.getElementById( 'article' ) ) { |
| 1246 | + // Non-Monobook but still recognizable (old-style) |
| 1247 | + document.getElementById( 'article').insertBefore( |
| 1248 | + messageDiv, |
| 1249 | + document.getElementById( 'article' ).firstChild |
| 1250 | + ); |
| 1251 | + } else { |
| 1252 | + return false; |
| 1253 | + } |
| 1254 | + } |
| 1255 | + |
| 1256 | + messageDiv.setAttribute( 'id', 'mw-js-message' ); |
| 1257 | + if( class ) { |
| 1258 | + messageDiv.setAttribute( 'class', 'mw-js-message-'+class ); |
| 1259 | + } |
| 1260 | + messageDiv.innerHTML = message; |
| 1261 | + return true; |
| 1262 | +} |
| 1263 | + |
1218 | 1264 | function runOnloadHook() { |
1219 | 1265 | // don't run anything below this for non-dom browsers |
1220 | 1266 | if (doneOnloadHook || !(document.getElementById && document.getElementsByTagName)) { |
— | — | @@ -1243,4 +1289,4 @@ |
1244 | 1290 | // so the below should be redundant. It's there just in case. |
1245 | 1291 | hookEvent("load", runOnloadHook); |
1246 | 1292 | |
1247 | | -hookEvent("load", mwSetupToolbar); |
\ No newline at end of file |
| 1293 | +hookEvent("load", mwSetupToolbar); |
Index: trunk/phase3/includes/AjaxFunctions.php |
— | — | @@ -136,22 +136,29 @@ |
137 | 137 | |
138 | 138 | /** |
139 | 139 | * Called for AJAX watch/unwatch requests. |
140 | | - * @param $pageID Integer ID of the page to be watched/unwatched |
| 140 | + * @param $pagename Prefixed title string for page to watch/unwatch |
141 | 141 | * @param $watch String 'w' to watch, 'u' to unwatch |
142 | | - * @return String '<w#>' or '<u#>' on successful watch or unwatch, respectively, or '<err#>' on error (invalid XML in case we want to add HTML sometime) |
| 142 | + * @return String '<w#>' or '<u#>' on successful watch or unwatch, |
| 143 | + * respectively, followed by an HTML message to display in the alert box; or |
| 144 | + * '<err#>' on error |
143 | 145 | */ |
144 | | -function wfAjaxWatch($pageID = "", $watch = "") { |
145 | | - if(wfReadOnly()) |
146 | | - return '<err#>'; // redirect to action=(un)watch, which will display the database lock message |
| 146 | +function wfAjaxWatch($pagename = "", $watch = "") { |
| 147 | + if(wfReadOnly()) { |
| 148 | + // redirect to action=(un)watch, which will display the database lock |
| 149 | + // message |
| 150 | + return '<err#>'; |
| 151 | + } |
147 | 152 | |
148 | | - if(('w' !== $watch && 'u' !== $watch) || !is_numeric($pageID)) |
| 153 | + if('w' !== $watch && 'u' !== $watch) { |
149 | 154 | return '<err#>'; |
| 155 | + } |
150 | 156 | $watch = 'w' === $watch; |
151 | | - $pageID = intval($pageID); |
152 | 157 | |
153 | | - $title = Title::newFromID($pageID); |
154 | | - if(!$title) |
| 158 | + $title = Title::newFromText($pagename); |
| 159 | + if(!$title) { |
| 160 | + // Invalid title |
155 | 161 | return '<err#>'; |
| 162 | + } |
156 | 163 | $article = new Article($title); |
157 | 164 | $watching = $title->userIsWatching(); |
158 | 165 | |
— | — | @@ -170,7 +177,10 @@ |
171 | 178 | $dbw->commit(); |
172 | 179 | } |
173 | 180 | } |
174 | | - |
175 | | - return $watch ? '<w#>' : '<u#>'; |
| 181 | + if( $watch ) { |
| 182 | + return '<w#>'.wfMsgExt( 'addedwatchtext', array( 'parse' ), $title->getPrefixedText() ); |
| 183 | + } else { |
| 184 | + return '<u#>'.wfMsgExt( 'removedwatchtext', array( 'parse' ), $title->getPrefixedText() ); |
| 185 | + } |
176 | 186 | } |
177 | 187 | ?> |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -2514,7 +2514,7 @@ |
2515 | 2515 | /** |
2516 | 2516 | * Enable AJAX framework |
2517 | 2517 | */ |
2518 | | -$wgUseAjax = false; |
| 2518 | +$wgUseAjax = true; |
2519 | 2519 | |
2520 | 2520 | /** |
2521 | 2521 | * Enable auto suggestion for the search bar |
— | — | @@ -2534,7 +2534,7 @@ |
2535 | 2535 | * Requires $wgUseAjax to be true too. |
2536 | 2536 | * Causes wfAjaxWatch to be added to $wgAjaxExportList |
2537 | 2537 | */ |
2538 | | -$wgAjaxWatch = false; |
| 2538 | +$wgAjaxWatch = true; |
2539 | 2539 | |
2540 | 2540 | /** |
2541 | 2541 | * Allow DISPLAYTITLE to change title display |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -97,6 +97,8 @@ |
98 | 98 | to cause hard-to-track-down interactions between extensions. |
99 | 99 | * Use $wgJobClasses to determine the correct Job to instantiate for a particular |
100 | 100 | queued task; allows extensions to introduce custom jobs |
| 101 | +* (bug 10326) AJAX-based page watching and unwatching has been cleaned up and |
| 102 | + enabled by default. |
101 | 103 | |
102 | 104 | == Bugfixes since 1.10 == |
103 | 105 | |