[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 // Distributed under an MIT license: https://codemirror.net/5/LICENSE 3 4 /** 5 * Tag-closer extension for CodeMirror. 6 * 7 * This extension adds an "autoCloseTags" option that can be set to 8 * either true to get the default behavior, or an object to further 9 * configure its behavior. 10 * 11 * These are supported options: 12 * 13 * `whenClosing` (default true) 14 * Whether to autoclose when the '/' of a closing tag is typed. 15 * `whenOpening` (default true) 16 * Whether to autoclose the tag when the final '>' of an opening 17 * tag is typed. 18 * `dontCloseTags` (default is empty tags for HTML, none for XML) 19 * An array of tag names that should not be autoclosed. 20 * `indentTags` (default is block tags for HTML, none for XML) 21 * An array of tag names that should, when opened, cause a 22 * blank line to be added inside the tag, and the blank line and 23 * closing line to be indented. 24 * `emptyTags` (default is none) 25 * An array of XML tag names that should be autoclosed with '/>'. 26 * 27 * See demos/closetag.html for a usage example. 28 */ 29 30 (function(mod) { 31 if (typeof exports == "object" && typeof module == "object") // CommonJS 32 mod(require("../../lib/codemirror"), require("../fold/xml-fold")); 33 else if (typeof define == "function" && define.amd) // AMD 34 define(["../../lib/codemirror", "../fold/xml-fold"], mod); 35 else // Plain browser env 36 mod(CodeMirror); 37 })(function(CodeMirror) { 38 CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) { 39 if (old != CodeMirror.Init && old) 40 cm.removeKeyMap("autoCloseTags"); 41 if (!val) return; 42 var map = {name: "autoCloseTags"}; 43 if (typeof val != "object" || val.whenClosing !== false) 44 map["'/'"] = function(cm) { return autoCloseSlash(cm); }; 45 if (typeof val != "object" || val.whenOpening !== false) 46 map["'>'"] = function(cm) { return autoCloseGT(cm); }; 47 cm.addKeyMap(map); 48 }); 49 50 var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", 51 "source", "track", "wbr"]; 52 var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", 53 "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; 54 55 function autoCloseGT(cm) { 56 if (cm.getOption("disableInput")) return CodeMirror.Pass; 57 var ranges = cm.listSelections(), replacements = []; 58 var opt = cm.getOption("autoCloseTags"); 59 for (var i = 0; i < ranges.length; i++) { 60 if (!ranges[i].empty()) return CodeMirror.Pass; 61 var pos = ranges[i].head, tok = cm.getTokenAt(pos); 62 var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; 63 var tagInfo = inner.mode.xmlCurrentTag && inner.mode.xmlCurrentTag(state) 64 var tagName = tagInfo && tagInfo.name 65 if (!tagName) return CodeMirror.Pass 66 67 var html = inner.mode.configuration == "html"; 68 var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); 69 var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); 70 71 if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); 72 var lowerTagName = tagName.toLowerCase(); 73 // Don't process the '>' at the end of an end-tag or self-closing tag 74 if (!tagName || 75 tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || 76 tok.type == "tag" && tagInfo.close || 77 tok.string.indexOf("/") == (pos.ch - tok.start - 1) || // match something like <someTagName /> 78 dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || 79 closingTagExists(cm, inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) || [], tagName, pos, true)) 80 return CodeMirror.Pass; 81 82 var emptyTags = typeof opt == "object" && opt.emptyTags; 83 if (emptyTags && indexOf(emptyTags, tagName) > -1) { 84 replacements[i] = { text: "/>", newPos: CodeMirror.Pos(pos.line, pos.ch + 2) }; 85 continue; 86 } 87 88 var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; 89 replacements[i] = {indent: indent, 90 text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">", 91 newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; 92 } 93 94 var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose); 95 for (var i = ranges.length - 1; i >= 0; i--) { 96 var info = replacements[i]; 97 cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); 98 var sel = cm.listSelections().slice(0); 99 sel[i] = {head: info.newPos, anchor: info.newPos}; 100 cm.setSelections(sel); 101 if (!dontIndentOnAutoClose && info.indent) { 102 cm.indentLine(info.newPos.line, null, true); 103 cm.indentLine(info.newPos.line + 1, null, true); 104 } 105 } 106 } 107 108 function autoCloseCurrent(cm, typingSlash) { 109 var ranges = cm.listSelections(), replacements = []; 110 var head = typingSlash ? "/" : "</"; 111 var opt = cm.getOption("autoCloseTags"); 112 var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnSlash); 113 for (var i = 0; i < ranges.length; i++) { 114 if (!ranges[i].empty()) return CodeMirror.Pass; 115 var pos = ranges[i].head, tok = cm.getTokenAt(pos); 116 var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; 117 if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" || 118 tok.start != pos.ch - 1)) 119 return CodeMirror.Pass; 120 // Kludge to get around the fact that we are not in XML mode 121 // when completing in JS/CSS snippet in htmlmixed mode. Does not 122 // work for other XML embedded languages (there is no general 123 // way to go from a mixed mode to its current XML state). 124 var replacement, mixed = inner.mode.name != "xml" && cm.getMode().name == "htmlmixed" 125 if (mixed && inner.mode.name == "javascript") { 126 replacement = head + "script"; 127 } else if (mixed && inner.mode.name == "css") { 128 replacement = head + "style"; 129 } else { 130 var context = inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) 131 var top = context.length ? context[context.length - 1] : "" 132 if (!context || (context.length && closingTagExists(cm, context, top, pos))) 133 return CodeMirror.Pass; 134 replacement = head + top 135 } 136 if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">"; 137 replacements[i] = replacement; 138 } 139 cm.replaceSelections(replacements); 140 ranges = cm.listSelections(); 141 if (!dontIndentOnAutoClose) { 142 for (var i = 0; i < ranges.length; i++) 143 if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line) 144 cm.indentLine(ranges[i].head.line); 145 } 146 } 147 148 function autoCloseSlash(cm) { 149 if (cm.getOption("disableInput")) return CodeMirror.Pass; 150 return autoCloseCurrent(cm, true); 151 } 152 153 CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); }; 154 155 function indexOf(collection, elt) { 156 if (collection.indexOf) return collection.indexOf(elt); 157 for (var i = 0, e = collection.length; i < e; ++i) 158 if (collection[i] == elt) return i; 159 return -1; 160 } 161 162 // If xml-fold is loaded, we use its functionality to try and verify 163 // whether a given tag is actually unclosed. 164 function closingTagExists(cm, context, tagName, pos, newTag) { 165 if (!CodeMirror.scanForClosingTag) return false; 166 var end = Math.min(cm.lastLine() + 1, pos.line + 500); 167 var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); 168 if (!nextClose || nextClose.tag != tagName) return false; 169 // If the immediate wrapping context contains onCx instances of 170 // the same tag, a closing tag only exists if there are at least 171 // that many closing tags of that type following. 172 var onCx = newTag ? 1 : 0 173 for (var i = context.length - 1; i >= 0; i--) { 174 if (context[i] == tagName) ++onCx 175 else break 176 } 177 pos = nextClose.to; 178 for (var i = 1; i < onCx; i++) { 179 var next = CodeMirror.scanForClosingTag(cm, pos, null, end); 180 if (!next || next.tag != tagName) return false; 181 pos = next.to; 182 } 183 return true; 184 } 185 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |