1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is BlueGriffon.
16 * The Initial Developer of the Original Code is
17 * Disruptive Innovations SARL.
18 * Portions created by the Initial Developer are Copyright (C) 2006
19 * the Initial Developer. All Rights Reserved.
22 * Daniel Glazman <daniel.glazman@disruptive-innovations.com>, Original author
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
40 /********** PUBLIC **********/
42 getCurrentTabEditor: function getCurrentTabEditor()
44 var tmpWindow = window;
47 // do we have an app-modal window on MAC OS X ?
48 if (window.location.href != "chrome://bluegriffon/content/xul/bluegriffon.xul" &&
51 var windowManager = Components.classes[kWINDOWMEDIATOR_CID].getService();
52 var windowManagerInterface = windowManager.QueryInterface(nsIWindowMediator);
53 tmpWindow = windowManagerInterface.getMostRecentWindow("bluegriffon");
58 var tabeditor = tmpWindow.document.getElementById("tabeditor");
63 tmpWindow = tmpWindow.opener;
70 getCurrentEditorElement: function getCurrentEditorElement()
72 var tabeditor = this.getCurrentTabEditor();
74 return tabeditor.getCurrentEditorElement() ;
78 getCurrentEditor: function getCurrentEditor()
80 // Get the active editor from the <editor> tag
83 var editorElement = this.getCurrentEditorElement();
86 editor = editorElement.getEditor(editorElement.contentWindow);
88 // Do QIs now so editor users won't have to figure out which interface to use
89 // Using "instanceof" does the QI for us.
90 editor instanceof Components.interfaces.nsIEditor;
91 editor instanceof Components.interfaces.nsIPlaintextEditor;
92 editor instanceof Components.interfaces.nsIHTMLEditor;
94 } catch (e) { dump("Error in GetCurrentEditor: " + e + "\n"); }
99 getCurrentDocument: function getCurrentDocument()
101 // Get the active editor from the <editor> tag
102 var editor = this.getCurrentEditor();
104 return editor.document;
108 getCurrentCommandManager: function getCurrentCommandManager()
111 return this.getCurrentEditorElement().commandManager;
112 } catch (e) { dump (e)+"\n"; }
117 newCommandParams: function newCommandParams()
120 const contractId = "@mozilla.org/embedcomp/command-params;1";
121 const nsICommandParams = Components.interfaces.nsICommandParams;
123 return Components.classes[contractId].createInstance(nsICommandParams);
125 catch(e) { dump("error thrown in newCommandParams: "+e+"\n"); }
129 getCurrentEditingSession: function getCurrentEditingSession()
132 return this.getCurrentEditorElement().editingSession;
133 } catch (e) { dump (e)+"\n"; }
138 getCurrentEditorType: function getCurrentEditorType()
141 return this.getCurrentEditorElement().editortype;
142 } catch (e) { dump (e)+"\n"; }
147 isAlreadyEdited: function isAlreadyEdited(aURL)
149 // blank documents are never "already edited"...
150 if (UrlUtils.isUrlAboutBlank(aURL))
153 var url = UrlUtils.newURI(aURL).spec;
155 var windowManager = Components.classes[kWINDOWMEDIATOR_CID].getService();
156 var windowManagerInterface = windowManager.QueryInterface(nsIWindowMediator);
157 var enumerator = windowManagerInterface.getEnumerator( "bluegriffon" );
158 while ( enumerator.hasMoreElements() )
160 var win = enumerator.getNext().QueryInterface(nsIDOMWindowInternal);
162 var mixed = win.gDialog.tabeditor.isAlreadyEdited(url);
164 return {window: win, editor: mixed.editor, index: mixed.index};
171 isDocumentEditable: function isDocumentEditable()
174 return this.getCurrentEditor().isDocumentEditable;
175 } catch (e) { dump (e)+"\n"; }
179 isDocumentModified: function isDocumentModified()
182 return this.getCurrentEditor().documentModified;
183 } catch (e) { dump (e)+"\n"; }
187 isDocumentEmpty: function isDocumentEmpty()
190 return this.getCurrentEditor().documentIsEmpty;
191 } catch (e) { dump (e)+"\n"; }
195 getDocumentTitle: function getDocumentTitle()
198 return this.getCurrentDocument().title;
199 } catch (e) { dump (e)+"\n"; }
204 isHTMLEditor: function isHTMLEditor()
206 // We don't have an editorElement, just return false
207 if (!this.getCurrentEditorElement())
210 var editortype = this.getCurrentEditorType();
222 dump("INVALID EDITOR TYPE: " + editortype + "\n");
228 isEditingRenderedHTML: function isEditingRenderedHTML()
230 return this.isHTMLEditor(); // && !this.isInHTMLSourceMode();
233 setDocumentTitle: function setDocumentTitle(title)
236 this.getCurrentEditor().setDocumentTitle(title);
238 // Update window title (doesn't work if called from a dialog)
239 if ("UpdateWindowTitle" in window)
240 window.UpdateWindowTitle();
241 else if ("UpdateWindowTitle" in window.opener)
242 window.opener.UpdateWindowTitle();
243 } catch (e) { dump (e)+"\n"; }
246 getSelectionContainer: function getSelectionContainer()
248 var editor = this.getCurrentEditor();
249 if (!editor) return null;
252 var selection = editor.selection;
253 if (!selection) return null;
255 catch (e) { return null; }
257 var result = { oneElementSelected:false };
259 if (selection.isCollapsed) {
260 result.node = selection.focusNode;
263 var rangeCount = selection.rangeCount;
264 if (rangeCount == 1) {
265 result.node = editor.getSelectedElement("");
266 var range = selection.getRangeAt(0);
268 // check for a weird case : when we select a piece of text inside
269 // a text node and apply an inline style to it, the selection starts
270 // at the end of the text node preceding the style and ends after the
271 // last char of the style. Assume the style element is selected for
274 range.startContainer.nodeType == Node.TEXT_NODE &&
275 range.startOffset == range.startContainer.length &&
276 range.endContainer.nodeType == Node.TEXT_NODE &&
277 range.endOffset == range.endContainer.length &&
278 range.endContainer.nextSibling == null &&
279 range.startContainer.nextSibling == range.endContainer.parentNode)
280 result.node = range.endContainer.parentNode;
283 // let's rely on the common ancestor of the selection
284 result.node = range.commonAncestorContainer;
287 result.oneElementSelected = true;
291 // assume table cells !
292 var i, container = null;
293 for (i = 0; i < rangeCount; i++) {
294 range = selection.getRangeAt(i);
296 container = range.startContainer;
298 else if (container != range.startContainer) {
299 // all table cells don't belong to same row so let's
300 // select the parent of all rows
301 result.node = container.parentNode;
304 result.node = container;
309 // make sure we have an element here
310 while (result.node.nodeType != Node.ELEMENT_NODE)
311 result.node = result.node.parentNode;
313 // and make sure the element is not a special editor node like
314 // the <br> we insert in blank lines
315 // and don't select anonymous content !!! (fix for bug 190279)
316 editor instanceof Components.interfaces.nsIHTMLEditor;
317 while (result.node.hasAttribute("_moz_editor_bogus_node") ||
318 editor.isAnonymousElement(result.node))
319 result.node = result.node.parentNode;
324 getMetaElement: function getMetaElement(aName)
328 var name = aName.toLowerCase();
330 var metanodes = this.getCurrentDocument()
331 .getElementsByTagName("meta");
332 for (var i = 0; i < metanodes.length; i++)
334 var metanode = metanodes.item(i);
335 if (metanode && metanode.getAttribute("name") == name)
344 createMetaElement: function createMetaElement(aName)
346 var editor = this.getCurrentEditor();
348 var metanode = editor.createElementWithDefaults("meta");
349 metanode.setAttribute("name", aName);
356 insertMetaElement: function insertMetaElement(aElt, aContent, aInsertNew, aPrepend)
360 var editor = this.getCurrentEditor();
365 editor.deleteNode(aElt);
371 aElt.setAttribute("content", aContent);
373 this.prependHeadElement(aElt);
375 this.appendHeadElement(aElt);
379 editor.setAttribute(aElt, "content", aContent);
387 getHeadElement: function getHeadElement()
390 var doc = EditorUtils.getCurrentDocument();
391 var heads = doc.getElementsByTagName("head");
392 return heads.item(0);
399 prependHeadElement: function prependHeadElement(aElt)
401 var head = this.getHeadElement();
404 var editor = EditorUtils.getCurrentEditor();
405 editor.insertNode(aElt, head, 0, true);
410 appendHeadElement: function appendHeadElement(aElt)
412 var head = this.getHeadElement();
416 if (head.hasChildNodes())
417 pos = head.childNodes.length;
419 var editor = EditorUtils.getCurrentEditor();
420 editor.insertNode(aElt, head, pos, true);
426 getTextProperty: function(property, attribute, value, firstHas, anyHas, allHas)
429 if (!gAtomService) GetAtomService();
430 var propAtom = gAtomService.getAtom(property);
432 this.getCurrentEditor().getInlineProperty(propAtom, attribute, value,
433 firstHas, anyHas, allHas);
438 getClasses: function(aElt)
441 var display = CssUtils.getComputedStyle(e).getPropertyValue("display");
442 while (e && display == "inline" && e.className == "")
445 display = CssUtils.getComputedStyle(e).getPropertyValue("display");
447 return {classes: e.className, node: e};
450 getCurrentTableEditor: function()
452 var editor = this.getCurrentEditor();
454 (editor instanceof Components.interfaces.nsITableEditor)) ? editor : null;
457 isStrictDTD: function()
459 var doctype = this.getCurrentEditor().document.doctype;
460 return (doctype.publicId.lastIndexOf("Strict") != -1);
463 isCSSDisabledAndStrictDTD: function()
465 var prefs = GetPrefs();
466 var IsCSSPrefChecked = prefs.getBoolPref("editor.use_css");
467 return !IsCSSPrefChecked && this.isStrictDTD();
470 getDocumentUrl: function()
473 var aDOMHTMLDoc = this.getCurrentEditor().document.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
474 return aDOMHTMLDoc.URL;
480 isXHTMLDocument: function()
482 var doctype = this.getCurrentEditor().document.doctype;
483 return (doctype.publicId == "-//W3C//DTD XHTML 1.0 Transitional//EN" ||
484 doctype.publicId == "-//W3C//DTD XHTML 1.0 Strict//EN");
487 getWrapColumn: function()
490 return this.getCurrentEditor().wrapWidth;
495 setDocumentURI: function(uri)
498 // XXX WE'LL NEED TO GET "CURRENT" CONTENT FRAME ONCE MULTIPLE EDITORS ARE ALLOWED
499 this.getCurrentEditorElement().docShell.setCurrentURI(uri);
500 } catch (e) { dump("SetDocumentURI:\n"+e +"\n"); }