Index: trunk/extensions/CodeEditor/CodeEditor.php |
— | — | @@ -27,13 +27,21 @@ |
28 | 28 | $tpl = array( |
29 | 29 | 'localBasePath' => dirname( __FILE__ ) . '/modules', |
30 | 30 | 'remoteExtPath' => 'CodeEditor/modules', |
31 | | - 'group' => 'ext.codeEditor', |
| 31 | + 'group' => 'ext.wikiEditor', |
32 | 32 | ); |
33 | 33 | |
34 | 34 | $wgResourceModules['ext.codeEditor'] = array( |
35 | 35 | 'scripts' => 'ext.codeEditor.js', |
36 | 36 | 'dependencies' => array( |
37 | 37 | 'ext.wikiEditor', |
| 38 | + 'jquery.codeEditor' |
| 39 | + ), |
| 40 | +) + $tpl; |
| 41 | + |
| 42 | +$wgResourceModules['jquery.codeEditor'] = array( |
| 43 | + 'scripts' => 'jquery.codeEditor.js', |
| 44 | + 'dependencies' => array( |
| 45 | + 'jquery.wikiEditor', |
38 | 46 | 'ext.codeEditor.ace', |
39 | 47 | ), |
40 | 48 | ) + $tpl; |
Index: trunk/extensions/CodeEditor/modules/jquery.codeEditor.js |
— | — | @@ -0,0 +1,207 @@ |
| 2 | +/* Ace syntax-highlighting code editor extension for wikiEditor */ |
| 3 | + |
| 4 | +( function( $ ) { |
| 5 | + |
| 6 | +$.wikiEditor.modules.codeEditor = { |
| 7 | + |
| 8 | +/** |
| 9 | + * Core Requirements |
| 10 | + */ |
| 11 | +'req': [ 'codeEditor' ], |
| 12 | +/** |
| 13 | + * Configuration |
| 14 | + */ |
| 15 | +cfg: { |
| 16 | + // |
| 17 | +}, |
| 18 | +/** |
| 19 | + * API accessible functions |
| 20 | + */ |
| 21 | +api: { |
| 22 | + // |
| 23 | +}, |
| 24 | +/** |
| 25 | + * Event handlers |
| 26 | + */ |
| 27 | +evt: { |
| 28 | + // |
| 29 | +}, |
| 30 | +/** |
| 31 | + * Internally used functions |
| 32 | + */ |
| 33 | +fn: { |
| 34 | +} |
| 35 | + |
| 36 | +}; |
| 37 | + |
| 38 | +$.wikiEditor.extensions.codeEditor = function( context ) { |
| 39 | + |
| 40 | +/* |
| 41 | + * Event Handlers |
| 42 | + * |
| 43 | + * These act as filters returning false if the event should be ignored or returning true if it should be passed |
| 44 | + * on to all modules. This is also where we can attach some extra information to the events. |
| 45 | + */ |
| 46 | +context.evt = $.extend( context.evt, { |
| 47 | + /** |
| 48 | + * Filters change events, which occur when the user interacts with the contents of the iframe. The goal of this |
| 49 | + * function is to both classify the scope of changes as 'division' or 'character' and to prevent further |
| 50 | + * processing of events which did not actually change the content of the iframe. |
| 51 | + */ |
| 52 | + 'keydown': function( event ) { |
| 53 | + }, |
| 54 | + 'change': function( event ) { |
| 55 | + }, |
| 56 | + 'delayedChange': function( event ) { |
| 57 | + }, |
| 58 | + 'cut': function( event ) { |
| 59 | + }, |
| 60 | + 'paste': function( event ) { |
| 61 | + }, |
| 62 | + 'ready': function( event ) { |
| 63 | + } |
| 64 | +} ); |
| 65 | + |
| 66 | +/** |
| 67 | + * Internally used functions |
| 68 | + */ |
| 69 | +context.fn = $.extend( context.fn, { |
| 70 | + 'saveCursorAndScrollTop': function() { |
| 71 | + // Stub out textarea behavior |
| 72 | + return; |
| 73 | + }, |
| 74 | + 'restoreCursorAndScrollTop': function() { |
| 75 | + // Stub out textarea behavior |
| 76 | + return; |
| 77 | + }, |
| 78 | + 'saveSelection': function() { |
| 79 | + }, |
| 80 | + 'restoreSelection': function() { |
| 81 | + }, |
| 82 | + /** |
| 83 | + * Sets up the iframe in place of the textarea to allow more advanced operations |
| 84 | + */ |
| 85 | + 'setupCodeEditor': function() { |
| 86 | + var box = context.$textarea; |
| 87 | + |
| 88 | + var matches = /\.(js|css)$/.exec(wgTitle); |
| 89 | + if (matches && (wgNamespaceNumber == 2 /* User: */ || wgNamespaceNumber == 8 /* MediaWiki: */)) { |
| 90 | + var ext = matches[1]; |
| 91 | + var map = {js: 'javascript', css: 'css'}; |
| 92 | + var lang = map[ext]; |
| 93 | + |
| 94 | + // Ace doesn't like replacing a textarea directly. |
| 95 | + // We'll stub this out to sit on top of it... |
| 96 | + // line-height is needed to compensate for oddity in WikiEditor extension, which zeroes the line-height on a parent container |
| 97 | + var container = $('<div style="position: relative"><div class="editor" style="line-height: 1.5em; top: 0px; left: 0px; right: 0px; bottom: 0px; border: 1px solid gray"></div></div>').insertAfter(box); |
| 98 | + var editdiv = container.find('.editor'); |
| 99 | + |
| 100 | + box.css('display', 'none'); |
| 101 | + container.width(box.width()) |
| 102 | + .height(box.height()); |
| 103 | + |
| 104 | + editdiv.text(box.val()); |
| 105 | + context.codeEditor = ace.edit(editdiv[0]); |
| 106 | + |
| 107 | + // fakeout for bug 29328 |
| 108 | + context.$iframe = [ |
| 109 | + { |
| 110 | + contentWindow: { |
| 111 | + focus: function() { |
| 112 | + context.codeEditor.focus(); |
| 113 | + } |
| 114 | + } |
| 115 | + } |
| 116 | + ]; |
| 117 | + box.closest('form').submit(function(event) { |
| 118 | + box.val(context.codeEditor.getSession().getValue()); |
| 119 | + }); |
| 120 | + context.codeEditor.getSession().setMode(new (require("ace/mode/" + lang).Mode)); |
| 121 | + |
| 122 | + // Force the box to resize horizontally to match in future :D |
| 123 | + var resize = function() { |
| 124 | + container.width(box.width()); |
| 125 | + }; |
| 126 | + $(window).resize(resize); |
| 127 | + // Use jquery.ui.resizable so user can make the box taller too |
| 128 | + container.resizable({ |
| 129 | + handles: 's', |
| 130 | + minHeight: box.height(), |
| 131 | + resize: function() { |
| 132 | + context.codeEditor.resize(); |
| 133 | + } |
| 134 | + }); |
| 135 | + |
| 136 | + var summary = $('#wpSummary'); |
| 137 | + if (summary.val() == '') { |
| 138 | + summary.val('/* using [[mw:CodeEditor|CodeEditor]] */ '); |
| 139 | + } |
| 140 | + // Let modules know we're ready to start working with the content |
| 141 | + context.fn.trigger( 'ready' ); |
| 142 | + } |
| 143 | + }, |
| 144 | + |
| 145 | + /* |
| 146 | + * Compatibility with the $.textSelection jQuery plug-in. When the iframe is in use, these functions provide |
| 147 | + * equivilant functionality to the otherwise textarea-based functionality. |
| 148 | + */ |
| 149 | + |
| 150 | + 'getElementAtCursor': function() { |
| 151 | + }, |
| 152 | + |
| 153 | + /** |
| 154 | + * Gets the currently selected text in the content |
| 155 | + * DO NOT CALL THIS DIRECTLY, use $.textSelection( 'functionname', options ) instead |
| 156 | + */ |
| 157 | + 'getSelection': function() { |
| 158 | + return context.$codeEditor.getSelectionRange(); |
| 159 | + }, |
| 160 | + /** |
| 161 | + * Inserts text at the begining and end of a text selection, optionally inserting text at the caret when |
| 162 | + * selection is empty. |
| 163 | + * DO NOT CALL THIS DIRECTLY, use $.textSelection( 'functionname', options ) instead |
| 164 | + */ |
| 165 | + 'encapsulateSelection': function( options ) { |
| 166 | + // Hack! Handle actual selection logic. |
| 167 | + var text = options.pre + options.peri + options.post; |
| 168 | + context.codeEditor.insert( text ); |
| 169 | + }, |
| 170 | + /** |
| 171 | + * Gets the position (in resolution of bytes not nessecarily characters) in a textarea |
| 172 | + * DO NOT CALL THIS DIRECTLY, use $.textSelection( 'functionname', options ) instead |
| 173 | + */ |
| 174 | + 'getCaretPosition': function( options ) { |
| 175 | + }, |
| 176 | + /** |
| 177 | + * Sets the selection of the content |
| 178 | + * DO NOT CALL THIS DIRECTLY, use $.textSelection( 'functionname', options ) instead |
| 179 | + * |
| 180 | + * @param start Character offset of selection start |
| 181 | + * @param end Character offset of selection end |
| 182 | + * @param startContainer Element in iframe to start selection in. If not set, start is a character offset |
| 183 | + * @param endContainer Element in iframe to end selection in. If not set, end is a character offset |
| 184 | + */ |
| 185 | + 'setSelection': function( options ) { |
| 186 | + }, |
| 187 | + /** |
| 188 | + * Scroll a textarea to the current cursor position. You can set the cursor position with setSelection() |
| 189 | + * DO NOT CALL THIS DIRECTLY, use $.textSelection( 'functionname', options ) instead |
| 190 | + */ |
| 191 | + 'scrollToCaretPosition': function( options ) { |
| 192 | + //context.fn.scrollToTop( context.fn.getElementAtCursor(), true ); |
| 193 | + }, |
| 194 | + /** |
| 195 | + * Scroll an element to the top of the iframe |
| 196 | + * DO NOT CALL THIS DIRECTLY, use $.textSelection( 'functionname', options ) instead |
| 197 | + * |
| 198 | + * @param $element jQuery object containing an element in the iframe |
| 199 | + * @param force If true, scroll the element even if it's already visible |
| 200 | + */ |
| 201 | + 'scrollToTop': function( $element, force ) { |
| 202 | + } |
| 203 | +} ); |
| 204 | + |
| 205 | +/* Setup the editor */ |
| 206 | +context.fn.setupCodeEditor(); |
| 207 | + |
| 208 | +} } )( jQuery ); |
Property changes on: trunk/extensions/CodeEditor/modules/jquery.codeEditor.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 209 | + native |
Index: trunk/extensions/CodeEditor/modules/ext.codeEditor.js |
— | — | @@ -35,56 +35,11 @@ |
36 | 36 | * - ctrl+R, ctrl+L, ctrl+T are taken over by the editor, which is SUPER annoying |
37 | 37 | * https://github.com/ajaxorg/ace/issues/210 |
38 | 38 | */ |
39 | | -(function(mw, $) { |
40 | | - // This should point to a checkout of Ace source. |
41 | | - var editorBase = mw.config.get('wgExtensionAssetsPath') + '/CodeEditor/modules/ace/'; |
| 39 | +/* |
| 40 | + * JavaScript for WikiEditor Table of Contents |
| 41 | + */ |
42 | 42 | |
43 | | - $(function() { |
44 | | - var box = $('#wpTextbox1'); |
45 | | - if (box.length > 0) { |
46 | | - var matches = /\.(js|css)$/.exec(wgTitle); |
47 | | - if (matches && (wgNamespaceNumber == 2 /* User: */ || wgNamespaceNumber == 8 /* MediaWiki: */)) { |
48 | | - var ext = matches[1]; |
49 | | - var map = {js: 'javascript', css: 'css'}; |
50 | | - var lang = map[ext]; |
51 | | - |
52 | | - // Ace doesn't like replacing a textarea directly. |
53 | | - // We'll stub this out to sit on top of it... |
54 | | - // line-height is needed to compensate for oddity in WikiEditor extension, which zeroes the line-height on a parent container |
55 | | - var container = $('<div style="position: relative"><div class="editor" style="line-height: 1.5em; top: 0px; left: 0px; right: 0px; bottom: 0px; border: 1px solid gray"></div></div>').insertAfter(box); |
56 | | - var editdiv = container.find('.editor'); |
57 | | - |
58 | | - box.css('display', 'none'); |
59 | | - container.width(box.width()) |
60 | | - .height(box.height()); |
61 | | - |
62 | | - editdiv.text(box.val()); |
63 | | - var editor = ace.edit(editdiv[0]); |
64 | | - box.closest('form').submit(function(event) { |
65 | | - box.val(editor.getSession().getValue()); |
66 | | - }); |
67 | | - editor.getSession().setMode(new (require("ace/mode/" + lang).Mode)); |
68 | | - |
69 | | - // Force the box to resize horizontally to match in future :D |
70 | | - var resize = function() { |
71 | | - container.width(box.width()); |
72 | | - }; |
73 | | - $(window).resize(resize); |
74 | | - // Use jquery.ui.resizable so user can make the box taller too |
75 | | - container.resizable({ |
76 | | - handles: 's', |
77 | | - minHeight: box.height(), |
78 | | - resize: function() { |
79 | | - editor.resize(); |
80 | | - } |
81 | | - }); |
82 | | - |
83 | | - var summary = $('#wpSummary'); |
84 | | - if (summary.val() == '') { |
85 | | - summary.val('/* using [[mw:CodeEditor|CodeEditor]] */ '); |
86 | | - } |
87 | | - } |
88 | | - } |
89 | | - }); |
90 | | - |
91 | | -})(mediaWiki, jQuery); |
| 43 | +$( document ).ready( function() { |
| 44 | + // Add code editor module |
| 45 | + $( '#wpTextbox1' ).wikiEditor( 'addModule', 'codeEditor' ); |
| 46 | +} ); |