http://www.mediawiki.org/wiki/Special:Code/MediaWiki/90564
Revision: 90564
Author: tparscal
Date: 2011-06-22 00:23:07 +0000 (Wed, 22 Jun 2011)
Log Message:
-----------
Replaced text flow algorithm with a binary-search approach, lifted from
jquery.autoEllipsis
Modified Paths:
--------------
trunk/parsers/wikidom/demos/es/index.html
trunk/parsers/wikidom/lib/es/es.Block.js
trunk/parsers/wikidom/lib/es/es.Document.js
trunk/parsers/wikidom/lib/es/es.ParagraphBlock.js
trunk/parsers/wikidom/lib/es/es.Surface.css
trunk/parsers/wikidom/lib/es/es.Surface.js
trunk/parsers/wikidom/lib/es/es.TextFlow.js
Modified: trunk/parsers/wikidom/demos/es/index.html
===================================================================
--- trunk/parsers/wikidom/demos/es/index.html 2011-06-22 00:16:25 UTC (rev
90563)
+++ trunk/parsers/wikidom/demos/es/index.html 2011-06-22 00:23:07 UTC (rev
90564)
@@ -37,7 +37,7 @@
var surface = new Surface( $('#es'), doc );
$(window).resize( function() {
- surface.reflow();
+ surface.render();
} );
} );
</script>
Modified: trunk/parsers/wikidom/lib/es/es.Block.js
===================================================================
--- trunk/parsers/wikidom/lib/es/es.Block.js 2011-06-22 00:16:25 UTC (rev
90563)
+++ trunk/parsers/wikidom/lib/es/es.Block.js 2011-06-22 00:23:07 UTC (rev
90564)
@@ -74,6 +74,15 @@
};
/**
+ * Updates the rendered content in a container.
+ *
+ * @param $container {jQuery Selection} Container to update content in
+ */
+Block.prototype.updateContent = function( $container ) {
+ throw 'Block.updateContent not implemented in this subclass.';
+};
+
+/**
* Gets the location of a position.
*
* @param position {Position} Position to translate
Modified: trunk/parsers/wikidom/lib/es/es.Document.js
===================================================================
--- trunk/parsers/wikidom/lib/es/es.Document.js 2011-06-22 00:16:25 UTC (rev
90563)
+++ trunk/parsers/wikidom/lib/es/es.Document.js 2011-06-22 00:23:07 UTC (rev
90564)
@@ -5,6 +5,9 @@
*/
function Document( blocks ) {
this.blocks = blocks || [];
+ this.width = null;
+ this.$ = $( '<div class="editSurface-document"></div>' )
+ .data( 'document', this );
}
/**
@@ -69,3 +72,27 @@
this.blocks.splice( block.index(), 1 );
block.document = null;
};
+
+Document.prototype.renderBlocks = function() {
+ // Remember width, to avoid updates when without width changes
+ this.width = this.$.innerWidth();
+ // Render blocks
+ for ( var i = 0; i < this.blocks.length; i++ ) {
+ this.$.append( this.blocks[i].$ );
+ this.blocks[i].renderContent();
+ }
+};
+
+Document.prototype.updateBlocks = function() {
+ // Bypass rendering when width has not changed
+ var width = this.$.innerWidth();
+ if ( this.width === width ) {
+ return;
+ }
+ this.width = width;
+ // Render blocks
+ var doc;
+ this.$.children( '.editSurface-block' ).each( function( i ) {
+ $(this).data( 'block' ).renderContent();
+ } );
+};
Modified: trunk/parsers/wikidom/lib/es/es.ParagraphBlock.js
===================================================================
--- trunk/parsers/wikidom/lib/es/es.ParagraphBlock.js 2011-06-22 00:16:25 UTC
(rev 90563)
+++ trunk/parsers/wikidom/lib/es/es.ParagraphBlock.js 2011-06-22 00:23:07 UTC
(rev 90564)
@@ -6,7 +6,10 @@
function ParagraphBlock( lines ) {
Block.call( this );
this.lines = lines || [];
- this.metrics = [];
+ this.lineMetrics = [];
+ this.$ = $( '<div class="editSurface-block
editSurface-paragraph"></div>' )
+ .data( 'block', this );
+ this.flow = new TextFlow( this.$ );
}
/**
@@ -78,13 +81,12 @@
*
* @param $container {jQuery Selection} Container to render into
*/
-Block.prototype.renderContent = function( $container ) {
- var flow = new TextFlow(),
- text = [];
+Block.prototype.renderContent = function() {
+ var text = [];
for ( var i = 0; i < this.lines.length; i++ ) {
text.push( this.lines[i].text );
}
- this.metrics = flow.render( $container, text.join( '\n' ) );
+ this.lineMetrics = this.flow.render( text.join( '\n' ) );
};
/**
Modified: trunk/parsers/wikidom/lib/es/es.Surface.css
===================================================================
--- trunk/parsers/wikidom/lib/es/es.Surface.css 2011-06-22 00:16:25 UTC (rev
90563)
+++ trunk/parsers/wikidom/lib/es/es.Surface.css 2011-06-22 00:23:07 UTC (rev
90564)
@@ -3,16 +3,14 @@
font-size: 0.8em;
}
-.editSurface-container {
- position: absolute;
- left: 3%;
- width: 45%;
- border: solid 1px red;
+.editSurface-document {
+ border: solid 1px silver;
cursor: text;
+ width: 50%;
}
.editSurface-paragraph {
- padding: 2em;
+ margin: 2em;
}
.editSurface-line {
@@ -21,6 +19,7 @@
line-height: 1.5em;
cursor: text;
white-space: nowrap;
+ background-color: #eeeeee;
}
.editSurface-line.empty {
Modified: trunk/parsers/wikidom/lib/es/es.Surface.js
===================================================================
--- trunk/parsers/wikidom/lib/es/es.Surface.js 2011-06-22 00:16:25 UTC (rev
90563)
+++ trunk/parsers/wikidom/lib/es/es.Surface.js 2011-06-22 00:23:07 UTC (rev
90564)
@@ -5,9 +5,10 @@
* @returns {Surface}
*/
function Surface( $container, document ) {
- this.$container = $container;
+ this.$ = $container;
this.document = document;
- this.reflow();
+ this.rendered = false;
+ this.render();
}
/**
@@ -167,10 +168,12 @@
*
* @param from Location: Where to start re-flowing from (optional)
*/
-Surface.prototype.reflow = function( from ) {
- this.$container.empty();
- for ( var i = 0; i < this.document.blocks.length; i++ ) {
- $block = $( '<div></div>' ).appendTo( this.$container );
- this.document.blocks[i].renderContent( $block );
+Surface.prototype.render = function( from ) {
+ if ( !this.rendered ) {
+ this.rendered = true;
+ this.$.append( this.document.$ );
+ this.document.renderBlocks();
+ } else {
+ this.document.updateBlocks();
}
};
Modified: trunk/parsers/wikidom/lib/es/es.TextFlow.js
===================================================================
--- trunk/parsers/wikidom/lib/es/es.TextFlow.js 2011-06-22 00:16:25 UTC (rev
90563)
+++ trunk/parsers/wikidom/lib/es/es.TextFlow.js 2011-06-22 00:23:07 UTC (rev
90564)
@@ -1,89 +1,90 @@
/**
* TODO: Don't re-flow lines beyond a given offset, an optimization for
insert/delete operations
*/
-function TextFlow() {
- //
+function TextFlow( $container ) {
+ this.$ = $container;
}
-TextFlow.prototype.render = function( $container, text ) {
- //console.time( 'TextFlow.render' );
- var metrics = [],
- $ruler = $( '<div class="editSurface-line"></div>' ).appendTo(
$container ),
- $line = $( '<div class="editSurface-line"></div>' ),
- lines = this.getLines( this.getWords( text, $ruler[0] ),
$ruler.innerWidth() );
- $container.empty();
- for ( var i = 0; i < lines.length; i++ ) {
- metrics.push( lines[i] );
- if ( lines[i].text.length === 1 && lines[1].text.match( /[
\-\t\r\n\f]/ ) ) {
- $container.append( $line.clone().html( ' '
).addClass( 'empty' ) );
- } else {
- $container.append( $line.clone().html( lines[i].html )
);
- }
- }
- //console.timeEnd( 'TextFlow.render' );
- return metrics;
+TextFlow.encodeHtml = function( text ) {
+ return text
+ .replace( /&/g, '&' )
+ .replace( / /g, ' ' )
+ .replace( /</g, '<' )
+ .replace( />/g, '>' )
+ .replace( /'/g, ''' )
+ .replace( /"/g, '"' )
+ .replace( /\n/g, '<span
class="editSurface-whitespace">\\n</span>' )
+ .replace( /\t/g, '<span
class="editSurface-whitespace">\\t</span>' );
};
-TextFlow.prototype.getWord = function( text, ruler ) {
- var word = {
- 'text': text,
- 'html': text
- .replace( /&/g, '&' )
- .replace( / /g, ' ' )
- .replace( /</g, '<' )
- .replace( />/g, '>' )
- .replace( /'/g, ''' )
- .replace( /"/g, '"' )
- .replace( /\n/g, '<span
class="editSurface-whitespace">\\n</span>' )
- .replace( /\t/g, '<span
class="editSurface-whitespace">\\t</span>' )
- };
- ruler.innerHTML = word.html;
- word.width = ruler.clientWidth;
- return word;
-};
-
-TextFlow.prototype.getWords = function( text, ruler ) {
- var words = [],
- bounadry = /[ \-\t\r\n\f]/,
+TextFlow.prototype.render = function( text ) {
+ //console.time( 'TextFlow.render' );
+
+ // Clear all lines -- FIXME: This should adaptively re-use/cleanup
existing lines
+ this.$.empty();
+
+ // Measure the container width
+ var $ruler = $( '<div> </div>' ).appendTo( this.$ );
+ var width = $ruler.innerWidth()
+ $ruler.remove();
+
+ // Build list of line break offsets
+ var words = [0],
+ boundary = /[ \-\t\r\n\f]/,
left = 0,
right = 0,
search = 0;
- while ( ( search = text.substr( right ).search( bounadry ) ) >= 0 ) {
+ while ( ( search = text.substr( right ).search( boundary ) ) >= 0 ) {
right += search;
- words.push( this.getWord( text.substring( left, right ), ruler
) );
- if ( right < text.length ) {
- words.push( this.getWord( text.substring( right,
++right ), ruler ) );
- }
+ words.push( ++right );
left = right;
}
- words.push( this.getWord( text.substring( right, text.length ), ruler )
);
- return words;
-};
-
-TextFlow.prototype.getLines = function( words, width ) {
- var lines = [],
- line = {
- 'text': '',
- 'html': '',
- 'width': 0,
- 'index': lines.length
- };
- for ( var i = 0; i < words.length; i++ ) {
- if ( line.width + words[i].width > width ) {
- lines.push( line );
- line = {
- 'text': '',
- 'html': '',
- 'width': 0,
- 'index': lines.length
- };
- }
- line.text += words[i].text;
- line.html += words[i].html;
- line.width += words[i].width;
+ words.push( right );
+ words.push( text.length );
+
+ // Create lines from text
+ var pos = 0,
+ index = 0,
+ metrics = [];
+ while ( pos < words.length - 1 ) {
+ // Create line
+ var $line = $( '<div class="editSurface-line"></div>' )
+ .attr( 'line-index', index )
+ .appendTo( this.$ ),
+ line = $line[0];
+
+ // Use binary search-like technique for efficiency
+ var l = pos,
+ r = words.length,
+ m;
+ do {
+ m = Math.ceil( ( l + r ) / 2 );
+ line.innerHTML = TextFlow.encodeHtml( text.substring(
words[pos], words[m] ) );
+ if ( line.clientWidth > width ) {
+ // Text is too long
+ r = m - 1;
+ } else {
+ l = m;
+ }
+ } while ( l < r );
+ line.innerHTML = TextFlow.encodeHtml( text.substring(
words[pos], words[l] ) );
+
+ // TODO: Check if it fits yet, if not, do binary search within
the really long word
+
+ metrics.push({
+ 'text': text.substring( words[pos], words[l] ),
+ 'offset': words[pos],
+ 'length': words[l] - words[pos],
+ 'width': line.clientWidth,
+ 'index': index
+ });
+
+ // Step forward
+ index++;
+ pos = m;
}
- if ( line.text.length ) {
- lines.push( line );
- }
- return lines;
+
+ //console.timeEnd( 'TextFlow.render' );
+
+ return metrics;
};
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs