// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE ;(function (mod) { if (typeof exports == 'object' && typeof module == 'object') // CommonJS mod(require('../../lib/codemirror'), require('../xml/xml'), require('../javascript/javascript'), require('../css/css')) else if (typeof define == 'function' && define.amd) // AMD define(['../../lib/codemirror', '../xml/xml', '../javascript/javascript', '../css/css'], mod) // Plain browser env else mod(CodeMirror) })(function (CodeMirror) { 'use strict' var defaultTags = { script: [ ['lang', /(javascript|babel)/i, 'javascript'], ['type', /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, 'javascript'], ['type', /./, 'text/plain'], [null, null, 'javascript'], ], style: [ ['lang', /^css$/i, 'css'], ['type', /^(text\/)?(x-)?(stylesheet|css)$/i, 'css'], ['type', /./, 'text/plain'], [null, null, 'css'], ], } function maybeBackup(stream, pat, style) { var cur = stream.current(), close = cur.search(pat) if (close > -1) { stream.backUp(cur.length - close) } else if (cur.match(/<\/?$/)) { stream.backUp(cur.length) if (!stream.match(pat, false)) stream.match(cur) } return style } var attrRegexpCache = {} function getAttrRegexp(attr) { var regexp = attrRegexpCache[attr] if (regexp) return regexp return (attrRegexpCache[attr] = new RegExp('\\s+' + attr + '\\s*=\\s*(\'|")?([^\'"]+)(\'|")?\\s*')) } function getAttrValue(text, attr) { var match = text.match(getAttrRegexp(attr)) return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : '' } function getTagRegexp(tagName, anchored) { return new RegExp((anchored ? '^' : '') + '', 'i') } function addTags(from, to) { for (var tag in from) { var dest = to[tag] || (to[tag] = []) var source = from[tag] for (var i = source.length - 1; i >= 0; i--) dest.unshift(source[i]) } } function findMatchingMode(tagInfo, tagText) { for (var i = 0; i < tagInfo.length; i++) { var spec = tagInfo[i] if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2] } } CodeMirror.defineMode( 'htmlmixed', function (config, parserConfig) { var htmlMode = CodeMirror.getMode(config, { name: 'xml', htmlMode: true, multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag, allowMissingTagName: parserConfig.allowMissingTagName, }) var tags = {} var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes addTags(defaultTags, tags) if (configTags) addTags(configTags, tags) if (configScript) for (var i = configScript.length - 1; i >= 0; i--) tags.script.unshift(['type', configScript[i].matches, configScript[i].mode]) function html(stream, state) { var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName if (tag && !/[<>\s\/]/.test(stream.current()) && (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) && tags.hasOwnProperty(tagName)) { state.inTag = tagName + ' ' } else if (state.inTag && tag && />$/.test(stream.current())) { var inTag = /^([\S]+) (.*)/.exec(state.inTag) state.inTag = null var modeSpec = stream.current() == '>' && findMatchingMode(tags[inTag[1]], inTag[2]) var mode = CodeMirror.getMode(config, modeSpec) var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false) state.token = function (stream, state) { if (stream.match(endTagA, false)) { state.token = html state.localState = state.localMode = null return null } return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState)) } state.localMode = mode state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, '', '')) } else if (state.inTag) { state.inTag += stream.current() if (stream.eol()) state.inTag += ' ' } return style } return { startState: function () { var state = CodeMirror.startState(htmlMode) return { token: html, inTag: null, localMode: null, localState: null, htmlState: state } }, copyState: function (state) { var local if (state.localState) { local = CodeMirror.copyState(state.localMode, state.localState) } return { token: state.token, inTag: state.inTag, localMode: state.localMode, localState: local, htmlState: CodeMirror.copyState(htmlMode, state.htmlState) } }, token: function (stream, state) { return state.token(stream, state) }, indent: function (state, textAfter, line) { if (!state.localMode || /^\s*<\//.test(textAfter)) return htmlMode.indent(state.htmlState, textAfter, line) else if (state.localMode.indent) return state.localMode.indent(state.localState, textAfter, line) else return CodeMirror.Pass }, innerMode: function (state) { return { state: state.localState || state.htmlState, mode: state.localMode || htmlMode } }, } }, 'xml', 'javascript', 'css' ) CodeMirror.defineMIME('text/html', 'htmlmixed') })