2 * The "codemirror" plugin. It's indented to enhance the
3 * "sourcearea" editing mode, which displays the xhtml source code with
4 * syntax highlight and line numbers.
5 * Licensed under the MIT license
6 * CodeMirror Plugin: http://codemirror.net/ (MIT License)
10 CKEDITOR
.plugins
.add('codemirror', {
11 icons
: 'SearchCode,AutoFormat,CommentSelectedRange,UncommentSelectedRange,AutoComplete',
12 lang
: 'af,ar,bg,bn,bs,ca,cs,cy,da,de,el,en-au,en-ca,en-gb,en,eo,es,et,eu,fa,fi,fo,fr-ca,fr,gl,gu,he,hi,hr,hu,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,pl,pt-br,pt,ro,ru,sk,sl,sr-latn,sr,sv,th,tr,ug,uk,vi,zh-cn,zh',
14 init: function (editor
) {
15 var rootPath
= this.path
,
17 autoCloseBrackets
: true,
19 autoFormatOnStart
: false,
20 autoFormatOnUncomment
: true,
21 continueComments
: true,
22 enableCodeFolding
: true,
23 enableCodeFormatting
: true,
24 enableSearchTools
: true,
25 highlightActiveLine
: true,
26 highlightMatches
: true,
27 indentWithTabs
: false,
33 showAutoCompleteButton
: true,
34 showCommentButton
: true,
35 showFormatButton
: true,
36 showSearchButton
: true,
37 showTrailingSpace
: true,
38 showUncommentButton
: true,
44 var config
= CKEDITOR
.tools
.extend(defaultConfig
, editor
.config
.codemirror
|| {}, true),
45 lang
= editor
.lang
.codemirror
;
47 // check for old config settings for legacy support
48 if (editor
.config
.codemirror_theme
) {
49 config
.theme
= editor
.config
.codemirror_theme
;
51 if (editor
.config
.codemirror_autoFormatOnStart
) {
52 config
.autoFormatOnStart
= editor
.config
.codemirror_autoFormatOnStart
;
55 // Source mode isn't available in inline mode yet.
56 if (editor
.elementMode
=== CKEDITOR
.ELEMENT_MODE_INLINE
) {
58 // Override Source Dialog
59 CKEDITOR
.dialog
.add('sourcedialog', function (editor
) {
60 var size
= CKEDITOR
.document
.getWindow().getViewPaneSize(),
61 width
= Math
.min(size
.width
- 70, 800),
62 height
= size
.height
/ 1.5,
65 function loadCodeMirrorInline(editor
, textarea
) {
68 window
["codemirror_" + editor
.id
] = CodeMirror
.fromTextArea(textarea
, {
70 matchBrackets
: config
.matchBrackets
,
71 matchTags
: config
.matchTags
,
74 readOnly
: editor
.config
.readOnly
,
75 lineNumbers
: config
.lineNumbers
,
76 lineWrapping
: config
.lineWrapping
,
77 autoCloseTags
: config
.autoCloseTags
,
78 autoCloseBrackets
: config
.autoCloseBrackets
,
79 highligctionMatches
: config
.highlightMatches
,
80 continueComments
: config
.continueComments
,
81 indentWithTabs
: config
.indentWithTabs
,
83 showTrailingSpace
: config
.showTrailingSpace
,
84 showCursorWhenSelecting
: true,
85 viewportMargin
: Infinity
,
86 //extraKeys: {"Ctrl-Space": "autocomplete"},
87 extraKeys
: { "Ctrl-Q": function (codeMirror_Editor
) { window
["foldFunc_" + editor
.id
](codeMirror_Editor
, codeMirror_Editor
.getCursor().line
); } },
88 onKeyEvent: function (codeMirror_Editor
, evt
) {
89 if (config
.enableCodeFormatting
) {
90 var range
= getSelectedRange();
91 if (evt
.type
=== "keydown" && evt
.ctrlKey
&& evt
.keyCode
=== 75 && !evt
.shiftKey
&& !evt
.altKey
) {
92 window
["codemirror_" + editor
.id
].commentRange(true, range
.from, range
.to
);
93 } else if (evt
.type
=== "keydown" && evt
.ctrlKey
&& evt
.keyCode
=== 75 && evt
.shiftKey
&& !evt
.altKey
) {
94 window
["codemirror_" + editor
.id
].commentRange(false, range
.from, range
.to
);
95 if (config
.autoFormatOnUncomment
) {
96 window
["codemirror_" + editor
.id
].autoFormatRange(range
.from, range
.to
);
98 } else if (evt
.type
=== "keydown" && evt
.ctrlKey
&& evt
.keyCode
=== 75 && !evt
.shiftKey
&& evt
.altKey
) {
99 window
["codemirror_" + editor
.id
].autoFormatRange(range
.from, range
.to
);
101 /*else if (evt.type === "keydown") {
102 CodeMirror.commands.newlineAndIndentContinueMarkdownList(window["codemirror_" + editor.id]);
108 var holderHeight
= height
+ 'px';
109 var holderWidth
= width
+ 'px';
111 // Store config so we can access it within commands etc.
112 window
["codemirror_" + editor
.id
].config
= config
;
114 if (config
.autoFormatOnStart
) {
115 if (config
.useBeautify
) {
118 brace_style
= 'collapse'; //collapse, expand, end-expand
120 var source
= window
["codemirror_" + editor
.id
].getValue();
122 window
["codemirror_" + editor
.id
].setValue(html_beautify(source
, indent_size
, indent_char
, 120, brace_style
));
124 window
["codemirror_" + editor
.id
].autoFormatAll({
128 line
: window
["codemirror_" + editor
.id
].lineCount(),
134 function getSelectedRange() {
136 from: window
["codemirror_" + editor
.id
].getCursor(true),
137 to
: window
["codemirror_" + editor
.id
].getCursor(false)
141 window
["codemirror_" + editor
.id
].on("change", function () {
143 delay
= setTimeout(function () {
144 var cm
= window
["codemirror_" + editor
.id
];
152 window
["codemirror_" + editor
.id
].setSize(holderWidth
, holderHeight
);
154 // Enable Code Folding (Requires 'lineNumbers' to be set to 'true')
155 if (config
.lineNumbers
&& config
.enableCodeFolding
) {
156 window
["codemirror_" + editor
.id
].on("gutterClick", window
["foldFunc_" + editor
.id
]);
158 // Highlight Active Line
159 if (config
.highlightActiveLine
) {
160 window
["codemirror_" + editor
.id
].hlLine
= window
["codemirror_" + editor
.id
].addLineClass(0, "background", "activeline");
161 window
["codemirror_" + editor
.id
].on("cursorActivity", function () {
162 var cur
= window
["codemirror_" + editor
.id
].getLineHandle(window
["codemirror_" + editor
.id
].getCursor().line
);
163 if (cur
!= window
["codemirror_" + editor
.id
].hlLine
) {
164 window
["codemirror_" + editor
.id
].removeLineClass(window
["codemirror_" + editor
.id
].hlLine
, "background", "activeline");
165 window
["codemirror_" + editor
.id
].hlLine
= window
["codemirror_" + editor
.id
].addLineClass(cur
, "background", "activeline");
170 // Run config.onLoad callback, if present.
171 if (typeof config
.onLoad
=== 'function') {
172 config
.onLoad(window
["codemirror_" + editor
.id
], editor
);
177 title
: editor
.lang
.sourcedialog
.title
,
180 resizable
: CKEDITOR
.DIALOG_RESIZE_NONE
,
181 onShow: function () {
183 this.getContentElement('main', 'data').focus();
184 this.getContentElement('main', 'AutoComplete').setValue(config
.autoCloseTags
, true);
186 var textArea
= this.getContentElement('main', 'data').getInputElement().$;
189 this.setValueOf('main', 'data', oldData
= editor
.getData());
191 if (typeof (CodeMirror
) == 'undefined') {
193 CKEDITOR
.document
.appendStyleSheet(rootPath
+ 'css/codemirror.min.css');
195 if (config
.theme
.length
&& config
.theme
!= 'default') {
196 CKEDITOR
.document
.appendStyleSheet(rootPath
+ 'theme/' + config
.theme
+ '.css');
199 CKEDITOR
.scriptLoader
.load(rootPath
+ 'js/codemirror.min.js', function () {
201 CKEDITOR
.scriptLoader
.load(getCodeMirrorScripts(), function () {
202 loadCodeMirrorInline(editor
, textArea
);
208 loadCodeMirrorInline(editor
, textArea
);
213 onCancel: function (event
) {
214 if (event
.data
.hide
) {
215 window
["codemirror_" + editor
.id
].toTextArea();
218 window
["codemirror_" + editor
.id
] = null;
223 function setData(newData
) {
226 editor
.setData(newData
, function () {
229 // Ensure correct selection.
230 var range
= editor
.createRange();
231 range
.moveToElementEditStart(editor
.editable());
237 window
["codemirror_" + editor
.id
].toTextArea();
240 window
["codemirror_" + editor
.id
] = null;
242 // Remove CR from input data for reliable comparison with editor data.
243 var newData
= this.getValueOf('main', 'data').replace(/\r/g, '');
245 // Avoid unnecessary setData. Also preserve selection
246 // when user changed his mind and goes back to wysiwyg editing.
247 if (newData
=== oldData
)
250 // Set data asynchronously to avoid errors in IE.
251 CKEDITOR
.env
.ie
? CKEDITOR
.tools
.setTimeout(setData
, 0, this, newData
) : setData
.call(this, newData
);
253 // Don't let the dialog close before setData is over.
260 label
: editor
.lang
.sourcedialog
.title
,
264 style
: 'width: 80px;margin:0;',
265 widths
: ['20px', '20px', '20px', '20px'],
271 title
: lang
.searchCode
,
272 'class': 'searchCodeButton',
273 onClick: function() {
274 CodeMirror
.commands
.find(window
["codemirror_" + editor
.id
]);
280 title
: lang
.autoFormat
,
281 'class': 'autoFormat',
282 onClick: function() {
284 from: window
["codemirror_" + editor
.id
].getCursor(true),
285 to
: window
["codemirror_" + editor
.id
].getCursor(false)
287 window
["codemirror_" + editor
.id
].autoFormatRange(range
.from, range
.to
);
291 id
: 'CommentSelectedRange',
293 title
: lang
.commentSelectedRange
,
294 'class': 'CommentSelectedRange',
295 onClick: function () {
297 from: window
["codemirror_" + editor
.id
].getCursor(true),
298 to
: window
["codemirror_" + editor
.id
].getCursor(false)
300 window
["codemirror_" + editor
.id
].commentRange(true, range
.from, range
.to
);
304 id
: 'UncommentSelectedRange',
306 title
: lang
.uncommentSelectedRange
,
307 'class': 'UncommentSelectedRange',
308 onClick: function () {
310 from: window
["codemirror_" + editor
.id
].getCursor(true),
311 to
: window
["codemirror_" + editor
.id
].getCursor(false)
313 window
["codemirror_" + editor
.id
].commentRange(false, range
.from, range
.to
);
314 if (window
["codemirror_" + editor
.id
].config
.autoFormatOnUncomment
) {
315 window
["codemirror_" + editor
.id
].autoFormatRange(range
.from, range
.to
);
322 label
: lang
.autoCompleteToggle
,
323 title
: lang
.autoCompleteToggle
,
324 onChange: function () {
325 window
["codemirror_" + editor
.id
].setOption("autoCloseTags", this.getValue());
331 inputStyle
: 'cursor:auto;' +
332 'width:' + width
+ 'px;' +
333 'height:' + height
+ 'px;' +
336 'class': 'cke_source cke_enable_context_menu'
346 var sourcearea
= CKEDITOR
.plugins
.sourcearea
;
348 // check if sourcearea plugin is overrriden
349 if (!sourcearea
.commands
.searchCode
) {
351 CKEDITOR
.plugins
.sourcearea
.commands
= {
359 exec: function(editorInstance
) {
360 if (editorInstance
.mode
=== 'wysiwyg') {
361 editorInstance
.fire('saveSnapshot');
363 editorInstance
.getCommand('source').setState(CKEDITOR
.TRISTATE_DISABLED
);
364 editorInstance
.setMode(editorInstance
.mode
=== 'source' ? 'wysiwyg' : 'source');
375 exec: function (editorInstance
) {
376 CodeMirror
.commands
.find(window
["codemirror_" + editorInstance
.id
]);
387 exec: function (editorInstance
) {
389 from: window
["codemirror_" + editorInstance
.id
].getCursor(true),
390 to
: window
["codemirror_" + editorInstance
.id
].getCursor(false)
392 window
["codemirror_" + editorInstance
.id
].autoFormatRange(range
.from, range
.to
);
396 commentSelectedRange
: {
403 exec: function (editorInstance
) {
405 from: window
["codemirror_" + editorInstance
.id
].getCursor(true),
406 to
: window
["codemirror_" + editorInstance
.id
].getCursor(false)
408 window
["codemirror_" + editorInstance
.id
].commentRange(true, range
.from, range
.to
);
412 uncommentSelectedRange
: {
419 exec: function (editorInstance
) {
421 from: window
["codemirror_" + editorInstance
.id
].getCursor(true),
422 to
: window
["codemirror_" + editorInstance
.id
].getCursor(false)
424 window
["codemirror_" + editorInstance
.id
].commentRange(false, range
.from, range
.to
);
425 if (window
["codemirror_" + editorInstance
.id
].config
.autoFormatOnUncomment
) {
426 window
["codemirror_" + editorInstance
.id
].autoFormatRange(
433 autoCompleteToggle
: {
440 exec: function (editorInstance
) {
441 if (this.state
== CKEDITOR
.TRISTATE_ON
) {
442 window
["codemirror_" + editorInstance
.id
].setOption("autoCloseTags", false);
443 } else if (this.state
== CKEDITOR
.TRISTATE_OFF
) {
444 window
["codemirror_" + editorInstance
.id
].setOption("autoCloseTags", true);
457 editor
.addMode('source', function(callback
) {
458 if (typeof (CodeMirror
) == 'undefined') {
460 CKEDITOR
.document
.appendStyleSheet(rootPath
+ 'css/codemirror.min.css');
462 if (config
.theme
.length
&& config
.theme
!= 'default') {
463 CKEDITOR
.document
.appendStyleSheet(rootPath
+ 'theme/' + config
.theme
+ '.css');
466 CKEDITOR
.scriptLoader
.load(rootPath
+ 'js/codemirror.min.js', function() {
468 CKEDITOR
.scriptLoader
.load(getCodeMirrorScripts(), function() {
469 loadCodeMirror(editor
);
476 loadCodeMirror(editor
);
481 function getCodeMirrorScripts() {
482 var scriptFiles
= [rootPath
+ 'js/codemirror.addons.min.js'];
484 switch (config
.mode
) {
487 scriptFiles
.push(rootPath
+ 'js/codemirror.mode.htmlmixed.min.js');
493 scriptFiles
.push(rootPath
+ 'js/codemirror.mode.htmlmixed.min.js');
497 case "application/x-httpd-php":
499 scriptFiles
.push(rootPath
+ 'js/codemirror.mode.php.min.js');
503 case "text/javascript":
505 scriptFiles
.push(rootPath
+ 'js/codemirror.mode.javascript.min.js');
510 scriptFiles
.push(rootPath
+ 'js/codemirror.mode.htmlmixed.min.js');
513 if (config
.useBeautify
) {
514 scriptFiles
.push(rootPath
+ 'js/beautify.min.js');
517 if (config
.enableSearchTools
) {
518 scriptFiles
.push(rootPath
+ 'js/codemirror.addons.search.min.js');
523 function loadCodeMirror(editor
) {
524 var contentsSpace
= editor
.ui
.space('contents'),
525 textarea
= contentsSpace
.getDocument().createElement('textarea');
528 CKEDITOR
.tools
.extend({
529 // IE7 has overflow the <textarea> from wrapping table cell.
530 width
: CKEDITOR
.env
.ie7Compat
? '99%' : '100%',
536 CKEDITOR
.tools
.cssVendorPrefix('tab-size', editor
.config
.sourceAreaTabSize
|| 4)));
537 var ariaLabel
= [editor
.lang
.editor
, editor
.name
].join(',');
538 textarea
.setAttributes({
540 tabIndex
: CKEDITOR
.env
.webkit
? -1 : editor
.tabIndex
,
542 'aria-label': ariaLabel
544 textarea
.addClass('cke_source cke_reset cke_enable_context_menu');
545 editor
.ui
.space('contents').append(textarea
);
546 window
["editable_" + editor
.id
] = editor
.editable(new sourceEditable(editor
, textarea
));
547 // Fill the textarea with the current editor data.
548 window
["editable_" + editor
.id
].setData(editor
.getData(1));
549 window
["editable_" + editor
.id
].editorID
= editor
.id
;
550 editor
.fire('ariaWidget', this);
552 var sourceAreaElement
= window
["editable_" + editor
.id
],
553 holderElement
= sourceAreaElement
.getParent();
555 //codemirror = editor.id;
557 /*CodeMirror.commands.autocomplete = function(cm) {
558 CodeMirror.showHint(cm, CodeMirror.htmlHint);
561 // Enable Code Folding (Requires 'lineNumbers' to be set to 'true')
562 if (config
.lineNumbers
&& config
.enableCodeFolding
) {
563 window
["foldFunc_" + editor
.id
] = CodeMirror
.newFoldFunction(CodeMirror
.tagRangeFinder
);
566 window
["codemirror_" + editor
.id
] = CodeMirror
.fromTextArea(sourceAreaElement
.$, {
568 matchBrackets
: config
.matchBrackets
,
569 matchTags
: config
.matchTags
,
572 readOnly
: editor
.config
.readOnly
,
573 lineNumbers
: config
.lineNumbers
,
574 lineWrapping
: config
.lineWrapping
,
575 autoCloseTags
: config
.autoCloseTags
,
576 autoCloseBrackets
: config
.autoCloseBrackets
,
577 highlightSelectionMatches
: config
.highlightMatches
,
578 continueComments
: config
.continueComments
,
579 indentWithTabs
: config
.indentWithTabs
,
581 showTrailingSpace
: config
.showTrailingSpace
,
582 showCursorWhenSelecting
: true,
583 //extraKeys: {"Ctrl-Space": "autocomplete"},
584 extraKeys
: { "Ctrl-Q": function(codeMirror_Editor
) { window
["foldFunc_" + editor
.id
](codeMirror_Editor
, codeMirror_Editor
.getCursor().line
); } },
585 onKeyEvent: function(codeMirror_Editor
, evt
) {
586 if (config
.enableCodeFormatting
) {
587 var range
= getSelectedRange();
588 if (evt
.type
=== "keydown" && evt
.ctrlKey
&& evt
.keyCode
=== 75 && !evt
.shiftKey
&& !evt
.altKey
) {
589 window
["codemirror_" + editor
.id
].commentRange(true, range
.from, range
.to
);
590 } else if (evt
.type
=== "keydown" && evt
.ctrlKey
&& evt
.keyCode
=== 75 && evt
.shiftKey
&& !evt
.altKey
) {
591 window
["codemirror_" + editor
.id
].commentRange(false, range
.from, range
.to
);
592 if (config
.autoFormatOnUncomment
) {
593 window
["codemirror_" + editor
.id
].autoFormatRange(range
.from, range
.to
);
595 } else if (evt
.type
=== "keydown" && evt
.ctrlKey
&& evt
.keyCode
=== 75 && !evt
.shiftKey
&& evt
.altKey
) {
596 window
["codemirror_" + editor
.id
].autoFormatRange(range
.from, range
.to
);
597 }/* else if (evt.type === "keydown") {
598 CodeMirror.commands.newlineAndIndentContinueMarkdownList(window["codemirror_" + editor.id]);
604 var holderHeight
= holderElement
.$.clientHeight
+ 'px';
605 var holderWidth
= holderElement
.$.clientWidth
+ 'px';
607 // Store config so we can access it within commands etc.
608 window
["codemirror_" + editor
.id
].config
= config
;
609 if (config
.autoFormatOnStart
) {
610 if (config
.useBeautify
) {
612 var indent_char
= ' ';
613 var brace_style
= 'collapse'; //collapse, expand, end-expand
615 var source
= window
["codemirror_" + editor
.id
].getValue();
617 window
["codemirror_" + editor
.id
].setValue(html_beautify(source
, indent_size
, indent_char
, 120, brace_style
));
619 window
["codemirror_" + editor
.id
].autoFormatAll({
623 line
: window
["codemirror_" + editor
.id
].lineCount(),
629 function getSelectedRange() {
631 from: window
["codemirror_" + editor
.id
].getCursor(true),
632 to
: window
["codemirror_" + editor
.id
].getCursor(false)
636 window
["codemirror_" + editor
.id
].on("change", function () {
638 delay
= setTimeout(function () {
639 var cm
= window
["codemirror_" + editor
.id
];
646 window
["codemirror_" + editor
.id
].setSize(holderWidth
, holderHeight
);
648 // Enable Code Folding (Requires 'lineNumbers' to be set to 'true')
649 if (config
.lineNumbers
&& config
.enableCodeFolding
) {
650 window
["codemirror_" + editor
.id
].on("gutterClick", window
["foldFunc_" + editor
.id
]);
652 // Highlight Active Line
653 if (config
.highlightActiveLine
) {
654 window
["codemirror_" + editor
.id
].hlLine
= window
["codemirror_" + editor
.id
].addLineClass(0, "background", "activeline");
655 window
["codemirror_" + editor
.id
].on("cursorActivity", function () {
657 var cur
= window
["codemirror_" + editor
.id
].getLineHandle(window
["codemirror_" + editor
.id
].getCursor().line
);
662 if (cur
!= window
["codemirror_" + editor
.id
].hlLine
) {
663 window
["codemirror_" + editor
.id
].removeLineClass(window
["codemirror_" + editor
.id
].hlLine
, "background", "activeline");
664 window
["codemirror_" + editor
.id
].hlLine
= window
["codemirror_" + editor
.id
].addLineClass(cur
, "background", "activeline");
671 // Run config.onLoad callback, if present.
672 if (typeof config
.onLoad
=== 'function') {
673 config
.onLoad(window
["codemirror_" + editor
.id
], editor
);
677 editor
.addCommand('source', sourcearea
.commands
.source
);
678 if (editor
.ui
.addButton
) {
679 editor
.ui
.addButton('Source', {
680 label
: editor
.lang
.codemirror
.toolbar
,
685 if (config
.enableCodeFormatting
) {
686 editor
.addCommand('searchCode', sourcearea
.commands
.searchCode
);
687 editor
.addCommand('autoFormat', sourcearea
.commands
.autoFormat
);
688 editor
.addCommand('commentSelectedRange', sourcearea
.commands
.commentSelectedRange
);
689 editor
.addCommand('uncommentSelectedRange', sourcearea
.commands
.uncommentSelectedRange
);
690 editor
.addCommand('autoCompleteToggle', sourcearea
.commands
.autoCompleteToggle
);
692 if (editor
.ui
.addButton
) {
693 if (config
.showFormatButton
|| config
.showCommentButton
|| config
.showUncommentButton
|| config
.showSearchButton
) {
694 editor
.ui
.add('-', CKEDITOR
.UI_SEPARATOR
, { toolbar
: 'mode,30' });
696 if (config
.showSearchButton
&& config
.enableSearchTools
) {
697 editor
.ui
.addButton('searchCode', {
698 label
: lang
.searchCode
,
699 command
: 'searchCode',
703 if (config
.showFormatButton
) {
704 editor
.ui
.addButton('autoFormat', {
705 label
: lang
.autoFormat
,
706 command
: 'autoFormat',
710 if (config
.showCommentButton
) {
711 editor
.ui
.addButton('CommentSelectedRange', {
712 label
: lang
.commentSelectedRange
,
713 command
: 'commentSelectedRange',
717 if (config
.showUncommentButton
) {
718 editor
.ui
.addButton('UncommentSelectedRange', {
719 label
: lang
.uncommentSelectedRange
,
720 command
: 'uncommentSelectedRange',
724 if (config
.showAutoCompleteButton
) {
725 editor
.ui
.addButton('AutoComplete', {
726 label
: lang
.autoCompleteToggle
,
727 command
: 'autoCompleteToggle',
734 editor
.on('beforeModeUnload', function (evt
) {
735 if (editor
.mode
=== 'source' && editor
.plugins
.textselection
) {
736 var range
= editor
.getTextSelection();
738 range
.startOffset
= LineChanngelToOffSet(window
["codemirror_" + editor
.id
], window
["codemirror_" + editor
.id
].getCursor(true));
739 range
.endOffset
= LineChanngelToOffSet(window
["codemirror_" + editor
.id
], window
["codemirror_" + editor
.id
].getCursor(false));
741 // Fly the range when create bookmark.
742 delete range
.element
;
743 range
.createBookmark();
744 sourceBookmark
= true;
745 evt
.data
= range
.content
;
748 editor
.on('mode', function () {
749 editor
.getCommand('source').setState(editor
.mode
=== 'source' ? CKEDITOR
.TRISTATE_ON
: CKEDITOR
.TRISTATE_OFF
);
751 if (editor
.mode
=== 'source') {
752 editor
.getCommand('autoCompleteToggle').setState(window
["codemirror_" + editor
.id
].config
.autoCloseTags
? CKEDITOR
.TRISTATE_ON
: CKEDITOR
.TRISTATE_OFF
);
755 if (editor
.plugins
.textselection
&& textRange
) {
756 textRange
.element
= new CKEDITOR
.dom
.element(editor
._
.editable
.$);
761 start
= OffSetToLineChannel(window
["codemirror_" + editor
.id
], textRange
.startOffset
);
763 if (typeof (textRange
.endOffset
) == 'undefined') {
764 window
["codemirror_" + editor
.id
].setCursor(start
);
766 end
= OffSetToLineChannel(window
["codemirror_" + editor
.id
], textRange
.endOffset
);
767 window
["codemirror_" + editor
.id
].setSelection(start
, end
);
773 editor
.on('resize', function() {
774 if (window
["editable_" + editor
.id
] && editor
.mode
=== 'source') {
775 var holderElement
= window
["editable_" + editor
.id
].getParent();
776 var holderHeight
= holderElement
.$.clientHeight
+ 'px';
777 var holderWidth
= holderElement
.$.clientWidth
+ 'px';
778 window
["codemirror_" + editor
.id
].setSize(holderWidth
, holderHeight
);
782 editor
.on('readOnly', function () {
783 if (window
["editable_" + editor
.id
] && editor
.mode
=== 'source') {
784 window
["codemirror_" + editor
.id
].setOption("readOnly", this.readOnly
);
788 editor
.on('instanceReady', function () {
789 var selectAllCommand
= editor
.commands
.selectAll
;
791 // Replace Complete SelectAll command from the plugin, otherwise it will not work in IE10
792 if (selectAllCommand
!= null) {
793 selectAllCommand
.exec = function () {
794 if (editor
.mode
=== 'source') {
795 window
["codemirror_" + editor
.id
].setSelection({
799 line
: window
["codemirror_" + editor
.id
].lineCount(),
803 var editable
= editor
.editable();
804 if (editable
.is('body'))
805 editor
.document
.$.execCommand('SelectAll', false, null);
807 var range
= editor
.createRange();
808 range
.selectNodeContents(editable
);
812 // Force triggering selectionChange (#7008)
813 editor
.forceNextSelectionCheck();
814 editor
.selectionChange();
820 editor
.on('setData', function (data
) {
821 if (window
["editable_" + editor
.id
] && editor
.mode
=== 'source') {
822 window
["codemirror_" + editor
.id
].setValue(data
.data
.dataValue
);
827 var sourceEditable
= CKEDITOR
.tools
.createClass({
828 base
: CKEDITOR
.editable
,
830 setData: function(data
) {
833 if (this.codeMirror
!= null) {
834 this.codeMirror
.setValue(data
);
837 this.editor
.fire('dataReady');
839 getData: function() {
840 return this.getValue();
842 // Insertions are not supported in source editable.
843 insertHtml: function() {
845 insertElement: function() {
847 insertText: function() {
849 // Read-only support for textarea.
850 setReadOnly: function(isReadOnly
) {
851 this[(isReadOnly
? 'set' : 'remove') + 'Attribute']('readOnly', 'readonly');
855 window
["codemirror_" + this.editorID
].toTextArea();
857 // Free Memory on destroy
858 window
["editable_" + this.editorID
] = null;
859 window
["codemirror_" + this.editorID
] = null;
861 sourceEditable
.baseProto
.detach
.call(this);
863 this.clearCustomData();
869 CKEDITOR
.plugins
.sourcearea
= {
878 exec: function(editor
) {
879 if (editor
.mode
=== 'wysiwyg') {
880 editor
.fire('saveSnapshot');
883 editor
.getCommand('source').setState(CKEDITOR
.TRISTATE_DISABLED
);
884 editor
.setMode(editor
.mode
=== 'source' ? 'wysiwyg' : 'source');
895 exec: function(editor
) {
896 CodeMirror
.commands
.find(window
["codemirror_" + editor
.id
]);
907 exec: function(editor
) {
909 from: window
["codemirror_" + editor
.id
].getCursor(true),
910 to
: window
["codemirror_" + editor
.id
].getCursor(false)
912 window
["codemirror_" + editor
.id
].autoFormatRange(range
.from, range
.to
);
916 commentSelectedRange
: {
923 exec: function(editor
) {
925 from: window
["codemirror_" + editor
.id
].getCursor(true),
926 to
: window
["codemirror_" + editor
.id
].getCursor(false)
928 window
["codemirror_" + editor
.id
].commentRange(true, range
.from, range
.to
);
932 uncommentSelectedRange
: {
939 exec: function(editor
) {
941 from: window
["codemirror_" + editor
.id
].getCursor(true),
942 to
: window
["codemirror_" + editor
.id
].getCursor(false)
944 window
["codemirror_" + editor
.id
].commentRange(false, range
.from, range
.to
);
945 if (window
["codemirror_" + editor
.id
].config
.autoFormatOnUncomment
) {
946 window
["codemirror_" + editor
.id
].autoFormatRange(
953 autoCompleteToggle
: {
960 exec: function (editor
) {
961 if (this.state
== CKEDITOR
.TRISTATE_ON
) {
962 window
["codemirror_" + editor
.id
].setOption("autoCloseTags", false);
963 } else if (this.state
== CKEDITOR
.TRISTATE_OFF
) {
964 window
["codemirror_" + editor
.id
].setOption("autoCloseTags", true);
974 function LineChanngelToOffSet(ed
, linech
) {
975 var line
= linech
.line
;
977 var n
= line
+ ch
; //for the \n s & chars in the line
978 for (i
= 0; i
< line
; i
++) {
979 n
+= (ed
.getLine(i
)).length
;//for the chars in all preceeding lines
984 function OffSetToLineChannel(ed
, n
) {
985 var line
= 0, ch
= 0, index
= 0;
986 for (i
= 0; i
< ed
.lineCount() ; i
++) {
987 len
= (ed
.getLine(i
)).length
;
988 if (n
< index
+ len
) {
989 //alert(len+","+index+","+(n-index));
992 return { line
: line
, ch
: ch
};
997 return { line
: line
, ch
: ch
};