123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- define("dojox/editor/plugins/Blockquote", [
- "dojo",
- "dijit",
- "dojox",
- "dijit/_editor/range",
- "dijit/_editor/selection",
- "dijit/_editor/_Plugin",
- "dijit/form/ToggleButton",
- "dojo/_base/connect",
- "dojo/_base/declare",
- "dojo/i18n",
- "dojo/i18n!dojox/editor/plugins/nls/Blockquote"
- ], function(dojo, dijit, dojox) {
- dojo.declare("dojox.editor.plugins.Blockquote",dijit._editor._Plugin,{
- // summary:
- // This plugin provides Blockquote cabability to the editor.
- // window/tab
- // iconClassPrefix: [const] String
- // The CSS class name for the button node icon.
- iconClassPrefix: "dijitAdditionalEditorIcon",
- _initButton: function(){
- // summary:
- // Over-ride for creation of the preview button.
- this._nlsResources = dojo.i18n.getLocalization("dojox.editor.plugins", "Blockquote");
- this.button = new dijit.form.ToggleButton({
- label: this._nlsResources["blockquote"],
- showLabel: false,
- iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "Blockquote",
- tabIndex: "-1",
- onClick: dojo.hitch(this, "_toggleQuote")
- });
- },
- setEditor: function(editor){
- // summary:
- // Over-ride for the setting of the editor.
- // editor: Object
- // The editor to configure for this plugin to use.
- this.editor = editor;
- this._initButton();
- this.connect(this.editor, "onNormalizedDisplayChanged", "updateState");
- // We need the custom undo code since we manipulate the dom
- // outside of the browser natives and only customUndo really handles
- // that. It will incur a performance hit, but should hopefully be
- // relatively small.
- editor.customUndo = true;
- },
-
- _toggleQuote: function(arg){
- // summary:
- // Function to trigger previewing of the editor document
- // tags:
- // private
- try{
- var ed = this.editor;
- ed.focus();
- var quoteIt = this.button.get("checked");
- var sel = dijit.range.getSelection(ed.window);
- var range, elem, start, end;
- if(sel && sel.rangeCount > 0){
- range = sel.getRangeAt(0);
- }
- if(range){
- ed.beginEditing();
- if(quoteIt){
- // Lets see what we've got as a selection...
- var bq, tag;
- if(range.startContainer === range.endContainer){
- // No selection, just cursor point, we need to see if we're
- // in an indentable block, or similar.
- if(this._isRootInline(range.startContainer)){
- // Text at the 'root' of the document, so we need to gather all of it.,
-
- // First, we need to find the toplevel inline element that is rooted
- // to the document 'editNode'
- start = range.startContainer;
- while(start && start.parentNode !== ed.editNode){
- start = start.parentNode;
- }
- // Now we need to walk up its siblings and look for the first one in the rooting
- // that isn't inline or text, as we want to grab all of that for indent.
- while(start && start.previousSibling && (
- this._isTextElement(start) ||
- (start.nodeType === 1 &&
- this._isInlineFormat(this._getTagName(start))
- ))){
- start = start.previousSibling;
- }
- if(start && start.nodeType === 1 &&
- !this._isInlineFormat(this._getTagName(start))){
- // Adjust slightly, we're one node too far back in this case.
- start = start.nextSibling;
- }
-
- // Okay, we have a configured start, lets grab everything following it that's
- // inline and make it part of the blockquote!
- if(start){
- bq = ed.document.createElement("blockquote");
- dojo.place(bq, start, "after");
- bq.appendChild(start);
- end = bq.nextSibling;
- while(end && (
- this._isTextElement(end) ||
- (end.nodeType === 1 &&
- this._isInlineFormat(this._getTagName(end)))
- )){
- // Add it.
- bq.appendChild(end);
- end = bq.nextSibling;
- }
- }
- }else{
- // Figure out what to do when not root inline....
- var node = range.startContainer;
- while ((this._isTextElement(node) ||
- this._isInlineFormat(this._getTagName(node))
- || this._getTagName(node) === "li") &&
- node !== ed.editNode && node !== ed.document.body){
- node = node.parentNode;
- }
- if(node !== ed.editNode && node !== node.ownerDocument.documentElement){
- bq = ed.document.createElement("blockquote");
- dojo.place(bq, node, "after");
- bq.appendChild(node);
- }
- }
- if(bq){
- dojo.withGlobal(ed.window,
- "selectElementChildren", dijit._editor.selection, [bq]);
- dojo.withGlobal(ed.window,
- "collapse", dijit._editor.selection, [true]);
- }
- }else{
- var curNode;
- // multi-node select. We need to scan over them.
- // Find the two containing nodes at start and end.
- // then move the end one node past. Then ... lets see
- // what we can blockquote!
- start = range.startContainer;
- end = range.endContainer;
- // Find the non-text nodes.
- while(start && this._isTextElement(start) && start.parentNode !== ed.editNode){
- start = start.parentNode;
- }
- // Try to find the end node. We have to check the selection junk
- curNode = start;
- while(curNode.nextSibling && dojo.withGlobal(ed.window,
- "inSelection", dijit._editor.selection, [curNode])){
- curNode = curNode.nextSibling;
- }
- end = curNode;
- if(end === ed.editNode || end === ed.document.body){
- // Unable to determine real selection end, so just make it
- // a single node indent of start + all following inline styles, if
- // present, then just exit.
- bq = ed.document.createElement("blockquote");
- dojo.place(bq, start, "after");
- tag = this._getTagName(start);
- if(this._isTextElement(start) || this._isInlineFormat(tag)){
- // inline element or textnode
- // Find and move all inline tags following the one we inserted also into the
- // blockquote so we don't split up content funny.
- var next = start;
- while(next && (
- this._isTextElement(next) ||
- (next.nodeType === 1 &&
- this._isInlineFormat(this._getTagName(next))))){
- bq.appendChild(next);
- next = bq.nextSibling;
- }
- }else{
- bq.appendChild(start);
- }
- return;
- }
- // Has a definite end somewhere, so lets try to blockquote up to it.
- // requires looking at the selections and in some cases, moving nodes
- // into separate blockquotes.
- end = end.nextSibling;
- curNode = start;
- while(curNode && curNode !== end){
- if(curNode.nodeType === 1){
- tag = this._getTagName(curNode);
- if(tag !== "br"){
- if(!window.getSelection){
- // IE sometimes inserts blank P tags, which we want to skip
- // as they end up blockquoted, which messes up layout.
- if(tag === "p" && this._isEmpty(curNode)){
- curNode = curNode.nextSibling;
- continue;
- }
- }
- if(this._isInlineFormat(tag)){
- // inline tag.
- if(!bq){
- bq = ed.document.createElement("blockquote");
- dojo.place(bq, curNode, "after");
- bq.appendChild(curNode);
- }else{
- bq.appendChild(curNode);
- }
- curNode = bq;
- }else{
- if(bq){
- if(this._isEmpty(bq)){
- bq.parentNode.removeChild(bq);
- }
- }
- bq = ed.document.createElement("blockquote");
- dojo.place(bq, curNode, "after");
- bq.appendChild(curNode);
- curNode = bq;
- }
- }
- }else if(this._isTextElement(curNode)){
- if(!bq){
- bq = ed.document.createElement("blockquote");
- dojo.place(bq, curNode, "after");
- bq.appendChild(curNode);
- }else{
- bq.appendChild(curNode);
- }
- curNode = bq;
- }
- curNode = curNode.nextSibling;
- }
- // Okay, check the last bq, remove it if no content.
- if(bq){
- if(this._isEmpty(bq)){
- bq.parentNode.removeChild(bq);
- }else{
- dojo.withGlobal(ed.window,
- "selectElementChildren", dijit._editor.selection, [bq]);
- dojo.withGlobal(ed.window,
- "collapse", dijit._editor.selection, [true]);
- }
- bq = null;
- }
- }
- }else{
- var found = false;
- if(range.startContainer === range.endContainer){
- elem = range.endContainer;
- // Okay, now see if we can find one of the formatting types we're in.
- while(elem && elem !== ed.editNode && elem !== ed.document.body){
- var tg = elem.tagName?elem.tagName.toLowerCase():"";
- if(tg === "blockquote"){
- found = true;
- break;
- }
- elem = elem.parentNode;
- }
- if(found){
- var lastChild;
- while(elem.firstChild){
- lastChild = elem.firstChild;
- dojo.place(lastChild, elem, "before");
- }
- elem.parentNode.removeChild(elem);
- if(lastChild){
- dojo.withGlobal(ed.window,
- "selectElementChildren", dijit._editor.selection, [lastChild]);
- dojo.withGlobal(ed.window,
- "collapse", dijit._editor.selection, [true]);
- }
- }
- }else{
- // Multi-select! Gotta find all the blockquotes contained within the selection area.
- start = range.startContainer;
- end = range.endContainer;
- while(start && this._isTextElement(start) && start.parentNode !== ed.editNode){
- start = start.parentNode;
- }
- var selectedNodes = [];
- var cNode = start;
- while(cNode && cNode.nextSibling && dojo.withGlobal(ed.window,
- "inSelection", dijit._editor.selection, [cNode])){
- if(cNode.parentNode && this._getTagName(cNode.parentNode) === "blockquote"){
- cNode = cNode.parentNode;
- }
- selectedNodes.push(cNode);
- cNode = cNode.nextSibling;
- }
-
- // Find all the blocknodes now that we know the selection area.
- var bnNodes = this._findBlockQuotes(selectedNodes);
- while(bnNodes.length){
- var bn = bnNodes.pop();
- if(bn.parentNode){
- // Make sure we haven't seen this before and removed it.
- while(bn.firstChild){
- dojo.place(bn.firstChild, bn, "before");
- }
- bn.parentNode.removeChild(bn);
- }
- }
- }
- }
- ed.endEditing();
- }
- ed.onNormalizedDisplayChanged();
- }catch(e){ /* Squelch */ }
- },
- updateState: function(){
- // summary:
- // Overrides _Plugin.updateState(). This controls whether or not the current
- // cursor position should toggle on the quote button or not.
- // tags:
- // protected
- var ed = this.editor;
- var disabled = this.get("disabled");
-
- if(!ed || !ed.isLoaded){ return; }
- if(this.button){
- this.button.set("disabled", disabled);
- if(disabled){
- return;
- }
- // Some browsers (WebKit) doesn't actually get the tag info right.
- // So ... lets check it manually.
- var elem;
- var found = false;
-
- // Try to find the ansestor element (and see if it is blockquote)
- var sel = dijit.range.getSelection(ed.window);
- if(sel && sel.rangeCount > 0){
- var range = sel.getRangeAt(0);
- if(range){
- elem = range.endContainer;
- }
- }
- // Okay, now see if we can find one of the formatting types we're in.
- while(elem && elem !== ed.editNode && elem !== ed.document){
- var tg = elem.tagName?elem.tagName.toLowerCase():"";
- if(tg === "blockquote"){
- found = true;
- break;
- }
- elem = elem.parentNode;
- }
- // toggle whether or not the current selection is blockquoted.
- this.button.set("checked", found);
- }
- },
- _findBlockQuotes: function(nodeList){
- // summary:
- // function to find a ll the blocknode elements in a collection of
- // nodes
- // nodeList:
- // The list of nodes.
- // tags:
- // private
- var bnList = [];
- if(nodeList){
- var i;
- for(i = 0; i < nodeList.length; i++){
- var node = nodeList[i];
- if(node.nodeType === 1){
- if(this._getTagName(node) === "blockquote"){
- bnList.push(node);
- }
- if(node.childNodes && node.childNodes.length > 0){
- bnList = bnList.concat(this._findBlockQuotes(node.childNodes));
- }
- }
- }
- }
- return bnList;
- },
- /*****************************************************************/
- /* Functions borrowed from NormalizeIndentOutdent */
- /*****************************************************************/
- _getTagName: function(node){
- // summary:
- // Internal function to get the tag name of an element
- // if any.
- // node:
- // The node to look at.
- // tags:
- // private
- var tag = "";
- if(node && node.nodeType === 1){
- tag = node.tagName?node.tagName.toLowerCase():"";
- }
- return tag;
- },
- _isRootInline: function(node){
- // summary:
- // This functions tests whether an indicated node is in root as inline
- // or rooted inline elements in the page.
- // node:
- // The node to start at.
- // tags:
- // private
- var ed = this.editor;
- if(this._isTextElement(node) && node.parentNode === ed.editNode){
- return true;
- }else if(node.nodeType === 1 && this._isInlineFormat(node) && node.parentNode === ed.editNode){
- return true;
- }else if(this._isTextElement(node) && this._isInlineFormat(this._getTagName(node.parentNode))){
- node = node.parentNode;
- while(node && node !== ed.editNode && this._isInlineFormat(this._getTagName(node))){
- node = node.parentNode;
- }
- if(node === ed.editNode){
- return true;
- }
- }
- return false;
- },
- _isTextElement: function(node){
- // summary:
- // Helper function to check for text nodes.
- // node:
- // The node to check.
- // tags:
- // private
- if(node && node.nodeType === 3 || node.nodeType === 4){
- return true;
- }
- return false;
- },
- _isEmpty: function(node){
- // summary:
- // Internal function to determine if a node is 'empty'
- // Eg, contains only blank text. Used to determine if
- // an empty list element should be removed or not.
- // node:
- // The node to check.
- // tags:
- // private
- if(node.childNodes){
- var empty = true;
- var i;
- for(i = 0; i < node.childNodes.length; i++){
- var n = node.childNodes[i];
- if(n.nodeType === 1){
- if(this._getTagName(n) === "p"){
- if(!dojo.trim(n.innerHTML)){
- continue;
- }
- }
- empty = false;
- break;
- }else if(this._isTextElement(n)){
- // Check for empty text.
- var nv = dojo.trim(n.nodeValue);
- if(nv && nv !==" " && nv !== "\u00A0"){
- empty = false;
- break;
- }
- }else{
- empty = false;
- break;
- }
- }
- return empty;
- }else{
- return true;
- }
- },
- _isInlineFormat: function(tag){
- // summary:
- // Function to determine if the current tag is an inline
- // element that does formatting, as we don't want to
- // break/indent around it, as it can screw up text.
- // tag:
- // The tag to examine
- // tags:
- // private
- switch(tag){
- case "a":
- case "b":
- case "strong":
- case "s":
- case "strike":
- case "i":
- case "u":
- case "em":
- case "sup":
- case "sub":
- case "span":
- case "font":
- case "big":
- case "cite":
- case "q":
- case "img":
- case "small":
- return true;
- default:
- return false;
- }
- }
- });
- // Register this plugin.
- dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
- if(o.plugin){ return; }
- var name = o.args.name.toLowerCase();
- if(name === "blockquote"){
- o.plugin = new dojox.editor.plugins.Blockquote({});
- }
- });
- return dojox.editor.plugins.Blockquote;
- });
|