ryan
unread,Jan 31, 2009, 7:37:04 PM1/31/09Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to MooEditable
Hello
As i mentioned, i found a few quirks in MooEditable.Selection,
particularly with webkit - it was returning the selected node as
<body> even when the getContent method was returning the correct
value.
Anyway, after a bit of hoking, i noticed that the guys at 37 signals
are creating a wyswig editor to work with prototype, and i checked out
their selection class - it seemed to have a lot more webkit specific
stuff in it, so i ported it over to MooEditable and my problems were
gone...
Here's the new class - I've not noticed any impact on other
browsers.... so it seems to be a positive change.
MooEditable.Selection = new Class({
initialize: function(editor) {
this.win = editor.win;
this.doc = editor.doc;
},
createRangeFromElement: function(node) {
if (this.doc.body.createTextRange) {
var range = this.doc.body.createTextRange();
range.moveToElementText(node);
} else if (this.doc.createRange) {
var range = this.doc.createRange();
range.selectNodeContents(node);
}
return range;
},
compareRanges: function(r1, r2) {
if (r1.compareEndPoints) {
return !(
r2.compareEndPoints('StartToStart', r1) == 1 &&
r2.compareEndPoints('EndToEnd', r1) == 1 &&
r2.compareEndPoints('StartToEnd', r1) == 1 &&
r2.compareEndPoints('EndToStart', r1) == 1
||
r2.compareEndPoints('StartToStart', r1) == -1 &&
r2.compareEndPoints('EndToEnd', r1) == -1 &&
r2.compareEndPoints('StartToEnd', r1) == -1 &&
r2.compareEndPoints('EndToStart', r1) == -1
);
} else if (r1.compareBoundaryPoints) {
return !(
r2.compareBoundaryPoints(0, r1) == 1 &&
r2.compareBoundaryPoints(2, r1) == 1 &&
r2.compareBoundaryPoints(1, r1) == 1 &&
r2.compareBoundaryPoints(3, r1) == 1
||
r2.compareBoundaryPoints(0, r1) == -1 &&
r2.compareBoundaryPoints(2, r1) == -1 &&
r2.compareBoundaryPoints(1, r1) == -1 &&
r2.compareBoundaryPoints(3, r1) == -1
);
}
return null;
},
getSelection: function() {
return (this.win.getSelection) ? this.win.getSelection() :
this.doc.selection;
},
getRange: function() {
var selection = this.getSelection();
try {
var range;
if (selection.getRangeAt)
range = selection.getRangeAt(0);
else
range = selection.createRange();
} catch(e) { return null; }
if (Browser.Engine.WebKit) {
range.setStart(selection.baseNode, selection.baseOffset);
range.setEnd(selection.extentNode, selection.extentOffset);
}
return range;
},
/*
getRange: function() {
var s = this.getSelection();
if (!s) return null;
try {
range = s.rangeCount > 0 ? s.getRangeAt(0) : (s.createRange ?
s.createRange() : null);
if (Browser.Engine.WebKit) {
range.setStart(selection.baseNode, selection.baseOffset);
range.setEnd(selection.extentNode, selection.extentOffset);
}
return range;
} catch (e) {
// IE bug when used in frameset
return this.doc.body.createTextRange();
}
}, */
setRange: function(range) {
if (range.select) $try(function(){
range.select();
});
else {
var s = this.getSelection();
if (s.addRange) {
s.removeAllRanges();
s.addRange(range);
}
}
},
selectNode: function(node) {
var selection = this.getSelection();
if (Browser.Engine.Trident) {
var range = createRangeFromElement(node);
range.select();
} else if (Browser.Engine.WebKit) {
selection.setBaseAndExtent(node, 0, node, node.innerText.length);
} else if (Browser.Engine.Presto) {
range = this.doc.createRange();
range.selectNode(node);
selection.removeAllRanges();
selection.addRange(range);
} else {
var range = this.createRangeFromElement(node);
selection.removeAllRanges();
selection.addRange(range);
}
return node;
},
isCollapsed: function() {
var r = this.getRange();
if (r.item) return false;
return r.boundingWidth == 0 || this.getSelection().isCollapsed;
},
collapse: function(toStart) {
var r = this.getRange();
var s = this.getSelection();
if (r.select) {
r.collapse(toStart);
r.select();
}
else
toStart ? s.collapseToStart() : s.collapseToEnd();
},
getContent: function() {
var r = this.getRange();
var body = new Element('body');
if (this.isCollapsed()) return '';
if (r.cloneContents) body.appendChild(r.cloneContents());
else if ($defined(r.item) || $defined(r.htmlText)) body.set('html',
r.item ? r.item(0).outerHTML : r.htmlText);
else body.set('html', r.toString());
var content = body.get('html');
return content;
},
getText : function() {
var r = this.getRange();
var s = this.getSelection();
return this.isCollapsed() ? '' : r.text || s.toString();
},
getNode: function() {
var nodes = null, candidates = [], children, el;
var range = this.getRange();
if (!range)
return null;
var parent;
if (range.parentElement)
parent = range.parentElement();
else
parent = range.commonAncestorContainer;
if (parent) {
while (parent.nodeType != 1) parent = parent.parentNode;
if (parent.nodeName.toLowerCase() != "body") {
el = parent;
do {
el = el.parentNode;
candidates[candidates.length] = el;
} while (el.nodeName.toLowerCase() != "body");
}
children = parent.all || parent.getElementsByTagName("*");
for (var j = 0; j < children.length; j++)
candidates[candidates.length] = children[j];
nodes = [parent];
for (var ii = 0, r2; ii < candidates.length; ii++) {
r2 = this.createRangeFromElement(candidates[ii]);
if (r2 && this.compareRanges(range, r2))
nodes[nodes.length] = candidates[ii];
}
}
return $(nodes[0]);
},
insertContent: function(content) {
var r = this.getRange();
if (r.insertNode) {
r.deleteContents();
if($type(content) == 'element') {
var temp = new Element('div').adopt(content);
content = temp.get('html');
}
r.insertNode(r.createContextualFragment(content));
}
else {
// Handle text and control range
if (r.pasteHTML) r.pasteHTML(content);
else r.item(0).outerHTML = content;
}
},
// get the properties of attributes
// return an object/hash
getProperties: function(me,tag,props) {
var el = me.selection.getNode();
var vals = new Hash();
if (el) {
if (el.nodeType == 1) {
if (tag.toLowerCase() == el.tagName.toLowerCase()) {
var hsh = new Hash({});
props.each(function(e) {
if(el.getProperty(e) != null)
hsh.set(e,el.getProperty(e))
},this);
return hsh;
}
}
}
return vals;
},
// surround selection with element (same as outerHTML)
surround: function(el) {
this.insertContent(el.set('html',this.getRange()));
}
});