-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0e46e44
commit 7f26b2e
Showing
2 changed files
with
1,034 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,369 @@ | ||
/*can-view-parser@3.8.1#can-view-parser*/ | ||
define([ | ||
'require', | ||
'exports', | ||
'module', | ||
'can-namespace', | ||
'can-log/dev', | ||
'can-attribute-encoder' | ||
], function (require, exports, module) { | ||
var namespace = require('can-namespace'), dev = require('can-log/dev'), encoder = require('can-attribute-encoder'); | ||
function each(items, callback) { | ||
for (var i = 0; i < items.length; i++) { | ||
callback(items[i], i); | ||
} | ||
} | ||
function makeMap(str) { | ||
var obj = {}, items = str.split(','); | ||
each(items, function (name) { | ||
obj[name] = true; | ||
}); | ||
return obj; | ||
} | ||
function handleIntermediate(intermediate, handler) { | ||
for (var i = 0, len = intermediate.length; i < len; i++) { | ||
var item = intermediate[i]; | ||
handler[item.tokenType].apply(handler, item.args); | ||
} | ||
return intermediate; | ||
} | ||
var alphaNumeric = 'A-Za-z0-9', alphaNumericHU = '-:_' + alphaNumeric, defaultMagicStart = '{{', endTag = new RegExp('^<\\/([' + alphaNumericHU + ']+)[^>]*>'), defaultMagicMatch = new RegExp('\\{\\{(![\\s\\S]*?!|[\\s\\S]*?)\\}\\}\\}?', 'g'), space = /\s/, alphaRegex = new RegExp('[' + alphaNumeric + ']'), attributeRegexp = new RegExp('[' + alphaNumericHU + ']+s*=s*("[^"]*"|\'[^\']*\')'); | ||
var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed'); | ||
var caseMattersElements = makeMap('altGlyph,altGlyphDef,altGlyphItem,animateColor,animateMotion,animateTransform,clipPath,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,foreignObject,glyphRef,linearGradient,radialGradient,textPath'); | ||
var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); | ||
var special = makeMap('script'); | ||
var tokenTypes = 'start,end,close,attrStart,attrEnd,attrValue,chars,comment,special,done'.split(','); | ||
var startOppositesMap = { | ||
'{': '}', | ||
'(': ')' | ||
}; | ||
var fn = function () { | ||
}; | ||
var HTMLParser = function (html, handler, returnIntermediate) { | ||
if (typeof html === 'object') { | ||
return handleIntermediate(html, handler); | ||
} | ||
var intermediate = []; | ||
handler = handler || {}; | ||
if (returnIntermediate) { | ||
each(tokenTypes, function (name) { | ||
var callback = handler[name] || fn; | ||
handler[name] = function () { | ||
if (callback.apply(this, arguments) !== false) { | ||
var end = arguments.length; | ||
if (arguments[end - 1] === undefined) { | ||
end = arguments.length - 1; | ||
} | ||
intermediate.push({ | ||
tokenType: name, | ||
args: [].slice.call(arguments, 0, end) | ||
}); | ||
} | ||
}; | ||
}); | ||
} | ||
var magicMatch = handler.magicMatch || defaultMagicMatch, magicStart = handler.magicStart || defaultMagicStart; | ||
if (handler.magicMatch) { | ||
dev.warn('can-view-parser: magicMatch is deprecated.'); | ||
} | ||
if (handler.magicStart) { | ||
dev.warn('can-view-parser: magicStart is deprecated.'); | ||
} | ||
function parseStartTag(tag, tagName, rest, unary) { | ||
tagName = caseMattersElements[tagName] ? tagName : tagName.toLowerCase(); | ||
if (closeSelf[tagName] && stack.last() === tagName) { | ||
parseEndTag('', tagName); | ||
} | ||
unary = empty[tagName] || !!unary; | ||
handler.start(tagName, unary, lineNo); | ||
if (!unary) { | ||
stack.push(tagName); | ||
} | ||
HTMLParser.parseAttrs(rest, handler, lineNo); | ||
handler.end(tagName, unary, lineNo); | ||
} | ||
function parseEndTag(tag, tagName) { | ||
var pos; | ||
if (!tagName) { | ||
pos = 0; | ||
} else { | ||
tagName = caseMattersElements[tagName] ? tagName : tagName.toLowerCase(); | ||
for (pos = stack.length - 1; pos >= 0; pos--) { | ||
if (stack[pos] === tagName) { | ||
break; | ||
} | ||
} | ||
} | ||
if (pos >= 0) { | ||
for (var i = stack.length - 1; i >= pos; i--) { | ||
if (handler.close) { | ||
handler.close(stack[i], lineNo); | ||
} | ||
} | ||
stack.length = pos; | ||
} | ||
} | ||
function parseMustache(mustache, inside) { | ||
if (handler.special) { | ||
handler.special(inside, lineNo); | ||
} | ||
} | ||
var callChars = function () { | ||
if (charsText) { | ||
if (handler.chars) { | ||
handler.chars(charsText, lineNo); | ||
} | ||
} | ||
charsText = ''; | ||
}; | ||
var index, chars, match, lineNo, stack = [], last = html, charsText = ''; | ||
stack.last = function () { | ||
return this[this.length - 1]; | ||
}; | ||
while (html) { | ||
chars = true; | ||
if (!stack.last() || !special[stack.last()]) { | ||
if (html.indexOf('<!--') === 0) { | ||
index = html.indexOf('-->'); | ||
if (index >= 0) { | ||
callChars(); | ||
if (handler.comment) { | ||
handler.comment(html.substring(4, index), lineNo); | ||
} | ||
html = html.substring(index + 3); | ||
chars = false; | ||
} | ||
} else if (html.indexOf('</') === 0) { | ||
match = html.match(endTag); | ||
if (match) { | ||
callChars(); | ||
match[0].replace(endTag, parseEndTag); | ||
html = html.substring(match[0].length); | ||
chars = false; | ||
} | ||
} else if (html.indexOf('<') === 0) { | ||
var res = HTMLParser.searchStartTag(html); | ||
if (res) { | ||
callChars(); | ||
parseStartTag.apply(null, res.match); | ||
html = res.html; | ||
chars = false; | ||
} | ||
} else if (html.indexOf(magicStart) === 0) { | ||
match = html.match(magicMatch); | ||
if (match) { | ||
callChars(); | ||
match[0].replace(magicMatch, parseMustache); | ||
html = html.substring(match[0].length); | ||
} | ||
} | ||
if (chars) { | ||
index = findBreak(html, magicStart); | ||
if (index === 0 && html === last) { | ||
charsText += html.charAt(0); | ||
html = html.substr(1); | ||
index = findBreak(html, magicStart); | ||
} | ||
var text = index < 0 ? html : html.substring(0, index); | ||
html = index < 0 ? '' : html.substring(index); | ||
if (text) { | ||
charsText += text; | ||
} | ||
} | ||
} else { | ||
html = html.replace(new RegExp('([\\s\\S]*?)</' + stack.last() + '[^>]*>'), function (all, text) { | ||
text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, '$1$2'); | ||
if (handler.chars) { | ||
handler.chars(text, lineNo); | ||
} | ||
return ''; | ||
}); | ||
parseEndTag('', stack.last()); | ||
} | ||
if (html === last) { | ||
throw new Error('Parse Error: ' + html); | ||
} | ||
last = html; | ||
} | ||
callChars(); | ||
parseEndTag(); | ||
handler.done(lineNo); | ||
return intermediate; | ||
}; | ||
var callAttrStart = function (state, curIndex, handler, rest, lineNo) { | ||
var attrName = rest.substring(typeof state.nameStart === 'number' ? state.nameStart : curIndex, curIndex), newAttrName = encoder.encode(attrName); | ||
state.attrStart = newAttrName; | ||
handler.attrStart(state.attrStart, lineNo); | ||
state.inName = false; | ||
}; | ||
var callAttrEnd = function (state, curIndex, handler, rest, lineNo) { | ||
if (state.valueStart !== undefined && state.valueStart < curIndex) { | ||
var val = rest.substring(state.valueStart, curIndex); | ||
handler.attrValue(val, lineNo); | ||
} | ||
handler.attrEnd(state.attrStart, lineNo); | ||
state.attrStart = undefined; | ||
state.valueStart = undefined; | ||
state.inValue = false; | ||
state.inName = false; | ||
state.lookingForEq = false; | ||
state.inQuote = false; | ||
state.lookingForName = true; | ||
}; | ||
var findBreak = function (str, magicStart) { | ||
var magicLength = magicStart.length; | ||
for (var i = 0, len = str.length; i < len; i++) { | ||
if (str[i] === '<' || str.substr(i, magicLength) === magicStart) { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
}; | ||
HTMLParser.parseAttrs = function (rest, handler, lineNo) { | ||
if (!rest) { | ||
return; | ||
} | ||
var magicMatch = handler.magicMatch || defaultMagicMatch, magicStart = handler.magicStart || defaultMagicStart; | ||
var i = 0; | ||
var curIndex; | ||
var state = { | ||
inName: false, | ||
nameStart: undefined, | ||
inValue: false, | ||
valueStart: undefined, | ||
inQuote: false, | ||
attrStart: undefined, | ||
lookingForName: true, | ||
lookingForValue: false, | ||
lookingForEq: false | ||
}; | ||
while (i < rest.length) { | ||
curIndex = i; | ||
var cur = rest.charAt(i); | ||
i++; | ||
if (magicStart === rest.substr(curIndex, magicStart.length)) { | ||
if (state.inValue && curIndex > state.valueStart) { | ||
handler.attrValue(rest.substring(state.valueStart, curIndex), lineNo); | ||
} else if (state.inName && state.nameStart < curIndex) { | ||
callAttrStart(state, curIndex, handler, rest, lineNo); | ||
callAttrEnd(state, curIndex, handler, rest, lineNo); | ||
} else if (state.lookingForValue) { | ||
state.inValue = true; | ||
} else if (state.lookingForEq && state.attrStart) { | ||
callAttrEnd(state, curIndex, handler, rest, lineNo); | ||
} | ||
magicMatch.lastIndex = curIndex; | ||
var match = magicMatch.exec(rest); | ||
if (match) { | ||
handler.special(match[1], lineNo); | ||
i = curIndex + match[0].length; | ||
if (state.inValue) { | ||
state.valueStart = curIndex + match[0].length; | ||
} | ||
} | ||
} else if (state.inValue) { | ||
if (state.inQuote) { | ||
if (cur === state.inQuote) { | ||
callAttrEnd(state, curIndex, handler, rest, lineNo); | ||
} | ||
} else if (space.test(cur)) { | ||
callAttrEnd(state, curIndex, handler, rest, lineNo); | ||
} | ||
} else if (cur === '=' && (state.lookingForEq || state.lookingForName || state.inName)) { | ||
if (!state.attrStart) { | ||
callAttrStart(state, curIndex, handler, rest, lineNo); | ||
} | ||
state.lookingForValue = true; | ||
state.lookingForEq = false; | ||
state.lookingForName = false; | ||
} else if (state.inName) { | ||
var started = rest[state.nameStart], otherStart, otherOpposite; | ||
if (startOppositesMap[started] === cur) { | ||
otherStart = started === '{' ? '(' : '{'; | ||
otherOpposite = startOppositesMap[otherStart]; | ||
if (rest[curIndex + 1] === otherOpposite) { | ||
callAttrStart(state, curIndex + 2, handler, rest, lineNo); | ||
i++; | ||
} else { | ||
callAttrStart(state, curIndex + 1, handler, rest, lineNo); | ||
} | ||
state.lookingForEq = true; | ||
} else if (space.test(cur) && started !== '{' && started !== '(') { | ||
callAttrStart(state, curIndex, handler, rest, lineNo); | ||
state.lookingForEq = true; | ||
} | ||
} else if (state.lookingForName) { | ||
if (!space.test(cur)) { | ||
if (state.attrStart) { | ||
callAttrEnd(state, curIndex, handler, rest, lineNo); | ||
} | ||
state.nameStart = curIndex; | ||
state.inName = true; | ||
} | ||
} else if (state.lookingForValue) { | ||
if (!space.test(cur)) { | ||
state.lookingForValue = false; | ||
state.inValue = true; | ||
if (cur === '\'' || cur === '"') { | ||
state.inQuote = cur; | ||
state.valueStart = curIndex + 1; | ||
} else { | ||
state.valueStart = curIndex; | ||
} | ||
} else if (i === rest.length) { | ||
callAttrEnd(state, curIndex, handler, rest, lineNo); | ||
} | ||
} | ||
} | ||
if (state.inName) { | ||
callAttrStart(state, curIndex + 1, handler, rest, lineNo); | ||
callAttrEnd(state, curIndex + 1, handler, rest, lineNo); | ||
} else if (state.lookingForEq || state.lookingForValue || state.inValue) { | ||
callAttrEnd(state, curIndex + 1, handler, rest, lineNo); | ||
} | ||
magicMatch.lastIndex = 0; | ||
}; | ||
HTMLParser.searchStartTag = function (html) { | ||
var closingIndex = html.indexOf('>'); | ||
var attributeRange = attributeRegexp.exec(html.substring(1)); | ||
var afterAttributeOffset = 1; | ||
while (attributeRange && closingIndex >= afterAttributeOffset + attributeRange.index) { | ||
afterAttributeOffset += attributeRange.index + attributeRange[0].length; | ||
while (closingIndex < afterAttributeOffset) { | ||
closingIndex += html.substring(closingIndex + 1).indexOf('>') + 1; | ||
} | ||
attributeRange = attributeRegexp.exec(html.substring(afterAttributeOffset)); | ||
} | ||
if (closingIndex === -1 || !alphaRegex.test(html[1])) { | ||
return null; | ||
} | ||
var tagName, tagContent, match, rest = '', unary = ''; | ||
var startTag = html.substring(0, closingIndex + 1); | ||
var isUnary = startTag[startTag.length - 2] === '/'; | ||
var spaceIndex = startTag.search(space); | ||
if (isUnary) { | ||
unary = '/'; | ||
tagContent = startTag.substring(1, startTag.length - 2).trim(); | ||
} else { | ||
tagContent = startTag.substring(1, startTag.length - 1).trim(); | ||
} | ||
if (spaceIndex === -1) { | ||
tagName = tagContent; | ||
} else { | ||
spaceIndex--; | ||
tagName = tagContent.substring(0, spaceIndex); | ||
rest = tagContent.substring(spaceIndex); | ||
} | ||
match = [ | ||
startTag, | ||
tagName, | ||
rest, | ||
unary | ||
]; | ||
return { | ||
match: match, | ||
html: html.substring(startTag.length) | ||
}; | ||
}; | ||
module.exports = namespace.HTMLParser = HTMLParser; | ||
}); |
Oops, something went wrong.