r62345 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r62344‎ | r62345 | r62346 >
Date:23:33, 11 February 2010
Author:adam
Status:ok (Comments)
Tags:
Comment:
Adding caret position saving to our undo management code and improving the general logic of undo/redo
Modified paths:
  • /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.wikiEditor.js (modified) (history)

Diff [purge]

Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php
@@ -72,7 +72,7 @@
7373 array( 'src' => 'js/plugins/jquery.namespaceSelect.js', 'version' => 1 ),
7474 array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 7 ),
7575 array( 'src' => 'js/plugins/jquery.textSelection.js', 'version' => 27 ),
76 - array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 123 ),
 76+ array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 124 ),
7777 array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 29 ),
7878 array( 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', 'version' => 48 ),
7979 array( 'src' => 'js/plugins/jquery.wikiEditor.dialogs.js', 'version' => 12 ),
@@ -82,10 +82,10 @@
8383 array( 'src' => 'js/plugins/jquery.wikiEditor.publish.js', 'version' => 2 ),
8484 ),
8585 'combined' => array(
86 - array( 'src' => 'js/plugins.combined.js', 'version' => 243 ),
 86+ array( 'src' => 'js/plugins.combined.js', 'version' => 244 ),
8787 ),
8888 'minified' => array(
89 - array( 'src' => 'js/plugins.combined.min.js', 'version' => 243 ),
 89+ array( 'src' => 'js/plugins.combined.min.js', 'version' => 244 ),
9090 ),
9191 ),
9292 );
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js
@@ -297,24 +297,31 @@
298298 if ( ( event.ctrlKey || event.metaKey ) && context.history.length ) {
299299 // HistoryPosition is a negative number between -1 and -context.history.length, in other words
300300 // it's the number of steps backwards from the latest state.
 301+ var newPosition;
301302 if ( event.shiftKey ) {
302303 // Redo
303 - context.historyPosition++;
 304+ newPosition = context.historyPosition + 1;
304305 } else {
305306 // Undo
306 - context.historyPosition--;
 307+ newPosition = context.historyPosition - 1;
307308 }
308309 // Only act if we are switching to a valid state
309 - if ( context.history.length + context.historyPosition >= 0 && context.historyPosition < 0 ) {
 310+ if ( newPosition >= ( context.history.length * -1 ) && newPosition < 0 ) {
 311+ // Make sure we run the history storing code before we make this change
 312+ context.evt.delayedChange( event );
 313+ context.historyPosition = newPosition;
310314 // Change state
311315 // FIXME: Destroys event handlers, will be a problem with template folding
312316 context.$content.html(
313317 context.history[context.history.length + context.historyPosition].html
314318 );
315 - } else {
316 - // Normalize the historyPosition
317 - context.historyPosition =
318 - Math.max( -context.history.length, Math.min( context.historyPosition, -1 ) );
 319+ context.fn.purgeOffsets();
 320+ if( context.history[context.history.length + context.historyPosition ].sel ) {
 321+ context.fn.setSelection( {
 322+ start: context.history[context.history.length + context.historyPosition ].sel[0],
 323+ end: context.history[context.history.length + context.historyPosition ].sel[1] }
 324+ );
 325+ }
319326 }
320327 // Prevent the browser from jumping in and doing its stuff
321328 return false;
@@ -367,21 +374,30 @@
368375 'delayedChange': function( event ) {
369376 event.data.scope = 'division';
370377 var newHTML = context.$content.html();
371 - if ( context.oldDelayedHTML != newHTML ) {
 378+ var newSel = context.fn.getCaretPosition();
 379+ // Was text changed? Was it because of a REDO or UNDO action?
 380+ if ( context.history.length == 0 || (context.oldDelayedHTML != newHTML
 381+ && newHTML != context.history[context.history.length + context.historyPosition].html ) ) {
372382 context.fn.purgeOffsets();
373383 context.oldDelayedHTML = newHTML;
 384+ context.oldDelayedSel = newSel;
374385 event.data.scope = 'realchange';
375 - // Save in the history
376 - //console.log( 'save-state' );
377 - // Only reset the historyPosition and begin moving forward if this change is not the result of undo
378 - if ( newHTML !== context.history[context.history.length + context.historyPosition].html ) {
 386+ // Do we need to trim extras from our history?
 387+ // FIXME: this should really be happing on change, not on the delay
 388+ if ( context.historyPosition < -1 ) {
 389+ //clear out the extras
 390+ context.history.splice( context.history.length + context.historyPosition );
379391 context.historyPosition = -1;
380392 }
381 - context.history.push( { 'html': newHTML } );
382 - // Keep the history under control
 393+ context.history.push( { 'html': newHTML, 'sel': newSel } );
 394+ // If the histroy has grown longer than 10 items, remove the earliest one
383395 while ( context.history.length > 10 ) {
384396 context.history.shift();
385397 }
 398+ } else if ( context.oldDelayedSel != newSel && context.historyPosition == -1 ) {
 399+ // If only the selection was changed, and we're not between undos, update it
 400+ context.oldDelayedSel = newSel;
 401+ context.history[context.history.length + context.historyPosition].sel = newSel;
386402 }
387403 return true;
388404 },
@@ -1485,8 +1501,6 @@
14861502 .replace( /&amp;esc;esc;/g, '&amp;esc;' );
14871503 context.$content.html( html );
14881504 context.oldHTML = html;
1489 - // FIXME: This needs to be merged somehow with the oldHTML thing
1490 - context.history.push( { 'html': html } );
14911505
14921506 // Reflect direction of parent frame into child
14931507 if ( $( 'body' ).is( '.rtl' ) ) {
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.js
@@ -6730,24 +6730,31 @@
67316731 if ( ( event.ctrlKey || event.metaKey ) && context.history.length ) {
67326732 // HistoryPosition is a negative number between -1 and -context.history.length, in other words
67336733 // it's the number of steps backwards from the latest state.
 6734+ var newPosition;
67346735 if ( event.shiftKey ) {
67356736 // Redo
6736 - context.historyPosition++;
 6737+ newPosition = context.historyPosition + 1;
67376738 } else {
67386739 // Undo
6739 - context.historyPosition--;
 6740+ newPosition = context.historyPosition - 1;
67406741 }
67416742 // Only act if we are switching to a valid state
6742 - if ( context.history.length + context.historyPosition >= 0 && context.historyPosition < 0 ) {
 6743+ if ( newPosition >= ( context.history.length * -1 ) && newPosition < 0 ) {
 6744+ // Make sure we run the history storing code before we make this change
 6745+ context.evt.delayedChange( event );
 6746+ context.historyPosition = newPosition;
67436747 // Change state
67446748 // FIXME: Destroys event handlers, will be a problem with template folding
67456749 context.$content.html(
67466750 context.history[context.history.length + context.historyPosition].html
67476751 );
6748 - } else {
6749 - // Normalize the historyPosition
6750 - context.historyPosition =
6751 - Math.max( -context.history.length, Math.min( context.historyPosition, -1 ) );
 6752+ context.fn.purgeOffsets();
 6753+ if( context.history[context.history.length + context.historyPosition ].sel ) {
 6754+ context.fn.setSelection( {
 6755+ start: context.history[context.history.length + context.historyPosition ].sel[0],
 6756+ end: context.history[context.history.length + context.historyPosition ].sel[1] }
 6757+ );
 6758+ }
67526759 }
67536760 // Prevent the browser from jumping in and doing its stuff
67546761 return false;
@@ -6800,21 +6807,30 @@
68016808 'delayedChange': function( event ) {
68026809 event.data.scope = 'division';
68036810 var newHTML = context.$content.html();
6804 - if ( context.oldDelayedHTML != newHTML ) {
 6811+ var newSel = context.fn.getCaretPosition();
 6812+ // Was text changed? Was it because of a REDO or UNDO action?
 6813+ if ( context.history.length == 0 || (context.oldDelayedHTML != newHTML
 6814+ && newHTML != context.history[context.history.length + context.historyPosition].html ) ) {
68056815 context.fn.purgeOffsets();
68066816 context.oldDelayedHTML = newHTML;
 6817+ context.oldDelayedSel = newSel;
68076818 event.data.scope = 'realchange';
6808 - // Save in the history
6809 - //console.log( 'save-state' );
6810 - // Only reset the historyPosition and begin moving forward if this change is not the result of undo
6811 - if ( newHTML !== context.history[context.history.length + context.historyPosition].html ) {
 6819+ // Do we need to trim extras from our history?
 6820+ // FIXME: this should really be happing on change, not on the delay
 6821+ if ( context.historyPosition < -1 ) {
 6822+ //clear out the extras
 6823+ context.history.splice( context.history.length + context.historyPosition );
68126824 context.historyPosition = -1;
68136825 }
6814 - context.history.push( { 'html': newHTML } );
6815 - // Keep the history under control
 6826+ context.history.push( { 'html': newHTML, 'sel': newSel } );
 6827+ // If the histroy has grown longer than 10 items, remove the earliest one
68166828 while ( context.history.length > 10 ) {
68176829 context.history.shift();
68186830 }
 6831+ } else if ( context.oldDelayedSel != newSel && context.historyPosition == -1 ) {
 6832+ // If only the selection was changed, and we're not between undos, update it
 6833+ context.oldDelayedSel = newSel;
 6834+ context.history[context.history.length + context.historyPosition].sel = newSel;
68196835 }
68206836 return true;
68216837 },
@@ -7918,8 +7934,6 @@
79197935 .replace( /&amp;esc;esc;/g, '&amp;esc;' );
79207936 context.$content.html( html );
79217937 context.oldHTML = html;
7922 - // FIXME: This needs to be merged somehow with the oldHTML thing
7923 - context.history.push( { 'html': html } );
79247938
79257939 // Reflect direction of parent frame into child
79267940 if ( $( 'body' ).is( '.rtl' ) ) {
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js
@@ -445,8 +445,8 @@
446446 return src+'?'+wgWikiEditorIconVersion;}};$.fn.wikiEditor=function(){if(!$j.wikiEditor.isSupported()){return $(this);}
447447 var context=$(this).data('wikiEditor-context');if(typeof context=='undefined'){context={'$textarea':$(this),'views':{},'modules':{},'data':{},'instance':$.wikiEditor.instances.push($(this))-1,'offsets':null,'htmlToTextMap':{},'oldHTML':null,'oldDelayedHTML':null,'savedSelection':null,'history':[],'historyPosition':-1};context.api={'addModule':function(context,data){var modules={};if(typeof data=='string'){modules[data]={};}else if(typeof data=='object'){modules=data;}
448448 for(var module in modules){if(typeof module=='string'&&$.wikiEditor.isSupported(module)){if('api'in $.wikiEditor.modules[module]){for(var call in $.wikiEditor.modules[module].api){if(!(call in context.api)){context.api[call]=$.wikiEditor.modules[module].api[call];}}}
449 -if('fn'in $.wikiEditor.modules[module]&&'create'in $.wikiEditor.modules[module].fn){context.modules[module]={};$.wikiEditor.modules[module].fn.create(context,modules[module]);}}}}};context.evt={'keydown':function(event){switch(event.which){case 90:if((event.ctrlKey||event.metaKey)&&context.history.length){if(event.shiftKey){context.historyPosition++;}else{context.historyPosition--;}
450 -if(context.history.length+context.historyPosition>=0&&context.historyPosition<0){context.$content.html(context.history[context.history.length+context.historyPosition].html);}else{context.historyPosition=Math.max(-context.history.length,Math.min(context.historyPosition,-1));}
 449+if('fn'in $.wikiEditor.modules[module]&&'create'in $.wikiEditor.modules[module].fn){context.modules[module]={};$.wikiEditor.modules[module].fn.create(context,modules[module]);}}}}};context.evt={'keydown':function(event){switch(event.which){case 90:if((event.ctrlKey||event.metaKey)&&context.history.length){var newPosition;if(event.shiftKey){newPosition=context.historyPosition+1;}else{newPosition=context.historyPosition-1;}
 450+if(newPosition>=(context.history.length*-1)&&newPosition<0){context.evt.delayedChange(event);context.historyPosition=newPosition;context.$content.html(context.history[context.history.length+context.historyPosition].html);context.fn.purgeOffsets();if(context.history[context.history.length+context.historyPosition].sel){context.fn.setSelection({start:context.history[context.history.length+context.historyPosition].sel[0],end:context.history[context.history.length+context.historyPosition].sel[1]});}}
451451 return false;}
452452 break;case 9:if(event.ctrlKey||event.altKey||event.shiftKey){return true;}else{var $tabindexList=$j('[tabindex]:visible').sort(function(a,b){return a.tabIndex-b.tabIndex;});for(var i=0;i<$tabindexList.length;i++){if($tabindexList.eq(i).attr('id')==context.$iframe.attr('id')){$tabindexList.get(i+1).focus();break;}}
453453 return false;}
@@ -454,8 +454,8 @@
455455 break;}
456456 return true;},'change':function(event){event.data.scope='division';var newHTML=context.$content.html();if(context.oldHTML!=newHTML){context.fn.purgeOffsets();context.oldHTML=newHTML;event.data.scope='realchange';}
457457 switch(event.which){case 8:break;}
458 -return true;},'delayedChange':function(event){event.data.scope='division';var newHTML=context.$content.html();if(context.oldDelayedHTML!=newHTML){context.fn.purgeOffsets();context.oldDelayedHTML=newHTML;event.data.scope='realchange';if(newHTML!==context.history[context.history.length+context.historyPosition].html){context.historyPosition=-1;}
459 -context.history.push({'html':newHTML});while(context.history.length>10){context.history.shift();}}
 458+return true;},'delayedChange':function(event){event.data.scope='division';var newHTML=context.$content.html();var newSel=context.fn.getCaretPosition();if(context.history.length==0||(context.oldDelayedHTML!=newHTML&&newHTML!=context.history[context.history.length+context.historyPosition].html)){context.fn.purgeOffsets();context.oldDelayedHTML=newHTML;context.oldDelayedSel=newSel;event.data.scope='realchange';if(context.historyPosition<-1){context.history.splice(context.history.length+context.historyPosition);context.historyPosition=-1;}
 459+context.history.push({'html':newHTML,'sel':newSel});while(context.history.length>10){context.history.shift();}}else if(context.oldDelayedSel!=newSel&&context.historyPosition==-1){context.oldDelayedSel=newSel;context.history[context.history.length+context.historyPosition].sel=newSel;}
460460 return true;},'paste':function(event){context.$content.find(':not(.wikiEditor)').addClass('wikiEditor');context.$content.addClass('pasting');setTimeout(function(){var $selection=context.$content.find(':not(.wikiEditor)');while($selection.length&&$selection.length>0){var $currentElement=$selection.eq(0);while(!$currentElement.parent().is('body')&&!$currentElement.parent().is('.wikiEditor')){$currentElement=$currentElement.parent();}
461461 if($currentElement.is('br')){$currentElement.addClass('wikiEditor');}else{$('<p></p>').text($currentElement.text()).addClass('wikiEditor').insertAfter($currentElement);$currentElement.remove();}
462462 $selection=context.$content.find(':not(.wikiEditor)');}
@@ -554,7 +554,7 @@
555555 context.$iframe[0].contentWindow.focus();context.savedSelection=context.$iframe[0].contentWindow.document.selection.createRange();},'restoreSelection':function(){if(!$.browser.msie||context.savedSelection===null){return;}
556556 context.$iframe[0].contentWindow.focus();context.savedSelection.select();context.savedSelection=null;}};var $loader=$('<div></div>').addClass('wikiEditor-ui-loading').append($('<span>'+mw.usability.getMsg('wikieditor-loading')+'</span>').css('marginTop',context.$textarea.height()/2));context.$textarea.after($loader).add($loader).wrapAll($('<div></div>').addClass('wikiEditor-ui')).wrapAll($('<div></div>').addClass('wikiEditor-ui-view wikiEditor-ui-view-wikitext')).wrapAll($('<div></div>').addClass('wikiEditor-ui-left')).wrapAll($('<div></div>').addClass('wikiEditor-ui-bottom')).wrapAll($('<div></div>').addClass('wikiEditor-ui-text'));context.$ui=context.$textarea.parent().parent().parent().parent().parent();context.$wikitext=context.$textarea.parent().parent().parent().parent();context.$wikitext.before($('<div></div>').addClass('wikiEditor-ui-controls').append($('<div></div>').addClass('wikiEditor-ui-tabs').hide()).append($('<div></div>').addClass('wikiEditor-ui-buttons'))).before($('<div style="clear:both;"></div>'));context.$controls=context.$ui.find('.wikiEditor-ui-buttons').hide();context.$buttons=context.$ui.find('.wikiEditor-ui-buttons');context.$tabs=context.$ui.find('.wikiEditor-ui-tabs');context.$ui.after($('<div style="clear:both;"></div>'));context.$wikitext.append($('<div></div>').addClass('wikiEditor-ui-right'));context.$wikitext.find('.wikiEditor-ui-left').prepend($('<div></div>').addClass('wikiEditor-ui-top'));context.view='wikitext';$(window).resize(function(event){context.fn.trigger('resize',event);});context.$iframe=$('<iframe></iframe>').attr({'frameBorder':0,'border':0,'tabindex':1,'src':wgScriptPath+'/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html?'+'instance='+context.instance+'&ts='+(new Date()).getTime()+'&is=content','id':'wikiEditor-iframe-'+context.instance}).css({'backgroundColor':'white','width':'100%','height':context.$textarea.height(),'display':'none','overflow-y':'scroll','overflow-x':'hidden'}).insertAfter(context.$textarea).load(function(){if(!this.isSecondRun){context.$iframe[0].contentWindow.document.designMode='on';if($.browser.msie){this.isSecondRun=true;return;}}
557557 context.$content=$(context.$iframe[0].contentWindow.document.body);var html=context.$textarea.val().replace(/&esc;/g,'&esc;esc;').replace(/\<p\>/g,'&esc;&lt;p&gt;').replace(/\<\/p\>/g,'&esc;&lt;/p&gt;').replace(/\<span class="wikiEditor-tab"\>\<\/span\>/g,'&esc;&lt;span&nbsp;class=&quot;wikiEditor-tab&quot;&gt;&lt;/span&gt;').replace(/&nbsp;/g,'&esc;&amp;nbsp;');if($.browser.msie){html=html.replace(/\t/g,'<span class="wikiEditor-tab"></span>');if($.browser.versionNumber<=7){html=html.replace(/ /g,"&nbsp;");}else{html=html.replace(/(^|\n) /g,"$1&nbsp;");}}
558 -html=$('<div />').text('<p>'+html.replace(/\r?\n/g,'</p><p>')+'</p>').html().replace(/&amp;nbsp;/g,'&nbsp;').replace(/&lt;p&gt;/g,'<p>').replace(/&lt;\/p&gt;/g,'</p>').replace(/&lt;span( |&nbsp;)class=("|&quot;)wikiEditor-tab("|&quot;)&gt;&lt;\/span&gt;/g,'<span class="wikiEditor-tab"></span>').replace(/<p><\/p>/g,'<p><br></p>').replace(/&amp;esc;&amp;amp;nbsp;/g,'&amp;nbsp;').replace(/&amp;esc;&amp;lt;p&amp;gt;/g,'&lt;p&gt;').replace(/&amp;esc;&amp;lt;\/p&amp;gt;/g,'&lt;/p&gt;').replace(/&amp;esc;&amp;lt;span&amp;nbsp;class=&amp;quot;wikiEditor-tab&amp;quot;&amp;gt;&amp;lt;\/span&amp;gt;/g,'&lt;span class="wikiEditor-tab"&gt;&lt;\/span&gt;').replace(/&amp;esc;esc;/g,'&amp;esc;');context.$content.html(html);context.oldHTML=html;context.history.push({'html':html});if($('body').is('.rtl')){context.$content.addClass('rtl').attr('dir','rtl');}
 558+html=$('<div />').text('<p>'+html.replace(/\r?\n/g,'</p><p>')+'</p>').html().replace(/&amp;nbsp;/g,'&nbsp;').replace(/&lt;p&gt;/g,'<p>').replace(/&lt;\/p&gt;/g,'</p>').replace(/&lt;span( |&nbsp;)class=("|&quot;)wikiEditor-tab("|&quot;)&gt;&lt;\/span&gt;/g,'<span class="wikiEditor-tab"></span>').replace(/<p><\/p>/g,'<p><br></p>').replace(/&amp;esc;&amp;amp;nbsp;/g,'&amp;nbsp;').replace(/&amp;esc;&amp;lt;p&amp;gt;/g,'&lt;p&gt;').replace(/&amp;esc;&amp;lt;\/p&amp;gt;/g,'&lt;/p&gt;').replace(/&amp;esc;&amp;lt;span&amp;nbsp;class=&amp;quot;wikiEditor-tab&amp;quot;&amp;gt;&amp;lt;\/span&amp;gt;/g,'&lt;span class="wikiEditor-tab"&gt;&lt;\/span&gt;').replace(/&amp;esc;esc;/g,'&amp;esc;');context.$content.html(html);context.oldHTML=html;if($('body').is('.rtl')){context.$content.addClass('rtl').attr('dir','rtl');}
559559 context.$textarea.attr('disabled',true);context.$textarea.hide();context.$iframe.show();context.fn.trigger('ready');$('.wikiEditor-ui-loading').fadeOut('fast',function(){$(this).remove();});$(context.$iframe[0].contentWindow.document).bind('keydown',function(event){return context.fn.trigger('keydown',event);}).bind('paste',function(event){return context.fn.trigger('paste',event);}).bind('keyup paste mouseup cut encapsulateSelection',function(event){return context.fn.trigger('change',event);}).delayedBind(250,'keyup paste mouseup cut encapsulateSelection',function(event){context.fn.trigger('delayedChange',event);});});context.$textarea.closest('form').submit(function(){context.$textarea.attr('disabled',false);context.$textarea.val(context.$textarea.textSelection('getContents'));});context.fallbackWindowOnBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){context.$textarea.val(context.$textarea.textSelection('getContents'));if(context.fallbackWindowOnBeforeUnload){return context.fallbackWindowOnBeforeUnload();}};}
560560 var args=$.makeArray(arguments);if(args.length>0){var call=args.shift();if(call in context.api){context.api[call](context,typeof args[0]=='undefined'?{}:args[0]);}}
561561 return $(this).data('wikiEditor-context',context);};})(jQuery);RegExp.escape=function(s){return s.replace(/([.*+?^${}()|\/\\[\]])/g,'\\$1');};(function($){$.wikiEditor.modules.dialogs={api:{addDialog:function(context,data){$.wikiEditor.modules.dialogs.fn.create(context,data)},openDialog:function(context,module){if(module in $.wikiEditor.modules.dialogs.modules){$('#'+$.wikiEditor.modules.dialogs.modules[module].id).dialog('open');}},closeDialog:function(context,data){if(module in $.wikiEditor.modules.dialogs.modules){$('#'+$.wikiEditor.modules.dialogs.modules[module].id).dialog('close');}}},fn:{create:function(context,config){for(module in config){$.wikiEditor.modules.dialogs.modules[module]=config[module];}

Follow-up revisions

RevisionCommit summaryAuthorDate
r62366UsabilityInitiative: Whitespace and comment fixes for r62345catrope13:11, 12 February 2010

Comments

#Comment by Catrope (talk | contribs)   13:11, 12 February 2010
+						if ( newPosition >= ( context.history.length * -1 ) && newPosition < 0 ) {

You can simply use -context.history.length instead of multiplying by -1, and you don't need the parentheses either way: arithmetic operators bind more tightly than comparison operators.

+			if ( context.history.length == 0 || (context.oldDelayedHTML != newHTML 
+				&& newHTML != context.history[context.history.length + context.historyPosition].html ) ) {
...
+				context.oldDelayedSel = newSel;
...
+			} else if ( context.oldDelayedSel != newSel && context.historyPosition == -1 ) {

This makes it look like context.oldDelayedSel is potentially being used without being initialized. I realize this can't actually ever happen because the else branch can never be taken on the first run, but it'd be nice to just initialize it to null somewhere, like we do for context.oldDelayedHTML.

Status & tagging log