o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1388437006.571197: @value"ÒK{I" class:EFI"ProcessedAsset;FI"logical_path;FI"-mercury/dependencies/jquery.htmlClean.js;FI" pathname;FI"—/Users/jrissler/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/mercury-rails-0.9.0/app/assets/javascripts/mercury/dependencies/jquery.htmlClean.js;FI"content_type;FI"application/javascript;FI" mtime;FI"2013-12-30T11:31:51-05:00;FI" length;FiÉGI" digest;F"%35f4dee1afb788a59a608c5177119917I" source;FI"ÉG/* HTML Clean for jQuery Anthony Johnston http://www.antix.co.uk version 1.2.3 $Revision: 51 $ requires jQuery http://jquery.com Use and distibution http://www.opensource.org/licenses/bsd-license.php 2010-04-02 allowedTags/removeTags added (white/black list) thanks to David Wartian (Dwartian) 2010-06-30 replaceStyles added for replacement of bold, italic, super and sub styles on a tag 2010-07-01 notRenderedTags added, where tags are to be removed but their contents are kept */ (function ($) { $.fn.htmlClean = function (options) { // iterate and html clean each matched element return this.each(function () { if (this.value) { this.value = $.htmlClean(this.value, options); } else { this.innerHTML = $.htmlClean(this.innerHTML, options); } }); }; // clean the passed html $.htmlClean = function (html, options) { options = $.extend({}, $.htmlClean.defaults, options); var tagsRE = /<(\/)?(\w+:)?([\w]+)([^>]*)>/gi; var attrsRE = /(\w+)=(".*?"|'.*?'|[^\s>]*)/gi; var tagMatch; var root = new Element(); var stack = [root]; var container = root; if (options.bodyOnly) { // check for body tag if (tagMatch = /]*>((\n|.)*)<\/body>/i.exec(html)) { html = tagMatch[1]; } } html = html.concat(""); // ensure last element/text is found var lastIndex; while (tagMatch = tagsRE.exec(html)) { var tag = new Tag(tagMatch[3], tagMatch[1], tagMatch[4], options); // add the text var text = html.substring(lastIndex, tagMatch.index); if (text.length > 0) { var child = container.children[container.children.length - 1]; if (container.children.length > 0 && isText(child = container.children[container.children.length - 1])) { // merge text container.children[container.children.length - 1] = child.concat(text); } else { container.children.push(text); } } lastIndex = tagsRE.lastIndex; if (tag.isClosing) { // find matching container if (pop(stack, [tag.name])) { stack.pop(); container = stack[stack.length - 1]; } } else { // create a new element var element = new Element(tag); // add attributes var attrMatch; while (attrMatch = attrsRE.exec(tag.rawAttributes)) { // check style attribute and do replacements if (attrMatch[1].toLowerCase() == "style" && options.replaceStyles) { var renderParent = !tag.isInline; for (var i = 0; i < options.replaceStyles.length; i++) { if (options.replaceStyles[i][0].test(attrMatch[2])) { if (!renderParent) { tag.render = false; renderParent = true; } container.children.push(element); // assumes not replaced stack.push(element); container = element; // assumes replacement is a container // create new tag and element tag = new Tag(options.replaceStyles[i][1], "", "", options); element = new Element(tag); } } } if (tag.allowedAttributes != null && (tag.allowedAttributes.length == 0 || $.inArray(attrMatch[1], tag.allowedAttributes) > -1)) { element.attributes.push(new Attribute(attrMatch[1], attrMatch[2])); } } // add required empty ones $.each(tag.requiredAttributes, function () { var name = this.toString(); if (!element.hasAttribute(name)) element.attributes.push(new Attribute(name, "")); }); // check for replacements for (var repIndex = 0; repIndex < options.replace.length; repIndex++) { for (var tagIndex = 0; tagIndex < options.replace[repIndex][0].length; tagIndex++) { var byName = typeof (options.replace[repIndex][0][tagIndex]) == "string"; if ((byName && options.replace[repIndex][0][tagIndex] == tag.name) || (!byName && options.replace[repIndex][0][tagIndex].test(tagMatch))) { // don't render this tag tag.render = false; container.children.push(element); stack.push(element); container = element; // render new tag, keep attributes tag = new Tag(options.replace[repIndex][1], tagMatch[1], tagMatch[4], options); element = new Element(tag); element.attributes = container.attributes; repIndex = options.replace.length; // break out of both loops break; } } } // check container rules var add = true; if (!container.isRoot) { if (container.tag.isInline && !tag.isInline) { add = false; } else if (container.tag.disallowNest && tag.disallowNest && !tag.requiredParent) { add = false; } else if (tag.requiredParent) { if (add = pop(stack, tag.requiredParent)) { container = stack[stack.length - 1]; } } } if (add) { container.children.push(element); if (tag.toProtect) { // skip to closing tag var tagMatch2 = null; while (tagMatch2 = tagsRE.exec(html)) { var tag2 = new Tag(tagMatch2[3], tagMatch2[1], tagMatch2[4], options); if (tag2.isClosing && tag2.name == tag.name) { element.children.push(RegExp.leftContext.substring(lastIndex)); lastIndex = tagsRE.lastIndex; break; } } } else { // set as current container element if (!tag.isSelfClosing && !tag.isNonClosing) { stack.push(element); container = element; } } } } } // render doc return render(root, options).join(""); }; // defaults $.htmlClean.defaults = { // only clean the body tagbody bodyOnly: true, // only allow tags in this array, (white list), contents still rendered allowedTags: [], // remove tags in this array, (black list), contents still rendered removeTags: ["basefont", "center", "dir", "font", "frame", "frameset", "iframe", "isindex", "menu", "noframes", "s", "strike", "u"], // array of attribute names to remove on all elements in addition to those not in tagAttributes e.g ["width", "height"] removeAttrs: [], // array of [className], [optional array of allowed on elements] e.g. [["class"], ["anotherClass", ["p", "dl"]]] allowedClasses: [], // tags not rendered, contents remain notRenderedTags: [], // format the result format: false, // format indent to start on formatIndent: 0, // tags to replace, and what to replace with, tag name or regex to match the tag and attributes replace: [ [ ["b", "big"], "strong" ], [ ["i"], "em" ] ], // styles to replace with tags, multiple style matches supported, inline tags are replaced by the first match blocks are retained replaceStyles: [ [/font-weight:\s*bold/i, "strong"], [/font-style:\s*italic/i, "em"], [/vertical-align:\s*super/i, "sup"], [/vertical-align:\s*sub/i, "sub"] ] }; function applyFormat(element, options, output, indent) { if (!element.tag.isInline && output.length > 0) { output.push("\n"); for (var i = 0; i < indent; i++) output.push("\t"); } } function render(element, options) { var output = [], empty = element.attributes.length == 0, indent = 0, outputChildren = null; // don't render if not in allowedTags or in removeTags var renderTag = element.tag.render && (options.allowedTags.length == 0 || $.inArray(element.tag.name, options.allowedTags) > -1) && (options.removeTags.length == 0 || $.inArray(element.tag.name, options.removeTags) == -1); if (!element.isRoot && renderTag) { // render opening tag output.push("<"); output.push(element.tag.name); $.each(element.attributes, function () { if ($.inArray(this.name, options.removeAttrs) == -1) { var m = new RegExp(/^(['"]?)(.*?)['"]?$/).exec(this.value); var value = m[2]; var valueQuote = m[1] || "'"; // check for classes allowed if (this.name == "class") { value = $.grep(value.split(" "), function (c) { return $.grep(options.allowedClasses, function (a) { return a[0] == c && (a.length == 1 || $.inArray(element.tag.name, a[1]) > -1); }).length > 0; }) .join(" "); valueQuote = "'"; } if (value != null && (value.length > 0 || $.inArray(this.name, element.tag.requiredAttributes) > -1)) { output.push(" "); output.push(this.name); output.push("="); output.push(valueQuote); output.push(value); output.push(valueQuote); } } }); } if (element.tag.isSelfClosing) { // self closing if (renderTag) output.push(" />"); empty = false; } else if (element.tag.isNonClosing) { empty = false; } else { if (!element.isRoot && renderTag) { // close output.push(">"); } indent = options.formatIndent++; // render children if (element.tag.toProtect) { outputChildren = $.htmlClean.trim(element.children.join("")).replace(/
/ig, "\n"); output.push(outputChildren); empty = outputChildren.length == 0; options.formatIndent--; } else { outputChildren = []; for (var i = 0; i < element.children.length; i++) { var child = element.children[i]; var text = $.htmlClean.trim(textClean(isText(child) ? child : child.childrenToString())); if (isInline(child)) { if (i > 0 && text.length > 0 && (startsWithWhitespace(child) || endsWithWhitespace(element.children[i - 1]))) { outputChildren.push(" "); } } if (isText(child)) { if (text.length > 0) { outputChildren.push(text); } } else { // don't allow a break to be the last child if (i != element.children.length - 1 || child.tag.name != "br") { if (options.format) applyFormat(child, options, outputChildren, indent); outputChildren = outputChildren.concat(render(child, options)); } } } options.formatIndent--; if (outputChildren.length > 0) { if (options.format && outputChildren[0] != "\n") applyFormat(element, options, output, indent); output = output.concat(outputChildren); empty = false; } } if (!element.isRoot && renderTag) { // render the closing tag if (options.format) applyFormat(element, options, output, indent - 1); output.push(""); } } // check for empty tags if (!element.tag.allowEmpty && empty) { return []; } return output; } // find a matching tag, and pop to it, if not do nothing function pop(stack, tagNameArray, index) { index = index || 1; if ($.inArray(stack[stack.length - index].tag.name, tagNameArray) > -1) { return true; } else if (stack.length - (index + 1) > 0 && pop(stack, tagNameArray, index + 1)) { stack.pop(); return true; } return false; } // Element Object function Element(tag) { if (tag) { this.tag = tag; this.isRoot = false; } else { this.tag = new Tag("root"); this.isRoot = true; } this.attributes = []; this.children = []; this.hasAttribute = function (name) { for (var i = 0; i < this.attributes.length; i++) { if (this.attributes[i].name == name) return true; } return false; }; this.childrenToString = function () { return this.children.join(""); }; return this; } // Attribute Object function Attribute(name, value) { this.name = name; this.value = value; return this; } // Tag object function Tag(name, close, rawAttributes, options) { this.name = name.toLowerCase(); this.isSelfClosing = $.inArray(this.name, tagSelfClosing) > -1; this.isNonClosing = $.inArray(this.name, tagNonClosing) > -1; this.isClosing = (close != undefined && close.length > 0); this.isInline = $.inArray(this.name, tagInline) > -1; this.disallowNest = $.inArray(this.name, tagDisallowNest) > -1; this.requiredParent = tagRequiredParent[$.inArray(this.name, tagRequiredParent) + 1]; this.allowEmpty = $.inArray(this.name, tagAllowEmpty) > -1; this.toProtect = $.inArray(this.name, tagProtect) > -1; this.rawAttributes = rawAttributes; this.allowedAttributes = tagAttributes[$.inArray(this.name, tagAttributes) + 1]; this.requiredAttributes = tagAttributesRequired[$.inArray(this.name, tagAttributesRequired) + 1]; this.render = options && $.inArray(this.name, options.notRenderedTags) == -1; return this; } function startsWithWhitespace(item) { while (isElement(item) && item.children.length > 0) { item = item.children[0] } return isText(item) && item.length > 0 && $.htmlClean.isWhitespace(item.charAt(0)); } function endsWithWhitespace(item) { while (isElement(item) && item.children.length > 0) { item = item.children[item.children.length - 1] } return isText(item) && item.length > 0 && $.htmlClean.isWhitespace(item.charAt(item.length - 1)); } function isText(item) { return item.constructor == String; } function isInline(item) { return isText(item) || item.tag.isInline; } function isElement(item) { return item.constructor == Element; } function textClean(text) { return text.replace(/ |\n/g, " ").replace(/\s\s+/g, " "); } // trim off white space, doesn't use regex $.htmlClean.trim = function (text) { return $.htmlClean.trimStart($.htmlClean.trimEnd(text)); }; $.htmlClean.trimStart = function (text) { return text.substring($.htmlClean.trimStartIndex(text)); }; $.htmlClean.trimStartIndex = function (text) { for (var start = 0; start < text.length - 1 && $.htmlClean.isWhitespace(text.charAt(start)); start++); return start; }; $.htmlClean.trimEnd = function (text) { return text.substring(0, $.htmlClean.trimEndIndex(text)); }; $.htmlClean.trimEndIndex = function (text) { for (var end = text.length - 1; end >= 0 && $.htmlClean.isWhitespace(text.charAt(end)); end--); return end + 1; }; // checks a char is white space or not $.htmlClean.isWhitespace = function (c) { return $.inArray(c, whitespace) != -1; }; // tags which are inline var tagInline = [ "a", "abbr", "acronym", "address", "b", "big", "br", "button", "caption", "cite", "code", "del", "em", "font", "hr", "i", "input", "img", "ins", "label", "legend", "map", "q", "samp", "select", "small", "span", "strong", "sub", "sup", "tt", "var"]; var tagDisallowNest = ["h1", "h2", "h3", "h4", "h5", "h6", "p", "th", "td"]; var tagAllowEmpty = ["th", "td"]; var tagRequiredParent = [ null, "li", ["ul", "ol"], "dt", ["dl"], "dd", ["dl"], "td", ["tr"], "th", ["tr"], "tr", ["table", "thead", "tbody", "tfoot"], "thead", ["table"], "tbody", ["table"], "tfoot", ["table"] ]; var tagProtect = ["script", "style", "pre", "code"]; // tags which self close e.g.
var tagSelfClosing = ["br", "hr", "img", "link", "meta"]; // tags which do not close var tagNonClosing = ["!doctype", "?xml"]; // attributes allowed on tags var tagAttributes = [ ["class"], // default, for all tags not mentioned "?xml", [], "!doctype", [], "a", ["accesskey", "class", "href", "name", "title", "rel", "rev", "type", "tabindex"], "abbr", ["class", "title"], "acronym", ["class", "title"], "blockquote", ["cite", "class"], "button", ["class", "disabled", "name", "type", "value"], "del", ["cite", "class", "datetime"], "form", ["accept", "action", "class", "enctype", "method", "name"], "input", ["accept", "accesskey", "alt", "checked", "class", "disabled", "ismap", "maxlength", "name", "size", "readonly", "src", "tabindex", "type", "usemap", "value"], "img", ["alt", "class", "height", "src", "width"], "ins", ["cite", "class", "datetime"], "label", ["accesskey", "class", "for"], "legend", ["accesskey", "class"], "link", ["href", "rel", "type"], "meta", ["content", "http-equiv", "name", "scheme"], "map", ["name"], "optgroup", ["class", "disabled", "label"], "option", ["class", "disabled", "label", "selected", "value"], "q", ["class", "cite"], "td", ["colspan", "rowspan"], "th", ["colspan", "rowspan"], "script", ["src", "type"], "select", ["class", "disabled", "multiple", "name", "size", "tabindex"], "style", ["type"], "table", ["class", "summary"], "textarea", ["accesskey", "class", "cols", "disabled", "name", "readonly", "rows", "tabindex"] ]; var tagAttributesRequired = [[], "img", ["alt"]]; // white space chars var whitespace = [" ", " ", "\t", "\n", "\r", "\f"]; })(jQuery); ;TI"dependency_digest;F"%8d1ec6ce89ca4ca71405fb0f18910994I"required_paths;F[I"—/Users/jrissler/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/mercury-rails-0.9.0/app/assets/javascripts/mercury/dependencies/jquery.htmlClean.js;FI"dependency_paths;F[{I" path;FI"—/Users/jrissler/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/mercury-rails-0.9.0/app/assets/javascripts/mercury/dependencies/jquery.htmlClean.js;FI" mtime;FI"2013-12-30T11:31:51-05:00;FI" digest;F"%58c3d9b22fb2893e42ffd101514510fdI" _version;F"%6776f581a4329e299531e1d52aa59832