http://www.mediawiki.org/wiki/Special:Code/MediaWiki/54935
Revision: 54935 Author: catrope Date: 2009-08-13 14:07:02 +0000 (Thu, 13 Aug 2009) Log Message: ----------- EditToolbar: Add AJAX page existence check widget to link CGD, and put labels and textboxes on the same line Modified Paths: -------------- trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.hooks.php trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.i18n.php trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.php Added Paths: ----------- trunk/extensions/UsabilityInitiative/images/wikiEditor/toolbar/insert-link-exists.png trunk/extensions/UsabilityInitiative/images/wikiEditor/toolbar/insert-link-invalid.png trunk/extensions/UsabilityInitiative/images/wikiEditor/toolbar/insert-link-notexists.png Modified: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.hooks.php =================================================================== --- trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.hooks.php 2009-08-13 12:48:01 UTC (rev 54934) +++ trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.hooks.php 2009-08-13 14:07:02 UTC (rev 54935) @@ -67,6 +67,10 @@ 'edittoolbar-tool-link-ext-text', 'edittoolbar-tool-link-insert', 'edittoolbar-tool-link-cancel', + 'edittoolbar-link-int-target-status-exists', + 'edittoolbar-link-int-target-status-notexists', + 'edittoolbar-link-int-target-status-invalid', + 'edittoolbar-link-int-target-status-loading', 'edittoolbar-tool-file', 'edittoolbar-tool-file-pre', 'edittoolbar-tool-file-example', Modified: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.i18n.php =================================================================== --- trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.i18n.php 2009-08-13 12:48:01 UTC (rev 54934) +++ trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.i18n.php 2009-08-13 14:07:02 UTC (rev 54935) @@ -31,6 +31,10 @@ 'edittoolbar-tool-link-ext-text' => 'Link text:', 'edittoolbar-tool-link-insert' => 'Insert link', 'edittoolbar-tool-link-cancel' => 'Cancel', + 'edittoolbar-link-int-target-status-exists' => 'Page exists', + 'edittoolbar-link-int-target-status-notexists' => 'Page does not exist', + 'edittoolbar-link-int-target-status-invalid' => 'Invalid title', + 'edittoolbar-link-int-target-status-loading' => 'Checking page existence...', 'edittoolbar-tool-file' => 'Embedded file', 'edittoolbar-tool-file-pre' => '$1{{ns:file}}:', 'edittoolbar-tool-file-example' => 'Example.jpg', @@ -188,6 +192,10 @@ 'edittoolbar-tool-bold-example' => '{{Identical|Bold text}}', 'edittoolbar-tool-italic' => '{{Identical|Italic}}', 'edittoolbar-tool-italic-example' => '{{Identical|Italic text}}', + 'edittoolbar-link-int-target-status-exists' => 'alt text and title text for the image shown when the title the user entered exists', + 'edittoolbar-link-int-target-status-notexists' => 'alt text and title text for the image shown when the title the user entered does not exist', + 'edittoolbar-link-int-target-status-invalid' => 'alt text and title text for the image shown when the title the user entered is invalid', + 'edittoolbar-link-int-target-status-loading' => 'alt text and title text for the image shown while the title the user entered is being checked for existence', 'edittoolbar-tool-reference' => '{{Identical|Reference}}', 'edittoolbar-group-list' => '{{Identical|List}}', 'edittoolbar-group-size' => '{{Identical|Size}}', Modified: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js =================================================================== --- trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js 2009-08-13 12:48:01 UTC (rev 54934) +++ trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.js 2009-08-13 14:07:02 UTC (rev 54935) @@ -69,12 +69,16 @@ titleMsg: 'edittoolbar-tool-link-title', id: 'edittoolbar-link-dialog', // TODO: break this line - html: '<div id="edittoolbar-link-tabs"><ul><li><a href="#edittoolbar-link-dialog-tab-int" rel="edittoolbar-tool-link-int"></a></li><li><a href="#edittoolbar-link-dialog-tab-ext" rel="edittoolbar-tool-link-ext"></a></li></ul><div id="edittoolbar-link-dialog-tab-int"><form><label for="edittoolbar-link-int-target" rel="edittoolbar-tool-link-int-target"></label><input type="text" id="edittoolbar-link-int-target" style="display:block;" /><label for="edittoolbar-link-int-text" rel="edittoolbar-tool-link-int-text"></label><input type="text" id="edittoolbar-link-int-text" style="display:block;" /></form></div><div id="edittoolbar-link-dialog-tab-ext"><form><label for="edittoolbar-link-ext-target" rel="edittoolbar-tool-link-ext-target"></label><input type="text" id="edittoolbar-link-ext-target" style="display:block;" /><label for="edittoolbar-link-ext-text" rel="edittoolbar-tool-link-ext-text"></label><input type="text" id="edittoolbar-link-ext-text" style="display:block;" /></form></div></div>', + html: '<div id="edittoolbar-link-tabs"><ul><li><a href="#edittoolbar-link-dialog-tab-int" rel="edittoolbar-tool-link-int"></a></li><li><a href="#edittoolbar-link-dialog-tab-ext" rel="edittoolbar-tool-link-ext"></a></li></ul><div id="edittoolbar-link-dialog-tab-int"><form><label for="edittoolbar-link-int-target" rel="edittoolbar-tool-link-int-target"></label> <input type="text" id="edittoolbar-link-int-target" /> <div id="edittoolbar-link-int-target-status" style="display: inline;"></div><br /><label for="edittoolbar-link-int-text" rel="edittoolbar-tool-link-int-text"></label> <input type="text" id="edittoolbar-link-int-text" /></form></div><div id="edittoolbar-link-dialog-tab-ext"><form><label for="edittoolbar-link-ext-target" rel="edittoolbar-tool-link-ext-target"></label> <input type="text" id="edittoolbar-link-ext-target" /><br /><label for="edittoolbar-link-ext-text" rel="edittoolbar-tool-link-ext-text"></label> <input type="text" id="edittoolbar-link-ext-text" /></form></div></div>', init: function() { $j(this).find( '[rel]' ).each( function() { $j(this).html( gM( $j(this).attr( 'rel' ) ) ); }); $j( '#edittoolbar-link-tabs' ).tabs(); + + // Link int-target and int-text fields + // This means mirroring the contents of int-target in int-text + // as long as int-text itself hasn't been changed by the user $j( '#edittoolbar-link-int-target' ).bind( 'keypress paste', function() { // $j(this).val() is the old value, before the keypress if ( $j( '#edittoolbar-link-int-text' ).data( 'untouched' ) ) @@ -84,6 +88,99 @@ $j( '#edittoolbar-link-int-text' ).bind( 'keypress paste', function() { $j(this).data( 'untouched', false ); }); + + // Page existence check widget + var existsImg = $j.wikiEditor.modules.toolbar.imgPath + 'insert-link-exists.png'; + var notexistsImg = $j.wikiEditor.modules.toolbar.imgPath + 'insert-link-notexists.png'; + var invalidImg = $j.wikiEditor.modules.toolbar.imgPath + 'insert-link-invalid.png'; + var loadingImg = $j.wikiEditor.modules.toolbar.imgPath + 'loading.gif'; + var existsMsg = gM( 'edittoolbar-link-int-target-status-exists' ); + var notexistsMsg = gM( 'edittoolbar-link-int-target-status-notexists' ); + var invalidMsg = gM( 'edittoolbar-link-int-target-status-invalid' ); + var loadingMsg = gM( 'edittoolbar-link-int-target-status-loading' ); + $j( '#edittoolbar-link-int-target-status' ) + .html( '<img id="edittoolbar-link-int-target-status-exists" src="' + existsImg + '" alt="' + existsMsg + '" title="' + existsMsg + '" />' + + '<img id="edittoolbar-link-int-target-status-notexists" src="' + notexistsImg + '" alt="' + notexistsMsg + '" title="' + notexistsMsg + '" />' + + '<img id="edittoolbar-link-int-target-status-invalid" src="' + invalidImg + '" alt="' + invalidMsg + '" title="' + invalidMsg + '" />' + + '<img id="edittoolbar-link-int-target-status-loading" src="' + loadingImg + '" alt="' + loadingMsg + '" title="' + loadingMsg + '" />' ) + .data( 'cache', {} ) + .children().hide(); + + function updateExistence( target ) { + function updateWidget( status ) { + $j( '#edittoolbar-link-int-target-status' ).children().hide(); + $j( '#edittoolbar-link-int-target-status-' + status ).show(); + } + + // Abort previous request + var request = $j( '#edittoolbar-link-int-target-status' ).data( 'request' ); + if ( request ) + request.abort(); + + var target = $j( '#edittoolbar-link-int-target' ).val(); + var cache = $j( '#edittoolbar-link-int-target-status' ).data( 'cache' ); + if ( cache[target] ) { + updateWidget( cache[target] ); + return; + } + + if ( target == '' ) { + // Hide the widget when the textbox is empty + $j( '#edittoolbar-link-int-target-status' ).children().hide(); + return; + } + if ( target.indexOf( '|' ) != -1 ) { + // Title contains | , which means it's invalid + // but confuses the API. Show invalid and bypass API + updateWidget( 'invalid' ); + return; + } + + updateWidget( 'loading' ); + var request = $j.ajax( { + url: wgScriptPath + '/api.php', + dataType: 'json', + data: { + 'action': 'query', + 'indexpageids': '', + 'titles': target, + 'format': 'json' + }, + success: function( data ) { + // TODO: What happens if data.query.pageids is undefined? + var page = data.query.pages[data.query.pageids[0]]; + var status = 'exists'; + if ( typeof page.missing != 'undefined' ) + status = 'notexists'; + else if ( typeof page.invalid != 'undefined' ) + status = 'invalid'; + + cache[target] = status; + updateWidget( status ); + } + }); + // Save request object so it can be aborted if necessary + $j( '#edittoolbar-link-int-target-status' ).data( 'request', request ); + } + + $j( '#edittoolbar-link-int-target' ).bind( 'keypress paste', function() { + // Cancel the running timer if applicable + if ( typeof $j(this).data( 'timerID' ) != 'undefined' ) + clearTimeout( $j(this).data( 'timerID' ) ); + + // Delay fetch for a while + // FIXME: Make 250 configurable elsewhere + var timerID = setTimeout( updateExistence, 250 ); + $j(this).data( 'timerID', timerID ); + }); + $j( '#edittoolbar-link-int-target' ).change( function() { + // Cancel the running timer if applicable + if ( typeof $j(this).data( 'timerID' ) != 'undefined' ) + clearTimeout( $j(this).data( 'timerID' ) ); + + // Fetch right now + updateExistence(); + }); }, dialog: { width: 550, // FIXME: autoresize width @@ -105,7 +202,7 @@ switch ( $j( '#edittoolbar-link-tabs' ).tabs( 'option', 'selected' ) ) { case 0: // Internal link // TODO: Escape this stuff - // TODO: Verify internal target validity + // TODO: Refuse to insert links to invalid titles insertText = '[[' + $j( '#edittoolbar-link-int-target' ).val() + '|' + @@ -138,9 +235,11 @@ }, open: function() { // Pre-fill text fields + // val() doesn't trigger the change event, so let's do that ourselves $j( '#edittoolbar-link-int-text, #edittoolbar-link-ext-text, #edittoolbar-link-int-target' ) - .val( $j(this).data( 'context' ).$textarea.getSelection() ); - $j( '#edittoolbar-link-ext-target' ).val( 'http://' ); + .val( $j(this).data( 'context' ).$textarea.getSelection() ) + .change(); + $j( '#edittoolbar-link-ext-target' ).val( 'http://' ).change(); $j( '#edittoolbar-link-int-text' ).data( 'untouched', true ); } } @@ -399,13 +498,14 @@ titleMsg: 'edittoolbar-tool-replace-title', id: 'edittoolbar-replace-dialog', // TODO: break this line - html: '<form><fieldset><label for="edittoolbar-replace-search" rel="edittoolbar-tool-replace-search"></label><input type="text" id="edittoolbar-replace-search" style="display:block;" /><label for="edittoolbar-replace-replace" rel="edittoolbar-tool-replace-replace"></label><input type="text" id="edittoolbar-replace-replace" style="display:block;" /><input type="checkbox" id="edittoolbar-replace-case" /><label for="edittoolbar-replace-case" rel="edittoolbar-tool-replace-case"></label><br /><input type="checkbox" id="edittoolbar-replace-regex" /><label for="edittoolbar-replace-regex" rel="edittoolbar-tool-replace-regex"></label><br /><input type="checkbox" id="edittoolbar-replace-all" /><label for="edittoolbar-replace-all" rel="edittoolbar-tool-replace-all"></label></fieldset></form>', + html: '<form><fieldset><label for="edittoolbar-replace-search" rel="edittoolbar-tool-replace-search"></label> <input type="text" id="edittoolbar-replace-search" /><br /><label for="edittoolbar-replace-replace" rel="edittoolbar-tool-replace-replace"></label> <input type="text" id="edittoolbar-replace-replace" /><br /><input type="checkbox" id="edittoolbar-replace-case" /><label for="edittoolbar-replace-case" rel="edittoolbar-tool-replace-case"></label><br /><input type="checkbox" id="edittoolbar-replace-regex" /><label for="edittoolbar-replace-regex" rel="edittoolbar-tool-replace-regex"></label><br /><input type="checkbox" id="edittoolbar-replace-all" /><label for="edittoolbar-replace-all" rel="edittoolbar-tool-replace-all"></label></fieldset></form>', init: function() { $j(this).find( '[rel]' ).each( function() { $j(this).html( gM( $j(this).attr( 'rel' ) ) ); }); }, dialog: { + width: 350, // FIXME: autoresize width buttons: { 'edittoolbar-tool-replace-button': function() { var searchStr = $j( '#edittoolbar-replace-search' ).val(); Modified: trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.php =================================================================== --- trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.php 2009-08-13 12:48:01 UTC (rev 54934) +++ trunk/extensions/UsabilityInitiative/EditToolbar/EditToolbar.php 2009-08-13 14:07:02 UTC (rev 54935) @@ -19,7 +19,7 @@ /* Configuration */ // Bump the version number every time you change any of the .css/.js files -$wgEditToolbarStyleVersion = 21; +$wgEditToolbarStyleVersion = 22; // Set this to true to simply override the stock toolbar for everyone $wgEditToolbarGlobalEnable = false; Added: trunk/extensions/UsabilityInitiative/images/wikiEditor/toolbar/insert-link-exists.png =================================================================== (Binary files differ) Property changes on: trunk/extensions/UsabilityInitiative/images/wikiEditor/toolbar/insert-link-exists.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: trunk/extensions/UsabilityInitiative/images/wikiEditor/toolbar/insert-link-invalid.png =================================================================== (Binary files differ) Property changes on: trunk/extensions/UsabilityInitiative/images/wikiEditor/toolbar/insert-link-invalid.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: trunk/extensions/UsabilityInitiative/images/wikiEditor/toolbar/insert-link-notexists.png =================================================================== (Binary files differ) Property changes on: trunk/extensions/UsabilityInitiative/images/wikiEditor/toolbar/insert-link-notexists.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream _______________________________________________ MediaWiki-CVS mailing list MediaWiki-CVS@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs