Index: trunk/extensions/UsabilityInitiative/UsabilityInitiative.hooks.php |
— | — | @@ -72,20 +72,21 @@ |
73 | 73 | array( 'src' => 'js/plugins/jquery.delayedBind.js', 'version' => 1 ), |
74 | 74 | array( 'src' => 'js/plugins/jquery.suggestions.js', 'version' => 11 ), |
75 | 75 | 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 ), |
78 | 78 | array( 'src' => 'js/plugins/jquery.wikiEditor.toolbar.js', 'version' => 59 ), |
79 | 79 | array( 'src' => 'js/plugins/jquery.wikiEditor.dialogs.js', 'version' => 24 ), |
80 | 80 | array( 'src' => 'js/plugins/jquery.wikiEditor.toc.js', 'version' => 98 ), |
81 | 81 | array( 'src' => 'js/plugins/jquery.wikiEditor.preview.js', 'version' => 11 ), |
82 | 82 | array( 'src' => 'js/plugins/jquery.wikiEditor.templateEditor.js', 'version' => 77 ), |
| 83 | + array( 'src' => 'js/plugins/jquery.wikiEditor.templates.js', 'version' => 1 ), |
83 | 84 | array( 'src' => 'js/plugins/jquery.wikiEditor.publish.js', 'version' => 5 ), |
84 | 85 | ), |
85 | 86 | 'combined' => array( |
86 | | - array( 'src' => 'js/plugins.combined.js', 'version' => 388 ), |
| 87 | + array( 'src' => 'js/plugins.combined.js', 'version' => 389 ), |
87 | 88 | ), |
88 | 89 | 'minified' => array( |
89 | | - array( 'src' => 'js/plugins.combined.min.js', 'version' => 388 ), |
| 90 | + array( 'src' => 'js/plugins.combined.min.js', 'version' => 389 ), |
90 | 91 | ), |
91 | 92 | ), |
92 | 93 | ); |
Index: trunk/extensions/UsabilityInitiative/WikiEditor/WikiEditor.php |
— | — | @@ -27,6 +27,7 @@ |
28 | 28 | 'publish' => array( 'global' => false, 'user' => true ), |
29 | 29 | 'toc' => array( 'global' => false, 'user' => true ), |
30 | 30 | 'templateEditor' => array( 'global' => false, 'user' => true ), |
| 31 | + 'templates' => array( 'global' => false, 'user' => true ), |
31 | 32 | 'addMediaWizard' => array( 'global' => false, 'user' => false ), |
32 | 33 | ); |
33 | 34 | |
— | — | @@ -59,6 +60,7 @@ |
60 | 61 | $wgExtensionMessagesFiles['WikiEditorToc'] = dirname( __FILE__ ) . '/Modules/Toc/Toc.i18n.php'; |
61 | 62 | $wgExtensionMessagesFiles['WikiEditorToolbar'] = dirname( __FILE__ ) . '/Modules/Toolbar/Toolbar.i18n.php'; |
62 | 63 | $wgExtensionMessagesFiles['WikiEditorTemplateEditor'] = dirname( __FILE__ ) . '/Modules/TemplateEditor/TemplateEditor.i18n.php'; |
| 64 | +$wgExtensionMessagesFiles['WikiEditorTemplates'] = dirname( __FILE__ ) . '/Modules/Templates/Templates.i18n.php'; |
63 | 65 | $wgExtensionMessagesFiles['WikiEditorAddMediaWizard'] = dirname( __FILE__ ) . '/Modules/AddMediaWizard/AddMediaWizard.i18n.php'; |
64 | 66 | |
65 | 67 | // Register Hooks |
Index: trunk/extensions/UsabilityInitiative/WikiEditor/WikiEditor.hooks.php |
— | — | @@ -18,6 +18,7 @@ |
19 | 19 | array( 'src' => 'Modules/Toc/Toc.js', 'version' => 7 ), |
20 | 20 | array( 'src' => 'Modules/Toolbar/Toolbar.js', 'version' => 83 ), |
21 | 21 | array( 'src' => 'Modules/TemplateEditor/TemplateEditor.js', 'version' => 6 ), |
| 22 | + array( 'src' => 'Modules/Templates/Templates.js', 'version' => 1 ), |
22 | 23 | array( 'src' => 'Modules/AddMediaWizard/AddMediaWizard.js', 'version' => 6 ), |
23 | 24 | ), |
24 | 25 | 'combined' => array( |
— | — | @@ -68,6 +69,19 @@ |
69 | 70 | 'wikieditor-template-editor-dialog-cancel', |
70 | 71 | ), |
71 | 72 | ), |
| 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 | + ), |
72 | 86 | 'addMediaWizard' => array( |
73 | 87 | 'i18n' => 'addMediaWizard', |
74 | 88 | '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 |
1 | 18 | + 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 |
1 | 18 | + native |
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.html |
— | — | @@ -37,15 +37,25 @@ |
38 | 38 | margin: 0; |
39 | 39 | padding: 0; |
40 | 40 | } |
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{ |
44 | 54 | height: 1px !important; |
45 | 55 | width: 1px !important; |
46 | 56 | overflow: hidden; |
47 | 57 | float: right; |
48 | 58 | } |
49 | | - .wikiEditor-template-text-visible{ |
| 59 | + .wikiEditor-templateEditor .wikiEditor-template-text-visible{ |
50 | 60 | padding: 0.5em 4px; |
51 | 61 | padding-top: 1.25em; |
52 | 62 | margin-top: -0.95em; |
— | — | @@ -54,19 +64,11 @@ |
55 | 65 | width: 100%; |
56 | 66 | border-bottom: solid 1px #cccccc; |
57 | 67 | } |
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 { |
67 | 69 | display: inline-block; |
68 | 70 | font-size: 12px; |
69 | 71 | } |
70 | | - .wikiEditor-template-name { |
| 72 | + .wikiEditor-templateEditor .wikiEditor-template-name { |
71 | 73 | cursor: pointer; |
72 | 74 | vertical-align: -2px; |
73 | 75 | display: inline-block; |
— | — | @@ -75,15 +77,13 @@ |
76 | 78 | margin-right: 2px; |
77 | 79 | overflow: hidden; |
78 | 80 | background: url( '../../images/wikiEditor/templateEditor/name-base.png' ) 0 0 repeat-x #e8e8e8; |
79 | | - /* color: #0645ad; */ |
80 | | - /* font-family: sans-serif; */ |
81 | 81 | color: #000000; |
82 | 82 | font-family: monospace; |
83 | 83 | text-decoration: none; |
84 | 84 | padding-left: 0.33em; |
85 | 85 | line-height: 16px; |
86 | 86 | } |
87 | | - .wikiEditor-template-expand { |
| 87 | + .wikiEditor-templateEditor .wikiEditor-template-expand { |
88 | 88 | cursor: pointer; |
89 | 89 | vertical-align: -2px; |
90 | 90 | display: inline-block; |
— | — | @@ -93,49 +93,42 @@ |
94 | 94 | line-height: 16px; |
95 | 95 | overflow: hidden; |
96 | 96 | width: 13px; |
97 | | - background-position: 50%; /*FF3*/ |
| 97 | + background-position: 50%; |
98 | 98 | } |
99 | | - .wikiEditor-template-dialog { |
| 99 | + .wikiEditor-templateEditor .wikiEditor-template-dialog { |
100 | 100 | 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%; |
102 | 102 | display: inline-block; |
103 | 103 | height: 16px; |
104 | 104 | overflow: hidden; |
105 | 105 | width: 22px; |
106 | | - background-position: 50%; /*FF3*/ |
| 106 | + background-position: 50%; |
107 | 107 | } |
108 | | - .wikiEditor-template-name:hover { |
| 108 | + .wikiEditor-templateEditor .wikiEditor-template-name:hover { |
109 | 109 | text-decoration: underline; |
110 | 110 | } |
111 | | - .wikiEditor-template-expanded .wikiEditor-template-expand { |
| 111 | + .wikiEditor-templateEditor .wikiEditor-template-expanded .wikiEditor-template-expand { |
112 | 112 | background-image: url(../../images/wikiEditor/templateEditor/collapse.png); |
113 | 113 | } |
114 | | - .wikiEditor-template-expanded .wikiEditor-template-dialog { |
| 114 | + .wikiEditor-templateEditor .wikiEditor-template-expanded .wikiEditor-template-dialog { |
115 | 115 | background-image: url(../../images/wikiEditor/templateEditor/dialog-expanded.png); |
116 | 116 | } |
117 | | - .wikiEditor-template-collapsed .wikiEditor-template-expand { |
| 117 | + .wikiEditor-templateEditor .wikiEditor-template-collapsed .wikiEditor-template-expand { |
118 | 118 | background-image: url(../../images/wikiEditor/templateEditor/expand.png); |
119 | 119 | } |
120 | | - .wikiEditor-template-collapsed .wikiEditor-template-dialog { |
| 120 | + .wikiEditor-templateEditor .wikiEditor-template-collapsed .wikiEditor-template-dialog { |
121 | 121 | background-image: url(../../images/wikiEditor/templateEditor/dialog-collapsed.png); |
122 | 122 | } |
123 | | - /* An expanded template */ |
124 | | - .wikiEditor-template-expanded { |
| 123 | + .wikiEditor-templateEditor .wikiEditor-template-expanded { |
125 | 124 | display: block; |
126 | 125 | } |
127 | | - .wikiEditor-template .wikiEditor-template-text { |
| 126 | + .wikiEditor-templateEditor .wikiEditor-template .wikiEditor-template-text { |
128 | 127 | |
129 | 128 | } |
130 | | - .wikiEditor-template-end, .wikiEditor-template-start { |
| 129 | + .wikiEditor-templateEditor .wikiEditor-template-end, .wikiEditor-template-start { |
131 | 130 | color: blue; |
132 | 131 | cursor: pointer; |
133 | 132 | } |
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 | | - } |
140 | 133 | </style> |
141 | 134 | </head> |
142 | 135 | <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 |
1 | 71 | + native |
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.js |
— | — | @@ -1057,6 +1057,10 @@ |
1058 | 1058 | } |
1059 | 1059 | // Get a reference to the content area of the iframe |
1060 | 1060 | 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 | + } |
1061 | 1065 | // If we just do "context.$content.text( context.$textarea.val() )", Internet Explorer will strip |
1062 | 1066 | // out the whitespace charcters, specifically "\n" - so we must manually encode text and append it |
1063 | 1067 | // TODO: Refactor this into a textToHtml() function |
Index: trunk/extensions/UsabilityInitiative/js/plugins/jquery.wikiEditor.highlight.js |
— | — | @@ -1,4 +1,5 @@ |
2 | 2 | /* Highlight module for wikiEditor */ |
| 3 | + |
3 | 4 | ( function( $ ) { $.wikiEditor.modules.highlight = { |
4 | 5 | |
5 | 6 | /** |
— | — | @@ -8,139 +9,73 @@ |
9 | 10 | /** |
10 | 11 | * Configuration |
11 | 12 | */ |
12 | | -cfg: { |
| 13 | +'cfg': { |
13 | 14 | 'styleVersion': 3 |
14 | 15 | }, |
15 | 16 | /** |
16 | 17 | * Internally used event handlers |
17 | 18 | */ |
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 ) { |
43 | 21 | 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 ); |
46 | 24 | } |
47 | 25 | }, |
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' ); |
53 | 29 | } |
54 | 30 | }, |
55 | 31 | /** |
56 | 32 | * Internally used functions |
57 | 33 | */ |
58 | | -fn: { |
| 34 | +'fn': { |
59 | 35 | /** |
60 | 36 | * Creates a highlight module within a wikiEditor |
61 | 37 | * |
62 | 38 | * @param config Configuration object to create module from |
63 | 39 | */ |
64 | | - create: function( context, config ) { |
| 40 | + 'create': function( context, config ) { |
65 | 41 | context.modules.highlight.markersStr = ''; |
66 | 42 | }, |
67 | 43 | /** |
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 | | - /** |
94 | 44 | * Scans text division for tokens |
95 | 45 | * |
96 | 46 | * @param division |
97 | 47 | */ |
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 |
112 | 50 | 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 |
114 | 52 | var text = context.fn.getContents(); |
| 53 | + // Perform a scan for each module which provides any expressions to scan for |
115 | 54 | for ( module in context.modules ) { |
116 | 55 | 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; |
123 | 73 | } |
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 | | - } |
138 | 74 | } |
139 | 75 | } |
140 | 76 | } |
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! |
145 | 80 | context.fn.trigger( 'scan' ); |
146 | 81 | }, |
147 | 82 | /** |
— | — | @@ -151,7 +86,7 @@ |
152 | 87 | */ |
153 | 88 | // FIXME: What do division and tokens do? |
154 | 89 | // TODO: Document the scan() and mark() APIs somewhere |
155 | | - mark: function( context, division, tokens ) { |
| 90 | + 'mark': function( context, division, tokens ) { |
156 | 91 | // Reset markers |
157 | 92 | var markers = []; |
158 | 93 | |
— | — | @@ -169,8 +104,8 @@ |
170 | 105 | context.fn.trigger( 'mark' ); |
171 | 106 | markers.sort( function( a, b ) { return a.start - b.start || a.end - b.end; } ); |
172 | 107 | |
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 |
175 | 110 | var markersStr = ''; |
176 | 111 | for ( var i = 0; i < markers.length; i++ ) { |
177 | 112 | markersStr += markers[i].start + ',' + markers[i].end + ',' + markers[i].type + ','; |
— | — | @@ -181,16 +116,15 @@ |
182 | 117 | } |
183 | 118 | context.modules.highlight.markersStr = markersStr; |
184 | 119 | |
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 |
187 | 122 | var visited = [], v = 0; |
188 | 123 | for ( var i = 0; i < markers.length; i++ ) { |
189 | 124 | if ( typeof markers[i].skipDivision !== 'undefined' && ( division == markers[i].skipDivision ) ) { |
190 | 125 | continue; |
191 | 126 | } |
192 | 127 | |
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. |
195 | 129 | var start = markers[i].start; |
196 | 130 | var s = context.fn.getOffset( start ); |
197 | 131 | if ( !s ) { |
— | — | @@ -200,9 +134,9 @@ |
201 | 135 | var startNode = s.node; |
202 | 136 | |
203 | 137 | // 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 |
207 | 141 | while ( startNode.nodeName == 'BR' || s.offset == startNode.nodeValue.length ) { |
208 | 142 | start++; |
209 | 143 | s = context.fn.getOffset( start ); |
— | — | @@ -211,20 +145,17 @@ |
212 | 146 | |
213 | 147 | // The next marker starts somewhere in this textNode or at this BR |
214 | 148 | 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 |
218 | 151 | var newStartNode = startNode.splitText( s.offset < s.node.nodeValue.length ? |
219 | 152 | s.offset : s.node.nodeValue.length - 1 |
220 | 153 | ); |
221 | 154 | var oldStartNode = startNode; |
222 | 155 | 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 |
229 | 160 | // with lastTextNode == oldStartNode, but that doesn't really matter |
230 | 161 | var subtracted = s.offset; |
231 | 162 | var oldLength = s.length; |
— | — | @@ -249,10 +180,9 @@ |
250 | 181 | } |
251 | 182 | } |
252 | 183 | } |
253 | | - |
254 | 184 | 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 |
257 | 187 | var e = context.fn.getOffset( end - 1 ); |
258 | 188 | if ( !e ) { |
259 | 189 | // This shouldn't happen |
— | — | @@ -263,11 +193,9 @@ |
264 | 194 | // Split off the suffix. This puts the suffix in a new node and leaves the rest in endNode |
265 | 195 | var oldEndNode = endNode; |
266 | 196 | var newEndNode = endNode.splitText( e.offset + 1 ); |
267 | | - |
268 | 197 | // Update offset objects |
269 | 198 | var subtracted = e.offset + 1; |
270 | 199 | var oldLength = e.length; |
271 | | - |
272 | 200 | var j, o; |
273 | 201 | // Update offset objects referring to oldEndNode |
274 | 202 | for ( j = end - subtracted; j < end; j++ ) { |
— | — | @@ -295,12 +223,10 @@ |
296 | 224 | } |
297 | 225 | } |
298 | 226 | } |
299 | | - |
300 | 227 | // Don't wrap trailing BRs, doing that causes weird issues |
301 | 228 | if ( endNode.nodeName == 'BR' ) { |
302 | 229 | endNode = e.lastTextNode; |
303 | 230 | } |
304 | | - |
305 | 231 | // If startNode and endNode have different parents, we need to pull endNode and all textnodes in between |
306 | 232 | // into startNode's parent and replace </p><p> with <br> |
307 | 233 | if ( startNode.parentNode != endNode.parentNode ) { |
— | — | @@ -354,7 +280,6 @@ |
355 | 281 | // TODO: Update offset objects ourselves for performance. Requires rewriting this code block to be |
356 | 282 | // offset-based rather than traverser-based |
357 | 283 | } |
358 | | - |
359 | 284 | // Now wrap everything between startNode and endNode (may be equal). |
360 | 285 | var ca1 = startNode, ca2 = endNode; |
361 | 286 | if ( ca1 && ca2 && ca1.parentNode ) { |
— | — | @@ -362,11 +287,8 @@ |
363 | 288 | if ( !anchor ) { |
364 | 289 | var commonAncestor = ca1.parentNode; |
365 | 290 | 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 |
369 | 292 | var newNode = ca1.ownerDocument.createElement( 'span' ); |
370 | | - |
371 | 293 | var nextNode = ca2.nextSibling; |
372 | 294 | // Append all nodes between ca1 and ca2 (inclusive) to newNode |
373 | 295 | var n = ca1; |
— | — | @@ -376,34 +298,31 @@ |
377 | 299 | n = ns; |
378 | 300 | } |
379 | 301 | // Insert newNode in the right place |
380 | | - |
381 | 302 | if ( nextNode ) { |
382 | 303 | commonAncestor.insertBefore( newNode, nextNode ); |
383 | 304 | } else { |
384 | 305 | commonAncestor.appendChild( newNode ); |
385 | 306 | } |
386 | | - |
387 | 307 | anchor = newNode; |
388 | 308 | } else if ( markers[i].anchor == 'tag' ) { |
389 | 309 | anchor = commonAncestor; |
390 | 310 | } |
391 | | - $( anchor ).data( 'marker', markers[i] ) |
392 | | - .addClass( 'wikiEditor-highlight' ); |
| 311 | + $( anchor ).data( 'marker', markers[i] ).addClass( 'wikiEditor-highlight' ); |
393 | 312 | // Allow the module adding this marker to manipulate it |
394 | 313 | markers[i].afterWrap( anchor, markers[i] ); |
395 | 314 | |
396 | 315 | } else { |
397 | 316 | // Update the marker object |
398 | 317 | $( anchor ).data( 'marker', markers[i] ); |
399 | | - markers[i].onSkip( anchor ); |
| 318 | + if ( typeof markers[i].onSkip == 'function' ) { |
| 319 | + markers[i].onSkip( anchor ); |
| 320 | + } |
400 | 321 | } |
401 | 322 | visited[v++] = anchor; |
402 | 323 | } |
403 | 324 | } |
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 |
408 | 327 | var j = 0; |
409 | 328 | context.$content.find( '.wikiEditor-highlight' ).each( function() { |
410 | 329 | if ( visited[j] == this ) { |
— | — | @@ -411,7 +330,6 @@ |
412 | 331 | j++; |
413 | 332 | return true; |
414 | 333 | } |
415 | | - |
416 | 334 | // Remove this marker |
417 | 335 | var marker = $(this).data( 'marker' ); |
418 | 336 | if ( marker && typeof marker.skipDivision != 'undefined' && ( division == marker.skipDivision ) ) { |
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.js |
— | — | @@ -7642,6 +7642,10 @@ |
7643 | 7643 | } |
7644 | 7644 | // Get a reference to the content area of the iframe |
7645 | 7645 | 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 | + } |
7646 | 7650 | // If we just do "context.$content.text( context.$textarea.val() )", Internet Explorer will strip |
7647 | 7651 | // out the whitespace charcters, specifically "\n" - so we must manually encode text and append it |
7648 | 7652 | // TODO: Refactor this into a textToHtml() function |
— | — | @@ -8610,6 +8614,7 @@ |
8611 | 8615 | |
8612 | 8616 | }; } ) ( jQuery ); |
8613 | 8617 | /* Highlight module for wikiEditor */ |
| 8618 | + |
8614 | 8619 | ( function( $ ) { $.wikiEditor.modules.highlight = { |
8615 | 8620 | |
8616 | 8621 | /** |
— | — | @@ -8619,139 +8624,73 @@ |
8620 | 8625 | /** |
8621 | 8626 | * Configuration |
8622 | 8627 | */ |
8623 | | -cfg: { |
| 8628 | +'cfg': { |
8624 | 8629 | 'styleVersion': 3 |
8625 | 8630 | }, |
8626 | 8631 | /** |
8627 | 8632 | * Internally used event handlers |
8628 | 8633 | */ |
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 ) { |
8654 | 8636 | 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 ); |
8657 | 8639 | } |
8658 | 8640 | }, |
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' ); |
8664 | 8644 | } |
8665 | 8645 | }, |
8666 | 8646 | /** |
8667 | 8647 | * Internally used functions |
8668 | 8648 | */ |
8669 | | -fn: { |
| 8649 | +'fn': { |
8670 | 8650 | /** |
8671 | 8651 | * Creates a highlight module within a wikiEditor |
8672 | 8652 | * |
8673 | 8653 | * @param config Configuration object to create module from |
8674 | 8654 | */ |
8675 | | - create: function( context, config ) { |
| 8655 | + 'create': function( context, config ) { |
8676 | 8656 | context.modules.highlight.markersStr = ''; |
8677 | 8657 | }, |
8678 | 8658 | /** |
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 | | - /** |
8705 | 8659 | * Scans text division for tokens |
8706 | 8660 | * |
8707 | 8661 | * @param division |
8708 | 8662 | */ |
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 |
8723 | 8665 | 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 |
8725 | 8667 | var text = context.fn.getContents(); |
| 8668 | + // Perform a scan for each module which provides any expressions to scan for |
8726 | 8669 | for ( module in context.modules ) { |
8727 | 8670 | 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; |
8734 | 8688 | } |
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 | | - } |
8749 | 8689 | } |
8750 | 8690 | } |
8751 | 8691 | } |
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! |
8756 | 8695 | context.fn.trigger( 'scan' ); |
8757 | 8696 | }, |
8758 | 8697 | /** |
— | — | @@ -8762,7 +8701,7 @@ |
8763 | 8702 | */ |
8764 | 8703 | // FIXME: What do division and tokens do? |
8765 | 8704 | // TODO: Document the scan() and mark() APIs somewhere |
8766 | | - mark: function( context, division, tokens ) { |
| 8705 | + 'mark': function( context, division, tokens ) { |
8767 | 8706 | // Reset markers |
8768 | 8707 | var markers = []; |
8769 | 8708 | |
— | — | @@ -8780,8 +8719,8 @@ |
8781 | 8720 | context.fn.trigger( 'mark' ); |
8782 | 8721 | markers.sort( function( a, b ) { return a.start - b.start || a.end - b.end; } ); |
8783 | 8722 | |
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 |
8786 | 8725 | var markersStr = ''; |
8787 | 8726 | for ( var i = 0; i < markers.length; i++ ) { |
8788 | 8727 | markersStr += markers[i].start + ',' + markers[i].end + ',' + markers[i].type + ','; |
— | — | @@ -8792,16 +8731,15 @@ |
8793 | 8732 | } |
8794 | 8733 | context.modules.highlight.markersStr = markersStr; |
8795 | 8734 | |
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 |
8798 | 8737 | var visited = [], v = 0; |
8799 | 8738 | for ( var i = 0; i < markers.length; i++ ) { |
8800 | 8739 | if ( typeof markers[i].skipDivision !== 'undefined' && ( division == markers[i].skipDivision ) ) { |
8801 | 8740 | continue; |
8802 | 8741 | } |
8803 | 8742 | |
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. |
8806 | 8744 | var start = markers[i].start; |
8807 | 8745 | var s = context.fn.getOffset( start ); |
8808 | 8746 | if ( !s ) { |
— | — | @@ -8811,9 +8749,9 @@ |
8812 | 8750 | var startNode = s.node; |
8813 | 8751 | |
8814 | 8752 | // 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 |
8818 | 8756 | while ( startNode.nodeName == 'BR' || s.offset == startNode.nodeValue.length ) { |
8819 | 8757 | start++; |
8820 | 8758 | s = context.fn.getOffset( start ); |
— | — | @@ -8822,20 +8760,17 @@ |
8823 | 8761 | |
8824 | 8762 | // The next marker starts somewhere in this textNode or at this BR |
8825 | 8763 | 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 |
8829 | 8766 | var newStartNode = startNode.splitText( s.offset < s.node.nodeValue.length ? |
8830 | 8767 | s.offset : s.node.nodeValue.length - 1 |
8831 | 8768 | ); |
8832 | 8769 | var oldStartNode = startNode; |
8833 | 8770 | 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 |
8840 | 8775 | // with lastTextNode == oldStartNode, but that doesn't really matter |
8841 | 8776 | var subtracted = s.offset; |
8842 | 8777 | var oldLength = s.length; |
— | — | @@ -8860,10 +8795,9 @@ |
8861 | 8796 | } |
8862 | 8797 | } |
8863 | 8798 | } |
8864 | | - |
8865 | 8799 | 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 |
8868 | 8802 | var e = context.fn.getOffset( end - 1 ); |
8869 | 8803 | if ( !e ) { |
8870 | 8804 | // This shouldn't happen |
— | — | @@ -8874,11 +8808,9 @@ |
8875 | 8809 | // Split off the suffix. This puts the suffix in a new node and leaves the rest in endNode |
8876 | 8810 | var oldEndNode = endNode; |
8877 | 8811 | var newEndNode = endNode.splitText( e.offset + 1 ); |
8878 | | - |
8879 | 8812 | // Update offset objects |
8880 | 8813 | var subtracted = e.offset + 1; |
8881 | 8814 | var oldLength = e.length; |
8882 | | - |
8883 | 8815 | var j, o; |
8884 | 8816 | // Update offset objects referring to oldEndNode |
8885 | 8817 | for ( j = end - subtracted; j < end; j++ ) { |
— | — | @@ -8906,12 +8838,10 @@ |
8907 | 8839 | } |
8908 | 8840 | } |
8909 | 8841 | } |
8910 | | - |
8911 | 8842 | // Don't wrap trailing BRs, doing that causes weird issues |
8912 | 8843 | if ( endNode.nodeName == 'BR' ) { |
8913 | 8844 | endNode = e.lastTextNode; |
8914 | 8845 | } |
8915 | | - |
8916 | 8846 | // If startNode and endNode have different parents, we need to pull endNode and all textnodes in between |
8917 | 8847 | // into startNode's parent and replace </p><p> with <br> |
8918 | 8848 | if ( startNode.parentNode != endNode.parentNode ) { |
— | — | @@ -8965,7 +8895,6 @@ |
8966 | 8896 | // TODO: Update offset objects ourselves for performance. Requires rewriting this code block to be |
8967 | 8897 | // offset-based rather than traverser-based |
8968 | 8898 | } |
8969 | | - |
8970 | 8899 | // Now wrap everything between startNode and endNode (may be equal). |
8971 | 8900 | var ca1 = startNode, ca2 = endNode; |
8972 | 8901 | if ( ca1 && ca2 && ca1.parentNode ) { |
— | — | @@ -8973,11 +8902,8 @@ |
8974 | 8903 | if ( !anchor ) { |
8975 | 8904 | var commonAncestor = ca1.parentNode; |
8976 | 8905 | 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 |
8980 | 8907 | var newNode = ca1.ownerDocument.createElement( 'span' ); |
8981 | | - |
8982 | 8908 | var nextNode = ca2.nextSibling; |
8983 | 8909 | // Append all nodes between ca1 and ca2 (inclusive) to newNode |
8984 | 8910 | var n = ca1; |
— | — | @@ -8987,34 +8913,31 @@ |
8988 | 8914 | n = ns; |
8989 | 8915 | } |
8990 | 8916 | // Insert newNode in the right place |
8991 | | - |
8992 | 8917 | if ( nextNode ) { |
8993 | 8918 | commonAncestor.insertBefore( newNode, nextNode ); |
8994 | 8919 | } else { |
8995 | 8920 | commonAncestor.appendChild( newNode ); |
8996 | 8921 | } |
8997 | | - |
8998 | 8922 | anchor = newNode; |
8999 | 8923 | } else if ( markers[i].anchor == 'tag' ) { |
9000 | 8924 | anchor = commonAncestor; |
9001 | 8925 | } |
9002 | | - $( anchor ).data( 'marker', markers[i] ) |
9003 | | - .addClass( 'wikiEditor-highlight' ); |
| 8926 | + $( anchor ).data( 'marker', markers[i] ).addClass( 'wikiEditor-highlight' ); |
9004 | 8927 | // Allow the module adding this marker to manipulate it |
9005 | 8928 | markers[i].afterWrap( anchor, markers[i] ); |
9006 | 8929 | |
9007 | 8930 | } else { |
9008 | 8931 | // Update the marker object |
9009 | 8932 | $( anchor ).data( 'marker', markers[i] ); |
9010 | | - markers[i].onSkip( anchor ); |
| 8933 | + if ( typeof markers[i].onSkip == 'function' ) { |
| 8934 | + markers[i].onSkip( anchor ); |
| 8935 | + } |
9011 | 8936 | } |
9012 | 8937 | visited[v++] = anchor; |
9013 | 8938 | } |
9014 | 8939 | } |
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 |
9019 | 8942 | var j = 0; |
9020 | 8943 | context.$content.find( '.wikiEditor-highlight' ).each( function() { |
9021 | 8944 | if ( visited[j] == this ) { |
— | — | @@ -9022,7 +8945,6 @@ |
9023 | 8946 | j++; |
9024 | 8947 | return true; |
9025 | 8948 | } |
9026 | | - |
9027 | 8949 | // Remove this marker |
9028 | 8950 | var marker = $(this).data( 'marker' ); |
9029 | 8951 | if ( marker && typeof marker.skipDivision != 'undefined' && ( division == marker.skipDivision ) ) { |
Index: trunk/extensions/UsabilityInitiative/js/plugins.combined.min.js |
— | — | @@ -520,7 +520,8 @@ |
521 | 521 | 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;} |
522 | 522 | 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;} |
523 | 523 | 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;<p>').replace(/\<\/p\>/g,'&esc;</p>').replace(/\<span class="wikiEditor-tab"\>\<\/span\>/g,'&esc;<span class="wikiEditor-tab"></span>').replace(/ /g,'&esc;&nbsp;');if($.browser.msie){html=html.replace(/\t/g,'<span class="wikiEditor-tab"></span>');if($.browser.versionNumber<=7){html=html.replace(/ /g," ");}else{html=html.replace(/(^|\n) /g,"$1 ");}} |
| 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;<p>').replace(/\<\/p\>/g,'&esc;</p>').replace(/\<span class="wikiEditor-tab"\>\<\/span\>/g,'&esc;<span class="wikiEditor-tab"></span>').replace(/ /g,'&esc;&nbsp;');if($.browser.msie){html=html.replace(/\t/g,'<span class="wikiEditor-tab"></span>');if($.browser.versionNumber<=7){html=html.replace(/ /g," ");}else{html=html.replace(/(^|\n) /g,"$1 ");}} |
525 | 526 | html=$('<div />').text('<p>'+html.replace(/\r?\n/g,'</p><p>')+'</p>').html().replace(/&nbsp;/g,' ').replace(/<p>/g,'<p>').replace(/<\/p>/g,'</p>').replace(/<span( | )class=("|")wikiEditor-tab("|")><\/span>/g,'<span class="wikiEditor-tab"></span>').replace(/<p><\/p>/g,'<p><br></p>').replace(/&esc;&amp;nbsp;/g,'&nbsp;').replace(/&esc;&lt;p&gt;/g,'<p>').replace(/&esc;&lt;\/p&gt;/g,'</p>').replace(/&esc;&lt;span&nbsp;class=&quot;wikiEditor-tab&quot;&gt;&lt;\/span&gt;/g,'<span class="wikiEditor-tab"><\/span>').replace(/&esc;esc;/g,'&esc;');context.$content.html(html);if($('body').is('.rtl')){context.$content.addClass('rtl').attr('dir','rtl');} |
526 | 527 | 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 $([]);} |
527 | 528 | 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 @@ |
588 | 589 | 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);});} |
589 | 590 | 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);} |
590 | 591 | $(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]);}}} |
596 | 594 | 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+',';} |
597 | 595 | if(context.modules.highlight.markersStr==markersStr){return;} |
598 | 596 | 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 @@ |
612 | 610 | 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;} |
613 | 611 | if(nextNode){commonAncestor.insertBefore(newNode,nextNode);}else{commonAncestor.appendChild(newNode);} |
614 | 612 | 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);}} |
616 | 614 | visited[v++]=anchor;}} |
617 | 615 | var j=0;context.$content.find('.wikiEditor-highlight').each(function(){if(visited[j]==this){j++;return true;} |
618 | 616 | var marker=$(this).data('marker');if(marker&&typeof marker.skipDivision!='undefined'&&(division==marker.skipDivision)){return true;} |