Subversion Repositories wimsdev

Rev

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