r110879 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r110878‎ | r110879 | r110880 >
Date:22:02, 7 February 2012
Author:inez
Status:deferred
Tags:
Comment:
Cleanup ve.es.Content.js for ContentEditable and setup toolbar as empty (as there is no working functionality for now)
Modified paths:
  • /trunk/extensions/VisualEditor/demos/ce/main.js (modified) (history)
  • /trunk/extensions/VisualEditor/modules/ve/ce/ve.es.Content.js (modified) (history)

Diff [purge]

Index: trunk/extensions/VisualEditor/demos/ce/main.js
@@ -565,7 +565,7 @@
566566 window.documentModel = ve.dm.DocumentNode.newFromPlainObject( wikidoms['Wikipedia article'] );
567567 window.surfaceModel = new ve.dm.Surface( window.documentModel );
568568 window.surfaceView = new ve.es.Surface( $( '#es-editor' ), window.surfaceModel );
569 - window.toolbarView = new ve.ui.Toolbar( $( '#es-toolbar' ), window.surfaceView );
 569+ window.toolbarView = new ve.ui.Toolbar( $( '#es-toolbar' ), window.surfaceView, [] );
570570 window.contextView = new ve.ui.Context( window.surfaceView );
571571 window.surfaceModel.select( new ve.Range( 1, 1 ) );
572572
Index: trunk/extensions/VisualEditor/modules/ve/ce/ve.es.Content.js
@@ -42,17 +42,9 @@
4343 // Events
4444 var _this = this;
4545 this.model.on( 'update', function( offset ) {
46 - _this.scanBoundaries();
4746 _this.render( offset || 0 );
4847 } );
4948
50 - // DOM Changes
51 - this.$ranges = $( '<div class="es-contentView-ranges"></div>' );
52 - this.$rangeStart = $( '<div class="es-contentView-range"></div>' );
53 - this.$rangeFill = $( '<div class="es-contentView-range"></div>' );
54 - this.$rangeEnd = $( '<div class="es-contentView-range"></div>' );
55 - this.$.prepend( this.$ranges.append( this.$rangeStart, this.$rangeFill, this.$rangeEnd ) );
56 -
5749 // Initialization
5850 this.scanBoundaries();
5951 }
@@ -211,277 +203,6 @@
212204 /* Methods */
213205
214206 /**
215 - * Draws selection around a given range of content.
216 - *
217 - * @method
218 - * @param {ve.Range} range Range to draw selection around
219 - */
220 -ve.es.Content.prototype.drawSelection = function( range ) {
221 - if ( typeof range === 'undefined' ) {
222 - range = new ve.Range( 0, this.model.getContentLength() );
223 - } else {
224 - range.normalize();
225 - }
226 - var fromLineIndex = this.getRenderedLineIndexFromOffset( range.start ),
227 - toLineIndex = this.getRenderedLineIndexFromOffset( range.end ),
228 - fromPosition = this.getRenderedPositionFromOffset( range.start ),
229 - toPosition = this.getRenderedPositionFromOffset( range.end );
230 -
231 - if ( fromLineIndex === toLineIndex ) {
232 - // Single line selection
233 - if ( toPosition.left - fromPosition.left ) {
234 - this.$rangeStart.css( {
235 - 'top': fromPosition.top,
236 - 'left': fromPosition.left,
237 - 'width': toPosition.left - fromPosition.left,
238 - 'height': fromPosition.bottom - fromPosition.top
239 - } ).show();
240 - }
241 - this.$rangeFill.hide();
242 - this.$rangeEnd.hide();
243 - } else {
244 - // Multiple line selection
245 - var contentWidth = this.$.width();
246 - if ( contentWidth - fromPosition.left ) {
247 - this.$rangeStart.css( {
248 - 'top': fromPosition.top,
249 - 'left': fromPosition.left,
250 - 'width': contentWidth - fromPosition.left,
251 - 'height': fromPosition.bottom - fromPosition.top
252 - } ).show();
253 - } else {
254 - this.$rangeStart.hide();
255 - }
256 - if ( toPosition.left ) {
257 - this.$rangeEnd.css( {
258 - 'top': toPosition.top,
259 - 'left': 0,
260 - 'width': toPosition.left,
261 - 'height': toPosition.bottom - toPosition.top
262 - } ).show();
263 - } else {
264 - this.$rangeEnd.hide();
265 - }
266 - if ( fromLineIndex + 1 < toLineIndex ) {
267 - this.$rangeFill.css( {
268 - 'top': fromPosition.bottom,
269 - 'left': 0,
270 - 'width': contentWidth,
271 - 'height': toPosition.top - fromPosition.bottom
272 - } ).show();
273 - } else {
274 - this.$rangeFill.hide();
275 - }
276 - }
277 -};
278 -
279 -/**
280 - * Clears selection if any was drawn.
281 - *
282 - * @method
283 - */
284 -ve.es.Content.prototype.clearSelection = function() {
285 - this.$rangeStart.hide();
286 - this.$rangeFill.hide();
287 - this.$rangeEnd.hide();
288 -};
289 -
290 -/**
291 - * Gets the index of the rendered line a given offset is within.
292 - *
293 - * Offsets that are out of range will always return the index of the last line.
294 - *
295 - * @method
296 - * @param {Integer} offset Offset to get line for
297 - * @returns {Integer} Index of rendered lin offset is within
298 - */
299 -ve.es.Content.prototype.getRenderedLineIndexFromOffset = function( offset ) {
300 - for ( var i = 0; i < this.lines.length; i++ ) {
301 - if ( this.lines[i].range.containsOffset( offset ) ) {
302 - return i;
303 - }
304 - }
305 - return this.lines.length - 1;
306 -};
307 -
308 -/*
309 - * Gets the index of the rendered line closest to a given position.
310 - *
311 - * If the position is above the first line, the offset will always be 0, and if the position is
312 - * below the last line the offset will always be the content length. All other vertical
313 - * positions will fall inside of one of the lines.
314 - *
315 - * @method
316 - * @returns {Integer} Index of rendered line closest to position
317 - */
318 -ve.es.Content.prototype.getRenderedLineIndexFromPosition = function( position ) {
319 - var lineCount = this.lines.length;
320 - // Positions above the first line always jump to the first offset
321 - if ( !lineCount || position.top < 0 ) {
322 - return 0;
323 - }
324 - // Find which line the position is inside of
325 - var i = 0,
326 - top = 0;
327 - while ( i < lineCount ) {
328 - top += this.lines[i].height;
329 - if ( position.top < top ) {
330 - break;
331 - }
332 - i++;
333 - }
334 - // Positions below the last line always jump to the last offset
335 - if ( i === lineCount ) {
336 - return i - 1;
337 - }
338 - return i;
339 -};
340 -
341 -/**
342 - * Gets the range of the rendered line a given offset is within.
343 - *
344 - * Offsets that are out of range will always return the range of the last line.
345 - *
346 - * @method
347 - * @param {Integer} offset Offset to get line for
348 - * @returns {ve.Range} Range of line offset is within
349 - */
350 -ve.es.Content.prototype.getRenderedLineRangeFromOffset = function( offset ) {
351 - for ( var i = 0; i < this.lines.length; i++ ) {
352 - if ( this.lines[i].range.containsOffset( offset ) ) {
353 - return this.lines[i].range;
354 - }
355 - }
356 - return this.lines[this.lines.length - 1].range;
357 -};
358 -
359 -/**
360 - * Gets offset within content model closest to of a given position.
361 - *
362 - * Position is assumed to be local to the container the text is being flowed in.
363 - *
364 - * @method
365 - * @param {Object} position Position to find offset for
366 - * @param {Integer} position.left Horizontal position in pixels
367 - * @param {Integer} position.top Vertical position in pixels
368 - * @returns {Integer} Offset within content model nearest the given coordinates
369 - */
370 -ve.es.Content.prototype.getOffsetFromRenderedPosition = function( position ) {
371 - // Empty content model shortcut
372 - if ( this.model.getContentLength() === 0 ) {
373 - return 0;
374 - }
375 -
376 - // Localize position
377 - position.subtract( ve.Position.newFromElementPagePosition( this.$ ) );
378 -
379 - // Get the line object nearest the position
380 - var line = this.lines[this.getRenderedLineIndexFromPosition( position )];
381 -
382 - /*
383 - * Offset finding
384 - *
385 - * Now that we know which line we are on, we can just use the "fitCharacters" method to get the
386 - * last offset before "position.left".
387 - *
388 - * TODO: The offset needs to be chosen based on nearest offset to the cursor, not offset before
389 - * the cursor.
390 - */
391 - var $ruler = $( '<div class="es-contentView-ruler"></div>' ).appendTo( this.$ ),
392 - ruler = $ruler[0],
393 - fit = this.fitCharacters( line.range, ruler, position.left ),
394 - center;
395 - ruler.innerHTML = this.getHtml( new ve.Range( line.range.start, fit.end ) );
396 - if ( fit.end < this.model.getContentLength() ) {
397 - var left = ruler.clientWidth;
398 - ruler.innerHTML = this.getHtml( new ve.Range( line.range.start, fit.end + 1 ) );
399 - center = Math.round( left + ( ( ruler.clientWidth - left ) / 2 ) );
400 - } else {
401 - center = ruler.clientWidth;
402 - }
403 - $ruler.remove();
404 - // Reset RegExp object's state
405 - this.boundaryTest.lastIndex = 0;
406 - return Math.min(
407 - // If the position is right of the center of the character it's on top of, increment offset
408 - fit.end + ( position.left >= center ? 1 : 0 ),
409 - // Don't allow the value to be higher than the end
410 - line.range.end
411 - );
412 -};
413 -
414 -/**
415 - * Gets position coordinates of a given offset.
416 - *
417 - * Offsets are boundaries between plain or annotated characters within content model. Results are
418 - * given in left, top and bottom positions, which could be used to draw a cursor, highlighting, etc.
419 - *
420 - * @method
421 - * @param {Integer} offset Offset within content model
422 - * @returns {Object} Object containing left, top and bottom properties, each positions in pixels as
423 - * well as a line index
424 - */
425 -ve.es.Content.prototype.getRenderedPositionFromOffset = function( offset, leftBias ) {
426 - /*
427 - * Range validation
428 - *
429 - * Rather than clamping the range, which can hide errors, exceptions will be thrown if offset is
430 - * less than 0 or greater than the length of the content model.
431 - */
432 - if ( offset < 0 ) {
433 - throw 'Out of range error. Offset is expected to be greater than or equal to 0.';
434 - } else if ( offset > this.model.getContentLength() ) {
435 - throw 'Out of range error. Offset is expected to be less than or equal to text length.';
436 - }
437 - /*
438 - * Line finding
439 - *
440 - * It's possible that a more efficient method could be used here, but the number of lines to be
441 - * iterated through will rarely be over 100, so it's unlikely that any significant gains will be
442 - * had. Plus, as long as we are iterating over each line, we can also sum up the top and bottom
443 - * positions, which is a nice benefit of this method.
444 - */
445 - var line,
446 - lineCount = this.lines.length,
447 - lineIndex = 0,
448 - position = new ve.Position();
449 - while ( lineIndex < lineCount ) {
450 - line = this.lines[lineIndex];
451 - if ( line.range.containsOffset( offset ) || ( leftBias && line.range.end === offset ) ) {
452 - position.bottom = position.top + line.height;
453 - break;
454 - }
455 - position.top += line.height;
456 - lineIndex++;
457 - }
458 - /*
459 - * Virtual n+1 position
460 - *
461 - * To allow access to position information of the right side of the last character on the last
462 - * line, a virtual n+1 position is supported. Offsets beyond this virtual position will cause
463 - * an exception to be thrown.
464 - */
465 - if ( lineIndex === lineCount ) {
466 - position.bottom = position.top;
467 - position.top -= line.height;
468 - }
469 - /*
470 - * Offset measuring
471 - *
472 - * Since the left position will be zero for the first character in the line, so we can skip
473 - * measuring for those cases.
474 - */
475 - if ( line.range.start < offset ) {
476 - var $ruler = $( '<div class="es-contentView-ruler"></div>' ).appendTo( this.$ ),
477 - ruler = $ruler[0];
478 - ruler.innerHTML = this.getHtml( new ve.Range( line.range.start, offset ) );
479 - position.left = ruler.clientWidth;
480 - $ruler.remove();
481 - }
482 - return position;
483 -};
484 -
485 -/**
486207 * Updates the word boundary cache, which is used for word fitting.
487208 *
488209 * @method
@@ -525,341 +246,11 @@
526247 }
527248 };
528249
529 -/**
530 - * Renders a batch of lines and then yields execution before rendering another batch.
531 - *
532 - * In cases where a single word is too long to fit on a line, the word will be "virtually" wrapped,
533 - * causing them to be fragmented. Word fragments are rendered on their own lines, except for their
534 - * remainder, which is combined with whatever proceeding words can fit on the same line.
535 - *
536 - * @method
537 - * @param {Integer} limit Maximum number of iterations to render before yeilding
538 - */
539 -ve.es.Content.prototype.renderIteration = function( limit ) {
540 - var rs = this.renderState,
541 - iteration = 0,
542 - fractional = false,
543 - lineStart = this.boundaries[rs.wordOffset],
544 - lineEnd,
545 - wordFit = null,
546 - charOffset = 0,
547 - charFit = null,
548 - wordCount = this.boundaries.length;
549 - while ( ++iteration <= limit && rs.wordOffset < wordCount - 1 ) {
550 - wordFit = this.fitWords( new ve.Range( rs.wordOffset, wordCount - 1 ), rs.ruler, rs.width );
551 - fractional = false;
552 - if ( wordFit.width > rs.width ) {
553 - // The first word didn't fit, we need to split it up
554 - charOffset = lineStart;
555 - var lineOffset = rs.wordOffset;
556 - rs.wordOffset++;
557 - lineEnd = this.boundaries[rs.wordOffset];
558 - do {
559 - charFit = this.fitCharacters(
560 - new ve.Range( charOffset, lineEnd ), rs.ruler, rs.width
561 - );
562 - // If we were able to get the rest of the characters on the line OK
563 - if ( charFit.end === lineEnd) {
564 - // Try to fit more words on the line
565 - wordFit = this.fitWords(
566 - new ve.Range( rs.wordOffset, wordCount - 1 ),
567 - rs.ruler,
568 - rs.width - charFit.width
569 - );
570 - if ( wordFit.end > rs.wordOffset ) {
571 - lineOffset = rs.wordOffset;
572 - rs.wordOffset = wordFit.end;
573 - charFit.end = lineEnd = this.boundaries[rs.wordOffset];
574 - }
575 - }
576 - this.appendLine( new ve.Range( charOffset, charFit.end ), lineOffset, fractional );
577 - // Move on to another line
578 - charOffset = charFit.end;
579 - // Mark the next line as fractional
580 - fractional = true;
581 - } while ( charOffset < lineEnd );
582 - } else {
583 - lineEnd = this.boundaries[wordFit.end];
584 - this.appendLine( new ve.Range( lineStart, lineEnd ), rs.wordOffset, fractional );
585 - rs.wordOffset = wordFit.end;
586 - }
587 - lineStart = lineEnd;
588 - }
589 - // Only perform on actual last iteration
590 - if ( rs.wordOffset >= wordCount - 1 ) {
591 - // Cleanup
592 - rs.$ruler.remove();
593 - if ( rs.line < this.lines.length ) {
594 - this.lines.splice( rs.line, this.lines.length - rs.line );
595 - }
596 - this.$.find( '.es-contentView-line[line-index=' + ( this.lines.length - 1 ) + ']' )
597 - .nextAll()
598 - .remove();
599 - rs.timeout = undefined;
600 - this.emit( 'update' );
601 - } else {
602 - rs.ruler.innerHTML = '';
603 - var that = this;
604 - rs.timeout = setTimeout( function() {
605 - that.renderIteration( 3 );
606 - }, 0 );
607 - }
608 -};
609 -
610 -/**
611 - * Renders text into a series of HTML elements, each a single line of wrapped text.
612 - *
613 - * The offset parameter can be used to reduce the amount of work involved in re-rendering the same
614 - * text, but will be automatically ignored if the text or width of the container has changed.
615 - *
616 - * Rendering happens asynchronously, and yields execution between iterations. Iterative rendering
617 - * provides the JavaScript engine an ability to process events between rendering batches of lines,
618 - * allowing rendering to be interrupted and restarted if changes to content model are happening before
619 - * rendering of all lines is complete.
620 - *
621 - * @method
622 - * @param {Integer} [offset] Offset to re-render from, if possible
623 - */
624250 ve.es.Content.prototype.render = function( offset ) {
625 - this.$.html(this.getHtml(0, this.model.getContentLength()));
626 - return;
627 -
628 - var rs = this.renderState;
629 - // Check if rendering is currently underway
630 - if ( rs.timeout !== undefined ) {
631 - // Cancel the active rendering process
632 - clearTimeout( rs.timeout );
633 - // Cleanup
634 - rs.$ruler.remove();
635 - }
636 - // Clear caches that were specific to the previous render
637 - this.widthCache = {};
638 - // In case of empty content model we still want to display empty with non-breaking space inside
639 - // This is very important for lists
640 - if(this.model.getContentLength() === 0) {
641 - var $line = $( '<div class="es-contentView-line" line-index="0">&nbsp;</div>' );
642 - this.$
643 - .children()
644 - .remove( '.es-contentView-line' )
645 - .end()
646 - .append( $line );
647 - this.lines = [{
648 - 'text': ' ',
649 - 'range': new ve.Range( 0,0 ),
650 - 'width': 0,
651 - 'height': $line.outerHeight(),
652 - 'wordOffset': 0,
653 - 'fractional': false
654 - }];
655 - this.emit( 'update' );
656 - return;
657 - }
658 - /*
659 - * Container measurement
660 - *
661 - * To get an accurate measurement of the inside of the container, without having to deal with
662 - * inconsistencies between browsers and box models, we can just create an element inside the
663 - * container and measure it.
664 - */
665 - rs.$ruler = $( '<div>&nbsp;</div>' ).appendTo( this.$ );
666 - rs.width = rs.$ruler.innerWidth();
667 - rs.ruler = rs.$ruler.addClass('es-contentView-ruler')[0];
668 - // Ignore offset optimization if the width has changed or the text has never been flowed before
669 - if (this.width !== rs.width) {
670 - offset = undefined;
671 - }
672 - this.width = rs.width;
673 - // Reset the render state
674 - if ( offset ) {
675 - var gap,
676 - currentLine = this.lines.length - 1;
677 - for ( var i = this.lines.length - 1; i >= 0; i-- ) {
678 - var line = this.lines[i];
679 - if ( line.range.start < offset && line.range.end > offset ) {
680 - currentLine = i;
681 - }
682 - if ( ( line.range.end < offset && !line.fractional ) || i === 0 ) {
683 - rs.line = i;
684 - rs.wordOffset = line.wordOffset;
685 - gap = currentLine - i;
686 - break;
687 - }
688 - }
689 - this.renderIteration( 2 + gap );
690 - } else {
691 - rs.line = 0;
692 - rs.wordOffset = 0;
693 - this.renderIteration( 3 );
694 - }
 251+ this.$.html( this.getHtml( 0, this.model.getContentLength() ) );
695252 };
696253
697254 /**
698 - * Adds a line containing a given range of text to the end of the DOM and the "lines" array.
699 - *
700 - * @method
701 - * @param {ve.Range} range Range of data within content model to append
702 - * @param {Integer} start Beginning of text range for line
703 - * @param {Integer} end Ending of text range for line
704 - * @param {Integer} wordOffset Index within this.words which the line begins with
705 - * @param {Boolean} fractional If the line begins in the middle of a word
706 - */
707 -ve.es.Content.prototype.appendLine = function( range, wordOffset, fractional ) {
708 - var rs = this.renderState,
709 - $line = this.$.children( '[line-index=' + rs.line + ']' );
710 - if ( !$line.length ) {
711 - $line = $(
712 - '<div class="es-contentView-line" line-index="' + rs.line + '"></div>'
713 - );
714 - this.$.append( $line );
715 - }
716 - $line[0].innerHTML = this.getHtml( range );
717 - // Overwrite/append line information
718 - this.lines[rs.line] = {
719 - 'text': this.model.getContentText( range ),
720 - 'range': range,
721 - 'width': $line.outerWidth(),
722 - 'height': $line.outerHeight(),
723 - 'wordOffset': wordOffset,
724 - 'fractional': fractional
725 - };
726 - // Disable links within rendered content
727 - $line.find( '.es-contentView-format-object a' )
728 - .mousedown( function( e ) {
729 - e.preventDefault();
730 - } )
731 - .click( function( e ) {
732 - e.preventDefault();
733 - } );
734 - rs.line++;
735 -};
736 -
737 -/**
738 - * Gets the index of the boundary of last word that fits inside the line
739 - *
740 - * The "words" and "boundaries" arrays provide linear access to the offsets around non-breakable
741 - * areas within the text. Using these, we can perform a binary-search for the best fit of words
742 - * within a line, just as we would with characters.
743 - *
744 - * Results are given as an object containing both an index and a width, the later of which can be
745 - * used to detect when the first word was too long to fit on a line. In such cases the result will
746 - * contain the index of the boundary of the first word and it's width.
747 - *
748 - * TODO: Because limit is most likely given as "words.length", it may be possible to improve the
749 - * efficiency of this code by making a best guess and working from there, rather than always
750 - * starting with [offset .. limit], which usually results in reducing the end position in all but
751 - * the last line, and in most cases more than 3 times, before changing directions.
752 - *
753 - * @method
754 - * @param {ve.Range} range Range of data within content model to try to fit
755 - * @param {HTMLElement} ruler Element to take measurements with
756 - * @param {Integer} width Maximum width to allow the line to extend to
757 - * @returns {Integer} Last index within "words" that contains a word that fits
758 - */
759 -ve.es.Content.prototype.fitWords = function( range, ruler, width ) {
760 - var offset = range.start,
761 - start = range.start,
762 - end = range.end,
763 - charOffset = this.boundaries[offset],
764 - middle,
765 - charMiddle,
766 - lineWidth,
767 - cacheKey;
768 - do {
769 - // Place "middle" directly in the center of "start" and "end"
770 - middle = Math.ceil( ( start + end ) / 2 );
771 - charMiddle = this.boundaries[middle];
772 - // Measure and cache width of substring
773 - cacheKey = charOffset + ':' + charMiddle;
774 - // Prepare the line for measurement using pre-escaped HTML
775 - ruler.innerHTML = this.getHtml( new ve.Range( charOffset, charMiddle ) );
776 - // Test for over/under using width of the rendered line
777 - this.widthCache[cacheKey] = lineWidth = ruler.clientWidth;
778 - // Test for over/under using width of the rendered line
779 - if ( lineWidth > width ) {
780 - // Detect impossible fit (the first word won't fit by itself)
781 - if (middle - offset === 1) {
782 - start = middle;
783 - break;
784 - }
785 - // Words after "middle" won't fit
786 - end = middle - 1;
787 - } else {
788 - // Words before "middle" will fit
789 - start = middle;
790 - }
791 - } while ( start < end );
792 - // Check if we ended by moving end to the left of middle
793 - if ( end === middle - 1 ) {
794 - // A final measurement is required
795 - var charStart = this.boundaries[start];
796 - ruler.innerHTML = this.getHtml( new ve.Range( charOffset, charStart ) );
797 - lineWidth = this.widthCache[charOffset + ':' + charStart] = ruler.clientWidth;
798 - }
799 - return { 'end': start, 'width': lineWidth };
800 -};
801 -
802 -/**
803 - * Gets the index of the boundary of the last character that fits inside the line
804 - *
805 - * Results are given as an object containing both an index and a width, the later of which can be
806 - * used to detect when the first character was too long to fit on a line. In such cases the result
807 - * will contain the index of the first character and it's width.
808 - *
809 - * @method
810 - * @param {ve.Range} range Range of data within content model to try to fit
811 - * @param {HTMLElement} ruler Element to take measurements with
812 - * @param {Integer} width Maximum width to allow the line to extend to
813 - * @returns {Integer} Last index within "text" that contains a character that fits
814 - */
815 -ve.es.Content.prototype.fitCharacters = function( range, ruler, width ) {
816 - var offset = range.start,
817 - start = range.start,
818 - end = range.end,
819 - middle,
820 - lineWidth,
821 - cacheKey;
822 - do {
823 - // Place "middle" directly in the center of "start" and "end"
824 - middle = Math.ceil( ( start + end ) / 2 );
825 - // Measure and cache width of substring
826 - cacheKey = offset + ':' + middle;
827 - if ( cacheKey in this.widthCache ) {
828 - lineWidth = this.widthCache[cacheKey];
829 - } else {
830 - // Fill the line with a portion of the text, escaped as HTML
831 - ruler.innerHTML = this.getHtml( new ve.Range( offset, middle ) );
832 - // Test for over/under using width of the rendered line
833 - this.widthCache[cacheKey] = lineWidth = ruler.clientWidth;
834 - }
835 - if ( lineWidth > width ) {
836 - // Detect impossible fit (the first character won't fit by itself)
837 - if (middle - offset === 1) {
838 - start = middle - 1;
839 - break;
840 - }
841 - // Words after "middle" won't fit
842 - end = middle - 1;
843 - } else {
844 - // Words before "middle" will fit
845 - start = middle;
846 - }
847 - } while ( start < end );
848 - // Check if we ended by moving end to the left of middle
849 - if ( end === middle - 1 ) {
850 - // Try for cache hit
851 - cacheKey = offset + ':' + start;
852 - if ( cacheKey in this.widthCache ) {
853 - lineWidth = this.widthCache[cacheKey];
854 - } else {
855 - // A final measurement is required
856 - ruler.innerHTML = this.getHtml( new ve.Range( offset, start ) );
857 - lineWidth = this.widthCache[cacheKey] = ruler.clientWidth;
858 - }
859 - }
860 - return { 'end': start, 'width': lineWidth };
861 -};
862 -
863 -/**
864255 * Gets an HTML rendering of a range of data within content model.
865256 *
866257 * @method
@@ -926,4 +317,4 @@
927318
928319 /* Inheritance */
929320
930 -ve.extendClass( ve.es.Content, ve.EventEmitter );
 321+ve.extendClass( ve.es.Content, ve.EventEmitter );
\ No newline at end of file

Status & tagging log