r70465 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r70464‎ | r70465 | r70466 >
Date:16:30, 4 August 2010
Author:pdhanda
Status:deferred (Comments)
Tags:
Comment:
Mostly cleanup for IE and workaround for things that don't work right (parts of highlighting).
Modified paths:
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.toc.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/thirdparty/contentCollector.js (modified) (history)

Diff [purge]

Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.toc.js
@@ -57,6 +57,9 @@
5858 ready: function( context, event ) {
5959 // Add the TOC to the document
6060 $.wikiEditor.modules.toc.fn.build( context );
 61+ if ( !context.$content ) {
 62+ return;
 63+ }
6164 context.$content.parent()
6265 .blur( function() {
6366 var context = event.data.context;
@@ -295,6 +298,9 @@
296299 * @param {Object} context
297300 */
298301 update: function( context ) {
 302+ //temporarily commenting this out because it is causing all kinds of cursor
 303+ //and text jumping issues in IE. WIll get back to this --pdhanda
 304+ /*
299305 var div = context.fn.beforeSelection( 'wikiEditor-toc-header' );
300306 if ( div === null ) {
301307 // beforeSelection couldn't figure it out, keep the old highlight state
@@ -309,6 +315,7 @@
310316
311317 // Scroll the highlighted link into view if necessary
312318 var relTop = sectionLink.offset().top - context.modules.toc.$toc.offset().top;
 319+
313320 var scrollTop = context.modules.toc.$toc.scrollTop();
314321 var divHeight = context.modules.toc.$toc.height();
315322 var sectionHeight = sectionLink.height();
@@ -319,6 +326,7 @@
320327 // Scroll down
321328 context.modules.toc.$toc.scrollTop( scrollTop + relTop + sectionHeight - divHeight );
322329 }
 330+ */
323331 },
324332
325333 /**
@@ -461,8 +469,11 @@
462470 // Bring user's eyes to the point we've now jumped to
463471 context.fn.highlightLine( $( wrapper ) );
464472 // Highlight the clicked link
465 - $.wikiEditor.modules.toc.fn.unhighlight( context );
 473+ //remove highlighting of toc after a second. Temporary hack till the highlight works --pdhanda
 474+ //$.wikiEditor.modules.toc.fn.unhighlight( context );
466475 $( this ).addClass( 'current' );
 476+ //$( this ).removeClass( 'current' );
 477+ setTimeout( function() { $.wikiEditor.modules.toc.fn.unhighlight( context ) }, 1000 );
467478
468479 if ( typeof $.trackAction != 'undefined' )
469480 $.trackAction( 'ntoc.heading' );
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js
@@ -413,36 +413,50 @@
414414 'paste': function( event ) {
415415 // Save the cursor position to restore it after all this voodoo
416416 var cursorPos = context.fn.getCaretPosition();
417 - var offset = 0;
418417 var oldLength = context.fn.getContents().length;
 418+ var positionFromEnd = oldLength - cursorPos[1];
419419
420420 //give everything the wikiEditor class so that we can easily pick out things without that class as pasted
421421 context.$content.find( '*' ).addClass( 'wikiEditor' );
422422 if ( $.layout.name !== 'webkit' ) {
423423 context.$content.addClass( 'pasting' );
424424 }
 425+
425426 setTimeout( function() {
426 -
427427 // Kill stuff we know we don't want
428428 context.$content.find( 'script,style,img,input,select,textarea,hr,button,link,meta' ).remove();
429 -
430 - //anything without wikiEditor class was pasted.
431 - var $selection = context.$content.find( ':not(.wikiEditor)' );
432429 var nodeToDelete = [];
 430+ var pastedContent = [];
433431 var firstDirtyNode;
434 - if ( $selection.length == 0 ) {
435 - firstDirtyNode = context.fn.getOffset( cursorPos[0] ).node;
 432+ var $lastDirtyNode;
 433+ var elementAtCursor;
 434+ if ( $.browser.msie && !context.offsets ) {
 435+ elementAtCursor = null;
436436 } else {
437 - firstDirtyNode = $selection.eq( 0 )[0];
 437+ elementAtCursor = context.fn.getOffset( cursorPos[0] );
438438 }
 439+ if ( elementAtCursor == null || elementAtCursor.node == null ) {
 440+ context.$content.prepend( '<p class = wikiEditor></p>' );
 441+ firstDirtyNode = context.$content.children()[0];
 442+ } else {
 443+ firstDirtyNode = elementAtCursor.node;
 444+ }
 445+
 446+ //this is ugly but seems like the best way to handle the case where we select and replace all editor contents
 447+ try {
 448+ firstDirtyNode.parentNode;
 449+ } catch ( err ) {
 450+ context.$content.prepend( '<p class = wikiEditor></p>' );
 451+ firstDirtyNode = context.$content.children()[0];
 452+ }
 453+
439454 while ( firstDirtyNode != null ) {
440 - //go up till we find the top pasted node
441 - while ( firstDirtyNode.parentNode.nodeName != 'BODY'
442 - && ! $( firstDirtyNode.parentNode ).hasClass( 'wikiEditor' )
 455+ //we're going to replace the contents of the entire parent node.
 456+ while ( firstDirtyNode.parentNode && firstDirtyNode.parentNode.nodeName != 'BODY'
 457+ && ! $( firstDirtyNode ).hasClass( 'wikiEditor' )
443458 ) {
444459 firstDirtyNode = firstDirtyNode.parentNode;
445460 }
446 -
447461 //go back till we find the first pasted node
448462 while ( firstDirtyNode.previousSibling != null
449463 && ! $( firstDirtyNode.previousSibling ).hasClass( 'wikiEditor' )
@@ -455,36 +469,27 @@
456470 }
457471 }
458472
459 - var $lastDirtyNode = $( firstDirtyNode );
 473+ if ( firstDirtyNode.previousSibling != null ) {
 474+ $lastDirtyNode = $( firstDirtyNode.previousSibling );
 475+ } else {
 476+ $lastDirtyNode = $( firstDirtyNode );
 477+ }
 478+
460479 var cc = makeContentCollector( $.browser, null );
461 - while ( firstDirtyNode != null && ! $( firstDirtyNode ).hasClass( 'wikiEditor' ) ) {
 480+ while ( firstDirtyNode != null ) {
462481 cc.collectContent(firstDirtyNode);
 482+ cc.notifyNextNode(firstDirtyNode.nextSibling);
463483
464 - cc.notifyNextNode(firstDirtyNode.nextSibling);
465 - pastedContent = cc.getLines();
466 - if ((pastedContent.length <= 1 || pastedContent[pastedContent.length - 1] !== "")
467 - && firstDirtyNode.nextSibling) {
468 - nodeToDelete.push( firstDirtyNode );
469 - firstDirtyNode = firstDirtyNode.nextSibling;
470 - cc.collectContent(firstDirtyNode);
471 - cc.notifyNextNode(firstDirtyNode.nextSibling);
472 - }
473484 nodeToDelete.push( firstDirtyNode );
 485+
474486 firstDirtyNode = firstDirtyNode.nextSibling;
 487+ if ( $( firstDirtyNode ).hasClass( 'wikiEditor' ) ) {
 488+ break;
 489+ }
475490 }
 491+
476492 var ccData = cc.finish();
477 - var pastedContent = ccData.lines;
478 - if ( pastedContent.length == 0 && firstDirtyNode ) {
479 - offset += $( firstDirtyNode ).text().length;
480 - }
481 -
482 - if ( nodeToDelete.length > 0 ) {
483 - $lastDirtyNode = $( nodeToDelete[nodeToDelete.length - 1] );
484 - }
485 -
486 - var testVal = '';
487 - testVal = $( nodeToDelete[0] ).text();
488 -
 493+ pastedContent = ccData.lines;
489494 var pastedPretty = '';
490495 for ( var i = 0; i < pastedContent.length; i++ ) {
491496 //escape html
@@ -497,45 +502,58 @@
498503 pastedPretty = leadingSpace + pastedPretty.substring(index, pastedPretty.length);
499504 }
500505
501 - $newElement = $( '<p class="wikiEditor" ></p>' );
 506+
 507+ if( !pastedPretty && $.browser.msie && i == 0 ) {
 508+ continue;
 509+ }
 510+ $newElement = $( '<p class="wikiEditor pasted" ></p>' );
502511 if ( pastedPretty ) {
503 - $newElement.html( '<span class = "wikiEditor">' + pastedPretty + '</span>' );
 512+ $newElement.html( pastedPretty );
504513 } else {
505514 $newElement.html( '<br class="wikiEditor">' );
506515 }
507516 $newElement.insertAfter( $lastDirtyNode );
508 - offset += pastedPretty.length;
 517+
509518 $lastDirtyNode = $newElement;
 519+
510520 }
511521
 522+ //now delete all the original nodes that we prettified already
512523 while ( nodeToDelete.length > 0 ) {
513 - $( nodeToDelete.pop() ).remove();
 524+ $deleteNode = $( nodeToDelete.pop() );
 525+ $deleteNode.remove();
514526 }
515527
516 - //find the next node that may not be the next sibling (in IE)
 528+ //anything without wikiEditor class was pasted.
517529 $selection = context.$content.find( ':not(.wikiEditor)' );
518530 if ( $selection.length == 0 ) {
519 - firstDirtyNode = null;
 531+ break;
520532 } else {
521533 firstDirtyNode = $selection.eq( 0 )[0];
522534 }
523535 }
524 -
525536 context.$content.find( '.wikiEditor' ).removeClass( 'wikiEditor' );
526537
527 - //context.$content.find( '*' ).addClass( 'wikiEditor' );
528 -
529538 //now place the cursor at the end of pasted content
530 - var restoreTo = cursorPos[1] + offset;
 539+ var newLength = context.fn.getContents().length;
 540+ var newPos = newLength - positionFromEnd;
531541
532 - context.fn.setSelection( { start: restoreTo, end: restoreTo } );
 542+ context.fn.purgeOffsets();
 543+ context.fn.setSelection( { start: newPos, end: newPos } );
 544+
 545+ context.fn.scrollToCaretPosition();
 546+
533547
534548 }, 0 );
535549 return true;
536550 },
537551 'ready': function( event ) {
538552 // Initialize our history queue
539 - context.history.push( { 'html': context.$content.html(), 'sel': context.fn.getCaretPosition() } );
 553+ if ( context.$content ) {
 554+ context.history.push( { 'html': context.$content.html(), 'sel': context.fn.getCaretPosition() } );
 555+ } else {
 556+ context.history.push( { 'html': '', 'sel': context.fn.getCaretPosition() } );
 557+ }
540558 return true;
541559 }
542560 };
@@ -555,15 +573,16 @@
556574 if ( typeof event.data == 'undefined' ) {
557575 event.data = {};
558576 }
 577+
559578 // Allow filtering to occur
560579 if ( name in context.evt ) {
561580 if ( !context.evt[name]( event ) ) {
562581 return false;
563582 }
564583 }
565 -
566584 var returnFromModules = null; //they return null by default
567585 // Pass the event around to all modules activated on this context
 586+
568587 for ( var module in context.modules ) {
569588 if (
570589 module in $.wikiEditor.modules &&
@@ -734,6 +753,9 @@
735754 classname = '';
736755 }
737756 var e = null, offset = null;
 757+ if ( $.browser.msie && !context.$iframe[0].contentWindow.document.body ) {
 758+ return null;
 759+ }
738760 if ( context.$iframe[0].contentWindow.getSelection ) {
739761 // Firefox and Opera
740762 var selection = context.$iframe[0].contentWindow.getSelection();
@@ -1231,6 +1253,9 @@
12321254 'getContents': function() {
12331255 // For <p></p>, .html() returns <p>&nbsp;</p> in IE
12341256 // This seems to convince IE while not affecting display
 1257+ if ( !context.$content ) {
 1258+ return '';
 1259+ }
12351260 var html;
12361261 if ( $.browser.msie ) {
12371262 // Don't manipulate the iframe DOM itself, causes cursor jumping issues
@@ -1847,6 +1872,7 @@
18481873 // Only allow modules which are supported (and thus actually being turned on) affect this decision
18491874 if ( module in $.wikiEditor.modules && $.wikiEditor.isSupported( $.wikiEditor.modules[module] ) &&
18501875 $.wikiEditor.isRequired( $.wikiEditor.modules[module], 'iframe' ) ) {
 1876+
18511877 context.fn.setupIframe();
18521878 break;
18531879 }
Index: trunk/extensions/UsabilityInitiative/js/thirdparty/contentCollector.js
@@ -35,8 +35,15 @@
3636 return n.tagName;
3737 },
3838 nodeValue : function(n) {
39 - return n.nodeValue;
 39+ try {
 40+ return n.nodeValue;
 41+ } catch ( err ) {
 42+ return '';
 43+ }
4044 },
 45+ nodeName : function(n) {
 46+ return n.nodeName;
 47+ },
4148 nodeNumChildren : function(n) {
4249 return n.childNodes.length;
4350 },
@@ -264,6 +271,7 @@
265272 }
266273
267274 } else {
 275+ var cls = dom.nodeProp(node, "className");
268276 var tname = (dom.nodeTagName(node) || "").toLowerCase();
269277 if (tname == "br") {
270278 _startNewLine(state);
@@ -271,8 +279,7 @@
272280 // ignore
273281 } else if (!isEmpty) {
274282 var styl = dom.nodeAttr(node, "style");
275 - var cls = dom.nodeProp(node, "className");
276 -
 283+
277284 var isPre = (tname == "pre");
278285 if ((!isPre) && browser.safari) {
279286 isPre = (styl && /\bwhite-space:\s*pre\b/i.exec(styl));
@@ -284,6 +291,11 @@
285292 var nc = dom.nodeNumChildren(node);
286293 for ( var i = 0; i < nc; i++) {
287294 var c = dom.nodeChild(node, i);
 295+ //very specific IE case where it inserts <span lang="en"> which we want to ginore.
 296+ //to reproduce copy content from wordpad andpaste into the middle of a line in IE
 297+ if ( browser.msie && cls.indexOf('wikiEditor') >= 0 && dom.nodeName(c) == 'SPAN' && dom.nodeAttr(c, 'lang') == "" ) {
 298+ continue;
 299+ }
288300 cc.collectContent(c, state);
289301 }
290302
@@ -347,7 +359,9 @@
348360 lines.flush();
349361 var lineStrings = cc.getLines();
350362
351 - lineStrings.length--;
 363+ if ( lineStrings.length > 0 && !lineStrings[lineStrings.length - 1] ) {
 364+ lineStrings.length--;
 365+ }
352366
353367 var ss = getSelectionStart();
354368 var se = getSelectionEnd();

Comments

#Comment by Catrope (talk | contribs)   11:08, 6 August 2010
+					context.$content.prepend( '<p class = wikiEditor></p>' );

Is that even valid HTML?

+				try {
+					firstDirtyNode.parentNode;
+				} catch ( err ) {

Are you sure this couldn't be done with e.g. if ( typeof firstDirtyNode.parentNode !== 'undefined' ) or if ( !firstDirtyNode ) or whatever?

-			return n.nodeValue;
+			try {
+				return n.nodeValue;
+			} catch ( err ) {
+				return '';
+			}

Same here.

#Comment by Pdhanda (talk | contribs)   17:25, 20 September 2010

Marking as new since this code has changed a bunch since then.

Status & tagging log