/** * Base for W3C Standard Engine * * @requires Xquared.js * @requires rdom/Base.js */ xq.rdom.W3 = xq.Class(xq.rdom.Base, /** * @name xq.rdom.W3 * @lends xq.rdom.W3.prototype * @extends xq.rdom.Base * @constructor */ { insertNode: function(node) { var rng = this.rng(); if(!rng) { this.getRoot().appendChild(node); } else { rng.insertNode(node); rng.selectNode(node); rng.collapse(false); } return node; }, removeTrailingWhitespace: function(block) { // TODO: do nothing }, getOuterHTML: function(element) { var div = element.ownerDocument.createElement("div"); div.appendChild(element.cloneNode(true)); return div.innerHTML; }, correctEmptyElement: function(element) { if(!element || element.nodeType !== 1 || this.tree.isAtomic(element)) return; if(element.firstChild) this.correctEmptyElement(element.firstChild); else element.appendChild(this.makePlaceHolder()); }, correctParagraph: function() { if(this.hasSelection()) return false; var block = this.getCurrentBlockElement(); var modified = false; if(!block) { try { this.execCommand("InsertParagraph"); modified = true; } catch(ignored) {} } else if(this.tree.isBlockOnlyContainer(block)) { this.execCommand("InsertParagraph"); // check for HR var newBlock = this.getCurrentElement(); if(this.tree.isAtomic(newBlock.previousSibling) && newBlock.previousSibling.nodeName === "HR") { var nextBlock = this.tree.findForward( newBlock, function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this) ); if(nextBlock) { this.deleteNode(newBlock); this.placeCaretAtStartOf(nextBlock); } } modified = true; } else if(this.tree.hasMixedContents(block)) { this.wrapAllInlineOrTextNodesAs("P", block, true); modified = true; } // insert placeholder - part 1 block = this.getCurrentBlockElement(); if(this.tree.isBlock(block) && !this._hasPlaceHolderAtEnd(block)) { block.appendChild(this.makePlaceHolder()); modified = true; } // insert placeholder - part 2 if(this.tree.isBlock(block)) { var parentsLastChild = block.parentNode.lastChild; if(this.isPlaceHolder(parentsLastChild)) { this.deleteNode(parentsLastChild); modified = true; } } // remove empty elements if(this.tree.isBlock(block)) { var nodes = block.childNodes; for(var i = 0; i < nodes.length; i++) { var node = nodes[i]; if(node.nodeType === 1 && !this.tree.isAtomic(node) && !node.hasChildNodes() && !this.isPlaceHolder(node)) { this.deleteNode(node); } } } return modified; }, _hasPlaceHolderAtEnd: function(block) { if(!block.hasChildNodes()) return false; return this.isPlaceHolder(block.lastChild) || this._hasPlaceHolderAtEnd(block.lastChild); }, applyBackgroundColor: function(color) { this.execCommand("styleWithCSS", "true"); this.execCommand("hilitecolor", color); this.execCommand("styleWithCSS", "false"); // 0. Save current selection var bookmark = this.saveSelection(); // 1. Get selected blocks var blocks = this.getSelectedBlockElements(); if(blocks.length === 0) return; // 2. Apply background-color to all adjust inline elements // 3. Remove background-color from blocks for(var i = 0; i < blocks.length; i++) { if((i === 0 || i === blocks.length-1) && !blocks[i].style.backgroundColor) continue; var spans = this.wrapAllInlineOrTextNodesAs("SPAN", blocks[i], true); for(var j = 0; j < spans.length; j++) { spans[j].style.backgroundColor = color; } blocks[i].style.backgroundColor = ""; } // 4. Restore selection this.restoreSelection(bookmark); }, ////// // Commands execCommand: function(commandId, param) { return this.getDoc().execCommand(commandId, false, param || null); }, applyRemoveFormat: function() { this.execCommand("RemoveFormat"); }, applyRemoveLink: function() { this.execCommand("Unlink"); }, applyEmphasis: function() { // Generate tag. It will be replaced with tag during cleanup phase. this.execCommand("styleWithCSS", "false"); this.execCommand("italic"); }, applyStrongEmphasis: function() { // Generate tag. It will be replaced with tag during cleanup phase. this.execCommand("styleWithCSS", "false"); this.execCommand("bold"); }, applyStrike: function() { // Generate tag. It will be replaced with