123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- // 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'))
- else if (typeof define == 'function' && define.amd)
- // AMD
- define(['../../lib/codemirror'], mod)
- // Plain browser env
- else mod(CodeMirror)
- })(function (CodeMirror) {
- 'use strict'
- var htmlConfig = {
- autoSelfClosers: {
- area: true,
- base: true,
- br: true,
- col: true,
- command: true,
- embed: true,
- frame: true,
- hr: true,
- img: true,
- input: true,
- keygen: true,
- link: true,
- meta: true,
- param: true,
- source: true,
- track: true,
- wbr: true,
- menuitem: true,
- },
- implicitlyClosed: { dd: true, li: true, optgroup: true, option: true, p: true, rp: true, rt: true, tbody: true, td: true, tfoot: true, th: true, tr: true },
- contextGrabbers: {
- dd: { dd: true, dt: true },
- dt: { dd: true, dt: true },
- li: { li: true },
- option: { option: true, optgroup: true },
- optgroup: { optgroup: true },
- p: {
- address: true,
- article: true,
- aside: true,
- blockquote: true,
- dir: true,
- div: true,
- dl: true,
- fieldset: true,
- footer: true,
- form: true,
- h1: true,
- h2: true,
- h3: true,
- h4: true,
- h5: true,
- h6: true,
- header: true,
- hgroup: true,
- hr: true,
- menu: true,
- nav: true,
- ol: true,
- p: true,
- pre: true,
- section: true,
- table: true,
- ul: true,
- },
- rp: { rp: true, rt: true },
- rt: { rp: true, rt: true },
- tbody: { tbody: true, tfoot: true },
- td: { td: true, th: true },
- tfoot: { tbody: true },
- th: { td: true, th: true },
- thead: { tbody: true, tfoot: true },
- tr: { tr: true },
- },
- doNotIndent: { pre: true },
- allowUnquoted: true,
- allowMissing: true,
- caseFold: true,
- }
- var xmlConfig = {
- autoSelfClosers: {},
- implicitlyClosed: {},
- contextGrabbers: {},
- doNotIndent: {},
- allowUnquoted: false,
- allowMissing: false,
- allowMissingTagName: false,
- caseFold: false,
- }
- CodeMirror.defineMode('xml', function (editorConf, config_) {
- var indentUnit = editorConf.indentUnit
- var config = {}
- var defaults = config_.htmlMode ? htmlConfig : xmlConfig
- for (var prop in defaults) config[prop] = defaults[prop]
- for (var prop in config_) config[prop] = config_[prop]
- // Return variables for tokenizers
- var type, setStyle
- function inText(stream, state) {
- function chain(parser) {
- state.tokenize = parser
- return parser(stream, state)
- }
- var ch = stream.next()
- if (ch == '<') {
- if (stream.eat('!')) {
- if (stream.eat('[')) {
- if (stream.match('CDATA[')) return chain(inBlock('atom', ']]>'))
- else return null
- } else if (stream.match('--')) {
- return chain(inBlock('comment', '-->'))
- } else if (stream.match('DOCTYPE', true, true)) {
- stream.eatWhile(/[\w\._\-]/)
- return chain(doctype(1))
- } else {
- return null
- }
- } else if (stream.eat('?')) {
- stream.eatWhile(/[\w\._\-]/)
- state.tokenize = inBlock('meta', '?>')
- return 'meta'
- } else {
- type = stream.eat('/') ? 'closeTag' : 'openTag'
- state.tokenize = inTag
- return 'tag bracket'
- }
- } else if (ch == '&') {
- var ok
- if (stream.eat('#')) {
- if (stream.eat('x')) {
- ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(';')
- } else {
- ok = stream.eatWhile(/[\d]/) && stream.eat(';')
- }
- } else {
- ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(';')
- }
- return ok ? 'atom' : 'error'
- } else {
- stream.eatWhile(/[^&<]/)
- return null
- }
- }
- inText.isInText = true
- function inTag(stream, state) {
- var ch = stream.next()
- if (ch == '>' || (ch == '/' && stream.eat('>'))) {
- state.tokenize = inText
- type = ch == '>' ? 'endTag' : 'selfcloseTag'
- return 'tag bracket'
- } else if (ch == '=') {
- type = 'equals'
- return null
- } else if (ch == '<') {
- state.tokenize = inText
- state.state = baseState
- state.tagName = state.tagStart = null
- var next = state.tokenize(stream, state)
- return next ? next + ' tag error' : 'tag error'
- } else if (/[\'\"]/.test(ch)) {
- state.tokenize = inAttribute(ch)
- state.stringStartCol = stream.column()
- return state.tokenize(stream, state)
- } else {
- stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/)
- return 'word'
- }
- }
- function inAttribute(quote) {
- var closure = function (stream, state) {
- while (!stream.eol()) {
- if (stream.next() == quote) {
- state.tokenize = inTag
- break
- }
- }
- return 'string'
- }
- closure.isInAttribute = true
- return closure
- }
- function inBlock(style, terminator) {
- return function (stream, state) {
- while (!stream.eol()) {
- if (stream.match(terminator)) {
- state.tokenize = inText
- break
- }
- stream.next()
- }
- return style
- }
- }
- function doctype(depth) {
- return function (stream, state) {
- var ch
- while ((ch = stream.next()) != null) {
- if (ch == '<') {
- state.tokenize = doctype(depth + 1)
- return state.tokenize(stream, state)
- } else if (ch == '>') {
- if (depth == 1) {
- state.tokenize = inText
- break
- } else {
- state.tokenize = doctype(depth - 1)
- return state.tokenize(stream, state)
- }
- }
- }
- return 'meta'
- }
- }
- function lower(tagName) {
- return tagName && tagName.toLowerCase()
- }
- function Context(state, tagName, startOfLine) {
- this.prev = state.context
- this.tagName = tagName || ''
- this.indent = state.indented
- this.startOfLine = startOfLine
- if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) this.noIndent = true
- }
- function popContext(state) {
- if (state.context) state.context = state.context.prev
- }
- function maybePopContext(state, nextTagName) {
- var parentTagName
- while (true) {
- if (!state.context) {
- return
- }
- parentTagName = state.context.tagName
- if (!config.contextGrabbers.hasOwnProperty(lower(parentTagName)) || !config.contextGrabbers[lower(parentTagName)].hasOwnProperty(lower(nextTagName))) {
- return
- }
- popContext(state)
- }
- }
- function baseState(type, stream, state) {
- if (type == 'openTag') {
- state.tagStart = stream.column()
- return tagNameState
- } else if (type == 'closeTag') {
- return closeTagNameState
- } else {
- return baseState
- }
- }
- function tagNameState(type, stream, state) {
- if (type == 'word') {
- state.tagName = stream.current()
- setStyle = 'tag'
- return attrState
- } else if (config.allowMissingTagName && type == 'endTag') {
- setStyle = 'tag bracket'
- return attrState(type, stream, state)
- } else {
- setStyle = 'error'
- return tagNameState
- }
- }
- function closeTagNameState(type, stream, state) {
- if (type == 'word') {
- var tagName = stream.current()
- if (state.context && state.context.tagName != tagName && config.implicitlyClosed.hasOwnProperty(lower(state.context.tagName))) popContext(state)
- if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
- setStyle = 'tag'
- return closeState
- } else {
- setStyle = 'tag error'
- return closeStateErr
- }
- } else if (config.allowMissingTagName && type == 'endTag') {
- setStyle = 'tag bracket'
- return closeState(type, stream, state)
- } else {
- setStyle = 'error'
- return closeStateErr
- }
- }
- function closeState(type, _stream, state) {
- if (type != 'endTag') {
- setStyle = 'error'
- return closeState
- }
- popContext(state)
- return baseState
- }
- function closeStateErr(type, stream, state) {
- setStyle = 'error'
- return closeState(type, stream, state)
- }
- function attrState(type, _stream, state) {
- if (type == 'word') {
- setStyle = 'attribute'
- return attrEqState
- } else if (type == 'endTag' || type == 'selfcloseTag') {
- var tagName = state.tagName,
- tagStart = state.tagStart
- state.tagName = state.tagStart = null
- if (type == 'selfcloseTag' || config.autoSelfClosers.hasOwnProperty(lower(tagName))) {
- maybePopContext(state, tagName)
- } else {
- maybePopContext(state, tagName)
- state.context = new Context(state, tagName, tagStart == state.indented)
- }
- return baseState
- }
- setStyle = 'error'
- return attrState
- }
- function attrEqState(type, stream, state) {
- if (type == 'equals') return attrValueState
- if (!config.allowMissing) setStyle = 'error'
- return attrState(type, stream, state)
- }
- function attrValueState(type, stream, state) {
- if (type == 'string') return attrContinuedState
- if (type == 'word' && config.allowUnquoted) {
- setStyle = 'string'
- return attrState
- }
- setStyle = 'error'
- return attrState(type, stream, state)
- }
- function attrContinuedState(type, stream, state) {
- if (type == 'string') return attrContinuedState
- return attrState(type, stream, state)
- }
- return {
- startState: function (baseIndent) {
- var state = { tokenize: inText, state: baseState, indented: baseIndent || 0, tagName: null, tagStart: null, context: null }
- if (baseIndent != null) state.baseIndent = baseIndent
- return state
- },
- token: function (stream, state) {
- if (!state.tagName && stream.sol()) state.indented = stream.indentation()
- if (stream.eatSpace()) return null
- type = null
- var style = state.tokenize(stream, state)
- if ((style || type) && style != 'comment') {
- setStyle = null
- state.state = state.state(type || style, stream, state)
- if (setStyle) style = setStyle == 'error' ? style + ' error' : setStyle
- }
- return style
- },
- indent: function (state, textAfter, fullLine) {
- var context = state.context
- // Indent multi-line strings (e.g. css).
- if (state.tokenize.isInAttribute) {
- if (state.tagStart == state.indented) return state.stringStartCol + 1
- else return state.indented + indentUnit
- }
- if (context && context.noIndent) return CodeMirror.Pass
- if (state.tokenize != inTag && state.tokenize != inText) return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0
- // Indent the starts of attribute names.
- if (state.tagName) {
- if (config.multilineTagIndentPastTag !== false) return state.tagStart + state.tagName.length + 2
- else return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1)
- }
- if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0
- var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter)
- if (tagAfter && tagAfter[1]) {
- // Closing tag spotted
- while (context) {
- if (context.tagName == tagAfter[2]) {
- context = context.prev
- break
- } else if (config.implicitlyClosed.hasOwnProperty(lower(context.tagName))) {
- context = context.prev
- } else {
- break
- }
- }
- } else if (tagAfter) {
- // Opening tag spotted
- while (context) {
- var grabbers = config.contextGrabbers[lower(context.tagName)]
- if (grabbers && grabbers.hasOwnProperty(lower(tagAfter[2]))) context = context.prev
- else break
- }
- }
- while (context && context.prev && !context.startOfLine) context = context.prev
- if (context) return context.indent + indentUnit
- else return state.baseIndent || 0
- },
- electricInput: /<\/[\s\w:]+>$/,
- blockCommentStart: '<!--',
- blockCommentEnd: '-->',
- configuration: config.htmlMode ? 'html' : 'xml',
- helperType: config.htmlMode ? 'html' : 'xml',
- skipAttribute: function (state) {
- if (state.state == attrValueState) state.state = attrState
- },
- xmlCurrentTag: function (state) {
- return state.tagName ? { name: state.tagName, close: state.type == 'closeTag' } : null
- },
- xmlCurrentContext: function (state) {
- var context = []
- for (var cx = state.context; cx; cx = cx.prev) context.push(cx.tagName)
- return context.reverse()
- },
- }
- })
- CodeMirror.defineMIME('text/xml', 'xml')
- CodeMirror.defineMIME('application/xml', 'xml')
- if (!CodeMirror.mimeModes.hasOwnProperty('text/html')) CodeMirror.defineMIME('text/html', { name: 'xml', htmlMode: true })
- })
|