r94081 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r94080‎ | r94081 | r94082 >
Date:20:07, 8 August 2011
Author:tparscal
Status:deferred
Tags:
Comment:
Moved rough draft code into surface demo
Modified paths:
  • /trunk/parsers/wikidom/demos/surface/index.html (modified) (history)
  • /trunk/parsers/wikidom/demos/surface/jquery.editSurface.css (added) (history)
  • /trunk/parsers/wikidom/demos/surface/jquery.editSurface.js (added) (history)
  • /trunk/parsers/wikidom/demos/surface/jquery.flow.js (added) (history)
  • /trunk/parsers/wikidom/lib/jquery.editSurface.css (deleted) (history)
  • /trunk/parsers/wikidom/lib/jquery.editSurface.js (deleted) (history)
  • /trunk/parsers/wikidom/lib/jquery.flow.js (deleted) (history)

Diff [purge]

Index: trunk/parsers/wikidom/lib/jquery.flow.js
@@ -1,187 +0,0 @@
2 -/*
3 - * Flow jQuery plugin
4 - *
5 - * Each line has data in the following structure, embedded as $line.data( 'flow' )
6 - * {
7 - * index: 0,
8 - * text: 'abc 123',
9 - * metrics: [9,4,9]
10 - * width: 22,
11 - * words: [
12 - * {
13 - * text: 'abc',
14 - * html: 'abc',
15 - * metrics: [3,3,3],
16 - * width: 9,
17 - * index: 0,
18 - * offset: 0
19 - * },
20 - * {
21 - * text: ' ',
22 - * html: ' ',
23 - * metrics: [4],
24 - * width: 4,
25 - * index: 1,
26 - * offset: 3
27 - * },
28 - * {
29 - * text: '123',
30 - * html: '123',
31 - * metrics: [3,3,3]
32 - * width: 9,
33 - * index: 2,
34 - * offset: 4
35 - * }
36 - * ]
37 - * }
38 - */
39 -function copy( from, to ) {
40 - if ( typeof to === 'undefined' ) {
41 - to = {};
42 - }
43 - if ( from == null || typeof from != 'object' ) {
44 - return from;
45 - }
46 - if ( from.constructor != Object && from.constructor != Array ) {
47 - return from;
48 - }
49 - if ( from.constructor == Date
50 - || from.constructor == RegExp
51 - || from.constructor == Function
52 - || from.constructor == String
53 - || from.constructor == Number
54 - || from.constructor == Boolean ) {
55 - return new from.constructor( from );
56 - }
57 - to = to || new from.constructor();
58 - for ( var name in from ) {
59 - to[name] = typeof to[name] == 'undefined' ? copy( from[name], null ) : to[name];
60 - }
61 - return to;
62 -}
63 -
64 -$.flow = {
65 - 'charCache': {},
66 - 'wordCache': {},
67 - 'measureWord': function( text, ruler ) {
68 - if ( typeof $.flow.wordCache[text] === 'undefined' ) {
69 - // Cache miss
70 - var word = { 'text': text, 'html': '', 'metrics': [] };
71 - for ( var i = 0; i < text.length; i++ ) {
72 - var char = text[i],
73 - charHtml = char
74 - .replace( '&', '&amp;' )
75 - .replace( ' ', '&nbsp;' )
76 - .replace( '<', '&lt;' )
77 - .replace( '>', '&gt;' )
78 - .replace( '\'', '&apos;' )
79 - .replace( '"', '&quot;' )
80 - .replace( '\n', '<span class="editSurface-whitespace">\\n</span>' )
81 - .replace( '\t', '<span class="editSurface-whitespace">\\t</span>' );
82 - word.html += charHtml;
83 - if ( typeof $.flow.charCache[char] === 'undefined' ) {
84 - // Cache miss
85 - ruler.innerHTML = charHtml;
86 - word.metrics.push( $.flow.charCache[char] = ruler.clientWidth );
87 - continue;
88 - }
89 - // Cache hit
90 - word.metrics.push( $.flow.charCache[char] );
91 - }
92 - ruler.innerHTML = word.html;
93 - word.width = ruler.clientWidth;
94 - $.flow.wordCache[text] = copy( word );
95 - return word;
96 - }
97 - // Cache hit
98 - return copy( $.flow.wordCache[text] );
99 - },
100 - 'getWords': function( text, ruler ) {
101 - var words = [],
102 - bounadry = /[ \-\t\r\n\f]/,
103 - left = 0,
104 - right = 0,
105 - search = 0;
106 - while ( ( search = text.substr( right ).search( bounadry ) ) >= 0 ) {
107 - right += search;
108 - words.push( $.flow.measureWord( text.substring( left, right ), ruler ) );
109 - if ( right < text.length ) {
110 - words.push( $.flow.measureWord( text.substring( right, ++right ), ruler ) );
111 - }
112 - left = right;
113 - }
114 - words.push( $.flow.measureWord( text.substring( right, text.length ), ruler ) );
115 - return words;
116 - },
117 - 'getLines': function( words, width ) {
118 - // Lineify
119 - var lineCount = 0,
120 - charCount = 0,
121 - wordCount = 0,
122 - lines = [],
123 - line = {
124 - 'text': '',
125 - 'html': '',
126 - 'width': 0,
127 - 'metrics': [],
128 - 'words': [],
129 - 'index': lineCount
130 - };
131 - for ( var i = 0; i < words.length; i++ ) {
132 - if ( line.width + words[i].width > width ) {
133 - lines.push( line );
134 - charCount = 0;
135 - wordCount = 0;
136 - lineCount++;
137 - line = {
138 - 'text': '',
139 - 'html': '',
140 - 'width': 0,
141 - 'metrics': [],
142 - 'words': [],
143 - 'index': lineCount
144 - };
145 - }
146 - words[i].index = wordCount;
147 - wordCount++;
148 - words[i].offset = charCount;
149 - charCount += words[i].text.length;
150 - line.words.push( words[i] );
151 - line.text += words[i].text;
152 - line.html += words[i].html;
153 - line.width += words[i].width;
154 - line.metrics.push( words[i].width );
155 - }
156 - if ( line.text.length ) {
157 - lines.push( line );
158 - }
159 - return lines;
160 - }
161 -};
162 -
163 -$.fn.flow = function( text ) {
164 - //console.time( 'flow' );
165 -
166 - var $this = $(this),
167 - $ruler = $( '<div></div>' ).appendTo( $(this) ),
168 - lines = $.flow.getLines(
169 - $.flow.getWords( text, $( '<div class="editSurface-line"></div>' ).appendTo( $this )[0] ),
170 - $ruler.innerWidth()
171 - );
172 -
173 - // Flow
174 - $this.empty();
175 - for ( var i = 0; i < lines.length; i++ ) {
176 - var $line = $( '<div class="editSurface-line"></div>' ).data( 'flow', lines[i] );
177 - if ( lines[i].text.length === 1 && lines[1].text.match( /[ \-\t\r\n\f]/ ) ) {
178 - $line.html( '&nbsp;' );
179 - $line.addClass( 'empty' );
180 - } else {
181 - $line.html( lines[i].html );
182 - }
183 - $this.append( $line );
184 - }
185 -
186 - //console.timeEnd( 'flow' );
187 - return $this;
188 -};
Index: trunk/parsers/wikidom/lib/jquery.editSurface.css
@@ -1,65 +0,0 @@
2 -body {
3 - font-family: "Arial";
4 - font-size: 0.8em;
5 -}
6 -
7 -#selection {
8 - position: absolute;
9 - right: 3%;
10 - width: 45%;
11 - border: solid 1px Highlight;
12 - line-height: 1.5em;
13 - cursor: text;
14 - font-family: "Courier New", monospace;
15 - white-space: pre-wrap;
16 -}
17 -
18 -#selection p {
19 - margin: 0;
20 - padding: 2em;
21 -}
22 -
23 -.editSurface-container {
24 - position: absolute;
25 - left: 3%;
26 - width: 45%;
27 - border: solid 1px red;
28 - cursor: text;
29 -}
30 -
31 -.editSurface-paragraph {
32 - padding: 2em;
33 -}
34 -
35 -.editSurface-line {
36 - display: inline-block;
37 - height: 1.5em;
38 - line-height: 1.5em;
39 - cursor: text;
40 - white-space: nowrap;
41 -}
42 -
43 -.editSurface-line.empty {
44 - display: block;
45 - width: 0px;
46 -}
47 -
48 -.editSurface-line .editSurface-whitespace {
49 - color: #888888;
50 - padding: 0 0.25em;
51 -}
52 -
53 -.editSurface-range {
54 - display: none;
55 - position: absolute;
56 - background-color: Highlight;
57 - cursor: text;
58 -}
59 -
60 -.editSurface-cursor {
61 - position: absolute;
62 - background-color: black;
63 - width: 1px;
64 - height: 1.5em;
65 - display: none;
66 -}
Index: trunk/parsers/wikidom/lib/jquery.editSurface.js
@@ -1,293 +0,0 @@
2 -$.fn.editSurface = function( options ) {
3 - var $this = $(this);
4 - sel = {
5 - 'active': false
6 - };
7 -
8 - options = $.extend( {
9 - // Defaults
10 - 'document': null
11 - }, options );
12 -
13 - // Initialization
14 - $this
15 - .addClass( 'editSurface-container' )
16 - .append( '<div class="editSurface-document"></div>' )
17 - .after( '<div class="editSurface-cursor"></div>' )
18 - .before( '<div class="editSurface-range"></div>'
19 - + '<div class="editSurface-range"></div>'
20 - + '<div class="editSurface-range"></div>');
21 -
22 - // Shortcuts
23 - var $document = $this.find( '.editSurface-document' );
24 - var ranges = {
25 - '$all': $( '.editSurface-range' ),
26 - '$first': $( '.editSurface-range:eq(0)' ),
27 - '$fill': $( '.editSurface-range:eq(1)' ),
28 - '$last': $( '.editSurface-range:eq(2)' )
29 - };
30 -
31 - // Events
32 - $(document).bind( {
33 - 'mousedown': function( e ) {
34 - var $target = $( e.target );
35 - if ( $target.is( '.editSurface-paragraph' ) ) {
36 - $target = getNearestLine( $target.children(), e.pageY );
37 - }
38 - if ( !$target.is( '.editSurface-line' ) ) {
39 - var $line = $target.closest( '.editSurface-line' );
40 - if ( $line.length ) {
41 - $target = $line;
42 - } else {
43 - return;
44 - }
45 - }
46 - sel = {
47 - 'active': true,
48 - 'from': null,
49 - 'to': null,
50 - 'start': getCursorPosition( e.pageX, e.pageY, $target ),
51 - 'end': null
52 - };
53 - cursor.show();
54 - drawSelection( sel.start.$target.parent() );
55 - // Move cursor
56 - if ( sel.start ) {
57 - cursor.$.css( {
58 - 'top': sel.start.top,
59 - 'left': sel.start.x
60 - } );
61 - }
62 - e.preventDefault();
63 - return false;
64 - },
65 - 'mouseup': function( e ) {
66 - if ( sel.active ) {
67 - if ( !sel.from || !sel.to
68 - || ( sel.from.line === sel.to.line && sel.from.char === sel.to.char ) ) {
69 - sel.from = null;
70 - sel.to = null;
71 - sel.start = null;
72 - sel.end = null;
73 - cursor.show();
74 - clearSelection();
75 - } else {
76 - drawSelection( sel.start.$target.parent() );
77 - }
78 - sel.active = false;
79 - }
80 - },
81 - 'mousemove': function( e ) {
82 - if ( sel.active ) {
83 - var $target = $( e.target );
84 - if ( !$target.is( '.editSurface-line' ) ) {
85 - $target = getNearestLine( sel.start.$target.parent().children(), e.pageY );
86 - }
87 - sel.end = getCursorPosition( e.pageX, e.pageY, $target );
88 - if ( sel.start.line < sel.end.line
89 - || ( sel.start.line === sel.end.line
90 - && sel.start.char < sel.end.char ) ) {
91 - sel.from = sel.start;
92 - sel.to = sel.end;
93 - } else {
94 - sel.from = sel.end;
95 - sel.to = sel.start;
96 - }
97 - cursor.hide();
98 - drawSelection( sel.start.$target.parent() );
99 - }
100 - }
101 - } );
102 -
103 - // Functions
104 - function getNearestLine( $lines, y ) {
105 - var $line,
106 - minDistance;
107 - $lines.each( function() {
108 - var top = $(this).offset().top;
109 - var bottom = top + $(this).height();
110 - // Inside test
111 - if ( y > top && y < bottom ) {
112 - $line = $(this);
113 - return false;
114 - }
115 - // Distance test
116 - var distance = Math.abs( y - top );
117 - if ( typeof minDistance === 'undefined' || distance < minDistance ) {
118 - minDistance = distance;
119 - $line = $(this);
120 - }
121 - } );
122 - return $line;
123 - }
124 - function getSelectionText() {
125 - var text;
126 - if ( sel.from && sel.to ) {
127 - if ( sel.from.line === sel.to.line ) {
128 - text = sel.from.$target.data( 'flow' ).text.substr(
129 - sel.from.char, sel.to.char - sel.from.char
130 - );
131 - } else {
132 - text = sel.from.$target.data( 'flow' ).text.substr( sel.from.char );
133 - var $sibling = sel.from.$target.next();
134 - for ( var i = sel.from.line + 1; i < sel.to.line; i++ ) {
135 - text += $sibling.data( 'flow' ).text
136 - $sibling = $sibling.next();
137 - }
138 - text += sel.to.$target.data( 'flow' ).text.substr( 0, sel.to.char );
139 - }
140 - }
141 - return text;
142 - }
143 - function getCursorPosition( x, y, $target ) {
144 - var line = $target.data( 'flow' ),
145 - offset = $target.offset(),
146 - height = $target.height(),
147 - l,
148 - r = 0,
149 - cur = x - offset.left;
150 - for ( var w = 0, eol = line.metrics.length - 1; w <= eol; w++ ) {
151 - l = r;
152 - r += line.metrics[w];
153 - if ( ( w === 0 && cur <= l ) || ( cur >= l && cur <= r ) || ( w === eol ) ) {
154 - var word = line.words[w],
155 - a,
156 - b = { 'l': l, 'c': l, 'r': l };
157 - for ( var c = 0, eow = word.metrics.length; c <= eow; c++ ) {
158 - a = b;
159 - b = {
160 - 'l': a.r,
161 - 'c': a.r + ( word.metrics[c] / 2 ),
162 - 'r': a.r + word.metrics[c]
163 - };
164 - if ( ( c === 0 && cur <= a.l ) || ( cur >= a.c && cur <= b.c ) || c === eow ) {
165 - return {
166 - '$target': $target,
167 - 'char': word.offset + Math.min( c, word.text.length - 1 ),
168 - 'word': word.index,
169 - 'line': line.index,
170 - 'x': offset.left + b.l,
171 - 'top': offset.top,
172 - 'bottom': offset.top + height,
173 - 'height': height
174 - };
175 - }
176 - }
177 - }
178 - }
179 - }
180 -
181 - function clearSelection() {
182 - ranges.$all.hide();
183 - }
184 -
185 - function drawSelection( $container ) {
186 - if ( sel.from && sel.to ) {
187 - if ( sel.from.line === sel.to.line ) {
188 - // 1 line
189 - if ( sel.from.char !== sel.to.char ) {
190 - ranges.$first.show().css( {
191 - 'left': sel.from.x,
192 - 'top': sel.from.top,
193 - 'width': sel.to.x - sel.from.x,
194 - 'height': sel.from.height
195 - } );
196 - ranges.$fill.hide();
197 - ranges.$last.hide();
198 - // XXX: Demo code!
199 - $( '#selection p' ).text( getSelectionText() );
200 - return;
201 - }
202 - } else if ( sel.from.line < sel.to.line ) {
203 - // 2+ lines
204 - ranges.$first.show().css( {
205 - 'left': sel.from.x,
206 - 'top': sel.from.top,
207 - 'width': ( $container.innerWidth() - sel.from.x )
208 - + $container.offset().left,
209 - 'height': sel.from.height
210 - } );
211 - if ( sel.from.line < sel.to.line - 1 ) {
212 - ranges.$fill.show().css( {
213 - 'left': $container.offset().left,
214 - 'top': sel.from.bottom,
215 - 'width': $container.innerWidth(),
216 - 'height': sel.to.top - sel.from.bottom
217 - } );
218 - } else {
219 - ranges.$fill.hide();
220 - }
221 - ranges.$last.show().css( {
222 - 'left': $container.offset().left,
223 - 'top': sel.to.top,
224 - 'width': sel.to.x - $container.offset().left,
225 - 'height': sel.to.height
226 - } );
227 - // XXX: Demo code!
228 - $( '#selection p' ).text( getSelectionText() );
229 - return;
230 - }
231 - }
232 - // No selection
233 - ranges.$all.hide();
234 - }
235 -
236 - function renderDocument( doc ) {
237 - $document.empty();
238 - for ( var i = 0; i < doc.blocks.length; i++ ) {
239 - switch ( doc.blocks[i].type ) {
240 - case 'paragraph':
241 - renderParagraph( doc.blocks[i], $document )
242 - break;
243 - }
244 - }
245 - }
246 -
247 - function renderParagraph( paragraph, $container ) {
248 - var $paragraph = $( '<div class="editSurface-paragraph"></div>' ).appendTo( $container );
249 - var lines = [];
250 - for ( var i = 0; i < paragraph.lines.length; i++ ) {
251 - lines.push( paragraph.lines[i].text );
252 - }
253 - $paragraph.flow( lines.join( '\n' ) );
254 - }
255 -
256 - function update() {
257 - // Render document
258 - if ( options.document !== null ) {
259 - renderDocument( options.document, $this );
260 - }
261 - }
262 -
263 - var cursor = {
264 - '$': $( '.editSurface-cursor' ),
265 - 'visible': true,
266 - 'timeout': null,
267 - 'speed': 500
268 - };
269 - cursor.blink = function() {
270 - // Flip
271 - cursor.visible = !cursor.visible;
272 - // Hide/show
273 - cursor.visible ? cursor.$.hide() : cursor.$.show();
274 - // Repeat
275 - cursor.timeout = setTimeout( cursor.blink, cursor.speed )
276 - }
277 - cursor.show = function() {
278 - // Start visible (will flip when run)
279 - cursor.visible = true;
280 - cursor.$.show();
281 - // Start/restart blinking
282 - clearTimeout( cursor.timeout );
283 - cursor.blink();
284 - };
285 - cursor.hide = function() {
286 - // Hide
287 - cursor.$.hide();
288 - // Stop blinking
289 - clearTimeout( cursor.timeout );
290 - };
291 -
292 - $(window).resize( update );
293 - update();
294 -};
Index: trunk/parsers/wikidom/demos/surface/jquery.flow.js
@@ -0,0 +1,187 @@
 2+/*
 3+ * Flow jQuery plugin
 4+ *
 5+ * Each line has data in the following structure, embedded as $line.data( 'flow' )
 6+ * {
 7+ * index: 0,
 8+ * text: 'abc 123',
 9+ * metrics: [9,4,9]
 10+ * width: 22,
 11+ * words: [
 12+ * {
 13+ * text: 'abc',
 14+ * html: 'abc',
 15+ * metrics: [3,3,3],
 16+ * width: 9,
 17+ * index: 0,
 18+ * offset: 0
 19+ * },
 20+ * {
 21+ * text: ' ',
 22+ * html: '&nbsp;',
 23+ * metrics: [4],
 24+ * width: 4,
 25+ * index: 1,
 26+ * offset: 3
 27+ * },
 28+ * {
 29+ * text: '123',
 30+ * html: '123',
 31+ * metrics: [3,3,3]
 32+ * width: 9,
 33+ * index: 2,
 34+ * offset: 4
 35+ * }
 36+ * ]
 37+ * }
 38+ */
 39+function copy( from, to ) {
 40+ if ( typeof to === 'undefined' ) {
 41+ to = {};
 42+ }
 43+ if ( from == null || typeof from != 'object' ) {
 44+ return from;
 45+ }
 46+ if ( from.constructor != Object && from.constructor != Array ) {
 47+ return from;
 48+ }
 49+ if ( from.constructor == Date
 50+ || from.constructor == RegExp
 51+ || from.constructor == Function
 52+ || from.constructor == String
 53+ || from.constructor == Number
 54+ || from.constructor == Boolean ) {
 55+ return new from.constructor( from );
 56+ }
 57+ to = to || new from.constructor();
 58+ for ( var name in from ) {
 59+ to[name] = typeof to[name] == 'undefined' ? copy( from[name], null ) : to[name];
 60+ }
 61+ return to;
 62+}
 63+
 64+$.flow = {
 65+ 'charCache': {},
 66+ 'wordCache': {},
 67+ 'measureWord': function( text, ruler ) {
 68+ if ( typeof $.flow.wordCache[text] === 'undefined' ) {
 69+ // Cache miss
 70+ var word = { 'text': text, 'html': '', 'metrics': [] };
 71+ for ( var i = 0; i < text.length; i++ ) {
 72+ var char = text[i],
 73+ charHtml = char
 74+ .replace( '&', '&amp;' )
 75+ .replace( ' ', '&nbsp;' )
 76+ .replace( '<', '&lt;' )
 77+ .replace( '>', '&gt;' )
 78+ .replace( '\'', '&apos;' )
 79+ .replace( '"', '&quot;' )
 80+ .replace( '\n', '<span class="editSurface-whitespace">\\n</span>' )
 81+ .replace( '\t', '<span class="editSurface-whitespace">\\t</span>' );
 82+ word.html += charHtml;
 83+ if ( typeof $.flow.charCache[char] === 'undefined' ) {
 84+ // Cache miss
 85+ ruler.innerHTML = charHtml;
 86+ word.metrics.push( $.flow.charCache[char] = ruler.clientWidth );
 87+ continue;
 88+ }
 89+ // Cache hit
 90+ word.metrics.push( $.flow.charCache[char] );
 91+ }
 92+ ruler.innerHTML = word.html;
 93+ word.width = ruler.clientWidth;
 94+ $.flow.wordCache[text] = copy( word );
 95+ return word;
 96+ }
 97+ // Cache hit
 98+ return copy( $.flow.wordCache[text] );
 99+ },
 100+ 'getWords': function( text, ruler ) {
 101+ var words = [],
 102+ bounadry = /[ \-\t\r\n\f]/,
 103+ left = 0,
 104+ right = 0,
 105+ search = 0;
 106+ while ( ( search = text.substr( right ).search( bounadry ) ) >= 0 ) {
 107+ right += search;
 108+ words.push( $.flow.measureWord( text.substring( left, right ), ruler ) );
 109+ if ( right < text.length ) {
 110+ words.push( $.flow.measureWord( text.substring( right, ++right ), ruler ) );
 111+ }
 112+ left = right;
 113+ }
 114+ words.push( $.flow.measureWord( text.substring( right, text.length ), ruler ) );
 115+ return words;
 116+ },
 117+ 'getLines': function( words, width ) {
 118+ // Lineify
 119+ var lineCount = 0,
 120+ charCount = 0,
 121+ wordCount = 0,
 122+ lines = [],
 123+ line = {
 124+ 'text': '',
 125+ 'html': '',
 126+ 'width': 0,
 127+ 'metrics': [],
 128+ 'words': [],
 129+ 'index': lineCount
 130+ };
 131+ for ( var i = 0; i < words.length; i++ ) {
 132+ if ( line.width + words[i].width > width ) {
 133+ lines.push( line );
 134+ charCount = 0;
 135+ wordCount = 0;
 136+ lineCount++;
 137+ line = {
 138+ 'text': '',
 139+ 'html': '',
 140+ 'width': 0,
 141+ 'metrics': [],
 142+ 'words': [],
 143+ 'index': lineCount
 144+ };
 145+ }
 146+ words[i].index = wordCount;
 147+ wordCount++;
 148+ words[i].offset = charCount;
 149+ charCount += words[i].text.length;
 150+ line.words.push( words[i] );
 151+ line.text += words[i].text;
 152+ line.html += words[i].html;
 153+ line.width += words[i].width;
 154+ line.metrics.push( words[i].width );
 155+ }
 156+ if ( line.text.length ) {
 157+ lines.push( line );
 158+ }
 159+ return lines;
 160+ }
 161+};
 162+
 163+$.fn.flow = function( text ) {
 164+ //console.time( 'flow' );
 165+
 166+ var $this = $(this),
 167+ $ruler = $( '<div></div>' ).appendTo( $(this) ),
 168+ lines = $.flow.getLines(
 169+ $.flow.getWords( text, $( '<div class="editSurface-line"></div>' ).appendTo( $this )[0] ),
 170+ $ruler.innerWidth()
 171+ );
 172+
 173+ // Flow
 174+ $this.empty();
 175+ for ( var i = 0; i < lines.length; i++ ) {
 176+ var $line = $( '<div class="editSurface-line"></div>' ).data( 'flow', lines[i] );
 177+ if ( lines[i].text.length === 1 && lines[1].text.match( /[ \-\t\r\n\f]/ ) ) {
 178+ $line.html( '&nbsp;' );
 179+ $line.addClass( 'empty' );
 180+ } else {
 181+ $line.html( lines[i].html );
 182+ }
 183+ $this.append( $line );
 184+ }
 185+
 186+ //console.timeEnd( 'flow' );
 187+ return $this;
 188+};
Property changes on: trunk/parsers/wikidom/demos/surface/jquery.flow.js
___________________________________________________________________
Added: svn:eol-style
1189 + native
Added: svn:mime-type
2190 + text/plain
Index: trunk/parsers/wikidom/demos/surface/jquery.editSurface.css
@@ -0,0 +1,65 @@
 2+body {
 3+ font-family: "Arial";
 4+ font-size: 0.8em;
 5+}
 6+
 7+#selection {
 8+ position: absolute;
 9+ right: 3%;
 10+ width: 45%;
 11+ border: solid 1px Highlight;
 12+ line-height: 1.5em;
 13+ cursor: text;
 14+ font-family: "Courier New", monospace;
 15+ white-space: pre-wrap;
 16+}
 17+
 18+#selection p {
 19+ margin: 0;
 20+ padding: 2em;
 21+}
 22+
 23+.editSurface-container {
 24+ position: absolute;
 25+ left: 3%;
 26+ width: 45%;
 27+ border: solid 1px red;
 28+ cursor: text;
 29+}
 30+
 31+.editSurface-paragraph {
 32+ padding: 2em;
 33+}
 34+
 35+.editSurface-line {
 36+ display: inline-block;
 37+ height: 1.5em;
 38+ line-height: 1.5em;
 39+ cursor: text;
 40+ white-space: nowrap;
 41+}
 42+
 43+.editSurface-line.empty {
 44+ display: block;
 45+ width: 0px;
 46+}
 47+
 48+.editSurface-line .editSurface-whitespace {
 49+ color: #888888;
 50+ padding: 0 0.25em;
 51+}
 52+
 53+.editSurface-range {
 54+ display: none;
 55+ position: absolute;
 56+ background-color: Highlight;
 57+ cursor: text;
 58+}
 59+
 60+.editSurface-cursor {
 61+ position: absolute;
 62+ background-color: black;
 63+ width: 1px;
 64+ height: 1.5em;
 65+ display: none;
 66+}
Property changes on: trunk/parsers/wikidom/demos/surface/jquery.editSurface.css
___________________________________________________________________
Added: svn:eol-style
167 + native
Added: svn:mime-type
268 + text/plain
Index: trunk/parsers/wikidom/demos/surface/jquery.editSurface.js
@@ -0,0 +1,293 @@
 2+$.fn.editSurface = function( options ) {
 3+ var $this = $(this);
 4+ sel = {
 5+ 'active': false
 6+ };
 7+
 8+ options = $.extend( {
 9+ // Defaults
 10+ 'document': null
 11+ }, options );
 12+
 13+ // Initialization
 14+ $this
 15+ .addClass( 'editSurface-container' )
 16+ .append( '<div class="editSurface-document"></div>' )
 17+ .after( '<div class="editSurface-cursor"></div>' )
 18+ .before( '<div class="editSurface-range"></div>'
 19+ + '<div class="editSurface-range"></div>'
 20+ + '<div class="editSurface-range"></div>');
 21+
 22+ // Shortcuts
 23+ var $document = $this.find( '.editSurface-document' );
 24+ var ranges = {
 25+ '$all': $( '.editSurface-range' ),
 26+ '$first': $( '.editSurface-range:eq(0)' ),
 27+ '$fill': $( '.editSurface-range:eq(1)' ),
 28+ '$last': $( '.editSurface-range:eq(2)' )
 29+ };
 30+
 31+ // Events
 32+ $(document).bind( {
 33+ 'mousedown': function( e ) {
 34+ var $target = $( e.target );
 35+ if ( $target.is( '.editSurface-paragraph' ) ) {
 36+ $target = getNearestLine( $target.children(), e.pageY );
 37+ }
 38+ if ( !$target.is( '.editSurface-line' ) ) {
 39+ var $line = $target.closest( '.editSurface-line' );
 40+ if ( $line.length ) {
 41+ $target = $line;
 42+ } else {
 43+ return;
 44+ }
 45+ }
 46+ sel = {
 47+ 'active': true,
 48+ 'from': null,
 49+ 'to': null,
 50+ 'start': getCursorPosition( e.pageX, e.pageY, $target ),
 51+ 'end': null
 52+ };
 53+ cursor.show();
 54+ drawSelection( sel.start.$target.parent() );
 55+ // Move cursor
 56+ if ( sel.start ) {
 57+ cursor.$.css( {
 58+ 'top': sel.start.top,
 59+ 'left': sel.start.x
 60+ } );
 61+ }
 62+ e.preventDefault();
 63+ return false;
 64+ },
 65+ 'mouseup': function( e ) {
 66+ if ( sel.active ) {
 67+ if ( !sel.from || !sel.to
 68+ || ( sel.from.line === sel.to.line && sel.from.char === sel.to.char ) ) {
 69+ sel.from = null;
 70+ sel.to = null;
 71+ sel.start = null;
 72+ sel.end = null;
 73+ cursor.show();
 74+ clearSelection();
 75+ } else {
 76+ drawSelection( sel.start.$target.parent() );
 77+ }
 78+ sel.active = false;
 79+ }
 80+ },
 81+ 'mousemove': function( e ) {
 82+ if ( sel.active ) {
 83+ var $target = $( e.target );
 84+ if ( !$target.is( '.editSurface-line' ) ) {
 85+ $target = getNearestLine( sel.start.$target.parent().children(), e.pageY );
 86+ }
 87+ sel.end = getCursorPosition( e.pageX, e.pageY, $target );
 88+ if ( sel.start.line < sel.end.line
 89+ || ( sel.start.line === sel.end.line
 90+ && sel.start.char < sel.end.char ) ) {
 91+ sel.from = sel.start;
 92+ sel.to = sel.end;
 93+ } else {
 94+ sel.from = sel.end;
 95+ sel.to = sel.start;
 96+ }
 97+ cursor.hide();
 98+ drawSelection( sel.start.$target.parent() );
 99+ }
 100+ }
 101+ } );
 102+
 103+ // Functions
 104+ function getNearestLine( $lines, y ) {
 105+ var $line,
 106+ minDistance;
 107+ $lines.each( function() {
 108+ var top = $(this).offset().top;
 109+ var bottom = top + $(this).height();
 110+ // Inside test
 111+ if ( y > top && y < bottom ) {
 112+ $line = $(this);
 113+ return false;
 114+ }
 115+ // Distance test
 116+ var distance = Math.abs( y - top );
 117+ if ( typeof minDistance === 'undefined' || distance < minDistance ) {
 118+ minDistance = distance;
 119+ $line = $(this);
 120+ }
 121+ } );
 122+ return $line;
 123+ }
 124+ function getSelectionText() {
 125+ var text;
 126+ if ( sel.from && sel.to ) {
 127+ if ( sel.from.line === sel.to.line ) {
 128+ text = sel.from.$target.data( 'flow' ).text.substr(
 129+ sel.from.char, sel.to.char - sel.from.char
 130+ );
 131+ } else {
 132+ text = sel.from.$target.data( 'flow' ).text.substr( sel.from.char );
 133+ var $sibling = sel.from.$target.next();
 134+ for ( var i = sel.from.line + 1; i < sel.to.line; i++ ) {
 135+ text += $sibling.data( 'flow' ).text
 136+ $sibling = $sibling.next();
 137+ }
 138+ text += sel.to.$target.data( 'flow' ).text.substr( 0, sel.to.char );
 139+ }
 140+ }
 141+ return text;
 142+ }
 143+ function getCursorPosition( x, y, $target ) {
 144+ var line = $target.data( 'flow' ),
 145+ offset = $target.offset(),
 146+ height = $target.height(),
 147+ l,
 148+ r = 0,
 149+ cur = x - offset.left;
 150+ for ( var w = 0, eol = line.metrics.length - 1; w <= eol; w++ ) {
 151+ l = r;
 152+ r += line.metrics[w];
 153+ if ( ( w === 0 && cur <= l ) || ( cur >= l && cur <= r ) || ( w === eol ) ) {
 154+ var word = line.words[w],
 155+ a,
 156+ b = { 'l': l, 'c': l, 'r': l };
 157+ for ( var c = 0, eow = word.metrics.length; c <= eow; c++ ) {
 158+ a = b;
 159+ b = {
 160+ 'l': a.r,
 161+ 'c': a.r + ( word.metrics[c] / 2 ),
 162+ 'r': a.r + word.metrics[c]
 163+ };
 164+ if ( ( c === 0 && cur <= a.l ) || ( cur >= a.c && cur <= b.c ) || c === eow ) {
 165+ return {
 166+ '$target': $target,
 167+ 'char': word.offset + Math.min( c, word.text.length - 1 ),
 168+ 'word': word.index,
 169+ 'line': line.index,
 170+ 'x': offset.left + b.l,
 171+ 'top': offset.top,
 172+ 'bottom': offset.top + height,
 173+ 'height': height
 174+ };
 175+ }
 176+ }
 177+ }
 178+ }
 179+ }
 180+
 181+ function clearSelection() {
 182+ ranges.$all.hide();
 183+ }
 184+
 185+ function drawSelection( $container ) {
 186+ if ( sel.from && sel.to ) {
 187+ if ( sel.from.line === sel.to.line ) {
 188+ // 1 line
 189+ if ( sel.from.char !== sel.to.char ) {
 190+ ranges.$first.show().css( {
 191+ 'left': sel.from.x,
 192+ 'top': sel.from.top,
 193+ 'width': sel.to.x - sel.from.x,
 194+ 'height': sel.from.height
 195+ } );
 196+ ranges.$fill.hide();
 197+ ranges.$last.hide();
 198+ // XXX: Demo code!
 199+ $( '#selection p' ).text( getSelectionText() );
 200+ return;
 201+ }
 202+ } else if ( sel.from.line < sel.to.line ) {
 203+ // 2+ lines
 204+ ranges.$first.show().css( {
 205+ 'left': sel.from.x,
 206+ 'top': sel.from.top,
 207+ 'width': ( $container.innerWidth() - sel.from.x )
 208+ + $container.offset().left,
 209+ 'height': sel.from.height
 210+ } );
 211+ if ( sel.from.line < sel.to.line - 1 ) {
 212+ ranges.$fill.show().css( {
 213+ 'left': $container.offset().left,
 214+ 'top': sel.from.bottom,
 215+ 'width': $container.innerWidth(),
 216+ 'height': sel.to.top - sel.from.bottom
 217+ } );
 218+ } else {
 219+ ranges.$fill.hide();
 220+ }
 221+ ranges.$last.show().css( {
 222+ 'left': $container.offset().left,
 223+ 'top': sel.to.top,
 224+ 'width': sel.to.x - $container.offset().left,
 225+ 'height': sel.to.height
 226+ } );
 227+ // XXX: Demo code!
 228+ $( '#selection p' ).text( getSelectionText() );
 229+ return;
 230+ }
 231+ }
 232+ // No selection
 233+ ranges.$all.hide();
 234+ }
 235+
 236+ function renderDocument( doc ) {
 237+ $document.empty();
 238+ for ( var i = 0; i < doc.blocks.length; i++ ) {
 239+ switch ( doc.blocks[i].type ) {
 240+ case 'paragraph':
 241+ renderParagraph( doc.blocks[i], $document )
 242+ break;
 243+ }
 244+ }
 245+ }
 246+
 247+ function renderParagraph( paragraph, $container ) {
 248+ var $paragraph = $( '<div class="editSurface-paragraph"></div>' ).appendTo( $container );
 249+ var lines = [];
 250+ for ( var i = 0; i < paragraph.lines.length; i++ ) {
 251+ lines.push( paragraph.lines[i].text );
 252+ }
 253+ $paragraph.flow( lines.join( '\n' ) );
 254+ }
 255+
 256+ function update() {
 257+ // Render document
 258+ if ( options.document !== null ) {
 259+ renderDocument( options.document, $this );
 260+ }
 261+ }
 262+
 263+ var cursor = {
 264+ '$': $( '.editSurface-cursor' ),
 265+ 'visible': true,
 266+ 'timeout': null,
 267+ 'speed': 500
 268+ };
 269+ cursor.blink = function() {
 270+ // Flip
 271+ cursor.visible = !cursor.visible;
 272+ // Hide/show
 273+ cursor.visible ? cursor.$.hide() : cursor.$.show();
 274+ // Repeat
 275+ cursor.timeout = setTimeout( cursor.blink, cursor.speed )
 276+ }
 277+ cursor.show = function() {
 278+ // Start visible (will flip when run)
 279+ cursor.visible = true;
 280+ cursor.$.show();
 281+ // Start/restart blinking
 282+ clearTimeout( cursor.timeout );
 283+ cursor.blink();
 284+ };
 285+ cursor.hide = function() {
 286+ // Hide
 287+ cursor.$.hide();
 288+ // Stop blinking
 289+ clearTimeout( cursor.timeout );
 290+ };
 291+
 292+ $(window).resize( update );
 293+ update();
 294+};
Property changes on: trunk/parsers/wikidom/demos/surface/jquery.editSurface.js
___________________________________________________________________
Added: svn:eol-style
1295 + native
Added: svn:mime-type
2296 + text/plain
Index: trunk/parsers/wikidom/demos/surface/index.html
@@ -3,7 +3,7 @@
44 <html>
55 <head>
66 <title>EditSurface Demo</title>
7 - <link rel="stylesheet" href="../../lib/jquery.editSurface.css">
 7+ <link rel="stylesheet" href="jquery.editSurface.css">
88 </head>
99 <body>
1010 <h1>EditSurface Demo</h1>
@@ -12,8 +12,8 @@
1313
1414 <!-- EditSurface -->
1515 <script type="text/javascript" src="../../lib/jquery.js"></script>
16 - <script type="text/javascript" src="../../lib/jquery.flow.js"></script>
17 - <script type="text/javascript" src="../../lib/jquery.editSurface.js"></script>
 16+ <script type="text/javascript" src="jquery.flow.js"></script>
 17+ <script type="text/javascript" src="jquery.editSurface.js"></script>
1818
1919 <!-- Demo -->
2020 <script>

Status & tagging log