/** * @requires Xquared.js * @requires rdom/Base.js */ xq.rdom.Trident = xq.Class(xq.rdom.Base, /** * @name xq.rdom.Trident * @lends xq.rdom.Trident.prototype * @extends xq.rdom.Base * @constructor */ { makePlaceHolder: function() { return this.createTextNode(" "); }, makePlaceHolderString: function() { return ' '; }, makeEmptyParagraph: function() { return this.createElementFromHtml("
"); }, isPlaceHolder: function(node) { return false; }, getOuterHTML: function(element) { return element.outerHTML; }, getCurrentBlockElement: function() { var cur = this.getCurrentElement(); if(!cur) return null; var block = this.getParentBlockElementOf(cur); if(!block) return null; if(block.nodeName === "BODY") { // Atomic block such as HR var newParagraph = this.insertNode(this.makeEmptyParagraph()); var next = newParagraph.nextSibling; if(this.tree.isAtomic(next)) { this.deleteNode(newParagraph); return next; } } else { return block; } }, insertNode: function(node) { if(this.hasSelection()) this.collapseSelection(true); this.rng().pasteHTML(''); var marker = this.$('xquared_temp'); if(node.id === 'xquared_temp') return marker; if(marker) marker.replaceNode(node); return node; }, removeTrailingWhitespace: function(block) { if(!block) return; // @TODO: reimplement to handle atomic tags and so on. (use DomTree) if(this.tree.isBlockOnlyContainer(block)) return; if(this.isEmptyBlock(block)) return; var text = block.innerText; var html = block.innerHTML; var lastCharCode = text.charCodeAt(text.length - 1); if(text.length <= 1 || [32,160].indexOf(lastCharCode) === -1) return; // shortcut for most common case if(text == html.replace(/ /g, " ")) { block.innerHTML = html.replace(/ $/, ""); return; } var node = block; while(node && node.nodeType !== 3) node = node.lastChild; if(!node) return; // DO NOT REMOVE OR MODIFY FOLLOWING CODE. Modifying following code will crash IE7 var nodeValue = node.nodeValue; if(nodeValue.length <= 1) { this.deleteNode(node, true); } else { node.nodeValue = nodeValue.substring(0, nodeValue.length - 1); } }, correctEmptyElement: function(element) { if(!element || element.nodeType !== 1 || this.tree.isAtomic(element)) return; if(element.firstChild) { this.correctEmptyElement(element.firstChild); } else { element.innerHTML = " "; } }, copyAttributes: function(from, to, copyId) { to.mergeAttributes(from, !copyId); }, correctParagraph: function() { if(!this.hasFocus()) return false; if(this.hasSelection()) return false; var block = this.getCurrentElement(); // if caret is at // * atomic block level elements(HR) or // * ... // then following is true if(this.tree.isBlockOnlyContainer(block)) { // check for atomic block element such as HR block = this.insertNode(this.makeEmptyParagraph()); if(this.tree.isAtomic(block.nextSibling)) { // @WORKAROUND: // At this point, HR has a caret but getCurrentElement() doesn't return the HR and // I couldn't find a way to get this HR. So I have to keep this reference. // I will be used in Editor._handleEnter. this.recentHR = block.nextSibling; this.deleteNode(block); return false; } else { // I can't remember exactly when following is executed and what it does :-( // * Case 1: Performing Ctrl+A and Ctrl+X repeatedly // * ... var nextBlock = this.tree.findForward( block, function(node) {return this.tree.isBlock(node) && !this.tree.isBlockOnlyContainer(node)}.bind(this) ); if(nextBlock) { this.deleteNode(block); this.placeCaretAtStartOf(nextBlock); } else { this.placeCaretAtStartOf(block); } return true; } } else { block = this.getCurrentBlockElement(); if(block.nodeType === 3) block = block.parentNode; if(this.tree.hasMixedContents(block)) { var marker = this.pushMarker(); this.wrapAllInlineOrTextNodesAs("P", block, true); this.popMarker(true); return true; } else if((this.tree.isTextOrInlineNode(block.previousSibling) || this.tree.isTextOrInlineNode(block.nextSibling)) && this.tree.hasMixedContents(block.parentNode)) { // @WORKAROUND: // IE에서는 Block과 Inline/Text가 인접한 경우 getCurrentElement 등이 오작동한다. // 따라서 현재 Block 주변까지 한번에 잡아주어야 한다. this.wrapAllInlineOrTextNodesAs("P", block.parentNode, true); return true; } else { return false; } } }, ////// // Commands execCommand: function(commandId, param) { return this.getDoc().execCommand(commandId, false, param); }, applyBackgroundColor: function(color) { this.execCommand("BackColor", color); }, applyEmphasis: function() { // Generate tag. It will be replaced with