r65913 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r65912‎ | r65913 | r65914 >
Date:19:10, 4 May 2010
Author:tparscal
Status:ok
Tags:
Comment:
Added templates module to WikiEditor. Also, rewrote the highligh module's scan function.
Modified paths:
  • /trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php (modified) (history)
  • /trunk/extensions/UsabilityInitiative/WikiEditor/Modules/Templates (added) (history)
  • /trunk/extensions/UsabilityInitiative/WikiEditor/Modules/Templates/Templates.i18n.php (added) (history)
  • /trunk/extensions/UsabilityInitiative/WikiEditor/Modules/Templates/Templates.js (added) (history)
  • /trunk/extensions/UsabilityInitiative/WikiEditor/WikiEditor.hooks.php (modified) (history)
  • /trunk/extensions/UsabilityInitiative/WikiEditor/WikiEditor.php (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins.combined.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js (modified) (history)
  • /trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.templates.js (added) (history)

Diff [purge]

Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php
@@ -72,20 +72,21 @@
7373 array( 'src' => 'js/plugins/jquery.delayedBind.js', 'version' => 1 ),
7474 array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 11 ),
7575 array( 'src' => 'js/plugins/jquery.textSelection.js', 'version' => 30 ),
76 - array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 184 ),
77 - array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 52 ),
 76+ array( 'src' => 'js/plugins/jquery.wikiEditor.js', 'version' => 185 ),
 77+ array( 'src' => 'js/plugins/jquery.wikiEditor.highlight.js', 'version' => 53 ),
7878 array( 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', 'version' => 59 ),
7979 array( 'src' => 'js/plugins/jquery.wikiEditor.dialogs.js', 'version' => 24 ),
8080 array( 'src' => 'js/plugins/jquery.wikiEditor.toc.js', 'version' => 98 ),
8181 array( 'src' => 'js/plugins/jquery.wikiEditor.preview.js', 'version' => 11 ),
8282 array( 'src' => 'js/plugins/jquery.wikiEditor.templateEditor.js', 'version' => 77 ),
 83+ array( 'src' => 'js/plugins/jquery.wikiEditor.templates.js', 'version' => 1 ),
8384 array( 'src' => 'js/plugins/jquery.wikiEditor.publish.js', 'version' => 5 ),
8485 ),
8586 'combined' => array(
86 - array( 'src' => 'js/plugins.combined.js', 'version' => 388 ),
 87+ array( 'src' => 'js/plugins.combined.js', 'version' => 389 ),
8788 ),
8889 'minified' => array(
89 - array( 'src' => 'js/plugins.combined.min.js', 'version' => 388 ),
 90+ array( 'src' => 'js/plugins.combined.min.js', 'version' => 389 ),
9091 ),
9192 ),
9293 );
Index: trunk/extensions/UsabilityInitiative/WikiEditor/WikiEditor.php
@@ -27,6 +27,7 @@
2828 'publish' => array( 'global' => false, 'user' => true ),
2929 'toc' => array( 'global' => false, 'user' => true ),
3030 'templateEditor' => array( 'global' => false, 'user' => true ),
 31+ 'templates' => array( 'global' => false, 'user' => true ),
3132 'addMediaWizard' => array( 'global' => false, 'user' => false ),
3233 );
3334
@@ -59,6 +60,7 @@
6061 $wgExtensionMessagesFiles['WikiEditorToc'] = dirname( __FILE__ ) . '/Modules/Toc/Toc.i18n.php';
6162 $wgExtensionMessagesFiles['WikiEditorToolbar'] = dirname( __FILE__ ) . '/Modules/Toolbar/Toolbar.i18n.php';
6263 $wgExtensionMessagesFiles['WikiEditorTemplateEditor'] = dirname( __FILE__ ) . '/Modules/TemplateEditor/TemplateEditor.i18n.php';
 64+$wgExtensionMessagesFiles['WikiEditorTemplates'] = dirname( __FILE__ ) . '/Modules/Templates/Templates.i18n.php';
6365 $wgExtensionMessagesFiles['WikiEditorAddMediaWizard'] = dirname( __FILE__ ) . '/Modules/AddMediaWizard/AddMediaWizard.i18n.php';
6466
6567 // Register Hooks
Index: trunk/extensions/UsabilityInitiative/WikiEditor/WikiEditor.hooks.php
@@ -18,6 +18,7 @@
1919 array( 'src' => 'Modules/Toc/Toc.js', 'version' => 7 ),
2020 array( 'src' => 'Modules/Toolbar/Toolbar.js', 'version' => 83 ),
2121 array( 'src' => 'Modules/TemplateEditor/TemplateEditor.js', 'version' => 6 ),
 22+ array( 'src' => 'Modules/Templates/Templates.js', 'version' => 1 ),
2223 array( 'src' => 'Modules/AddMediaWizard/AddMediaWizard.js', 'version' => 6 ),
2324 ),
2425 'combined' => array(
@@ -68,6 +69,19 @@
6970 'wikieditor-template-editor-dialog-cancel',
7071 ),
7172 ),
 73+ 'templates' => array(
 74+ 'i18n' => 'WikiEditorTemplates',
 75+ 'preferences' => array(
 76+ 'enable' => array(
 77+ 'key' => 'wikieditor-templates',
 78+ 'ui' => array(
 79+ 'type' => 'toggle',
 80+ 'label-message' => 'wikieditor-templates-preference',
 81+ 'section' => 'editing/labs',
 82+ ),
 83+ ),
 84+ ),
 85+ ),
7286 'addMediaWizard' => array(
7387 'i18n' => 'addMediaWizard',
7488 'preferences' => array(
Index: trunk/extensions/UsabilityInitiative/WikiEditor/Modules/Templates/Templates.i18n.php
@@ -0,0 +1,16 @@
 2+<?php
 3+/**
 4+ * Internationalisation for the Highlight module of the Usability Initiative wikiEditor extension
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+$messages = array();
 11+
 12+/** English
 13+ * @author Trevor Parscal
 14+ */
 15+$messages['en'] = array(
 16+ 'wikieditor-templates-preference' => 'Enable template collapsing',
 17+);
Property changes on: trunk/extensions/UsabilityInitiative/WikiEditor/Modules/Templates/Templates.i18n.php
___________________________________________________________________
Name: svn:eol-style
118 + native
Index: trunk/extensions/UsabilityInitiative/WikiEditor/Modules/Templates/Templates.js
@@ -0,0 +1,16 @@
 2+/* JavaScript for WikiEditor Templates module */
 3+
 4+$j(document).ready( function() {
 5+ // Check preferences for templateEditor
 6+ if ( !wgWikiEditorEnabledModules.templates ) {
 7+ return true;
 8+ }
 9+ // Disable for template namespace
 10+ if ( wgNamespaceNumber == 10 ) {
 11+ return true;
 12+ }
 13+ // Add the templateEditor module
 14+ if ( $j.fn.wikiEditor ) {
 15+ $j( 'textarea#wpTextbox1' ).wikiEditor( 'addModule', 'templates' );
 16+ }
 17+});
Property changes on: trunk/extensions/UsabilityInitiative/WikiEditor/Modules/Templates/Templates.js
___________________________________________________________________
Name: svn:eol-style
118 + native
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html
@@ -37,15 +37,25 @@
3838 margin: 0;
3939 padding: 0;
4040 }
41 - /* Wikitext that's folded away and shouldn't be displayed */
42 -
43 - .wikiEditor-template-text-shrunken{
 41+ /* General WikiEditor stuff */
 42+ .wikiEditor-nodisplay {
 43+ display: none !important;
 44+ }
 45+ .wikiEditor-tab {
 46+ padding-left: 4em;
 47+ }
 48+ /* WikiEditor Templates */
 49+ .wikiEditor-templates .wikiEditor-template {
 50+ color: silver;
 51+ }
 52+ /* WikiEditor TemplateEditor */
 53+ .wikiEditor-templateEditor .wikiEditor-template-text-shrunken{
4454 height: 1px !important;
4555 width: 1px !important;
4656 overflow: hidden;
4757 float: right;
4858 }
49 - .wikiEditor-template-text-visible{
 59+ .wikiEditor-templateEditor .wikiEditor-template-text-visible{
5060 padding: 0.5em 4px;
5161 padding-top: 1.25em;
5262 margin-top: -0.95em;
@@ -54,19 +64,11 @@
5565 width: 100%;
5666 border-bottom: solid 1px #cccccc;
5767 }
58 -
59 - .wikiEditor-nodisplay {
60 - display: none !important;
61 - }
62 - .wikiEditor-tab {
63 - padding-left: 4em;
64 - }
65 - /* A collapsed template */
66 - .wikiEditor-template {
 68+ .wikiEditor-templateEditor .wikiEditor-template {
6769 display: inline-block;
6870 font-size: 12px;
6971 }
70 - .wikiEditor-template-name {
 72+ .wikiEditor-templateEditor .wikiEditor-template-name {
7173 cursor: pointer;
7274 vertical-align: -2px;
7375 display: inline-block;
@@ -75,15 +77,13 @@
7678 margin-right: 2px;
7779 overflow: hidden;
7880 background: url( '../../images/wikiEditor/templateEditor/name-base.png' ) 0 0 repeat-x #e8e8e8;
79 - /* color: #0645ad; */
80 - /* font-family: sans-serif; */
8181 color: #000000;
8282 font-family: monospace;
8383 text-decoration: none;
8484 padding-left: 0.33em;
8585 line-height: 16px;
8686 }
87 - .wikiEditor-template-expand {
 87+ .wikiEditor-templateEditor .wikiEditor-template-expand {
8888 cursor: pointer;
8989 vertical-align: -2px;
9090 display: inline-block;
@@ -93,49 +93,42 @@
9494 line-height: 16px;
9595 overflow: hidden;
9696 width: 13px;
97 - background-position: 50%; /*FF3*/
 97+ background-position: 50%;
9898 }
99 - .wikiEditor-template-dialog {
 99+ .wikiEditor-templateEditor .wikiEditor-template-dialog {
100100 cursor: pointer;
101 - vertical-align: -18%; /* This arbitrary value because straight up px evaluate differently between win and mac FF apparently */
 101+ vertical-align: -18%;
102102 display: inline-block;
103103 height: 16px;
104104 overflow: hidden;
105105 width: 22px;
106 - background-position: 50%; /*FF3*/
 106+ background-position: 50%;
107107 }
108 - .wikiEditor-template-name:hover {
 108+ .wikiEditor-templateEditor .wikiEditor-template-name:hover {
109109 text-decoration: underline;
110110 }
111 - .wikiEditor-template-expanded .wikiEditor-template-expand {
 111+ .wikiEditor-templateEditor .wikiEditor-template-expanded .wikiEditor-template-expand {
112112 background-image: url(../../images/wikiEditor/templateEditor/collapse.png);
113113 }
114 - .wikiEditor-template-expanded .wikiEditor-template-dialog {
 114+ .wikiEditor-templateEditor .wikiEditor-template-expanded .wikiEditor-template-dialog {
115115 background-image: url(../../images/wikiEditor/templateEditor/dialog-expanded.png);
116116 }
117 - .wikiEditor-template-collapsed .wikiEditor-template-expand {
 117+ .wikiEditor-templateEditor .wikiEditor-template-collapsed .wikiEditor-template-expand {
118118 background-image: url(../../images/wikiEditor/templateEditor/expand.png);
119119 }
120 - .wikiEditor-template-collapsed .wikiEditor-template-dialog {
 120+ .wikiEditor-templateEditor .wikiEditor-template-collapsed .wikiEditor-template-dialog {
121121 background-image: url(../../images/wikiEditor/templateEditor/dialog-collapsed.png);
122122 }
123 - /* An expanded template */
124 - .wikiEditor-template-expanded {
 123+ .wikiEditor-templateEditor .wikiEditor-template-expanded {
125124 display: block;
126125 }
127 - .wikiEditor-template .wikiEditor-template-text {
 126+ .wikiEditor-templateEditor .wikiEditor-template .wikiEditor-template-text {
128127
129128 }
130 - .wikiEditor-template-end, .wikiEditor-template-start {
 129+ .wikiEditor-templateEditor .wikiEditor-template-end, .wikiEditor-template-start {
131130 color: blue;
132131 cursor: pointer;
133132 }
134 - /* == Header == */
135 - .wikiEditor-toc-header {
136 - /* Fix for Webkit Browsers resistence to give these elements an offsetTop value */
137 - /*display: -webkit-box; -- presumably not needed now that this is a <p> without display: inline; */
138 - /*font-weight: bold; -- not sure about this styling just yet */
139 - }
140133 </style>
141134 </head>
142135 <body></body>
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.templates.js
@@ -0,0 +1,69 @@
 2+/* Templates Module for wikiEditor */
 3+( function( $ ) { $.wikiEditor.modules.templates = {
 4+
 5+/**
 6+ * Core Requirements
 7+ */
 8+'req': [ 'iframe' ],
 9+/**
 10+ * Object Templates
 11+ */
 12+'tpl': {
 13+ 'marker': {
 14+ 'type': 'template',
 15+ 'anchor': 'wrap',
 16+ 'skipDivision': 'realchange',
 17+ 'afterWrap': function( node ) {
 18+ $( node ).addClass( 'wikiEditor-template' );
 19+ },
 20+ 'getAnchor': function( ca1, ca2 ) {
 21+ return $( ca1.parentNode ).is( '.wikiEditor-template' ) ? ca1.parentNode : null;
 22+ }
 23+ }
 24+},
 25+/**
 26+ * Event handlers
 27+ */
 28+'evt': {
 29+ 'mark': function( context, event ) {
 30+ // The markers returned by this function are skipped on realchange, so don't regenerate them in that case
 31+ if ( context.modules.highlight.currentScope == 'realchange' ) {
 32+ return;
 33+ }
 34+ // Get references to the markers and tokens from the current context
 35+ var markers = context.modules.highlight.markers;
 36+ var tokens = context.modules.highlight.tokenArray;
 37+ // Use depth-tracking to extract top-level templates from tokens
 38+ var depth = 0, bias, start;
 39+ for ( i in tokens ) {
 40+ depth += bias = tokens[i].label == 'TEMPLATE_BEGIN' ? 1 : tokens[i].label == 'TEMPLATE_END' ? -1 : 0;
 41+ if ( bias > 0 && depth == 1 ) {
 42+ // Top-level opening - use offset as start
 43+ start = tokens[i].offset;
 44+ } else if ( bias < 0 && depth == 0 ) {
 45+ // Top-level closing - use offset as end
 46+ markers[markers.length] = $.extend(
 47+ { 'context': context, 'start': start, 'end': tokens[i].offset },
 48+ $.wikiEditor.modules.templates.tpl.marker
 49+ );
 50+ }
 51+ if ( depth < 0 ) {
 52+ depth = 0;
 53+ }
 54+ }
 55+ }
 56+},
 57+'exp': [
 58+ { 'regex': /{{/, 'label': "TEMPLATE_BEGIN" },
 59+ { 'regex': /}}/, 'label': "TEMPLATE_END", 'markAfter': true }
 60+],
 61+/**
 62+ * Internally used functions
 63+ */
 64+'fn': {
 65+ 'create': function( context, config ) {
 66+ // Do some stuff here...
 67+ }
 68+}
 69+
 70+}; } ) ( jQuery );
Property changes on: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.templates.js
___________________________________________________________________
Name: svn:eol-style
171 + native
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js
@@ -1057,6 +1057,10 @@
10581058 }
10591059 // Get a reference to the content area of the iframe
10601060 context.$content = $( context.$iframe[0].contentWindow.document.body );
 1061+ // Add classes to the body to influence the styles based on what's enabled
 1062+ for ( module in context.modules ) {
 1063+ context.$content.addClass( 'wikiEditor-' + module );
 1064+ }
10611065 // If we just do "context.$content.text( context.$textarea.val() )", Internet Explorer will strip
10621066 // out the whitespace charcters, specifically "\n" - so we must manually encode text and append it
10631067 // TODO: Refactor this into a textToHtml() function
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js
@@ -1,4 +1,5 @@
22 /* Highlight module for wikiEditor */
 3+
34 ( function( $ ) { $.wikiEditor.modules.highlight = {
45
56 /**
@@ -8,139 +9,73 @@
910 /**
1011 * Configuration
1112 */
12 -cfg: {
 13+'cfg': {
1314 'styleVersion': 3
1415 },
1516 /**
1617 * Internally used event handlers
1718 */
18 -evt: {
19 - delayedChange: function( context, event ) {
20 - /*
21 - * Triggered on any of the following events, with the intent on detecting if something was added, deleted or
22 - * replaced due to user action.
23 - *
24 - * The following conditions are indicative that one or more divisions need to be re-scanned/marked:
25 - * Keypress while something is highlighted
26 - * Cut
27 - * Paste
28 - * Drag+drop selected text
29 - * The following conditions are indicative that special handlers need to be consulted to properly parse content
30 - * Keypress with any of the following characters
31 - * } Template or Table handler
32 - * > Tag handler
33 - * ] Link handler
34 - * The following conditions are indicative that divisions might be being made which would need encapsulation
35 - * Keypress with any of the following characters
36 - * = Heading
37 - * # Ordered
38 - * * Unordered
39 - * ; Definition
40 - * : Definition
41 - */
42 - $.wikiEditor.modules.highlight.currentScope = event.data.scope;
 19+'evt': {
 20+ 'delayedChange': function( context, event ) {
4321 if ( event.data.scope == 'realchange' ) {
44 - $.wikiEditor.modules.highlight.fn.scan( context, '' );
45 - $.wikiEditor.modules.highlight.fn.mark( context, 'realchange', '' );
 22+ $.wikiEditor.modules.highlight.fn.scan( context );
 23+ $.wikiEditor.modules.highlight.fn.mark( context, event.data.scope );
4624 }
4725 },
48 - ready: function( context, event ) {
49 - // Highlight stuff for the first time
50 - $.wikiEditor.modules.highlight.currentScope = 'ready'; // FIXME: Ugly global, kill with fire
51 - $.wikiEditor.modules.highlight.fn.scan( context, '' );
52 - $.wikiEditor.modules.highlight.fn.mark( context, '', '' );
 26+ 'ready': function( context, event ) {
 27+ $.wikiEditor.modules.highlight.fn.scan( context );
 28+ $.wikiEditor.modules.highlight.fn.mark( context, 'ready' );
5329 }
5430 },
5531 /**
5632 * Internally used functions
5733 */
58 -fn: {
 34+'fn': {
5935 /**
6036 * Creates a highlight module within a wikiEditor
6137 *
6238 * @param config Configuration object to create module from
6339 */
64 - create: function( context, config ) {
 40+ 'create': function( context, config ) {
6541 context.modules.highlight.markersStr = '';
6642 },
6743 /**
68 - * Divides text into divisions
69 - */
70 - divide: function( context ) {
71 - /*
72 - * We need to add some markup to the iframe content to encapsulate divisions
73 - */
74 - },
75 - /**
76 - * Isolates division which was affected by most recent change
77 - */
78 - isolate: function( context ) {
79 - /*
80 - * A change just occured, and we need to know which sections were affected
81 - */
82 - return []; // array of sections?
83 - },
84 - /**
85 - * Strips division of HTML
86 - * FIXME: Isn't this done by context.fn.htmlToText() already?
87 - *
88 - * @param division
89 - */
90 - strip: function( context, division ) {
91 - return $( '<div />' ).html( division.html().replace( /\<br[^\>]*\>/g, "\n" ) ).text();
92 - },
93 - /**
9444 * Scans text division for tokens
9545 *
9646 * @param division
9747 */
98 - scan: function( context, division ) {
99 - /**
100 - * Builds a Token object
101 - *
102 - * @param offset
103 - * @param label
104 - */
105 - function Token( offset, label, tokenStart, match ) {
106 - this.offset = offset;
107 - this.label = label;
108 - this.tokenStart = tokenStart;
109 - this.match = match;
110 - }
111 - // Reset tokens
 48+ 'scan': function( context, division ) {
 49+ // Remove all existing tokens
11250 var tokenArray = context.modules.highlight.tokenArray = [];
113 - // We need to look over some text and find interesting areas, then return the positions of those areas as tokens
 51+ // Scan text for new tokens
11452 var text = context.fn.getContents();
 53+ // Perform a scan for each module which provides any expressions to scan for
11554 for ( module in context.modules ) {
11655 if ( module in $.wikiEditor.modules && 'exp' in $.wikiEditor.modules[module] ) {
117 - for ( var i = 0; i < $.wikiEditor.modules[module].exp.length; i++ ) {
118 - var regex = $.wikiEditor.modules[module].exp[i].regex;
119 - var label = $.wikiEditor.modules[module].exp[i].label;
120 - var markAfter = false;
121 - if ( typeof $.wikiEditor.modules[module].exp[i].markAfter != 'undefined' ) {
122 - markAfter = true;
 56+ for ( exp in $.wikiEditor.modules[module].exp ) {
 57+ // Prepare configuration
 58+ var regex = $.wikiEditor.modules[module].exp[exp].regex;
 59+ var label = $.wikiEditor.modules[module].exp[exp].label;
 60+ var markAfter = ( typeof $.wikiEditor.modules[module].exp[exp].markAfter != 'undefined' );
 61+ // Search for tokens
 62+ var offset = 0, left, right;
 63+ while ( ( match = text.substr( offset ).match( regex ) ) != null ) {
 64+ right = ( left = offset + match.index ) + match[0].length;
 65+ tokenArray[tokenArray.length] = {
 66+ 'offset': markAfter ? right : left,
 67+ 'label': label,
 68+ 'tokenStart': left,
 69+ 'match': match
 70+ };
 71+ // Move to the right of this match
 72+ offset = right;
12373 }
124 - match = text.match( regex );
125 - var oldOffset = 0;
126 - while ( match != null ) {
127 - var markOffset = 0;
128 - var tokenStart = match.index + oldOffset + markOffset;
129 - if ( markAfter ) {
130 - markOffset += match[0].length;
131 - }
132 - tokenArray.push( new Token( match.index + oldOffset + markOffset,
133 - label, tokenStart, match ) );
134 - oldOffset += match.index + match[0].length;
135 - newSubstring = text.substring( oldOffset );
136 - match = newSubstring.match( regex );
137 - }
13874 }
13975 }
14076 }
141 - //sort by offset, or if offset same, sort by start
142 - tokenArray.sort( function( a, b ) {
143 - return a.offset - b.offset || a.tokenStart - b.tokenStart;
144 - } );
 77+ // Sort by start
 78+ tokenArray.sort( function( a, b ) { return a.tokenStart - b.tokenStart; } );
 79+ // Let the world know, a scan just happend!
14580 context.fn.trigger( 'scan' );
14681 },
14782 /**
@@ -151,7 +86,7 @@
15287 */
15388 // FIXME: What do division and tokens do?
15489 // TODO: Document the scan() and mark() APIs somewhere
155 - mark: function( context, division, tokens ) {
 90+ 'mark': function( context, division, tokens ) {
15691 // Reset markers
15792 var markers = [];
15893
@@ -169,8 +104,8 @@
170105 context.fn.trigger( 'mark' );
171106 markers.sort( function( a, b ) { return a.start - b.start || a.end - b.end; } );
172107
173 - // Serialize the markers array to a string and compare it with the one stored in the previous run
174 - // If they're equal, there's no markers to change
 108+ // Serialize the markers array to a string and compare it with the one stored in the previous run - if they're
 109+ // equal, there's no markers to change
175110 var markersStr = '';
176111 for ( var i = 0; i < markers.length; i++ ) {
177112 markersStr += markers[i].start + ',' + markers[i].end + ',' + markers[i].type + ',';
@@ -181,16 +116,15 @@
182117 }
183118 context.modules.highlight.markersStr = markersStr;
184119
185 - // Traverse the iframe DOM, inserting markers where they're needed.
186 - // Store visited markers here so we know which markers should be removed
 120+ // Traverse the iframe DOM, inserting markers where they're needed - store visited markers here so we know which
 121+ // markers should be removed
187122 var visited = [], v = 0;
188123 for ( var i = 0; i < markers.length; i++ ) {
189124 if ( typeof markers[i].skipDivision !== 'undefined' && ( division == markers[i].skipDivision ) ) {
190125 continue;
191126 }
192127
193 - // We want to isolate each marker, so we may need to split textNodes
194 - // if a marker starts or ends halfway one.
 128+ // We want to isolate each marker, so we may need to split textNodes if a marker starts or ends halfway one.
195129 var start = markers[i].start;
196130 var s = context.fn.getOffset( start );
197131 if ( !s ) {
@@ -200,9 +134,9 @@
201135 var startNode = s.node;
202136
203137 // Don't wrap leading BRs, produces undesirable results
204 - // FIXME: It's also possible that the offset is a bit high because getOffset() has incremented
205 - // .length to fake the newline caused by startNode being in a P. In this case, prevent
206 - // the textnode splitting below from making startNode an empty textnode, IE barfs on that
 138+ // FIXME: It's also possible that the offset is a bit high because getOffset() has incremented .length to
 139+ // fake the newline caused by startNode being in a P. In this case, prevent the textnode splitting below
 140+ // from making startNode an empty textnode, IE barfs on that
207141 while ( startNode.nodeName == 'BR' || s.offset == startNode.nodeValue.length ) {
208142 start++;
209143 s = context.fn.getOffset( start );
@@ -211,20 +145,17 @@
212146
213147 // The next marker starts somewhere in this textNode or at this BR
214148 if ( s.offset > 0 && s.node.nodeName == '#text' ) {
215 - // Split off the prefix
216 - // This leaves the prefix in the current node and puts
217 - // the rest in a new node which is our start node
 149+ // Split off the prefix - this leaves the prefix in the current node and puts the rest in a new node
 150+ // which is our start node
218151 var newStartNode = startNode.splitText( s.offset < s.node.nodeValue.length ?
219152 s.offset : s.node.nodeValue.length - 1
220153 );
221154 var oldStartNode = startNode;
222155 startNode = newStartNode;
223 -
224 - // Update offset objects. We don't need purgeOffsets(), simply
225 - // manipulating the existing offset objects will suffice
226 - // FIXME: This manipulates context.offsets directly, which is ugly,
227 - // but the performance improvement vs. purgeOffsets() is worth it
228 - // This code doesn't set lastTextNode to newStartNode for offset objects
 156+ // Update offset objects. We don't need purgeOffsets(), simply manipulating the existing offset objects
 157+ // will suffice
 158+ // FIXME: This manipulates context.offsets directly, which is ugly, but the performance improvement vs.
 159+ // purgeOffsets() is worth it - this code doesn't set lastTextNode to newStartNode for offset objects
229160 // with lastTextNode == oldStartNode, but that doesn't really matter
230161 var subtracted = s.offset;
231162 var oldLength = s.length;
@@ -249,10 +180,9 @@
250181 }
251182 }
252183 }
253 -
254184 var end = markers[i].end;
255 - // To avoid ending up at the first char of the next node, we grab the offset for end - 1
256 - // and add one to the offset
 185+ // To avoid ending up at the first char of the next node, we grab the offset for end - 1 and add one to the
 186+ // offset
257187 var e = context.fn.getOffset( end - 1 );
258188 if ( !e ) {
259189 // This shouldn't happen
@@ -263,11 +193,9 @@
264194 // Split off the suffix. This puts the suffix in a new node and leaves the rest in endNode
265195 var oldEndNode = endNode;
266196 var newEndNode = endNode.splitText( e.offset + 1 );
267 -
268197 // Update offset objects
269198 var subtracted = e.offset + 1;
270199 var oldLength = e.length;
271 -
272200 var j, o;
273201 // Update offset objects referring to oldEndNode
274202 for ( j = end - subtracted; j < end; j++ ) {
@@ -295,12 +223,10 @@
296224 }
297225 }
298226 }
299 -
300227 // Don't wrap trailing BRs, doing that causes weird issues
301228 if ( endNode.nodeName == 'BR' ) {
302229 endNode = e.lastTextNode;
303230 }
304 -
305231 // If startNode and endNode have different parents, we need to pull endNode and all textnodes in between
306232 // into startNode's parent and replace </p><p> with <br>
307233 if ( startNode.parentNode != endNode.parentNode ) {
@@ -354,7 +280,6 @@
355281 // TODO: Update offset objects ourselves for performance. Requires rewriting this code block to be
356282 // offset-based rather than traverser-based
357283 }
358 -
359284 // Now wrap everything between startNode and endNode (may be equal).
360285 var ca1 = startNode, ca2 = endNode;
361286 if ( ca1 && ca2 && ca1.parentNode ) {
@@ -362,11 +287,8 @@
363288 if ( !anchor ) {
364289 var commonAncestor = ca1.parentNode;
365290 if ( markers[i].anchor == 'wrap') {
366 - // We have to store things like .parentNode and .nextSibling because
367 - // appendChild() changes these properties
368 -
 291+ // We have to store things like .parentNode and .nextSibling because appendChild() changes these
369292 var newNode = ca1.ownerDocument.createElement( 'span' );
370 -
371293 var nextNode = ca2.nextSibling;
372294 // Append all nodes between ca1 and ca2 (inclusive) to newNode
373295 var n = ca1;
@@ -376,34 +298,31 @@
377299 n = ns;
378300 }
379301 // Insert newNode in the right place
380 -
381302 if ( nextNode ) {
382303 commonAncestor.insertBefore( newNode, nextNode );
383304 } else {
384305 commonAncestor.appendChild( newNode );
385306 }
386 -
387307 anchor = newNode;
388308 } else if ( markers[i].anchor == 'tag' ) {
389309 anchor = commonAncestor;
390310 }
391 - $( anchor ).data( 'marker', markers[i] )
392 - .addClass( 'wikiEditor-highlight' );
 311+ $( anchor ).data( 'marker', markers[i] ).addClass( 'wikiEditor-highlight' );
393312 // Allow the module adding this marker to manipulate it
394313 markers[i].afterWrap( anchor, markers[i] );
395314
396315 } else {
397316 // Update the marker object
398317 $( anchor ).data( 'marker', markers[i] );
399 - markers[i].onSkip( anchor );
 318+ if ( typeof markers[i].onSkip == 'function' ) {
 319+ markers[i].onSkip( anchor );
 320+ }
400321 }
401322 visited[v++] = anchor;
402323 }
403324 }
404 -
405 - // Remove markers that were previously inserted but weren't passed to this function
406 - // This function works because visited[] contains the visited elements in order and find() and each()
407 - // preserve order
 325+ // Remove markers that were previously inserted but weren't passed to this function - visited[] contains the
 326+ // visited elements in order and find() and each() preserve order
408327 var j = 0;
409328 context.$content.find( '.wikiEditor-highlight' ).each( function() {
410329 if ( visited[j] == this ) {
@@ -411,7 +330,6 @@
412331 j++;
413332 return true;
414333 }
415 -
416334 // Remove this marker
417335 var marker = $(this).data( 'marker' );
418336 if ( marker && typeof marker.skipDivision != 'undefined' && ( division == marker.skipDivision ) ) {
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.js
@@ -7642,6 +7642,10 @@
76437643 }
76447644 // Get a reference to the content area of the iframe
76457645 context.$content = $( context.$iframe[0].contentWindow.document.body );
 7646+ // Add classes to the body to influence the styles based on what's enabled
 7647+ for ( module in context.modules ) {
 7648+ context.$content.addClass( 'wikiEditor-' + module );
 7649+ }
76467650 // If we just do "context.$content.text( context.$textarea.val() )", Internet Explorer will strip
76477651 // out the whitespace charcters, specifically "\n" - so we must manually encode text and append it
76487652 // TODO: Refactor this into a textToHtml() function
@@ -8610,6 +8614,7 @@
86118615
86128616 }; } ) ( jQuery );
86138617 /* Highlight module for wikiEditor */
 8618+
86148619 ( function( $ ) { $.wikiEditor.modules.highlight = {
86158620
86168621 /**
@@ -8619,139 +8624,73 @@
86208625 /**
86218626 * Configuration
86228627 */
8623 -cfg: {
 8628+'cfg': {
86248629 'styleVersion': 3
86258630 },
86268631 /**
86278632 * Internally used event handlers
86288633 */
8629 -evt: {
8630 - delayedChange: function( context, event ) {
8631 - /*
8632 - * Triggered on any of the following events, with the intent on detecting if something was added, deleted or
8633 - * replaced due to user action.
8634 - *
8635 - * The following conditions are indicative that one or more divisions need to be re-scanned/marked:
8636 - * Keypress while something is highlighted
8637 - * Cut
8638 - * Paste
8639 - * Drag+drop selected text
8640 - * The following conditions are indicative that special handlers need to be consulted to properly parse content
8641 - * Keypress with any of the following characters
8642 - * } Template or Table handler
8643 - * > Tag handler
8644 - * ] Link handler
8645 - * The following conditions are indicative that divisions might be being made which would need encapsulation
8646 - * Keypress with any of the following characters
8647 - * = Heading
8648 - * # Ordered
8649 - * * Unordered
8650 - * ; Definition
8651 - * : Definition
8652 - */
8653 - $.wikiEditor.modules.highlight.currentScope = event.data.scope;
 8634+'evt': {
 8635+ 'delayedChange': function( context, event ) {
86548636 if ( event.data.scope == 'realchange' ) {
8655 - $.wikiEditor.modules.highlight.fn.scan( context, '' );
8656 - $.wikiEditor.modules.highlight.fn.mark( context, 'realchange', '' );
 8637+ $.wikiEditor.modules.highlight.fn.scan( context );
 8638+ $.wikiEditor.modules.highlight.fn.mark( context, event.data.scope );
86578639 }
86588640 },
8659 - ready: function( context, event ) {
8660 - // Highlight stuff for the first time
8661 - $.wikiEditor.modules.highlight.currentScope = 'ready'; // FIXME: Ugly global, kill with fire
8662 - $.wikiEditor.modules.highlight.fn.scan( context, '' );
8663 - $.wikiEditor.modules.highlight.fn.mark( context, '', '' );
 8641+ 'ready': function( context, event ) {
 8642+ $.wikiEditor.modules.highlight.fn.scan( context );
 8643+ $.wikiEditor.modules.highlight.fn.mark( context, 'ready' );
86648644 }
86658645 },
86668646 /**
86678647 * Internally used functions
86688648 */
8669 -fn: {
 8649+'fn': {
86708650 /**
86718651 * Creates a highlight module within a wikiEditor
86728652 *
86738653 * @param config Configuration object to create module from
86748654 */
8675 - create: function( context, config ) {
 8655+ 'create': function( context, config ) {
86768656 context.modules.highlight.markersStr = '';
86778657 },
86788658 /**
8679 - * Divides text into divisions
8680 - */
8681 - divide: function( context ) {
8682 - /*
8683 - * We need to add some markup to the iframe content to encapsulate divisions
8684 - */
8685 - },
8686 - /**
8687 - * Isolates division which was affected by most recent change
8688 - */
8689 - isolate: function( context ) {
8690 - /*
8691 - * A change just occured, and we need to know which sections were affected
8692 - */
8693 - return []; // array of sections?
8694 - },
8695 - /**
8696 - * Strips division of HTML
8697 - * FIXME: Isn't this done by context.fn.htmlToText() already?
8698 - *
8699 - * @param division
8700 - */
8701 - strip: function( context, division ) {
8702 - return $( '<div />' ).html( division.html().replace( /\<br[^\>]*\>/g, "\n" ) ).text();
8703 - },
8704 - /**
87058659 * Scans text division for tokens
87068660 *
87078661 * @param division
87088662 */
8709 - scan: function( context, division ) {
8710 - /**
8711 - * Builds a Token object
8712 - *
8713 - * @param offset
8714 - * @param label
8715 - */
8716 - function Token( offset, label, tokenStart, match ) {
8717 - this.offset = offset;
8718 - this.label = label;
8719 - this.tokenStart = tokenStart;
8720 - this.match = match;
8721 - }
8722 - // Reset tokens
 8663+ 'scan': function( context, division ) {
 8664+ // Remove all existing tokens
87238665 var tokenArray = context.modules.highlight.tokenArray = [];
8724 - // We need to look over some text and find interesting areas, then return the positions of those areas as tokens
 8666+ // Scan text for new tokens
87258667 var text = context.fn.getContents();
 8668+ // Perform a scan for each module which provides any expressions to scan for
87268669 for ( module in context.modules ) {
87278670 if ( module in $.wikiEditor.modules && 'exp' in $.wikiEditor.modules[module] ) {
8728 - for ( var i = 0; i < $.wikiEditor.modules[module].exp.length; i++ ) {
8729 - var regex = $.wikiEditor.modules[module].exp[i].regex;
8730 - var label = $.wikiEditor.modules[module].exp[i].label;
8731 - var markAfter = false;
8732 - if ( typeof $.wikiEditor.modules[module].exp[i].markAfter != 'undefined' ) {
8733 - markAfter = true;
 8671+ for ( exp in $.wikiEditor.modules[module].exp ) {
 8672+ // Prepare configuration
 8673+ var regex = $.wikiEditor.modules[module].exp[exp].regex;
 8674+ var label = $.wikiEditor.modules[module].exp[exp].label;
 8675+ var markAfter = ( typeof $.wikiEditor.modules[module].exp[exp].markAfter != 'undefined' );
 8676+ // Search for tokens
 8677+ var offset = 0, left, right;
 8678+ while ( ( match = text.substr( offset ).match( regex ) ) != null ) {
 8679+ right = ( left = offset + match.index ) + match[0].length;
 8680+ tokenArray[tokenArray.length] = {
 8681+ 'offset': markAfter ? right : left,
 8682+ 'label': label,
 8683+ 'tokenStart': left,
 8684+ 'match': match
 8685+ };
 8686+ // Move to the right of this match
 8687+ offset = right;
87348688 }
8735 - match = text.match( regex );
8736 - var oldOffset = 0;
8737 - while ( match != null ) {
8738 - var markOffset = 0;
8739 - var tokenStart = match.index + oldOffset + markOffset;
8740 - if ( markAfter ) {
8741 - markOffset += match[0].length;
8742 - }
8743 - tokenArray.push( new Token( match.index + oldOffset + markOffset,
8744 - label, tokenStart, match ) );
8745 - oldOffset += match.index + match[0].length;
8746 - newSubstring = text.substring( oldOffset );
8747 - match = newSubstring.match( regex );
8748 - }
87498689 }
87508690 }
87518691 }
8752 - //sort by offset, or if offset same, sort by start
8753 - tokenArray.sort( function( a, b ) {
8754 - return a.offset - b.offset || a.tokenStart - b.tokenStart;
8755 - } );
 8692+ // Sort by start
 8693+ tokenArray.sort( function( a, b ) { return a.tokenStart - b.tokenStart; } );
 8694+ // Let the world know, a scan just happend!
87568695 context.fn.trigger( 'scan' );
87578696 },
87588697 /**
@@ -8762,7 +8701,7 @@
87638702 */
87648703 // FIXME: What do division and tokens do?
87658704 // TODO: Document the scan() and mark() APIs somewhere
8766 - mark: function( context, division, tokens ) {
 8705+ 'mark': function( context, division, tokens ) {
87678706 // Reset markers
87688707 var markers = [];
87698708
@@ -8780,8 +8719,8 @@
87818720 context.fn.trigger( 'mark' );
87828721 markers.sort( function( a, b ) { return a.start - b.start || a.end - b.end; } );
87838722
8784 - // Serialize the markers array to a string and compare it with the one stored in the previous run
8785 - // If they're equal, there's no markers to change
 8723+ // Serialize the markers array to a string and compare it with the one stored in the previous run - if they're
 8724+ // equal, there's no markers to change
87868725 var markersStr = '';
87878726 for ( var i = 0; i < markers.length; i++ ) {
87888727 markersStr += markers[i].start + ',' + markers[i].end + ',' + markers[i].type + ',';
@@ -8792,16 +8731,15 @@
87938732 }
87948733 context.modules.highlight.markersStr = markersStr;
87958734
8796 - // Traverse the iframe DOM, inserting markers where they're needed.
8797 - // Store visited markers here so we know which markers should be removed
 8735+ // Traverse the iframe DOM, inserting markers where they're needed - store visited markers here so we know which
 8736+ // markers should be removed
87988737 var visited = [], v = 0;
87998738 for ( var i = 0; i < markers.length; i++ ) {
88008739 if ( typeof markers[i].skipDivision !== 'undefined' && ( division == markers[i].skipDivision ) ) {
88018740 continue;
88028741 }
88038742
8804 - // We want to isolate each marker, so we may need to split textNodes
8805 - // if a marker starts or ends halfway one.
 8743+ // We want to isolate each marker, so we may need to split textNodes if a marker starts or ends halfway one.
88068744 var start = markers[i].start;
88078745 var s = context.fn.getOffset( start );
88088746 if ( !s ) {
@@ -8811,9 +8749,9 @@
88128750 var startNode = s.node;
88138751
88148752 // Don't wrap leading BRs, produces undesirable results
8815 - // FIXME: It's also possible that the offset is a bit high because getOffset() has incremented
8816 - // .length to fake the newline caused by startNode being in a P. In this case, prevent
8817 - // the textnode splitting below from making startNode an empty textnode, IE barfs on that
 8753+ // FIXME: It's also possible that the offset is a bit high because getOffset() has incremented .length to
 8754+ // fake the newline caused by startNode being in a P. In this case, prevent the textnode splitting below
 8755+ // from making startNode an empty textnode, IE barfs on that
88188756 while ( startNode.nodeName == 'BR' || s.offset == startNode.nodeValue.length ) {
88198757 start++;
88208758 s = context.fn.getOffset( start );
@@ -8822,20 +8760,17 @@
88238761
88248762 // The next marker starts somewhere in this textNode or at this BR
88258763 if ( s.offset > 0 && s.node.nodeName == '#text' ) {
8826 - // Split off the prefix
8827 - // This leaves the prefix in the current node and puts
8828 - // the rest in a new node which is our start node
 8764+ // Split off the prefix - this leaves the prefix in the current node and puts the rest in a new node
 8765+ // which is our start node
88298766 var newStartNode = startNode.splitText( s.offset < s.node.nodeValue.length ?
88308767 s.offset : s.node.nodeValue.length - 1
88318768 );
88328769 var oldStartNode = startNode;
88338770 startNode = newStartNode;
8834 -
8835 - // Update offset objects. We don't need purgeOffsets(), simply
8836 - // manipulating the existing offset objects will suffice
8837 - // FIXME: This manipulates context.offsets directly, which is ugly,
8838 - // but the performance improvement vs. purgeOffsets() is worth it
8839 - // This code doesn't set lastTextNode to newStartNode for offset objects
 8771+ // Update offset objects. We don't need purgeOffsets(), simply manipulating the existing offset objects
 8772+ // will suffice
 8773+ // FIXME: This manipulates context.offsets directly, which is ugly, but the performance improvement vs.
 8774+ // purgeOffsets() is worth it - this code doesn't set lastTextNode to newStartNode for offset objects
88408775 // with lastTextNode == oldStartNode, but that doesn't really matter
88418776 var subtracted = s.offset;
88428777 var oldLength = s.length;
@@ -8860,10 +8795,9 @@
88618796 }
88628797 }
88638798 }
8864 -
88658799 var end = markers[i].end;
8866 - // To avoid ending up at the first char of the next node, we grab the offset for end - 1
8867 - // and add one to the offset
 8800+ // To avoid ending up at the first char of the next node, we grab the offset for end - 1 and add one to the
 8801+ // offset
88688802 var e = context.fn.getOffset( end - 1 );
88698803 if ( !e ) {
88708804 // This shouldn't happen
@@ -8874,11 +8808,9 @@
88758809 // Split off the suffix. This puts the suffix in a new node and leaves the rest in endNode
88768810 var oldEndNode = endNode;
88778811 var newEndNode = endNode.splitText( e.offset + 1 );
8878 -
88798812 // Update offset objects
88808813 var subtracted = e.offset + 1;
88818814 var oldLength = e.length;
8882 -
88838815 var j, o;
88848816 // Update offset objects referring to oldEndNode
88858817 for ( j = end - subtracted; j < end; j++ ) {
@@ -8906,12 +8838,10 @@
89078839 }
89088840 }
89098841 }
8910 -
89118842 // Don't wrap trailing BRs, doing that causes weird issues
89128843 if ( endNode.nodeName == 'BR' ) {
89138844 endNode = e.lastTextNode;
89148845 }
8915 -
89168846 // If startNode and endNode have different parents, we need to pull endNode and all textnodes in between
89178847 // into startNode's parent and replace </p><p> with <br>
89188848 if ( startNode.parentNode != endNode.parentNode ) {
@@ -8965,7 +8895,6 @@
89668896 // TODO: Update offset objects ourselves for performance. Requires rewriting this code block to be
89678897 // offset-based rather than traverser-based
89688898 }
8969 -
89708899 // Now wrap everything between startNode and endNode (may be equal).
89718900 var ca1 = startNode, ca2 = endNode;
89728901 if ( ca1 && ca2 && ca1.parentNode ) {
@@ -8973,11 +8902,8 @@
89748903 if ( !anchor ) {
89758904 var commonAncestor = ca1.parentNode;
89768905 if ( markers[i].anchor == 'wrap') {
8977 - // We have to store things like .parentNode and .nextSibling because
8978 - // appendChild() changes these properties
8979 -
 8906+ // We have to store things like .parentNode and .nextSibling because appendChild() changes these
89808907 var newNode = ca1.ownerDocument.createElement( 'span' );
8981 -
89828908 var nextNode = ca2.nextSibling;
89838909 // Append all nodes between ca1 and ca2 (inclusive) to newNode
89848910 var n = ca1;
@@ -8987,34 +8913,31 @@
89888914 n = ns;
89898915 }
89908916 // Insert newNode in the right place
8991 -
89928917 if ( nextNode ) {
89938918 commonAncestor.insertBefore( newNode, nextNode );
89948919 } else {
89958920 commonAncestor.appendChild( newNode );
89968921 }
8997 -
89988922 anchor = newNode;
89998923 } else if ( markers[i].anchor == 'tag' ) {
90008924 anchor = commonAncestor;
90018925 }
9002 - $( anchor ).data( 'marker', markers[i] )
9003 - .addClass( 'wikiEditor-highlight' );
 8926+ $( anchor ).data( 'marker', markers[i] ).addClass( 'wikiEditor-highlight' );
90048927 // Allow the module adding this marker to manipulate it
90058928 markers[i].afterWrap( anchor, markers[i] );
90068929
90078930 } else {
90088931 // Update the marker object
90098932 $( anchor ).data( 'marker', markers[i] );
9010 - markers[i].onSkip( anchor );
 8933+ if ( typeof markers[i].onSkip == 'function' ) {
 8934+ markers[i].onSkip( anchor );
 8935+ }
90118936 }
90128937 visited[v++] = anchor;
90138938 }
90148939 }
9015 -
9016 - // Remove markers that were previously inserted but weren't passed to this function
9017 - // This function works because visited[] contains the visited elements in order and find() and each()
9018 - // preserve order
 8940+ // Remove markers that were previously inserted but weren't passed to this function - visited[] contains the
 8941+ // visited elements in order and find() and each() preserve order
90198942 var j = 0;
90208943 context.$content.find( '.wikiEditor-highlight' ).each( function() {
90218944 if ( visited[j] == this ) {
@@ -9022,7 +8945,6 @@
90238946 j++;
90248947 return true;
90258948 }
9026 -
90278949 // Remove this marker
90288950 var marker = $(this).data( 'marker' );
90298951 if ( marker && typeof marker.skipDivision != 'undefined' && ( division == marker.skipDivision ) ) {
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js
@@ -520,7 +520,8 @@
521521 context.savedSelection.select();context.savedSelection=null;},'updateHistory':function(htmlChange){var newHTML=context.$content.html();var newSel=context.fn.getCaretPosition();if(context.history.length==0||(htmlChange&&context.oldDelayedHistoryPosition==context.historyPosition)){context.oldDelayedSel=newSel;if(context.historyPosition<-1){context.history.splice(context.history.length+context.historyPosition+1);context.historyPosition=-1;}
522522 context.history.push({'html':newHTML,'sel':newSel});while(context.history.length>10){context.history.shift();}}else if(context.oldDelayedSel!=newSel){context.oldDelayedSel=newSel;context.history[context.history.length+context.historyPosition].sel=newSel;}
523523 context.oldDelayedHistoryPosition=context.historyPosition;},'setupIframe':function(){context.$iframe=$('<iframe></iframe>').attr({'frameBorder':0,'border':0,'tabindex':1,'src':wgScriptPath+'/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html?'+'instance='+context.instance+'&ts='+(new Date()).getTime()+'&is=content','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;}}
524 -context.$content=$(context.$iframe[0].contentWindow.document.body);var html=context.$textarea.val().replace(/&esc;/g,'&esc;esc;').replace(/\<p\>/g,'&esc;&lt;p&gt;').replace(/\<\/p\>/g,'&esc;&lt;/p&gt;').replace(/\<span class="wikiEditor-tab"\>\<\/span\>/g,'&esc;&lt;span&nbsp;class=&quot;wikiEditor-tab&quot;&gt;&lt;/span&gt;').replace(/&nbsp;/g,'&esc;&amp;nbsp;');if($.browser.msie){html=html.replace(/\t/g,'<span class="wikiEditor-tab"></span>');if($.browser.versionNumber<=7){html=html.replace(/ /g,"&nbsp;");}else{html=html.replace(/(^|\n) /g,"$1&nbsp;");}}
 524+context.$content=$(context.$iframe[0].contentWindow.document.body);for(module in context.modules){context.$content.addClass('wikiEditor-'+module);}
 525+var html=context.$textarea.val().replace(/&esc;/g,'&esc;esc;').replace(/\<p\>/g,'&esc;&lt;p&gt;').replace(/\<\/p\>/g,'&esc;&lt;/p&gt;').replace(/\<span class="wikiEditor-tab"\>\<\/span\>/g,'&esc;&lt;span&nbsp;class=&quot;wikiEditor-tab&quot;&gt;&lt;/span&gt;').replace(/&nbsp;/g,'&esc;&amp;nbsp;');if($.browser.msie){html=html.replace(/\t/g,'<span class="wikiEditor-tab"></span>');if($.browser.versionNumber<=7){html=html.replace(/ /g,"&nbsp;");}else{html=html.replace(/(^|\n) /g,"$1&nbsp;");}}
525526 html=$('<div />').text('<p>'+html.replace(/\r?\n/g,'</p><p>')+'</p>').html().replace(/&amp;nbsp;/g,'&nbsp;').replace(/&lt;p&gt;/g,'<p>').replace(/&lt;\/p&gt;/g,'</p>').replace(/&lt;span( |&nbsp;)class=("|&quot;)wikiEditor-tab("|&quot;)&gt;&lt;\/span&gt;/g,'<span class="wikiEditor-tab"></span>').replace(/<p><\/p>/g,'<p><br></p>').replace(/&amp;esc;&amp;amp;nbsp;/g,'&amp;nbsp;').replace(/&amp;esc;&amp;lt;p&amp;gt;/g,'&lt;p&gt;').replace(/&amp;esc;&amp;lt;\/p&amp;gt;/g,'&lt;/p&gt;').replace(/&amp;esc;&amp;lt;span&amp;nbsp;class=&amp;quot;wikiEditor-tab&amp;quot;&amp;gt;&amp;lt;\/span&amp;gt;/g,'&lt;span class="wikiEditor-tab"&gt;&lt;\/span&gt;').replace(/&amp;esc;esc;/g,'&amp;esc;');context.$content.html(html);if($('body').is('.rtl')){context.$content.addClass('rtl').attr('dir','rtl');}
526527 context.$textarea.attr('disabled',true);context.$textarea.hide();context.$iframe.show();context.fn.trigger('ready');context.oldHTML=context.oldDelayedHTML=context.$content.html();$(context.$iframe[0].contentWindow.document).bind('keydown',function(event){event.jQueryNode=context.fn.getElementAtCursor();return context.fn.trigger('keydown',event);}).bind('keyup',function(event){event.jQueryNode=context.fn.getElementAtCursor();return context.fn.trigger('keyup',event);}).bind('keypress',function(event){event.jQueryNode=context.fn.getElementAtCursor();return context.fn.trigger('keypress',event);}).bind('paste',function(event){return context.fn.trigger('paste',event);}).bind('cut',function(event){return context.fn.trigger('cut',event);}).bind('keyup paste mouseup cut encapsulateSelection',function(event){return context.fn.trigger('change',event);}).delayedBind(250,'keyup paste mouseup cut encapsulateSelection',function(event){context.fn.trigger('delayedChange',event);});});context.$textarea.closest('form').submit(function(){context.$textarea.attr('disabled',false);context.$textarea.val(context.$textarea.textSelection('getContents'));});context.fallbackWindowOnBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){context.$textarea.val(context.$textarea.textSelection('getContents'));if(context.fallbackWindowOnBeforeUnload){return context.fallbackWindowOnBeforeUnload();}};},'getElementAtCursor':function(){if(context.$iframe[0].contentWindow.getSelection){var selection=context.$iframe[0].contentWindow.getSelection();if(selection.rangeCount==0){return $([]);}
527528 var sc=selection.getRangeAt(0).startContainer;if(sc.nodeName=="#text")sc=sc.parentNode;return $(sc);}else if(context.$iframe[0].contentWindow.document.selection){var selection=context.$iframe[0].contentWindow.document.selection.createRange();return $(selection.parentElement());}},'getContents':function(){var html;if($.browser.msie){var $c=$(context.$content.get(0).cloneNode(true));$c.find('p').each(function(){if($(this).html()==''){$(this).replaceWith('<p></p>');}});html=$c.html();}else{html=context.$content.html();}
@@ -587,11 +588,8 @@
588589 configuration.newButtons[mw.usability.getMsg(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);$.wikiEditor.modules.dialogs.fn.setTabindexes(dialogDiv.closest('.ui-dialog').find('button').not('[tabindex]'));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);});}
589590 dialogDiv.bind('dialogclose',function(){context.fn.restoreSelection();});context.$textarea.trigger('wikiEditor-dialogs-loaded-'+mod);});},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);}
590591 $(this).css('white-space',oldWS);oldHidden.each(function(){$(this).attr('style',$(this).data('oldstyle'));});},setTabindexes:function($elements){var maxTI=0;$j('[tabindex]').each(function(){var ti=parseInt($j(this).attr('tabindex'));if(ti>maxTI)
591 -maxTI=ti;});var tabIndex=maxTI+1;$elements.each(function(){$j(this).attr('tabindex',tabIndex++);});}},modules:{},quickDialog:function(body,settings){$('<div />').text(body).appendTo($('body')).dialog($.extend({bgiframe:true,modal:true},settings)).dialog('open');}};})(jQuery);(function($){$.wikiEditor.modules.highlight={'req':['iframe'],cfg:{'styleVersion':3},evt:{delayedChange:function(context,event){$.wikiEditor.modules.highlight.currentScope=event.data.scope;if(event.data.scope=='realchange'){$.wikiEditor.modules.highlight.fn.scan(context,'');$.wikiEditor.modules.highlight.fn.mark(context,'realchange','');}},ready:function(context,event){$.wikiEditor.modules.highlight.currentScope='ready';$.wikiEditor.modules.highlight.fn.scan(context,'');$.wikiEditor.modules.highlight.fn.mark(context,'','');}},fn:{create:function(context,config){context.modules.highlight.markersStr='';},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;}
592 -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;}
593 -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;}
594 -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);}}}}
595 -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=[];if(context.modules.highlight.markers&&division!=''){for(var i=0;i<context.modules.highlight.markers.length;i++){if(context.modules.highlight.markers[i].skipDivision==division){markers.push(context.modules.highlight.markers[i]);}}}
 592+maxTI=ti;});var tabIndex=maxTI+1;$elements.each(function(){$j(this).attr('tabindex',tabIndex++);});}},modules:{},quickDialog:function(body,settings){$('<div />').text(body).appendTo($('body')).dialog($.extend({bgiframe:true,modal:true},settings)).dialog('open');}};})(jQuery);(function($){$.wikiEditor.modules.highlight={'req':['iframe'],'cfg':{'styleVersion':3},'evt':{'delayedChange':function(context,event){if(event.data.scope=='realchange'){$.wikiEditor.modules.highlight.fn.scan(context);$.wikiEditor.modules.highlight.fn.mark(context,event.data.scope);}},'ready':function(context,event){$.wikiEditor.modules.highlight.fn.scan(context);$.wikiEditor.modules.highlight.fn.mark(context,'ready');}},'fn':{'create':function(context,config){context.modules.highlight.markersStr='';},'scan':function(context,division){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(exp in $.wikiEditor.modules[module].exp){var regex=$.wikiEditor.modules[module].exp[exp].regex;var label=$.wikiEditor.modules[module].exp[exp].label;var markAfter=(typeof $.wikiEditor.modules[module].exp[exp].markAfter!='undefined');var offset=0,left,right;while((match=text.substr(offset).match(regex))!=null){right=(left=offset+match.index)+match[0].length;tokenArray[tokenArray.length]={'offset':markAfter?right:left,'label':label,'tokenStart':left,'match':match};offset=right;}}}}
 593+tokenArray.sort(function(a,b){return a.tokenStart-b.tokenStart;});context.fn.trigger('scan');},'mark':function(context,division,tokens){var markers=[];if(context.modules.highlight.markers&&division!=''){for(var i=0;i<context.modules.highlight.markers.length;i++){if(context.modules.highlight.markers[i].skipDivision==division){markers.push(context.modules.highlight.markers[i]);}}}
596594 context.modules.highlight.markers=markers;context.fn.trigger('mark');markers.sort(function(a,b){return a.start-b.start||a.end-b.end;});var markersStr='';for(var i=0;i<markers.length;i++){markersStr+=markers[i].start+','+markers[i].end+','+markers[i].type+',';}
597595 if(context.modules.highlight.markersStr==markersStr){return;}
598596 context.modules.highlight.markersStr=markersStr;var visited=[],v=0;for(var i=0;i<markers.length;i++){if(typeof markers[i].skipDivision!=='undefined'&&(division==markers[i].skipDivision)){continue;}
@@ -611,7 +609,7 @@
612610 var ca1=startNode,ca2=endNode;if(ca1&&ca2&&ca1.parentNode){var anchor=markers[i].getAnchor(ca1,ca2);if(!anchor){var commonAncestor=ca1.parentNode;if(markers[i].anchor=='wrap'){var newNode=ca1.ownerDocument.createElement('span');var nextNode=ca2.nextSibling;var n=ca1;while(n!=nextNode){var ns=n.nextSibling;newNode.appendChild(n);n=ns;}
613611 if(nextNode){commonAncestor.insertBefore(newNode,nextNode);}else{commonAncestor.appendChild(newNode);}
614612 anchor=newNode;}else if(markers[i].anchor=='tag'){anchor=commonAncestor;}
615 -$(anchor).data('marker',markers[i]).addClass('wikiEditor-highlight');markers[i].afterWrap(anchor,markers[i]);}else{$(anchor).data('marker',markers[i]);markers[i].onSkip(anchor);}
 613+$(anchor).data('marker',markers[i]).addClass('wikiEditor-highlight');markers[i].afterWrap(anchor,markers[i]);}else{$(anchor).data('marker',markers[i]);if(typeof markers[i].onSkip=='function'){markers[i].onSkip(anchor);}}
616614 visited[v++]=anchor;}}
617615 var j=0;context.$content.find('.wikiEditor-highlight').each(function(){if(visited[j]==this){j++;return true;}
618616 var marker=$(this).data('marker');if(marker&&typeof marker.skipDivision!='undefined'&&(division==marker.skipDivision)){return true;}

Follow-up revisions

RevisionCommit summaryAuthorDate
r65917Follow-up r65913: Add module to translatewikiraymond19:47, 4 May 2010
r65985UsabilityInitiative: Various style fixes for r65913. No functional changes, s...catrope13:22, 6 May 2010

Status & tagging log