Skip to content

Commit f12f573

Browse files
committed
[closetag addon] Define a closeTag command that closes the nearest open tag
Closes codemirror#3028
1 parent 6d8de27 commit f12f573

File tree

2 files changed

+20
-9
lines changed

2 files changed

+20
-9
lines changed

addon/edit/closetag.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,32 +94,32 @@
9494
}
9595
}
9696

97-
function autoCloseSlash(cm) {
98-
if (cm.getOption("disableInput")) return CodeMirror.Pass;
97+
function autoCloseCurrent(cm, typingSlash) {
9998
var ranges = cm.listSelections(), replacements = [];
99+
var head = typingSlash ? "/" : "</";
100100
for (var i = 0; i < ranges.length; i++) {
101101
if (!ranges[i].empty()) return CodeMirror.Pass;
102102
var pos = ranges[i].head, tok = cm.getTokenAt(pos);
103103
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
104-
if (tok.type == "string" || tok.string.charAt(0) != "<" ||
105-
tok.start != pos.ch - 1)
104+
if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" ||
105+
tok.start != pos.ch - 1))
106106
return CodeMirror.Pass;
107107
// Kludge to get around the fact that we are not in XML mode
108108
// when completing in JS/CSS snippet in htmlmixed mode. Does not
109109
// work for other XML embedded languages (there is no general
110110
// way to go from a mixed mode to its current XML state).
111111
if (inner.mode.name != "xml") {
112112
if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript")
113-
replacements[i] = "/script>";
113+
replacements[i] = head + "script>";
114114
else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css")
115-
replacements[i] = "/style>";
115+
replacements[i] = head + "style>";
116116
else
117117
return CodeMirror.Pass;
118118
} else {
119119
if (!state.context || !state.context.tagName ||
120120
closingTagExists(cm, state.context.tagName, pos, state))
121121
return CodeMirror.Pass;
122-
replacements[i] = "/" + state.context.tagName + ">";
122+
replacements[i] = head + state.context.tagName + ">";
123123
}
124124
}
125125
cm.replaceSelections(replacements);
@@ -129,6 +129,13 @@
129129
cm.indentLine(ranges[i].head.line);
130130
}
131131

132+
function autoCloseSlash(cm) {
133+
if (cm.getOption("disableInput")) return CodeMirror.Pass;
134+
autoCloseCurrent(cm, true);
135+
}
136+
137+
CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };
138+
132139
function indexOf(collection, elt) {
133140
if (collection.indexOf) return collection.indexOf(elt);
134141
for (var i = 0, e = collection.length; i < e; ++i)

doc/manual.html

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,8 +2232,12 @@ <h2 id="addons">Addons</h2>
22322232
squiggly underline style for this class.</dd>
22332233

22342234
<dt id="addon_closetag"><a href="../addon/edit/closetag.js"><code>edit/closetag.js</code></a></dt>
2235-
<dd>Provides utility functions for adding automatic tag closing
2236-
to XML modes. See
2235+
<dd>Defines an <code>autoCloseTags</code> option that will
2236+
auto-close XML tags when '<code>&gt;</code>' or '<code>/</code>'
2237+
is typed, and
2238+
a <code>closeTag</code> <a href="#commands">command</a> that
2239+
closes the nearest open tag. Depends on
2240+
the <code>fold/xml-fold.js</code> addon. See
22372241
the <a href="../demo/closetag.html">demo</a>.</dd>
22382242

22392243
<dt id="addon_continuelist"><a href="../addon/edit/continuelist.js"><code>edit/continuelist.js</code></a></dt>

0 commit comments

Comments
 (0)