Index: openacs-4/packages/xowiki/www/resources/wymeditor/xhtml_parser.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/www/resources/wymeditor/xhtml_parser.js,v diff -u -r1.2 -r1.3 --- openacs-4/packages/xowiki/www/resources/wymeditor/xhtml_parser.js 27 Jul 2007 01:15:20 -0000 1.2 +++ openacs-4/packages/xowiki/www/resources/wymeditor/xhtml_parser.js 14 Sep 2007 17:53:31 -0000 1.3 @@ -29,7 +29,7 @@ { this._entitiesDiv = document.createElement('div'); return this; -} +}; /* @@ -55,7 +55,7 @@ options = options || false; open = open || false; return '<'+name+(options ? this.tagOptions(options) : '')+(open ? '>' : ' />'); -} +}; /* * @name contentTag @@ -76,7 +76,7 @@ { options = options || false; return '<'+name+(options ? this.tagOptions(options) : '')+'>'+content+''; -} +}; /* * @name cdataSection @@ -90,7 +90,7 @@ XmlHelper.prototype.cdataSection = function(content) { return ''; -} +}; /* @@ -104,7 +104,7 @@ XmlHelper.prototype.escapeOnce = function(xml) { return this._fixDoubleEscape(this.escapeEntities(xml)); -} +}; /* * @name _fixDoubleEscape @@ -114,7 +114,7 @@ XmlHelper.prototype._fixDoubleEscape = function(escaped) { return escaped.replace(/&([a-z]+|(#\d+));/ig, "&$1;"); -} +}; /* * @name tagOptions @@ -146,7 +146,7 @@ } } return xml._formated_options; -} +}; /* * @name escapeEntities @@ -164,7 +164,7 @@ if(escape_quotes == true) result = result.replace('"', '''); } return result; -} +}; /* * Parses a string conatining tag attributes and values an returns an array formated like @@ -194,7 +194,7 @@ } } return result; -} +}; /** * XhtmlValidator for validating tag attributes @@ -887,11 +887,11 @@ this._possible_tag_attributes = {}; } if (!this._possible_tag_attributes[tag]) { - this._possible_tag_attributes[tag] = this.getUniqueAttributesAndEventsForTag(tag).concat(this.getDefaultAttributesAndEventsForTag(tag));; + this._possible_tag_attributes[tag] = this.getUniqueAttributesAndEventsForTag(tag).concat(this.getDefaultAttributesAndEventsForTag(tag)); } return this._possible_tag_attributes[tag]; } -} +}; /** @@ -913,7 +913,7 @@ this._labels = []; this._regex = null; return this; -} +}; /** @@ -931,7 +931,7 @@ this._patterns[count] = pattern; this._labels[count] = label; this._regex = null; -} +}; /** * Attempts to match all patterns at once against @@ -960,7 +960,7 @@ } } return [true, matches[0]]; -} +}; /** * Compounds the patterns into a single @@ -979,7 +979,7 @@ this._regex = new RegExp(this._patterns.join("|") ,this._getPerlMatchingFlags()); } return this._regex; -} +}; /** * Escape lookahead/lookbehind blocks @@ -994,7 +994,7 @@ replace(/\(\?\<\=(.*)\)/, '~~~~~~Tk5\$1~~~~~~'). replace(/\(\?\<\!(.*)\)/, '~~~~~~Tk6\$1~~~~~~'). replace(/\(\?\:(.*)\)/, '~~~~~~Tk7\$1~~~~~~'); -} +}; /** * Unscape lookahead/lookbehind blocks @@ -1009,7 +1009,7 @@ replace(/~~~~~~Tk5(.*)~~~~~~/, "(?<=\$1)"). replace(/~~~~~~Tk6(.*)~~~~~~/, "(?", 'Comment'); -} +}; XhtmlLexer.prototype.addScriptTokens = function(scope) { this.addEntryPattern("", 'Script'); -} +}; XhtmlLexer.prototype.addCssTokens = function(scope) { this.addEntryPattern("", 'Css'); -} +}; XhtmlLexer.prototype.addTagTokens = function(scope) { @@ -1445,7 +1445,7 @@ this.addSpecialPattern("", scope, 'ClosingTag'); -} +}; XhtmlLexer.prototype.addInTagDeclarationTokens = function(scope) { @@ -1456,7 +1456,7 @@ this.addExitPattern('/>', scope); this.addExitPattern('>', scope); -} +}; XhtmlLexer.prototype.addAttributeTokens = function(scope) { @@ -1471,7 +1471,7 @@ this.addExitPattern("'", 'SingleQuotedAttribute'); this.addSpecialPattern('=\\s*[^>\\s]*', scope, 'UnquotedAttribute'); -} +}; @@ -1494,13 +1494,13 @@ this._current_match = ''; return this; -} +}; XhtmlParser.prototype.parse = function(raw) { this._Lexer.parse(this.beforeParsing(raw)); return this.afterParsing(this._Listener.getResult()); -} +}; XhtmlParser.prototype.beforeParsing = function(raw) { @@ -1509,42 +1509,42 @@ this._Listener.avoidStylingTagsAndAttributes(); } return this._Listener.beforeParsing(raw); -} +}; XhtmlParser.prototype.afterParsing = function(parsed) { if(this._Listener._avoiding_tags_implicitly){ this._Listener.allowStylingTagsAndAttributes(); } return this._Listener.afterParsing(parsed); -} +}; XhtmlParser.prototype.Ignore = function(match, state) { return true; -} +}; XhtmlParser.prototype.Text = function(text) { this._Listener.addContent(text); return true; -} +}; XhtmlParser.prototype.Comment = function(match, status) { return this._addNonTagBlock(match, status, 'addComment'); -} +}; XhtmlParser.prototype.Script = function(match, status) { return this._addNonTagBlock(match, status, 'addScript'); -} +}; XhtmlParser.prototype.Css = function(match, status) { return this._addNonTagBlock(match, status, 'addCss'); -} +}; XhtmlParser.prototype._addNonTagBlock = function(match, state, type) { @@ -1569,7 +1569,7 @@ } } return true; -} +}; XhtmlParser.prototype.OpeningTag = function(match, state) { @@ -1585,21 +1585,22 @@ this._callOpenTagListener(this._tag, this._tag_attributes); } return true; -} +}; XhtmlParser.prototype.ClosingTag = function(match, state) { this._callCloseTagListener(this.normalizeTag(match)); return true; -} +}; XhtmlParser.prototype._callOpenTagListener = function(tag, attributes) { var attributes = attributes || {}; this.autoCloseUnclosedBeforeNewOpening(tag); if(this._Listener.isBlockTag(tag)){ - this._Listener._tag_stack.push(tag); + this._Listener._tag_stack.push(tag); + this._Listener.fixNestingBeforeOpeningBlockTag(tag, attributes); this._Listener.openBlockTag(tag, attributes); this._increaseOpenTagCounter(tag); }else if(this._Listener.isInlineTag(tag)){ @@ -1611,7 +1612,7 @@ this._Listener.last_tag = tag; this._Listener.last_tag_opened = true; this._Listener.last_tag_attributes = attributes; -} +}; XhtmlParser.prototype._callCloseTagListener = function(tag) { @@ -1634,13 +1635,13 @@ } this._Listener.last_tag = tag; this._Listener.last_tag_opened = false; -} +}; XhtmlParser.prototype._increaseOpenTagCounter = function(tag) { this._Listener._open_tags[tag] = this._Listener._open_tags[tag] || 0; this._Listener._open_tags[tag]++; -} +}; XhtmlParser.prototype._decreaseOpenTagCounter = function(tag) { @@ -1652,17 +1653,17 @@ return true; } return false; -} +}; XhtmlParser.prototype.autoCloseUnclosedBeforeNewOpening = function(new_tag) { this._autoCloseUnclosed(new_tag, false); -} +}; XhtmlParser.prototype.autoCloseUnclosedBeforeTagClosing = function(tag) { this._autoCloseUnclosed(tag, true); -} +}; XhtmlParser.prototype._autoCloseUnclosed = function(new_tag, closing) { @@ -1675,12 +1676,12 @@ } } } -} +}; XhtmlParser.prototype.getTagReplacements = function() { return this._Listener.getTagReplacements(); -} +}; XhtmlParser.prototype.normalizeTag = function(tag) { @@ -1690,35 +1691,37 @@ return tags[tag]; } return tag; -} +}; XhtmlParser.prototype.TagAttributes = function(match, state) { if(LEXER_SPECIAL == state){ this._current_attribute = match; } return true; -} +}; XhtmlParser.prototype.DoubleQuotedAttribute = function(match, state) { if(LEXER_UNMATCHED == state){ this._tag_attributes[this._current_attribute] = match; } return true; -} +}; + XhtmlParser.prototype.SingleQuotedAttribute = function(match, state) { if(LEXER_UNMATCHED == state){ this._tag_attributes[this._current_attribute] = match; } return true; -} +}; + XhtmlParser.prototype.UnquotedAttribute = function(match, state) { this._tag_attributes[this._current_attribute] = match.replace(/^=/,''); return true; -} +}; @@ -1836,7 +1839,7 @@ this.inline_tags = ["br", "hr", "img", "input"]; return this; -} +}; XhtmlSaxListener.prototype.shouldCloseTagAutomatically = function(tag, now_on_tag, closing) { @@ -1852,132 +1855,133 @@ } } return false; -} +}; XhtmlSaxListener.prototype.beforeParsing = function(raw) { this.output = ''; return raw; -} +}; XhtmlSaxListener.prototype.afterParsing = function(xhtml) { xhtml = this.replaceNamedEntities(xhtml); xhtml = this.joinRepeatedEntities(xhtml); xhtml = this.removeEmptyTags(xhtml); return xhtml; -} +}; XhtmlSaxListener.prototype.replaceNamedEntities = function(xhtml) { for (entity in this.entities) { xhtml = xhtml.replace(entity, this.entities[entity]); } return xhtml; -} +}; XhtmlSaxListener.prototype.joinRepeatedEntities = function(xhtml) { var tags = 'em|strong|sub|sup|acronym|pre|del|blockquote|address'; return xhtml.replace(new RegExp('<\/('+tags+')><\\1>' ,''),''). replace(new RegExp('(\s*<('+tags+')>\s*){2}(.*)(\s*<\/\\2>\s*){2}' ,''),'<\$2>\$3<\$2>'); -} +}; XhtmlSaxListener.prototype.removeEmptyTags = function(xhtml) { return xhtml.replace(new RegExp('<('+this.block_tags.join("|")+')>(
| | |\s)*<\/\\1>' ,'g'),''); -} +}; XhtmlSaxListener.prototype.getResult = function() { return this.output; -} +}; XhtmlSaxListener.prototype.getTagReplacements = function() { return {'b':'strong', 'i':'em'}; -} +}; XhtmlSaxListener.prototype.addContent = function(text) { this.output += text; -} +}; XhtmlSaxListener.prototype.addComment = function(text) { if(this.remove_comments){ this.output += text; } -} +}; XhtmlSaxListener.prototype.addScript = function(text) { if(!this.remove_scripts){ this.output += text; } -} +}; XhtmlSaxListener.prototype.addCss = function(text) { if(!this.remove_embeded_styles){ this.output += text; } -} +}; + XhtmlSaxListener.prototype.openBlockTag = function(tag, attributes) { this.output += this.helper.tag(tag, this.validator.getValidTagAttributes(tag, attributes), true); -} +}; XhtmlSaxListener.prototype.inlineTag = function(tag, attributes) { this.output += this.helper.tag(tag, this.validator.getValidTagAttributes(tag, attributes)); -} +}; XhtmlSaxListener.prototype.openUnknownTag = function(tag, attributes) { //this.output += this.helper.tag(tag, attributes, true); -} +}; XhtmlSaxListener.prototype.closeBlockTag = function(tag) -{ - this.output += this._getClosingTagContent('before', tag)+""+this._getClosingTagContent('after', tag); +{ + this.output = this.output.replace(/
$/, '')+this._getClosingTagContent('before', tag)+""+this._getClosingTagContent('after', tag); }; XhtmlSaxListener.prototype.closeUnknownTag = function(tag) { //this.output += ""; -} +}; XhtmlSaxListener.prototype.closeUnopenedTag = function(tag) { this.output += ""; -} +}; XhtmlSaxListener.prototype.avoidStylingTagsAndAttributes = function() { this.avoided_tags = ['div','span']; this.validator.skiped_attributes = ['style']; this.validator.skiped_attribute_values = ['MsoNormal','main1']; // MS Word attributes for class this._avoiding_tags_implicitly = true; -} +}; XhtmlSaxListener.prototype.allowStylingTagsAndAttributes = function() { this.avoided_tags = []; this.validator.skiped_attributes = []; this.validator.skiped_attribute_values = []; this._avoiding_tags_implicitly = false; -} +}; XhtmlSaxListener.prototype.isBlockTag = function(tag) { return !this.avoided_tags.contains(tag) && this.block_tags.contains(tag); -} +}; XhtmlSaxListener.prototype.isInlineTag = function(tag) { return !this.avoided_tags.contains(tag) && this.inline_tags.contains(tag); -} +}; XhtmlSaxListener.prototype.insertContentAfterClosingTag = function(tag, content) { @@ -1988,6 +1992,14 @@ { this._insertContentWhenClosingTag('before', tag, content); }; + +XhtmlSaxListener.prototype.fixNestingBeforeOpeningBlockTag = function(tag, attributes) +{ + if(tag != 'li' && (tag == 'ul' || tag == 'ol') && this.last_tag && !this.last_tag_opened && this.last_tag == 'li'){ + this.output = this.output.replace(/<\/li>$/, ''); + this.insertContentAfterClosingTag(tag, ''); + } +}; XhtmlSaxListener.prototype._insertContentWhenClosingTag = function(position, tag, content) { @@ -1998,7 +2010,7 @@ this['_insert_'+position+'_closing'][tag] = []; } this['_insert_'+position+'_closing'][tag].push(content); -}; +}; XhtmlSaxListener.prototype._getClosingTagContent = function(position, tag) {