bzr branch
http://gegoxaren.bato24.eu/bzr/lenasys/trunk
15.1.1
by galaxyAbstractor
Started implementation of a new codeviewer using Ace |
1 |
/* ***** BEGIN LICENSE BLOCK *****
|
2 |
* Distributed under the BSD license:
|
|
3 |
*
|
|
4 |
* Copyright (c) 2010, Ajax.org B.V.
|
|
5 |
* All rights reserved.
|
|
6 |
*
|
|
7 |
* Redistribution and use in source and binary forms, with or without
|
|
8 |
* modification, are permitted provided that the following conditions are met:
|
|
9 |
* * Redistributions of source code must retain the above copyright
|
|
10 |
* notice, this list of conditions and the following disclaimer.
|
|
11 |
* * Redistributions in binary form must reproduce the above copyright
|
|
12 |
* notice, this list of conditions and the following disclaimer in the
|
|
13 |
* documentation and/or other materials provided with the distribution.
|
|
14 |
* * Neither the name of Ajax.org B.V. nor the
|
|
15 |
* names of its contributors may be used to endorse or promote products
|
|
16 |
* derived from this software without specific prior written permission.
|
|
17 |
*
|
|
18 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
19 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
20 |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21 |
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
|
22 |
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
23 |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
24 |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
25 |
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
26 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
27 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
28 |
*
|
|
29 |
* ***** END LICENSE BLOCK ***** */
|
|
30 |
||
31 |
define('ace/ext/textarea', ['require', 'exports', 'module' , 'ace/lib/event', 'ace/lib/useragent', 'ace/lib/net', 'ace/ace', 'ace/theme/textmate', 'ace/mode/text'], function(require, exports, module) { |
|
32 |
||
33 |
||
34 |
var event = require("../lib/event"); |
|
35 |
var UA = require("../lib/useragent"); |
|
36 |
var net = require("../lib/net"); |
|
37 |
var ace = require("../ace"); |
|
38 |
||
39 |
require("../theme/textmate"); |
|
40 |
||
41 |
module.exports = exports = ace; |
|
42 |
var getCSSProperty = function(element, container, property) { |
|
43 |
var ret = element.style[property]; |
|
44 |
||
45 |
if (!ret) { |
|
46 |
if (window.getComputedStyle) { |
|
47 |
ret = window.getComputedStyle(element, '').getPropertyValue(property); |
|
48 |
} else { |
|
49 |
ret = element.currentStyle[property]; |
|
50 |
} |
|
51 |
} |
|
52 |
||
53 |
if (!ret || ret == 'auto' || ret == 'intrinsic') { |
|
54 |
ret = container.style[property]; |
|
55 |
} |
|
56 |
return ret; |
|
57 |
};
|
|
58 |
||
59 |
function applyStyles(elm, styles) { |
|
60 |
for (var style in styles) { |
|
61 |
elm.style[style] = styles[style]; |
|
62 |
} |
|
63 |
}
|
|
64 |
||
65 |
function setupContainer(element, getValue) { |
|
66 |
if (element.type != 'textarea') { |
|
67 |
throw "Textarea required!"; |
|
68 |
} |
|
69 |
||
70 |
var parentNode = element.parentNode; |
|
71 |
var container = document.createElement('div'); |
|
72 |
var resizeEvent = function() { |
|
73 |
var style = 'position:relative;'; |
|
74 |
[ |
|
75 |
'margin-top', 'margin-left', 'margin-right', 'margin-bottom' |
|
76 |
].forEach(function(item) { |
|
77 |
style += item + ':' + |
|
78 |
getCSSProperty(element, container, item) + ';'; |
|
79 |
}); |
|
80 |
var width = getCSSProperty(element, container, 'width') || (element.clientWidth + "px"); |
|
81 |
var height = getCSSProperty(element, container, 'height') || (element.clientHeight + "px"); |
|
82 |
style += 'height:' + height + ';width:' + width + ';'; |
|
83 |
style += 'display:inline-block;'; |
|
84 |
container.setAttribute('style', style); |
|
85 |
}; |
|
86 |
event.addListener(window, 'resize', resizeEvent); |
|
87 |
resizeEvent(); |
|
88 |
parentNode.insertBefore(container, element.nextSibling); |
|
89 |
while (parentNode !== document) { |
|
90 |
if (parentNode.tagName.toUpperCase() === 'FORM') { |
|
91 |
var oldSumit = parentNode.onsubmit; |
|
92 |
parentNode.onsubmit = function(evt) { |
|
93 |
element.value = getValue(); |
|
94 |
if (oldSumit) { |
|
95 |
oldSumit.call(this, evt); |
|
96 |
} |
|
97 |
}; |
|
98 |
break; |
|
99 |
} |
|
100 |
parentNode = parentNode.parentNode; |
|
101 |
} |
|
102 |
return container; |
|
103 |
}
|
|
104 |
||
105 |
exports.transformTextarea = function(element, loader) { |
|
106 |
var session; |
|
107 |
var container = setupContainer(element, function() { |
|
108 |
return session.getValue(); |
|
109 |
}); |
|
110 |
element.style.display = 'none'; |
|
111 |
container.style.background = 'white'; |
|
112 |
var editorDiv = document.createElement("div"); |
|
113 |
applyStyles(editorDiv, { |
|
114 |
top: "0px", |
|
115 |
left: "0px", |
|
116 |
right: "0px", |
|
117 |
bottom: "0px", |
|
118 |
border: "1px solid gray", |
|
119 |
position: "absolute" |
|
120 |
}); |
|
121 |
container.appendChild(editorDiv); |
|
122 |
||
123 |
var settingOpener = document.createElement("div"); |
|
124 |
applyStyles(settingOpener, { |
|
125 |
position: "absolute", |
|
126 |
right: "0px", |
|
127 |
bottom: "0px", |
|
128 |
background: "red", |
|
129 |
cursor: "nw-resize", |
|
130 |
borderStyle: "solid", |
|
131 |
borderWidth: "9px 8px 10px 9px", |
|
132 |
width: "2px", |
|
133 |
borderColor: "lightblue gray gray lightblue", |
|
134 |
zIndex: 101 |
|
135 |
}); |
|
136 |
||
137 |
var settingDiv = document.createElement("div"); |
|
138 |
var settingDivStyles = { |
|
139 |
top: "0px", |
|
140 |
left: "20%", |
|
141 |
right: "0px", |
|
142 |
bottom: "0px", |
|
143 |
position: "absolute", |
|
144 |
padding: "5px", |
|
145 |
zIndex: 100, |
|
146 |
color: "white", |
|
147 |
display: "none", |
|
148 |
overflow: "auto", |
|
149 |
fontSize: "14px", |
|
150 |
boxShadow: "-5px 2px 3px gray" |
|
151 |
}; |
|
152 |
if (!UA.isOldIE) { |
|
153 |
settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)"; |
|
154 |
} else { |
|
155 |
settingDivStyles.backgroundColor = "#333"; |
|
156 |
} |
|
157 |
||
158 |
applyStyles(settingDiv, settingDivStyles); |
|
159 |
container.appendChild(settingDiv); |
|
160 |
var options = {}; |
|
161 |
||
162 |
var editor = ace.edit(editorDiv); |
|
163 |
session = editor.getSession(); |
|
164 |
||
165 |
session.setValue(element.value || element.innerHTML); |
|
166 |
editor.focus(); |
|
167 |
container.appendChild(settingOpener); |
|
168 |
setupApi(editor, editorDiv, settingDiv, ace, options, loader); |
|
169 |
setupSettingPanel(settingDiv, settingOpener, editor, options); |
|
170 |
|
|
171 |
var state = ""; |
|
172 |
event.addListener(settingOpener, "mousemove", function(e) { |
|
173 |
var rect = this.getBoundingClientRect(); |
|
174 |
var x = e.clientX - rect.left, y = e.clientY - rect.top; |
|
175 |
if (x + y < (rect.width + rect.height)/2) { |
|
176 |
this.style.cursor = "pointer"; |
|
177 |
state = "toggle"; |
|
178 |
} else { |
|
179 |
state = "resize"; |
|
180 |
this.style.cursor = "nw-resize"; |
|
181 |
} |
|
182 |
}); |
|
183 |
|
|
184 |
event.addListener(settingOpener, "mousedown", function(e) { |
|
185 |
if (state == "toggle") { |
|
186 |
editor.setDisplaySettings(); |
|
187 |
return; |
|
188 |
} |
|
189 |
container.style.zIndex = 100000; |
|
190 |
var rect = container.getBoundingClientRect(); |
|
191 |
var startX = rect.width + rect.left - e.clientX; |
|
192 |
var startY = rect.height + rect.top - e.clientY; |
|
193 |
event.capture(settingOpener, function(e) { |
|
194 |
container.style.width = e.clientX - rect.left + startX + "px"; |
|
195 |
container.style.height = e.clientY - rect.top + startY + "px"; |
|
196 |
editor.resize(); |
|
197 |
}, function() {}); |
|
198 |
}); |
|
199 |
||
200 |
return editor; |
|
201 |
};
|
|
202 |
||
203 |
function load(url, module, callback) { |
|
204 |
net.loadScript(url, function() { |
|
205 |
require([module], callback); |
|
206 |
}); |
|
207 |
}
|
|
208 |
||
209 |
function setupApi(editor, editorDiv, settingDiv, ace, options, loader) { |
|
210 |
var session = editor.getSession(); |
|
211 |
var renderer = editor.renderer; |
|
212 |
loader = loader || load; |
|
213 |
||
214 |
function toBool(value) { |
|
215 |
return value === "true" || value == true; |
|
216 |
} |
|
217 |
||
218 |
editor.setDisplaySettings = function(display) { |
|
219 |
if (display == null) |
|
220 |
display = settingDiv.style.display == "none"; |
|
221 |
if (display) { |
|
222 |
settingDiv.style.display = "block"; |
|
223 |
settingDiv.hideButton.focus(); |
|
224 |
editor.on("focus", function onFocus() { |
|
225 |
editor.removeListener("focus", onFocus); |
|
226 |
settingDiv.style.display = "none" |
|
227 |
}); |
|
228 |
} else { |
|
229 |
editor.focus(); |
|
230 |
}; |
|
231 |
}; |
|
232 |
|
|
233 |
editor.setOption = function(key, value) { |
|
234 |
if (options[key] == value) return; |
|
235 |
||
236 |
switch (key) { |
|
237 |
case "gutter": |
|
238 |
renderer.setShowGutter(toBool(value)); |
|
239 |
break; |
|
240 |
||
241 |
case "mode": |
|
242 |
if (value != "text") { |
|
243 |
loader("mode-" + value + ".js", "ace/mode/" + value, function() { |
|
244 |
var aceMode = require("../mode/" + value).Mode; |
|
245 |
session.setMode(new aceMode()); |
|
246 |
}); |
|
247 |
} else { |
|
248 |
session.setMode(new (require("../mode/text").Mode)); |
|
249 |
} |
|
250 |
break; |
|
251 |
||
252 |
case "theme": |
|
253 |
if (value != "textmate") { |
|
254 |
loader("theme-" + value + ".js", "ace/theme/" + value, function() { |
|
255 |
editor.setTheme("ace/theme/" + value); |
|
256 |
}); |
|
257 |
} else { |
|
258 |
editor.setTheme("ace/theme/textmate"); |
|
259 |
} |
|
260 |
break; |
|
261 |
||
262 |
case "fontSize": |
|
263 |
editorDiv.style.fontSize = value; |
|
264 |
break; |
|
265 |
||
266 |
case "keybindings": |
|
267 |
switch (value) { |
|
268 |
case "vim": |
|
269 |
editor.setKeyboardHandler("ace/keyboard/vim"); |
|
270 |
break; |
|
271 |
case "emacs": |
|
272 |
editor.setKeyboardHandler("ace/keyboard/emacs"); |
|
273 |
break; |
|
274 |
default: |
|
275 |
editor.setKeyboardHandler(null); |
|
276 |
} |
|
277 |
break; |
|
278 |
||
279 |
case "softWrap": |
|
280 |
switch (value) { |
|
281 |
case "off": |
|
282 |
session.setUseWrapMode(false); |
|
283 |
renderer.setPrintMarginColumn(80); |
|
284 |
break; |
|
285 |
case "40": |
|
286 |
session.setUseWrapMode(true); |
|
287 |
session.setWrapLimitRange(40, 40); |
|
288 |
renderer.setPrintMarginColumn(40); |
|
289 |
break; |
|
290 |
case "80": |
|
291 |
session.setUseWrapMode(true); |
|
292 |
session.setWrapLimitRange(80, 80); |
|
293 |
renderer.setPrintMarginColumn(80); |
|
294 |
break; |
|
295 |
case "free": |
|
296 |
session.setUseWrapMode(true); |
|
297 |
session.setWrapLimitRange(null, null); |
|
298 |
renderer.setPrintMarginColumn(80); |
|
299 |
break; |
|
300 |
} |
|
301 |
break; |
|
302 |
||
303 |
case "useSoftTabs": |
|
304 |
session.setUseSoftTabs(toBool(value)); |
|
305 |
break; |
|
306 |
||
307 |
case "showPrintMargin": |
|
308 |
renderer.setShowPrintMargin(toBool(value)); |
|
309 |
break; |
|
310 |
||
311 |
case "showInvisibles": |
|
312 |
editor.setShowInvisibles(toBool(value)); |
|
313 |
break; |
|
314 |
} |
|
315 |
||
316 |
options[key] = value; |
|
317 |
}; |
|
318 |
||
319 |
editor.getOption = function(key) { |
|
320 |
return options[key]; |
|
321 |
}; |
|
322 |
||
323 |
editor.getOptions = function() { |
|
324 |
return options; |
|
325 |
}; |
|
326 |
||
327 |
for (var option in exports.options) { |
|
328 |
editor.setOption(option, exports.options[option]); |
|
329 |
} |
|
330 |
||
331 |
return editor; |
|
332 |
}
|
|
333 |
||
334 |
function setupSettingPanel(settingDiv, settingOpener, editor, options) { |
|
335 |
var BOOL = null; |
|
336 |
||
337 |
var desc = { |
|
338 |
mode: "Mode:", |
|
339 |
gutter: "Display Gutter:", |
|
340 |
theme: "Theme:", |
|
341 |
fontSize: "Font Size:", |
|
342 |
softWrap: "Soft Wrap:", |
|
343 |
keybindings: "Keyboard", |
|
344 |
showPrintMargin: "Show Print Margin:", |
|
345 |
useSoftTabs: "Use Soft Tabs:", |
|
346 |
showInvisibles: "Show Invisibles" |
|
347 |
}; |
|
348 |
||
349 |
var optionValues = { |
|
350 |
mode: { |
|
351 |
text: "Plain", |
|
352 |
javascript: "JavaScript", |
|
353 |
xml: "XML", |
|
354 |
html: "HTML", |
|
355 |
css: "CSS", |
|
356 |
scss: "SCSS", |
|
357 |
python: "Python", |
|
358 |
php: "PHP", |
|
359 |
java: "Java", |
|
360 |
ruby: "Ruby", |
|
361 |
c_cpp: "C/C++", |
|
362 |
coffee: "CoffeeScript", |
|
363 |
json: "json", |
|
364 |
perl: "Perl", |
|
365 |
clojure: "Clojure", |
|
366 |
ocaml: "OCaml", |
|
367 |
csharp: "C#", |
|
368 |
haxe: "haXe", |
|
369 |
svg: "SVG", |
|
370 |
textile: "Textile", |
|
371 |
groovy: "Groovy", |
|
372 |
liquid: "Liquid", |
|
373 |
Scala: "Scala" |
|
374 |
}, |
|
375 |
theme: { |
|
376 |
clouds: "Clouds", |
|
377 |
clouds_midnight: "Clouds Midnight", |
|
378 |
cobalt: "Cobalt", |
|
379 |
crimson_editor: "Crimson Editor", |
|
380 |
dawn: "Dawn", |
|
381 |
eclipse: "Eclipse", |
|
382 |
idle_fingers: "Idle Fingers", |
|
383 |
kr_theme: "Kr Theme", |
|
384 |
merbivore: "Merbivore", |
|
385 |
merbivore_soft: "Merbivore Soft", |
|
386 |
mono_industrial: "Mono Industrial", |
|
387 |
monokai: "Monokai", |
|
388 |
pastel_on_dark: "Pastel On Dark", |
|
389 |
solarized_dark: "Solarized Dark", |
|
390 |
solarized_light: "Solarized Light", |
|
391 |
textmate: "Textmate", |
|
392 |
twilight: "Twilight", |
|
393 |
vibrant_ink: "Vibrant Ink" |
|
394 |
}, |
|
395 |
gutter: BOOL, |
|
396 |
fontSize: { |
|
397 |
"10px": "10px", |
|
398 |
"11px": "11px", |
|
399 |
"12px": "12px", |
|
400 |
"14px": "14px", |
|
401 |
"16px": "16px" |
|
402 |
}, |
|
403 |
softWrap: { |
|
404 |
off: "Off", |
|
405 |
40: "40", |
|
406 |
80: "80", |
|
407 |
free: "Free" |
|
408 |
}, |
|
409 |
keybindings: { |
|
410 |
ace: "ace", |
|
411 |
vim: "vim", |
|
412 |
emacs: "emacs" |
|
413 |
}, |
|
414 |
showPrintMargin: BOOL, |
|
415 |
useSoftTabs: BOOL, |
|
416 |
showInvisibles: BOOL |
|
417 |
}; |
|
418 |
||
419 |
var table = []; |
|
420 |
table.push("<table><tr><th>Setting</th><th>Value</th></tr>"); |
|
421 |
||
422 |
function renderOption(builder, option, obj, cValue) { |
|
423 |
if (!obj) { |
|
424 |
builder.push( |
|
425 |
"<input type='checkbox' title='", option, "' ", |
|
426 |
cValue == "true" ? "checked='true'" : "", |
|
427 |
"'></input>" |
|
428 |
); |
|
429 |
return |
|
430 |
} |
|
431 |
builder.push("<select title='" + option + "'>"); |
|
432 |
for (var value in obj) { |
|
433 |
builder.push("<option value='" + value + "' "); |
|
434 |
||
435 |
if (cValue == value) { |
|
436 |
builder.push(" selected "); |
|
437 |
} |
|
438 |
||
439 |
builder.push(">", |
|
440 |
obj[value], |
|
441 |
"</option>"); |
|
442 |
} |
|
443 |
builder.push("</select>"); |
|
444 |
} |
|
445 |
||
446 |
for (var option in options) { |
|
447 |
table.push("<tr><td>", desc[option], "</td>"); |
|
448 |
table.push("<td>"); |
|
449 |
renderOption(table, option, optionValues[option], options[option]); |
|
450 |
table.push("</td></tr>"); |
|
451 |
} |
|
452 |
table.push("</table>"); |
|
453 |
settingDiv.innerHTML = table.join(""); |
|
454 |
||
455 |
var onChange = function(e) { |
|
456 |
var select = e.currentTarget; |
|
457 |
editor.setOption(select.title, select.value); |
|
458 |
}; |
|
459 |
var onClick = function(e) { |
|
460 |
var cb = e.currentTarget; |
|
461 |
editor.setOption(cb.title, cb.checked); |
|
462 |
}; |
|
463 |
var selects = settingDiv.getElementsByTagName("select"); |
|
464 |
for (var i = 0; i < selects.length; i++) |
|
465 |
selects[i].onchange = onChange; |
|
466 |
var cbs = settingDiv.getElementsByTagName("input"); |
|
467 |
for (var i = 0; i < cbs.length; i++) |
|
468 |
cbs[i].onclick = onClick; |
|
469 |
||
470 |
||
471 |
var button = document.createElement("input"); |
|
472 |
button.type = "button"; |
|
473 |
button.value = "Hide"; |
|
474 |
event.addListener(button, "click", function() { |
|
475 |
editor.setDisplaySettings(false); |
|
476 |
}); |
|
477 |
settingDiv.appendChild(button); |
|
478 |
settingDiv.hideButton = button; |
|
479 |
}
|
|
480 |
exports.options = { |
|
481 |
mode: "text", |
|
482 |
theme: "textmate", |
|
483 |
gutter: "false", |
|
484 |
fontSize: "12px", |
|
485 |
softWrap: "off", |
|
486 |
keybindings: "ace", |
|
487 |
showPrintMargin: "false", |
|
488 |
useSoftTabs: "true", |
|
489 |
showInvisibles: "false" |
|
490 |
};
|
|
491 |
||
492 |
});
|