Subversion Repositories wimsdev

Rev

Rev 8231 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1442 bpr 1
 
2
//Call speck Init to convert all text areas with "iEdit" to speck edit windows.
3
//Alternatively:
4
//var editor = new speckEditor();
5
//editor.init(textareaelement, optional callback on loaded)
8231 bpr 6
function speckInit(callback) {
1442 bpr 7
    var tas = document.getElementsByTagName("textarea");
8
    var found = false;
9
    for(i=0;i<tas.length;i++) {
9054 obado 10
        var ta = tas[i];
11
        if (ta.className == "iEdit") {
12
            var editor = new speckEditor();
13
            editor.init(ta, callback);
14
            found = true;
15
        }
8231 bpr 16
    }
1442 bpr 17
    if (!found) {
18
        if (callback)
19
            callback.call();
20
    }
9054 obado 21
    return true;
1442 bpr 22
};
23
 
8231 bpr 24
//Be sure to call speckClose if you are hiding or removing a speck edit
25
//from the screen and plan to open another before refreshing the page.
1442 bpr 26
function speckClose() {
27
    for(var i in iEdit)
28
    {
29
        iEdit[i].iframe.contentWindow.document.designMode = "off";
30
    }
31
};
32
 
9054 obado 33
/** (re)Opens all specks **/
34
function speckOpen() {
35
    for(var i in iEdit)
36
    {
37
        iEdit[i].iframe.contentWindow.document.designMode = "on";
38
    }
39
};
40
 
41
/** Toggle Html Editor on all specks */
42
function speckToggleAll() {
43
    for(var i in iEdit)
44
    {
45
        iEdit[i].toggleMode();
46
    }
47
};
48
 
1442 bpr 49
//Collection of all text windows: accessible by:
50
//iEdit[TextAreaId].html();
51
var iEdit = [];
52
 
53
//One instance of a speck edit window
54
function speckEditor() {};
55
speckEditor.prototype = {
56
    //Edit this path to point to the location of the stylesheet you would like applied to the edit window.
8231 bpr 57
    editStylePath: window.location.protocol + "//" + window.location.host + "/speck/editstyle.css",
58
 
1442 bpr 59
    //Remove or add features from this list. a=action, t=hover information text
8231 bpr 60
    features: [
1442 bpr 61
        "html", "Toggle HTML View",
62
        "bold", "Bold",
63
        "italic", "Italic",
64
        "underline", "Underline",
65
        "justifyleft", "Align Left",
66
        "justifycenter", "Align Center",
67
        "justifyright", "Align Right",
68
        "insertorderedlist", "Insert Ordered List",
69
        "insertunorderedlist", "Insert Unordered List",
70
        "link", "Create Link",
71
        "unlink", "Remove Link",
72
        "formatblock", "Choose Format",
73
        "fontname", "Choose Font Style",
74
        "fontsize", "Choose Font Size",
75
        "forecolor", "Choose Font Color",
76
        "removeformat", "Remove Formatting"
77
    ],
8231 bpr 78
 
1442 bpr 79
    //Colors available in the color bar
8231 bpr 80
    colors: [ "006600", "666600", "ccff66", "669933", "ffffff", "eeeeee", "999999", "333333", "000000", "666699", "000033", "000066", "ccffff", "ffff33", "ffcc00", "ffff99", "990000", "330033", "cc3399", "ffcccc", "ffffcc", "996633", "663300", "330000"],
81
 
1442 bpr 82
    //Block Options for formatblock
83
    blockOptions: [
84
        "<h1>", "Heading 1",
85
        "<h2>", "Heading 2",
86
        "<h3>", "Heading 3",
87
        "<h4>", "Heading 4",
88
        "<h5>", "Heading 5",
89
        "<h6>", "Heading 6",
90
        "<p>", "Normal",
91
        "<blockquote>", "Block Quote"
92
    ],
8231 bpr 93
 
1442 bpr 94
    //Font options for fontname
95
    fontOptions: [
96
        "Verdana", "Verdana",
97
        "Arial", "Arial",
98
        "Georgia", "Georgia",
99
        "Trebuchet", "Trebuchet",
100
        "Courier New", "Courier",
101
        "Times New Roman", "Times"
102
    ],
8231 bpr 103
 
1442 bpr 104
    //Font size options for fontsize
105
    fontSizes: [
106
        "1", "Small",
107
        "3", "Medium",
108
        "5", "Large",
109
        "7", "Largest"
110
    ],
8231 bpr 111
 
1442 bpr 112
    //Initialize the edit window
113
    init: function(ta, callback) {
114
 
9054 obado 115
        this.ta = ta;
8231 bpr 116
        this.id = ta.id;
1442 bpr 117
        iEdit[this.id] = this;
8231 bpr 118
 
9054 obado 119
        if (callback)
120
            this.loaded = callback;
8231 bpr 121
 
9054 obado 122
        //Get the current width
123
        this.width = this.ta.offsetWidth;
124
        if (this.width == 0)
125
            this.width = parseInt(this.ta.style.width);
8231 bpr 126
 
1442 bpr 127
        //Get the current height
128
        this.height = this.ta.offsetHeight;
9054 obado 129
        if (this.height == 0)
130
            this.height = parseInt(this.ta.style.height);
8231 bpr 131
 
1442 bpr 132
        this.ta.style.display = "none";
8231 bpr 133
 
9054 obado 134
        this.container = this.$new("div");
8231 bpr 135
 
9054 obado 136
        this.tb = this.$new("div");
137
        this.tb.className = "speckToolbar";
1442 bpr 138
        this.tb.style.width = this.width + "px";
139
        this.container.appendChild(this.tb);
8231 bpr 140
 
9054 obado 141
        //Add the features
142
        for(var i=0;i<this.features.length;i+=2) {
143
            this.addFeature(this.features[i], this.features[i+1]);
144
        }
8231 bpr 145
 
146
        this.ta.style.height = (this.height-32) + "px";
1442 bpr 147
        this.ta.parentNode.replaceChild(this.container, this.ta);
9054 obado 148
        this.container.appendChild(this.ta);
8231 bpr 149
 
1442 bpr 150
        this.initEdit();
151
 
152
    },
8231 bpr 153
    initEdit: function(content) {
1442 bpr 154
        if (this.iframe)
155
            this.container.removeChild(this.iframe);
156
 
157
        //Create the iframe
158
        this.iframe = this.$new("iframe");
159
        this.iframe.className = "speckFrame";
160
        this.iframe.frameBorder = "0";
161
        this.iframe.style.width = (this.width-2) + "px";
162
        this.iframe.style.height = (this.height-32) + "px";
163
        this.container.appendChild(this.iframe);
8231 bpr 164
 
1442 bpr 165
        //Save style properties with property called savestyle
8231 bpr 166
        content = this.ta.value.replace(/(style|STYLE|Style)=('|").+?('|")/g, function(match){ return match + " save" + match; });
167
 
1442 bpr 168
        //Write out current content to the iframe window, include edit mode stylesheet
9054 obado 169
        this.iframe.contentWindow.document.open();
170
        //this.iframe.contentWindow.document.write("<html><head><link id='ThemeStyle' href='" + this.editStylePath + "' type='text/css' rel='stylesheet' /></head><body style='background:#fff url();color:#000;'>" + content + "</body></html>");
171
        this.iframe.contentWindow.document.write("<html><head></head><body style='background:#fff url();color:#000;'>" + content + "</body></html>");
172
        this.iframe.contentWindow.document.close();
8231 bpr 173
 
1442 bpr 174
        this.enterDesignMode();
175
 
9054 obado 176
        return true;
1442 bpr 177
    },
178
    enterDesignMode: function() {
8231 bpr 179
 
1442 bpr 180
        //Firefox needs a little time for this.
8231 bpr 181
        if (!this.iframe.contentWindow.document.body) {
1442 bpr 182
            var self = this;
9054 obado 183
            setTimeout(function() { self.enterDesignMode(); }, 1);
184
            return;
185
        }
8231 bpr 186
 
9054 obado 187
        //Turn on design mode
188
        this.iframe.contentWindow.document.designMode = "on";
8231 bpr 189
 
9054 obado 190
        this.wysiwyg = true;
1442 bpr 191
 
192
        //call loaded event
193
        if (this.loaded)
194
            this.loaded.call();
195
    },
196
    addFeature: function(action, text) {
197
        switch (action) {
8231 bpr 198
            case "formatblock":
9054 obado 199
                this.hBar = this.$new("div");
200
                this.hBar.id = this.id + "Hbar";
1442 bpr 201
                this.addBar(this.hBar, "formatblock", this.blockOptions, text);
202
                this.container.appendChild(this.hBar);
203
                break;
8231 bpr 204
            case "fontname":
9054 obado 205
                this.fBar = this.$new("div");
206
                this.fBar.id = this.id + "Fbar";
1442 bpr 207
                this.addBar(this.fBar, "fontname", this.fontOptions, text);
208
                this.container.appendChild(this.fBar);
209
                break;
8231 bpr 210
            case "fontsize":
9054 obado 211
                this.sBar = this.$new("div");
212
                this.sBar.id = this.id + "Sbar";
1442 bpr 213
                this.addBar(this.sBar, "fontsize", this.fontSizes, text);
214
                this.container.appendChild(this.sBar);
215
                break;
8231 bpr 216
            case "forecolor":
1442 bpr 217
                this.addColor("forecolor", this.colors, text);
8231 bpr 218
                this.container.appendChild(this.cBar);
219
                break;
1442 bpr 220
            case "link":
8231 bpr 221
                this.addLinkBar("link", text);
222
                this.container.appendChild(this.lBar);
1442 bpr 223
                break;
224
            default:
8231 bpr 225
                this.tb.appendChild(this.getButton(action, text));
1442 bpr 226
                break;
227
        }
228
    },
229
    getButton: function(action, text) {
230
        var self = this;
8231 bpr 231
 
1442 bpr 232
        var button = this.$new("input");
233
        button.type = "button";
234
        button.id = action + "Button";
235
        button.title = text;
236
        button.className = "speckButton";
237
        button.action = action;
8231 bpr 238
        button.onclick = function() { self.execCommand(this); };
1442 bpr 239
        return button;
240
    },
241
    addColor: function(action, options, text) {
8231 bpr 242
 
9054 obado 243
        var button = this.getButton(action, text); // this.$new("input");
1442 bpr 244
        var self = this;
245
        button.onclick = function() { self.showSelect(this); };
8231 bpr 246
 
9054 obado 247
        var bar = this.$new("div");
248
        bar.id = action + "Select";
249
        bar.className = "speckColorBar";
1442 bpr 250
        bar.style.width = (this.width - 2) + "px"; //2 is border width
8231 bpr 251
        bar.style.display = "none";
9054 obado 252
        for (var i=0;i<options.length;i++)
253
        {
254
            var option = this.$new("input");
255
            option.val = options[i];
256
            option.type = "button";
257
            option.style.backgroundColor = "#" + option.val;
258
            option.action = action;
259
            option.className = "speckColor";
260
            option.onclick = function() { self.execCommand(this); };
8231 bpr 261
 
9054 obado 262
            bar.appendChild(option);
263
        }
264
        this.cBar = bar;
1442 bpr 265
        button.selectMenuId = bar.id;
266
        this.tb.appendChild(button);
9054 obado 267
        return true;
1442 bpr 268
    },
269
    addLinkBar: function(action, text) {
9054 obado 270
        var button = this.getButton(action, text); //this.$new("input");
8231 bpr 271
 
1442 bpr 272
        var self = this;
273
        button.onclick = function() { self.showSelect(this); };
8231 bpr 274
 
9054 obado 275
        var bar = this.$new("div");
276
        bar.id = action + "linkbar";
277
        bar.className = "speckLinkbar";
1442 bpr 278
        bar.style.width = (this.width-2) + "px"; //2 is border width
8231 bpr 279
        bar.style.display = "none";
1442 bpr 280
 
9054 obado 281
        this.linkUrl = this.$new("input");
282
        this.linkUrl.id = this.id + "link";
1442 bpr 283
        this.linkUrl.style.width = (this.width - 60) + "px";
284
        this.linkUrl.value = "http://";
8231 bpr 285
 
1442 bpr 286
        var link = this.$new("input");
287
        link.type = "button";
288
        link.id = "linkingButton";
8231 bpr 289
        link.value = "link";
1442 bpr 290
        link.className = "linkbarButton";
291
        link.action = "createlink";
292
        link.onclick = function() { self.execCommand(this) };
293
        bar.appendChild(this.linkUrl);
294
        bar.appendChild(link);
295
 
9054 obado 296
        this.lBar = bar;
1442 bpr 297
        button.selectMenuId = bar.id;
298
        this.tb.appendChild(button);
9054 obado 299
        return true;
1442 bpr 300
    },
301
    addBar: function(bar, action, options, text) {
9054 obado 302
        var button = this.getButton(action, text); //this.$new("input");
1442 bpr 303
        var self = this;
304
        button.onclick = function() { self.showSelect(this); };
8231 bpr 305
 
9054 obado 306
        bar.className = "speckBar";
1442 bpr 307
        bar.style.width = (this.width-2) + "px";
8231 bpr 308
        bar.style.display = "none";
309
 
9054 obado 310
        for (var i=0;i<options.length;i+=2)
311
        {
312
            var option = this.$new("input");
313
            option.val = options[i];
314
            option.value = options[i + 1];
315
            option.type = "button";
316
            option.action = action;
317
            option.editor = this.id;
318
            option.className = "speckOption";
319
            option.onclick = function() { self.execCommand(this) };
8231 bpr 320
 
9054 obado 321
            bar.appendChild(option);
322
        }
1442 bpr 323
        button.selectMenuId = bar.id;
324
        this.tb.appendChild(button);
9054 obado 325
        return true;
1442 bpr 326
    },
327
    hideSelects: function() {
328
        var buttons = this.tb.childNodes;
329
        for(var i=0;i<buttons.length;i++) {
330
            var button = buttons[i];
331
            if (button.selectMenuId) {
332
                var selectMenu = document.getElementById(button.selectMenuId);
333
                selectMenu.style.display = "none";
334
            }
335
        }
336
        this.lBar.style.display = "none";
337
        this.iframe.style.height = (this.height-32) + "px";
338
        this.ta.style.height = (this.height-32) + "px";
339
    },
340
    addLinkbar: function() {
9054 obado 341
        this.lBar = this.$new("div");
342
        this.lBar.id = this.id + "linkbar";
343
        this.lBar.className = "speckLinkbar";
1442 bpr 344
        this.lBar.style.width = this.width-10 + "px";
8231 bpr 345
        this.lBar.style.display = "none";
346
 
9054 obado 347
        this.linkUrl = this.$new("input");
348
        this.linkUrl.id = this.id + "link";
1442 bpr 349
        this.linkUrl.style.width = (this.width - 60) + "px";
350
        this.linkUrl.value = "http://";
8231 bpr 351
 
1442 bpr 352
        var link = this.$new("input");
353
        link.type = "button";
8231 bpr 354
        link.value = "link";
1442 bpr 355
        link.className = "linkbarButton";
356
        link.action = "createlink";
357
        var self = this;
358
        link.onclick = function() { self.execCommand(); };
359
        this.lBar.appendChild(this.linkUrl);
360
        this.lBar.appendChild(link);
361
    },
362
    toggleLinkbar: function() {
363
        if (this.lBar.style.display == "none") {
364
            this.lBar.style.display = "block";
365
            this.iframe.style.height = (this.height-(64)) + "px";
366
        } else {
367
            this.lBar.style.display = "none";
8231 bpr 368
            this.iframe.style.height = (this.height-32) + "px";
1442 bpr 369
        }
370
    },
371
    setFocus: function() {
9054 obado 372
        if (this.wysiwyg == true)
373
            this.iframe.contentWindow.focus();
374
        else
375
            this.ta.focus();
1442 bpr 376
    },
377
    toggleMode: function() {
378
        this.hideSelects();
379
        if (this.wysiwyg) {
380
            this.html(); //update html
381
            this.ta.style.display = "block";
382
            this.iframe.style.display = "none";
383
            this.wysiwyg = false;
384
        }
385
        else {
386
            this.ta.style.display = "none";
9054 obado 387
            this.initEdit(this.ta.value);
1442 bpr 388
            this.wysiwyg = true;
389
        }
390
    },
9054 obado 391
    disable: function() {
392
        this.hideSelects();
393
        if (this.wysiwyg) {
394
            this.html(); //update html
395
            this.ta.style.display = "block";
396
            this.iframe.style.display = "none";
397
            this.wysiwyg = false;
398
        }
399
    },
400
    enable: function() {
401
        this.hideSelects();
402
        if (!this.wysiwyg) {
403
            this.ta.style.display = "none";
404
            this.initEdit(this.ta.value);
405
            this.wysiwyg = true;
406
        }
407
    },
1442 bpr 408
    html: function() {
409
        this.ta.value = this.innerXML(this.iframe.contentWindow.document.body.cloneNode(true));
410
        return this.ta.value;
411
    },
412
    showSelect: function(selector) {
8231 bpr 413
 
1442 bpr 414
        var selectMenu = document.getElementById(selector.selectMenuId);
8231 bpr 415
 
416
        //if select bar is already open, close it.
1442 bpr 417
        if (selectMenu.style.display == "block") {
418
            this.hideSelects();
419
            return;
420
        }
8231 bpr 421
 
422
        this.hideSelects();
1442 bpr 423
        this.iframe.style.height = (this.height-64) + "px";
424
        this.ta.style.height = (this.height-64) + "px";
425
        selectMenu.style.display = "block";
426
    },
427
    execCommand: function(button) {
8231 bpr 428
 
1442 bpr 429
        var doc = this.iframe.contentWindow.document;
8231 bpr 430
 
9054 obado 431
        switch (button.action) {
432
            case "createlink":
433
                if (this.linkUrl.value != "") {
1442 bpr 434
                    doc.execCommand(button.action, false, this.linkUrl.value);
8231 bpr 435
                    this.toggleLinkbar();
1442 bpr 436
                }
437
                break;
9054 obado 438
            case "formatblock":
439
            case "fontsize":
440
            case "forecolor":
441
            case "fontname":
442
                doc.execCommand(button.action, false, button.val);
1442 bpr 443
                break;
444
            case "link":
445
                this.toggleLinkbar();
446
                break;
447
            case "html":
448
                this.toggleMode();
8231 bpr 449
                break;
9054 obado 450
            default:
451
                doc.execCommand(button.action, false, null);
1442 bpr 452
                break;
453
        }
8231 bpr 454
 
1442 bpr 455
        if (button.parentNode.className == "speckSelect") {
456
            button.parentNode.style.display = "none";
457
            return false;
8231 bpr 458
        }
459
        this.setFocus();
1442 bpr 460
    },
461
    innerXML: function(oNode) {
462
        //Returns the innerXML of an HTML DOM node
463
        var s = "";
8231 bpr 464
 
1442 bpr 465
        var nodes = oNode.childNodes;
466
        for(var i=0; i < nodes.length; i++)
467
        {
468
            var node = nodes[i];
469
            var nodeType = node.nodeType;
470
            if (nodeType == 1 || nodeType == 9 || nodeType == 11) //Element Node, Document Node, Document Fragment Node
471
                s += this.xml(node, "");
472
            else
8231 bpr 473
                s += node.data;
1442 bpr 474
        }
475
        return s;
8231 bpr 476
    },
1442 bpr 477
    xml: function(oNode, indent) {
478
        //Returns outerXML of the node.
479
 
480
        var s = "";
481
        var nodes = oNode.childNodes;
482
        var tag = oNode.nodeName.toLowerCase();
8231 bpr 483
 
1442 bpr 484
        if (nodes.length == 0 && (tag == "input" || tag == "img" || tag == "hr" || tag == "br" || tag == "feature" ))
485
        {
486
            if (!oNode.getAttribute("_moz_editor_bogus_node")) {
8231 bpr 487
              s += indent + "<" + tag + this.getAttributes(oNode) + "/>";
7298 bpr 488
              //s += indent + "<" + tag + this.getAttributes(oNode) + ">\n";
1442 bpr 489
            }
490
        }
491
        else
8231 bpr 492
        {
1442 bpr 493
            if (this.isEmptyNode(oNode))
494
                return s;
8231 bpr 495
 
1442 bpr 496
            s += indent + "<" + tag + this.getAttributes(oNode) + ">";
497
            for(var i=0; i < nodes.length; i++)
498
            {
499
                var node = nodes[i];
500
                var nodeType = node.nodeType;
8231 bpr 501
 
1442 bpr 502
                if (nodeType == 1 || nodeType == 9 || nodeType == 11) //Element Node, Document Node, Document Fragment Node
503
                    s += this.xml(node, indent + "");
504
                else
8231 bpr 505
                    s += indent + node.data;
1442 bpr 506
            }
507
            s += indent + "</" + tag + ">";
508
        }
509
        return s;
8231 bpr 510
    },
1442 bpr 511
    getAttributes: function(oNode) {
512
        var s = "";
513
        var atts = oNode.attributes;
514
        var style = "";
515
        for(var i=0; i < atts.length; i++) {
516
            var att = atts[i];
517
 
518
            var name = att.nodeName.toLowerCase();
519
            var val = att.nodeValue;
520
 
521
            if (this.validAttribute(att, oNode.nodeName)) {
522
                if (name == "savestyle" || name == "style") {
523
                    if (style.indexOf(val)<0) //not already there
524
                        style += val;
525
                } else {
8231 bpr 526
                    s += " " + name + "=\"" + val.replace("about:/", "/") + "\" ";
1442 bpr 527
                }
528
            }
529
        }
530
        if (style.length>0)
531
            s += " style=\"" + style + "\" ";
8231 bpr 532
 
1442 bpr 533
        return s;
534
    },
535
    validAttribute: function(att, tag) {
536
        //eliminate unwanted or unsupported attributes
537
        var name = att.nodeName.toLowerCase();
538
        var val = att.nodeValue;
539
 
8231 bpr 540
        if (name == "start")
541
            return false;
542
 
1442 bpr 543
        if (val == null || val == "" || val == "inherit" || val == "_moz")
544
            return false;
8231 bpr 545
 
1442 bpr 546
        if (name == "colspan" || name == "rowspan")
547
            if (val == "1") { return false; }
8231 bpr 548
 
1442 bpr 549
        if (tag == "INPUT")
550
            if (name == "height" || name == "maxlength" || name == "loop")
551
                return false;
552
 
553
        if (tag == "IMG")
554
            if (name == "start" || name == "loop")
555
                return false;
556
 
557
        return true;
558
    },
559
    isEmptyNode: function(oNode) {
560
        var nodes = oNode.childNodes;
561
        for(var i=0; i < nodes.length; i++) {
562
            var node = nodes[i];
563
            var nodeType = node.nodeType;
8231 bpr 564
 
1442 bpr 565
            if (nodeType == 1 || nodeType == 9 || nodeType == 11) {
566
                return false;
8231 bpr 567
            } else {
1442 bpr 568
                if  (node.data.replace(/^\s+|\s+$/g,"").replace(/^\n+|\n+$/g,"") != "")
569
                    return false;
570
            }
571
        }
572
        return true;
573
    },
574
    $new: function(tag) {
575
        return document.createElement(tag);
8231 bpr 576
    }
1442 bpr 577
}
578