1 /*==============================================================================
2 This Wikiwyg mode supports a DesignMode wysiwyg editor with toolbar buttons
6 Copyright (c) 2005 Socialtext Corporation
8 Palo Alto, CA 94301 U.S.A.
11 Wikiwyg is free software.
13 This library is free software; you can redistribute it and/or modify it
14 under the terms of the GNU Lesser General Public License as published by
15 the Free Software Foundation; either version 2.1 of the License, or (at
16 your option) any later version.
18 This library is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
21 General Public License for more details.
23 http://www.gnu.org/copyleft/lesser.txt
25 =============================================================================*/
27 proto = new Subclass('Wikiwyg.Wysiwyg', 'Wikiwyg.Mode');
29 proto.classtype = 'wysiwyg';
30 proto.modeDescription = 'Wysiwyg';
33 useParentStyles: true,
34 useStyleMedia: 'wikiwyg',
37 disabledToolbarButtons: [],
38 editHeightMinimum: 150,
39 editHeightAdjustment: 1.3,
40 editHeightOffset: 500,
44 proto.initializeObject = function() {
45 this.edit_iframe = this.get_edit_iframe();
46 this.div = this.edit_iframe;
47 this.set_design_mode_early();
50 proto.set_design_mode_early = function() { // Se IE, below
54 proto.fromHtml = function(html) {
55 this.set_inner_html(html);
58 // Added to allow wysiwyg mode by default
59 proto.fromWikitext = function(wikitext) {
60 var editiframe = this.get_edit_document();
62 this.wikiwyg.call_action('wikiwyg_wikitext_to_html', wikitext,
63 function(html) {editiframe.body.innerHTML = html;} );
66 proto.toHtml = function(func) {
67 func(this.get_inner_html());
70 // This is needed to work around the broken IMGs in Firefox design mode.
71 // Works harmlessly on IE, too.
72 // TODO - IMG URLs that don't match /^\//
73 proto.fix_up_relative_imgs = function() {
74 var base = location.href.replace(/(.*?:\/\/.*?\/).*/, '$1');
75 var imgs = this.get_edit_document().getElementsByTagName('img');
76 for (var ii = 0; ii < imgs.length; ++ii)
77 imgs[ii].src = imgs[ii].src.replace(/^\//, base);
80 proto.enableThis = function() {
81 this.superfunc('enableThis').call(this);
82 this.edit_iframe.style.border = '1px black solid';
83 this.edit_iframe.width = '100%';
84 this.setHeightOf(this.edit_iframe);
85 this.fix_up_relative_imgs();
86 this.get_edit_document().designMode = 'on';
87 // XXX - Doing stylesheets in initializeObject might get rid of blue flash
88 // this.apply_stylesheets();
89 this.enable_keybindings();
90 this.clear_inner_html();
93 proto.clear_inner_html = function() {
94 var inner_html = this.get_inner_html();
95 var clear = this.config.clearRegex;
96 if (clear && inner_html.match(clear))
97 this.set_inner_html('');
100 proto.get_keybinding_area = function() {
101 return this.get_edit_document();
104 proto.get_edit_iframe = function() {
106 if (this.config.iframeId) {
107 iframe = document.getElementById(this.config.iframeId);
108 iframe.iframe_hack = true;
110 else if (this.config.iframeObject) {
111 iframe = this.config.iframeObject;
112 iframe.iframe_hack = true;
115 // XXX in IE need to wait a little while for iframe to load up
116 iframe = document.createElement('iframe');
121 proto.get_edit_window = function() { // See IE, below
122 return this.edit_iframe.contentWindow;
125 proto.get_edit_document = function() { // See IE, below
126 return this.get_edit_window().document;
129 proto.get_inner_html = function() {
130 return this.get_edit_document().body.innerHTML;
132 proto.set_inner_html = function(html) {
133 this.get_edit_document().body.innerHTML = html;
136 proto.apply_stylesheets = function(styles) {
137 var styles = document.styleSheets;
138 var head = this.get_edit_document().getElementsByTagName("head")[0];
140 for (var i = 0; i < styles.length; i++) {
141 var style = styles[i];
143 if (style.href == location.href)
144 this.apply_inline_stylesheet(style, head);
146 if (this.should_link_stylesheet(style))
147 this.apply_linked_stylesheet(style, head);
151 proto.apply_inline_stylesheet = function(style, head) {
152 // TODO: figure this out
155 proto.should_link_stylesheet = function(style, head) {
156 var media = style.media;
157 var config = this.config;
158 var media_text = media.mediaText ? media.mediaText : media;
160 ((!media_text || media_text == 'screen') &&
161 config.useParentStyles);
162 var use_style = (media_text && (media_text == config.useStyleMedia));
163 if (!use_parent && !use_style) // TODO: simplify
169 proto.apply_linked_stylesheet = function(style, head) {
170 var link = Wikiwyg.createElementWithAttrs(
176 }, this.get_edit_document()
178 head.appendChild(link);
181 proto.process_command = function(command) {
182 if (this['do_' + command])
183 this['do_' + command](command);
185 this.get_edit_window().focus();
188 proto.exec_command = function(command, option) {
189 this.get_edit_document().execCommand(command, false, option);
192 proto.format_command = function(command) {
193 this.exec_command('formatblock', '<' + command + '>');
196 proto.do_bold = proto.exec_command;
197 proto.do_italic = proto.exec_command;
198 proto.do_underline = proto.exec_command;
199 proto.do_strike = function() {
200 this.exec_command('strikethrough');
202 proto.do_hr = function() {
203 this.exec_command('inserthorizontalrule');
205 proto.do_ordered = function() {
206 this.exec_command('insertorderedlist');
208 proto.do_unordered = function() {
209 this.exec_command('insertunorderedlist');
211 proto.do_indent = proto.exec_command;
212 proto.do_outdent = proto.exec_command;
214 proto.do_h1 = proto.format_command;
215 proto.do_h2 = proto.format_command;
216 proto.do_h3 = proto.format_command;
217 proto.do_h4 = proto.format_command;
218 proto.do_h5 = proto.format_command;
219 proto.do_h6 = proto.format_command;
220 proto.do_pre = proto.format_command;
221 proto.do_p = proto.format_command;
223 proto.do_table = function() {
224 var rows = prompt("Number of rows", '2');
227 var cols = prompt("Number of columns", '2');
231 // Test if variables are valid numbers
232 if( isNaN(rows) == true || isNaN(cols) == true
233 ||(rows = parseInt(rows).toFixed(0)) <= 0
234 ||(cols = parseInt(cols).toFixed(0)) <= 0)
236 alert("Please enter positive numbers");
241 '<table border="5"><tbody>';
243 for(i=0; i<rows;i++) {
244 html = html + "<tr>";
245 for(var j=0;j<cols;j++) {
246 html = html + "<td> </td>";
248 html = html + "</tr>";
251 html = html + "<tbody></table>";
254 this.get_edit_window().focus();
255 this.insert_table(html);
258 proto.insert_table = function(html) { // See IE
259 this.exec_command('inserthtml', html);
262 proto.do_toc = function() {
263 var html = '<p><div style="background-color:#D3D3D3;font-size:smaller;">'+
264 'Wikitext { <br> <?plugin CreateToc ?> <br>}</div></p>';
265 this.insert_html(html);
268 proto.do_wikitext = function() {
269 var html = '<p><div style="background-color:#D3D3D3;font-size:smaller;">'+
270 'Wikitext { <br> <br>}</div></p>';
271 this.insert_html(html);
274 proto.insert_html = function(html) { // See IE
275 this.exec_command('inserthtml', html);
278 proto.do_link = function() {
279 var selection = this.get_link_selection_text();
280 if (! selection) return;
283 var url_selection = "";
286 url_selection = this.get_edit_document().selection.createRange().htmlText;
289 if(this.get_edit_window().getSelection())
290 url_selection = this.get_edit_window().getSelection();
295 var tmp_match = url_selection.match(/href=.*/m);
296 if(tmp_match!=null) {
297 var toreplace = /.*href=\"(.*?)\".*/m;
298 url = tmp_match.toString().replace(toreplace,'$1');
303 if(url_selection.focusNode.innerHTML) {
304 var reg_match = new RegExp('(href=\".*?\".*?'
307 var tmp_match = url_selection.focusNode.innerHTML.match(reg_match);
308 if(tmp_match!=null) {
309 var toreplace = /.*href=\"(.*?)\".*/m;
310 url = tmp_match.toString().replace(toreplace,'$1');
315 url = prompt('Enter the URL. No URL will remove the link.',unescape(url));
319 this.exec_command('Unlink');
320 this.exec_command('CreateLink',url);
321 this.exec_command('ForeColor','blue');
323 else if(!url) {// No URL entered by the user
324 this.exec_command('Unlink');
325 this.exec_command('ForeColor','black');
329 proto.get_selection_text = function() { // See IE, below
330 return this.get_edit_window().getSelection().toString();
333 proto.get_link_selection_text = function() {
334 var selection = this.get_selection_text();
336 alert("Please select the text you would like to turn into a link.");
342 proto.do_sup = function() {
343 this.exec_command('SuperScript');
346 proto.do_sub = function() {
347 this.exec_command('SubScript');
350 proto.do_preview = function() {
351 this.wikiwyg.previewChanges_button();
354 proto.do_save_button = function() {
355 this.wikiwyg.saveChanges_button();
358 /*==============================================================================
359 Support for Internet Explorer in Wikiwyg.Wysiwyg
360 =============================================================================*/
363 proto.set_design_mode_early = function(wikiwyg) {
364 // XXX - need to know if iframe is ready yet...
365 this.get_edit_document().designMode = 'on';
368 proto.get_edit_window = function() {
369 return this.edit_iframe;
372 proto.get_edit_document = function() {
373 return this.edit_iframe.contentWindow.document;
376 proto.get_selection_text = function() {
377 var selection = this.get_edit_document().selection;
378 if (selection != null)
379 return selection.createRange().htmlText;
383 proto.insert_table = function(html) {
384 var doc = this.get_edit_document();
385 var range = this.get_edit_document().selection.createRange();
387 if(range.parentElement().isContentEditable == false){
388 alert("Please click where you want to insert the table");
392 if (range.boundingTop == 2 && range.boundingLeft == 2)
394 range.pasteHTML(html);
395 range.collapse(false);
399 proto.insert_html = function(html) {
400 var doc = this.get_edit_document();
401 var range = this.get_edit_document().selection.createRange();
403 if(range.parentElement().isContentEditable == false){
404 alert("Please click in the edit area");
408 if (range.boundingTop == 2 && range.boundingLeft == 2)
410 range.pasteHTML(html);
411 range.collapse(false);
415 // Use IE's design mode default key bindings for now.
416 proto.enable_keybindings = function() {}
418 } // end of global if