MDL-41241 Atto: Restrict searching for anchor tags to selection.

This commit is contained in:
Damyon Wiese 2013-10-02 22:58:29 +08:00
parent 30509335dd
commit 8c11cd2e09
8 changed files with 137 additions and 53 deletions

View File

@ -97,6 +97,7 @@ M.atto_link = M.atto_link || {
resolve_anchors : function() {
// Find the first anchor tag in the selection.
var selectednode = M.editor_atto.get_selection_parent_node(),
anchornodes,
anchornode,
url;
@ -105,9 +106,10 @@ M.atto_link = M.atto_link || {
return;
}
anchornode = M.atto_link.find_nearest_anchor(Y.one(selectednode));
anchornodes = M.atto_link.find_selected_anchors(Y.one(selectednode));
if (anchornode) {
if (anchornodes.length > 0) {
anchornode = anchornodes[0];
M.atto_link.selection = M.editor_atto.get_selection_from_node(anchornode);
url = anchornode.getAttribute('href');
target = anchornode.getAttribute('target');
@ -160,7 +162,7 @@ M.atto_link = M.atto_link || {
var input,
target,
selectednode,
anchornode,
anchornodes,
value;
e.preventDefault();
@ -182,42 +184,47 @@ M.atto_link = M.atto_link || {
return;
}
anchornode = M.atto_link.find_nearest_anchor(Y.one(selectednode));
if (anchornode) {
anchornodes = M.atto_link.find_selected_anchors(Y.one(selectednode));
Y.Array.each(anchornodes, function(anchornode) {
target = e.currentTarget.get('parentNode').one('input[type=checkbox]');
if (target.get('checked')) {
anchornode.setAttribute('target', '_blank');
} else {
anchornode.removeAttribute('target');
}
}
});
}
},
/**
* Look up and down for the nearest anchor tag.
* Look up and down for the nearest anchor tags that are least partly contained in the selection.
*
* @method find_nearest_anchor
* @method find_selected_anchors
* @param Node node
* @return Node|false
*/
find_nearest_anchor : function(node) {
var tagname = node.get('tagName'), hit;
find_selected_anchors : function(node) {
var tagname = node.get('tagName'), hit, hits;
// Direct hit.
if (tagname && tagname.toLowerCase() === 'a') {
return node;
return [node];
}
// Search down.
hit = node.one('a');
if (hit) {
return hit;
// Search down but check that each node is part of the selection.
hits = [];
node.all('a').each(function(n) {
if (!hit && M.editor_atto.selection_contains_node(n)) {
hits.push(n);
}
});
if (hits.length > 0) {
return hits;
}
// Search up.
hit = node.ancestor('a');
if (hit) {
return hit;
return [hit];
}
return false;
return [];
},
/**

View File

@ -1 +1 @@
YUI.add("moodle-atto_link-button",function(e,t){M.atto_link=M.atto_link||{dialogue:null,selection:null,display_chooser:function(e,t){e.preventDefault(),M.editor_atto.is_active(t)||M.editor_atto.focus(t),M.atto_link.selection=M.editor_atto.get_selection();if(M.atto_link.selection!==!1&&!M.atto_link.selection.collapsed){var n;M.atto_link.dialogue?n=M.atto_link.dialogue:n=new M.core.dialogue({visible:!1,modal:!0,close:!0,draggable:!0}),n.render(),n.set("bodyContent",M.atto_link.get_form_content(t)),n.set("headerContent",M.util.get_string("createlink","atto_link")),M.atto_link.resolve_anchors(),n.show(),M.atto_link.dialogue=n}},init:function(e){M.editor_atto.add_toolbar_button(e.elementid,"link",e.icon,e.group,this.display_chooser,this)},resolve_anchors:function(){var t=M.editor_atto.get_selection_parent_node(),n,r;if(!t)return;n=M.atto_link.find_nearest_anchor(e.one(t)),n&&(M.atto_link.selection=M.editor_atto.get_selection_from_node(n),r=n.getAttribute("href"),target=n.getAttribute("target"),r!==""&&e.one("#atto_link_urlentry").set("value",r),target==="_blank"?e.one("#atto_link_openinnewwindow").set("checked","checked"):e.one("#atto_link_openinnewwindow").set("checked",""))},open_filepicker:function(e){var t=this.getAttribute("data-editor");e.preventDefault(),M.editor_atto.show_filepicker(t,"link",M.atto_link.filepicker_callback)},filepicker_callback:function(e){M.atto_link.dialogue.hide(),e.url!==""&&(M.editor_atto.set_selection(M.atto_link.selection),document.execCommand("unlink",!1,null),document.execCommand("createLink",!1,e.url))},set_link:function(t){var n,r,i,s,o;t.preventDefault(),M.atto_link.dialogue.hide(),n=t.currentTarget.get("parentNode").one("input[type=url]"),o=n.get("value");if(o!==""){M.editor_atto.set_selection(M.atto_link.selection),document.execCommand("unlink",!1,null),document.execCommand("createLink",!1,o),i=M.editor_atto.get_selection_parent_node();if(!i)return;s=M.atto_link.find_nearest_anchor(e.one(i)),s&&(r=t.currentTarget.get("parentNode").one("input[type=checkbox]"),r.get("checked")?s.setAttribute("target","_blank"):s.removeAttribute("target"))}},find_nearest_anchor:function(e){var t=e.get("tagName"),n;return t&&t.toLowerCase()==="a"?e:(n=e.one("a"),n?n:(n=e.ancestor("a"),n?n:!1))},get_form_content:function(t){var n=e.Node.create('<form><label for="atto_link_urlentry">'+M.util.get_string("enterurl","atto_link")+"</label><br/>"+'<input type="url" value="" id="atto_link_urlentry" size="32"/>'+"<br/>"+'<label for="atto_link_openinnewwindow">'+M.util.get_string("openinnewwindow","atto_link")+"</label><br/>"+'<input type="checkbox" id="atto_link_openinnewwindow"/>'+"<br/>"+'<button id="openlinkbrowser" data-editor="'+e.Escape.html(t)+'">'+M.util.get_string("browserepositories","atto_link")+"</button>"+"<hr/>"+'<button id="atto_link_urlentrysubmit">'+M.util.get_string("createlink","atto_link")+"</button>"+"</form>"+"<hr/>"+M.util.get_string("accessibilityhint","atto_link"));return n.one("#atto_link_urlentrysubmit").on("click",M.atto_link.set_link),n.one("#openlinkbrowser").on("click",M.atto_link.open_filepicker),n}}},"@VERSION@",{requires:["node","escape"]});
YUI.add("moodle-atto_link-button",function(e,t){M.atto_link=M.atto_link||{dialogue:null,selection:null,display_chooser:function(e,t){e.preventDefault(),M.editor_atto.is_active(t)||M.editor_atto.focus(t),M.atto_link.selection=M.editor_atto.get_selection();if(M.atto_link.selection!==!1&&!M.atto_link.selection.collapsed){var n;M.atto_link.dialogue?n=M.atto_link.dialogue:n=new M.core.dialogue({visible:!1,modal:!0,close:!0,draggable:!0}),n.render(),n.set("bodyContent",M.atto_link.get_form_content(t)),n.set("headerContent",M.util.get_string("createlink","atto_link")),M.atto_link.resolve_anchors(),n.show(),M.atto_link.dialogue=n}},init:function(e){M.editor_atto.add_toolbar_button(e.elementid,"link",e.icon,e.group,this.display_chooser,this)},resolve_anchors:function(){var t=M.editor_atto.get_selection_parent_node(),n,r,i;if(!t)return;n=M.atto_link.find_selected_anchors(e.one(t)),n.length>0&&(r=n[0],M.atto_link.selection=M.editor_atto.get_selection_from_node(r),i=r.getAttribute("href"),target=r.getAttribute("target"),i!==""&&e.one("#atto_link_urlentry").set("value",i),target==="_blank"?e.one("#atto_link_openinnewwindow").set("checked","checked"):e.one("#atto_link_openinnewwindow").set("checked",""))},open_filepicker:function(e){var t=this.getAttribute("data-editor");e.preventDefault(),M.editor_atto.show_filepicker(t,"link",M.atto_link.filepicker_callback)},filepicker_callback:function(e){M.atto_link.dialogue.hide(),e.url!==""&&(M.editor_atto.set_selection(M.atto_link.selection),document.execCommand("unlink",!1,null),document.execCommand("createLink",!1,e.url))},set_link:function(t){var n,r,i,s,o;t.preventDefault(),M.atto_link.dialogue.hide(),n=t.currentTarget.get("parentNode").one("input[type=url]"),o=n.get("value");if(o!==""){M.editor_atto.set_selection(M.atto_link.selection),document.execCommand("unlink",!1,null),document.execCommand("createLink",!1,o),i=M.editor_atto.get_selection_parent_node();if(!i)return;s=M.atto_link.find_selected_anchors(e.one(i)),e.Array.each(s,function(e){r=t.currentTarget.get("parentNode").one("input[type=checkbox]"),r.get("checked")?e.setAttribute("target","_blank"):e.removeAttribute("target")})}},find_selected_anchors:function(e){var t=e.get("tagName"),n,r;return t&&t.toLowerCase()==="a"?[e]:(r=[],e.all("a").each(function(e){!n&&M.editor_atto.selection_contains_node(e)&&r.push(e)}),r.length>0?r:(n=e.ancestor("a"),n?[n]:[]))},get_form_content:function(t){var n=e.Node.create('<form><label for="atto_link_urlentry">'+M.util.get_string("enterurl","atto_link")+"</label><br/>"+'<input type="url" value="" id="atto_link_urlentry" size="32"/>'+"<br/>"+'<label for="atto_link_openinnewwindow">'+M.util.get_string("openinnewwindow","atto_link")+"</label><br/>"+'<input type="checkbox" id="atto_link_openinnewwindow"/>'+"<br/>"+'<button id="openlinkbrowser" data-editor="'+e.Escape.html(t)+'">'+M.util.get_string("browserepositories","atto_link")+"</button>"+"<hr/>"+'<button id="atto_link_urlentrysubmit">'+M.util.get_string("createlink","atto_link")+"</button>"+"</form>"+"<hr/>"+M.util.get_string("accessibilityhint","atto_link"));return n.one("#atto_link_urlentrysubmit").on("click",M.atto_link.set_link),n.one("#openlinkbrowser").on("click",M.atto_link.open_filepicker),n}}},"@VERSION@",{requires:["node","escape"]});

View File

@ -97,6 +97,7 @@ M.atto_link = M.atto_link || {
resolve_anchors : function() {
// Find the first anchor tag in the selection.
var selectednode = M.editor_atto.get_selection_parent_node(),
anchornodes,
anchornode,
url;
@ -105,9 +106,10 @@ M.atto_link = M.atto_link || {
return;
}
anchornode = M.atto_link.find_nearest_anchor(Y.one(selectednode));
anchornodes = M.atto_link.find_selected_anchors(Y.one(selectednode));
if (anchornode) {
if (anchornodes.length > 0) {
anchornode = anchornodes[0];
M.atto_link.selection = M.editor_atto.get_selection_from_node(anchornode);
url = anchornode.getAttribute('href');
target = anchornode.getAttribute('target');
@ -160,7 +162,7 @@ M.atto_link = M.atto_link || {
var input,
target,
selectednode,
anchornode,
anchornodes,
value;
e.preventDefault();
@ -182,42 +184,47 @@ M.atto_link = M.atto_link || {
return;
}
anchornode = M.atto_link.find_nearest_anchor(Y.one(selectednode));
if (anchornode) {
anchornodes = M.atto_link.find_selected_anchors(Y.one(selectednode));
Y.Array.each(anchornodes, function(anchornode) {
target = e.currentTarget.get('parentNode').one('input[type=checkbox]');
if (target.get('checked')) {
anchornode.setAttribute('target', '_blank');
} else {
anchornode.removeAttribute('target');
}
}
});
}
},
/**
* Look up and down for the nearest anchor tag.
* Look up and down for the nearest anchor tags that are least partly contained in the selection.
*
* @method find_nearest_anchor
* @method find_selected_anchors
* @param Node node
* @return Node|false
*/
find_nearest_anchor : function(node) {
var tagname = node.get('tagName'), hit;
find_selected_anchors : function(node) {
var tagname = node.get('tagName'), hit, hits;
// Direct hit.
if (tagname && tagname.toLowerCase() === 'a') {
return node;
return [node];
}
// Search down.
hit = node.one('a');
if (hit) {
return hit;
// Search down but check that each node is part of the selection.
hits = [];
node.all('a').each(function(n) {
if (!hit && M.editor_atto.selection_contains_node(n)) {
hits.push(n);
}
});
if (hits.length > 0) {
return hits;
}
// Search up.
hit = node.ancestor('a');
if (hit) {
return hit;
return [hit];
}
return false;
return [];
},
/**

View File

@ -95,6 +95,7 @@ M.atto_link = M.atto_link || {
resolve_anchors : function() {
// Find the first anchor tag in the selection.
var selectednode = M.editor_atto.get_selection_parent_node(),
anchornodes,
anchornode,
url;
@ -103,9 +104,10 @@ M.atto_link = M.atto_link || {
return;
}
anchornode = M.atto_link.find_nearest_anchor(Y.one(selectednode));
anchornodes = M.atto_link.find_selected_anchors(Y.one(selectednode));
if (anchornode) {
if (anchornodes.length > 0) {
anchornode = anchornodes[0];
M.atto_link.selection = M.editor_atto.get_selection_from_node(anchornode);
url = anchornode.getAttribute('href');
target = anchornode.getAttribute('target');
@ -158,7 +160,7 @@ M.atto_link = M.atto_link || {
var input,
target,
selectednode,
anchornode,
anchornodes,
value;
e.preventDefault();
@ -180,42 +182,47 @@ M.atto_link = M.atto_link || {
return;
}
anchornode = M.atto_link.find_nearest_anchor(Y.one(selectednode));
if (anchornode) {
anchornodes = M.atto_link.find_selected_anchors(Y.one(selectednode));
Y.Array.each(anchornodes, function(anchornode) {
target = e.currentTarget.get('parentNode').one('input[type=checkbox]');
if (target.get('checked')) {
anchornode.setAttribute('target', '_blank');
} else {
anchornode.removeAttribute('target');
}
}
});
}
},
/**
* Look up and down for the nearest anchor tag.
* Look up and down for the nearest anchor tags that are least partly contained in the selection.
*
* @method find_nearest_anchor
* @method find_selected_anchors
* @param Node node
* @return Node|false
*/
find_nearest_anchor : function(node) {
var tagname = node.get('tagName'), hit;
find_selected_anchors : function(node) {
var tagname = node.get('tagName'), hit, hits;
// Direct hit.
if (tagname && tagname.toLowerCase() === 'a') {
return node;
return [node];
}
// Search down.
hit = node.one('a');
if (hit) {
return hit;
// Search down but check that each node is part of the selection.
hits = [];
node.all('a').each(function(n) {
if (!hit && M.editor_atto.selection_contains_node(n)) {
hits.push(n);
}
});
if (hits.length > 0) {
return hits;
}
// Search up.
hit = node.ancestor('a');
if (hit) {
return hit;
return [hit];
}
return false;
return [];
},
/**

View File

@ -485,6 +485,27 @@ M.editor_atto = M.editor_atto || {
return false;
},
/**
* Check that a YUI node it at least partly contained by the selection.
* @param Range selection
* @param Y.Node node
* @return boolean
*/
selection_contains_node : function(node) {
var range, sel;
if (window.getSelection) {
sel = window.getSelection();
if (sel.containsNode) {
return sel.containsNode(node.getDOMNode(), true);
}
}
sel = document.selection.createRange();
range = sel.duplicate();
range.moveToElementText(node.getDOMNode());
return sel.inRange(range);
},
/**
* Get the dom node representing the common anscestor of the selection nodes.
* @return DOMNode

File diff suppressed because one or more lines are too long

View File

@ -485,6 +485,27 @@ M.editor_atto = M.editor_atto || {
return false;
},
/**
* Check that a YUI node it at least partly contained by the selection.
* @param Range selection
* @param Y.Node node
* @return boolean
*/
selection_contains_node : function(node) {
var range, sel;
if (window.getSelection) {
sel = window.getSelection();
if (sel.containsNode) {
return sel.containsNode(node.getDOMNode(), true);
}
}
sel = document.selection.createRange();
range = sel.duplicate();
range.moveToElementText(node.getDOMNode());
return sel.inRange(range);
},
/**
* Get the dom node representing the common anscestor of the selection nodes.
* @return DOMNode

View File

@ -483,6 +483,27 @@ M.editor_atto = M.editor_atto || {
return false;
},
/**
* Check that a YUI node it at least partly contained by the selection.
* @param Range selection
* @param Y.Node node
* @return boolean
*/
selection_contains_node : function(node) {
var range, sel;
if (window.getSelection) {
sel = window.getSelection();
if (sel.containsNode) {
return sel.containsNode(node.getDOMNode(), true);
}
}
sel = document.selection.createRange();
range = sel.duplicate();
range.moveToElementText(node.getDOMNode());
return sel.inRange(range);
},
/**
* Get the dom node representing the common anscestor of the selection nodes.
* @return DOMNode