Dotclear

source: admin/js/jsToolBar/jsToolBar.wysiwyg.js @ 2566:9bf417837888

Revision 2566:9bf417837888, 25.6 KB checked in by franck <carnet.franck.paul@…>, 12 years ago (diff)

Add some people in CREDITS, remove trailing spaces and tabs.

Line 
1/* ***** BEGIN LICENSE BLOCK *****
2 * This file is part of DotClear.
3 * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All
4 * rights reserved.
5 *
6 * DotClear is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * DotClear is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with DotClear; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 *
20 * ***** END LICENSE BLOCK *****
21*/
22
23jsToolBar.prototype.can_wwg = (document.designMode != undefined);
24jsToolBar.prototype.iframe = null;
25jsToolBar.prototype.iwin = null;
26jsToolBar.prototype.ibody = null;
27jsToolBar.prototype.iframe_css = null;
28
29/* Editor methods
30-------------------------------------------------------- */
31jsToolBar.prototype.drawToolBar = jsToolBar.prototype.draw;
32jsToolBar.prototype.draw = function(mode) {
33     mode = mode || 'xhtml';
34
35     if (this.can_wwg) {
36          this.mode = 'wysiwyg';
37          this.drawToolBar('wysiwyg');
38          this.initWindow();
39     } else {
40          this.drawToolBar(mode);
41     }
42};
43
44jsToolBar.prototype.switchMode = function(mode) {
45     mode = mode || 'xhtml';
46
47     if (mode == 'xhtml') {
48          this.wwg_mode = true;
49          this.draw(mode);
50     } else {
51          if (this.wwg_mode) {
52               this.syncContents('iframe');
53          }
54          this.wwg_mode = false;
55          this.removeEditor();
56          this.textarea.style.display = '';
57          this.drawToolBar(mode);
58     }
59};
60
61jsToolBar.prototype.syncContents = function(from) {
62     from = from || 'textarea';
63     var This = this;
64     if (from == 'textarea') {
65          initContent();
66     } else {
67          this.validBlockquote();
68          var html = this.applyHtmlFilters(this.ibody.innerHTML);
69          if (html == '<br />') { html = '<p></p>'; }
70          this.textarea.value = html;
71     }
72
73     function initContent() {
74          if (!This.iframe.contentWindow.document || !This.iframe.contentWindow.document.body) {
75               setTimeout(initContent, 1);
76               return;
77          }
78          This.ibody = This.iframe.contentWindow.document.body;
79
80          if (This.textarea.value != '' && This.textarea.value != '<p></p>') {
81               This.ibody.innerHTML = This.applyWysiwygFilters(This.textarea.value);
82               if (This.ibody.createTextRange) { //cursor at the begin for IE
83                    var IErange = This.ibody.createTextRange();
84                    IErange.execCommand("SelectAll");
85                    IErange.collapse();
86                    IErange.select();
87               }
88          } else {
89               var idoc = This.iwin.document;
90               var para = idoc.createElement('p');
91               para.appendChild(idoc.createElement('br'));
92               while (idoc.body.hasChildNodes()) {
93                    idoc.body.removeChild(idoc.body.lastChild);
94               }
95               idoc.body.appendChild(para);
96          }
97     }
98};
99jsToolBar.prototype.htmlFilters = {
100     tagsoup: function(str){
101          return this.tagsoup2xhtml(str);
102     }
103};
104jsToolBar.prototype.applyHtmlFilters = function(str) {
105     for (var fn in this.htmlFilters) {
106           str = this.htmlFilters[fn].call(this, str);
107     }
108     return str;
109};
110jsToolBar.prototype.wysiwygFilters = {};
111jsToolBar.prototype.applyWysiwygFilters = function( str) {
112     for (var fn in this.wysiwygFilters) {
113           str = this.wysiwygFilters[fn].call(this, str);
114     }
115     return str;
116};
117
118jsToolBar.prototype.switchEdit = function() {
119     if (this.wwg_mode) {
120          this.textarea.style.display = '';
121          this.iframe.style.display = 'none';
122          this.syncContents('iframe');
123          this.drawToolBar('xhtml');
124          this.wwg_mode = false;
125          this.focusEditor();
126     } else {
127          this.iframe.style.display = '';
128          this.textarea.style.display = 'none';
129          this.syncContents('textarea');
130          this.drawToolBar('wysiwyg');
131          this.wwg_mode = true;
132          this.focusEditor();
133     }
134     this.setSwitcher();
135};
136
137/** Creates iframe for editor, inits a blank document
138*/
139jsToolBar.prototype.initWindow = function() {
140     var This = this;
141
142     this.iframe = document.createElement('iframe');
143     this.textarea.parentNode.insertBefore(this.iframe,this.textarea.nextSibling);
144
145     this.switcher = document.createElement('ul');
146     this.switcher.className = 'jstSwitcher';
147     this.editor.appendChild(this.switcher);
148
149     this.iframe.height = this.textarea.offsetHeight + 0;
150     this.iframe.width = this.textarea.offsetWidth + 0;
151
152     if (this.textarea.tabIndex != undefined) {
153          this.iframe.tabIndex = this.textarea.tabIndex;
154     }
155
156     function initIframe() {
157          var doc = This.iframe.contentWindow.document;
158          if (!doc) {
159               setTimeout(initIframe,1);
160               return false;
161          }
162
163          doc.open();
164          var html =
165          '<html>\n'+
166          '<head>\n'+
167          '<style type="text/css">'+This.iframe_css+'</style>\n'+
168          (This.base_url != '' ? '<base href="'+This.base_url+'" />' : '')+
169          '</head>\n'+
170          '<body>\n'+
171          '</body>\n'+
172          '</html>';
173
174          doc.write(html);
175          doc.close();
176          if (document.all) { // for IE
177               doc.designMode = 'on';
178               // warning : doc is now inaccessible for IE6 sp1
179          }
180
181          This.iwin = This.iframe.contentWindow;
182
183          This.syncContents('textarea');
184
185          if (This.wwg_mode == undefined) {
186               This.wwg_mode = true;
187          }
188
189          if (This.wwg_mode) {
190               This.textarea.style.display = 'none';
191          } else {
192               This.iframe.style.display = 'none';
193          }
194
195          // update textarea on submit
196          if (This.textarea.form) {
197               chainHandler(This.textarea.form,'onsubmit', function() {
198                    if (This.wwg_mode) {
199                         This.syncContents('iframe');
200                    }
201               });
202          }
203
204          for (var evt in This.iwinEvents) {
205               var event = This.iwinEvents[evt];
206               This.addIwinEvent(This.iframe.contentWindow.document, event.type, event.fn, This);
207          }
208
209          This.setSwitcher();
210          try { This.iwin.document.designMode = 'on'; } catch (e) {}; // Firefox needs this
211
212          return true;
213     }
214     initIframe();
215};
216jsToolBar.prototype.addIwinEvent = function(target, type, fn, scope) {
217     var myFn = function(e){fn.call(scope, e)};
218     addEvent(target, type, myFn, true);
219     // fix memory leak
220     addEvent(scope.iwin, 'unload', function(){
221          removeEvent(target, type, myFn, true);
222     }, true);
223};
224jsToolBar.prototype.iwinEvents = {
225     block1: {
226          type: 'mouseup',
227          fn: function(){ this.adjustBlockLevelCombo() }
228     },
229     block2: {
230          type: 'keyup',
231          fn: function(){ this.adjustBlockLevelCombo() }
232     }
233};
234
235/** Insert a mode switcher after editor area
236*/
237jsToolBar.prototype.switcher_visual_title = 'visual';
238jsToolBar.prototype.switcher_source_title = 'source';
239jsToolBar.prototype.setSwitcher = function() {
240     while (this.switcher.hasChildNodes()) {
241          this.switcher.removeChild(this.switcher.firstChild);
242     }
243
244     var This = this;
245     function setLink(title,link) {
246          var li = document.createElement('li');
247          if (link) {
248               var a = document.createElement('a');
249               a.href = '#';
250               a.editor = This;
251               a.onclick = function() { this.editor.switchEdit(); return false; };
252               a.appendChild(document.createTextNode(title));
253          } else {
254               li.className = 'jstSwitcherCurrent';
255               a = document.createTextNode(title);
256          }
257
258          li.appendChild(a);
259          This.switcher.appendChild(li);
260     }
261
262     setLink(this.switcher_visual_title,!this.wwg_mode);
263     setLink(this.switcher_source_title,this.wwg_mode);
264};
265
266/** Removes editor area and mode switcher
267*/
268jsToolBar.prototype.removeEditor = function() {
269     if (this.iframe != null) {
270          this.iframe.parentNode.removeChild(this.iframe);
271          this.iframe = null;
272     }
273
274     if (this.switcher != undefined && this.switcher.parentNode != undefined) {
275          this.switcher.parentNode.removeChild(this.switcher);
276     }
277};
278
279/** Focus on the editor area
280*/
281jsToolBar.prototype.focusEditor = function() {
282     if (this.wwg_mode) {
283          try { this.iwin.document.designMode = 'on'; } catch (e) {}; // Firefox needs this
284          var This = this;
285          setTimeout(function() {This.iframe.contentWindow.focus()},1);
286     } else {
287          this.textarea.focus();
288     }
289};
290
291/** Resizer
292*/
293jsToolBar.prototype.resizeSetStartH = function() {
294     if (this.wwg_mode && this.iframe != undefined) {
295          this.dragStartH = this.iframe.offsetHeight;
296          return;
297     }
298     this.dragStartH = this.textarea.offsetHeight + 0;
299};
300jsToolBar.prototype.resizeDragMove = function(event) {
301     var new_height = (this.dragStartH+event.clientY-this.dragStartY)+'px';
302     if (this.iframe != undefined) {
303          this.iframe.style.height = new_height;
304     }
305     this.textarea.style.height = new_height;
306};
307
308/* Editing methods
309-------------------------------------------------------- */
310/** Replaces current selection by given node
311*/
312jsToolBar.prototype.insertNode = function(node) {
313     var range;
314
315     if (this.iwin.getSelection) { // Gecko
316          var sel = this.iwin.getSelection();
317          range = sel.getRangeAt(0);
318
319          // deselect all ranges
320          sel.removeAllRanges();
321
322          // empty range
323          range.deleteContents();
324
325          // Insert node
326          range.insertNode(node);
327
328          range.selectNodeContents(node);
329          range.setEndAfter(node);
330          if (range.endContainer.childNodes.length > range.endOffset &&
331          range.endContainer.nodeType != Node.TEXT_NODE) {
332               range.setEnd(range.endContainer.childNodes[range.endOffset], 0);
333          } else {
334               range.setEnd(range.endContainer.childNodes[0]);
335          }
336          sel.addRange(range);
337
338          sel.collapseToEnd();
339     } else { // IE
340          // lambda element
341          var p = this.iwin.document.createElement('div');
342          p.appendChild(node);
343          range = this.iwin.document.selection.createRange();
344          range.execCommand('delete');
345          // insert innerHTML from element
346          range.pasteHTML(p.innerHTML);
347          range.collapse(false);
348          range.select();
349     }
350     this.iwin.focus();
351};
352
353/** Returns a document fragment with selected nodes
354*/
355jsToolBar.prototype.getSelectedNode = function() {
356     if (this.iwin.getSelection) { // Gecko
357          var sel = this.iwin.getSelection();
358          var range = sel.getRangeAt(0);
359          var content = range.cloneContents();
360     } else { // IE
361          var sel = this.iwin.document.selection;
362          var d = this.iwin.document.createElement('div');
363          d.innerHTML = sel.createRange().htmlText;
364          var content = this.iwin.document.createDocumentFragment();
365          for (var i=0; i < d.childNodes.length; i++) {
366               content.appendChild(d.childNodes[i].cloneNode(true));
367          }
368     }
369     return content;
370};
371
372/** Returns string representation for selected node
373*/
374jsToolBar.prototype.getSelectedText = function() {
375     if (this.iwin.getSelection) { // Gecko
376          return this.iwin.getSelection().toString();
377     } else { // IE
378          var range = this.iwin.document.selection.createRange();
379          return range.text;
380     }
381};
382
383jsToolBar.prototype.replaceNodeByContent = function(node) {
384     var content = this.iwin.document.createDocumentFragment();
385     for (var i=0; i < node.childNodes.length; i++) {
386          content.appendChild(node.childNodes[i].cloneNode(true));
387     }
388     node.parentNode.replaceChild(content, node);
389};
390
391jsToolBar.prototype.getBlockLevel = function() {
392     var blockElts = ['p','h1','h2','h3','h4','h5','h6'];
393
394     var range, commonAncestorContainer;
395     if (this.iwin.getSelection) { //gecko
396          var selection = this.iwin.getSelection();
397          range = selection.getRangeAt(0);
398          commonAncestorContainer = range.commonAncestorContainer;
399          while (commonAncestorContainer.nodeType != 1) {
400               commonAncestorContainer = commonAncestorContainer.parentNode;
401          }
402     } else { //ie
403          range = this.iwin.document.selection.createRange();
404          commonAncestorContainer = range.parentElement();
405     }
406
407     var ancestorTagName = commonAncestorContainer.tagName.toLowerCase();
408     while (arrayIndexOf(blockElts, ancestorTagName)==-1 && ancestorTagName!='body') {
409          commonAncestorContainer = commonAncestorContainer.parentNode;
410          ancestorTagName = commonAncestorContainer.tagName.toLowerCase();
411     }
412     if (ancestorTagName == 'body') return null;
413     else return commonAncestorContainer;
414};
415jsToolBar.prototype.adjustBlockLevelCombo = function() {
416     var blockLevel = this.getBlockLevel();
417     if (blockLevel !== null)
418          this.toolNodes.blocks.value = blockLevel.tagName.toLowerCase();
419     else {
420          if (this.mode == 'wysiwyg') this.toolNodes.blocks.value = 'none';
421          if (this.mode == 'xhtml') this.toolNodes.blocks.value = 'nonebis';
422     }
423};
424
425/** HTML code cleanup
426-------------------------------------------------------- */
427jsToolBar.prototype.simpleCleanRegex = new Array(
428     /* Remove every tags we don't need */
429     [/<meta[\w\W]*?>/gim,''],
430     [/<style[\w\W]*?>[\w\W]*?<\/style>/gim, ''],
431     [/<\/?font[\w\W]*?>/gim, ''],
432
433
434     /* Replacements */
435     [/<(\/?)(B|b|STRONG)([\s>\/])/g, "<$1strong$3"],
436     [/<(\/?)(I|i|EM)([\s>\/])/g, "<$1em$3"],
437     [/<IMG ([^>]*?[^\/])>/gi, "<img $1 />"],
438     [/<INPUT ([^>]*?[^\/])>/gi, "<input $1 />"],
439     [/<COL ([^>]*?[^\/])>/gi, "<col $1 />"],
440     [/<AREA ([^>]*?[^\/])>/gi, "<area $1 />"],
441     [/<PARAM ([^>]*?[^\/])>/gi, "<param $1 />"],
442     [/<HR ([^>]*?[^\/])>/gi, "<hr $1/>"],
443     [/<BR ([^>]*?[^\/])>/gi, "<br $1/>"],
444     [/<(\/?)U([\s>\/])/gi, "<$1ins$2"],
445     [/<(\/?)STRIKE([\s>\/])/gi, "<$1del$2"],
446     [/<span style="font-weight: normal;">([\w\W]*?)<\/span>/gm, "$1"],
447     [/<span style="font-weight: bold;">([\w\W]*?)<\/span>/gm, "<strong>$1</strong>"],
448     [/<span style="font-style: italic;">([\w\W]*?)<\/span>/gm, "<em>$1</em>"],
449     [/<span style="text-decoration: underline;">([\w\W]*?)<\/span>/gm, "<ins>$1</ins>"],
450     [/<span style="text-decoration: line-through;">([\w\W]*?)<\/span>/gm, "<del>$1</del>"],
451     [/<span style="text-decoration: underline line-through;">([\w\W]*?)<\/span>/gm, "<del><ins>$1</ins></del>"],
452     [/<span style="(font-weight: bold; ?|font-style: italic; ?){2}">([\w\W]*?)<\/span>/gm, "<strong><em>$2</em></strong>"],
453     [/<span style="(font-weight: bold; ?|text-decoration: underline; ?){2}">([\w\W]*?)<\/span>/gm, "<ins><strong>$2</strong></ins>"],
454     [/<span style="(font-weight: italic; ?|text-decoration: underline; ?){2}">([\w\W]*?)<\/span>/gm, "<ins><em>$2</em></ins>"],
455     [/<span style="(font-weight: bold; ?|text-decoration: line-through; ?){2}">([\w\W]*?)<\/span>/gm, "<del><strong>$2</strong></del>"],
456     [/<span style="(font-weight: italic; ?|text-decoration: line-through; ?){2}">([\w\W]*?)<\/span>/gm, "<del><em>$2</em></del>"],
457     [/<span style="(font-weight: bold; ?|font-style: italic; ?|text-decoration: underline; ?){3}">([\w\W]*?)<\/span>/gm, "<ins><strong><em>$2</em></strong></ins>"],
458     [/<span style="(font-weight: bold; ?|font-style: italic; ?|text-decoration: line-through; ?){3}">([\w\W]*?)<\/span>/gm, "<del><strong><em>$2</em></strong></del>"],
459     [/<span style="(font-weight: bold; ?|font-style: italic; ?|text-decoration: underline line-through; ?){3}">([\w\W]*?)<\/span>/gm, "<del><ins><strong><em>$2</em></strong></ins></del>"],
460     [/<strong style="font-weight: normal;">([\w\W]*?)<\/strong>/gm, "$1"],
461     [/<([a-z]+) style="font-weight: normal;">([\w\W]*?)<\/\1>/gm, "<$1>$2</$1>"],
462     [/<([a-z]+) style="font-weight: bold;">([\w\W]*?)<\/\1>/gm, "<$1><strong>$2</strong></$1>"],
463     [/<([a-z]+) style="font-style: italic;">([\w\W]*?)<\/\1>/gm, "<$1><em>$2</em></$1>"],
464     [/<([a-z]+) style="text-decoration: underline;">([\w\W]*?)<\/\1>/gm, "<ins><$1>$2</$1></ins>"],
465     [/<([a-z]+) style="text-decoration: line-through;">([\w\W]*?)<\/\1>/gm, "<del><$1>$2</$1></del>"],
466     [/<([a-z]+) style="text-decoration: underline line-through;">([\w\W]*?)<\/\1>/gm, "<del><ins><$1>$2</$1></ins></del>"],
467     [/<([a-z]+) style="(font-weight: bold; ?|font-style: italic; ?){2}">([\w\W]*?)<\/\1>/gm, "<$1><strong><em>$3</em></strong></$1>"],
468     [/<([a-z]+) style="(font-weight: bold; ?|text-decoration: underline; ?){2}">([\w\W]*?)<\/\1>/gm, "<ins><$1><strong>$3</strong></$1></ins>"],
469     [/<([a-z]+) style="(font-weight: italic; ?|text-decoration: underline; ?){2}">([\w\W]*?)<\/\1>/gm, "<ins><$1><em>$3</em></$1></ins>"],
470     [/<([a-z]+) style="(font-weight: bold; ?|text-decoration: line-through; ?){2}">([\w\W]*?)<\/\1>/gm, "<del><$1><strong>$3</strong></$1></del>"],
471     [/<([a-z]+) style="(font-weight: italic; ?|text-decoration: line-through; ?){2}">([\w\W]*?)<\/\1>/gm, "<del><$1><em>$3</em></$1></del>"],
472     [/<([a-z]+) style="(font-weight: bold; ?|font-style: italic; ?|text-decoration: underline; ?){3}">([\w\W]*?)<\/\1>/gm, "<ins><$1><strong><em>$3</em></strong></$1></ins>"],
473     [/<([a-z]+) style="(font-weight: bold; ?|font-style: italic; ?|text-decoration: line-through; ?){3}">([\w\W]*?)<\/\1>/gm, "<del><$1><strong><em>$3</em></strong></$1></del>"],
474     [/<([a-z]+) style="(font-weight: bold; ?|font-style: italic; ?|text-decoration: underline line-through; ?){3}">([\w\W]*?)<\/\1>/gm, "<del><ins><$1><strong><em>$3</em></strong></$1></ins></del>"],
475     [/<p><blockquote>(.*)(\n)+<\/blockquote><\/p>/i,"<blockquote>$1</blockquote>\n"],
476     /* mise en forme identique contigue */
477     [/<\/(strong|em|ins|del|q|code)>(\s*?)<\1>/gim, "$2"],
478     [/<(br|BR)>/g, "<br />"],
479     [/<(hr|HR)>/g, "<hr />"],
480     /* opera est trop strict ;)) */
481     [/([^\s])\/>/g, "$1 />"],
482     /* br intempestifs de fin de block */
483     [/<br \/>\s*<\/(h1|h2|h3|h4|h5|h6|ul|ol|li|p|blockquote|div)/gi, "</$1"],
484     [/<\/(h1|h2|h3|h4|h5|h6|ul|ol|li|p|blockquote)>([^\n\u000B\r\f])/gi, "</$1>\n$2"],
485     [/<hr style="width: 100%; height: 2px;" \/>/g, "<hr />"]
486);
487
488/** Cleanup HTML code
489*/
490jsToolBar.prototype.tagsoup2xhtml = function(html) {
491     for (var reg in this.simpleCleanRegex) {
492          html = html.replace(this.simpleCleanRegex[reg][0], this.simpleCleanRegex[reg][1]);
493     }
494     /* tags vides */
495     /* note : on tente de ne pas tenir compte des commentaires html, ceux-ci
496        permettent entre autre d'inserer des commentaires conditionnels pour ie */
497     while ( /(<[^\/!]>|<[^\/!][^>]*[^\/]>)\s*<\/[^>]*[^-]>/.test(html) ) {
498          html = html.replace(/(<[^\/!]>|<[^\/!][^>]*[^\/]>)\s*<\/[^>]*[^-]>/g, "");
499     }
500
501     /* tous les tags en minuscule */
502     html = html.replace(/<(\/?)([A-Z0-9]+)/g,
503               function(match0, match1, match2) {
504                    return "<" + match1 + match2.toLowerCase();
505               });
506
507     /* IE laisse souvent des attributs sans guillemets */
508     var myRegexp = /<[^>]+((\s+\w+\s*=\s*)([^"'][\w~@+$,%\/:.#?=&;!*()-]*))[^>]*?>/;
509     while ( myRegexp.test(html)) {
510          html = html.replace(
511               myRegexp,
512               function (str, val1, val2, val3){
513                    var tamponRegex = new RegExp(regexpEscape(val1));
514                    return str.replace(tamponRegex, val2+'"'+val3+'"');
515               }
516          )
517     }
518
519     /* les navigateurs rajoutent une unite aux longueurs css nulles */
520     /* note: a ameliorer ! */
521     while ( /(<[^>]+style=(["'])[^>]+[\s:]+)0(pt|px)(\2|\s|;)/.test(html)) {
522          html = html.replace(/(<[^>]+style=(["'])[^>]+[\s:]+)0(pt|px)(\2|\s|;)/gi, "$1"+"0$4");
523     }
524
525     /* correction des fins de lignes : le textarea edite contient des \n
526     * le wysiwyg des \r\n , et le textarea mis a jour SANS etre affiche des \r\n ! */
527     html = html.replace(/\r\n/g,"\n");
528
529     /* Trim */
530     html = html.replace(/^\s+/gm,'');
531     html = html.replace(/\s+$/gm,'');
532
533     return html;
534};
535jsToolBar.prototype.validBlockquote = function() {
536     var blockElts = ['address','blockquote','dl','div','fieldset','form','h1',
537                      'h2','h3','h4','h5','h6','hr','ol','p','pre','table','ul'];
538     var BQs = this.iwin.document.getElementsByTagName('blockquote');
539     var bqChilds;
540
541     for (var bq = 0; bq < BQs.length; bq++) {
542          bqChilds = BQs[bq].childNodes;
543          var frag = this.iwin.document.createDocumentFragment();
544          for (var i = (bqChilds.length-1); i >= 0; i--) {
545               if (bqChilds[i].nodeType == 1 && // Node.ELEMENT_NODE
546                   arrayIndexOf(blockElts, bqChilds[i].tagName.toLowerCase()) >= 0)
547               {
548                    if (frag.childNodes.length > 0) {
549                         var p = this.iwin.document.createElement('p');
550                         p.appendChild(frag);
551                         BQs[bq].replaceChild(p, bqChilds[i+1]);
552                         frag = this.iwin.document.createDocumentFragment();
553                    }
554               } else {
555                    if (frag.childNodes.length > 0) BQs[bq].removeChild(bqChilds[i+1]);
556                    frag.insertBefore(bqChilds[i].cloneNode(true), frag.firstChild);
557               }
558          }
559          if (frag.childNodes.length > 0) {
560               var p = this.iwin.document.createElement('p');
561               p.appendChild(frag);
562               BQs[bq].replaceChild(p, bqChilds[0]);
563          }
564     }
565};
566
567/* Removing text formating */
568jsToolBar.prototype.removeFormatRegexp = new Array(
569     [/(<[a-z][^>]*)margin\s*:[^;]*;/mg, "$1"],
570     [/(<[a-z][^>]*)margin-bottom\s*:[^;]*;/mg, "$1"],
571     [/(<[a-z][^>]*)margin-left\s*:[^;]*;/mg, "$1"],
572     [/(<[a-z][^>]*)margin-right\s*:[^;]*;/mg, "$1"],
573     [/(<[a-z][^>]*)margin-top\s*:[^;]*;/mg, "$1"],
574
575     [/(<[a-z][^>]*)padding\s*:[^;]*;/mg, "$1"],
576     [/(<[a-z][^>]*)padding-bottom\s*:[^;]*;/mg, "$1"],
577     [/(<[a-z][^>]*)padding-left\s*:[^;]*;/mg, "$1"],
578     [/(<[a-z][^>]*)padding-right\s*:[^;]*;/mg, "$1"],
579     [/(<[a-z][^>]*)padding-top\s*:[^;]*;/mg, "$1"],
580
581     [/(<[a-z][^>]*)font\s*:[^;]*;/mg, "$1"],
582     [/(<[a-z][^>]*)font-family\s*:[^;]*;/mg, "$1"],
583     [/(<[a-z][^>]*)font-size\s*:[^;]*;/mg, "$1"],
584     [/(<[a-z][^>]*)font-style\s*:[^;]*;/mg, "$1"],
585     [/(<[a-z][^>]*)font-variant\s*:[^;]*;/mg, "$1"],
586     [/(<[a-z][^>]*)font-weight\s*:[^;]*;/mg, "$1"],
587
588     [/(<[a-z][^>]*)color\s*:[^;]*;/mg, "$1"]
589);
590
591jsToolBar.prototype.removeTextFormating = function(html) {
592     for (var reg in this.removeFormatRegexp) {
593          html = html.replace(this.removeFormatRegexp[reg][0], this.removeFormatRegexp[reg][1]);
594     }
595
596     html = this.tagsoup2xhtml(html);
597     html = html.replace(/style="\s*?"/mgi,'');
598     return html;
599};
600
601/** Toolbar elements
602-------------------------------------------------------- */
603jsToolBar.prototype.elements.blocks.wysiwyg = {
604     list: ['none','p','h1','h2','h3','h4','h5','h6'],
605     fn: function(opt) {
606          if (opt=='none') {
607               var blockLevel = this.getBlockLevel();
608               if (blockLevel !== null) {
609                    this.replaceNodeByContent(blockLevel);
610               }
611               this.iwin.focus();
612          } else {
613               try { this.iwin.document.execCommand('formatblock',false,'<'+opt+'>');
614               } catch(e){};
615               this.iwin.focus();
616          }
617     }
618};
619
620jsToolBar.prototype.elements.strong.fn.wysiwyg = function() {
621     this.iwin.document.execCommand('bold', false, null);
622     this.iwin.focus();
623};
624
625jsToolBar.prototype.elements.em.fn.wysiwyg = function() {
626     this.iwin.document.execCommand('italic', false, null);
627     this.iwin.focus();
628};
629
630jsToolBar.prototype.elements.ins.fn.wysiwyg = function() {
631     this.iwin.document.execCommand('underline', false, null);
632     this.iwin.focus();
633};
634
635jsToolBar.prototype.elements.del.fn.wysiwyg = function() {
636     this.iwin.document.execCommand('strikethrough', false, null);
637     this.iwin.focus();
638};
639
640jsToolBar.prototype.elements.quote.fn.wysiwyg = function() {
641     var n = this.getSelectedNode();
642     var q = this.iwin.document.createElement('q');
643     q.appendChild(n);
644     this.insertNode(q);
645};
646
647jsToolBar.prototype.elements.code.fn.wysiwyg = function() {
648     var n = this.getSelectedNode();
649     var code = this.iwin.document.createElement('code');
650     code.appendChild(n);
651     this.insertNode(code);
652};
653
654jsToolBar.prototype.elements.br.fn.wysiwyg = function() {
655     var n = this.iwin.document.createElement('br');
656     this.insertNode(n);
657};
658
659jsToolBar.prototype.elements.blockquote.fn.wysiwyg = function() {
660     var n = this.getSelectedNode();
661     var q = this.iwin.document.createElement('blockquote');
662     q.appendChild(n);
663     this.insertNode(q);
664};
665
666jsToolBar.prototype.elements.pre.fn.wysiwyg = function() {
667     this.iwin.document.execCommand('formatblock',false,'<pre>');
668     this.iwin.focus();
669};
670
671jsToolBar.prototype.elements.ul.fn.wysiwyg = function() {
672     this.iwin.document.execCommand('insertunorderedlist',false,null);
673     this.iwin.focus();
674};
675
676jsToolBar.prototype.elements.ol.fn.wysiwyg = function() {
677     this.iwin.document.execCommand('insertorderedlist',false,null);
678     this.iwin.focus();
679};
680
681jsToolBar.prototype.elements.link.fn.wysiwyg = function() {
682     var href, hreflang;
683     var range, commonAncestorContainer;
684     if (this.iwin.getSelection) { //gecko
685          var selection = this.iwin.getSelection();
686          range = selection.getRangeAt(0);
687          commonAncestorContainer = range.commonAncestorContainer;
688          while (commonAncestorContainer.nodeType != 1) {
689               commonAncestorContainer = commonAncestorContainer.parentNode;
690          }
691     } else { //ie
692          range = this.iwin.document.selection.createRange();
693          commonAncestorContainer = range.parentElement();
694     }
695
696     var ancestorTagName = commonAncestorContainer.tagName.toLowerCase();
697     while (ancestorTagName!='a' && ancestorTagName!='body') {
698          commonAncestorContainer = commonAncestorContainer.parentNode;
699          ancestorTagName = commonAncestorContainer.tagName.toLowerCase();
700     }
701
702     // Update or remove link?
703     if (ancestorTagName == 'a') {
704          href = commonAncestorContainer.href || '';
705          hreflang = commonAncestorContainer.hreflang || '';
706     }
707
708     href = window.prompt(this.elements.link.href_prompt,href);
709
710     // Remove link
711     if (ancestorTagName == 'a' && href=='') {
712          this.replaceNodeByContent(commonAncestorContainer);
713     }
714     if (!href) return; // user cancel
715
716     hreflang = window.prompt(this.elements.link.hreflang_prompt, hreflang);
717
718     // Update link
719     if (ancestorTagName == 'a' && href) {
720          commonAncestorContainer.setAttribute('href', href);
721          if (hreflang) {
722               commonAncestorContainer.setAttribute('hreflang', hreflang);
723          } else {
724               commonAncestorContainer.removeAttribute('hreflang');
725          }
726          return;
727     }
728
729     // Create link
730     var n = this.getSelectedNode();
731     var a = this.iwin.document.createElement('a');
732     a.href = href;
733     if (hreflang) a.setAttribute('hreflang',hreflang);
734     a.appendChild(n);
735     this.insertNode(a);
736};
737
738
739
740// Remove format and Toggle
741jsToolBar.prototype.elements.removeFormat = {
742     type: 'button',
743     title: 'Remove text formating',
744     fn: {}
745};
746jsToolBar.prototype.elements.removeFormat.disabled = !jsToolBar.prototype.can_wwg;
747jsToolBar.prototype.elements.removeFormat.fn.xhtml = function() {
748     var html = this.textarea.value;
749     html = this.removeTextFormating(html);
750     this.textarea.value = html;
751};
752jsToolBar.prototype.elements.removeFormat.fn.wysiwyg = function() {
753     var html = this.iwin.document.body.innerHTML;
754     html = this.removeTextFormating(html);
755     this.iwin.document.body.innerHTML = html;
756};
757/** Utilities
758-------------------------------------------------------- */
759function arrayIndexOf(aArray, aValue){
760     if (typeof Array.indexOf == 'function') {
761          return aArray.indexOf(aValue);
762     } else {
763          var index = -1;
764          var l = aArray.length;
765          for (var i = 0; i < l ; i++) {
766               if (aArray[i] === aValue) {
767                    index = i;
768                    break;
769               }
770          }
771          return index;
772     }
773};
774function addEvent(obj, evType, fn, useCapture) {
775     if (obj.addEventListener){
776          obj.addEventListener(evType, fn, useCapture);
777          return true;
778     } else if (obj.attachEvent){
779          var r = obj.attachEvent("on"+evType, fn);
780          return r;
781     } else {
782          return false;
783     }
784};
785function removeEvent(obj, evType, fn, useCapture) {
786     if (obj.removeEventListener){
787          obj.removeEventListener(evType, fn, useCapture);
788          return true;
789     } else if (obj.detachEvent){
790          var r = obj.detachEvent("on"+evType, fn);
791          return r;
792     } else {
793          return false;
794  }
795};
796function regexpEscape(s) {
797     return s.replace(/([\\\^\$*+[\]?{}.=!:(|)])/g,"\\$1")
798};
Note: See TracBrowser for help on using the repository browser.

Sites map