r56063 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r56062‎ | r56063 | r56064 >
Date:19:43, 8 September 2009
Author:catrope
Status:deferred
Tags:
Comment:
EditToolbar: Add namespace selector and title suggestions to link dialog, and make the suggestions plugin work nicely with jQuery UI Draggable
Modified paths:
  • /trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.php (modified) (history)
  • /trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php (modified) (history)
  • /trunk/extensions/UsabilityInitiative/css/wikiEditor.dialogs.css (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.namespaceSelect.js (added) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.suggestions.js (modified) (history)

Diff [purge]

Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php
@@ -58,7 +58,8 @@
5959 array( 'src' => 'js/plugins/jquery.async.js', 'version' => 3 ),
6060 array( 'src' => 'js/plugins/jquery.browser.js', 'version' => 3 ),
6161 array( 'src' => 'js/plugins/jquery.cookie.js', 'version' => 3 ),
62 - array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 0 ),
 62+ array( 'src' => 'js/plugins/jquery.namespaceSelect.js', 'version' => 0 ),
 63+ array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 1 ),
6364 array( 'src' => 'js/plugins/jquery.textSelection.js', 'version' => 9 ),
6465 array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 4 ),
6566 array( 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', 'version' => 11 ),
Index: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js
@@ -710,6 +710,7 @@
711711 <div id="edittoolbar-link-dialog-tab-int"><form><fieldset><table><tr>\
712712 <td><label for="edittoolbar-link-int-target" rel="edittoolbar-tool-link-int-target"></label></td>\
713713 <td>\
 714+ <select id="edittoolbar-link-int-target-ns" />\
714715 <input type="text" id="edittoolbar-link-int-target" />\
715716 <div id="edittoolbar-link-int-target-status" style="display: inline;"></div>\
716717 </td>\
@@ -727,7 +728,7 @@
728729 </div>',
729730 init: function() {
730731 // Updates the UI to show if the page title being inputed by the user exists or not
731 - function updateExistence( target ) {
 732+ function updateExistence() {
732733 function updateWidget( status ) {
733734 $j( '#edittoolbar-link-int-target-status' ).children().hide();
734735 $j( '#edittoolbar-link-int-target-status-' + status ).show();
@@ -737,13 +738,25 @@
738739 if ( request ) {
739740 request.abort();
740741 }
741 - var target = $j( '#edittoolbar-link-int-target' ).val();
742 - var cache = $j( '#edittoolbar-link-int-target-status' ).data( 'cache' );
 742+
 743+ var targetNSID = $j( '#edittoolbar-link-int-target-ns' ).val();
 744+ if ( targetNSID < 0 ) {
 745+ // Can't check existence for Special: or Media: titles
 746+ updateWidget( 'exists' );
 747+ return;
 748+ }
 749+
 750+ var targetNS = $j( '#edittoolbar-link-int-target-ns option:selected' ).text();
 751+ if ( targetNS != '' )
 752+ targetNS += ':';
 753+ var targetTitle = $j( '#edittoolbar-link-int-target' ).val();
 754+ var target = targetNS + targetTitle;
 755+ var cache = $j( '#edittoolbar-link-int-target-status' ).data( 'existencecache' );
743756 if ( cache[target] ) {
744757 updateWidget( cache[target] );
745758 return;
746759 }
747 - if ( target == '' ) {
 760+ if ( targetTitle == '' ) {
748761 // Hide the widget when the textbox is empty
749762 $j( '#edittoolbar-link-int-target-status' ).children().hide();
750763 return;
@@ -789,20 +802,30 @@
790803 });
791804 // Build tabs
792805 $j( '#edittoolbar-link-tabs' ).tabs();
 806+ // Set up the namespace selector
 807+ $j( '#edittoolbar-link-int-target-ns' ).namespaceSelector();
793808 // Automatically copy the value of the internal link page title field to the link text field unless the user
794809 // has changed the link text field - this is a convience thing since most link texts are going to be the
795810 // the same as the page title
796 - $j( '#edittoolbar-link-int-target' ).bind( 'keypress paste', function() {
 811+ $j( '#edittoolbar-link-int-target' ).bind( 'change keypress paste cut', function() {
797812 // $j(this).val() is the old value, before the keypress
798813 if ( $j( '#edittoolbar-link-int-text' ).data( 'untouched' ) )
799814 // Defer this until $j(this).val() has been updated
800815 setTimeout( function() {
801 - $j( '#edittoolbar-link-int-text' ).val( $j( '#edittoolbar-link-int-target' ).val() );
 816+ var ns = $j( '#edittoolbar-link-int-target-ns option:selected' ).text();
 817+ if ( ns != '' )
 818+ ns += ':';
 819+ $j( '#edittoolbar-link-int-text' ).val( ns + $j( '#edittoolbar-link-int-target' ).val() );
802820 }, 0 );
803821 });
804 - $j( '#edittoolbar-link-int-text' ).bind( 'keypress paste cut', function() {
 822+ $j( '#edittoolbar-link-int-text' ).bind( 'change keypress paste cut', function() {
805823 $j(this).data( 'untouched', false );
806824 });
 825+ // Make sure changes to the namespace selector also trigger value copying and AJAX stuff
 826+ // This is ugly
 827+ $j( '#edittoolbar-link-int-target-ns' ).change( function() {
 828+ $j( '#edittoolbar-link-int-target' ).keydown().keypress().keyup();
 829+ });
807830 // Set the initial value of the external link field to start out as a real URL
808831 $j( '#edittoolbar-link-ext-target' ).val( 'http://' );
809832 // Add images to the page existence widget, which will be shown mutually exclusively to communicate if the
@@ -836,7 +859,7 @@
837860 'alt': loadingMsg,
838861 'title': loadingMsg
839862 } ) )
840 - .data( 'cache', {} )
 863+ .data( 'existencecache', {} )
841864 .children().hide();
842865
843866 $j( '#edittoolbar-link-int-target' )
@@ -858,6 +881,59 @@
859882 // Fetch right now
860883 updateExistence();
861884 } );
 885+
 886+ // Title suggestions
 887+ $j( '#edittoolbar-link-int-target' ).data( 'suggcache', {} ).suggestions( {
 888+ fetch: function( query ) {
 889+ var that = this;
 890+ var ns = $j( '#edittoolbar-link-int-target-ns' ).val();
 891+ var title = $j(this).val();
 892+ if ( ns < 0 ) {
 893+ // Can't search for Special: or Media: titles
 894+ $j(this).suggestions( 'suggestions', [] );
 895+ return;
 896+ }
 897+
 898+ var cache = $j(this).data( 'suggcache' );
 899+ if ( typeof cache[ns] != 'undefined' &&
 900+ typeof cache[ns][title] != 'undefined' ) {
 901+ $j(this).suggestions( 'suggestions', cache[ns][title] );
 902+ return;
 903+ }
 904+
 905+ var request = $j.ajax( {
 906+ url: wgScriptPath + '/api.php',
 907+ data: {
 908+ 'action': 'query',
 909+ 'list': 'allpages',
 910+ 'apnamespace': ns,
 911+ 'apprefix': title,
 912+ 'aplimit': '10',
 913+ 'format': 'json'
 914+ },
 915+ dataType: 'json',
 916+ success: function( data ) {
 917+ var titles = [];
 918+ for ( var i = 0; i < data.query.allpages.length; i++ ) {
 919+ titles[i] = data.query.allpages[i].title;
 920+ if ( ns != 0 )
 921+ titles[i] = titles[i].substr(
 922+ titles[i].indexOf( ':' ) + 1 );
 923+ }
 924+ if ( typeof cache[ns] == 'undefined' )
 925+ cache[ns] = {};
 926+ cache[ns][title] = titles;
 927+ $j(that).suggestions( 'suggestions', titles );
 928+ }
 929+ });
 930+ $j(this).data( 'request', request );
 931+ },
 932+ cancel: function() {
 933+ var request = $j(this).data( 'request' );
 934+ if ( request.abort )
 935+ request.abort();
 936+ }
 937+ });
862938 },
863939 dialog: {
864940 width: 550, // FIXME: autoresize width
@@ -883,7 +959,11 @@
884960 alert( gM( 'edittoolbar-tool-link-int-invalid' ) );
885961 return;
886962 }
887 - var target = $j( '#edittoolbar-link-int-target' ).val();
 963+ var targetNS = $j( '#edittoolbar-link-int-target-ns option:selected' ).text();
 964+ if ( targetNS != '' )
 965+ targetNS += ':';
 966+ var targetTitle = $j( '#edittoolbar-link-int-target' ).val();
 967+ var target = targetNS + targetTitle;
888968 var text = $j( '#edittoolbar-link-int-text' ).val();
889969 whitespace = $j( '#edittoolbar-link-dialog-tab-int' ).data( 'whitespace' );
890970 if ( target == text )
@@ -961,6 +1041,7 @@
9621042 $j( '#edittoolbar-link-int-text' ).data( 'untouched',
9631043 $j( '#edittoolbar-link-int-text' ).val() == $j( '#edittoolbar-link-int-target' ).val()
9641044 );
 1045+ $j( '#edittoolbar-link-int-target' ).suggestions();
9651046 }
9661047 }
9671048 },
Index: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.php
@@ -19,7 +19,7 @@
2020 /* Configuration */
2121
2222 // Bump the version number every time you change any of the .css/.js files
23 -$wgEditToolbarStyleVersion = 27;
 23+$wgEditToolbarStyleVersion = 28;
2424
2525 // Set this to true to simply override the stock toolbar for everyone
2626 $wgEditToolbarGlobalEnable = false;
Index: trunk/extensions/UsabilityInitiative/css/wikiEditor.dialogs.css
@@ -2,4 +2,9 @@
33
44 .ui-widget table td {
55 padding: 0.5em;
6 -}
\ No newline at end of file
 6+}
 7+
 8+/* Put suggestions (default z-index 99) on top of dialogs (z-index 1002) */
 9+div.os-suggest {
 10+ z-index: 1099;
 11+}
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.suggestions.js
@@ -134,6 +134,7 @@
135135 return;
136136 }
137137
 138+ positionDiv();
138139 var table = conf._data.div.children( 'table' );
139140 table.empty();
140141 for ( var i = 0; i < conf.suggestions.length; i++ ) {
@@ -285,8 +286,13 @@
286287 if ( updateTextbox ) {
287288 if ( result.size() == 0 )
288289 restoreText();
289 - else
 290+ else {
290291 conf._data.textbox.val( result.data( 'text' ) );
 292+
 293+ // Trigger the change event for listeners
 294+ // This isn't exactly pretty
 295+ conf._data.textbox.change();
 296+ }
291297 }
292298
293299 if ( result.size() > 0 && conf._data.visibleResults < conf.suggestions.length ) {
@@ -311,6 +317,15 @@
312318 }
313319 }
314320
 321+ function positionDiv() {
 322+ conf._data.div.css( {
 323+ top: Math.round( conf._data.textbox.offset().top ) +
 324+ conf._data.textbox.get( 0 ).offsetHeight,
 325+ left: Math.round( conf._data.textbox.offset().left ),
 326+ width: conf._data.textbox.outerWidth()
 327+ });
 328+ }
 329+
315330 /**
316331 * Initialize the widget
317332 */
@@ -345,14 +360,13 @@
346361 // Create container div for suggestions
347362 conf._data.div = $( '<div />' )
348363 .addClass( 'os-suggest' ) //TODO: use own CSS
349 - .css( {
350 - top: Math.round( $(this).offset().top ) + this.offsetHeight,
351 - left: Math.round( $(this).offset().left ),
352 - width: $(this).outerWidth()
353 - })
354364 .hide()
355365 .appendTo( $( 'body' ) );
356366
 367+ // Recalculate position when <div> gets moved by jQuery Draggable
 368+ var draggableParent = conf._data.textbox.closest( '.ui-draggable' );
 369+ draggableParent.bind( 'drag', positionDiv );
 370+
357371 // Create results table
358372 $( '<table />' )
359373 .addClass( 'os-suggest-results' ) // TODO: use descendant selector
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.namespaceSelect.js
@@ -0,0 +1,20 @@
 2+/**
 3+ * Plugin that fills a <select> with namespaces
 4+ */
 5+
 6+(function ($) {
 7+$.fn.namespaceSelector = function( defaultNS ) {
 8+ if ( typeof defaultNS == 'undefined' )
 9+ defaultNS = 0;
 10+ return this.each( function() {
 11+ for ( var id in wgFormattedNamespaces ) {
 12+ var opt = $( '<option />' )
 13+ .attr( 'value', id )
 14+ .text( wgFormattedNamespaces[id] );
 15+ if ( id == defaultNS )
 16+ opt.attr( 'selected', 'selected' );
 17+ opt.appendTo( $(this) );
 18+ }
 19+ });
 20+};})(jQuery);
 21+

Status & tagging log