r57841 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r57840‎ | r57841 | r57842 >
Date:01:45, 17 October 2009
Author:catrope
Status:deferred
Tags:
Comment:
EditToolbar: Totally revamp link dialog based on experiences from usability test; based on http://usability.wikimedia.org/w/index.php?title=File:Wireframe-Babaco-Dialogs.pdf&page=1
* Replace internal/external tabs with radio buttons
* Autodetect which type the user is entering and select that type
* Be smart about turning e.g. www.google.com into http://www.google.com
* Add an icon for external links
* Make suggestion caching actually work
* TODO: be smart about turning e.g. http://en.wikipedia.org/wiki/Foo into an internal link to Foo (optionally)
Modified paths:
  • /trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.hooks.php (modified) (history)
  • /trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.i18n.php (modified) (history)
  • /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/js/plugins.combined.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.suggestions.js (modified) (history)

Diff [purge]

Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php
@@ -64,7 +64,7 @@
6565 array( 'src' => 'js/plugins/jquery.collapsibleTabs.js', 'version' => 1 ),
6666 array( 'src' => 'js/plugins/jquery.delayedBind.js', 'version' => 1 ),
6767 array( 'src' => 'js/plugins/jquery.namespaceSelect.js', 'version' => 1 ),
68 - array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 4 ),
 68+ array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 5 ),
6969 array( 'src' => 'js/plugins/jquery.textSelection.js', 'version' => 16 ),
7070 array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 12 ),
7171 array( 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', 'version' => 12 ),
@@ -72,10 +72,10 @@
7373 array( 'src' => 'js/plugins/jquery.wikiEditor.toc.js', 'version' => 20 ),
7474 ),
7575 'combined' => array(
76 - array( 'src' => 'js/plugins.combined.js', 'version' => 44 ),
 76+ array( 'src' => 'js/plugins.combined.js', 'version' => 45 ),
7777 ),
7878 'minified' => array(
79 - array( 'src' => 'js/plugins.combined.min.js', 'version' => 44 ),
 79+ array( 'src' => 'js/plugins.combined.min.js', 'version' => 45 ),
8080 ),
8181 ),
8282 );
Index: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.hooks.php
@@ -59,7 +59,6 @@
6060 'edittoolbar-tool-link-int-target-status-invalid',
6161 'edittoolbar-tool-link-int-target-status-loading',
6262 'edittoolbar-tool-link-int-invalid',
63 - 'edittoolbar-tool-link-ext-invalid',
6463 'edittoolbar-tool-file',
6564 'edittoolbar-tool-file-pre',
6665 'edittoolbar-tool-file-example',
Index: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js
@@ -752,30 +752,39 @@
753753 titleMsg: 'edittoolbar-tool-link-title',
754754 id: 'edittoolbar-link-dialog',
755755 html: '\
756 - <div id="edittoolbar-link-tabs">\
757 - <ul>\
758 - <li><a href="#edittoolbar-link-dialog-tab-int" rel="edittoolbar-tool-link-int"></a></li>\
759 - <li><a href="#edittoolbar-link-dialog-tab-ext" rel="edittoolbar-tool-link-ext"></a></li>\
760 - </ul>\
761 - <div id="edittoolbar-link-dialog-tab-int"><fieldset><table><tr>\
762 - <td><label for="edittoolbar-link-int-target" rel="edittoolbar-tool-link-int-target"></label></td>\
763 - <td>\
764 - <input type="text" id="edittoolbar-link-int-target" size="50" />\
765 - <div id="edittoolbar-link-int-target-status" style="display: inline;"></div>\
766 - </td>\
767 - </tr><tr>\
768 - <td><label for="edittoolbar-link-int-text" rel="edittoolbar-tool-link-int-text"></label></td>\
769 - <td><input type="text" id="edittoolbar-link-int-text" size="50" /></td>\
770 - </table></fieldset></div>\
771 - <div id="edittoolbar-link-dialog-tab-ext"><fieldset><table><tr>\
772 - <td><label for="edittoolbar-link-ext-target" rel="edittoolbar-tool-link-ext-target"></label></td>\
773 - <td><input type="text" id="edittoolbar-link-ext-target" size="50" /></td>\
774 - </tr><tr>\
775 - <td><label for="edittoolbar-link-ext-text" rel="edittoolbar-tool-link-ext-text"></label></td>\
776 - <td><input type="text" id="edittoolbar-link-ext-text" size="50" /></td>\
777 - </table></fieldset></div>\
778 - </div>',
 756+ <fieldset><table style="width: 100%;"><tr>\
 757+ <td>\
 758+ <label for="edittoolbar-link-int-target" rel="edittoolbar-tool-link-int-target"></label><br />\
 759+ <input type="text" id="edittoolbar-link-int-target" style="width: 100%;" />\
 760+ </td><td style="width: 48px;">\
 761+ <div id="edittoolbar-link-int-target-status" style="display: inline;"></div>\
 762+ </td>\
 763+ </tr><tr>\
 764+ <td>\
 765+ <label for="edittoolbar-link-int-text" rel="edittoolbar-tool-link-int-text"></label><br />\
 766+ <input type="text" id="edittoolbar-link-int-text" style="width: 100%;" />\
 767+ </td>\
 768+ </tr><tr>\
 769+ <td colspan="2">\
 770+ <div style="float: left; margin-right: 2em;">\
 771+ <input type="radio" id="edittoolbar-link-type-int" name="edittoolbar-link-type" selected />\
 772+ <label for="edittoolbar-link-type-int" rel="edittoolbar-tool-link-int"></label>\
 773+ </div><div style="float: left;">\
 774+ <input type="radio" id="edittoolbar-link-type-ext" name="edittoolbar-link-type" />\
 775+ <label for="edittoolbar-link-type-ext" rel="edittoolbar-tool-link-ext"></label>\
 776+ </div>\
 777+ </td>\
 778+ </tr>\
 779+ </table></fieldset>',
779780 init: function() {
 781+ function isExternalLink( s ) {
 782+ // The following things are considered to be external links:
 783+ // * Starts with one or more letters followed by ://
 784+ // * Starts with www.
 785+ // * Ends with a . followed by two or more letters
 786+ // * Contains a . followed by two or more letters followed by /
 787+ return s.match( /(^[a-z]+:\/\/)|(^www\.)|([^.]\.[a-z]{2,}($|\/))/i );
 788+ }
780789 // Updates the UI to show if the page title being inputed by the user exists or not
781790 function updateExistence() {
782791 function updateWidget( status ) {
@@ -799,6 +808,10 @@
800809 $j( '#edittoolbar-link-int-target-status' ).children().hide();
801810 return;
802811 }
 812+ if ( isExternalLink( target ) ) {
 813+ updateWidget( 'external' );
 814+ return;
 815+ }
803816 if ( target.indexOf( '|' ) != -1 ) {
804817 // Title contains | , which means it's invalid
805818 // but confuses the API. Show invalid and bypass API
@@ -838,31 +851,32 @@
839852 $j(this).find( '[rel]' ).each( function() {
840853 $j(this).text( gM( $j(this).attr( 'rel' ) ) );
841854 });
842 - // Build tabs
843 - mvJsLoader.doLoad( [ '$j.ui', '$j.ui.tabs' ], function() {
844 - $j( '#edittoolbar-link-tabs' ).tabs();
845 - });
846855 // Automatically copy the value of the internal link page title field to the link text field unless the user
847856 // has changed the link text field - this is a convience thing since most link texts are going to be the
848857 // the same as the page title
 858+ // Also change the internal/external radio button accordingly
849859 $j( '#edittoolbar-link-int-target' ).bind( 'change keypress paste cut', function() {
850860 // $j(this).val() is the old value, before the keypress
851 - if ( $j( '#edittoolbar-link-int-text' ).data( 'untouched' ) )
852 - // Defer this until $j(this).val() has been updated
853 - setTimeout( function() {
 861+ // Defer this until $j(this).val() has been updated
 862+ setTimeout( function() {
 863+ if ( isExternalLink( $j( '#edittoolbar-link-int-target' ).val() ) )
 864+ $j( '#edittoolbar-link-type-ext' ).attr( 'checked', 'checked' );
 865+ else
 866+ $j( '#edittoolbar-link-type-int' ).attr( 'checked', 'checked' );
 867+
 868+ if ( $j( '#edittoolbar-link-int-text' ).data( 'untouched' ) )
854869 $j( '#edittoolbar-link-int-text' ).val( $j( '#edittoolbar-link-int-target' ).val() );
855 - }, 0 );
 870+ }, 0 );
856871 });
857872 $j( '#edittoolbar-link-int-text' ).bind( 'change keypress paste cut', function() {
858873 $j(this).data( 'untouched', false );
859874 });
860 - // Set the initial value of the external link field to start out as a real URL
861 - $j( '#edittoolbar-link-ext-target' ).val( 'http://' );
862875 // Add images to the page existence widget, which will be shown mutually exclusively to communicate if the
863876 // page exists, does not exist or the title is invalid (like if it contains a | character)
864877 var existsMsg = gM( 'edittoolbar-tool-link-int-target-status-exists' );
865878 var notexistsMsg = gM( 'edittoolbar-tool-link-int-target-status-notexists' );
866879 var invalidMsg = gM( 'edittoolbar-tool-link-int-target-status-invalid' );
 880+ var externalMsg = gM( 'edittoolbar-tool-link-int-target-status-external' );
867881 var loadingMsg = gM( 'edittoolbar-tool-link-int-target-status-loading' );
868882 $j( '#edittoolbar-link-int-target-status' )
869883 .append( $j( '<img />' ).attr( {
@@ -884,6 +898,12 @@
885899 'title': invalidMsg
886900 } ) )
887901 .append( $j( '<img />' ).attr( {
 902+ 'id': 'edittoolbar-link-int-target-status-external',
 903+ 'src': $j.wikiEditor.imgPath + 'dialogs/' + 'insert-link-external.png',
 904+ 'alt': externalMsg,
 905+ 'title': externalMsg
 906+ } ) )
 907+ .append( $j( '<img />' ).attr( {
888908 'id': 'edittoolbar-link-int-target-status-loading',
889909 'src': $j.wikiEditor.imgPath + 'dialogs/loading.gif',
890910 'alt': loadingMsg,
@@ -899,8 +919,8 @@
900920 clearTimeout( $j(this).data( 'timerID' ) );
901921 }
902922 // Delay fetch for a while
903 - // FIXME: Make 250 configurable elsewhere
904 - var timerID = setTimeout( updateExistence, 250 );
 923+ // FIXME: Make 120 configurable elsewhere
 924+ var timerID = setTimeout( updateExistence, 120 );
905925 $j(this).data( 'timerID', timerID );
906926 } )
907927 .change( function() {
@@ -918,6 +938,11 @@
919939 var that = this;
920940 var title = $j(this).val();
921941
 942+ if ( isExternalLink( title ) || title.indexOf( '|' ) != -1 || title == '') {
 943+ $j(this).suggestions( 'suggestions', [] );
 944+ return;
 945+ }
 946+
922947 var cache = $j(this).data( 'suggcache' );
923948 if ( typeof cache[title] != 'undefined' ) {
924949 $j(this).suggestions( 'suggestions', cache[title] );
@@ -935,6 +960,7 @@
936961 },
937962 dataType: 'json',
938963 success: function( data ) {
 964+ cache[title] = data[1];
939965 $j(that).suggestions( 'suggestions', data[1] );
940966 }
941967 });
@@ -948,6 +974,7 @@
949975 });
950976 },
951977 dialog: {
 978+ width: 500,
952979 buttons: {
953980 'edittoolbar-tool-link-insert': function() {
954981 function escapeInternalText( s ) {
@@ -961,42 +988,35 @@
962989 return s.replace( /(]+)/g, '<nowiki>$1</nowiki>' );
963990 }
964991 var insertText = '';
965 - var whitespace = [ '', '' ];
966 - switch ( $j( '#edittoolbar-link-tabs' ).tabs( 'option', 'selected' ) ) {
967 - case 0: // Internal link
968 - var target = $j( '#edittoolbar-link-int-target' ).val();
969 - var text = $j( '#edittoolbar-link-int-text' ).val();
970 - // FIXME: Exactly how fragile is this?
971 - if ( $j( '#edittoolbar-link-int-target-status-invalid' ).is( ':visible' ) ||
972 - target == '' ) {
973 - // Refuse to add links to invalid titles
974 - alert( gM( 'edittoolbar-tool-link-int-invalid' ) );
975 - return;
976 - }
977 - whitespace = $j( '#edittoolbar-link-dialog-tab-int' ).data( 'whitespace' );
978 - if ( target == text )
979 - insertText = '[[' + target + ']]';
980 - else
981 - insertText = '[[' + target + '|' + escapeInternalText( text ) + ']]';
982 - break;
983 - case 1:
984 - var target = $j( '#edittoolbar-link-ext-target' ).val();
985 - var text = $j( '#edittoolbar-link-ext-text' ).val();
986 - var escTarget = escapeExternalTarget( target );
987 - var escText = escapeExternalText( text );
988 - whitespace = $j( '#edittoolbar-link-dialog-tab-ext' ).data( 'whitespace' );
989 - if ( !target.match( /^[a-z]+:\/\/./ ) ) {
990 - // Refuse to add links to invalid URLs
991 - alert( gM( 'edittoolbar-tool-link-ext-invalid' ) );
992 - return;
993 - }
994 - if ( escTarget == escText )
995 - insertText = escTarget;
996 - else if ( text == '' )
997 - insertText = '[' + escTarget + ']';
998 - else
999 - insertText = '[' + escTarget + ' ' + escText + ']';
1000 - break;
 992+ var whitespace = $j( '#edittoolbar-link-dialog' ).data( 'whitespace' );
 993+ var target = $j( '#edittoolbar-link-int-target' ).val();
 994+ var text = $j( '#edittoolbar-link-int-text' ).val();
 995+ if ( $j( '#edittoolbar-link-type-int' ).is( ':checked' ) ) {
 996+ // FIXME: Exactly how fragile is this?
 997+ if ( $j( '#edittoolbar-link-int-target-status-invalid' ).is( ':visible' ) ||
 998+ target == '' ) {
 999+ // Refuse to add links to invalid titles
 1000+ alert( gM( 'edittoolbar-tool-link-int-invalid' ) );
 1001+ return;
 1002+ }
 1003+
 1004+ if ( target == text )
 1005+ insertText = '[[' + target + ']]';
 1006+ else
 1007+ insertText = '[[' + target + '|' + escapeInternalText( text ) + ']]';
 1008+ } else {
 1009+ var escTarget = escapeExternalTarget( target );
 1010+ var escText = escapeExternalText( text );
 1011+ // Prepend http:// if there is no protocol
 1012+ if ( !escTarget.match( /^[a-z]+:\/\/./ ) ) {
 1013+ escTarget = 'http://' + escTarget;
 1014+ }
 1015+ if ( escTarget == escText )
 1016+ insertText = escTarget;
 1017+ else if ( text == '' )
 1018+ insertText = '[' + escTarget + ']';
 1019+ else
 1020+ insertText = '[' + escTarget + ' ' + escText + ']';
10011021 }
10021022 // Preserve whitespace in selection when replacing
10031023 insertText = whitespace[0] + insertText + whitespace[1];
@@ -1013,46 +1033,37 @@
10141034 }
10151035 },
10161036 open: function() {
1017 - $j( '#edittoolbar-link-int-target, #edittoolbar-link-ext-target' )
1018 - .filter( ':visible' )
1019 - .focus();
 1037+ $j( '#edittoolbar-link-int-target' ).focus();
10201038 // Pre-fill the text fields based on the current selection
10211039 var selection = $j(this).data( 'context' ).$textarea.getSelection();
1022 - $j( '#edittoolbar-link-dialog-tab-int' ).data( 'whitespace', [ '', '' ] );
1023 - $j( '#edittoolbar-link-dialog-tab-ext' ).data( 'whitespace', [ '', '' ] );
 1040+ $j( '#edittoolbar-link-dialog' ).data( 'whitespace', [ '', '' ] );
10241041 if ( selection != '' ) {
1025 - var intText, intTarget, extText, extTarget;
 1042+ var target, text, type;
10261043 var matches;
1027 - var tab = -1;
10281044 if ( ( matches = selection.match( /^(\s*)\[\[([^\]\|]+)(\|([^\]\|]*))?\]\](\s*)$/ ) ) ) {
10291045 // [[foo|bar]] or [[foo]]
1030 - intTarget = matches[2];
1031 - intText = ( matches[4] ? matches[4] : matches[2] );
1032 - tab = 0;
 1046+ target = matches[2];
 1047+ text = ( matches[4] ? matches[4] : matches[2] );
 1048+ type = 'int';
10331049 // Preserve whitespace when replacing
1034 - $j( '#edittoolbar-link-dialog-tab-int' ).data( 'whitespace', [ matches[1], matches[5] ] );
 1050+ $j( '#edittoolbar-link-dialog' ).data( 'whitespace', [ matches[1], matches[5] ] );
10351051 } else if ( ( matches = selection.match( /^(\s*)\[([^\] ]+)( ([^\]]+))?\](\s*)$/ ) ) ) {
10361052 // [http://www.example.com foo] or [http://www.example.com]
1037 - extTarget = matches[2];
1038 - extText = ( matches[4] ? matches[4] : '' );
1039 - tab = 1;
 1053+ target = matches[2];
 1054+ text = ( matches[4] ? matches[4] : '' );
 1055+ type = 'ext';
10401056 // Preserve whitespace when replacing
1041 - $j( '#edittoolbar-link-dialog-tab-ext' ).data( 'whitespace', [ matches[1], matches[5] ] );
 1057+ $j( '#edittoolbar-link-dialog' ).data( 'whitespace', [ matches[1], matches[5] ] );
10421058 } else {
1043 - intTarget = intText = extText = selection;
1044 - extTarget = 'http://';
 1059+ target = text = selection;
10451060 }
10461061 // Change the value by calling val() doesn't trigger the change event, so let's do that ourselves
1047 - if ( typeof intText != 'undefined' )
1048 - $j( '#edittoolbar-link-int-text' ).val( intText ).change();
1049 - if ( typeof intTarget != 'undefined' )
1050 - $j( '#edittoolbar-link-int-target' ).val( intTarget ).change();
1051 - if ( typeof extText != 'undefined' )
1052 - $j( '#edittoolbar-link-ext-text' ).val( extText ).change();
1053 - if ( typeof extTarget != 'undefined' )
1054 - $j( '#edittoolbar-link-ext-target' ).val( extTarget ).change();
1055 - if ( tab != -1 )
1056 - $j( '#edittoolbar-link-tabs' ).tabs( 'select', tab );
 1062+ if ( typeof text != 'undefined' )
 1063+ $j( '#edittoolbar-link-int-text' ).val( text ).change();
 1064+ if ( typeof target != 'undefined' )
 1065+ $j( '#edittoolbar-link-int-target' ).val( target ).change();
 1066+ if ( typeof type != 'undefined' )
 1067+ $j( '#edittoolbar-link-' + type ).attr( 'checked', 'checked' );
10571068 }
10581069 $j( '#edittoolbar-link-int-text' ).data( 'untouched',
10591070 $j( '#edittoolbar-link-int-text' ).val() == $j( '#edittoolbar-link-int-target' ).val()
Index: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.i18n.php
@@ -41,7 +41,6 @@
4242 'edittoolbar-tool-link-int-target-status-invalid' => 'Invalid title',
4343 'edittoolbar-tool-link-int-target-status-loading' => 'Checking page existence...',
4444 'edittoolbar-tool-link-int-invalid' => 'The title you specified is invalid.',
45 - 'edittoolbar-tool-link-ext-invalid' => 'The URL you specified is invalid.',
4645 'edittoolbar-tool-file' => 'Embedded file',
4746 'edittoolbar-tool-file-pre' => '$1{{ns:file}}:',
4847 'edittoolbar-tool-file-example' => 'Example.jpg',
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 = 58;
 23+$wgEditToolbarStyleVersion = 59;
2424
2525 // Set this to true to simply override the stock toolbar for everyone
2626 $wgEditToolbarGlobalEnable = false;
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.suggestions.js
@@ -100,7 +100,7 @@
101101 * @param {Mixed} value Value to set property with
102102 */
103103 configure: function( context, property, value ) {
104 - // Validate ccontextration using fallback values
 104+ // Validate creation using fallback values
105105 switch( property ) {
106106 case 'fetch':
107107 case 'cancel':
@@ -113,8 +113,9 @@
114114 context.config[property] = value;
115115 // Update suggestions
116116 if ( typeof context.data !== 'undefined' ) {
117 - if ( context.config.suggestions.length == 0 ) {
118 - // Hide the dive when no suggestion exist
 117+ if ( typeof context.config.suggestions == 'undefined' ||
 118+ context.config.suggestions.length == 0 ) {
 119+ // Hide the div when no suggestion exist
119120 context.data.$container.hide();
120121 } else {
121122 // Rebuild the suggestions list
@@ -150,7 +151,7 @@
151152 context.config[property] = Math.max( 1, Math.min( 100, value ) );
152153 break;
153154 case 'delay':
154 - context.config[property] = Math.max( 0, Math.min( 12000, value ) );
 155+ context.config[property] = Math.max( 0, Math.min( 1200, value ) );
155156 break;
156157 case 'submitOnClick':
157158 context.config[property] = value ? true : false;
@@ -264,7 +265,7 @@
265266 '$region': $(this),
266267 'suggestions': [],
267268 'maxRows': 7,
268 - 'delay': 1200,
 269+ 'delay': 120,
269270 'submitOnClick': false
270271 }
271272 };
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.js
@@ -508,7 +508,7 @@
509509 * @param {Mixed} value Value to set property with
510510 */
511511 configure: function( context, property, value ) {
512 - // Validate ccontextration using fallback values
 512+ // Validate creation using fallback values
513513 switch( property ) {
514514 case 'fetch':
515515 case 'cancel':
@@ -521,8 +521,9 @@
522522 context.config[property] = value;
523523 // Update suggestions
524524 if ( typeof context.data !== 'undefined' ) {
525 - if ( context.config.suggestions.length == 0 ) {
526 - // Hide the dive when no suggestion exist
 525+ if ( typeof context.config.suggestions == 'undefined' ||
 526+ context.config.suggestions.length == 0 ) {
 527+ // Hide the div when no suggestion exist
527528 context.data.$container.hide();
528529 } else {
529530 // Rebuild the suggestions list
@@ -558,7 +559,7 @@
559560 context.config[property] = Math.max( 1, Math.min( 100, value ) );
560561 break;
561562 case 'delay':
562 - context.config[property] = Math.max( 0, Math.min( 12000, value ) );
 563+ context.config[property] = Math.max( 0, Math.min( 1200, value ) );
563564 break;
564565 case 'submitOnClick':
565566 context.config[property] = value ? true : false;
@@ -672,7 +673,7 @@
673674 '$region': $(this),
674675 'suggestions': [],
675676 'maxRows': 7,
676 - 'delay': 1200,
 677+ 'delay': 120,
677678 'submitOnClick': false
678679 }
679680 };
@@ -1846,25 +1847,23 @@
18471848 .text( label )
18481849 .attr( 'rel', id )
18491850 .data( 'context', context )
1850 - .click(
1851 - function() {
1852 -
1853 - $(this).parent().parent().find( '.page' ).hide();
1854 - $(this).parent().parent().find( '.page-' + $(this).attr( 'rel' ) ).show();
1855 - $(this).siblings().removeClass( 'current' );
1856 - $(this).addClass( 'current' );
1857 - var section = $(this).parent().parent().attr( 'rel' );
1858 -
1859 - //click tracking
1860 - if($.trackAction != undefined){
1861 - $.trackAction(section + '.' + $(this).attr('rel'));
1862 - }
1863 -
1864 - $.cookie(
1865 - 'wikiEditor-' + $(this).data( 'context' ).instance + '-booklet-' + section + '-page',
1866 - $(this).attr( 'rel' )
1867 - );
1868 - } );
 1851+ .bind( 'mousedown', function() {
 1852+ $(this).parent().parent().find( '.page' ).hide();
 1853+ $(this).parent().parent().find( '.page-' + $(this).attr( 'rel' ) ).show();
 1854+ $(this).siblings().removeClass( 'current' );
 1855+ $(this).addClass( 'current' );
 1856+ var section = $(this).parent().parent().attr( 'rel' );
 1857+
 1858+ //click tracking
 1859+ if($.trackAction != undefined){
 1860+ $.trackAction(section + '.' + $(this).attr('rel'));
 1861+ }
 1862+
 1863+ $.cookie(
 1864+ 'wikiEditor-' + $(this).data( 'context' ).instance + '-booklet-' + section + '-page',
 1865+ $(this).attr( 'rel' )
 1866+ );
 1867+ } );
18691868 },
18701869 buildPage : function( context, id, page ) {
18711870 var $page = $( '<div />' ).attr( {
@@ -1971,7 +1970,7 @@
19721971 .attr( 'href', '#' )
19731972 .text( $.wikiEditor.autoMsg( section, 'label' ) )
19741973 .data( 'context', context )
1975 - .click( function() {
 1974+ .bind( 'mousedown', function() {
19761975 var $sections = $(this).data( 'context' ).$ui.find( '.sections' );
19771976 var $section =
19781977 $(this).data( 'context' ).$ui.find( '.section-' + $(this).parent().attr( 'rel' ) );
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js
@@ -32,8 +32,8 @@
3333 if(typeof context.config.cancel=='function'){context.config.cancel.call(context.data.$textbox);}},restore:function(context){context.data.$textbox.val(context.data.prevText);},update:function(context,delayed){function maybeFetch(){if(context.data.$textbox.val()!==context.data.prevText){context.data.prevText=context.data.$textbox.val();if(typeof context.config.fetch=='function'){context.config.fetch.call(context.data.$textbox,context.data.$textbox.val());}}}
3434 if(context.data.timerID!=null){clearTimeout(context.data.timerID);}
3535 if(delayed){context.data.timerID=setTimeout(maybeFetch,context.config.delay);}else{maybeFetch();}
36 -$.suggestions.special(context);},special:function(context){if(typeof context.config.special.render=='function'){setTimeout(function(){$special=context.data.$container.find('.suggestions-special');context.config.special.render.call($special,context.data.$textbox.val());},1);}},configure:function(context,property,value){switch(property){case'fetch':case'cancel':case'special':case'result':case'$region':context.config[property]=value;break;case'suggestions':context.config[property]=value;if(typeof context.data!=='undefined'){if(context.config.suggestions.length==0){context.data.$container.hide();}else{context.data.$container.show();context.data.$container.css({'top':context.config.$region.offset().top+context.config.$region.outerHeight(),'bottom':'auto','width':context.config.$region.outerWidth(),'height':'auto','left':context.config.$region.offset().left,'right':'auto'});var $results=context.data.$container.children('.suggestions-results');$results.empty();for(var i=0;i<context.config.suggestions.length;i++){$result=$('<div />').addClass('suggestions-result').attr('rel',i).data('text',context.config.suggestions[i]).appendTo($results);if(typeof context.config.result.render=='function'){context.config.result.render.call($result,context.config.suggestions[i]);}else{$result.text(context.config.suggestions[i]).autoEllipse();}}}}
37 -break;case'maxRows':context.config[property]=Math.max(1,Math.min(100,value));break;case'delay':context.config[property]=Math.max(0,Math.min(12000,value));break;case'submitOnClick':context.config[property]=value?true:false;break;}},highlight:function(context,result,updateTextbox){var selected=context.data.$container.find('.suggestions-result-current')
 36+$.suggestions.special(context);},special:function(context){if(typeof context.config.special.render=='function'){setTimeout(function(){$special=context.data.$container.find('.suggestions-special');context.config.special.render.call($special,context.data.$textbox.val());},1);}},configure:function(context,property,value){switch(property){case'fetch':case'cancel':case'special':case'result':case'$region':context.config[property]=value;break;case'suggestions':context.config[property]=value;if(typeof context.data!=='undefined'){if(typeof context.config.suggestions=='undefined'||context.config.suggestions.length==0){context.data.$container.hide();}else{context.data.$container.show();context.data.$container.css({'top':context.config.$region.offset().top+context.config.$region.outerHeight(),'bottom':'auto','width':context.config.$region.outerWidth(),'height':'auto','left':context.config.$region.offset().left,'right':'auto'});var $results=context.data.$container.children('.suggestions-results');$results.empty();for(var i=0;i<context.config.suggestions.length;i++){$result=$('<div />').addClass('suggestions-result').attr('rel',i).data('text',context.config.suggestions[i]).appendTo($results);if(typeof context.config.result.render=='function'){context.config.result.render.call($result,context.config.suggestions[i]);}else{$result.text(context.config.suggestions[i]).autoEllipse();}}}}
 37+break;case'maxRows':context.config[property]=Math.max(1,Math.min(100,value));break;case'delay':context.config[property]=Math.max(0,Math.min(1200,value));break;case'submitOnClick':context.config[property]=value?true:false;break;}},highlight:function(context,result,updateTextbox){var selected=context.data.$container.find('.suggestions-result-current')
3838 if(!result.get||selected.get(0)!=result.get(0)){if(result=='prev'){result=selected.prev();}else if(result=='next'){if(selected.size()==0)
3939 result=context.data.$container.find('.suggestions-results div:first');else{result=selected.next();if(result.size()==0)
4040 result=selected;}}
@@ -42,7 +42,7 @@
4343 $.suggestions.special(context);},keypress:function(e,context,key){var wasVisible=context.data.$container.is(':visible');var preventDefault=false;switch(key){case 40:if(wasVisible){$.suggestions.highlight(context,'next',true);}else{$.suggestions.update(context,false);}
4444 context.data.$textbox.trigger('change');preventDefault=true;break;case 38:if(wasVisible){$.suggestions.highlight(context,'prev',true);}
4545 context.data.$textbox.trigger('change');preventDefault=wasVisible;break;case 27:context.data.$container.hide();$.suggestions.restore(context);$.suggestions.cancel(context);context.data.$textbox.trigger('change');preventDefault=wasVisible;break;case 13:context.data.$container.hide();preventDefault=wasVisible;break;default:$.suggestions.update(context,true);break;}
46 -if(preventDefault){e.preventDefault();e.stopImmediatePropagation();}}};$.fn.suggestions=function(){var returnValue=null;var args=arguments;$(this).each(function(){var context=$(this).data('suggestions-context');if(typeof context=='undefined'){context={config:{'fetch':function(){},'cancel':function(){},'special':{},'result':{},'$region':$(this),'suggestions':[],'maxRows':7,'delay':1200,'submitOnClick':false}};}
 46+if(preventDefault){e.preventDefault();e.stopImmediatePropagation();}}};$.fn.suggestions=function(){var returnValue=null;var args=arguments;$(this).each(function(){var context=$(this).data('suggestions-context');if(typeof context=='undefined'){context={config:{'fetch':function(){},'cancel':function(){},'special':{},'result':{},'$region':$(this),'suggestions':[],'maxRows':7,'delay':120,'submitOnClick':false}};}
4747 if(args.length>0){if(typeof args[0]=='object'){for(key in args[0]){$.suggestions.configure(context,key,args[0][key]);}}else if(typeof args[0]=='string'){if(args.length>1){$.suggestions.configure(context,args[0],args[1]);}else if(returnValue==null){returnValue=(args[0]in context.config?undefined:context.config[args[0]]);}}}
4848 if(typeof context.data=='undefined'){context.data={'timerID':null,'prevText':null,'visibleResults':0,'mouseDownOn':$([]),'$textbox':$(this)};context.data.$container=$('<div />').css({'top':Math.round(context.data.$textbox.offset().top+context.data.$textbox.outerHeight()),'left':Math.round(context.data.$textbox.offset().left),'width':context.data.$textbox.outerWidth(),'display':'none'}).mouseover(function(e){$.suggestions.highlight(context,$(e.target).closest('.suggestions-results div'),false);}).addClass('suggestions').append($('<div />').addClass('suggestions-results').mousedown(function(e){context.data.mouseDownOn=$(e.target).closest('.suggestions-results div');}).mouseup(function(e){var $result=$(e.target).closest('.suggestions-results div');var $other=context.data.mouseDownOn;context.data.mouseDownOn=$([]);if($result.get(0)!=$other.get(0)){return;}
4949 $.suggestions.highlight(context,$result,true);context.data.$container.hide();if(typeof context.config.result.select=='function'){context.config.result.select.call($result,context.data.$textbox);}
@@ -118,7 +118,7 @@
119119 var label=$.wikiEditor.autoMsg(tool,'label');switch(tool.type){case'button':var src=tool.icon;if(src.indexOf('http://')!==0&&src.indexOf('https://')!==0){src=$.wikiEditor.imgPath+'toolbar/'+src;}
120120 $button=$('<img />').attr({'src':src,'width':22,'height':22,'alt':label,'title':label,'rel':id,'class':'tool tool-button'});if('action'in tool){$button.data('action',tool.action).data('context',context).click(function(){$.wikiEditor.modules.toolbar.fn.doAction($(this).data('context'),$(this).data('action'),$(this));return false;});}
121121 return $button;case'select':var $select=$('<div />').attr({'rel':id,'class':'tool tool-select'}).click(function(){var $options=$(this).find('.options');$options.animate({'opacity':'toggle'},'fast');});$options=$('<div />').addClass('options');if('list'in tool){for(option in tool.list){var optionLabel=$.wikiEditor.autoMsg(tool.list[option],'label');$options.append($('<a />').data('action',tool.list[option].action).data('context',context).click(function(){$.wikiEditor.modules.toolbar.fn.doAction($(this).data('context'),$(this).data('action'),$(this));}).text(optionLabel).addClass('option').attr('rel',option));}}
122 -$select.append($('<div />').addClass('menu').append($options));$select.append($('<div />').addClass('label').text(label));return $select;default:return null;}},buildBookmark:function(context,id,page){var label=$.wikiEditor.autoMsg(page,'label');return $('<div />').text(label).attr('rel',id).data('context',context).click(function(){$(this).parent().parent().find('.page').hide();$(this).parent().parent().find('.page-'+$(this).attr('rel')).show();$(this).siblings().removeClass('current');$(this).addClass('current');var section=$(this).parent().parent().attr('rel');if($.trackAction!=undefined){$.trackAction(section+'.'+$(this).attr('rel'));}
 122+$select.append($('<div />').addClass('menu').append($options));$select.append($('<div />').addClass('label').text(label));return $select;default:return null;}},buildBookmark:function(context,id,page){var label=$.wikiEditor.autoMsg(page,'label');return $('<div />').text(label).attr('rel',id).data('context',context).bind('mousedown',function(){$(this).parent().parent().find('.page').hide();$(this).parent().parent().find('.page-'+$(this).attr('rel')).show();$(this).siblings().removeClass('current');$(this).addClass('current');var section=$(this).parent().parent().attr('rel');if($.trackAction!=undefined){$.trackAction(section+'.'+$(this).attr('rel'));}
123123 $.cookie('wikiEditor-'+$(this).data('context').instance+'-booklet-'+section+'-page',$(this).attr('rel'));});},buildPage:function(context,id,page){var $page=$('<div />').attr({'class':'page page-'+id,'rel':id});switch(page.layout){case'table':$page.addClass('page-table');var html='<table cellpadding=0 cellspacing=0 '+'border=0 width="100%" class="table table-"'+id+'">';if('headings'in page){html+=$.wikiEditor.modules.toolbar.fn.buildHeading(context,page.headings)}
124124 if('rows'in page){for(row in page.rows){html+=$.wikiEditor.modules.toolbar.fn.buildRow(context,page.rows[row])}}
125125 $page.html(html);break;case'characters':$page.addClass('page-characters');$characters=$('<div />').data('context',context).data('actions',{});var actions=$characters.data('actions');if('language'in page){$characters.attr('lang',page.language);}
@@ -130,7 +130,7 @@
131131 return html;},buildRow:function(context,row){var html='<tr>';for(cell in row){html+='<td class="cell cell-'+cell+'" valign="top"><span>'+
132132 $.wikiEditor.autoMsg(row[cell],['html','text'])+'</span></td>';}
133133 html+='</tr>';return html;},buildCharacter:function(character,actions){if(typeof character=='string'){character={'label':character,'action':{'type':'encapsulate','options':{'pre':character}}};}else if(0 in character&&1 in character){character={'label':character[0],'action':{'type':'encapsulate','options':{'pre':character[1]}}};}
134 -if('action'in character&&'label'in character){actions[character.label]=character.action;return'<a rel="'+character.label+'" href="#">'+character.label+'</a>';}},buildTab:function(context,id,section){var selected=$.cookie('wikiEditor-'+context.instance+'-toolbar-section');return $('<span />').attr({'class':'tab tab-'+id,'rel':id}).append($('<a />').addClass(selected==id?'current':null).attr('href','#').text($.wikiEditor.autoMsg(section,'label')).data('context',context).click(function(){var $sections=$(this).data('context').$ui.find('.sections');var $section=$(this).data('context').$ui.find('.section-'+$(this).parent().attr('rel'));$(this).blur();var show=$section.css('display')=='none';$previousSections=$section.parent().find('.section:visible');$previousSections.css('position','absolute');$previousSections.fadeOut('fast',function(){$(this).css('position','relative');});$(this).parent().parent().find('a').removeClass('current');if(show){$section.fadeIn('fast');$sections.animate({'height':$section.outerHeight()},$section.outerHeight()*2);$(this).addClass('current');}else{$sections.animate({'height':0},$section.outerHeight()*2);}
 134+if('action'in character&&'label'in character){actions[character.label]=character.action;return'<a rel="'+character.label+'" href="#">'+character.label+'</a>';}},buildTab:function(context,id,section){var selected=$.cookie('wikiEditor-'+context.instance+'-toolbar-section');return $('<span />').attr({'class':'tab tab-'+id,'rel':id}).append($('<a />').addClass(selected==id?'current':null).attr('href','#').text($.wikiEditor.autoMsg(section,'label')).data('context',context).bind('mousedown',function(){var $sections=$(this).data('context').$ui.find('.sections');var $section=$(this).data('context').$ui.find('.section-'+$(this).parent().attr('rel'));$(this).blur();var show=$section.css('display')=='none';$previousSections=$section.parent().find('.section:visible');$previousSections.css('position','absolute');$previousSections.fadeOut('fast',function(){$(this).css('position','relative');});$(this).parent().parent().find('a').removeClass('current');if(show){$section.fadeIn('fast');$sections.animate({'height':$section.outerHeight()},$section.outerHeight()*2);$(this).addClass('current');}else{$sections.animate({'height':0},$section.outerHeight()*2);}
135135 if($.trackAction!=undefined){$.trackAction($section.attr('rel')+'.'+(show?'show':'hide'));}
136136 $.cookie('wikiEditor-'+$(this).data('context').instance+'-toolbar-section',show?$section.attr('rel'):null);return false;}));},buildSection:function(context,id,section){context.$textarea.trigger('wikiEditor-toolbar-buildSection-'+id,[section]);var selected=$.cookie('wikiEditor-'+context.instance+'-toolbar-section');var $section;switch(section.type){case'toolbar':var $section=$('<div />').attr({'class':'toolbar section section-'+id,'rel':id});if('groups'in section){for(group in section.groups){$section.append($.wikiEditor.modules.toolbar.fn.buildGroup(context,group,section.groups[group]));}}
137137 break;case'booklet':var $pages=$('<div />').addClass('pages');var $index=$('<div />').addClass('index');if('pages'in section){for(page in section.pages){$pages.append($.wikiEditor.modules.toolbar.fn.buildPage(context,page,section.pages[page]));$index.append($.wikiEditor.modules.toolbar.fn.buildBookmark(context,page,section.pages[page]));}}

Status & tagging log