r23233 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r23232‎ | r23233 | r23234 >
Date:17:36, 22 June 2007
Author:simetrical
Status:old
Tags:
Comment:
Fix up AJAX watch and enable it by default.

* Allow it to work for nonexistent articles (pass title instead of ID)
* Use event handlers, not javascript: URLs
* Fix bug preventing akeytt from setting tooltips for a single element
* Add jsMsg() function to wikibits to allow messages to be displayed dynamically at the top of the screen (could use dismiss button?)

Some test-cases I've thrown at it worked fine (nonexistent pages, namespaced pages, pages with funny characters), but I haven't spent seven weeks in a cave meditating on what could possibly go wrong, so there may be some kind of omission somewhere.
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/includes/AjaxFunctions.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/skins/common/ajaxwatch.js (modified) (history)
  • /trunk/phase3/skins/common/shared.css (modified) (history)
  • /trunk/phase3/skins/common/wikibits.js (modified) (history)

Diff [purge]

Index: trunk/phase3/skins/common/ajaxwatch.js
@@ -2,17 +2,17 @@
33 // * ajax.js:
44 /*extern sajax_init_object, sajax_do_call */
55 // * wikibits.js:
6 - /*extern changeText, akeytt, hookEvent */
 6+ /*extern changeText, akeytt, hookEvent, alertMsg */
77
88 // These should have been initialized in the generated js
9 -/*extern wgAjaxWatch, wgArticleId */
 9+/*extern wgAjaxWatch, wgPageName */
1010
1111 if(typeof wgAjaxWatch === "undefined" || !wgAjaxWatch) {
1212 var wgAjaxWatch = {
1313 watchMsg: "Watch",
1414 unwatchMsg: "Unwatch",
1515 watchingMsg: "Watching...",
16 - unwatchingMsg: "Unwatching..."
 16+ unwatchingMsg: "Unwatching...",
1717 };
1818 }
1919
@@ -20,32 +20,52 @@
2121 wgAjaxWatch.watching = false; // currently watching page
2222 wgAjaxWatch.inprogress = false; // ajax request in progress
2323 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
2725
2826 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);
3229 }
3330 };
3431
3532 wgAjaxWatch.setLinkID = function(newId) {
36 - wgAjaxWatch.watchLink1.id = newId;
 33+ // We can only set the first one
 34+ wgAjaxWatch.watchLinks[0].setAttribute( 'id', newId );
3735 akeytt(newId); // update tooltips for Monobook
3836 };
3937
 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+
4050 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;
4355 }
4456 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+ );
4764 // 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;
5070 };
5171
5272 wgAjaxWatch.processResult = function(request) {
@@ -53,20 +73,21 @@
5474 return;
5575 }
5676 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;
5979 return;
60 - } else if(response == "<w#>") {
 80+ } else if( response.match(/^<w#>/) ) {
6181 wgAjaxWatch.watching = true;
6282 wgAjaxWatch.setLinkText(wgAjaxWatch.unwatchMsg);
6383 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#>/) ) {
6686 wgAjaxWatch.watching = false;
6787 wgAjaxWatch.setLinkText(wgAjaxWatch.watchMsg);
6888 wgAjaxWatch.setLinkID("ca-watch");
69 - wgAjaxWatch.oldHref = wgAjaxWatch.oldHref.replace(/action=unwatch/, "action=watch");
 89+ wgAjaxWatch.setHref( 'watch' );
7090 }
 91+ jsMsg( response.substr(4), 'watch' );
7192 wgAjaxWatch.inprogress = false;
7293 if(wgAjaxWatch.timeoutID) {
7394 window.clearTimeout(wgAjaxWatch.timeoutID);
@@ -75,6 +96,8 @@
7697 };
7798
7899 wgAjaxWatch.onLoad = function() {
 100+ // This document structure hardcoding sucks. We should make a class and
 101+ // toss all this out the window.
79102 var el1 = document.getElementById("ca-unwatch");
80103 var el2 = null;
81104 if (!el1) {
@@ -103,14 +126,18 @@
104127
105128 // The id can be either for the parent (Monobook-based) or the element
106129 // 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 );
109132
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 );
114135 }
 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+ }
115142 return;
116143 };
117144
@@ -124,4 +151,4 @@
125152 var supportsAjax = request ? true : false;
126153 delete request;
127154 return supportsAjax;
128 -}
\ No newline at end of file
 155+}
Index: trunk/phase3/skins/common/shared.css
@@ -6,4 +6,5 @@
77 .mw-plusminus-null { color: #aaa; }
88 .texvc { direction: ltr; unicode-bidi: embed; }
99 /* 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 @@
605605 // the original.
606606 var ta;
607607 if ( doId ) {
608 - ta = new Array;
609 - ta[doId] = window.ta[doId];
 608+ ta = [doId];
610609 } else {
611610 ta = window.ta;
612611 }
@@ -1214,6 +1213,53 @@
12151214 * End of table sorting code
12161215 */
12171216
 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+
12181264 function runOnloadHook() {
12191265 // don't run anything below this for non-dom browsers
12201266 if (doneOnloadHook || !(document.getElementById && document.getElementsByTagName)) {
@@ -1243,4 +1289,4 @@
12441290 // so the below should be redundant. It's there just in case.
12451291 hookEvent("load", runOnloadHook);
12461292
1247 -hookEvent("load", mwSetupToolbar);
\ No newline at end of file
 1293+hookEvent("load", mwSetupToolbar);
Index: trunk/phase3/includes/AjaxFunctions.php
@@ -136,22 +136,29 @@
137137
138138 /**
139139 * 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
141141 * @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
143145 */
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+ }
147152
148 - if(('w' !== $watch && 'u' !== $watch) || !is_numeric($pageID))
 153+ if('w' !== $watch && 'u' !== $watch) {
149154 return '<err#>';
 155+ }
150156 $watch = 'w' === $watch;
151 - $pageID = intval($pageID);
152157
153 - $title = Title::newFromID($pageID);
154 - if(!$title)
 158+ $title = Title::newFromText($pagename);
 159+ if(!$title) {
 160+ // Invalid title
155161 return '<err#>';
 162+ }
156163 $article = new Article($title);
157164 $watching = $title->userIsWatching();
158165
@@ -170,7 +177,10 @@
171178 $dbw->commit();
172179 }
173180 }
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+ }
176186 }
177187 ?>
Index: trunk/phase3/includes/DefaultSettings.php
@@ -2514,7 +2514,7 @@
25152515 /**
25162516 * Enable AJAX framework
25172517 */
2518 -$wgUseAjax = false;
 2518+$wgUseAjax = true;
25192519
25202520 /**
25212521 * Enable auto suggestion for the search bar
@@ -2534,7 +2534,7 @@
25352535 * Requires $wgUseAjax to be true too.
25362536 * Causes wfAjaxWatch to be added to $wgAjaxExportList
25372537 */
2538 -$wgAjaxWatch = false;
 2538+$wgAjaxWatch = true;
25392539
25402540 /**
25412541 * Allow DISPLAYTITLE to change title display
Index: trunk/phase3/RELEASE-NOTES
@@ -97,6 +97,8 @@
9898 to cause hard-to-track-down interactions between extensions.
9999 * Use $wgJobClasses to determine the correct Job to instantiate for a particular
100100 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.
101103
102104 == Bugfixes since 1.10 ==
103105

Follow-up revisions

RevisionCommit summaryAuthorDate
r23407Merged revisions 23203-23405 via svnmerge from...david23:00, 25 June 2007

Status & tagging log