github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/app/public/codemirror/mode/htmlmixed/htmlmixed.js (about) 1 // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 // Distributed under an MIT license: http://codemirror.net/LICENSE 3 4 (function(mod) { 5 if (typeof exports == "object" && typeof module == "object") // CommonJS 6 mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css")); 7 else if (typeof define == "function" && define.amd) // AMD 8 define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod); 9 else // Plain browser env 10 mod(CodeMirror); 11 })(function(CodeMirror) { 12 "use strict"; 13 14 var defaultTags = { 15 script: [ 16 ["lang", /(javascript|babel)/i, "javascript"], 17 ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, "javascript"], 18 ["type", /./, "text/plain"], 19 [null, null, "javascript"] 20 ], 21 style: [ 22 ["lang", /^css$/i, "css"], 23 ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"], 24 ["type", /./, "text/plain"], 25 [null, null, "css"] 26 ] 27 }; 28 29 function maybeBackup(stream, pat, style) { 30 var cur = stream.current(), close = cur.search(pat); 31 if (close > -1) { 32 stream.backUp(cur.length - close); 33 } else if (cur.match(/<\/?$/)) { 34 stream.backUp(cur.length); 35 if (!stream.match(pat, false)) stream.match(cur); 36 } 37 return style; 38 } 39 40 var attrRegexpCache = {}; 41 function getAttrRegexp(attr) { 42 var regexp = attrRegexpCache[attr]; 43 if (regexp) return regexp; 44 return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"); 45 } 46 47 function getAttrValue(stream, attr) { 48 var pos = stream.pos, match; 49 while (pos >= 0 && stream.string.charAt(pos) !== "<") pos--; 50 if (pos < 0) return pos; 51 if (match = stream.string.slice(pos, stream.pos).match(getAttrRegexp(attr))) 52 return match[2]; 53 return ""; 54 } 55 56 function getTagRegexp(tagName, anchored) { 57 return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i"); 58 } 59 60 function addTags(from, to) { 61 for (var tag in from) { 62 var dest = to[tag] || (to[tag] = []); 63 var source = from[tag]; 64 for (var i = source.length - 1; i >= 0; i--) 65 dest.unshift(source[i]) 66 } 67 } 68 69 function findMatchingMode(tagInfo, stream) { 70 for (var i = 0; i < tagInfo.length; i++) { 71 var spec = tagInfo[i]; 72 if (!spec[0] || spec[1].test(getAttrValue(stream, spec[0]))) return spec[2]; 73 } 74 } 75 76 CodeMirror.defineMode("htmlmixed", function (config, parserConfig) { 77 var htmlMode = CodeMirror.getMode(config, { 78 name: "xml", 79 htmlMode: true, 80 multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, 81 multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag 82 }); 83 84 var tags = {}; 85 var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes; 86 addTags(defaultTags, tags); 87 if (configTags) addTags(configTags, tags); 88 if (configScript) for (var i = configScript.length - 1; i >= 0; i--) 89 tags.script.unshift(["type", configScript[i].matches, configScript[i].mode]) 90 91 function html(stream, state) { 92 var tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase(); 93 var tagInfo = tagName && tags.hasOwnProperty(tagName) && tags[tagName]; 94 95 var style = htmlMode.token(stream, state.htmlState), modeSpec; 96 97 if (tagInfo && /\btag\b/.test(style) && stream.current() === ">" && 98 (modeSpec = findMatchingMode(tagInfo, stream))) { 99 var mode = CodeMirror.getMode(config, modeSpec); 100 var endTagA = getTagRegexp(tagName, true), endTag = getTagRegexp(tagName, false); 101 state.token = function (stream, state) { 102 if (stream.match(endTagA, false)) { 103 state.token = html; 104 state.localState = state.localMode = null; 105 return null; 106 } 107 return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState)); 108 }; 109 state.localMode = mode; 110 state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "")); 111 } 112 return style; 113 }; 114 115 return { 116 startState: function () { 117 var state = htmlMode.startState(); 118 return {token: html, localMode: null, localState: null, htmlState: state}; 119 }, 120 121 copyState: function (state) { 122 var local; 123 if (state.localState) { 124 local = CodeMirror.copyState(state.localMode, state.localState); 125 } 126 return {token: state.token, localMode: state.localMode, localState: local, 127 htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; 128 }, 129 130 token: function (stream, state) { 131 return state.token(stream, state); 132 }, 133 134 indent: function (state, textAfter) { 135 if (!state.localMode || /^\s*<\//.test(textAfter)) 136 return htmlMode.indent(state.htmlState, textAfter); 137 else if (state.localMode.indent) 138 return state.localMode.indent(state.localState, textAfter); 139 else 140 return CodeMirror.Pass; 141 }, 142 143 innerMode: function (state) { 144 return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; 145 } 146 }; 147 }, "xml", "javascript", "css"); 148 149 CodeMirror.defineMIME("text/html", "htmlmixed"); 150 });