|
|
(42 intermediate revisions not shown) |
Line 1: |
Line 1: |
| <html> | | <html> |
| | | |
- | <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script> | + | <!-- MathJax (LaTeX for the web) --> |
| + | <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script> |
| + | |
| | | |
| <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script> | | <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script> |
- |
| |
- |
| |
- | <script>
| |
- | (function() {
| |
- | var supports = (function() {
| |
- | var supports = {};
| |
- |
| |
- | var html;
| |
- | var work = this.document.createElement('div');
| |
- |
| |
- | html = "<P><I></P></I>";
| |
- | work.innerHTML = html;
| |
- | supports.tagSoup = work.innerHTML !== html;
| |
- |
| |
- | work.innerHTML = "<P><i><P></P></i></P>";
| |
- | supports.selfClose = work.childNodes.length === 2;
| |
- |
| |
- | return supports;
| |
- | })();
| |
- |
| |
- |
| |
- |
| |
- | // Regular Expressions for parsing tags and attributes
| |
- | var startTag = /^<([\-A-Za-z0-9_]+)((?:\s+[\w\-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
| |
- | var endTag = /^<\/([\-A-Za-z0-9_]+)[^>]*>/;
| |
- | var attr = /([\-A-Za-z0-9_]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
| |
- | var fillAttr = /^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noresize|noshade|nowrap|readonly|selected)$/i;
| |
- |
| |
- | var DEBUG = false;
| |
- |
| |
- | function htmlParser(stream, options) {
| |
- | stream = stream || '';
| |
- |
| |
- | // Options
| |
- | options = options || {};
| |
- |
| |
- | for(var key in supports) {
| |
- | if(supports.hasOwnProperty(key)) {
| |
- | if(options.autoFix) {
| |
- | options['fix_'+key] = true;//!supports[key];
| |
- | }
| |
- | options.fix = options.fix || options['fix_'+key];
| |
- | }
| |
- | }
| |
- |
| |
- | var stack = [];
| |
- |
| |
- | var append = function(str) {
| |
- | stream += str;
| |
- | };
| |
- |
| |
- | var prepend = function(str) {
| |
- | stream = str + stream;
| |
- | };
| |
- |
| |
- | // Order of detection matters: detection of one can only
| |
- | // succeed if detection of previous didn't
| |
- | var detect = {
| |
- | comment: /^<!--/,
| |
- | endTag: /^<\//,
| |
- | atomicTag: /^<\s*(script|style|noscript|iframe|textarea)[\s>]/i,
| |
- | startTag: /^</,
| |
- | chars: /^[^<]/
| |
- | };
| |
- |
| |
- | // Detection has already happened when a reader is called.
| |
- | var reader = {
| |
- |
| |
- | comment: function() {
| |
- | var index = stream.indexOf("-->");
| |
- | if ( index >= 0 ) {
| |
- | return {
| |
- | content: stream.substr(4, index),
| |
- | length: index + 3
| |
- | };
| |
- | }
| |
- | },
| |
- |
| |
- | endTag: function() {
| |
- | var match = stream.match( endTag );
| |
- |
| |
- | if ( match ) {
| |
- | return {
| |
- | tagName: match[1],
| |
- | length: match[0].length
| |
- | };
| |
- | }
| |
- | },
| |
- |
| |
- | atomicTag: function() {
| |
- | var start = reader.startTag();
| |
- | if(start) {
| |
- | var rest = stream.slice(start.length);
| |
- | // for optimization, we check first just for the end tag
| |
- | if(rest.match(new RegExp("<\/\\s*" + start.tagName + "\\s*>", "i"))) {
| |
- | // capturing the content is inefficient, so we do it inside the if
| |
- | var match = rest.match(new RegExp("([\\s\\S]*?)<\/\\s*" + start.tagName + "\\s*>", "i"));
| |
- | if(match) {
| |
- | // good to go
| |
- | return {
| |
- | tagName: start.tagName,
| |
- | attrs: start.attrs,
| |
- | content: match[1],
| |
- | length: match[0].length + start.length
| |
- | };
| |
- | }
| |
- | }
| |
- | }
| |
- | },
| |
- |
| |
- | startTag: function() {
| |
- | var match = stream.match( startTag );
| |
- |
| |
- | if ( match ) {
| |
- | var attrs = {};
| |
- |
| |
- | match[2].replace(attr, function(match, name) {
| |
- | var value = arguments[2] || arguments[3] || arguments[4] ||
| |
- | fillAttr.test(name) && name || null;
| |
- |
| |
- | attrs[name] = value;
| |
- | });
| |
- |
| |
- | return {
| |
- | tagName: match[1],
| |
- | attrs: attrs,
| |
- | unary: !!match[3],
| |
- | length: match[0].length
| |
- | };
| |
- | }
| |
- | },
| |
- |
| |
- | chars: function() {
| |
- | var index = stream.indexOf("<");
| |
- | return {
| |
- | length: index >= 0 ? index : stream.length
| |
- | };
| |
- | }
| |
- | };
| |
- |
| |
- | var readToken = function() {
| |
- |
| |
- | // Enumerate detects in order
| |
- | for (var type in detect) {
| |
- |
| |
- | if(detect[type].test(stream)) {
| |
- | if(DEBUG) { console.log('suspected ' + type); }
| |
- |
| |
- | var token = reader[type]();
| |
- | if(token) {
| |
- | if(DEBUG) { console.log('parsed ' + type, token); }
| |
- | // Type
| |
- | token.type = token.type || type;
| |
- | // Entire text
| |
- | token.text = stream.substr(0, token.length);
| |
- | // Update the stream
| |
- | stream = stream.slice(token.length);
| |
- |
| |
- | return token;
| |
- | }
| |
- | return null;
| |
- | }
| |
- | }
| |
- | };
| |
- |
| |
- | var readTokens = function(handlers) {
| |
- | var tok;
| |
- | while(tok = readToken()) {
| |
- | // continue until we get an explicit "false" return
| |
- | if(handlers[tok.type] && handlers[tok.type](tok) === false) {
| |
- | return;
| |
- | }
| |
- | }
| |
- | };
| |
- |
| |
- | var clear = function() {
| |
- | var rest = stream;
| |
- | stream = '';
| |
- | return rest;
| |
- | };
| |
- |
| |
- | var rest = function() {
| |
- | return stream;
| |
- | };
| |
- |
| |
- | if(options.fix) {
| |
- | (function() {
| |
- | // Empty Elements - HTML 4.01
| |
- | var EMPTY = /^(AREA|BASE|BASEFONT|BR|COL|FRAME|HR|IMG|INPUT|ISINDEX|LINK|META|PARAM|EMBED)$/i;
| |
- |
| |
- | // Elements that you can| intentionally| leave open
| |
- | // (and which close themselves)
| |
- | var CLOSESELF = /^(COLGROUP|DD|DT|LI|OPTIONS|P|TD|TFOOT|TH|THEAD|TR)$/i;
| |
- |
| |
- |
| |
- | var stack = [];
| |
- | stack.last = function() {
| |
- | return this[this.length - 1];
| |
- | };
| |
- | stack.lastTagNameEq = function(tagName) {
| |
- | var last = this.last();
| |
- | return last && last.tagName &&
| |
- | last.tagName.toUpperCase() === tagName.toUpperCase();
| |
- | };
| |
- |
| |
- | stack.containsTagName = function(tagName) {
| |
- | for(var i = 0, tok; tok = this[i]; i++) {
| |
- | if(tok.tagName === tagName) {
| |
- | return true;
| |
- | }
| |
- | }
| |
- | return false;
| |
- | };
| |
- |
| |
- | var correct = function(tok) {
| |
- | if(tok && tok.type === 'startTag') {
| |
- | // unary
| |
- | tok.unary = EMPTY.test(tok.tagName) || tok.unary;
| |
- | }
| |
- | return tok;
| |
- | };
| |
- |
| |
- | var readTokenImpl = readToken;
| |
- |
| |
- | var peekToken = function() {
| |
- | var tmp = stream;
| |
- | var tok = correct(readTokenImpl());
| |
- | stream = tmp;
| |
- | return tok;
| |
- | };
| |
- |
| |
- | var closeLast = function() {
| |
- | var tok = stack.pop();
| |
- |
| |
- | // prepend close tag to stream.
| |
- | prepend('</'+tok.tagName+'>');
| |
- | };
| |
- |
| |
- | var handlers = {
| |
- | startTag: function(tok) {
| |
- | var tagName = tok.tagName;
| |
- | // Fix tbody
| |
- | if(tagName.toUpperCase() === 'TR' && stack.lastTagNameEq('TABLE')) {
| |
- | prepend('<TBODY>');
| |
- | prepareNextToken();
| |
- | } else if(options.fix_selfClose &&
| |
- | CLOSESELF.test(tagName) &&
| |
- | stack.containsTagName(tagName)) {
| |
- | if(stack.lastTagNameEq(tagName)) {
| |
- | closeLast();
| |
- | } else {
| |
- | prepend('</'+tok.tagName+'>');
| |
- | prepareNextToken();
| |
- | }
| |
- | } else if (!tok.unary) {
| |
- | stack.push(tok);
| |
- | }
| |
- | },
| |
- |
| |
- | endTag: function(tok) {
| |
- | var last = stack.last();
| |
- | if(last) {
| |
- | if(options.fix_tagSoup && !stack.lastTagNameEq(tok.tagName)) {
| |
- | // cleanup tag soup
| |
- | closeLast();
| |
- | } else {
| |
- | stack.pop();
| |
- | }
| |
- | } else if (options.fix_tagSoup) {
| |
- | // cleanup tag soup part 2: skip this token
| |
- | skipToken();
| |
- | }
| |
- | }
| |
- | };
| |
- |
| |
- | var skipToken = function() {
| |
- | // shift the next token
| |
- | readTokenImpl();
| |
- |
| |
- | prepareNextToken();
| |
- | };
| |
- |
| |
- | var prepareNextToken = function() {
| |
- | var tok = peekToken();
| |
- | if(tok && handlers[tok.type]) {
| |
- | handlers[tok.type](tok);
| |
- | }
| |
- | };
| |
- |
| |
- | // redefine readToken
| |
- | readToken = function() {
| |
- | prepareNextToken();
| |
- | return correct(readTokenImpl());
| |
- | };
| |
- | })();
| |
- | }
| |
- |
| |
- | return {
| |
- | append: append,
| |
- | readToken: readToken,
| |
- | readTokens: readTokens,
| |
- | clear: clear,
| |
- | rest: rest,
| |
- | stack: stack
| |
- | };
| |
- |
| |
- | }
| |
- |
| |
- | htmlParser.supports = supports;
| |
- |
| |
- | htmlParser.tokenToString = function(tok) {
| |
- | var handler = {
| |
- | comment: function(tok) {
| |
- | return '<--' + tok.content + '-->';
| |
- | },
| |
- | endTag: function(tok) {
| |
- | return '</'+tok.tagName+'>';
| |
- | },
| |
- | atomicTag: function(tok) {
| |
- | console.log(tok);
| |
- | return handler.startTag(tok) +
| |
- | tok.content +
| |
- | handler.endTag(tok);
| |
- | },
| |
- | startTag: function(tok) {
| |
- | var str = '<'+tok.tagName;
| |
- | for (var key in tok.attrs) {
| |
- | var val = tok.attrs[key];
| |
- | // escape quotes
| |
- | str += ' '+key+'="'+(val ? val.replace(/(^|[^\\])"/g, '$1\\\"') : '')+'"';
| |
- | }
| |
- | return str + (tok.unary ? '/>' : '>');
| |
- | },
| |
- | chars: function(tok) {
| |
- | return tok.text;
| |
- | }
| |
- | };
| |
- | return handler[tok.type](tok);
| |
- | };
| |
- |
| |
- | htmlParser.escapeAttributes = function(attrs) {
| |
- | var escapedAttrs = {};
| |
- | // escape double-quotes for writing html as a string
| |
- |
| |
- | for(var name in attrs) {
| |
- | var value = attrs[name];
| |
- | escapedAttrs[name] = value && value.replace(/(^|[^\\])"/g, '$1\\\"');
| |
- | }
| |
- | return escapedAttrs;
| |
- | };
| |
- |
| |
- | for(var key in supports) {
| |
- | htmlParser.browserHasFlaw = htmlParser.browserHasFlaw || (!supports[key]) && key;
| |
- | }
| |
- |
| |
- | this.htmlParser = htmlParser;
| |
- | })();
| |
| </script> | | </script> |
| | | |
- | | + | <script src="http://lokeshdhakar.com/projects/lightbox2/js/jquery-1.11.0.min.js"></script> |
| + | <script src="http://lokeshdhakar.com/projects/lightbox2/js/lightbox.js"></script> |
| | | |
| </html> | | </html> |