Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php |
— | — | @@ -72,12 +72,12 @@ |
73 | 73 | array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 6 ), |
74 | 74 | array( 'src' => 'js/plugins/jquery.textSelection.js', 'version' => 21 ), |
75 | 75 | array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 36 ), |
76 | | - array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 2 ), |
| 76 | + array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 3 ), |
77 | 77 | array( 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', 'version' => 40 ), |
78 | 78 | array( 'src' => 'js/plugins/jquery.wikiEditor.dialogs.js', 'version' => 10 ), |
79 | 79 | array( 'src' => 'js/plugins/jquery.wikiEditor.toc.js', 'version' => 52 ), |
80 | 80 | array( 'src' => 'js/plugins/jquery.wikiEditor.preview.js', 'version' => 8 ), |
81 | | - array( 'src' => 'js/plugins/jquery.wikiEditor.templateEditor.js', 'version' => 2 ), |
| 81 | + array( 'src' => 'js/plugins/jquery.wikiEditor.templateEditor.js', 'version' => 3 ), |
82 | 82 | array( 'src' => 'js/plugins/jquery.wikiEditor.publish.js', 'version' => 1 ), |
83 | 83 | ), |
84 | 84 | 'combined' => array( |
Index: trunk/extensions/UsabilityInitiative/css/wikiEditor.highlight.css |
— | — | @@ -0,0 +1,13 @@ |
| 2 | +/* CSS for highlight module. Note that this CSS is loaded in the iframe, |
| 3 | + * not in the main document. For that reason, it's also not in the combined and |
| 4 | + * minified files. |
| 5 | + */ |
| 6 | +.wikiEditor-highlight-template { |
| 7 | + display: inline; |
| 8 | + color: red; |
| 9 | +} |
| 10 | + |
| 11 | +.wikiEditor-toc-header { /* TODO: move parsing to highlight module and rename this */ |
| 12 | + display: inline; |
| 13 | + font-weight: bold; |
| 14 | +} |
Property changes on: trunk/extensions/UsabilityInitiative/css/wikiEditor.highlight.css |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 15 | + native |
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.templateEditor.js |
— | — | @@ -46,22 +46,19 @@ |
47 | 47 | } |
48 | 48 | }; |
49 | 49 | // Get the markers and tokens from the current context |
50 | | - var markers = context.modules.highlight.data.markers; |
51 | | - var tokenStack = context.modules.highlight.data.tokenArray; |
| 50 | + var markers = context.modules.highlight.markers; |
| 51 | + var tokenStack = context.modules.highlight.tokenArray; |
52 | 52 | // Scan through and detect the boundries of template calls |
53 | 53 | var templateBeginFound = false; |
54 | 54 | var templateBoundaries; |
55 | 55 | while ( templateBoundaries = findOutermostTemplates( tokenStack ) ) { |
56 | | - // Ensure indexes exist for left and right boundry markers |
57 | | - if ( typeof markers[tokenStack[templateBoundaries[0]].offset] == 'undefined' ) { |
58 | | - markers[tokenStack[templateBoundaries[0]].offset] = []; |
59 | | - } |
60 | | - if ( typeof markers[tokenStack[templateBoundaries[1]].offset] == 'undefined' ) { |
61 | | - markers[tokenStack[templateBoundaries[1]].offset] = []; |
62 | | - } |
63 | | - // Append boundry markers |
64 | | - markers[tokenStack[templateBoundaries[0]].offset].push( "<div class='wiki-template'>" ); |
65 | | - markers[tokenStack[templateBoundaries[1]].offset].push( "</div>" ); |
| 56 | + context.modules.highlight.markers.push( { |
| 57 | + start: tokenStack[templateBoundaries[0]].offset, |
| 58 | + end: tokenStack[templateBoundaries[1]].offset, |
| 59 | + wrapElement: function() { |
| 60 | + return $( '<div />' ).addClass( 'wikiEditor-highlight-template' ); |
| 61 | + } |
| 62 | + } ); |
66 | 63 | } |
67 | 64 | } |
68 | 65 | }, |
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js |
— | — | @@ -28,10 +28,22 @@ |
29 | 29 | * ; Definition |
30 | 30 | * : Definition |
31 | 31 | */ |
32 | | - if ( event.data.scope == 'do_not_trigger' ) { |
| 32 | + if ( event.data.scope == 'keydown' ) { |
33 | 33 | $.wikiEditor.modules.highlight.fn.scan( context, "" ); |
34 | 34 | $.wikiEditor.modules.highlight.fn.mark( context, "", "" ); |
35 | 35 | } |
| 36 | + }, |
| 37 | + ready: function( context, event ) { |
| 38 | + // Add our CSS to the iframe |
| 39 | + context.$content.parent().find( 'head' ).append( $j( '<link />' ).attr( { |
| 40 | + 'rel': 'stylesheet', |
| 41 | + 'type': 'text/css', |
| 42 | + 'href': wgScriptPath + '/extensions/UsabilityInitiative/css/wikiEditor.highlight.css', |
| 43 | + } ) ); |
| 44 | + |
| 45 | + // Highlight stuff for the first time |
| 46 | + $.wikiEditor.modules.highlight.fn.scan( context, "" ); |
| 47 | + $.wikiEditor.modules.highlight.fn.mark( context, "", "" ); |
36 | 48 | } |
37 | 49 | }, |
38 | 50 | /** |
— | — | @@ -117,6 +129,7 @@ |
118 | 130 | } |
119 | 131 | } |
120 | 132 | |
| 133 | + context.modules.highlight.tokenArray.sort( function( a, b ) { return a.offset - b.offset; } ); |
121 | 134 | return context.modules.highlight.tokenArray; // array of tokens |
122 | 135 | }, |
123 | 136 | /** |
— | — | @@ -125,30 +138,155 @@ |
126 | 139 | * @param division |
127 | 140 | * @param tokens |
128 | 141 | */ |
| 142 | + // FIXME: What do division and tokens do? |
129 | 143 | mark: function( context, division, tokens ) { |
130 | | - // We need to markup some text based on some tokens |
131 | | - var rawText = context.fn.getContents(); |
132 | | - |
133 | | - //get all markers |
| 144 | + // Get all markers |
| 145 | + context.modules.highlight.markers = []; |
134 | 146 | for ( module in $.wikiEditor.modules ) { |
135 | 147 | if ( 'evt' in $.wikiEditor.modules[module] && 'mark' in $.wikiEditor.modules[module].evt ) { |
136 | | - $.wikiEditor.modules[module].evt.mark(); |
| 148 | + $.wikiEditor.modules[module].evt.mark( context ); // FIXME: event? |
137 | 149 | } |
138 | 150 | } |
139 | | - markedText = ''; |
140 | | - var previousIndex = 0; |
141 | | - for ( var currentIndex in context.modules.highlight.markers ){ |
142 | | - markedText += rawText.substring( previousIndex, currentIndex ); |
143 | | - for( var i = 0 ; i < context.modules.highlight.markers[currentIndex].length; i++ ){ |
144 | | - markedText += context.modules.highlight.markers[currentIndex][i]; |
145 | | - } |
146 | | - previousIndex = currentIndex; |
147 | | - } |
148 | | - if ( markedText != '' ){ |
149 | | - markedText.replace( /\n/g, '<br\>' ); |
150 | | - context.fn.setContents( { contents:markedText } ); |
151 | | - } |
| 151 | + var markers = context.modules.highlight.markers; |
| 152 | + markers.sort( function( a, b ) { return a.start - b.start || a.end - b.end; } ); |
| 153 | + |
| 154 | + // Traverse the iframe DOM, inserting markers where they're needed |
| 155 | + // The loop traverses all leaf nodes in the DOM, and uses DOM methods |
| 156 | + // rather than jQuery because it has to work with text nodes and for performance |
| 157 | + var pos = 0; |
| 158 | + var node = context.$content.get( 0 ); |
| 159 | + var next = null; |
| 160 | + var i = 0; // index for markers[] |
| 161 | + var startNode = null; |
| 162 | + var depth = 0, nextDepth = 0, startDepth = null; |
| 163 | + |
| 164 | + // Find the leftmost leaf node in the tree |
| 165 | + while ( node.firstChild ) { |
| 166 | + node = node.firstChild; |
| 167 | + depth++; |
| 168 | + } |
| 169 | + while ( i < markers.length && node ) { |
| 170 | + // Find the next leaf node |
| 171 | + var p = node; |
| 172 | + nextDepth = depth; |
| 173 | + while ( p && !p.nextSibling ) { |
| 174 | + p = p.parentNode; |
| 175 | + nextDepth--; |
| 176 | + } |
| 177 | + p = p ? p.nextSibling : null; |
| 178 | + while ( p && p.firstChild ) { |
| 179 | + p = p.firstChild; |
| 180 | + nextDepth++; |
| 181 | + } |
| 182 | + next = p; |
| 183 | + |
| 184 | + if ( node.nodeName != '#text' ) { |
| 185 | + if ( node.nodeName == 'BR' ) |
| 186 | + pos++; |
| 187 | + // Skip this node |
| 188 | + node = next; |
| 189 | + depth = nextDepth; |
| 190 | + continue; |
| 191 | + } |
| 192 | + var newPos = pos + node.nodeValue.length; |
| 193 | + |
| 194 | + // We want to isolate each marker, so we may need to split textNodes |
| 195 | + // if a marker starts or end halfway one. |
| 196 | + if ( !startNode && markers[i].start >= pos && markers[i].start < newPos ) { |
| 197 | + // The next marker starts somewhere in this textNode |
| 198 | + if ( markers[i].start > pos ) { |
| 199 | + // Split off the prefix |
| 200 | + // This leaves the prefix in the current node and puts |
| 201 | + // the rest in a new node, which we immediately advance to |
| 202 | + node = node.splitText( markers[i].start - pos ); |
| 203 | + pos = markers[i].start; |
| 204 | + } |
| 205 | + startNode = node; |
| 206 | + startDepth = depth; |
| 207 | + } |
| 208 | + |
| 209 | + // TODO: What happens when wrapping a zero-length string? |
| 210 | + // TODO: Detect that something's already been wrapped and leave it alone |
| 211 | + if ( startNode && markers[i].end > pos && markers[i].end <= newPos ) { |
| 212 | + // The marker ends somewhere in this textNode |
| 213 | + if ( markers[i].end < newPos ) { |
| 214 | + // Split off the suffix |
| 215 | + // This puts the suffix in a new node and leaves the rest |
| 216 | + // in the current node. We have to make sure the split-off |
| 217 | + // node will be visited correctly |
| 218 | + |
| 219 | + // node.nodeValue.length - ( newPos - markers[i].end ) |
| 220 | + next = node.splitText( node.nodeValue.length - newPos + markers[i].end ); |
| 221 | + newPos = markers[i].end; |
| 222 | + } |
| 223 | + |
| 224 | + // Now wrap everything between startNode and node (may be equal). |
| 225 | + // First find the common ancestor of startNode and node. |
| 226 | + // ca1 and ca2 will be children of this common ancestor, such that |
| 227 | + // ca1 is an ancestor of startNode and ca2 of node. |
| 228 | + // We also check that startNode and node are the leftmost and rightmost |
| 229 | + // leaves in the subtrees rooted at ca1 and ca2 respectively; if this is |
| 230 | + // not the case, we can't cleanly wrap things without misnesting and we |
| 231 | + // silently fail. |
| 232 | + var ca1 = startNode, ca2 = node; |
| 233 | + // Correct for startNode and node possibly not having the same depth |
| 234 | + if ( startDepth > depth ) { |
| 235 | + for ( var j = 0; j < startDepth - depth && ca1; j++ ) { |
| 236 | + ca1 = ca1.parentNode; |
| 237 | + } |
| 238 | + } |
| 239 | + else if ( startDepth < depth ) { |
| 240 | + for ( var j = 0; j < depth - startDepth && ca2; j++ ) { |
| 241 | + ca2 = ca2.parentNode; |
| 242 | + } |
| 243 | + } |
| 244 | + while ( ca1 && ca2 && ca1.parentNode != ca2.parentNode ) { |
| 245 | + if ( ca1.parentNode.firstChild != ca1 || ca2.parentNode.lastChild != ca2 ) { |
| 246 | + // startNode and node are not the leftmost and rightmost leaves |
| 247 | + ca1 = ca2 = null; |
| 248 | + } else { |
| 249 | + ca1 = ca1.parentNode; |
| 250 | + ca2 = ca2.parentNode; |
| 251 | + } |
| 252 | + } |
| 253 | + |
| 254 | + if ( ca1 && ca2 ) { |
| 255 | + // We have to store things like .parentNode and .nextSibling |
| 256 | + // because appendChild() changes these properties |
| 257 | + var newNode = markers[i].wrapElement; |
| 258 | + if ( typeof newNode == 'function' ) |
| 259 | + newNode = newNode(); |
| 260 | + if ( newNode.jquery ) |
| 261 | + newNode = newNode.get( 0 ); |
| 262 | + var commonAncestor = ca1.parentNode; |
| 263 | + var nextNode = ca2.nextSibling; |
| 264 | + |
| 265 | + // Append all nodes between ca1 and ca2 (inclusive) |
| 266 | + // to newNode |
| 267 | + var n = ca1; |
| 268 | + while ( n != nextNode ) { |
| 269 | + var ns = n.nextSibling; |
| 270 | + newNode.appendChild( n ); |
| 271 | + n = ns; |
| 272 | + } |
| 273 | + |
| 274 | + // Insert newNode in the right place |
| 275 | + if ( nextNode ) |
| 276 | + commonAncestor.insertBefore( newNode, nextNode ); |
| 277 | + else |
| 278 | + commonAncestor.appendChild( newNode ); |
| 279 | + } |
| 280 | + startNode = null; // Clear for next iteration |
| 281 | + startDepth = null; |
| 282 | + i++; |
| 283 | + } |
| 284 | + |
| 285 | + pos = newPos; |
| 286 | + node = next; |
| 287 | + depth = nextDepth; |
| 288 | + } |
152 | 289 | } |
153 | 290 | } |
154 | 291 | |
155 | | -}; })( jQuery ); |
\ No newline at end of file |
| 292 | +}; })( jQuery ); |
| 293 | + |
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.js |
— | — | @@ -2156,10 +2156,22 @@ |
2157 | 2157 | * ; Definition |
2158 | 2158 | * : Definition |
2159 | 2159 | */ |
2160 | | - if ( event.data.scope == 'do_not_trigger' ) { |
| 2160 | + if ( event.data.scope == 'keydown' ) { |
2161 | 2161 | $.wikiEditor.modules.highlight.fn.scan( context, "" ); |
2162 | 2162 | $.wikiEditor.modules.highlight.fn.mark( context, "", "" ); |
2163 | 2163 | } |
| 2164 | + }, |
| 2165 | + ready: function( context, event ) { |
| 2166 | + // Add our CSS to the iframe |
| 2167 | + context.$content.parent().find( 'head' ).append( $j( '<link />' ).attr( { |
| 2168 | + 'rel': 'stylesheet', |
| 2169 | + 'type': 'text/css', |
| 2170 | + 'href': wgScriptPath + '/extensions/UsabilityInitiative/css/wikiEditor.highlight.css', |
| 2171 | + } ) ); |
| 2172 | + |
| 2173 | + // Highlight stuff for the first time |
| 2174 | + $.wikiEditor.modules.highlight.fn.scan( context, "" ); |
| 2175 | + $.wikiEditor.modules.highlight.fn.mark( context, "", "" ); |
2164 | 2176 | } |
2165 | 2177 | }, |
2166 | 2178 | /** |
— | — | @@ -2245,6 +2257,7 @@ |
2246 | 2258 | } |
2247 | 2259 | } |
2248 | 2260 | |
| 2261 | + context.modules.highlight.tokenArray.sort( function( a, b ) { return a.offset - b.offset; } ); |
2249 | 2262 | return context.modules.highlight.tokenArray; // array of tokens |
2250 | 2263 | }, |
2251 | 2264 | /** |
— | — | @@ -2253,33 +2266,159 @@ |
2254 | 2267 | * @param division |
2255 | 2268 | * @param tokens |
2256 | 2269 | */ |
| 2270 | + // FIXME: What do division and tokens do? |
2257 | 2271 | mark: function( context, division, tokens ) { |
2258 | | - // We need to markup some text based on some tokens |
2259 | | - var rawText = context.fn.getContents(); |
2260 | | - |
2261 | | - //get all markers |
| 2272 | + // Get all markers |
| 2273 | + context.modules.highlight.markers = []; |
2262 | 2274 | for ( module in $.wikiEditor.modules ) { |
2263 | 2275 | if ( 'evt' in $.wikiEditor.modules[module] && 'mark' in $.wikiEditor.modules[module].evt ) { |
2264 | | - $.wikiEditor.modules[module].evt.mark(); |
| 2276 | + $.wikiEditor.modules[module].evt.mark( context ); // FIXME: event? |
2265 | 2277 | } |
2266 | 2278 | } |
2267 | | - markedText = ''; |
2268 | | - var previousIndex = 0; |
2269 | | - for ( var currentIndex in context.modules.highlight.markers ){ |
2270 | | - markedText += rawText.substring( previousIndex, currentIndex ); |
2271 | | - for( var i = 0 ; i < context.modules.highlight.markers[currentIndex].length; i++ ){ |
2272 | | - markedText += context.modules.highlight.markers[currentIndex][i]; |
2273 | | - } |
2274 | | - previousIndex = currentIndex; |
2275 | | - } |
2276 | | - if ( markedText != '' ){ |
2277 | | - markedText.replace( /\n/g, '<br\>' ); |
2278 | | - context.fn.setContents( { contents:markedText } ); |
2279 | | - } |
| 2279 | + var markers = context.modules.highlight.markers; |
| 2280 | + markers.sort( function( a, b ) { return a.start - b.start || a.end - b.end; } ); |
| 2281 | + |
| 2282 | + // Traverse the iframe DOM, inserting markers where they're needed |
| 2283 | + // The loop traverses all leaf nodes in the DOM, and uses DOM methods |
| 2284 | + // rather than jQuery because it has to work with text nodes and for performance |
| 2285 | + var pos = 0; |
| 2286 | + var node = context.$content.get( 0 ); |
| 2287 | + var next = null; |
| 2288 | + var i = 0; // index for markers[] |
| 2289 | + var startNode = null; |
| 2290 | + var depth = 0, nextDepth = 0, startDepth = null; |
| 2291 | + |
| 2292 | + // Find the leftmost leaf node in the tree |
| 2293 | + while ( node.firstChild ) { |
| 2294 | + node = node.firstChild; |
| 2295 | + depth++; |
| 2296 | + } |
| 2297 | + while ( i < markers.length && node ) { |
| 2298 | + // Find the next leaf node |
| 2299 | + var p = node; |
| 2300 | + nextDepth = depth; |
| 2301 | + while ( p && !p.nextSibling ) { |
| 2302 | + p = p.parentNode; |
| 2303 | + nextDepth--; |
| 2304 | + } |
| 2305 | + p = p ? p.nextSibling : null; |
| 2306 | + while ( p && p.firstChild ) { |
| 2307 | + p = p.firstChild; |
| 2308 | + nextDepth++; |
| 2309 | + } |
| 2310 | + next = p; |
| 2311 | + |
| 2312 | + if ( node.nodeName != '#text' ) { |
| 2313 | + if ( node.nodeName == 'BR' ) |
| 2314 | + pos++; |
| 2315 | + // Skip this node |
| 2316 | + node = next; |
| 2317 | + depth = nextDepth; |
| 2318 | + continue; |
| 2319 | + } |
| 2320 | + var newPos = pos + node.nodeValue.length; |
| 2321 | + |
| 2322 | + // We want to isolate each marker, so we may need to split textNodes |
| 2323 | + // if a marker starts or end halfway one. |
| 2324 | + if ( !startNode && markers[i].start >= pos && markers[i].start < newPos ) { |
| 2325 | + // The next marker starts somewhere in this textNode |
| 2326 | + if ( markers[i].start > pos ) { |
| 2327 | + // Split off the prefix |
| 2328 | + // This leaves the prefix in the current node and puts |
| 2329 | + // the rest in a new node, which we immediately advance to |
| 2330 | + node = node.splitText( markers[i].start - pos ); |
| 2331 | + pos = markers[i].start; |
| 2332 | + } |
| 2333 | + startNode = node; |
| 2334 | + startDepth = depth; |
| 2335 | + } |
| 2336 | + |
| 2337 | + // TODO: What happens when wrapping a zero-length string? |
| 2338 | + // TODO: Detect that something's already been wrapped and leave it alone |
| 2339 | + if ( startNode && markers[i].end > pos && markers[i].end <= newPos ) { |
| 2340 | + // The marker ends somewhere in this textNode |
| 2341 | + if ( markers[i].end < newPos ) { |
| 2342 | + // Split off the suffix |
| 2343 | + // This puts the suffix in a new node and leaves the rest |
| 2344 | + // in the current node. We have to make sure the split-off |
| 2345 | + // node will be visited correctly |
| 2346 | + |
| 2347 | + // node.nodeValue.length - ( newPos - markers[i].end ) |
| 2348 | + next = node.splitText( node.nodeValue.length - newPos + markers[i].end ); |
| 2349 | + newPos = markers[i].end; |
| 2350 | + } |
| 2351 | + |
| 2352 | + // Now wrap everything between startNode and node (may be equal). |
| 2353 | + // First find the common ancestor of startNode and node. |
| 2354 | + // ca1 and ca2 will be children of this common ancestor, such that |
| 2355 | + // ca1 is an ancestor of startNode and ca2 of node. |
| 2356 | + // We also check that startNode and node are the leftmost and rightmost |
| 2357 | + // leaves in the subtrees rooted at ca1 and ca2 respectively; if this is |
| 2358 | + // not the case, we can't cleanly wrap things without misnesting and we |
| 2359 | + // silently fail. |
| 2360 | + var ca1 = startNode, ca2 = node; |
| 2361 | + // Correct for startNode and node possibly not having the same depth |
| 2362 | + if ( startDepth > depth ) { |
| 2363 | + for ( var j = 0; j < startDepth - depth && ca1; j++ ) { |
| 2364 | + ca1 = ca1.parentNode; |
| 2365 | + } |
| 2366 | + } |
| 2367 | + else if ( startDepth < depth ) { |
| 2368 | + for ( var j = 0; j < depth - startDepth && ca2; j++ ) { |
| 2369 | + ca2 = ca2.parentNode; |
| 2370 | + } |
| 2371 | + } |
| 2372 | + while ( ca1 && ca2 && ca1.parentNode != ca2.parentNode ) { |
| 2373 | + if ( ca1.parentNode.firstChild != ca1 || ca2.parentNode.lastChild != ca2 ) { |
| 2374 | + // startNode and node are not the leftmost and rightmost leaves |
| 2375 | + ca1 = ca2 = null; |
| 2376 | + } else { |
| 2377 | + ca1 = ca1.parentNode; |
| 2378 | + ca2 = ca2.parentNode; |
| 2379 | + } |
| 2380 | + } |
| 2381 | + |
| 2382 | + if ( ca1 && ca2 ) { |
| 2383 | + // We have to store things like .parentNode and .nextSibling |
| 2384 | + // because appendChild() changes these properties |
| 2385 | + var newNode = markers[i].wrapElement; |
| 2386 | + if ( typeof newNode == 'function' ) |
| 2387 | + newNode = newNode(); |
| 2388 | + if ( newNode.jquery ) |
| 2389 | + newNode = newNode.get( 0 ); |
| 2390 | + var commonAncestor = ca1.parentNode; |
| 2391 | + var nextNode = ca2.nextSibling; |
| 2392 | + |
| 2393 | + // Append all nodes between ca1 and ca2 (inclusive) |
| 2394 | + // to newNode |
| 2395 | + var n = ca1; |
| 2396 | + while ( n != nextNode ) { |
| 2397 | + var ns = n.nextSibling; |
| 2398 | + newNode.appendChild( n ); |
| 2399 | + n = ns; |
| 2400 | + } |
| 2401 | + |
| 2402 | + // Insert newNode in the right place |
| 2403 | + if ( nextNode ) |
| 2404 | + commonAncestor.insertBefore( newNode, nextNode ); |
| 2405 | + else |
| 2406 | + commonAncestor.appendChild( newNode ); |
| 2407 | + } |
| 2408 | + startNode = null; // Clear for next iteration |
| 2409 | + startDepth = null; |
| 2410 | + i++; |
| 2411 | + } |
| 2412 | + |
| 2413 | + pos = newPos; |
| 2414 | + node = next; |
| 2415 | + depth = nextDepth; |
| 2416 | + } |
2280 | 2417 | } |
2281 | 2418 | } |
2282 | 2419 | |
2283 | | -}; })( jQuery );/* Preview module for wikiEditor */ |
| 2420 | +}; })( jQuery ); |
| 2421 | + |
| 2422 | +/* Preview module for wikiEditor */ |
2284 | 2423 | ( function( $ ) { $.wikiEditor.modules.preview = { |
2285 | 2424 | |
2286 | 2425 | /** |
— | — | @@ -2572,22 +2711,19 @@ |
2573 | 2712 | } |
2574 | 2713 | }; |
2575 | 2714 | // Get the markers and tokens from the current context |
2576 | | - var markers = context.modules.highlight.data.markers; |
2577 | | - var tokenStack = context.modules.highlight.data.tokenArray; |
| 2715 | + var markers = context.modules.highlight.markers; |
| 2716 | + var tokenStack = context.modules.highlight.tokenArray; |
2578 | 2717 | // Scan through and detect the boundries of template calls |
2579 | 2718 | var templateBeginFound = false; |
2580 | 2719 | var templateBoundaries; |
2581 | 2720 | while ( templateBoundaries = findOutermostTemplates( tokenStack ) ) { |
2582 | | - // Ensure indexes exist for left and right boundry markers |
2583 | | - if ( typeof markers[tokenStack[templateBoundaries[0]].offset] == 'undefined' ) { |
2584 | | - markers[tokenStack[templateBoundaries[0]].offset] = []; |
2585 | | - } |
2586 | | - if ( typeof markers[tokenStack[templateBoundaries[1]].offset] == 'undefined' ) { |
2587 | | - markers[tokenStack[templateBoundaries[1]].offset] = []; |
2588 | | - } |
2589 | | - // Append boundry markers |
2590 | | - markers[tokenStack[templateBoundaries[0]].offset].push( "<div class='wiki-template'>" ); |
2591 | | - markers[tokenStack[templateBoundaries[1]].offset].push( "</div>" ); |
| 2721 | + context.modules.highlight.markers.push( { |
| 2722 | + start: tokenStack[templateBoundaries[0]].offset, |
| 2723 | + end: tokenStack[templateBoundaries[1]].offset, |
| 2724 | + wrapElement: function() { |
| 2725 | + return $( '<div />' ).addClass( 'wikiEditor-highlight-template' ); |
| 2726 | + } |
| 2727 | + } ); |
2592 | 2728 | } |
2593 | 2729 | } |
2594 | 2730 | }, |
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js |
— | — | @@ -119,14 +119,30 @@ |
120 | 120 | configuration.newButtons[gM(msg)]=configuration.buttons[msg];configuration.buttons=configuration.newButtons;var dialogDiv=$('<div /> ').attr('id',module.id).html(module.html).data('context',context).appendTo($('body')).each(module.init).dialog(configuration);if(!('resizeme'in module)||module.resizeme){dialogDiv.bind('dialogopen',$.wikiEditor.modules.dialogs.fn.resize).find('.ui-tabs').bind('tabsshow',function(){$(this).closest('.ui-dialog-content').each($.wikiEditor.modules.dialogs.fn.resize);});} |
121 | 121 | var maxTI=0;$j('[tabindex]').each(function(){var ti=parseInt($j(this).attr('tabindex'));if(ti>maxTI) |
122 | 122 | maxTI=ti;});var tabIndex=maxTI+1;$j('.ui-dialog input, .ui-dialog button').not('[tabindex]').each(function(){$j(this).attr('tabindex',tabIndex++);});}}});},resize:function(){var wrapper=$(this).closest('.ui-dialog');var oldWidth=wrapper.width();var oldHidden=$(this).find('*').not(':visible');oldHidden.each(function(){$(this).data('oldstyle',$(this).attr('style'));});oldHidden.show();var oldWS=$(this).css('white-space');$(this).css('white-space','nowrap');if(wrapper.width()<=$(this).get(0).scrollWidth){var thisWidth=$(this).data('thisWidth')?$(this).data('thisWidth'):0;thisWidth=Math.max($(this).get(0).scrollWidth,thisWidth);$(this).width(thisWidth);$(this).data('thisWidth',thisWidth);var wrapperWidth=$(this).data('wrapperWidth')?$(this).data('wrapperWidth'):0;wrapperWidth=Math.max(wrapper.get(0).scrollWidth,wrapperWidth);wrapper.width(wrapperWidth);$(this).data('wrapperWidth',wrapperWidth);$(this).dialog({'width':wrapper.width()});wrapper.css('left',parseInt(wrapper.css('left'))-(wrapper.width()-oldWidth)/2);} |
123 | | -$(this).css('white-space',oldWS);oldHidden.each(function(){$(this).attr('style',$(this).data('oldstyle'));});}},modules:{},quickDialog:function(body,settings){$('<div />').text(body).appendTo($('body')).dialog($.extend({bgiframe:true,modal:true},settings)).dialog('open');}};})(jQuery);(function($){$.wikiEditor.modules.highlight={evt:{change:function(context,event){if(event.data.scope=='do_not_trigger'){$.wikiEditor.modules.highlight.fn.scan(context,"");$.wikiEditor.modules.highlight.fn.mark(context,"","");}}},fn:{create:function(context,config){},divide:function(context){},isolate:function(context){return[];},strip:function(context,division){return $('<div />').html(division.html().replace(/\<br[^\>]*\>/g,"\n")).text();},scan:function(context,division){function Token(offset,label){this.offset=offset;this.label=label;} |
| 123 | +$(this).css('white-space',oldWS);oldHidden.each(function(){$(this).attr('style',$(this).data('oldstyle'));});}},modules:{},quickDialog:function(body,settings){$('<div />').text(body).appendTo($('body')).dialog($.extend({bgiframe:true,modal:true},settings)).dialog('open');}};})(jQuery);(function($){$.wikiEditor.modules.highlight={evt:{change:function(context,event){if(event.data.scope=='keydown'){$.wikiEditor.modules.highlight.fn.scan(context,"");$.wikiEditor.modules.highlight.fn.mark(context,"","");}},ready:function(context,event){context.$content.parent().find('head').append($j('<link />').attr({'rel':'stylesheet','type':'text/css','href':wgScriptPath+'/extensions/UsabilityInitiative/css/wikiEditor.highlight.css',}));$.wikiEditor.modules.highlight.fn.scan(context,"");$.wikiEditor.modules.highlight.fn.mark(context,"","");}},fn:{create:function(context,config){},divide:function(context){},isolate:function(context){return[];},strip:function(context,division){return $('<div />').html(division.html().replace(/\<br[^\>]*\>/g,"\n")).text();},scan:function(context,division){function Token(offset,label){this.offset=offset;this.label=label;} |
124 | 124 | context.modules.highlight.tokenArray=[];var text=context.fn.getContents();for(module in $.wikiEditor.modules){if('exp'in $.wikiEditor.modules[module]){for(var i=0;i<$.wikiEditor.modules[module].exp.length;i++){var regex=$.wikiEditor.modules[module].exp[i].regex;var label=$.wikiEditor.modules[module].exp[i].label;var markAfter=false;if(typeof $.wikiEditor.modules[module].exp[i].markAfter!='undefined'){markAfter=true;} |
125 | 125 | match=text.match(regex);var oldOffset=0;while(match!=null){var markOffset=0;if(markAfter){markOffset+=match[0].length;} |
126 | 126 | context.modules.highlight.tokenArray.push(new Token(match.index+oldOffset+markOffset,label));oldOffset+=match.index+match[0].length;newSubstring=text.substring(oldOffset);match=newSubstring.match(regex);}}}} |
127 | | -return context.modules.highlight.tokenArray;},mark:function(context,division,tokens){var rawText=context.fn.getContents();for(module in $.wikiEditor.modules){if('evt'in $.wikiEditor.modules[module]&&'mark'in $.wikiEditor.modules[module].evt){$.wikiEditor.modules[module].evt.mark();}} |
128 | | -markedText='';var previousIndex=0;for(var currentIndex in context.modules.highlight.markers){markedText+=rawText.substring(previousIndex,currentIndex);for(var i=0;i<context.modules.highlight.markers[currentIndex].length;i++){markedText+=context.modules.highlight.markers[currentIndex][i];} |
129 | | -previousIndex=currentIndex;} |
130 | | -if(markedText!=''){markedText.replace(/\n/g,'<br\>');context.fn.setContents({contents:markedText});}}}};})(jQuery);(function($){$.wikiEditor.modules.preview={fn:{create:function(context,config){if('initialized'in context.modules.preview){return;} |
| 127 | +context.modules.highlight.tokenArray.sort(function(a,b){return a.offset-b.offset;});return context.modules.highlight.tokenArray;},mark:function(context,division,tokens){context.modules.highlight.markers=[];for(module in $.wikiEditor.modules){if('evt'in $.wikiEditor.modules[module]&&'mark'in $.wikiEditor.modules[module].evt){$.wikiEditor.modules[module].evt.mark(context);}} |
| 128 | +var markers=context.modules.highlight.markers;markers.sort(function(a,b){return a.start-b.start||a.end-b.end;});var pos=0;var node=context.$content.get(0);var next=null;var i=0;var startNode=null;var depth=0,nextDepth=0,startDepth=null;while(node.firstChild){node=node.firstChild;depth++;} |
| 129 | +while(i<markers.length&&node){var p=node;nextDepth=depth;while(p&&!p.nextSibling){p=p.parentNode;nextDepth--;} |
| 130 | +p=p?p.nextSibling:null;while(p&&p.firstChild){p=p.firstChild;nextDepth++;} |
| 131 | +next=p;if(node.nodeName!='#text'){if(node.nodeName=='BR') |
| 132 | +pos++;node=next;depth=nextDepth;continue;} |
| 133 | +var newPos=pos+node.nodeValue.length;if(!startNode&&markers[i].start>=pos&&markers[i].start<newPos){if(markers[i].start>pos){node=node.splitText(markers[i].start-pos);pos=markers[i].start;} |
| 134 | +startNode=node;startDepth=depth;} |
| 135 | +if(startNode&&markers[i].end>pos&&markers[i].end<=newPos){if(markers[i].end<newPos){next=node.splitText(node.nodeValue.length-newPos+markers[i].end);newPos=markers[i].end;} |
| 136 | +var ca1=startNode,ca2=node;if(startDepth>depth){for(var j=0;j<startDepth-depth&&ca1;j++){ca1=ca1.parentNode;}} |
| 137 | +else if(startDepth<depth){for(var j=0;j<depth-startDepth&&ca2;j++){ca2=ca2.parentNode;}} |
| 138 | +while(ca1&&ca2&&ca1.parentNode!=ca2.parentNode){if(ca1.parentNode.firstChild!=ca1||ca2.parentNode.lastChild!=ca2){ca1=ca2=null;}else{ca1=ca1.parentNode;ca2=ca2.parentNode;}} |
| 139 | +if(ca1&&ca2){var newNode=markers[i].wrapElement;if(typeof newNode=='function') |
| 140 | +newNode=newNode();if(newNode.jquery) |
| 141 | +newNode=newNode.get(0);var commonAncestor=ca1.parentNode;var nextNode=ca2.nextSibling;var n=ca1;while(n!=nextNode){var ns=n.nextSibling;newNode.appendChild(n);n=ns;} |
| 142 | +if(nextNode) |
| 143 | +commonAncestor.insertBefore(newNode,nextNode);else |
| 144 | +commonAncestor.appendChild(newNode);} |
| 145 | +startNode=null;startDepth=null;i++;} |
| 146 | +pos=newPos;node=next;depth=nextDepth;}}}};})(jQuery);(function($){$.wikiEditor.modules.preview={fn:{create:function(context,config){if('initialized'in context.modules.preview){return;} |
131 | 147 | context.modules.preview={'initialized':true,'previewText':null,'changesText':null};context.modules.preview.$preview=context.fn.addView({'name':'preview','titleMsg':'wikieditor-preview-tab','init':function(context){var wikitext=context.fn.getContents();if(context.modules.preview.previewText==wikitext){return;} |
132 | 148 | context.modules.preview.$preview.find('.wikiEditor-preview-contents').empty();context.modules.preview.$preview.find('.wikiEditor-preview-loading').show();$.post(wgScriptPath+'/api.php',{'action':'parse','title':wgPageName,'text':wikitext,'prop':'text','pst':'','format':'json'},function(data){if(typeof data.parse=='undefined'||typeof data.parse.text=='undefined'||typeof data.parse.text['*']=='undefined'){return;} |
133 | 149 | context.modules.preview.previewText=wikitext;context.modules.preview.$preview.find('.wikiEditor-preview-loading').hide();context.modules.preview.$preview.find('.wikiEditor-preview-contents').html(data.parse.text['*']).find('a:not([href^=#])').click(function(){return false;});},'json');}});context.$changesTab=context.fn.addView({'name':'changes','titleMsg':'wikieditor-preview-changes-tab','init':function(context){var wikitext=context.fn.getContents();if(context.modules.preview.changesText==wikitext){return;} |
— | — | @@ -158,9 +174,7 @@ |
159 | 175 | $('#wikiEditor-'+context.instance+'-dialog-watch').hide();else if($('#wpWatchthis').is(':checked')) |
160 | 176 | $('#wikiEditor-'+context.instance+'-dialog-watch').attr('checked','checked');$(this).find('form').submit(function(e){$(this).closest('.ui-dialog').find('button:first').click();e.preventDefault();});},dialog:{buttons:{'wikieditor-publish-dialog-publish':function(){var minorChecked=$('#wikiEditor-'+context.instance+'-dialog-minor').is(':checked')?'checked':'';var watchChecked=$('#wikiEditor-'+context.instance+'-dialog-watch').is(':checked')?'checked':'';$('#wpMinoredit').attr('checked',minorChecked);$('#wpWatchthis').attr('checked',watchChecked);$('#wpSummary').val($j('#wikiEditor-'+context.instance+'-dialog-summary').val());$('#editform').submit();},'wikieditor-publish-dialog-goback':function(){$(this).dialog('close');}},open:function(){$('#wikiEditor-'+context.instance+'-dialog-summary').focus();},width:500},resizeme:false}});context.fn.addButton({'captionMsg':'wikieditor-publish-button-publish','action':function(){$('#'+dialogID).dialog('open');return false;}});context.fn.addButton({'captionMsg':'wikieditor-publish-button-cancel','action':function(){}});}}};})(jQuery);(function($){$.wikiEditor.modules.templateEditor={evt:{mark:function(context,event){var i=0;function findOutermostTemplates(tokenStack){var templateBeginFound=false;for(;i<tokenStack.length;i++){if(tokenStack[i].label=='TEMPLATE_BEGIN'){templateBeginFound=true;break;}} |
161 | 177 | var j=i++;if(!templateBeginFound){return false;}else{var nestedBegins=1;while(nestedBegins>0&&j<tokenStack.length){var label=tokenStack[++j].label;nestedBegins+=label=='TEMPLATE_END'?-1:label=='TEMPLATE_BEGIN'?1:0;} |
162 | | -if(nestedBegins==0){var leftMarker=i-1;var rightMarker=j;i=j;return[leftMarker,rightMarker];}else{return false;}}};var markers=context.modules.highlight.data.markers;var tokenStack=context.modules.highlight.data.tokenArray;var templateBeginFound=false;var templateBoundaries;while(templateBoundaries=findOutermostTemplates(tokenStack)){if(typeof markers[tokenStack[templateBoundaries[0]].offset]=='undefined'){markers[tokenStack[templateBoundaries[0]].offset]=[];} |
163 | | -if(typeof markers[tokenStack[templateBoundaries[1]].offset]=='undefined'){markers[tokenStack[templateBoundaries[1]].offset]=[];} |
164 | | -markers[tokenStack[templateBoundaries[0]].offset].push("<div class='wiki-template'>");markers[tokenStack[templateBoundaries[1]].offset].push("</div>");}}},exp:[{'regex':/{{/,'label':"TEMPLATE_BEGIN"},{'regex':/}}/,'label':"TEMPLATE_END",'markAfter':true}],fn:{create:function(context,config){},model:function(wikitext){function Param(name,value,number,nameIndex,equalsIndex,valueIndex){this.name=name;this.value=value;this.number=number;this.nameIndex=nameIndex;this.equalsIndex=equalsIndex;this.valueIndex=valueIndex;} |
| 178 | +if(nestedBegins==0){var leftMarker=i-1;var rightMarker=j;i=j;return[leftMarker,rightMarker];}else{return false;}}};var markers=context.modules.highlight.markers;var tokenStack=context.modules.highlight.tokenArray;var templateBeginFound=false;var templateBoundaries;while(templateBoundaries=findOutermostTemplates(tokenStack)){context.modules.highlight.markers.push({start:tokenStack[templateBoundaries[0]].offset,end:tokenStack[templateBoundaries[1]].offset,wrapElement:function(){return $('<div />').addClass('wikiEditor-highlight-template');}});}}},exp:[{'regex':/{{/,'label':"TEMPLATE_BEGIN"},{'regex':/}}/,'label':"TEMPLATE_END",'markAfter':true}],fn:{create:function(context,config){},model:function(wikitext){function Param(name,value,number,nameIndex,equalsIndex,valueIndex){this.name=name;this.value=value;this.number=number;this.nameIndex=nameIndex;this.equalsIndex=equalsIndex;this.valueIndex=valueIndex;} |
165 | 179 | function Range(begin,end){this.begin=begin;this.end=end;} |
166 | 180 | function getSetValue(name,value,original){var valueRange;var rangeIndex;var retVal;if(isNaN(name)){if(typeof paramsByName[name]=='undefined'){return"";} |
167 | 181 | rangeIndex=paramsByName[name];}else{rangeIndex=parseInt(name);} |