Skip to content

Commit

Permalink
Fix for Issue 55: Webkit cut is broken
Browse files Browse the repository at this point in the history
The problem stemmed from always inserting the icecut div into the main
document context. Now it uses the document context of the editor, which
is window.document for the contenteditable version and the iframe for
the TinyMCE version. This way Webkit does not get confused about what
element's contents to stick on the clipboard.
  • Loading branch information
Scott Koenig committed Aug 23, 2013
1 parent 7434cea commit 5ca6a39
Showing 1 changed file with 43 additions and 81 deletions.
124 changes: 43 additions & 81 deletions src/plugins/IceCopyPastePlugin/IceCopyPastePlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ IceCopyPastePlugin.prototype = {
}
} else if (c === 'v'){
if(ice.dom.isBrowser("webkit")){
var div = document.getElementById(self._pasteId);
div.focus();
this._ice.env.document.getElementById(self._pasteId).focus();
}
}
return true;
Expand Down Expand Up @@ -140,27 +139,20 @@ IceCopyPastePlugin.prototype = {
// Create a temporary div and set focus to it so that the browser can paste into it.
// Set a timeout to push a paste handler on to the end of the execution stack.
setupPaste: function(stripTags) {
var div = this.createDiv(this._pasteId), self = this;
var div = this.createDiv(this._pasteId),
self = this,
range = this._ice.getCurrentRange();

range.selectNodeContents(div);
this._ice.selection.addRange(range);

div.onpaste = function() {
setTimeout(function(){
self.handlePasteValue(stripTags);
},0);
};

if(this._ice.env.frame){
if(ice.dom.isBrowser("webkit")){
div.blur();
setTimeout(function(){
div.focus();
}, 0);
} else {
div.focus();
}
}
else{
div.focus();
}
return true;
},

Expand All @@ -169,8 +161,9 @@ IceCopyPastePlugin.prototype = {
// and merge the pasted content into the original fragment body.
handlePasteValue: function(stripTags) {
// Get the pasted content.
var html = ice.dom.getHtml(document.getElementById(this._pasteId));
var childBlocks = ice.dom.children('<div>' + html + '</div>', this._ice.blockEl);
var doc = this._ice.env.document,
html = ice.dom.getHtml(doc.getElementById(this._pasteId)),
childBlocks = ice.dom.children('<div>' + html + '</div>', this._ice.blockEl);
if(childBlocks.length === 1 && ice.dom.getNodeTextContent('<div>' + html + '</div>') === ice.dom.getNodeTextContent(childBlocks)) {
html = ice.dom.getHtml(html);
}
Expand Down Expand Up @@ -203,7 +196,7 @@ IceCopyPastePlugin.prototype = {
range.setEndAfter(block.lastChild);
this._ice.selection.addRange(range);
var contents = range.extractContents();
var newblock = this._ice.env.document.createElement(this._ice.blockEl);
var newblock = doc.createElement(this._ice.blockEl);
newblock.appendChild(contents);
ice.dom.insertAfter(block, newblock);

Expand All @@ -228,11 +221,11 @@ IceCopyPastePlugin.prototype = {
if(this._ice.isTracking) {
insert = this._ice.createIceNode('insertType');
this._ice.addChange('insertType', [insert]);
newEl = document.createElement(fragment.firstChild.tagName);
newEl = doc.createElement(fragment.firstChild.tagName);
insert.innerHTML = fragment.firstChild.innerHTML;
newEl.appendChild(insert);
} else {
insert = newEl = document.createElement(fragment.firstChild.tagName);
insert = newEl = doc.createElement(fragment.firstChild.tagName);
newEl.innerHTML = fragment.firstChild.innerHTML;
}
lastEl = insert;
Expand All @@ -242,7 +235,7 @@ IceCopyPastePlugin.prototype = {
} else {
if(!innerBlock) {
// Create a new block and append an insert
newEl = document.createElement(this._ice.blockEl);
newEl = doc.createElement(this._ice.blockEl);
ice.dom.insertBefore(prevBlock, newEl);
if(this._ice.isTracking) {
innerBlock = this._ice.createIceNode('insertType');
Expand Down Expand Up @@ -282,12 +275,13 @@ IceCopyPastePlugin.prototype = {


createDiv: function(id) {
var oldEl = ice.dom.getId(id);
var doc = this._ice.env.document, // Document object of window or tinyMCE iframe
oldEl = doc.getElementById(id);
if(oldEl) {
ice.dom.remove(oldEl);
}

var div = this._ice.env.document.createElement('div');
var div = doc.createElement('div');
div.id = id;
div.setAttribute('contentEditable', true);
ice.dom.setStyle(div, 'width', '1px');
Expand All @@ -297,75 +291,43 @@ IceCopyPastePlugin.prototype = {
ice.dom.setStyle(div, 'top', '10px');
ice.dom.setStyle(div, 'left', '10px');

document.body.appendChild(div);
div.appendChild(doc.createElement('br'));
doc.body.appendChild(div);
return div;
},

// Intercepts cut operation and handles by creating an editable div, copying the current selection
// into it, deleting the current selection with track changes, and selecting the contents in the
// editable div.
handleCut: function() {
this.cutElementId = 'icecut';
this.cutElement = this.createDiv(this.cutElementId);
var range = this._ice.getCurrentRange();
if(range.collapsed) return;
var html = range.getHTMLContents();
var self = this,
range = this._ice.getCurrentRange();
if (range.collapsed) return; // If nothing is selected, there's nothing to mark deleted

this.cutElement = this.createDiv('icecut');
// Chrome strips out spaces between text nodes and elements node during cut
this.cutElement.innerHTML = range.getHTMLContents().replace(/ </g, '&nbsp;<').replace(/> /g, '>&nbsp;');

if (this._ice.isTracking) this._ice.deleteContents();
else range.deleteContents();
// var crange = range.cloneRange();
// var crange = rangy.createRange();
var crange = document.createRange();
// crange.collapse(true);
this.cutElement.innerHTML = html;

var crange = this._ice.env.document.createRange();
crange.setStart(this.cutElement.firstChild, 0);
crange.setEndAfter(this.cutElement.lastChild);
var self = this;

// this.cutElement.blur();
if(this._ice.env.frame){
// TINYMCE
setTimeout(function(){
self.cutElement.focus();

// After the browser cuts out of the `cutElement`, reset the range and remove the cut element.
setTimeout(function() {
ice.dom.remove(self.cutElement);
range.setStart(range.startContainer, range.startOffset);
range.collapse(false);
self._ice.env.selection.addRange(range);
// Set focus back to ice element.
if(self._ice.env.frame) {
self._ice.env.frame.contentWindow.focus();
} else {
self._ice.element.focus();
}
}, 100);
}, 0);
} else {
// Vanilla Div
setTimeout(function(){
self.cutElement.focus();

// After the browser cuts out of the `cutElement`, reset the range and remove the cut element.
setTimeout(function() {
range.setStart(range.startContainer, range.startOffset);
range.collapse(false);
self._ice.env.selection.addRange(range);
// Set focus back to ice element.
if(self._ice.env.frame) {
self._ice.env.frame.contentWindow.focus();
} else {
self._ice.element.focus();
}
}, 100);
}, 0);

if(ice.dom.getWebkitType() === "chrome"){
self.cutElement.focus();
}
}
self._ice.env.selection.addRange(crange);
crange.setEndAfter(this.cutElement.lastChild);

setTimeout(function() {
self.cutElement.focus();

// After the browser cuts out of the `cutElement`, reset the range and remove the cut element.
setTimeout(function() {
ice.dom.remove(self.cutElement);
range.setStart(range.startContainer, range.startOffset);
range.collapse(false);
self._ice.env.selection.addRange(range);
}, 100);
}, 0);

self._ice.env.selection.addRange(crange);
},


Expand Down

0 comments on commit 5ca6a39

Please sign in to comment.