http://www.mediawiki.org/wiki/Special:Code/MediaWiki/60546
Revision: 60546 Author: catrope Date: 2010-01-01 20:40:33 +0000 (Fri, 01 Jan 2010) Log Message: ----------- UsabilityInitiative: Delay parsing for 250 ms, fix an issue with the prevent-BRs-from-getting-wrapped code Modified Paths: -------------- trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html trunk/extensions/UsabilityInitiative/js/plugins.combined.js trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js Modified: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php =================================================================== --- trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php 2010-01-01 19:49:37 UTC (rev 60545) +++ trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php 2010-01-01 20:40:33 UTC (rev 60546) @@ -73,7 +73,7 @@ array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 6 ), array( 'src' => 'js/plugins/jquery.textSelection.js', 'version' => 21 ), array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 41 ), - array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 10 ), + array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 11 ), array( 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', 'version' => 40 ), array( 'src' => 'js/plugins/jquery.wikiEditor.dialogs.js', 'version' => 10 ), array( 'src' => 'js/plugins/jquery.wikiEditor.toc.js', 'version' => 55 ), @@ -82,10 +82,10 @@ array( 'src' => 'js/plugins/jquery.wikiEditor.publish.js', 'version' => 1 ), ), 'combined' => array( - array( 'src' => 'js/plugins.combined.js', 'version' => 128 ), + array( 'src' => 'js/plugins.combined.js', 'version' => 129 ), ), 'minified' => array( - array( 'src' => 'js/plugins.combined.min.js', 'version' => 128 ), + array( 'src' => 'js/plugins.combined.min.js', 'version' => 129 ), ), ), ); Modified: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js =================================================================== --- trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js 2010-01-01 19:49:37 UTC (rev 60545) +++ trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js 2010-01-01 20:40:33 UTC (rev 60546) @@ -11,7 +11,7 @@ * Internally used event handlers */ evt: { - change: function( context, event ) { + delayedChange: function( context, event ) { /* * Triggered on any of the following events, with the intent on detecting if something was added, deleted or * replaced due to user action. @@ -167,6 +167,7 @@ var i = 0; // index for markers[] var startNode = null; var depth = 0, nextDepth = 0, startDepth = null; + var lastTextNode = null, lastTextNodeDepth = null; // Find the leftmost leaf node in the tree while ( node.firstChild ) { node = node.firstChild; @@ -201,6 +202,10 @@ continue; } var newPos = node.nodeName == '#text' ? pos + node.nodeValue.length : pos + 1; + if ( node.nodeName == '#text' ) { + lastTextNode = node; + lastTextNodeDepth = depth; + } // We want to isolate each marker, so we may need to split textNodes // if a marker starts or end halfway one. if ( !startNode && markers[i].start >= pos && markers[i].start < newPos ) { @@ -218,6 +223,11 @@ startNode = node; startDepth = depth; } + // Don't wrap BRs, produces undesirable results + if ( startNode && startNode.nodeName == 'BR' ) { + startNode = node; + startDepth = depth; + } // TODO: What happens when wrapping a zero-length string? if ( startNode && markers[i].end > pos && markers[i].end <= newPos ) { // The marker ends somewhere in this textNode or at this BR @@ -233,12 +243,11 @@ } // Don't wrap leading or trailing BRs, doing that causes weird issues - var endNode = node; - while ( startNode.nodeName == 'BR' && startNode != endNode ) - startNode = startNode.nextSibling; - - while ( endNode.nodeName == 'BR' && endNode != startNode ) - endNode = endNode.previousSibling; + var endNode = node, endDepth = depth; + if ( endNode.nodeName == 'BR' ) { + endNode = lastTextNode; + endDepth = lastTextNodeDepth; + } // Now wrap everything between startNode and endNode (may be equal). First find the common ancestor of // startNode and endNode. ca1 and ca2 will be children of this common ancestor, such that ca1 is an @@ -247,13 +256,13 @@ // can't cleanly wrap things without misnesting and we silently fail. var ca1 = startNode, ca2 = endNode; // Correct for startNode and node possibly not having the same depth - if ( startDepth > depth ) { - for ( var j = 0; j < startDepth - depth && ca1; j++ ) { + if ( startDepth > endDepth ) { + for ( var j = 0; j < startDepth - endDepth && ca1; j++ ) { ca1 = ca1.parentNode.firstChild == ca1 ? ca1.parentNode : null; } } - else if ( startDepth < depth ) { - for ( var j = 0; j < depth - startDepth && ca2; j++ ) { + else if ( startDepth < endDepth ) { + for ( var j = 0; j < endDepth - startDepth && ca2; j++ ) { ca2 = ca2.parentNode.lastChild == ca2 ? ca2.parentNode : null; } } Modified: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html =================================================================== --- trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html 2010-01-01 19:49:37 UTC (rev 60545) +++ trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html 2010-01-01 20:40:33 UTC (rev 60546) @@ -12,9 +12,13 @@ return v == null ? '' : v[1]; } var context = window.parent.jQuery.wikiEditor.instances[get( 'instance' )].data( 'wikiEditor-context' ); - $j( document ).bind( "keydown keypress keyup mousedown mouseup cut paste", function( event ) { - context.fn.trigger( "change", event ) - } ); + $j( document ) + .bind( "keydown keypress keyup mousedown mouseup cut paste", function( event ) { + context.fn.trigger( "change", event ); + } ) + .delayedBind( 250, "keydown keypress keyup mousedown mouseup cut paste", function( event ) { + context.fn.trigger( "delayedChange", event ); + } ); } ); </script> </head> Modified: trunk/extensions/UsabilityInitiative/js/plugins.combined.js =================================================================== --- trunk/extensions/UsabilityInitiative/js/plugins.combined.js 2010-01-01 19:49:37 UTC (rev 60545) +++ trunk/extensions/UsabilityInitiative/js/plugins.combined.js 2010-01-01 20:40:33 UTC (rev 60546) @@ -2168,7 +2168,7 @@ * Internally used event handlers */ evt: { - change: function( context, event ) { + delayedChange: function( context, event ) { /* * Triggered on any of the following events, with the intent on detecting if something was added, deleted or * replaced due to user action. @@ -2324,6 +2324,7 @@ var i = 0; // index for markers[] var startNode = null; var depth = 0, nextDepth = 0, startDepth = null; + var lastTextNode = null, lastTextNodeDepth = null; // Find the leftmost leaf node in the tree while ( node.firstChild ) { node = node.firstChild; @@ -2358,6 +2359,10 @@ continue; } var newPos = node.nodeName == '#text' ? pos + node.nodeValue.length : pos + 1; + if ( node.nodeName == '#text' ) { + lastTextNode = node; + lastTextNodeDepth = depth; + } // We want to isolate each marker, so we may need to split textNodes // if a marker starts or end halfway one. if ( !startNode && markers[i].start >= pos && markers[i].start < newPos ) { @@ -2375,6 +2380,11 @@ startNode = node; startDepth = depth; } + // Don't wrap BRs, produces undesirable results + if ( startNode && startNode.nodeName == 'BR' ) { + startNode = node; + startDepth = depth; + } // TODO: What happens when wrapping a zero-length string? if ( startNode && markers[i].end > pos && markers[i].end <= newPos ) { // The marker ends somewhere in this textNode or at this BR @@ -2390,12 +2400,11 @@ } // Don't wrap leading or trailing BRs, doing that causes weird issues - var endNode = node; - while ( startNode.nodeName == 'BR' && startNode != endNode ) - startNode = startNode.nextSibling; - - while ( endNode.nodeName == 'BR' && endNode != startNode ) - endNode = endNode.previousSibling; + var endNode = node, endDepth = depth; + if ( endNode.nodeName == 'BR' ) { + endNode = lastTextNode; + endDepth = lastTextNodeDepth; + } // Now wrap everything between startNode and endNode (may be equal). First find the common ancestor of // startNode and endNode. ca1 and ca2 will be children of this common ancestor, such that ca1 is an @@ -2404,13 +2413,13 @@ // can't cleanly wrap things without misnesting and we silently fail. var ca1 = startNode, ca2 = endNode; // Correct for startNode and node possibly not having the same depth - if ( startDepth > depth ) { - for ( var j = 0; j < startDepth - depth && ca1; j++ ) { + if ( startDepth > endDepth ) { + for ( var j = 0; j < startDepth - endDepth && ca1; j++ ) { ca1 = ca1.parentNode.firstChild == ca1 ? ca1.parentNode : null; } } - else if ( startDepth < depth ) { - for ( var j = 0; j < depth - startDepth && ca2; j++ ) { + else if ( startDepth < endDepth ) { + for ( var j = 0; j < endDepth - startDepth && ca2; j++ ) { ca2 = ca2.parentNode.lastChild == ca2 ? ca2.parentNode : null; } } Modified: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js =================================================================== --- trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js 2010-01-01 19:49:37 UTC (rev 60545) +++ trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js 2010-01-01 20:40:33 UTC (rev 60546) @@ -125,23 +125,24 @@ configuration.newButtons[gM(msg)]=configuration.buttons[msg];configuration.buttons=configuration.newButtons;var dialogDiv=$('<div /> ').attr('id',module.id).html(module.html).data('context',context).appendTo($('body')).each(module.init).dialog(configuration);if(!('resizeme'in module)||module.resizeme){dialogDiv.bind('dialogopen',$.wikiEditor.modules.dialogs.fn.resize).find('.ui-tabs').bind('tabsshow',function(){$(this).closest('.ui-dialog-content').each($.wikiEditor.modules.dialogs.fn.resize);});} var maxTI=0;$j('[tabindex]').each(function(){var ti=parseInt($j(this).attr('tabindex'));if(ti>maxTI) maxTI=ti;});var tabIndex=maxTI+1;$j('.ui-dialog input, .ui-dialog button').not('[tabindex]').each(function(){$j(this).attr('tabindex',tabIndex++);});}}});},resize:function(){var wrapper=$(this).closest('.ui-dialog');var oldWidth=wrapper.width();var oldHidden=$(this).find('*').not(':visible');oldHidden.each(function(){$(this).data('oldstyle',$(this).attr('style'));});oldHidden.show();var oldWS=$(this).css('white-space');$(this).css('white-space','nowrap');if(wrapper.width()<=$(this).get(0).scrollWidth){var thisWidth=$(this).data('thisWidth')?$(this).data('thisWidth'):0;thisWidth=Math.max($(this).get(0).scrollWidth,thisWidth);$(this).width(thisWidth);$(this).data('thisWidth',thisWidth);var wrapperWidth=$(this).data('wrapperWidth')?$(this).data('wrapperWidth'):0;wrapperWidth=Math.max(wrapper.get(0).scrollWidth,wrapperWidth);wrapper.width(wrapperWidth);$(this).data('wrapperWidth',wrapperWidth);$(this).dialog({'width':wrapper.width()});wrapper.css('left',parseInt(wrapper.css('left'))-(wrapper.width()-oldWidth)/2);} -$(this).css('white-space',oldWS);oldHidden.each(function(){$(this).attr('style',$(this).data('oldstyle'));});}},modules:{},quickDialog:function(body,settings){$('<div />').text(body).appendTo($('body')).dialog($.extend({bgiframe:true,modal:true},settings)).dialog('open');}};})(jQuery);(function($){$.wikiEditor.modules.highlight={cfg:{'styleVersion':2},evt:{change:function(context,event){if(event.data.scope=='none'){$.wikiEditor.modules.highlight.fn.scan(context,"");$.wikiEditor.modules.highlight.fn.mark(context,"","");}},ready:function(context,event){context.$content.parent().find('head').append($j('<link />').attr({'rel':'stylesheet','type':'text/css','href':wgScriptPath+'/extensions/UsabilityInitiative/css/wikiEditor.highlight.css?'+ +$(this).css('white-space',oldWS);oldHidden.each(function(){$(this).attr('style',$(this).data('oldstyle'));});}},modules:{},quickDialog:function(body,settings){$('<div />').text(body).appendTo($('body')).dialog($.extend({bgiframe:true,modal:true},settings)).dialog('open');}};})(jQuery);(function($){$.wikiEditor.modules.highlight={cfg:{'styleVersion':2},evt:{delayedChange:function(context,event){if(event.data.scope=='none'){$.wikiEditor.modules.highlight.fn.scan(context,"");$.wikiEditor.modules.highlight.fn.mark(context,"","");}},ready:function(context,event){context.$content.parent().find('head').append($j('<link />').attr({'rel':'stylesheet','type':'text/css','href':wgScriptPath+'/extensions/UsabilityInitiative/css/wikiEditor.highlight.css?'+ $.wikiEditor.modules.highlight.cfg.styleVersion,}));$.wikiEditor.modules.highlight.fn.scan(context,"");$.wikiEditor.modules.highlight.fn.mark(context,"","");}},fn:{create:function(context,config){},divide:function(context){},isolate:function(context){return[];},strip:function(context,division){return $('<div />').html(division.html().replace(/\<br[^\>]*\>/g,"\n")).text();},scan:function(context,division){function Token(offset,label,tokenStart,match){this.offset=offset;this.label=label;this.tokenStart=tokenStart;this.match=match;} var tokenArray=context.modules.highlight.tokenArray=[];var text=context.fn.getContents();for(module in $.wikiEditor.modules){if('exp'in $.wikiEditor.modules[module]){for(var i=0;i<$.wikiEditor.modules[module].exp.length;i++){var regex=$.wikiEditor.modules[module].exp[i].regex;var label=$.wikiEditor.modules[module].exp[i].label;var markAfter=false;if(typeof $.wikiEditor.modules[module].exp[i].markAfter!='undefined'){markAfter=true;} match=text.match(regex);var oldOffset=0;while(match!=null){var markOffset=0;var tokenStart=match.index+oldOffset+markOffset;if(markAfter){markOffset+=match[0].length;} tokenArray.push(new Token(match.index+oldOffset+markOffset,label,tokenStart,match));oldOffset+=match.index+match[0].length;newSubstring=text.substring(oldOffset);match=newSubstring.match(regex);}}}} -tokenArray.sort(function(a,b){return a.offset-b.offset||a.tokenStart-b.tokenStart;});context.fn.trigger('scan');},mark:function(context,division,tokens){var markers=context.modules.highlight.markers=[];context.fn.trigger('mark');markers.sort(function(a,b){return a.start-b.start||a.end-b.end;});var pos=0;var node=context.$content.get(0);var next=null;var i=0;var startNode=null;var depth=0,nextDepth=0,startDepth=null;while(node.firstChild){node=node.firstChild;depth++;while(node&&$(node).hasClass('wikiEditor-noinclude')){node=node.nextSibling;}} +tokenArray.sort(function(a,b){return a.offset-b.offset||a.tokenStart-b.tokenStart;});context.fn.trigger('scan');},mark:function(context,division,tokens){var markers=context.modules.highlight.markers=[];context.fn.trigger('mark');markers.sort(function(a,b){return a.start-b.start||a.end-b.end;});var pos=0;var node=context.$content.get(0);var next=null;var i=0;var startNode=null;var depth=0,nextDepth=0,startDepth=null;var lastTextNode=null,lastTextNodeDepth=null;while(node.firstChild){node=node.firstChild;depth++;while(node&&$(node).hasClass('wikiEditor-noinclude')){node=node.nextSibling;}} while(i<markers.length&&node){var p=node;nextDepth=depth;while(p&&!p.nextSibling){p=p.parentNode;nextDepth--;} p=p?p.nextSibling:null;while(p&&$(p).hasClass('wikiEditor-noinclude')){p=p.nextSibling;} while(p&&p.firstChild){p=p.firstChild;nextDepth++;} next=p;if(node.nodeName!='#text'&&node.nodeName!='BR'){node=next;depth=nextDepth;continue;} -var newPos=node.nodeName=='#text'?pos+node.nodeValue.length:pos+1;if(!startNode&&markers[i].start>=pos&&markers[i].start<newPos){if(markers[i].start>pos){node=node.splitText(markers[i].start-pos);pos=markers[i].start;} +var newPos=node.nodeName=='#text'?pos+node.nodeValue.length:pos+1;if(node.nodeName=='#text'){lastTextNode=node;lastTextNodeDepth=depth;} +if(!startNode&&markers[i].start>=pos&&markers[i].start<newPos){if(markers[i].start>pos){node=node.splitText(markers[i].start-pos);pos=markers[i].start;} startNode=node;startDepth=depth;} +if(startNode&&startNode.nodeName=='BR'){startNode=node;startDepth=depth;} if(startNode&&markers[i].end>pos&&markers[i].end<=newPos){if(markers[i].end<newPos){next=node.splitText(node.nodeValue.length-newPos+markers[i].end);newPos=markers[i].end;} -var endNode=node;while(startNode.nodeName=='BR'&&startNode!=endNode) -startNode=startNode.nextSibling;while(endNode.nodeName=='BR'&&endNode!=startNode) -endNode=endNode.previousSibling;var ca1=startNode,ca2=endNode;if(startDepth>depth){for(var j=0;j<startDepth-depth&&ca1;j++){ca1=ca1.parentNode.firstChild==ca1?ca1.parentNode:null;}} -else if(startDepth<depth){for(var j=0;j<depth-startDepth&&ca2;j++){ca2=ca2.parentNode.lastChild==ca2?ca2.parentNode:null;}} +var endNode=node,endDepth=depth;if(endNode.nodeName=='BR'){endNode=lastTextNode;endDepth=lastTextNodeDepth;} +var ca1=startNode,ca2=endNode;if(startDepth>endDepth){for(var j=0;j<startDepth-endDepth&&ca1;j++){ca1=ca1.parentNode.firstChild==ca1?ca1.parentNode:null;}} +else if(startDepth<endDepth){for(var j=0;j<endDepth-startDepth&&ca2;j++){ca2=ca2.parentNode.lastChild==ca2?ca2.parentNode:null;}} while(ca1&&ca2&&ca1.parentNode!=ca2.parentNode){ca1=ca1.parentNode.firstChild==ca1?ca1.parentNode:null;ca2=ca2.parentNode.lastChild==ca2?ca2.parentNode:null;} if(ca1&&ca2){var wrapper=markers[i].getWrapper(ca1,ca2);if(!wrapper){var newNode=ca1.ownerDocument.createElement('div');var commonAncestor=ca1.parentNode;var nextNode=ca2.nextSibling;var n=ca1;while(n!=nextNode){var ns=n.nextSibling;newNode.appendChild(n);n=ns;} if(nextNode){commonAncestor.insertBefore(newNode,nextNode);}else{commonAncestor.appendChild(newNode);} _______________________________________________ MediaWiki-CVS mailing list MediaWiki-CVS@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs