mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-10-09 13:24:08 +00:00
refactor(blog): use monaco editor
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
5677f55ce3
commit
387e7b45af
@ -171,8 +171,6 @@ class UOJBlogEditor {
|
||||
}
|
||||
|
||||
public function handleSave() {
|
||||
global $REQUIRE_LIB;
|
||||
|
||||
$save = $this->save;
|
||||
$this->receivePostData();
|
||||
$ret = $save($this->post_data);
|
||||
@ -185,15 +183,19 @@ class UOJBlogEditor {
|
||||
if ($this->type == 'blog') {
|
||||
$req_lib = [
|
||||
'mathjax' => '',
|
||||
'hljs' => '',
|
||||
];
|
||||
|
||||
$req_lib['hljs'] = '';
|
||||
echoUOJPageHeader('博客预览', [
|
||||
'ShowPageHeader' => false,
|
||||
'REQUIRE_LIB' => $req_lib,
|
||||
]);
|
||||
|
||||
echoUOJPageHeader('博客预览', array('ShowPageHeader' => false, 'REQUIRE_LIB' => $req_lib));
|
||||
echo '<article class="markdown-body">';
|
||||
echo $this->post_data['content'];
|
||||
echo '</article>';
|
||||
echoUOJPageFooter(array('ShowPageFooter' => false));
|
||||
|
||||
echoUOJPageFooter(['ShowPageFooter' => false]);
|
||||
} elseif ($this->type == 'slide') {
|
||||
uojIncludeView('slide', array_merge(
|
||||
UOJContext::pageConfig(),
|
||||
|
@ -1,39 +1,47 @@
|
||||
<form method="post" class="form-horizontal" id="form-<?= $editor->name ?>" enctype="multipart/form-data">
|
||||
<?= HTML::hiddenToken() ?>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<?= HTML::div_vinput("{$editor->name}_title", 'text', $editor->label_text['title'], html_entity_decode($editor->cur_data['title'])) ?>
|
||||
</div>
|
||||
<?php if ($editor->show_tags): ?>
|
||||
<div class="col-sm-6">
|
||||
<?= HTML::div_vinput("{$editor->name}_tags", 'text', $editor->label_text['tags'], join(', ', $editor->cur_data['tags'])) ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<?php if ($editor->show_editor): ?>
|
||||
<?= HTML::div_vtextarea("{$editor->name}_content_md", $editor->label_text['content'], $editor->cur_data['content_md']) ?>
|
||||
<?php endif ?>
|
||||
<div class="row mt-2">
|
||||
<div class="col-sm-6">
|
||||
<?php if ($editor->blog_url): ?>
|
||||
<a id="a-<?= $editor->name ?>_view_blog" class="btn btn-info" href="<?= HTML::escape($editor->blog_url) ?>"><?= $editor->label_text['view blog'] ?></a>
|
||||
<?php else: ?>
|
||||
<a id="a-<?= $editor->name ?>_view_blog" class="btn btn-info" style="display: none;"><?= $editor->label_text['view blog'] ?></a>
|
||||
<?= HTML::hiddenToken() ?>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<?= HTML::div_vinput("{$editor->name}_title", 'text', $editor->label_text['title'], html_entity_decode($editor->cur_data['title'])) ?>
|
||||
</div>
|
||||
<?php if ($editor->show_tags) : ?>
|
||||
<div class="col-sm-6">
|
||||
<?= HTML::div_vinput("{$editor->name}_tags", 'text', $editor->label_text['tags'], join(', ', $editor->cur_data['tags'])) ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<div class="col-sm-6 text-end">
|
||||
<?= HTML::checkbox("{$editor->name}_is_hidden", $editor->cur_data['is_hidden']) ?>
|
||||
<?php if ($editor->show_editor) : ?>
|
||||
<div id="div-<?= $editor->name ?>_content_md">
|
||||
<div id="div_container-<?= $editor->name ?>_content_md" style="height: 500px">
|
||||
<div class="border d-flex justify-content-center align-items-center" style="width: 100%; height: 350px;">
|
||||
<div class="spinner-border text-muted" style="width: 3rem; height: 3rem;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="help-block" id="help-<?= $editor->name ?>_content_md"></div>
|
||||
<input type="hidden" id="input-<?= $editor->name ?>_content_md" name="<?= $editor->name ?>_content_md" value="<?= HTML::escape($editor->cur_data['content_md']) ?>" />
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="row mt-2">
|
||||
<div class="col-sm-6">
|
||||
<?php if ($editor->blog_url) : ?>
|
||||
<a id="a-<?= $editor->name ?>_view_blog" class="btn btn-secondary" href="<?= HTML::escape($editor->blog_url) ?>"><?= $editor->label_text['view blog'] ?></a>
|
||||
<?php else : ?>
|
||||
<a id="a-<?= $editor->name ?>_view_blog" class="btn btn-secondary" style="display: none;"><?= $editor->label_text['view blog'] ?></a>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<div class="col-sm-6 text-end">
|
||||
<?= HTML::checkbox("{$editor->name}_is_hidden", $editor->cur_data['is_hidden']) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
$('#<?= "input-{$editor->name}_is_hidden" ?>').bootstrapSwitch({
|
||||
onText: <?= json_encode($editor->label_text['private']) ?>,
|
||||
onColor: 'danger',
|
||||
offText: <?= json_encode($editor->label_text['public']) ?>,
|
||||
offColor: 'primary',
|
||||
labelText: <?= json_encode($editor->label_text['blog visibility']) ?>,
|
||||
handleWidth: 100
|
||||
});
|
||||
blog_editor_init("<?= $editor->name ?>", <?= json_encode(array('type' => $editor->type)) ?>);
|
||||
$('#<?= "input-{$editor->name}_is_hidden" ?>').bootstrapSwitch({
|
||||
onText: <?= json_encode($editor->label_text['private']) ?>,
|
||||
onColor: 'danger',
|
||||
offText: <?= json_encode($editor->label_text['public']) ?>,
|
||||
offColor: 'primary',
|
||||
labelText: <?= json_encode($editor->label_text['blog visibility']) ?>,
|
||||
handleWidth: 100
|
||||
});
|
||||
blog_editor_init("<?= $editor->name ?>", <?= json_encode(array('type' => $editor->type)) ?>);
|
||||
</script>
|
||||
|
@ -72,31 +72,8 @@ if (!isset($ShowPageHeader)) {
|
||||
<!-- UOJ blog editor -->
|
||||
<?php $REQUIRE_LIB['jquery.hotkeys'] = '' ?>
|
||||
<?php $REQUIRE_LIB['switch'] = '' ?>
|
||||
<?= HTML::css_link('/js/codemirror/lib/codemirror.css') ?>
|
||||
<?= HTML::css_link('/css/blog-editor.css') ?>
|
||||
<?= HTML::js_src('/js/marked.js?v=2016.10.19') ?>
|
||||
<?= HTML::js_src('/js/blog-editor/blog-editor.js?v=' . UOJConfig::$data['profile']['s2oj-version']) ?>
|
||||
<?= HTML::js_src('/js/codemirror/lib/codemirror.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/addon/mode/overlay.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/addon/selection/active-line.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/mode/xml/xml.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/mode/gfm/gfm.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/mode/markdown/markdown.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/mode/javascript/javascript.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/mode/css/css.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/mode/htmlmixed/htmlmixed.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/mode/clike/clike.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/mode/pascal/pascal.js') ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['slide-editor'])) : ?>
|
||||
<!-- UOJ slide editor -->
|
||||
<?= HTML::css_link('/js/codemirror/lib/codemirror.css') ?>
|
||||
<?= HTML::css_link('/css/slide-editor.css') ?>
|
||||
<?= HTML::js_src('/js/slide-editor/slide-editor.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/lib/codemirror.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/addon/mode/overlay.js') ?>
|
||||
<?= HTML::js_src('/js/codemirror/addon/selection/active-line.js') ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (isset($REQUIRE_LIB['md5'])) : ?>
|
||||
|
@ -23,8 +23,3 @@
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.blog-content-md-editor .CodeMirror{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
.slide-editor {
|
||||
height: 600px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.slide-editor .CodeMirror{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
@ -455,12 +455,6 @@ form.form-horizontal {
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix CodeMirror */
|
||||
|
||||
.CodeMirror-linenumber {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
/* Back button */
|
||||
|
||||
.uoj-back-btn {
|
||||
|
@ -12,7 +12,8 @@ function blog_editor_init(name, editor_config) {
|
||||
var input_content_md = $("#input-" + name + "_content_md");
|
||||
var input_is_hidden = $("#input-" + name + "_is_hidden");
|
||||
var this_form = input_is_hidden[0].form;
|
||||
|
||||
var div_container_editor = $("#div_container-" + name + "_content_md");
|
||||
|
||||
var is_saved;
|
||||
var last_save_done = true;
|
||||
|
||||
@ -77,35 +78,109 @@ function blog_editor_init(name, editor_config) {
|
||||
|
||||
set_saved(true);
|
||||
|
||||
// init codemirror
|
||||
// init editor
|
||||
if (input_content_md[0]) {
|
||||
input_content_md.wrap('<div class="blog-content-md-editor"></div>');
|
||||
var blog_contend_md_editor = input_content_md.parent();
|
||||
input_content_md.before($('<div class="blog-content-md-editor-toolbar"></div>')
|
||||
.append(toolbar)
|
||||
);
|
||||
input_content_md.wrap('<div class="blog-content-md-editor-in"></div>');
|
||||
div_container_editor.empty();
|
||||
div_container_editor.wrap('<div class="blog-content-md-editor"></div>');
|
||||
var blog_contend_md_editor = div_container_editor.parent();
|
||||
blog_contend_md_editor.prepend($('<div class="blog-content-md-editor-toolbar"></div>').append(toolbar));
|
||||
div_container_editor.wrap('<div class="blog-content-md-editor-in border"></div>');
|
||||
div_container_editor.append($('<div class="border d-flex justify-content-center align-items-center" style="width: 100%; height: 500px;" />').append('<div class="spinner-border text-muted" style="width: 3rem; height: 3rem;" />'));
|
||||
|
||||
var codeeditor;
|
||||
if (editor_config.type == 'blog') {
|
||||
codeeditor = CodeMirror.fromTextArea(input_content_md[0], {
|
||||
mode: 'gfm',
|
||||
lineNumbers: true,
|
||||
matchBrackets: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
theme: 'default'
|
||||
require_monaco({}, function() {
|
||||
$(div_container_editor).empty();
|
||||
|
||||
var monaco_editor_instance = monaco.editor.create(div_container_editor[0], {
|
||||
language: editor_config.type == 'slide' ? 'yaml' : 'markdown',
|
||||
automaticLayout: true,
|
||||
fontSize: "16px",
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
wordWrap: 'on',
|
||||
theme: 'vs',
|
||||
});
|
||||
} else if (editor_config.type == 'slide') {
|
||||
codeeditor = CodeMirror.fromTextArea(input_content_md[0], {
|
||||
mode: 'plain',
|
||||
lineNumbers: true,
|
||||
matchBrackets: true,
|
||||
lineWrapping: true,
|
||||
styleActiveLine: true,
|
||||
theme: 'default'
|
||||
|
||||
monaco_editor_instance.getModel().setValue(input_content_md.val());
|
||||
|
||||
monaco_editor_instance.onDidChangeModelContent(function () {
|
||||
set_saved(false);
|
||||
input_content_md.val(monaco_editor_instance.getModel().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
function add_around(sl, sr) {
|
||||
var selection = monaco_editor_instance.getSelection();
|
||||
var selection_value = monaco_editor_instance.getModel().getValueInRange(selection);
|
||||
|
||||
monaco_editor_instance.executeEdits(sl + selection_value + sr, [{
|
||||
range: selection,
|
||||
text: sl + selection_value + sr,
|
||||
forceMoveMarkers: true,
|
||||
}]);
|
||||
}
|
||||
|
||||
bold_btn.click(function() {
|
||||
add_around("**", "**");
|
||||
monaco_editor_instance.focus();
|
||||
});
|
||||
|
||||
italic_btn.click(function() {
|
||||
add_around("_", "_");
|
||||
monaco_editor_instance.focus();
|
||||
});
|
||||
|
||||
monaco_editor_instance.addAction({
|
||||
id: 'save',
|
||||
label: 'Save',
|
||||
keybindings: [
|
||||
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS,
|
||||
],
|
||||
precondition: null,
|
||||
keybindingContext: null,
|
||||
run: function(ed) {
|
||||
save_btn.click();
|
||||
},
|
||||
});
|
||||
|
||||
monaco_editor_instance.addAction({
|
||||
id: 'bold',
|
||||
label: 'Bold',
|
||||
keybindings: [
|
||||
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyB,
|
||||
],
|
||||
precondition: null,
|
||||
keybindingContext: null,
|
||||
run: function(ed) {
|
||||
bold_btn.click();
|
||||
},
|
||||
});
|
||||
|
||||
monaco_editor_instance.addAction({
|
||||
id: 'preview',
|
||||
label: 'Preview',
|
||||
keybindings: [
|
||||
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyD,
|
||||
],
|
||||
precondition: null,
|
||||
keybindingContext: null,
|
||||
run: function(ed) {
|
||||
preview_btn.click();
|
||||
},
|
||||
});
|
||||
|
||||
monaco_editor_instance.addAction({
|
||||
id: 'italic',
|
||||
label: 'Italic',
|
||||
keybindings: [
|
||||
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyI,
|
||||
],
|
||||
precondition: null,
|
||||
keybindingContext: null,
|
||||
run: function(ed) {
|
||||
italic_btn.click();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function preview(html) {
|
||||
@ -219,17 +294,8 @@ function blog_editor_init(name, editor_config) {
|
||||
config.done();
|
||||
});
|
||||
}
|
||||
function add_around(sl, sr) {
|
||||
codeeditor.replaceSelection(sl + codeeditor.getSelection() + sr);
|
||||
}
|
||||
|
||||
// event
|
||||
if (input_content_md[0]) {
|
||||
codeeditor.on('change', function() {
|
||||
codeeditor.save();
|
||||
set_saved(false);
|
||||
});
|
||||
}
|
||||
$.merge(input_title, input_tags).on('input', function() {
|
||||
set_saved(false);
|
||||
});
|
||||
@ -251,19 +317,10 @@ function blog_editor_init(name, editor_config) {
|
||||
blog_contend_md_editor.find('.blog-content-md-editor-preview').slideUp('fast', function() {
|
||||
$(this).remove();
|
||||
});
|
||||
codeeditor.focus();
|
||||
} else {
|
||||
save({need_preview: true});
|
||||
}
|
||||
});
|
||||
bold_btn.click(function() {
|
||||
add_around("**", "**");
|
||||
codeeditor.focus();
|
||||
});
|
||||
italic_btn.click(function() {
|
||||
add_around("*", "*");
|
||||
codeeditor.focus();
|
||||
});
|
||||
input_is_hidden.on('switchChange.bootstrapSwitch', function(e, state) {
|
||||
var ok = true;
|
||||
if (!state && !confirm("你确定要公开吗?")) {
|
||||
@ -289,22 +346,6 @@ function blog_editor_init(name, editor_config) {
|
||||
});
|
||||
|
||||
// init hot keys
|
||||
if (input_content_md[0]) {
|
||||
codeeditor.setOption("extraKeys", {
|
||||
"Ctrl-S": function(cm) {
|
||||
save_btn.click();
|
||||
},
|
||||
"Ctrl-B": function(cm) {
|
||||
bold_btn.click();
|
||||
},
|
||||
"Ctrl-D": function(cm) {
|
||||
preview_btn.click();
|
||||
},
|
||||
"Ctrl-I": function(cm) {
|
||||
italic_btn.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
$(document).bind('keydown', 'ctrl+d', function() {
|
||||
preview_btn.click();
|
||||
return false;
|
||||
|
183
web/js/codemirror/addon/comment/comment.js
vendored
183
web/js/codemirror/addon/comment/comment.js
vendored
@ -1,183 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var noOptions = {};
|
||||
var nonWS = /[^\s\u00a0]/;
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function firstNonWS(str) {
|
||||
var found = str.search(nonWS);
|
||||
return found == -1 ? 0 : found;
|
||||
}
|
||||
|
||||
CodeMirror.commands.toggleComment = function(cm) {
|
||||
var minLine = Infinity, ranges = cm.listSelections(), mode = null;
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var from = ranges[i].from(), to = ranges[i].to();
|
||||
if (from.line >= minLine) continue;
|
||||
if (to.line >= minLine) to = Pos(minLine, 0);
|
||||
minLine = from.line;
|
||||
if (mode == null) {
|
||||
if (cm.uncomment(from, to)) mode = "un";
|
||||
else { cm.lineComment(from, to); mode = "line"; }
|
||||
} else if (mode == "un") {
|
||||
cm.uncomment(from, to);
|
||||
} else {
|
||||
cm.lineComment(from, to);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.defineExtension("lineComment", function(from, to, options) {
|
||||
if (!options) options = noOptions;
|
||||
var self = this, mode = self.getModeAt(from);
|
||||
var commentString = options.lineComment || mode.lineComment;
|
||||
if (!commentString) {
|
||||
if (options.blockCommentStart || mode.blockCommentStart) {
|
||||
options.fullLines = true;
|
||||
self.blockComment(from, to, options);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var firstLine = self.getLine(from.line);
|
||||
if (firstLine == null) return;
|
||||
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
|
||||
var pad = options.padding == null ? " " : options.padding;
|
||||
var blankLines = options.commentBlankLines || from.line == to.line;
|
||||
|
||||
self.operation(function() {
|
||||
if (options.indent) {
|
||||
var baseString = firstLine.slice(0, firstNonWS(firstLine));
|
||||
for (var i = from.line; i < end; ++i) {
|
||||
var line = self.getLine(i), cut = baseString.length;
|
||||
if (!blankLines && !nonWS.test(line)) continue;
|
||||
if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
|
||||
self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
|
||||
}
|
||||
} else {
|
||||
for (var i = from.line; i < end; ++i) {
|
||||
if (blankLines || nonWS.test(self.getLine(i)))
|
||||
self.replaceRange(commentString + pad, Pos(i, 0));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("blockComment", function(from, to, options) {
|
||||
if (!options) options = noOptions;
|
||||
var self = this, mode = self.getModeAt(from);
|
||||
var startString = options.blockCommentStart || mode.blockCommentStart;
|
||||
var endString = options.blockCommentEnd || mode.blockCommentEnd;
|
||||
if (!startString || !endString) {
|
||||
if ((options.lineComment || mode.lineComment) && options.fullLines != false)
|
||||
self.lineComment(from, to, options);
|
||||
return;
|
||||
}
|
||||
|
||||
var end = Math.min(to.line, self.lastLine());
|
||||
if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
|
||||
|
||||
var pad = options.padding == null ? " " : options.padding;
|
||||
if (from.line > end) return;
|
||||
|
||||
self.operation(function() {
|
||||
if (options.fullLines != false) {
|
||||
var lastLineHasText = nonWS.test(self.getLine(end));
|
||||
self.replaceRange(pad + endString, Pos(end));
|
||||
self.replaceRange(startString + pad, Pos(from.line, 0));
|
||||
var lead = options.blockCommentLead || mode.blockCommentLead;
|
||||
if (lead != null) for (var i = from.line + 1; i <= end; ++i)
|
||||
if (i != end || lastLineHasText)
|
||||
self.replaceRange(lead + pad, Pos(i, 0));
|
||||
} else {
|
||||
self.replaceRange(endString, to);
|
||||
self.replaceRange(startString, from);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("uncomment", function(from, to, options) {
|
||||
if (!options) options = noOptions;
|
||||
var self = this, mode = self.getModeAt(from);
|
||||
var end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end);
|
||||
|
||||
// Try finding line comments
|
||||
var lineString = options.lineComment || mode.lineComment, lines = [];
|
||||
var pad = options.padding == null ? " " : options.padding, didSomething;
|
||||
lineComment: {
|
||||
if (!lineString) break lineComment;
|
||||
for (var i = start; i <= end; ++i) {
|
||||
var line = self.getLine(i);
|
||||
var found = line.indexOf(lineString);
|
||||
if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
|
||||
if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment;
|
||||
if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
|
||||
lines.push(line);
|
||||
}
|
||||
self.operation(function() {
|
||||
for (var i = start; i <= end; ++i) {
|
||||
var line = lines[i - start];
|
||||
var pos = line.indexOf(lineString), endPos = pos + lineString.length;
|
||||
if (pos < 0) continue;
|
||||
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
|
||||
didSomething = true;
|
||||
self.replaceRange("", Pos(i, pos), Pos(i, endPos));
|
||||
}
|
||||
});
|
||||
if (didSomething) return true;
|
||||
}
|
||||
|
||||
// Try block comments
|
||||
var startString = options.blockCommentStart || mode.blockCommentStart;
|
||||
var endString = options.blockCommentEnd || mode.blockCommentEnd;
|
||||
if (!startString || !endString) return false;
|
||||
var lead = options.blockCommentLead || mode.blockCommentLead;
|
||||
var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end);
|
||||
var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString);
|
||||
if (close == -1 && start != end) {
|
||||
endLine = self.getLine(--end);
|
||||
close = endLine.lastIndexOf(endString);
|
||||
}
|
||||
if (open == -1 || close == -1 ||
|
||||
!/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) ||
|
||||
!/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))
|
||||
return false;
|
||||
|
||||
// Avoid killing block comments completely outside the selection.
|
||||
// Positions of the last startString before the start of the selection, and the first endString after it.
|
||||
var lastStart = startLine.lastIndexOf(startString, from.ch);
|
||||
var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);
|
||||
if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false;
|
||||
// Positions of the first endString after the end of the selection, and the last startString before it.
|
||||
firstEnd = endLine.indexOf(endString, to.ch);
|
||||
var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
|
||||
lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
|
||||
if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;
|
||||
|
||||
self.operation(function() {
|
||||
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
|
||||
Pos(end, close + endString.length));
|
||||
var openEnd = open + startString.length;
|
||||
if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
|
||||
self.replaceRange("", Pos(start, open), Pos(start, openEnd));
|
||||
if (lead) for (var i = start + 1; i <= end; ++i) {
|
||||
var line = self.getLine(i), found = line.indexOf(lead);
|
||||
if (found == -1 || nonWS.test(line.slice(0, found))) continue;
|
||||
var foundEnd = found + lead.length;
|
||||
if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
|
||||
self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
});
|
@ -1,85 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
var modes = ["clike", "css", "javascript"];
|
||||
|
||||
for (var i = 0; i < modes.length; ++i)
|
||||
CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "});
|
||||
|
||||
function continueComment(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections(), mode, inserts = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var pos = ranges[i].head, token = cm.getTokenAt(pos);
|
||||
if (token.type != "comment") return CodeMirror.Pass;
|
||||
var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode;
|
||||
if (!mode) mode = modeHere;
|
||||
else if (mode != modeHere) return CodeMirror.Pass;
|
||||
|
||||
var insert = null;
|
||||
if (mode.blockCommentStart && mode.blockCommentContinue) {
|
||||
var end = token.string.indexOf(mode.blockCommentEnd);
|
||||
var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found;
|
||||
if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) {
|
||||
// Comment ended, don't continue it
|
||||
} else if (token.string.indexOf(mode.blockCommentStart) == 0) {
|
||||
insert = full.slice(0, token.start);
|
||||
if (!/^\s*$/.test(insert)) {
|
||||
insert = "";
|
||||
for (var j = 0; j < token.start; ++j) insert += " ";
|
||||
}
|
||||
} else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 &&
|
||||
found + mode.blockCommentContinue.length > token.start &&
|
||||
/^\s*$/.test(full.slice(0, found))) {
|
||||
insert = full.slice(0, found);
|
||||
}
|
||||
if (insert != null) insert += mode.blockCommentContinue;
|
||||
}
|
||||
if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) {
|
||||
var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment);
|
||||
if (found > -1) {
|
||||
insert = line.slice(0, found);
|
||||
if (/\S/.test(insert)) insert = null;
|
||||
else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0];
|
||||
}
|
||||
}
|
||||
if (insert == null) return CodeMirror.Pass;
|
||||
inserts[i] = "\n" + insert;
|
||||
}
|
||||
|
||||
cm.operation(function() {
|
||||
for (var i = ranges.length - 1; i >= 0; i--)
|
||||
cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert");
|
||||
});
|
||||
}
|
||||
|
||||
function continueLineCommentEnabled(cm) {
|
||||
var opt = cm.getOption("continueComments");
|
||||
if (opt && typeof opt == "object")
|
||||
return opt.continueLineComment !== false;
|
||||
return true;
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
|
||||
if (prev && prev != CodeMirror.Init)
|
||||
cm.removeKeyMap("continueComment");
|
||||
if (val) {
|
||||
var key = "Enter";
|
||||
if (typeof val == "string")
|
||||
key = val;
|
||||
else if (typeof val == "object" && val.key)
|
||||
key = val.key;
|
||||
var map = {name: "continueComment"};
|
||||
map[key] = continueComment;
|
||||
cm.addKeyMap(map);
|
||||
}
|
||||
});
|
||||
});
|
32
web/js/codemirror/addon/dialog/dialog.css
vendored
32
web/js/codemirror/addon/dialog/dialog.css
vendored
@ -1,32 +0,0 @@
|
||||
.CodeMirror-dialog {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
background: white;
|
||||
z-index: 15;
|
||||
padding: .1em .8em;
|
||||
overflow: hidden;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog-top {
|
||||
border-bottom: 1px solid #eee;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog-bottom {
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog input {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
width: 20em;
|
||||
color: inherit;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog button {
|
||||
font-size: 70%;
|
||||
}
|
152
web/js/codemirror/addon/dialog/dialog.js
vendored
152
web/js/codemirror/addon/dialog/dialog.js
vendored
@ -1,152 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// Open simple dialogs on top of an editor. Relies on dialog.css.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
function dialogDiv(cm, template, bottom) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
var dialog;
|
||||
dialog = wrap.appendChild(document.createElement("div"));
|
||||
if (bottom)
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
|
||||
else
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
|
||||
|
||||
if (typeof template == "string") {
|
||||
dialog.innerHTML = template;
|
||||
} else { // Assuming it's a detached DOM element.
|
||||
dialog.appendChild(template);
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
function closeNotification(cm, newVal) {
|
||||
if (cm.state.currentNotificationClose)
|
||||
cm.state.currentNotificationClose();
|
||||
cm.state.currentNotificationClose = newVal;
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
|
||||
if (!options) options = {};
|
||||
|
||||
closeNotification(this, null);
|
||||
|
||||
var dialog = dialogDiv(this, template, options.bottom);
|
||||
var closed = false, me = this;
|
||||
function close(newVal) {
|
||||
if (typeof newVal == 'string') {
|
||||
inp.value = newVal;
|
||||
} else {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
|
||||
if (options.onClose) options.onClose(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
var inp = dialog.getElementsByTagName("input")[0], button;
|
||||
if (inp) {
|
||||
if (options.value) inp.value = options.value;
|
||||
|
||||
if (options.onInput)
|
||||
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
|
||||
if (options.onKeyUp)
|
||||
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
|
||||
|
||||
CodeMirror.on(inp, "keydown", function(e) {
|
||||
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
|
||||
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
|
||||
inp.blur();
|
||||
CodeMirror.e_stop(e);
|
||||
close();
|
||||
}
|
||||
if (e.keyCode == 13) callback(inp.value);
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
|
||||
|
||||
inp.focus();
|
||||
} else if (button = dialog.getElementsByTagName("button")[0]) {
|
||||
CodeMirror.on(button, "click", function() {
|
||||
close();
|
||||
me.focus();
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
|
||||
|
||||
button.focus();
|
||||
}
|
||||
return close;
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
|
||||
closeNotification(this, null);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var buttons = dialog.getElementsByTagName("button");
|
||||
var closed = false, me = this, blurring = 1;
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
}
|
||||
buttons[0].focus();
|
||||
for (var i = 0; i < buttons.length; ++i) {
|
||||
var b = buttons[i];
|
||||
(function(callback) {
|
||||
CodeMirror.on(b, "click", function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
if (callback) callback(me);
|
||||
});
|
||||
})(callbacks[i]);
|
||||
CodeMirror.on(b, "blur", function() {
|
||||
--blurring;
|
||||
setTimeout(function() { if (blurring <= 0) close(); }, 200);
|
||||
});
|
||||
CodeMirror.on(b, "focus", function() { ++blurring; });
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* openNotification
|
||||
* Opens a notification, that can be closed with an optional timer
|
||||
* (default 5000ms timer) and always closes on click.
|
||||
*
|
||||
* If a notification is opened while another is opened, it will close the
|
||||
* currently opened one and open the new one immediately.
|
||||
*/
|
||||
CodeMirror.defineExtension("openNotification", function(template, options) {
|
||||
closeNotification(this, close);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var closed = false, doneTimer;
|
||||
var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
|
||||
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
clearTimeout(doneTimer);
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
}
|
||||
|
||||
CodeMirror.on(dialog, 'click', function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
});
|
||||
|
||||
if (duration)
|
||||
doneTimer = setTimeout(close, duration);
|
||||
|
||||
return close;
|
||||
});
|
||||
});
|
@ -1,6 +0,0 @@
|
||||
.CodeMirror-fullscreen {
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
height: auto;
|
||||
z-index: 9;
|
||||
}
|
41
web/js/codemirror/addon/display/fullscreen.js
vendored
41
web/js/codemirror/addon/display/fullscreen.js
vendored
@ -1,41 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("fullScreen", false, function(cm, val, old) {
|
||||
if (old == CodeMirror.Init) old = false;
|
||||
if (!old == !val) return;
|
||||
if (val) setFullscreen(cm);
|
||||
else setNormal(cm);
|
||||
});
|
||||
|
||||
function setFullscreen(cm) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
|
||||
width: wrap.style.width, height: wrap.style.height};
|
||||
wrap.style.width = "";
|
||||
wrap.style.height = "auto";
|
||||
wrap.className += " CodeMirror-fullscreen";
|
||||
document.documentElement.style.overflow = "hidden";
|
||||
cm.refresh();
|
||||
}
|
||||
|
||||
function setNormal(cm) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, "");
|
||||
document.documentElement.style.overflow = "";
|
||||
var info = cm.state.fullScreenRestore;
|
||||
wrap.style.width = info.width; wrap.style.height = info.height;
|
||||
window.scrollTo(info.scrollLeft, info.scrollTop);
|
||||
cm.refresh();
|
||||
}
|
||||
});
|
58
web/js/codemirror/addon/display/placeholder.js
vendored
58
web/js/codemirror/addon/display/placeholder.js
vendored
@ -1,58 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
|
||||
var prev = old && old != CodeMirror.Init;
|
||||
if (val && !prev) {
|
||||
cm.on("blur", onBlur);
|
||||
cm.on("change", onChange);
|
||||
onChange(cm);
|
||||
} else if (!val && prev) {
|
||||
cm.off("blur", onBlur);
|
||||
cm.off("change", onChange);
|
||||
clearPlaceholder(cm);
|
||||
var wrapper = cm.getWrapperElement();
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
|
||||
}
|
||||
|
||||
if (val && !cm.hasFocus()) onBlur(cm);
|
||||
});
|
||||
|
||||
function clearPlaceholder(cm) {
|
||||
if (cm.state.placeholder) {
|
||||
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
|
||||
cm.state.placeholder = null;
|
||||
}
|
||||
}
|
||||
function setPlaceholder(cm) {
|
||||
clearPlaceholder(cm);
|
||||
var elt = cm.state.placeholder = document.createElement("pre");
|
||||
elt.style.cssText = "height: 0; overflow: visible";
|
||||
elt.className = "CodeMirror-placeholder";
|
||||
elt.appendChild(document.createTextNode(cm.getOption("placeholder")));
|
||||
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
|
||||
}
|
||||
|
||||
function onBlur(cm) {
|
||||
if (isEmpty(cm)) setPlaceholder(cm);
|
||||
}
|
||||
function onChange(cm) {
|
||||
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
|
||||
|
||||
if (empty) setPlaceholder(cm);
|
||||
else clearPlaceholder(cm);
|
||||
}
|
||||
|
||||
function isEmpty(cm) {
|
||||
return (cm.lineCount() === 1) && (cm.getLine(0) === "");
|
||||
}
|
||||
});
|
64
web/js/codemirror/addon/display/rulers.js
vendored
64
web/js/codemirror/addon/display/rulers.js
vendored
@ -1,64 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("rulers", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
clearRulers(cm);
|
||||
cm.off("refresh", refreshRulers);
|
||||
}
|
||||
if (val && val.length) {
|
||||
setRulers(cm);
|
||||
cm.on("refresh", refreshRulers);
|
||||
}
|
||||
});
|
||||
|
||||
function clearRulers(cm) {
|
||||
for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) {
|
||||
var node = cm.display.lineSpace.childNodes[i];
|
||||
if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className))
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
function setRulers(cm) {
|
||||
var val = cm.getOption("rulers");
|
||||
var cw = cm.defaultCharWidth();
|
||||
var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left;
|
||||
var minH = cm.display.scroller.offsetHeight + 30;
|
||||
for (var i = 0; i < val.length; i++) {
|
||||
var elt = document.createElement("div");
|
||||
elt.className = "CodeMirror-ruler";
|
||||
var col, cls = null, conf = val[i];
|
||||
if (typeof conf == "number") {
|
||||
col = conf;
|
||||
} else {
|
||||
col = conf.column;
|
||||
if (conf.className) elt.className += " " + conf.className;
|
||||
if (conf.color) elt.style.borderColor = conf.color;
|
||||
if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle;
|
||||
if (conf.width) elt.style.borderLeftWidth = conf.width;
|
||||
cls = val[i].className;
|
||||
}
|
||||
elt.style.left = (left + col * cw) + "px";
|
||||
elt.style.top = "-50px";
|
||||
elt.style.bottom = "-20px";
|
||||
elt.style.minHeight = minH + "px";
|
||||
cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv);
|
||||
}
|
||||
}
|
||||
|
||||
function refreshRulers(cm) {
|
||||
clearRulers(cm);
|
||||
setRulers(cm);
|
||||
}
|
||||
});
|
158
web/js/codemirror/addon/edit/closebrackets.js
vendored
158
web/js/codemirror/addon/edit/closebrackets.js
vendored
@ -1,158 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
var DEFAULT_BRACKETS = "()[]{}''\"\"";
|
||||
var DEFAULT_EXPLODE_ON_ENTER = "[]{}";
|
||||
var SPACE_CHAR_REGEX = /\s/;
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
|
||||
if (old != CodeMirror.Init && old)
|
||||
cm.removeKeyMap("autoCloseBrackets");
|
||||
if (!val) return;
|
||||
var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER;
|
||||
if (typeof val == "string") pairs = val;
|
||||
else if (typeof val == "object") {
|
||||
if (val.pairs != null) pairs = val.pairs;
|
||||
if (val.explode != null) explode = val.explode;
|
||||
}
|
||||
var map = buildKeymap(pairs);
|
||||
if (explode) map.Enter = buildExplodeHandler(explode);
|
||||
cm.addKeyMap(map);
|
||||
});
|
||||
|
||||
function charsAround(cm, pos) {
|
||||
var str = cm.getRange(Pos(pos.line, pos.ch - 1),
|
||||
Pos(pos.line, pos.ch + 1));
|
||||
return str.length == 2 ? str : null;
|
||||
}
|
||||
|
||||
// Project the token type that will exists after the given char is
|
||||
// typed, and use it to determine whether it would cause the start
|
||||
// of a string token.
|
||||
function enteringString(cm, pos, ch) {
|
||||
var line = cm.getLine(pos.line);
|
||||
var token = cm.getTokenAt(pos);
|
||||
if (/\bstring2?\b/.test(token.type)) return false;
|
||||
var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);
|
||||
stream.pos = stream.start = token.start;
|
||||
for (;;) {
|
||||
var type1 = cm.getMode().token(stream, token.state);
|
||||
if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1);
|
||||
stream.start = stream.pos;
|
||||
}
|
||||
}
|
||||
|
||||
function buildKeymap(pairs) {
|
||||
var map = {
|
||||
name : "autoCloseBrackets",
|
||||
Backspace: function(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var around = charsAround(cm, ranges[i].head);
|
||||
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
||||
}
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var cur = ranges[i].head;
|
||||
cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1));
|
||||
}
|
||||
}
|
||||
};
|
||||
var closingBrackets = "";
|
||||
for (var i = 0; i < pairs.length; i += 2) (function(left, right) {
|
||||
if (left != right) closingBrackets += right;
|
||||
map["'" + left + "'"] = function(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections(), type, next;
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i], cur = range.head, curType;
|
||||
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
|
||||
if (!range.empty())
|
||||
curType = "surround";
|
||||
else if (left == right && next == right) {
|
||||
if (cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == left + left + left)
|
||||
curType = "skipThree";
|
||||
else
|
||||
curType = "skip";
|
||||
} else if (left == right && cur.ch > 1 &&
|
||||
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left &&
|
||||
(cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != left))
|
||||
curType = "addFour";
|
||||
else if (left == '"' || left == "'") {
|
||||
if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, left)) curType = "both";
|
||||
else return CodeMirror.Pass;
|
||||
} else if (cm.getLine(cur.line).length == cur.ch || closingBrackets.indexOf(next) >= 0 || SPACE_CHAR_REGEX.test(next))
|
||||
curType = "both";
|
||||
else
|
||||
return CodeMirror.Pass;
|
||||
if (!type) type = curType;
|
||||
else if (type != curType) return CodeMirror.Pass;
|
||||
}
|
||||
|
||||
cm.operation(function() {
|
||||
if (type == "skip") {
|
||||
cm.execCommand("goCharRight");
|
||||
} else if (type == "skipThree") {
|
||||
for (var i = 0; i < 3; i++)
|
||||
cm.execCommand("goCharRight");
|
||||
} else if (type == "surround") {
|
||||
var sels = cm.getSelections();
|
||||
for (var i = 0; i < sels.length; i++)
|
||||
sels[i] = left + sels[i] + right;
|
||||
cm.replaceSelections(sels, "around");
|
||||
} else if (type == "both") {
|
||||
cm.replaceSelection(left + right, null);
|
||||
cm.execCommand("goCharLeft");
|
||||
} else if (type == "addFour") {
|
||||
cm.replaceSelection(left + left + left + left, "before");
|
||||
cm.execCommand("goCharRight");
|
||||
}
|
||||
});
|
||||
};
|
||||
if (left != right) map["'" + right + "'"] = function(cm) {
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i];
|
||||
if (!range.empty() ||
|
||||
cm.getRange(range.head, Pos(range.head.line, range.head.ch + 1)) != right)
|
||||
return CodeMirror.Pass;
|
||||
}
|
||||
cm.execCommand("goCharRight");
|
||||
};
|
||||
})(pairs.charAt(i), pairs.charAt(i + 1));
|
||||
return map;
|
||||
}
|
||||
|
||||
function buildExplodeHandler(pairs) {
|
||||
return function(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var around = charsAround(cm, ranges[i].head);
|
||||
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
||||
}
|
||||
cm.operation(function() {
|
||||
cm.replaceSelection("\n\n", null);
|
||||
cm.execCommand("goCharLeft");
|
||||
ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var line = ranges[i].head.line;
|
||||
cm.indentLine(line, null, true);
|
||||
cm.indentLine(line + 1, null, true);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
159
web/js/codemirror/addon/edit/closetag.js
vendored
159
web/js/codemirror/addon/edit/closetag.js
vendored
@ -1,159 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
/**
|
||||
* Tag-closer extension for CodeMirror.
|
||||
*
|
||||
* This extension adds an "autoCloseTags" option that can be set to
|
||||
* either true to get the default behavior, or an object to further
|
||||
* configure its behavior.
|
||||
*
|
||||
* These are supported options:
|
||||
*
|
||||
* `whenClosing` (default true)
|
||||
* Whether to autoclose when the '/' of a closing tag is typed.
|
||||
* `whenOpening` (default true)
|
||||
* Whether to autoclose the tag when the final '>' of an opening
|
||||
* tag is typed.
|
||||
* `dontCloseTags` (default is empty tags for HTML, none for XML)
|
||||
* An array of tag names that should not be autoclosed.
|
||||
* `indentTags` (default is block tags for HTML, none for XML)
|
||||
* An array of tag names that should, when opened, cause a
|
||||
* blank line to be added inside the tag, and the blank line and
|
||||
* closing line to be indented.
|
||||
*
|
||||
* See demos/closetag.html for a usage example.
|
||||
*/
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../fold/xml-fold"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
|
||||
if (old != CodeMirror.Init && old)
|
||||
cm.removeKeyMap("autoCloseTags");
|
||||
if (!val) return;
|
||||
var map = {name: "autoCloseTags"};
|
||||
if (typeof val != "object" || val.whenClosing)
|
||||
map["'/'"] = function(cm) { return autoCloseSlash(cm); };
|
||||
if (typeof val != "object" || val.whenOpening)
|
||||
map["'>'"] = function(cm) { return autoCloseGT(cm); };
|
||||
cm.addKeyMap(map);
|
||||
});
|
||||
|
||||
var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
|
||||
"source", "track", "wbr"];
|
||||
var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
|
||||
"h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
|
||||
|
||||
function autoCloseGT(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections(), replacements = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var pos = ranges[i].head, tok = cm.getTokenAt(pos);
|
||||
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
|
||||
if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
|
||||
|
||||
var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
|
||||
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
|
||||
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
|
||||
|
||||
var tagName = state.tagName;
|
||||
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
|
||||
var lowerTagName = tagName.toLowerCase();
|
||||
// Don't process the '>' at the end of an end-tag or self-closing tag
|
||||
if (!tagName ||
|
||||
tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
|
||||
tok. |