/* wax - 7.0.1 - v6.0.4-181-ga34788e */ !function (name, context, definition) { //if (typeof module !== 'undefined') module.exports = definition(name, context); //else if (typeof define === 'function' && typeof define.amd === 'object') define(definition); //else context[name] = definition(name, context); context[name] = definition(name, context); }('bean', this, function (name, context) { var win = window , old = context[name] , overOut = /over|out/ , namespaceRegex = /[^\.]*(?=\..*)\.|.*/ , nameRegex = /\..*/ , addEvent = 'addEventListener' , attachEvent = 'attachEvent' , removeEvent = 'removeEventListener' , detachEvent = 'detachEvent' , doc = document || {} , root = doc.documentElement || {} , W3C_MODEL = root[addEvent] , eventSupport = W3C_MODEL ? addEvent : attachEvent , slice = Array.prototype.slice , mouseTypeRegex = /click|mouse(?!(.*wheel|scroll))|menu|drag|drop/i , mouseWheelTypeRegex = /mouse.*(wheel|scroll)/i , textTypeRegex = /^text/i , touchTypeRegex = /^touch|^gesture/i , ONE = { one: 1 } // singleton for quick matching making add() do one() , nativeEvents = (function (hash, events, i) { for (i = 0; i < events.length; i++) hash[events[i]] = 1 return hash })({}, ( 'click dblclick mouseup mousedown contextmenu ' + // mouse buttons 'mousewheel mousemultiwheel DOMMouseScroll ' + // mouse wheel 'mouseover mouseout mousemove selectstart selectend ' + // mouse movement 'keydown keypress keyup ' + // keyboard 'orientationchange ' + // mobile 'focus blur change reset select submit ' + // form elements 'load unload beforeunload resize move DOMContentLoaded readystatechange ' + // window 'error abort scroll ' + // misc (W3C_MODEL ? // element.fireEvent('onXYZ'... is not forgiving if we try to fire an event // that doesn't actually exist, so make sure we only do these on newer browsers 'show ' + // mouse buttons 'input invalid ' + // form elements 'touchstart touchmove touchend touchcancel ' + // touch 'gesturestart gesturechange gestureend ' + // gesture 'MSPointerUp MSPointerDown MSPointerCancel MSPointerMove ' + // MS Pointer events 'MSPointerOver MSPointerOut ' + // MS Pointer events 'pointerup pointerdown pointermove pointercancel' + // MS Pointer events 'message readystatechange pageshow pagehide popstate ' + // window 'hashchange offline online ' + // window 'afterprint beforeprint ' + // printing 'dragstart dragenter dragover dragleave drag drop dragend ' + // dnd 'loadstart progress suspend emptied stalled loadmetadata ' + // media 'loadeddata canplay canplaythrough playing waiting seeking ' + // media 'seeked ended durationchange timeupdate play pause ratechange ' + // media 'volumechange cuechange ' + // media 'checking noupdate downloading cached updateready obsolete ' + // appcache '' : '') ).split(' ') ) , customEvents = (function () { function isDescendant(parent, node) { while ((node = node.parentNode) !== null) { if (node === parent) return true } return false } function check(event) { var related = event.relatedTarget if (!related) return related === null return (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString()) && !isDescendant(this, related)) } return { mouseenter: { base: 'mouseover', condition: check } , mouseleave: { base: 'mouseout', condition: check } , mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' } } })() , fixEvent = (function () { var commonProps = 'altKey attrChange attrName bubbles cancelable ctrlKey currentTarget detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey srcElement target timeStamp type view which'.split(' ') , mouseProps = commonProps.concat('button buttons clientX clientY dataTransfer fromElement offsetX offsetY pageX pageY screenX screenY toElement'.split(' ')) , mouseWheelProps = mouseProps.concat('wheelDelta wheelDeltaX wheelDeltaY wheelDeltaZ axis'.split(' ')) // 'axis' is FF specific , keyProps = commonProps.concat('char charCode key keyCode keyIdentifier keyLocation'.split(' ')) , textProps = commonProps.concat(['data']) , touchProps = commonProps.concat('touches targetTouches changedTouches scale rotation'.split(' ')) , preventDefault = 'preventDefault' , createPreventDefault = function (event) { return function () { if (event[preventDefault]) event[preventDefault]() else event.returnValue = false } } , stopPropagation = 'stopPropagation' , createStopPropagation = function (event) { return function () { if (event[stopPropagation]) event[stopPropagation]() else event.cancelBubble = true } } , createStop = function (synEvent) { return function () { synEvent[preventDefault]() synEvent[stopPropagation]() synEvent.stopped = true } } , copyProps = function (event, result, props) { var i, p for (i = props.length; i--;) { p = props[i] if (!(p in result) && p in event) result[p] = event[p] } } return function (event, isNative) { var result = { originalEvent: event, isNative: isNative } if (!event) return result var props , type = event.type , target = event.target || event.srcElement result[preventDefault] = createPreventDefault(event) result[stopPropagation] = createStopPropagation(event) result.stop = createStop(result) result.target = target && target.nodeType === 3 ? target.parentNode : target if (isNative) { // we only need basic augmentation on custom events, the rest is too expensive if (type.indexOf('key') !== -1) { props = keyProps result.keyCode = event.which || event.keyCode } else if (mouseTypeRegex.test(type)) { props = mouseProps result.rightClick = event.which === 3 || event.button === 2 result.pos = { x: 0, y: 0 } if (event.pageX || event.pageY) { result.clientX = event.pageX result.clientY = event.pageY } else if (event.clientX || event.clientY) { result.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft result.clientY = event.clientY + doc.body.scrollTop + root.scrollTop } if (overOut.test(type)) result.relatedTarget = event.relatedTarget || event[(type === 'mouseover' ? 'from' : 'to') + 'Element'] } else if (touchTypeRegex.test(type)) { props = touchProps } else if (mouseWheelTypeRegex.test(type)) { props = mouseWheelProps } else if (textTypeRegex.test(type)) { props = textProps } copyProps(event, result, props || commonProps) } return result } })() // if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both , targetElement = function (element, isNative) { return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element } // we use one of these per listener, of any type , RegEntry = (function () { function entry(element, type, handler, original, namespaces) { this.element = element this.type = type this.handler = handler this.original = original this.namespaces = namespaces this.custom = customEvents[type] this.isNative = nativeEvents[type] && element[eventSupport] this.eventType = W3C_MODEL || this.isNative ? type : 'propertychange' this.customType = !W3C_MODEL && !this.isNative && type this.target = targetElement(element, this.isNative) this.eventSupport = this.target[eventSupport] } entry.prototype = { // given a list of namespaces, is our entry in any of them? inNamespaces: function (checkNamespaces) { var i, j if (!checkNamespaces) return true if (!this.namespaces) return false for (i = checkNamespaces.length; i--;) { for (j = this.namespaces.length; j--;) { if (checkNamespaces[i] === this.namespaces[j]) return true } } return false } // match by element, original fn (opt), handler fn (opt) , matches: function (checkElement, checkOriginal, checkHandler) { return this.element === checkElement && (!checkOriginal || this.original === checkOriginal) && (!checkHandler || this.handler === checkHandler) } } return entry })() , registry = (function () { // our map stores arrays by event type, just because it's better than storing // everything in a single array. uses '$' as a prefix for the keys for safety var map = {} // generic functional search of our registry for matching listeners, // `fn` returns false to break out of the loop , forAll = function (element, type, original, handler, fn) { if (!type || type === '*') { // search the whole registry for (var t in map) { if (t.charAt(0) === '$') forAll(element, t.substr(1), original, handler, fn) } } else { var i = 0, l, list = map['$' + type], all = element === '*' if (!list) return for (l = list.length; i < l; i++) { if (all || list[i].matches(element, original, handler)) if (!fn(list[i], list, i, type)) return } } } , has = function (element, type, original) { // we're not using forAll here simply because it's a bit slower and this // needs to be fast var i, list = map['$' + type] if (list) { for (i = list.length; i--;) { if (list[i].matches(element, original, null)) return true } } return false } , get = function (element, type, original) { var entries = [] forAll(element, type, original, null, function (entry) { return entries.push(entry) }) return entries } , put = function (entry) { (map['$' + entry.type] || (map['$' + entry.type] = [])).push(entry) return entry } , del = function (entry) { forAll(entry.element, entry.type, null, entry.handler, function (entry, list, i) { list.splice(i, 1) if (list.length === 0) delete map['$' + entry.type] return false }) } // dump all entries, used for onunload , entries = function () { var t, entries = [] for (t in map) { if (t.charAt(0) === '$') entries = entries.concat(map[t]) } return entries } return { has: has, get: get, put: put, del: del, entries: entries } })() // add and remove listeners to DOM elements , listener = W3C_MODEL ? function (element, type, fn, add) { element[add ? addEvent : removeEvent](type, fn, false) } : function (element, type, fn, add, custom) { if (custom && add && element['_on' + custom] === null) element['_on' + custom] = 0 element[add ? attachEvent : detachEvent]('on' + type, fn) } , nativeHandler = function (element, fn, args) { return function (event) { event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || win).event, true) return fn.apply(element, [event].concat(args)) } } , customHandler = function (element, fn, type, condition, args, isNative) { return function (event) { if (condition ? condition.apply(this, arguments) : W3C_MODEL ? true : event && event.propertyName === '_on' + type || !event) { if (event) event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || win).event, isNative) fn.apply(element, event && (!args || args.length === 0) ? arguments : slice.call(arguments, event ? 0 : 1).concat(args)) } } } , once = function (rm, element, type, fn, originalFn) { // wrap the handler in a handler that does a remove as well return function () { rm(element, type, originalFn) fn.apply(this, arguments) } } , removeListener = function (element, orgType, handler, namespaces) { var i, l, entry , type = (orgType && orgType.replace(nameRegex, '')) , handlers = registry.get(element, type, handler) for (i = 0, l = handlers.length; i < l; i++) { if (handlers[i].inNamespaces(namespaces)) { if ((entry = handlers[i]).eventSupport) listener(entry.target, entry.eventType, entry.handler, false, entry.type) // TODO: this is problematic, we have a registry.get() and registry.del() that // both do registry searches so we waste cycles doing this. Needs to be rolled into // a single registry.forAll(fn) that removes while finding, but the catch is that // we'll be splicing the arrays that we're iterating over. Needs extra tests to // make sure we don't screw it up. @rvagg registry.del(entry) } } } , addListener = function (element, orgType, fn, originalFn, args) { var entry , type = orgType.replace(nameRegex, '') , namespaces = orgType.replace(namespaceRegex, '').split('.') if (registry.has(element, type, fn)) return element // no dupe if (type === 'unload') fn = once(removeListener, element, type, fn, originalFn) // self clean-up if (customEvents[type]) { if (customEvents[type].condition) fn = customHandler(element, fn, type, customEvents[type].condition, true) type = customEvents[type].base || type } entry = registry.put(new RegEntry(element, type, fn, originalFn, namespaces[0] && namespaces)) entry.handler = entry.isNative ? nativeHandler(element, entry.handler, args) : customHandler(element, entry.handler, type, false, args, false) if (entry.eventSupport) listener(entry.target, entry.eventType, entry.handler, true, entry.customType) } , del = function (selector, fn, $) { return function (e) { var target, i, array = typeof selector === 'string' ? $(selector, this) : selector for (target = e.target; target && target !== this; target = target.parentNode) { for (i = array.length; i--;) { if (array[i] === target) { return fn.apply(target, arguments) } } } } } , remove = function (element, typeSpec, fn) { var k, m, type, namespaces, i , rm = removeListener , isString = typeSpec && typeof typeSpec === 'string' if (isString && typeSpec.indexOf(' ') > 0) { // remove(el, 't1 t2 t3', fn) or remove(el, 't1 t2 t3') typeSpec = typeSpec.split(' ') for (i = typeSpec.length; i--;) remove(element, typeSpec[i], fn) return element } type = isString && typeSpec.replace(nameRegex, '') if (type && customEvents[type]) type = customEvents[type].type if (!typeSpec || isString) { // remove(el) or remove(el, t1.ns) or remove(el, .ns) or remove(el, .ns1.ns2.ns3) if (namespaces = isString && typeSpec.replace(namespaceRegex, '')) namespaces = namespaces.split('.') rm(element, type, fn, namespaces) } else if (typeof typeSpec === 'function') { // remove(el, fn) rm(element, null, typeSpec) } else { // remove(el, { t1: fn1, t2, fn2 }) for (k in typeSpec) { if (typeSpec.hasOwnProperty(k)) remove(element, k, typeSpec[k]) } } return element } , add = function (element, events, fn, delfn, $) { var type, types, i, args , originalFn = fn , isDel = fn && typeof fn === 'string' if (events && !fn && typeof events === 'object') { for (type in events) { if (events.hasOwnProperty(type)) add.apply(this, [ element, type, events[type] ]) } } else { args = arguments.length > 3 ? slice.call(arguments, 3) : [] types = (isDel ? fn : events).split(' ') isDel && (fn = del(events, (originalFn = delfn), $)) && (args = slice.call(args, 1)) // special case for one() this === ONE && (fn = once(remove, element, events, fn, originalFn)) for (i = types.length; i--;) addListener(element, types[i], fn, originalFn, args) } return element } , one = function () { return add.apply(ONE, arguments) } , fireListener = W3C_MODEL ? function (isNative, type, element) { var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents') evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1) element.dispatchEvent(evt) } : function (isNative, type, element) { element = targetElement(element, isNative) // if not-native then we're using onpropertychange so we just increment a custom property isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++ } , fire = function (element, type, args) { var i, j, l, names, handlers , types = type.split(' ') for (i = types.length; i--;) { type = types[i].replace(nameRegex, '') if (names = types[i].replace(namespaceRegex, '')) names = names.split('.') if (!names && !args && element[eventSupport]) { fireListener(nativeEvents[type], type, element) } else { // non-native event, either because of a namespace, arguments or a non DOM element // iterate over all listeners and manually 'fire' handlers = registry.get(element, type) args = [false].concat(args) for (j = 0, l = handlers.length; j < l; j++) { if (handlers[j].inNamespaces(names)) handlers[j].handler.apply(element, args) } } } return element } , clone = function (element, from, type) { var i = 0 , handlers = registry.get(from, type) , l = handlers.length for (;i < l; i++) handlers[i].original && add(element, handlers[i].type, handlers[i].original) return element } , bean = { add: add , one: one , remove: remove , clone: clone , fire: fire , noConflict: function () { context[name] = old return this } } if (win[attachEvent]) { // for IE, clean up on unload to avoid leaks var cleanup = function () { var i, entries = registry.entries() for (i in entries) { if (entries[i].type && entries[i].type !== 'unload') remove(entries[i].element, entries[i].type) } win[detachEvent]('onunload', cleanup) win.CollectGarbage && win.CollectGarbage() } win[attachEvent]('onunload', cleanup) } return bean }) // Copyright Google Inc. // Licensed under the Apache Licence Version 2.0 // Autogenerated at Tue Oct 11 13:36:46 EDT 2011 // @provides html4 var html4 = {}; html4.atype = { NONE: 0, URI: 1, URI_FRAGMENT: 11, SCRIPT: 2, STYLE: 3, ID: 4, IDREF: 5, IDREFS: 6, GLOBAL_NAME: 7, LOCAL_NAME: 8, CLASSES: 9, FRAME_TARGET: 10 }; html4.ATTRIBS = { '*::class': 9, '*::dir': 0, '*::id': 4, '*::lang': 0, '*::onclick': 2, '*::ondblclick': 2, '*::onkeydown': 2, '*::onkeypress': 2, '*::onkeyup': 2, '*::onload': 2, '*::onmousedown': 2, '*::onmousemove': 2, '*::onmouseout': 2, '*::onmouseover': 2, '*::onmouseup': 2, '*::style': 3, '*::title': 0, 'a::accesskey': 0, 'a::coords': 0, 'a::href': 1, 'a::hreflang': 0, 'a::name': 7, 'a::onblur': 2, 'a::onfocus': 2, 'a::rel': 0, 'a::rev': 0, 'a::shape': 0, 'a::tabindex': 0, 'a::target': 10, 'a::type': 0, 'area::accesskey': 0, 'area::alt': 0, 'area::coords': 0, 'area::href': 1, 'area::nohref': 0, 'area::onblur': 2, 'area::onfocus': 2, 'area::shape': 0, 'area::tabindex': 0, 'area::target': 10, 'bdo::dir': 0, 'blockquote::cite': 1, 'br::clear': 0, 'button::accesskey': 0, 'button::disabled': 0, 'button::name': 8, 'button::onblur': 2, 'button::onfocus': 2, 'button::tabindex': 0, 'button::type': 0, 'button::value': 0, 'canvas::height': 0, 'canvas::width': 0, 'caption::align': 0, 'col::align': 0, 'col::char': 0, 'col::charoff': 0, 'col::span': 0, 'col::valign': 0, 'col::width': 0, 'colgroup::align': 0, 'colgroup::char': 0, 'colgroup::charoff': 0, 'colgroup::span': 0, 'colgroup::valign': 0, 'colgroup::width': 0, 'del::cite': 1, 'del::datetime': 0, 'dir::compact': 0, 'div::align': 0, 'dl::compact': 0, 'font::color': 0, 'font::face': 0, 'font::size': 0, 'form::accept': 0, 'form::action': 1, 'form::autocomplete': 0, 'form::enctype': 0, 'form::method': 0, 'form::name': 7, 'form::onreset': 2, 'form::onsubmit': 2, 'form::target': 10, 'h1::align': 0, 'h2::align': 0, 'h3::align': 0, 'h4::align': 0, 'h5::align': 0, 'h6::align': 0, 'hr::align': 0, 'hr::noshade': 0, 'hr::size': 0, 'hr::width': 0, 'iframe::align': 0, 'iframe::frameborder': 0, 'iframe::height': 0, 'iframe::marginheight': 0, 'iframe::marginwidth': 0, 'iframe::width': 0, 'img::align': 0, 'img::alt': 0, 'img::border': 0, 'img::height': 0, 'img::hspace': 0, 'img::ismap': 0, 'img::name': 7, 'img::src': 1, 'img::usemap': 11, 'img::vspace': 0, 'img::width': 0, 'input::accept': 0, 'input::accesskey': 0, 'input::align': 0, 'input::alt': 0, 'input::autocomplete': 0, 'input::checked': 0, 'input::disabled': 0, 'input::ismap': 0, 'input::maxlength': 0, 'input::name': 8, 'input::onblur': 2, 'input::onchange': 2, 'input::onfocus': 2, 'input::onselect': 2, 'input::readonly': 0, 'input::size': 0, 'input::src': 1, 'input::tabindex': 0, 'input::type': 0, 'input::usemap': 11, 'input::value': 0, 'ins::cite': 1, 'ins::datetime': 0, 'label::accesskey': 0, 'label::for': 5, 'label::onblur': 2, 'label::onfocus': 2, 'legend::accesskey': 0, 'legend::align': 0, 'li::type': 0, 'li::value': 0, 'map::name': 7, 'menu::compact': 0, 'ol::compact': 0, 'ol::start': 0, 'ol::type': 0, 'optgroup::disabled': 0, 'optgroup::label': 0, 'option::disabled': 0, 'option::label': 0, 'option::selected': 0, 'option::value': 0, 'p::align': 0, 'pre::width': 0, 'q::cite': 1, 'select::disabled': 0, 'select::multiple': 0, 'select::name': 8, 'select::onblur': 2, 'select::onchange': 2, 'select::onfocus': 2, 'select::size': 0, 'select::tabindex': 0, 'table::align': 0, 'table::bgcolor': 0, 'table::border': 0, 'table::cellpadding': 0, 'table::cellspacing': 0, 'table::frame': 0, 'table::rules': 0, 'table::summary': 0, 'table::width': 0, 'tbody::align': 0, 'tbody::char': 0, 'tbody::charoff': 0, 'tbody::valign': 0, 'td::abbr': 0, 'td::align': 0, 'td::axis': 0, 'td::bgcolor': 0, 'td::char': 0, 'td::charoff': 0, 'td::colspan': 0, 'td::headers': 6, 'td::height': 0, 'td::nowrap': 0, 'td::rowspan': 0, 'td::scope': 0, 'td::valign': 0, 'td::width': 0, 'textarea::accesskey': 0, 'textarea::cols': 0, 'textarea::disabled': 0, 'textarea::name': 8, 'textarea::onblur': 2, 'textarea::onchange': 2, 'textarea::onfocus': 2, 'textarea::onselect': 2, 'textarea::readonly': 0, 'textarea::rows': 0, 'textarea::tabindex': 0, 'tfoot::align': 0, 'tfoot::char': 0, 'tfoot::charoff': 0, 'tfoot::valign': 0, 'th::abbr': 0, 'th::align': 0, 'th::axis': 0, 'th::bgcolor': 0, 'th::char': 0, 'th::charoff': 0, 'th::colspan': 0, 'th::headers': 6, 'th::height': 0, 'th::nowrap': 0, 'th::rowspan': 0, 'th::scope': 0, 'th::valign': 0, 'th::width': 0, 'thead::align': 0, 'thead::char': 0, 'thead::charoff': 0, 'thead::valign': 0, 'tr::align': 0, 'tr::bgcolor': 0, 'tr::char': 0, 'tr::charoff': 0, 'tr::valign': 0, 'ul::compact': 0, 'ul::type': 0 }; html4.eflags = { OPTIONAL_ENDTAG: 1, EMPTY: 2, CDATA: 4, RCDATA: 8, UNSAFE: 16, FOLDABLE: 32, SCRIPT: 64, STYLE: 128 }; html4.ELEMENTS = { 'a': 0, 'abbr': 0, 'acronym': 0, 'address': 0, 'applet': 16, 'area': 2, 'b': 0, 'base': 18, 'basefont': 18, 'bdo': 0, 'big': 0, 'blockquote': 0, 'body': 49, 'br': 2, 'button': 0, 'canvas': 0, 'caption': 0, 'center': 0, 'cite': 0, 'code': 0, 'col': 2, 'colgroup': 1, 'dd': 1, 'del': 0, 'dfn': 0, 'dir': 0, 'div': 0, 'dl': 0, 'dt': 1, 'em': 0, 'fieldset': 0, 'font': 0, 'form': 0, 'frame': 18, 'frameset': 16, 'h1': 0, 'h2': 0, 'h3': 0, 'h4': 0, 'h5': 0, 'h6': 0, 'head': 49, 'hr': 2, 'html': 49, 'i': 0, 'iframe': 4, 'img': 2, 'input': 2, 'ins': 0, 'isindex': 18, 'kbd': 0, 'label': 0, 'legend': 0, 'li': 1, 'link': 18, 'map': 0, 'menu': 0, 'meta': 18, 'nobr': 0, 'noembed': 4, 'noframes': 20, 'noscript': 20, 'object': 16, 'ol': 0, 'optgroup': 0, 'option': 1, 'p': 1, 'param': 18, 'pre': 0, 'q': 0, 's': 0, 'samp': 0, 'script': 84, 'select': 0, 'small': 0, 'span': 0, 'strike': 0, 'strong': 0, 'style': 148, 'sub': 0, 'sup': 0, 'table': 0, 'tbody': 1, 'td': 1, 'textarea': 8, 'tfoot': 1, 'th': 1, 'thead': 1, 'title': 24, 'tr': 1, 'tt': 0, 'u': 0, 'ul': 0, 'var': 0 }; html4.ueffects = { NOT_LOADED: 0, SAME_DOCUMENT: 1, NEW_DOCUMENT: 2 }; html4.URIEFFECTS = { 'a::href': 2, 'area::href': 2, 'blockquote::cite': 0, 'body::background': 1, 'del::cite': 0, 'form::action': 2, 'img::src': 1, 'input::src': 1, 'ins::cite': 0, 'q::cite': 0 }; html4.ltypes = { UNSANDBOXED: 2, SANDBOXED: 1, DATA: 0 }; html4.LOADERTYPES = { 'a::href': 2, 'area::href': 2, 'blockquote::cite': 2, 'body::background': 1, 'del::cite': 2, 'form::action': 2, 'img::src': 1, 'input::src': 1, 'ins::cite': 2, 'q::cite': 2 };; // Copyright (C) 2006 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /** * @fileoverview * An HTML sanitizer that can satisfy a variety of security policies. * *
* The HTML sanitizer is built around a SAX parser and HTML element and
* attributes schemas.
*
* @author mikesamuel@gmail.com
* @requires html4
* @overrides window
* @provides html, html_sanitize
*/
/**
* @namespace
*/
var html = (function (html4) {
var lcase;
// The below may not be true on browsers in the Turkish locale.
if ('script' === 'SCRIPT'.toLowerCase()) {
lcase = function (s) { return s.toLowerCase(); };
} else {
/**
* {@updoc
* $ lcase('SCRIPT')
* # 'script'
* $ lcase('script')
* # 'script'
* }
*/
lcase = function (s) {
return s.replace(
/[A-Z]/g,
function (ch) {
return String.fromCharCode(ch.charCodeAt(0) | 32);
});
};
}
var ENTITIES = {
lt : '<',
gt : '>',
amp : '&',
nbsp : '\240',
quot : '"',
apos : '\''
};
// Schemes on which to defer to uripolicy. Urls with other schemes are denied
var WHITELISTED_SCHEMES = /^(?:https?|mailto|data)$/i;
var decimalEscapeRe = /^#(\d+)$/;
var hexEscapeRe = /^#x([0-9A-Fa-f]+)$/;
/**
* Decodes an HTML entity.
*
* {@updoc
* $ lookupEntity('lt')
* # '<'
* $ lookupEntity('GT')
* # '>'
* $ lookupEntity('amp')
* # '&'
* $ lookupEntity('nbsp')
* # '\xA0'
* $ lookupEntity('apos')
* # "'"
* $ lookupEntity('quot')
* # '"'
* $ lookupEntity('#xa')
* # '\n'
* $ lookupEntity('#10')
* # '\n'
* $ lookupEntity('#x0a')
* # '\n'
* $ lookupEntity('#010')
* # '\n'
* $ lookupEntity('#x00A')
* # '\n'
* $ lookupEntity('Pi') // Known failure
* # '\u03A0'
* $ lookupEntity('pi') // Known failure
* # '\u03C0'
* }
*
* @param name the content between the '&' and the ';'.
* @return a single unicode code-point as a string.
*/
function lookupEntity(name) {
name = lcase(name); // TODO: π is different from Π
if (ENTITIES.hasOwnProperty(name)) { return ENTITIES[name]; }
var m = name.match(decimalEscapeRe);
if (m) {
return String.fromCharCode(parseInt(m[1], 10));
} else if (!!(m = name.match(hexEscapeRe))) {
return String.fromCharCode(parseInt(m[1], 16));
}
return '';
}
function decodeOneEntity(_, name) {
return lookupEntity(name);
}
var nulRe = /\0/g;
function stripNULs(s) {
return s.replace(nulRe, '');
}
var entityRe = /&(#\d+|#x[0-9A-Fa-f]+|\w+);/g;
/**
* The plain text of a chunk of HTML CDATA which possibly containing.
*
* {@updoc
* $ unescapeEntities('')
* # ''
* $ unescapeEntities('hello World!')
* # 'hello World!'
* $ unescapeEntities('1 < 2 && 4 > 3
')
* # '1 < 2 && 4 > 3\n'
* $ unescapeEntities('<< <- unfinished entity>')
* # '<< <- unfinished entity>'
* $ unescapeEntities('/foo?bar=baz©=true') // & often unescaped in URLS
* # '/foo?bar=baz©=true'
* $ unescapeEntities('pi=ππ, Pi=Π\u03A0') // FIXME: known failure
* # 'pi=\u03C0\u03c0, Pi=\u03A0\u03A0'
* }
*
* @param s a chunk of HTML CDATA. It must not start or end inside an HTML
* entity.
*/
function unescapeEntities(s) {
return s.replace(entityRe, decodeOneEntity);
}
var ampRe = /&/g;
var looseAmpRe = /&([^a-z#]|#(?:[^0-9x]|x(?:[^0-9a-f]|$)|$)|$)/gi;
var ltRe = //g;
var quotRe = /\"/g;
var eqRe = /\=/g; // Backslash required on JScript.net
/**
* Escapes HTML special characters in attribute values as HTML entities.
*
* {@updoc
* $ escapeAttrib('')
* # ''
* $ escapeAttrib('"<<&==&>>"') // Do not just escape the first occurrence.
* # '"<<&==&>>"'
* $ escapeAttrib('Hello