Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php |
— | — | @@ -105,7 +105,7 @@ |
106 | 106 | array( |
107 | 107 | 'src' => 'js/plugins/jquery.autoEllipsis.js', |
108 | 108 | 'class' => 'j.fn.autoEllipsis', |
109 | | - 'version' => 6 |
| 109 | + 'version' => 7 |
110 | 110 | ), |
111 | 111 | array( |
112 | 112 | 'src' => 'js/plugins/jquery.browser.js', |
— | — | @@ -135,12 +135,12 @@ |
136 | 136 | array( |
137 | 137 | 'src' => 'js/plugins/jquery.wikiEditor.js', |
138 | 138 | 'class' => 'j.wikiEditor', |
139 | | - 'version' => 69 |
| 139 | + 'version' => 70 |
140 | 140 | ), |
141 | 141 | array( |
142 | 142 | 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', |
143 | 143 | 'class' => 'j.wikiEditor.modules.highlight', |
144 | | - 'version' => 22 |
| 144 | + 'version' => 23 |
145 | 145 | ), |
146 | 146 | array( |
147 | 147 | 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', |
— | — | @@ -173,10 +173,10 @@ |
174 | 174 | 'version' => 1 ), |
175 | 175 | ), |
176 | 176 | 'combined' => array( |
177 | | - array( 'src' => 'js/plugins.combined.js', 'version' => 180 ), |
| 177 | + array( 'src' => 'js/plugins.combined.js', 'version' => 181 ), |
178 | 178 | ), |
179 | 179 | 'minified' => array( |
180 | | - array( 'src' => 'js/plugins.combined.min.js', 'version' => 180 ), |
| 180 | + array( 'src' => 'js/plugins.combined.min.js', 'version' => 181 ), |
181 | 181 | ), |
182 | 182 | ), |
183 | 183 | ); |
Index: trunk/extensions/UsabilityInitiative/WikiEditor/WikiEditor.combined.js |
— | — | @@ -1773,19 +1773,24 @@ |
1774 | 1774 | <div id="wikieditor-toolbar-replace-emptysearch" rel="wikieditor-toolbar-tool-replace-emptysearch"></div>\ |
1775 | 1775 | <div id="wikieditor-toolbar-replace-invalidregex"></div>\ |
1776 | 1776 | </div>\ |
1777 | | - <fieldset><table width="100%"><tr>\ |
1778 | | - <td width="25%"><label for="wikieditor-toolbar-replace-search" rel="wikieditor-toolbar-tool-replace-search"></label></td>\ |
1779 | | - <td width="75%"><input type="text" id="wikieditor-toolbar-replace-search" style="width: 90%;" /></td>\ |
1780 | | - </tr><tr>\ |
1781 | | - <td><label for="wikieditor-toolbar-replace-replace" rel="wikieditor-toolbar-tool-replace-replace"></label></td>\ |
1782 | | - <td><input type="text" id="wikieditor-toolbar-replace-replace" style="width: 90%;" /></td>\ |
1783 | | - </tr></table><table><tr>\ |
1784 | | - <td><input type="checkbox" id="wikieditor-toolbar-replace-case" /></td>\ |
1785 | | - <td><label for="wikieditor-toolbar-replace-case" rel="wikieditor-toolbar-tool-replace-case"></label></td>\ |
1786 | | - </tr><tr>\ |
1787 | | - <td><input type="checkbox" id="wikieditor-toolbar-replace-regex" /></td>\ |
1788 | | - <td><label for="wikieditor-toolbar-replace-regex" rel="wikieditor-toolbar-tool-replace-regex"></label></td>\ |
1789 | | - </tr></table></fieldset>', |
| 1777 | + <fieldset>\ |
| 1778 | + <div class="wikieditor-toolbar-field-wrapper">\ |
| 1779 | + <label for="wikieditor-toolbar-replace-search" rel="wikieditor-toolbar-tool-replace-search"></label>\ |
| 1780 | + <input type="text" id="wikieditor-toolbar-replace-search" style="width: 100%;" />\ |
| 1781 | + </div>\ |
| 1782 | + <div class="wikieditor-toolbar-field-wrapper">\ |
| 1783 | + <label for="wikieditor-toolbar-replace-replace" rel="wikieditor-toolbar-tool-replace-replace"></label>\ |
| 1784 | + <input type="text" id="wikieditor-toolbar-replace-replace" style="width: 100%;" />\ |
| 1785 | + </div>\ |
| 1786 | + <div class="wikieditor-toolbar-field-wrapper">\ |
| 1787 | + <input type="checkbox" id="wikieditor-toolbar-replace-case" />\ |
| 1788 | + <label for="wikieditor-toolbar-replace-case" rel="wikieditor-toolbar-tool-replace-case"></label>\ |
| 1789 | + </div>\ |
| 1790 | + <div class="wikieditor-toolbar-field-wrapper">\ |
| 1791 | + <input type="checkbox" id="wikieditor-toolbar-replace-regex" />\ |
| 1792 | + <label for="wikieditor-toolbar-replace-regex" rel="wikieditor-toolbar-tool-replace-regex"></label>\ |
| 1793 | + </div>\ |
| 1794 | + </fieldset>', |
1790 | 1795 | init: function() { |
1791 | 1796 | $j(this).find( '[rel]' ).each( function() { |
1792 | 1797 | $j(this).text( gM( $j(this).attr( 'rel' ) ) ); |
Index: trunk/extensions/UsabilityInitiative/WikiEditor/WikiEditor.combined.min.js |
— | — | @@ -147,19 +147,24 @@ |
148 | 148 | <div id="wikieditor-toolbar-replace-emptysearch" rel="wikieditor-toolbar-tool-replace-emptysearch"></div>\ |
149 | 149 | <div id="wikieditor-toolbar-replace-invalidregex"></div>\ |
150 | 150 | </div>\ |
151 | | - <fieldset><table width="100%"><tr>\ |
152 | | - <td width="25%"><label for="wikieditor-toolbar-replace-search" rel="wikieditor-toolbar-tool-replace-search"></label></td>\ |
153 | | - <td width="75%"><input type="text" id="wikieditor-toolbar-replace-search" style="width: 90%;" /></td>\ |
154 | | - </tr><tr>\ |
155 | | - <td><label for="wikieditor-toolbar-replace-replace" rel="wikieditor-toolbar-tool-replace-replace"></label></td>\ |
156 | | - <td><input type="text" id="wikieditor-toolbar-replace-replace" style="width: 90%;" /></td>\ |
157 | | - </tr></table><table><tr>\ |
158 | | - <td><input type="checkbox" id="wikieditor-toolbar-replace-case" /></td>\ |
159 | | - <td><label for="wikieditor-toolbar-replace-case" rel="wikieditor-toolbar-tool-replace-case"></label></td>\ |
160 | | - </tr><tr>\ |
161 | | - <td><input type="checkbox" id="wikieditor-toolbar-replace-regex" /></td>\ |
162 | | - <td><label for="wikieditor-toolbar-replace-regex" rel="wikieditor-toolbar-tool-replace-regex"></label></td>\ |
163 | | - </tr></table></fieldset>',init:function(){$j(this).find('[rel]').each(function(){$j(this).text(gM($j(this).attr('rel')));});$j(this).data('replaceCallback',function(mode){$j('#wikieditor-toolbar-replace-nomatch, #wikieditor-toolbar-replace-success, #wikieditor-toolbar-replace-emptysearch, #wikieditor-toolbar-replace-invalidregex').hide();var searchStr=$j('#wikieditor-toolbar-replace-search').val();if(searchStr==''){$j('#wikieditor-toolbar-replace-emptysearch').show();return;} |
| 151 | + <fieldset>\ |
| 152 | + <div class="wikieditor-toolbar-field-wrapper">\ |
| 153 | + <label for="wikieditor-toolbar-replace-search" rel="wikieditor-toolbar-tool-replace-search"></label>\ |
| 154 | + <input type="text" id="wikieditor-toolbar-replace-search" style="width: 100%;" />\ |
| 155 | + </div>\ |
| 156 | + <div class="wikieditor-toolbar-field-wrapper">\ |
| 157 | + <label for="wikieditor-toolbar-replace-replace" rel="wikieditor-toolbar-tool-replace-replace"></label>\ |
| 158 | + <input type="text" id="wikieditor-toolbar-replace-replace" style="width: 100%;" />\ |
| 159 | + </div>\ |
| 160 | + <div class="wikieditor-toolbar-field-wrapper">\ |
| 161 | + <input type="checkbox" id="wikieditor-toolbar-replace-case" />\ |
| 162 | + <label for="wikieditor-toolbar-replace-case" rel="wikieditor-toolbar-tool-replace-case"></label>\ |
| 163 | + </div>\ |
| 164 | + <div class="wikieditor-toolbar-field-wrapper">\ |
| 165 | + <input type="checkbox" id="wikieditor-toolbar-replace-regex" />\ |
| 166 | + <label for="wikieditor-toolbar-replace-regex" rel="wikieditor-toolbar-tool-replace-regex"></label>\ |
| 167 | + </div>\ |
| 168 | + </fieldset>',init:function(){$j(this).find('[rel]').each(function(){$j(this).text(gM($j(this).attr('rel')));});$j(this).data('replaceCallback',function(mode){$j('#wikieditor-toolbar-replace-nomatch, #wikieditor-toolbar-replace-success, #wikieditor-toolbar-replace-emptysearch, #wikieditor-toolbar-replace-invalidregex').hide();var searchStr=$j('#wikieditor-toolbar-replace-search').val();if(searchStr==''){$j('#wikieditor-toolbar-replace-emptysearch').show();return;} |
164 | 169 | var replaceStr=$j('#wikieditor-toolbar-replace-replace').val();var flags='m';var matchCase=$j('#wikieditor-toolbar-replace-case').is(':checked');var isRegex=$j('#wikieditor-toolbar-replace-regex').is(':checked');if(!matchCase){flags+='i';} |
165 | 170 | if(mode=='replaceAll'){flags+='g';} |
166 | 171 | if(!isRegex){searchStr=RegExp.escape(searchStr);} |
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js |
— | — | @@ -554,13 +554,12 @@ |
555 | 555 | // Firefox and Opera |
556 | 556 | var start = options.start, end = options.end; |
557 | 557 | if ( !sc || !ec ) { |
558 | | - var offsets = context.fn.getOffsets(); |
559 | | - var startContainer = offsets[start].node, startOffset = offsets[start].offset; |
560 | | - var endContainer = offsets[end].node, endOffset = offsets[end].offset; |
561 | | - sc = offsets[start].node; |
562 | | - ec = offsets[end].node; |
563 | | - start = offsets[start].offset; |
564 | | - end = offsets[end].offset; |
| 558 | + var s = context.fn.getOffset( start ); |
| 559 | + var e = context.fn.getOffset( end ); |
| 560 | + sc = s.node; |
| 561 | + ec = e.node; |
| 562 | + start = s.offset; |
| 563 | + end = e.offset; |
565 | 564 | } |
566 | 565 | if ( !sc || !ec ) { |
567 | 566 | // The requested offset isn't in the offsets array |
— | — | @@ -673,11 +672,12 @@ |
674 | 673 | return $( [] ); |
675 | 674 | } |
676 | 675 | var seekPos = context.fn.htmlToText( range2.htmlText ).length; |
677 | | - var offsets = context.fn.getOffsets(); |
678 | | - e = offsets[seekPos] ? offsets[seekPos].node : null; |
679 | | - offset = offsets[seekPos] ? offsets[seekPos].offset : null; |
680 | | - if ( !e ) |
| 676 | + var offset = context.fn.getOffset( seekPos ); |
| 677 | + e = offset ? offset.node : null; |
| 678 | + offset = offset ? offset.offset : null; |
| 679 | + if ( !e ) { |
681 | 680 | return $( [] ); |
| 681 | + } |
682 | 682 | } |
683 | 683 | if ( e.nodeName != '#text' ) { |
684 | 684 | // The selection is not in a textnode, but between two non-text nodes |
— | — | @@ -738,7 +738,9 @@ |
739 | 739 | p = p ? p.nextSibling : null; |
740 | 740 | do { |
741 | 741 | // Filter nodes with the wikiEditor-noinclude class |
742 | | - while ( p && $( p ).hasClass( 'wikiEditor-noinclude' ) ) { |
| 742 | + // Don't use $( p ).hasClass( 'wikiEditor-noinclude' ) because |
| 743 | + // $() is slow in a tight loop |
| 744 | + while ( p && ( ' ' + p.className + ' ' ).indexOf( ' wikiEditor-noinclude ' ) != -1 ) { |
743 | 745 | p = p.nextSibling; |
744 | 746 | } |
745 | 747 | if ( p && p.firstChild ) { |
— | — | @@ -758,7 +760,9 @@ |
759 | 761 | var inP = node.nodeName == "P"; |
760 | 762 | do { |
761 | 763 | // Filter nodes with the wikiEditor-noinclude class |
762 | | - while ( node && $( node ).hasClass( 'wikiEditor-noinclude' ) ) { |
| 764 | + // Don't use $( p ).hasClass( 'wikiEditor-noinclude' ) because |
| 765 | + // $() is slow in a tight loop |
| 766 | + while ( node && ( ' ' + node.className + ' ' ).indexOf( ' wikiEditor-noinclude ' ) != -1 ) { |
763 | 767 | node = node.nextSibling; |
764 | 768 | } |
765 | 769 | if ( node && node.firstChild ) { |
— | — | @@ -771,11 +775,30 @@ |
772 | 776 | } while ( node && node.firstChild ); |
773 | 777 | return new Traverser( node, depth, inP ); |
774 | 778 | }, |
775 | | - 'getOffsets': function() { |
| 779 | + 'getOffset': function( offset ) { |
776 | 780 | if ( !context.offsets ) { |
777 | 781 | context.fn.refreshOffsets(); |
778 | 782 | } |
779 | | - return context.offsets; |
| 783 | + if ( offset in context.offsets ) { |
| 784 | + return context.offsets[offset]; |
| 785 | + } |
| 786 | + // Our offset is not pre-cached. Find the highest offset below it and interpolate |
| 787 | + var lowerBound = 0; |
| 788 | + for ( var o in context.offsets ) { |
| 789 | + if ( o > offset ) { |
| 790 | + break; |
| 791 | + } |
| 792 | + lowerBound = o; |
| 793 | + } |
| 794 | + var base = context.offsets[lowerBound]; |
| 795 | + return context.offsets[offset] = { |
| 796 | + 'node': base.node, |
| 797 | + 'offset': base.offset + offset - o, |
| 798 | + 'length': base.length, |
| 799 | + 'depth': base.depth, |
| 800 | + 'lastTextNode': lastTextNode, |
| 801 | + 'lastTextNodeDepth': lastTextNodeDepth |
| 802 | + }; |
780 | 803 | }, |
781 | 804 | 'purgeOffsets': function() { |
782 | 805 | context.offsets = null; |
— | — | @@ -792,16 +815,14 @@ |
793 | 816 | var nextPos = t.node.nodeName == '#text' ? pos + t.node.nodeValue.length : pos + 1; |
794 | 817 | var nextT = t.next(); |
795 | 818 | var leavingP = t.inP && nextT && !nextT.inP; |
796 | | - for ( var p = pos; p < nextPos; p++ ) { |
797 | | - context.offsets[p] = { |
798 | | - 'node': t.node, |
799 | | - 'offset': p - pos, |
800 | | - 'length': nextPos - pos + ( leavingP ? 1 : 0 ), |
801 | | - 'depth': t.depth, |
802 | | - 'lastTextNode': lastTextNode, |
803 | | - 'lastTextNodeDepth': lastTextNodeDepth |
804 | | - }; |
805 | | - } |
| 819 | + context.offsets[pos] = { |
| 820 | + 'node': t.node, |
| 821 | + 'offset': 0, |
| 822 | + 'length': nextPos - pos + ( leavingP ? 1 : 0 ), |
| 823 | + 'depth': t.depth, |
| 824 | + 'lastTextNode': lastTextNode, |
| 825 | + 'lastTextNodeDepth': lastTextNodeDepth |
| 826 | + }; |
806 | 827 | if ( leavingP ) { |
807 | 828 | // <p>Foo</p> looks like "Foo\n", make it quack like it too |
808 | 829 | // Basically we're faking the \n character much like we're treating <br>s |
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.autoEllipsis.js |
— | — | @@ -3,24 +3,40 @@ |
4 | 4 | */ |
5 | 5 | ( function( $ ) { |
6 | 6 | |
| 7 | +// Cache ellipsed substrings for every string-width combination |
| 8 | +var cache = { }; |
| 9 | + |
7 | 10 | $.fn.autoEllipsis = function( options ) { |
| 11 | + options = $.extend( { |
| 12 | + 'position': 'center', |
| 13 | + 'tooltip': false, |
| 14 | + 'restoreText': false |
| 15 | + }, options ); |
8 | 16 | $(this).each( function() { |
9 | | - options = $.extend( { |
10 | | - 'position': 'center', |
11 | | - 'tooltip': false, |
12 | | - 'restoreText': false |
13 | | - }, options ); |
| 17 | + var $this = $(this); |
14 | 18 | if ( options.restoreText ) { |
15 | | - if ( ! $( this ).data( 'autoEllipsis.originalText' ) ) { |
16 | | - $( this ).data( 'autoEllipsis.originalText', $( this ).text() ); |
| 19 | + if ( ! $this.data( 'autoEllipsis.originalText' ) ) { |
| 20 | + $this.data( 'autoEllipsis.originalText', $this.text() ); |
17 | 21 | } else { |
18 | | - $( this ).text( $( this ).data( 'autoEllipsis.originalText' ) ); |
| 22 | + $this.text( $this.data( 'autoEllipsis.originalText' ) ); |
19 | 23 | } |
20 | 24 | } |
21 | | - var text = $(this).text(); |
22 | | - var $text = $( '<span />' ).text( text ).css( 'whiteSpace', 'nowrap' ); |
23 | | - $(this).empty().append( $text ); |
24 | | - if ( $text.width() > $(this).width() ) { |
| 25 | + var text = $this.text(); |
| 26 | + var w = $this.width(); |
| 27 | + var $text = $( '<span />' ).css( 'whiteSpace', 'nowrap' ); |
| 28 | + $this.empty().append( $text ); |
| 29 | + |
| 30 | + // Try cache |
| 31 | + if ( !( text in cache ) ) { |
| 32 | + cache[text] = {}; |
| 33 | + } |
| 34 | + if ( w in cache[text] ) { |
| 35 | + $text.text( cache[text][w] ); |
| 36 | + return; |
| 37 | + } |
| 38 | + |
| 39 | + $text.text( text ); |
| 40 | + if ( $text.width() > w ) { |
25 | 41 | switch ( options.position ) { |
26 | 42 | case 'right': |
27 | 43 | // Use binary search-like technique for efficiency |
— | — | @@ -28,7 +44,7 @@ |
29 | 45 | do { |
30 | 46 | var m = Math.ceil( ( l + r ) / 2 ); |
31 | 47 | $text.text( text.substr( 0, m ) + '...' ); |
32 | | - if ( $text.width() > $(this).width() ) { |
| 48 | + if ( $text.width() > w ) { |
33 | 49 | // Text is too long |
34 | 50 | r = m - 1; |
35 | 51 | } else { |
— | — | @@ -41,7 +57,7 @@ |
42 | 58 | // TODO: Use binary search like for 'right' |
43 | 59 | var i = [Math.round( text.length / 2 ), Math.round( text.length / 2 )]; |
44 | 60 | var side = 1; // Begin with making the end shorter |
45 | | - while ( $text.outerWidth() > ( $(this).width() ) && i[0] > 0 ) { |
| 61 | + while ( $text.outerWidth() > w && i[0] > 0 ) { |
46 | 62 | $text.text( text.substr( 0, i[0] ) + '...' + text.substr( i[1] ) ); |
47 | 63 | // Alternate between trimming the end and begining |
48 | 64 | if ( side == 0 ) { |
— | — | @@ -58,7 +74,7 @@ |
59 | 75 | case 'left': |
60 | 76 | // TODO: Use binary search like for 'right' |
61 | 77 | var r = 0; |
62 | | - while ( $text.outerWidth() > $(this).width() && r < text.length ) { |
| 78 | + while ( $text.outerWidth() > w && r < text.length ) { |
63 | 79 | $text.text( '...' + text.substr( r ) ); |
64 | 80 | r++; |
65 | 81 | } |
— | — | @@ -67,6 +83,7 @@ |
68 | 84 | if ( options.tooltip ) |
69 | 85 | $text.attr( 'title', text ); |
70 | 86 | } |
| 87 | + cache[text][w] = $text.text(); |
71 | 88 | } ); |
72 | 89 | }; |
73 | 90 | |
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js |
— | — | @@ -76,6 +76,7 @@ |
77 | 77 | }, |
78 | 78 | /** |
79 | 79 | * Strips division of HTML |
| 80 | + * FIXME: Isn't this done by context.fn.htmlToText() already? |
80 | 81 | * |
81 | 82 | * @param division |
82 | 83 | */ |
— | — | @@ -104,8 +105,8 @@ |
105 | 106 | var tokenArray = context.modules.highlight.tokenArray = []; |
106 | 107 | // We need to look over some text and find interesting areas, then return the positions of those areas as tokens |
107 | 108 | var text = context.fn.getContents(); |
108 | | - for ( module in $.wikiEditor.modules ) { |
109 | | - if ( 'exp' in $.wikiEditor.modules[module] ) { |
| 109 | + for ( module in context.modules ) { |
| 110 | + if ( module in $.wikiEditor.modules && 'exp' in $.wikiEditor.modules[module] ) { |
110 | 111 | for ( var i = 0; i < $.wikiEditor.modules[module].exp.length; i++ ) { |
111 | 112 | var regex = $.wikiEditor.modules[module].exp[i].regex; |
112 | 113 | var label = $.wikiEditor.modules[module].exp[i].label; |
— | — | @@ -151,55 +152,48 @@ |
152 | 153 | markers.sort( function( a, b ) { return a.start - b.start || a.end - b.end; } ); |
153 | 154 | |
154 | 155 | // Traverse the iframe DOM, inserting markers where they're needed. |
155 | | - var offsets = context.fn.getOffsets(); |
156 | 156 | for ( var i = 0; i < markers.length; i++ ) { |
157 | 157 | // We want to isolate each marker, so we may need to split textNodes |
158 | 158 | // if a marker starts or ends halfway one. |
159 | 159 | var start = markers[i].start; |
160 | | - if ( !( start in offsets ) ) { |
161 | | - // This shouldn't happen |
162 | | - continue; |
163 | | - } |
164 | | - var startNode = offsets[start].node; |
165 | | - var startDepth = offsets[start].depth; |
| 160 | + var s = context.fn.getOffset( start ); |
| 161 | + var startNode = s.node; |
| 162 | + var startDepth = s.depth; |
166 | 163 | // The next marker starts somewhere in this textNode or at this BR |
167 | | - if ( offsets[start].offset > 0 ) { |
| 164 | + if ( s.offset > 0 ) { |
168 | 165 | // t.node must be a textnode at this point because |
169 | 166 | // only textnodes can have offset > 0 |
170 | 167 | |
171 | 168 | // Split off the prefix |
172 | 169 | // This leaves the prefix in the current node and puts |
173 | 170 | // the rest in a new node which is our start node |
174 | | - startNode = startNode.splitText( offsets[start].offset ); |
| 171 | + startNode = startNode.splitText( s.offset ); |
175 | 172 | } |
176 | 173 | // Don't wrap leading BRs, produces undesirable results |
177 | 174 | while ( startNode.nodeName == 'BR' && start + 1 in offsets ) { |
178 | 175 | start++; |
179 | | - startNode = offsets[start].node; |
180 | | - startDepth = offsets[start].depth; |
| 176 | + startNode = s.node; |
| 177 | + startDepth = s.depth; |
181 | 178 | } |
182 | 179 | |
183 | 180 | var end = markers[i].end; |
184 | | - if ( !( end in offsets ) ) { |
185 | | - // This shouldn't happen |
186 | | - continue; |
187 | | - } |
188 | | - var endNode = offsets[end].node; |
189 | | - var endDepth = offsets[end].depth; |
190 | | - if ( offsets[end].offset < offsets[end].length - 1 ) { |
| 181 | + var e = context.fn.getOffset( end ); |
| 182 | + var endNode = e.node; |
| 183 | + var endDepth = e.depth; |
| 184 | + if ( e.offset < e.length - 1 ) { |
191 | 185 | // t.node must be a textnode at this point because |
192 | 186 | // .length is 1 for BRs and offset can't be < 0 |
193 | 187 | |
194 | 188 | // Split off the suffix - This puts the suffix in a new node and leaves the rest in the current |
195 | 189 | // node. |
196 | 190 | // endNode.nodeValue.length - ( newPos - markers[i].end ) |
197 | | - endNode.splitText( offsets[end].offset + 1 ); |
| 191 | + endNode.splitText( e.offset + 1 ); |
198 | 192 | } |
199 | 193 | |
200 | 194 | // Don't wrap trailing BRs, doing that causes weird issues |
201 | 195 | if ( endNode.nodeName == 'BR' ) { |
202 | | - endNode = offsets[end].lastTextNode; |
203 | | - endDepth = offsets[end].lastTextNodeDepth; |
| 196 | + endNode = e.lastTextNode; |
| 197 | + endDepth = e.lastTextNodeDepth; |
204 | 198 | } |
205 | 199 | |
206 | 200 | // Now wrap everything between startNode and endNode (may be equal). First find the common ancestor of |
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.js |
— | — | @@ -5130,24 +5130,40 @@ |
5131 | 5131 | */ |
5132 | 5132 | ( function( $ ) { |
5133 | 5133 | |
| 5134 | +// Cache ellipsed substrings for every string-width combination |
| 5135 | +var cache = { }; |
| 5136 | + |
5134 | 5137 | $.fn.autoEllipsis = function( options ) { |
| 5138 | + options = $.extend( { |
| 5139 | + 'position': 'center', |
| 5140 | + 'tooltip': false, |
| 5141 | + 'restoreText': false |
| 5142 | + }, options ); |
5135 | 5143 | $(this).each( function() { |
5136 | | - options = $.extend( { |
5137 | | - 'position': 'center', |
5138 | | - 'tooltip': false, |
5139 | | - 'restoreText': false |
5140 | | - }, options ); |
| 5144 | + var $this = $(this); |
5141 | 5145 | if ( options.restoreText ) { |
5142 | | - if ( ! $( this ).data( 'autoEllipsis.originalText' ) ) { |
5143 | | - $( this ).data( 'autoEllipsis.originalText', $( this ).text() ); |
| 5146 | + if ( ! $this.data( 'autoEllipsis.originalText' ) ) { |
| 5147 | + $this.data( 'autoEllipsis.originalText', $this.text() ); |
5144 | 5148 | } else { |
5145 | | - $( this ).text( $( this ).data( 'autoEllipsis.originalText' ) ); |
| 5149 | + $this.text( $this.data( 'autoEllipsis.originalText' ) ); |
5146 | 5150 | } |
5147 | 5151 | } |
5148 | | - var text = $(this).text(); |
5149 | | - var $text = $( '<span />' ).text( text ).css( 'whiteSpace', 'nowrap' ); |
5150 | | - $(this).empty().append( $text ); |
5151 | | - if ( $text.width() > $(this).width() ) { |
| 5152 | + var text = $this.text(); |
| 5153 | + var w = $this.width(); |
| 5154 | + var $text = $( '<span />' ).css( 'whiteSpace', 'nowrap' ); |
| 5155 | + $this.empty().append( $text ); |
| 5156 | + |
| 5157 | + // Try cache |
| 5158 | + if ( !( text in cache ) ) { |
| 5159 | + cache[text] = {}; |
| 5160 | + } |
| 5161 | + if ( w in cache[text] ) { |
| 5162 | + $text.text( cache[text][w] ); |
| 5163 | + return; |
| 5164 | + } |
| 5165 | + |
| 5166 | + $text.text( text ); |
| 5167 | + if ( $text.width() > w ) { |
5152 | 5168 | switch ( options.position ) { |
5153 | 5169 | case 'right': |
5154 | 5170 | // Use binary search-like technique for efficiency |
— | — | @@ -5155,7 +5171,7 @@ |
5156 | 5172 | do { |
5157 | 5173 | var m = Math.ceil( ( l + r ) / 2 ); |
5158 | 5174 | $text.text( text.substr( 0, m ) + '...' ); |
5159 | | - if ( $text.width() > $(this).width() ) { |
| 5175 | + if ( $text.width() > w ) { |
5160 | 5176 | // Text is too long |
5161 | 5177 | r = m - 1; |
5162 | 5178 | } else { |
— | — | @@ -5168,7 +5184,7 @@ |
5169 | 5185 | // TODO: Use binary search like for 'right' |
5170 | 5186 | var i = [Math.round( text.length / 2 ), Math.round( text.length / 2 )]; |
5171 | 5187 | var side = 1; // Begin with making the end shorter |
5172 | | - while ( $text.outerWidth() > ( $(this).width() ) && i[0] > 0 ) { |
| 5188 | + while ( $text.outerWidth() > w && i[0] > 0 ) { |
5173 | 5189 | $text.text( text.substr( 0, i[0] ) + '...' + text.substr( i[1] ) ); |
5174 | 5190 | // Alternate between trimming the end and begining |
5175 | 5191 | if ( side == 0 ) { |
— | — | @@ -5185,7 +5201,7 @@ |
5186 | 5202 | case 'left': |
5187 | 5203 | // TODO: Use binary search like for 'right' |
5188 | 5204 | var r = 0; |
5189 | | - while ( $text.outerWidth() > $(this).width() && r < text.length ) { |
| 5205 | + while ( $text.outerWidth() > w && r < text.length ) { |
5190 | 5206 | $text.text( '...' + text.substr( r ) ); |
5191 | 5207 | r++; |
5192 | 5208 | } |
— | — | @@ -5194,6 +5210,7 @@ |
5195 | 5211 | if ( options.tooltip ) |
5196 | 5212 | $text.attr( 'title', text ); |
5197 | 5213 | } |
| 5214 | + cache[text][w] = $text.text(); |
5198 | 5215 | } ); |
5199 | 5216 | }; |
5200 | 5217 | |
— | — | @@ -6916,13 +6933,12 @@ |
6917 | 6934 | // Firefox and Opera |
6918 | 6935 | var start = options.start, end = options.end; |
6919 | 6936 | if ( !sc || !ec ) { |
6920 | | - var offsets = context.fn.getOffsets(); |
6921 | | - var startContainer = offsets[start].node, startOffset = offsets[start].offset; |
6922 | | - var endContainer = offsets[end].node, endOffset = offsets[end].offset; |
6923 | | - sc = offsets[start].node; |
6924 | | - ec = offsets[end].node; |
6925 | | - start = offsets[start].offset; |
6926 | | - end = offsets[end].offset; |
| 6937 | + var s = context.fn.getOffset( start ); |
| 6938 | + var e = context.fn.getOffset( end ); |
| 6939 | + sc = s.node; |
| 6940 | + ec = e.node; |
| 6941 | + start = s.offset; |
| 6942 | + end = e.offset; |
6927 | 6943 | } |
6928 | 6944 | if ( !sc || !ec ) { |
6929 | 6945 | // The requested offset isn't in the offsets array |
— | — | @@ -7035,11 +7051,12 @@ |
7036 | 7052 | return $( [] ); |
7037 | 7053 | } |
7038 | 7054 | var seekPos = context.fn.htmlToText( range2.htmlText ).length; |
7039 | | - var offsets = context.fn.getOffsets(); |
7040 | | - e = offsets[seekPos] ? offsets[seekPos].node : null; |
7041 | | - offset = offsets[seekPos] ? offsets[seekPos].offset : null; |
7042 | | - if ( !e ) |
| 7055 | + var offset = context.fn.getOffset( seekPos ); |
| 7056 | + e = offset ? offset.node : null; |
| 7057 | + offset = offset ? offset.offset : null; |
| 7058 | + if ( !e ) { |
7043 | 7059 | return $( [] ); |
| 7060 | + } |
7044 | 7061 | } |
7045 | 7062 | if ( e.nodeName != '#text' ) { |
7046 | 7063 | // The selection is not in a textnode, but between two non-text nodes |
— | — | @@ -7100,7 +7117,9 @@ |
7101 | 7118 | p = p ? p.nextSibling : null; |
7102 | 7119 | do { |
7103 | 7120 | // Filter nodes with the wikiEditor-noinclude class |
7104 | | - while ( p && $( p ).hasClass( 'wikiEditor-noinclude' ) ) { |
| 7121 | + // Don't use $( p ).hasClass( 'wikiEditor-noinclude' ) because |
| 7122 | + // $() is slow in a tight loop |
| 7123 | + while ( p && ( ' ' + p.className + ' ' ).indexOf( ' wikiEditor-noinclude ' ) != -1 ) { |
7105 | 7124 | p = p.nextSibling; |
7106 | 7125 | } |
7107 | 7126 | if ( p && p.firstChild ) { |
— | — | @@ -7120,7 +7139,9 @@ |
7121 | 7140 | var inP = node.nodeName == "P"; |
7122 | 7141 | do { |
7123 | 7142 | // Filter nodes with the wikiEditor-noinclude class |
7124 | | - while ( node && $( node ).hasClass( 'wikiEditor-noinclude' ) ) { |
| 7143 | + // Don't use $( p ).hasClass( 'wikiEditor-noinclude' ) because |
| 7144 | + // $() is slow in a tight loop |
| 7145 | + while ( node && ( ' ' + node.className + ' ' ).indexOf( ' wikiEditor-noinclude ' ) != -1 ) { |
7125 | 7146 | node = node.nextSibling; |
7126 | 7147 | } |
7127 | 7148 | if ( node && node.firstChild ) { |
— | — | @@ -7133,11 +7154,30 @@ |
7134 | 7155 | } while ( node && node.firstChild ); |
7135 | 7156 | return new Traverser( node, depth, inP ); |
7136 | 7157 | }, |
7137 | | - 'getOffsets': function() { |
| 7158 | + 'getOffset': function( offset ) { |
7138 | 7159 | if ( !context.offsets ) { |
7139 | 7160 | context.fn.refreshOffsets(); |
7140 | 7161 | } |
7141 | | - return context.offsets; |
| 7162 | + if ( offset in context.offsets ) { |
| 7163 | + return context.offsets[offset]; |
| 7164 | + } |
| 7165 | + // Our offset is not pre-cached. Find the highest offset below it and interpolate |
| 7166 | + var lowerBound = 0; |
| 7167 | + for ( var o in context.offsets ) { |
| 7168 | + if ( o > offset ) { |
| 7169 | + break; |
| 7170 | + } |
| 7171 | + lowerBound = o; |
| 7172 | + } |
| 7173 | + var base = context.offsets[lowerBound]; |
| 7174 | + return context.offsets[offset] = { |
| 7175 | + 'node': base.node, |
| 7176 | + 'offset': base.offset + offset - o, |
| 7177 | + 'length': base.length, |
| 7178 | + 'depth': base.depth, |
| 7179 | + 'lastTextNode': lastTextNode, |
| 7180 | + 'lastTextNodeDepth': lastTextNodeDepth |
| 7181 | + }; |
7142 | 7182 | }, |
7143 | 7183 | 'purgeOffsets': function() { |
7144 | 7184 | context.offsets = null; |
— | — | @@ -7154,16 +7194,14 @@ |
7155 | 7195 | var nextPos = t.node.nodeName == '#text' ? pos + t.node.nodeValue.length : pos + 1; |
7156 | 7196 | var nextT = t.next(); |
7157 | 7197 | var leavingP = t.inP && nextT && !nextT.inP; |
7158 | | - for ( var p = pos; p < nextPos; p++ ) { |
7159 | | - context.offsets[p] = { |
7160 | | - 'node': t.node, |
7161 | | - 'offset': p - pos, |
7162 | | - 'length': nextPos - pos + ( leavingP ? 1 : 0 ), |
7163 | | - 'depth': t.depth, |
7164 | | - 'lastTextNode': lastTextNode, |
7165 | | - 'lastTextNodeDepth': lastTextNodeDepth |
7166 | | - }; |
7167 | | - } |
| 7198 | + context.offsets[pos] = { |
| 7199 | + 'node': t.node, |
| 7200 | + 'offset': 0, |
| 7201 | + 'length': nextPos - pos + ( leavingP ? 1 : 0 ), |
| 7202 | + 'depth': t.depth, |
| 7203 | + 'lastTextNode': lastTextNode, |
| 7204 | + 'lastTextNodeDepth': lastTextNodeDepth |
| 7205 | + }; |
7168 | 7206 | if ( leavingP ) { |
7169 | 7207 | // <p>Foo</p> looks like "Foo\n", make it quack like it too |
7170 | 7208 | // Basically we're faking the \n character much like we're treating <br>s |
— | — | @@ -7554,6 +7592,7 @@ |
7555 | 7593 | }, |
7556 | 7594 | /** |
7557 | 7595 | * Strips division of HTML |
| 7596 | + * FIXME: Isn't this done by context.fn.htmlToText() already? |
7558 | 7597 | * |
7559 | 7598 | * @param division |
7560 | 7599 | */ |
— | — | @@ -7582,8 +7621,8 @@ |
7583 | 7622 | var tokenArray = context.modules.highlight.tokenArray = []; |
7584 | 7623 | // We need to look over some text and find interesting areas, then return the positions of those areas as tokens |
7585 | 7624 | var text = context.fn.getContents(); |
7586 | | - for ( module in $.wikiEditor.modules ) { |
7587 | | - if ( 'exp' in $.wikiEditor.modules[module] ) { |
| 7625 | + for ( module in context.modules ) { |
| 7626 | + if ( module in $.wikiEditor.modules && 'exp' in $.wikiEditor.modules[module] ) { |
7588 | 7627 | for ( var i = 0; i < $.wikiEditor.modules[module].exp.length; i++ ) { |
7589 | 7628 | var regex = $.wikiEditor.modules[module].exp[i].regex; |
7590 | 7629 | var label = $.wikiEditor.modules[module].exp[i].label; |
— | — | @@ -7629,55 +7668,48 @@ |
7630 | 7669 | markers.sort( function( a, b ) { return a.start - b.start || a.end - b.end; } ); |
7631 | 7670 | |
7632 | 7671 | // Traverse the iframe DOM, inserting markers where they're needed. |
7633 | | - var offsets = context.fn.getOffsets(); |
7634 | 7672 | for ( var i = 0; i < markers.length; i++ ) { |
7635 | 7673 | // We want to isolate each marker, so we may need to split textNodes |
7636 | 7674 | // if a marker starts or ends halfway one. |
7637 | 7675 | var start = markers[i].start; |
7638 | | - if ( !( start in offsets ) ) { |
7639 | | - // This shouldn't happen |
7640 | | - continue; |
7641 | | - } |
7642 | | - var startNode = offsets[start].node; |
7643 | | - var startDepth = offsets[start].depth; |
| 7676 | + var s = context.fn.getOffset( start ); |
| 7677 | + var startNode = s.node; |
| 7678 | + var startDepth = s.depth; |
7644 | 7679 | // The next marker starts somewhere in this textNode or at this BR |
7645 | | - if ( offsets[start].offset > 0 ) { |
| 7680 | + if ( s.offset > 0 ) { |
7646 | 7681 | // t.node must be a textnode at this point because |
7647 | 7682 | // only textnodes can have offset > 0 |
7648 | 7683 | |
7649 | 7684 | // Split off the prefix |
7650 | 7685 | // This leaves the prefix in the current node and puts |
7651 | 7686 | // the rest in a new node which is our start node |
7652 | | - startNode = startNode.splitText( offsets[start].offset ); |
| 7687 | + startNode = startNode.splitText( s.offset ); |
7653 | 7688 | } |
7654 | 7689 | // Don't wrap leading BRs, produces undesirable results |
7655 | 7690 | while ( startNode.nodeName == 'BR' && start + 1 in offsets ) { |
7656 | 7691 | start++; |
7657 | | - startNode = offsets[start].node; |
7658 | | - startDepth = offsets[start].depth; |
| 7692 | + startNode = s.node; |
| 7693 | + startDepth = s.depth; |
7659 | 7694 | } |
7660 | 7695 | |
7661 | 7696 | var end = markers[i].end; |
7662 | | - if ( !( end in offsets ) ) { |
7663 | | - // This shouldn't happen |
7664 | | - continue; |
7665 | | - } |
7666 | | - var endNode = offsets[end].node; |
7667 | | - var endDepth = offsets[end].depth; |
7668 | | - if ( offsets[end].offset < offsets[end].length - 1 ) { |
| 7697 | + var e = context.fn.getOffset( end ); |
| 7698 | + var endNode = e.node; |
| 7699 | + var endDepth = e.depth; |
| 7700 | + if ( e.offset < e.length - 1 ) { |
7669 | 7701 | // t.node must be a textnode at this point because |
7670 | 7702 | // .length is 1 for BRs and offset can't be < 0 |
7671 | 7703 | |
7672 | 7704 | // Split off the suffix - This puts the suffix in a new node and leaves the rest in the current |
7673 | 7705 | // node. |
7674 | 7706 | // endNode.nodeValue.length - ( newPos - markers[i].end ) |
7675 | | - endNode.splitText( offsets[end].offset + 1 ); |
| 7707 | + endNode.splitText( e.offset + 1 ); |
7676 | 7708 | } |
7677 | 7709 | |
7678 | 7710 | // Don't wrap trailing BRs, doing that causes weird issues |
7679 | 7711 | if ( endNode.nodeName == 'BR' ) { |
7680 | | - endNode = offsets[end].lastTextNode; |
7681 | | - endDepth = offsets[end].lastTextNodeDepth; |
| 7712 | + endNode = e.lastTextNode; |
| 7713 | + endDepth = e.lastTextNodeDepth; |
7682 | 7714 | } |
7683 | 7715 | |
7684 | 7716 | // Now wrap everything between startNode and endNode (may be equal). First find the common ancestor of |
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js |
— | — | @@ -354,12 +354,15 @@ |
355 | 355 | {var i=0,l=array.length,loop=opts.loop||function(){};$.whileAsync($.extend(opts,{test:function(){return i<l;},loop:function() |
356 | 356 | {var val=array[i];return loop.call(val,i++,val);}}));} |
357 | 357 | $.fn.eachAsync=function(opts) |
358 | | -{$.eachAsync(this,opts);return this;}})(jQuery);(function($){$.fn.autoEllipsis=function(options){$(this).each(function(){options=$.extend({'position':'center','tooltip':false,'restoreText':false},options);if(options.restoreText){if(!$(this).data('autoEllipsis.originalText')){$(this).data('autoEllipsis.originalText',$(this).text());}else{$(this).text($(this).data('autoEllipsis.originalText'));}} |
359 | | -var text=$(this).text();var $text=$('<span />').text(text).css('whiteSpace','nowrap');$(this).empty().append($text);if($text.width()>$(this).width()){switch(options.position){case'right':var l=0,r=text.length;do{var m=Math.ceil((l+r)/2);$text.text(text.substr(0,m)+'...');if($text.width()>$(this).width()){r=m-1;}else{l=m;}}while(l<r);$text.text(text.substr(0,l)+'...');break;case'center':var i=[Math.round(text.length/2),Math.round(text.length/2)];var side=1;while($text.outerWidth()>($(this).width())&&i[0]>0){$text.text(text.substr(0,i[0])+'...'+text.substr(i[1]));if(side==0){i[0]--;side=1;}else{i[1]++;side=0;}} |
360 | | -break;case'left':var r=0;while($text.outerWidth()>$(this).width()&&r<text.length){$text.text('...'+text.substr(r));r++;} |
| 358 | +{$.eachAsync(this,opts);return this;}})(jQuery);(function($){var cache={};$.fn.autoEllipsis=function(options){options=$.extend({'position':'center','tooltip':false,'restoreText':false},options);$(this).each(function(){var $this=$(this);if(options.restoreText){if(!$this.data('autoEllipsis.originalText')){$this.data('autoEllipsis.originalText',$this.text());}else{$this.text($this.data('autoEllipsis.originalText'));}} |
| 359 | +var text=$this.text();var w=$this.width();var $text=$('<span />').css('whiteSpace','nowrap');$this.empty().append($text);if(!(text in cache)){cache[text]={};} |
| 360 | +if(w in cache[text]){$text.text(cache[text][w]);return;} |
| 361 | +$text.text(text);if($text.width()>w){switch(options.position){case'right':var l=0,r=text.length;do{var m=Math.ceil((l+r)/2);$text.text(text.substr(0,m)+'...');if($text.width()>w){r=m-1;}else{l=m;}}while(l<r);$text.text(text.substr(0,l)+'...');break;case'center':var i=[Math.round(text.length/2),Math.round(text.length/2)];var side=1;while($text.outerWidth()>w&&i[0]>0){$text.text(text.substr(0,i[0])+'...'+text.substr(i[1]));if(side==0){i[0]--;side=1;}else{i[1]++;side=0;}} |
| 362 | +break;case'left':var r=0;while($text.outerWidth()>w&&r<text.length){$text.text('...'+text.substr(r));r++;} |
361 | 363 | break;} |
362 | 364 | if(options.tooltip) |
363 | | -$text.attr('title',text);}});};})(jQuery);(function($){$.browserTest=function(a,z){var u='unknown',x='X',m=function(r,h){for(var i=0;i<h.length;i=i+1){r=r.replace(h[i][0],h[i][1]);} |
| 365 | +$text.attr('title',text);} |
| 366 | +cache[text][w]=$text.text();});};})(jQuery);(function($){$.browserTest=function(a,z){var u='unknown',x='X',m=function(r,h){for(var i=0;i<h.length;i=i+1){r=r.replace(h[i][0],h[i][1]);} |
364 | 367 | return r;},c=function(i,a,b,c){var r={name:m((a.exec(i)||[u,u])[1],b)};r[r.name]=true;r.version=(c.exec(i)||[x,x,x,x])[3];if(r.name.match(/safari/)&&r.version>400){r.version='2.0';} |
365 | 368 | if(r.name==='presto'){r.version=($.browser.version>9.27)?'futhark':'linear_b';} |
366 | 369 | r.versionNumber=parseFloat(r.version,10)||0;r.versionX=(r.version!==x)?(r.version+'').substr(0,1):x;r.className=r.name+r.versionX;return r;};a=(a.match(/Opera|Navigator|Minefield|KHTML|Chrome/)?m(a,[[/(Firefox|MSIE|KHTML,\slike\sGecko|Konqueror)/,''],['Chrome Safari','Chrome'],['KHTML','Konqueror'],['Minefield','Firefox'],['Navigator','Netscape']]):a).toLowerCase();$.browser=$.extend((!z)?$.browser:{},c(a,/(camino|chrome|firefox|netscape|konqueror|lynx|msie|opera|safari)/,[],/(camino|chrome|firefox|netscape|netscape6|opera|version|konqueror|lynx|msie|safari)(\/|\s)([a-z0-9\.\+]*?)(\;|dev|rel|\s|$)/));$.layout=c(a,/(gecko|konqueror|msie|opera|webkit)/,[['konqueror','khtml'],['msie','trident'],['opera','presto']],/(applewebkit|rv|konqueror|msie)(\:|\/|\s)([a-z0-9\.]*?)(\;|\)|\s)/);$.os={name:(/(win|mac|linux|sunos|solaris|iphone)/.exec(navigator.platform.toLowerCase())||[u])[0].replace('sunos','solaris')};if(!z){$('html').addClass([$.os.name,$.browser.name,$.browser.className,$.layout.name,$.layout.className].join(' '));}};$.browserTest(navigator.userAgent);})(jQuery);(function($){$.fn.collapsibleTabs=function($$options){if(!this.length)return this;var $settings=$.extend({},$.collapsibleTabs.defaults,$$options);this.each(function(){var $this=$(this);$.collapsibleTabs.instances=($.collapsibleTabs.instances.length==0?$this:$.collapsibleTabs.instances.add($this));$this.data('collapsibleTabsSettings',$settings);$this.children($settings.collapsible).each(function(){var $collapsible=$(this);$collapsible.data('collapsibleTabsSettings',{'expandedContainer':$settings.expandedContainer,'collapsedContainer':$settings.collapsedContainer,'expandedWidth':$collapsible.width(),'prevElement':$collapsible.prev()});});});if(!$.collapsibleTabs.boundEvent){$(window).delayedBind('500','resize',function(){$.collapsibleTabs.handleResize();});} |
— | — | @@ -453,7 +456,7 @@ |
454 | 457 | var range3=context.$iframe[0].contentWindow.document.selection.createRange();range3.collapse(false);range3.moveEnd('character',1);if(range3.text!="\r"&&range3.text!="\n"&&range3.text!=""){post+="\n";}} |
455 | 458 | var insertText="";if(options.splitlines){for(var i=0;i<selTextArr.length;i++){insertText=insertText+pre+selTextArr[i]+post;if(i!=selTextArr.length-1)insertText+="\n";}}else{insertText=pre+selText+post;} |
456 | 459 | range.pasteHTML(insertText.replace(/\</g,'<').replace(/>/g,'>').replace(/\r?\n/g,'<br />'));} |
457 | | -$(context.$iframe[0].contentWindow.document).trigger('encapsulateSelection',[pre,options.peri,post,options.ownline,options.replace]);return context.$textarea;},'getCaretPosition':function(options){},'setSelection':function(options){var sc=options.startContainer,ec=options.endContainer;sc=sc&&sc.jquery?sc[0]:sc;ec=ec&&ec.jquery?ec[0]:ec;if(context.$iframe[0].contentWindow.getSelection){var start=options.start,end=options.end;if(!sc||!ec){var offsets=context.fn.getOffsets();var startContainer=offsets[start].node,startOffset=offsets[start].offset;var endContainer=offsets[end].node,endOffset=offsets[end].offset;sc=offsets[start].node;ec=offsets[end].node;start=offsets[start].offset;end=offsets[end].offset;} |
| 460 | +$(context.$iframe[0].contentWindow.document).trigger('encapsulateSelection',[pre,options.peri,post,options.ownline,options.replace]);return context.$textarea;},'getCaretPosition':function(options){},'setSelection':function(options){var sc=options.startContainer,ec=options.endContainer;sc=sc&&sc.jquery?sc[0]:sc;ec=ec&&ec.jquery?ec[0]:ec;if(context.$iframe[0].contentWindow.getSelection){var start=options.start,end=options.end;if(!sc||!ec){var s=context.fn.getOffset(start);var e=context.fn.getOffset(end);sc=s.node;ec=e.node;start=s.offset;end=e.offset;} |
458 | 461 | if(!sc||!ec){return context.$textarea;} |
459 | 462 | var sel=context.$iframe[0].contentWindow.getSelection();while(sc.firstChild&&sc.nodeName!='#text'){sc=sc.firstChild;} |
460 | 463 | while(ec.firstChild&&ec.nodeName!='#text'){ec=ec.firstChild;} |
— | — | @@ -464,8 +467,7 @@ |
465 | 468 | var topBound=html.scrollTop()>body.scrollTop()?html.scrollTop():body.scrollTop(),bottomBound=topBound+context.$iframe.height();if(force||y<topBound||y>bottomBound){html.scrollTop(y);body.scrollTop(y);} |
466 | 469 | $element.trigger('scrollToTop');},'beforeSelection':function(selector,strict){if(typeof selector=='undefined'){selector='*';} |
467 | 470 | var e,offset;if(context.$iframe[0].contentWindow.getSelection){var selection=context.$iframe[0].contentWindow.getSelection();if(selection.baseNode!==null){e=selection.getRangeAt(0).startContainer;offset=selection.startOffset;}else{return $([]);}}else if(context.$iframe[0].contentWindow.document.selection){var range=context.$iframe[0].contentWindow.document.selection.createRange();var range2=context.$iframe[0].contentWindow.document.body.createTextRange();try{range2.setEndPoint('EndToStart',range);}catch(e){return $([]);} |
468 | | -var seekPos=context.fn.htmlToText(range2.htmlText).length;var offsets=context.fn.getOffsets();e=offsets[seekPos]?offsets[seekPos].node:null;offset=offsets[seekPos]?offsets[seekPos].offset:null;if(!e) |
469 | | -return $([]);} |
| 471 | +var seekPos=context.fn.htmlToText(range2.htmlText).length;var offset=context.fn.getOffset(seekPos);e=offset?offset.node:null;offset=offset?offset.offset:null;if(!e){return $([]);}} |
470 | 472 | if(e.nodeName!='#text'){var newE=e.firstChild;for(var i=0;i<offset-1&&newE;i++){newE=newE.nextSibling;} |
471 | 473 | while(newE&&newE.lastChild){newE=newE.lastChild;} |
472 | 474 | e=newE||e;} |
— | — | @@ -474,13 +476,15 @@ |
475 | 477 | e=next||e.parentNode;strict=false;} |
476 | 478 | return $([]);},'traverser':function(start){function Traverser(node,depth,inP){this.node=node;this.depth=depth;this.inP=inP;this.next=function(){var p=this.node;var nextDepth=this.depth;var nextInP=this.inP;while(p&&!p.nextSibling){if(p.nodeName=="P"){nextInP=false;} |
477 | 479 | p=p.parentNode;nextDepth--;if(nextDepth==0){p=null;}} |
478 | | -p=p?p.nextSibling:null;do{while(p&&$(p).hasClass('wikiEditor-noinclude')){p=p.nextSibling;} |
| 480 | +p=p?p.nextSibling:null;do{while(p&&(' '+p.className+' ').indexOf(' wikiEditor-noinclude ')!=-1){p=p.nextSibling;} |
479 | 481 | if(p&&p.firstChild){p=p.firstChild;nextDepth++;if(p.nodeName=="P"){nextInP=true;}}}while(p&&p.firstChild);return p?new Traverser(p,nextDepth,nextInP):null;};} |
480 | | -var node=start.jquery?start.get(0):start;var depth=0;var inP=node.nodeName=="P";do{while(node&&$(node).hasClass('wikiEditor-noinclude')){node=node.nextSibling;} |
481 | | -if(node&&node.firstChild){node=node.firstChild;depth++;if(node.nodeName=="P"){inP=true;}}}while(node&&node.firstChild);return new Traverser(node,depth,inP);},'getOffsets':function(){if(!context.offsets){context.fn.refreshOffsets();} |
482 | | -return context.offsets;},'purgeOffsets':function(){context.offsets=null;},'refreshOffsets':function(){context.offsets=[];var t=context.fn.traverser(context.$content);var pos=0,lastTextNode=null,lastTextNodeDepth=null;while(t){if(t.node.nodeName!='#text'&&t.node.nodeName!='BR'){t=t.next();continue;} |
483 | | -var nextPos=t.node.nodeName=='#text'?pos+t.node.nodeValue.length:pos+1;var nextT=t.next();var leavingP=t.inP&&nextT&&!nextT.inP;for(var p=pos;p<nextPos;p++){context.offsets[p]={'node':t.node,'offset':p-pos,'length':nextPos-pos+(leavingP?1:0),'depth':t.depth,'lastTextNode':lastTextNode,'lastTextNodeDepth':lastTextNodeDepth};} |
484 | | -if(leavingP){context.offsets[nextPos]={'node':t.node,'offset':nextPos-pos,'length':nextPos-pos+1,'depth':t.depth,'lastTextNode':lastTextNode,'lastTextNodeDepth':lastTextNodeDepth};} |
| 482 | +var node=start.jquery?start.get(0):start;var depth=0;var inP=node.nodeName=="P";do{while(node&&(' '+node.className+' ').indexOf(' wikiEditor-noinclude ')!=-1){node=node.nextSibling;} |
| 483 | +if(node&&node.firstChild){node=node.firstChild;depth++;if(node.nodeName=="P"){inP=true;}}}while(node&&node.firstChild);return new Traverser(node,depth,inP);},'getOffset':function(offset){if(!context.offsets){context.fn.refreshOffsets();} |
| 484 | +if(offset in context.offsets){return context.offsets[offset];} |
| 485 | +var lowerBound=0;for(var o in context.offsets){if(o>offset){break;} |
| 486 | +lowerBound=o;} |
| 487 | +var base=context.offsets[lowerBound];return context.offsets[offset]={'node':base.node,'offset':base.offset+offset-o,'length':base.length,'depth':base.depth,'lastTextNode':lastTextNode,'lastTextNodeDepth':lastTextNodeDepth};},'purgeOffsets':function(){context.offsets=null;},'refreshOffsets':function(){context.offsets=[];var t=context.fn.traverser(context.$content);var pos=0,lastTextNode=null,lastTextNodeDepth=null;while(t){if(t.node.nodeName!='#text'&&t.node.nodeName!='BR'){t=t.next();continue;} |
| 488 | +var nextPos=t.node.nodeName=='#text'?pos+t.node.nodeValue.length:pos+1;var nextT=t.next();var leavingP=t.inP&&nextT&&!nextT.inP;context.offsets[pos]={'node':t.node,'offset':0,'length':nextPos-pos+(leavingP?1:0),'depth':t.depth,'lastTextNode':lastTextNode,'lastTextNodeDepth':lastTextNodeDepth};if(leavingP){context.offsets[nextPos]={'node':t.node,'offset':nextPos-pos,'length':nextPos-pos+1,'depth':t.depth,'lastTextNode':lastTextNode,'lastTextNodeDepth':lastTextNodeDepth};} |
485 | 489 | pos=nextPos+(leavingP?1:0);if(t.node.nodeName=='#text'){lastTextNode=t.node;lastTextNodeDepth=t.depth;} |
486 | 490 | t=nextT;}}};context.$textarea.wrap($('<div></div>').addClass('wikiEditor-ui')).wrap($('<div></div>').addClass('wikiEditor-ui-view wikiEditor-ui-view-wikitext')).wrap($('<div></div>').addClass('wikiEditor-ui-left')).wrap($('<div></div>').addClass('wikiEditor-ui-bottom')).wrap($('<div></div>').addClass('wikiEditor-ui-text'));context.$ui=context.$textarea.parent().parent().parent().parent().parent();context.$wikitext=context.$textarea.parent().parent().parent().parent();context.$wikitext.before($('<div></div>').addClass('wikiEditor-ui-controls').append($('<div></div>').addClass('wikiEditor-ui-tabs').hide()).append($('<div></div>').addClass('wikiEditor-ui-buttons'))).before($('<div style="clear:both;"></div>'));context.$controls=context.$ui.find('.wikiEditor-ui-buttons').hide();context.$buttons=context.$ui.find('.wikiEditor-ui-buttons');context.$tabs=context.$ui.find('.wikiEditor-ui-tabs');context.$ui.after($('<div style="clear:both;"></div>'));context.$wikitext.append($('<div></div>').addClass('wikiEditor-ui-right'));context.$wikitext.find('.wikiEditor-ui-left').prepend($('<div></div>').addClass('wikiEditor-ui-top'));context.view='wikitext';$(window).resize(function(event){context.fn.trigger('resize',event)});context.$iframe=$('<iframe></iframe>').attr({'frameBorder':0,'border':0,'src':wgScriptPath+'/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html?'+'instance='+context.instance+'&ts='+(new Date()).getTime(),'id':'wikiEditor-iframe-'+context.instance}).css({'backgroundColor':'white','width':'100%','height':context.$textarea.height(),'display':'none','overflow-y':'scroll','overflow-x':'hidden'}).insertAfter(context.$textarea).load(function(){if(!this.isSecondRun){context.$iframe[0].contentWindow.document.designMode='on';if($.browser.msie){this.isSecondRun=true;return;}} |
487 | 491 | context.$content=$(context.$iframe[0].contentWindow.document.body);var html=context.$textarea.val().replace(/\</g,'<').replace(/\>/g,'>');if($.browser.msie){if($.browser.versionNumber<=7){html=html.replace(/ /g," ");}else{html=html.replace(/(^|\n) /g,"$1 ");} |
— | — | @@ -494,15 +498,13 @@ |
495 | 499 | var maxTI=0;$j('[tabindex]').each(function(){var ti=parseInt($j(this).attr('tabindex'));if(ti>maxTI) |
496 | 500 | 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);} |
497 | 501 | $(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={cfg:{'styleVersion':3},evt:{delayedChange:function(context,event){if(event.data.scope=='division'){$.wikiEditor.modules.highlight.fn.scan(context,"");$.wikiEditor.modules.highlight.fn.mark(context,"","");}},ready:function(context,event){$.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,tokenStart,match){this.offset=offset;this.label=label;this.tokenStart=tokenStart;this.match=match;} |
498 | | -var tokenArray=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;} |
| 502 | +var tokenArray=context.modules.highlight.tokenArray=[];var text=context.fn.getContents();for(module in context.modules){if(module in $.wikiEditor.modules&&'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;} |
499 | 503 | match=text.match(regex);var oldOffset=0;while(match!=null){var markOffset=0;var tokenStart=match.index+oldOffset+markOffset;if(markAfter){markOffset+=match[0].length;} |
500 | 504 | tokenArray.push(new Token(match.index+oldOffset+markOffset,label,tokenStart,match));oldOffset+=match.index+match[0].length;newSubstring=text.substring(oldOffset);match=newSubstring.match(regex);}}}} |
501 | | -tokenArray.sort(function(a,b){return a.offset-b.offset||a.tokenStart-b.tokenStart;});context.fn.trigger('scan');},mark:function(context,division,tokens){var markers=context.modules.highlight.markers=[];context.fn.trigger('mark');markers.sort(function(a,b){return a.start-b.start||a.end-b.end;});var offsets=context.fn.getOffsets();for(var i=0;i<markers.length;i++){var start=markers[i].start;if(!(start in offsets)){continue;} |
502 | | -var startNode=offsets[start].node;var startDepth=offsets[start].depth;if(offsets[start].offset>0){startNode=startNode.splitText(offsets[start].offset);} |
503 | | -while(startNode.nodeName=='BR'&&start+1 in offsets){start++;startNode=offsets[start].node;startDepth=offsets[start].depth;} |
504 | | -var end=markers[i].end;if(!(end in offsets)){continue;} |
505 | | -var endNode=offsets[end].node;var endDepth=offsets[end].depth;if(offsets[end].offset<offsets[end].length-1){endNode.splitText(offsets[end].offset+1);} |
506 | | -if(endNode.nodeName=='BR'){endNode=offsets[end].lastTextNode;endDepth=offsets[end].lastTextNodeDepth;} |
| 505 | +tokenArray.sort(function(a,b){return a.offset-b.offset||a.tokenStart-b.tokenStart;});context.fn.trigger('scan');},mark:function(context,division,tokens){var markers=context.modules.highlight.markers=[];context.fn.trigger('mark');markers.sort(function(a,b){return a.start-b.start||a.end-b.end;});for(var i=0;i<markers.length;i++){var start=markers[i].start;var s=context.fn.getOffset(start);var startNode=s.node;var startDepth=s.depth;if(s.offset>0){startNode=startNode.splitText(s.offset);} |
| 506 | +while(startNode.nodeName=='BR'&&start+1 in offsets){start++;startNode=s.node;startDepth=s.depth;} |
| 507 | +var end=markers[i].end;var e=context.fn.getOffset(end);var endNode=e.node;var endDepth=e.depth;if(e.offset<e.length-1){endNode.splitText(e.offset+1);} |
| 508 | +if(endNode.nodeName=='BR'){endNode=e.lastTextNode;endDepth=e.lastTextNodeDepth;} |
507 | 509 | var ca1=startNode,ca2=endNode;if(startDepth>endDepth){for(var j=0;j<startDepth-endDepth&&ca1;j++){ca1=ca1.parentNode.firstChild==ca1?ca1.parentNode:null;}} |
508 | 510 | else if(startDepth<endDepth){for(var j=0;j<endDepth-startDepth&&ca2;j++){ca2=ca2.parentNode.lastChild==ca2?ca2.parentNode:null;}} |
509 | 511 | while(ca1&&ca2&&ca1.parentNode&&ca2.parentNode&&ca1.parentNode!=ca2.parentNode&&ca1.parentNode.firstChild&&ca2.parentNode.lastChild){ca1=ca1.parentNode.firstChild==ca1?ca1.parentNode:null;ca2=ca2.parentNode.lastChild==ca2?ca2.parentNode:null;} |