Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php |
— | — | @@ -58,7 +58,8 @@ |
59 | 59 | array( 'src' => 'js/plugins/jquery.async.js', 'version' => 3 ), |
60 | 60 | array( 'src' => 'js/plugins/jquery.browser.js', 'version' => 3 ), |
61 | 61 | 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 ), |
63 | 64 | array( 'src' => 'js/plugins/jquery.textSelection.js', 'version' => 9 ), |
64 | 65 | array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 4 ), |
65 | 66 | array( 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', 'version' => 11 ), |
Index: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js |
— | — | @@ -710,6 +710,7 @@ |
711 | 711 | <div id="edittoolbar-link-dialog-tab-int"><form><fieldset><table><tr>\ |
712 | 712 | <td><label for="edittoolbar-link-int-target" rel="edittoolbar-tool-link-int-target"></label></td>\ |
713 | 713 | <td>\ |
| 714 | + <select id="edittoolbar-link-int-target-ns" />\ |
714 | 715 | <input type="text" id="edittoolbar-link-int-target" />\ |
715 | 716 | <div id="edittoolbar-link-int-target-status" style="display: inline;"></div>\ |
716 | 717 | </td>\ |
— | — | @@ -727,7 +728,7 @@ |
728 | 729 | </div>', |
729 | 730 | init: function() { |
730 | 731 | // Updates the UI to show if the page title being inputed by the user exists or not |
731 | | - function updateExistence( target ) { |
| 732 | + function updateExistence() { |
732 | 733 | function updateWidget( status ) { |
733 | 734 | $j( '#edittoolbar-link-int-target-status' ).children().hide(); |
734 | 735 | $j( '#edittoolbar-link-int-target-status-' + status ).show(); |
— | — | @@ -737,13 +738,25 @@ |
738 | 739 | if ( request ) { |
739 | 740 | request.abort(); |
740 | 741 | } |
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' ); |
743 | 756 | if ( cache[target] ) { |
744 | 757 | updateWidget( cache[target] ); |
745 | 758 | return; |
746 | 759 | } |
747 | | - if ( target == '' ) { |
| 760 | + if ( targetTitle == '' ) { |
748 | 761 | // Hide the widget when the textbox is empty |
749 | 762 | $j( '#edittoolbar-link-int-target-status' ).children().hide(); |
750 | 763 | return; |
— | — | @@ -789,20 +802,30 @@ |
790 | 803 | }); |
791 | 804 | // Build tabs |
792 | 805 | $j( '#edittoolbar-link-tabs' ).tabs(); |
| 806 | + // Set up the namespace selector |
| 807 | + $j( '#edittoolbar-link-int-target-ns' ).namespaceSelector(); |
793 | 808 | // Automatically copy the value of the internal link page title field to the link text field unless the user |
794 | 809 | // has changed the link text field - this is a convience thing since most link texts are going to be the |
795 | 810 | // 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() { |
797 | 812 | // $j(this).val() is the old value, before the keypress |
798 | 813 | if ( $j( '#edittoolbar-link-int-text' ).data( 'untouched' ) ) |
799 | 814 | // Defer this until $j(this).val() has been updated |
800 | 815 | 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() ); |
802 | 820 | }, 0 ); |
803 | 821 | }); |
804 | | - $j( '#edittoolbar-link-int-text' ).bind( 'keypress paste cut', function() { |
| 822 | + $j( '#edittoolbar-link-int-text' ).bind( 'change keypress paste cut', function() { |
805 | 823 | $j(this).data( 'untouched', false ); |
806 | 824 | }); |
| 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 | + }); |
807 | 830 | // Set the initial value of the external link field to start out as a real URL |
808 | 831 | $j( '#edittoolbar-link-ext-target' ).val( 'http://' ); |
809 | 832 | // Add images to the page existence widget, which will be shown mutually exclusively to communicate if the |
— | — | @@ -836,7 +859,7 @@ |
837 | 860 | 'alt': loadingMsg, |
838 | 861 | 'title': loadingMsg |
839 | 862 | } ) ) |
840 | | - .data( 'cache', {} ) |
| 863 | + .data( 'existencecache', {} ) |
841 | 864 | .children().hide(); |
842 | 865 | |
843 | 866 | $j( '#edittoolbar-link-int-target' ) |
— | — | @@ -858,6 +881,59 @@ |
859 | 882 | // Fetch right now |
860 | 883 | updateExistence(); |
861 | 884 | } ); |
| 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 | + }); |
862 | 938 | }, |
863 | 939 | dialog: { |
864 | 940 | width: 550, // FIXME: autoresize width |
— | — | @@ -883,7 +959,11 @@ |
884 | 960 | alert( gM( 'edittoolbar-tool-link-int-invalid' ) ); |
885 | 961 | return; |
886 | 962 | } |
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; |
888 | 968 | var text = $j( '#edittoolbar-link-int-text' ).val(); |
889 | 969 | whitespace = $j( '#edittoolbar-link-dialog-tab-int' ).data( 'whitespace' ); |
890 | 970 | if ( target == text ) |
— | — | @@ -961,6 +1041,7 @@ |
962 | 1042 | $j( '#edittoolbar-link-int-text' ).data( 'untouched', |
963 | 1043 | $j( '#edittoolbar-link-int-text' ).val() == $j( '#edittoolbar-link-int-target' ).val() |
964 | 1044 | ); |
| 1045 | + $j( '#edittoolbar-link-int-target' ).suggestions(); |
965 | 1046 | } |
966 | 1047 | } |
967 | 1048 | }, |
Index: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.php |
— | — | @@ -19,7 +19,7 @@ |
20 | 20 | /* Configuration */ |
21 | 21 | |
22 | 22 | // Bump the version number every time you change any of the .css/.js files |
23 | | -$wgEditToolbarStyleVersion = 27; |
| 23 | +$wgEditToolbarStyleVersion = 28; |
24 | 24 | |
25 | 25 | // Set this to true to simply override the stock toolbar for everyone |
26 | 26 | $wgEditToolbarGlobalEnable = false; |
Index: trunk/extensions/UsabilityInitiative/css/wikiEditor.dialogs.css |
— | — | @@ -2,4 +2,9 @@ |
3 | 3 | |
4 | 4 | .ui-widget table td { |
5 | 5 | 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 @@ |
135 | 135 | return; |
136 | 136 | } |
137 | 137 | |
| 138 | + positionDiv(); |
138 | 139 | var table = conf._data.div.children( 'table' ); |
139 | 140 | table.empty(); |
140 | 141 | for ( var i = 0; i < conf.suggestions.length; i++ ) { |
— | — | @@ -285,8 +286,13 @@ |
286 | 287 | if ( updateTextbox ) { |
287 | 288 | if ( result.size() == 0 ) |
288 | 289 | restoreText(); |
289 | | - else |
| 290 | + else { |
290 | 291 | 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 | + } |
291 | 297 | } |
292 | 298 | |
293 | 299 | if ( result.size() > 0 && conf._data.visibleResults < conf.suggestions.length ) { |
— | — | @@ -311,6 +317,15 @@ |
312 | 318 | } |
313 | 319 | } |
314 | 320 | |
| 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 | + |
315 | 330 | /** |
316 | 331 | * Initialize the widget |
317 | 332 | */ |
— | — | @@ -345,14 +360,13 @@ |
346 | 361 | // Create container div for suggestions |
347 | 362 | conf._data.div = $( '<div />' ) |
348 | 363 | .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 | | - }) |
354 | 364 | .hide() |
355 | 365 | .appendTo( $( 'body' ) ); |
356 | 366 | |
| 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 | + |
357 | 371 | // Create results table |
358 | 372 | $( '<table />' ) |
359 | 373 | .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 | +
|