htmlmixed.js 4.2 KB

123456789101112131415161718192021222324252627
  1. (function(mod){if(typeof exports=="object"&&typeof module=="object")
  2. mod(require("../../lib/codemirror"),require("../xml/xml"),require("../javascript/javascript"),require("../css/css"));else if(typeof define=="function"&&define.amd)
  3. define(["../../lib/codemirror","../xml/xml","../javascript/javascript","../css/css"],mod);else
  4. 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);}
  5. return style;}
  6. var attrRegexpCache={};function getAttrRegexp(attr){var regexp=attrRegexpCache[attr];if(regexp)return regexp;return attrRegexpCache[attr]=new RegExp("\\s+"+attr+"\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");}
  7. function getAttrValue(text,attr){var match=text.match(getAttrRegexp(attr))
  8. return match?/^\s*(.*?)\s*$/.exec(match[2])[1]:""}
  9. function getTagRegexp(tagName,anchored){return new RegExp((anchored?"^":"")+"<\/\s*"+tagName+"\s*>","i");}
  10. 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--)
  11. dest.unshift(source[i])}}
  12. 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];}}
  13. CodeMirror.defineMode("htmlmixed",function(config,parserConfig){var htmlMode=CodeMirror.getMode(config,{name:"xml",htmlMode:true,multilineTagIndentFactor:parserConfig.multilineTagIndentFactor,multilineTagIndentPastTag:parserConfig.multilineTagIndentPastTag});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--)
  14. tags.script.unshift(["type",configScript[i].matches,configScript[i].mode])
  15. function html(stream,state){var style=htmlMode.token(stream,state.htmlState),tag=/\btag\b/.test(style),tagName
  16. 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)
  17. state.inTag=null
  18. var modeSpec=stream.current()==">"&&findMatchingMode(tags[inTag[1]],inTag[2])
  19. var mode=CodeMirror.getMode(config,modeSpec)
  20. 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;}
  21. 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()
  22. if(stream.eol())state.inTag+=" "}
  23. 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);}
  24. 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))
  25. return htmlMode.indent(state.htmlState,textAfter,line);else if(state.localMode.indent)
  26. return state.localMode.indent(state.localState,textAfter,line);else
  27. return CodeMirror.Pass;},innerMode:function(state){return{state:state.localState||state.htmlState,mode:state.localMode||htmlMode};}};},"xml","javascript","css");CodeMirror.defineMIME("text/html","htmlmixed");});