~lss-team/lilsoftstats/trunk

« back to all changes in this revision

Viewing changes to js/jquery/jquery.wysiwyg.js

  • Committer: Nick
  • Date: 2011-11-14 04:10:28 UTC
  • Revision ID: nick@little-apps.org-20111114041028-cvmpwq6z6hx3pkya
first commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * WYSIWYG - jQuery plugin 0.5
 
3
 *
 
4
 * Copyright (c) 2008-2009 Juan M Martinez
 
5
 * http://plugins.jquery.com/project/jWYSIWYG
 
6
 *
 
7
 * Dual licensed under the MIT and GPL licenses:
 
8
 *   http://www.opensource.org/licenses/mit-license.php
 
9
 *   http://www.gnu.org/licenses/gpl.html
 
10
 *
 
11
 * $Id: $
 
12
 */
 
13
(function( $ )
 
14
{
 
15
    $.fn.document = function()
 
16
    {
 
17
        var element = this[0];
 
18
 
 
19
        if ( element.nodeName.toLowerCase() == 'iframe' )
 
20
            return element.contentWindow.document;
 
21
            /*
 
22
            return ( $.browser.msie )
 
23
                ? document.frames[element.id].document
 
24
                : element.contentWindow.document // contentDocument;
 
25
             */
 
26
        else
 
27
            return $(this);
 
28
    };
 
29
 
 
30
    $.fn.documentSelection = function()
 
31
    {
 
32
        var element = this[0];
 
33
 
 
34
        if ( element.contentWindow.document.selection )
 
35
            return element.contentWindow.document.selection.createRange().text;
 
36
        else
 
37
            return element.contentWindow.getSelection().toString();
 
38
    };
 
39
 
 
40
    $.fn.wysiwyg = function( options )
 
41
    {
 
42
        if ( arguments.length > 0 && arguments[0].constructor == String )
 
43
        {
 
44
            var action = arguments[0].toString();
 
45
            var params = [];
 
46
 
 
47
            for ( var i = 1; i < arguments.length; i++ )
 
48
                params[i - 1] = arguments[i];
 
49
 
 
50
            if ( action in Wysiwyg )
 
51
            {
 
52
                return this.each(function()
 
53
                {
 
54
                    $.data(this, 'wysiwyg')
 
55
                     .designMode();
 
56
 
 
57
                    Wysiwyg[action].apply(this, params);
 
58
                });
 
59
            }
 
60
            else return this;
 
61
        }
 
62
 
 
63
        var controls = {};
 
64
 
 
65
        /**
 
66
         * If the user set custom controls, we catch it, and merge with the
 
67
         * defaults controls later.
 
68
         */
 
69
        if ( options && options.controls )
 
70
        {
 
71
            var controls = options.controls;
 
72
            delete options.controls;
 
73
        }
 
74
 
 
75
        var options = $.extend({
 
76
            html : '<'+'?xml version="1.0" encoding="UTF-8"?'+'><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">STYLE_SHEET</head><body style="font-family: Arial, Helvetica, sans-serif !important; font-size: 13px; height: 100%; line-height: 1.5em !important;">INITIAL_CONTENT</body></html>',
 
77
            css  : {},
 
78
 
 
79
            debug        : false,
 
80
 
 
81
            autoSave     : true,  // http://code.google.com/p/jwysiwyg/issues/detail?id=11
 
82
            rmUnwantedBr : true,  // http://code.google.com/p/jwysiwyg/issues/detail?id=15
 
83
            brIE         : true,
 
84
 
 
85
            controls : {},
 
86
            messages : {}
 
87
        }, options);
 
88
 
 
89
        options.messages = $.extend(true, options.messages, Wysiwyg.MSGS_EN);
 
90
        options.controls = $.extend(true, options.controls, Wysiwyg.TOOLBAR);
 
91
 
 
92
        for ( var control in controls )
 
93
        {
 
94
            if ( control in options.controls )
 
95
                $.extend(options.controls[control], controls[control]);
 
96
            else
 
97
                options.controls[control] = controls[control];
 
98
        }
 
99
 
 
100
        // not break the chain
 
101
        return this.each(function()
 
102
        {
 
103
            Wysiwyg(this, options);
 
104
        });
 
105
    };
 
106
 
 
107
    function Wysiwyg( element, options )
 
108
    {
 
109
        return this instanceof Wysiwyg
 
110
            ? this.init(element, options)
 
111
            : new Wysiwyg(element, options);
 
112
    }
 
113
 
 
114
    $.extend(Wysiwyg, {
 
115
        insertImage : function( szURL, attributes )
 
116
        {
 
117
            var self = $.data(this, 'wysiwyg');
 
118
 
 
119
            if ( self.constructor == Wysiwyg && szURL && szURL.length > 0 )
 
120
            {
 
121
                if ( attributes )
 
122
                {
 
123
                    self.editorDoc.execCommand('insertImage', false, '#jwysiwyg#');
 
124
                    var img = self.getElementByAttributeValue('img', 'src', '#jwysiwyg#');
 
125
 
 
126
                    if ( img )
 
127
                    {
 
128
                        img.src = szURL;
 
129
 
 
130
                        for ( var attribute in attributes )
 
131
                        {
 
132
                            img.setAttribute(attribute, attributes[attribute]);
 
133
                        }
 
134
                    }
 
135
                }
 
136
                else
 
137
                {
 
138
                    self.editorDoc.execCommand('insertImage', false, szURL);
 
139
                }
 
140
            }
 
141
        },
 
142
 
 
143
        createLink : function( szURL )
 
144
        {
 
145
            var self = $.data(this, 'wysiwyg');
 
146
 
 
147
            if ( self.constructor == Wysiwyg && szURL && szURL.length > 0 )
 
148
            {
 
149
                var selection = $(self.editor).documentSelection();
 
150
 
 
151
                if ( selection.length > 0 )
 
152
                {
 
153
                    self.editorDoc.execCommand('unlink', false, []);
 
154
                    self.editorDoc.execCommand('createLink', false, szURL);
 
155
                }
 
156
                else if ( self.options.messages.nonSelection )
 
157
                    alert(self.options.messages.nonSelection);
 
158
            }
 
159
        },
 
160
 
 
161
        setContent : function( newContent )
 
162
        {
 
163
            var self = $.data(this, 'wysiwyg');
 
164
                self.setContent( newContent );
 
165
                self.saveContent();
 
166
        },
 
167
 
 
168
        clear : function()
 
169
        {
 
170
            var self = $.data(this, 'wysiwyg');
 
171
                self.setContent('');
 
172
                self.saveContent();
 
173
        },
 
174
 
 
175
        MSGS_EN : {
 
176
            nonSelection : 'select the text you wish to link'
 
177
        },
 
178
 
 
179
        TOOLBAR : {
 
180
            bold          : { visible : true, tags : ['b', 'strong'], css : { fontWeight : 'bold' } },
 
181
            italic        : { visible : true, tags : ['i', 'em'], css : { fontStyle : 'italic' } },
 
182
            strikeThrough : { visible : false, tags : ['s', 'strike'], css : { textDecoration : 'line-through' } },
 
183
            underline     : { visible : false, tags : ['u'], css : { textDecoration : 'underline' } },
 
184
 
 
185
            separator00 : { visible : false, separator : true },
 
186
 
 
187
            justifyLeft   : { visible : false, css : { textAlign : 'left' } },
 
188
            justifyCenter : { visible : false, tags : ['center'], css : { textAlign : 'center' } },
 
189
            justifyRight  : { visible : false, css : { textAlign : 'right' } },
 
190
            justifyFull   : { visible : false, css : { textAlign : 'justify' } },
 
191
 
 
192
            separator01 : { visible : false, separator : true },
 
193
 
 
194
            indent  : { visible : false },
 
195
            outdent : { visible : false },
 
196
 
 
197
            separator02 : { visible : false, separator : true },
 
198
 
 
199
            subscript   : { visible : false, tags : ['sub'] },
 
200
            superscript : { visible : false, tags : ['sup'] },
 
201
 
 
202
            separator03 : { visible : false, separator : true },
 
203
 
 
204
            undo : { visible : false },
 
205
            redo : { visible : false },
 
206
 
 
207
            separator04 : { visible : false, separator : true },
 
208
 
 
209
            insertOrderedList    : { visible : false, tags : ['ol'] },
 
210
            insertUnorderedList  : { visible : false, tags : ['ul'] },
 
211
            insertHorizontalRule : { visible : false, tags : ['hr'] },
 
212
 
 
213
            separator05 : { separator : true },
 
214
 
 
215
            createLink : {
 
216
                visible : true,
 
217
                exec    : function()
 
218
                {
 
219
                    var selection = $(this.editor).documentSelection();
 
220
 
 
221
                    if ( selection.length > 0 )
 
222
                    {
 
223
                        if ( $.browser.msie )
 
224
                            this.editorDoc.execCommand('createLink', true, null);
 
225
                        else
 
226
                        {
 
227
                            var szURL = prompt('URL', 'http://');
 
228
 
 
229
                            if ( szURL && szURL.length > 0 )
 
230
                            {
 
231
                                this.editorDoc.execCommand('unlink', false, []);
 
232
                                this.editorDoc.execCommand('createLink', false, szURL);
 
233
                            }
 
234
                        }
 
235
                    }
 
236
                    else if ( this.options.messages.nonSelection )
 
237
                        alert(this.options.messages.nonSelection);
 
238
                },
 
239
 
 
240
                tags : ['a']
 
241
            },
 
242
 
 
243
            insertImage : {
 
244
                visible : true,
 
245
                exec    : function()
 
246
                {
 
247
                    if ( $.browser.msie )
 
248
                        this.editorDoc.execCommand('insertImage', true, null);
 
249
                    else
 
250
                    {
 
251
                        var szURL = prompt('URL', 'http://');
 
252
 
 
253
                        if ( szURL && szURL.length > 0 )
 
254
                            this.editorDoc.execCommand('insertImage', false, szURL);
 
255
                    }
 
256
                },
 
257
 
 
258
                tags : ['img']
 
259
            },
 
260
 
 
261
            separator06 : { separator : true },
 
262
 
 
263
            h1mozilla : { visible : true && $.browser.mozilla, className : 'h1', command : 'heading', arguments : ['h1'], tags : ['h1'] },
 
264
            h2mozilla : { visible : true && $.browser.mozilla, className : 'h2', command : 'heading', arguments : ['h2'], tags : ['h2'] },
 
265
            h3mozilla : { visible : true && $.browser.mozilla, className : 'h3', command : 'heading', arguments : ['h3'], tags : ['h3'] },
 
266
 
 
267
            h1 : { visible : true && !( $.browser.mozilla ), className : 'h1', command : 'formatBlock', arguments : ['Heading 1'], tags : ['h1'] },
 
268
            h2 : { visible : true && !( $.browser.mozilla ), className : 'h2', command : 'formatBlock', arguments : ['Heading 2'], tags : ['h2'] },
 
269
            h3 : { visible : true && !( $.browser.mozilla ), className : 'h3', command : 'formatBlock', arguments : ['Heading 3'], tags : ['h3'] },
 
270
 
 
271
            separator07 : { visible : false, separator : true },
 
272
 
 
273
            cut   : { visible : false },
 
274
            copy  : { visible : false },
 
275
            paste : { visible : false },
 
276
 
 
277
            separator08 : { separator : true && !( $.browser.msie ) },
 
278
 
 
279
            increaseFontSize : { visible : true && !( $.browser.msie ), tags : ['big'] },
 
280
            decreaseFontSize : { visible : true && !( $.browser.msie ), tags : ['small'] },
 
281
 
 
282
            separator09 : { separator : true },
 
283
 
 
284
            html : {
 
285
                visible : false,
 
286
                exec    : function()
 
287
                {
 
288
                    if ( this.viewHTML )
 
289
                    {
 
290
                        this.setContent( $(this.original).val() );
 
291
                        $(this.original).hide();
 
292
                    }
 
293
                    else
 
294
                    {
 
295
                        this.saveContent();
 
296
                        $(this.original).show();
 
297
                    }
 
298
 
 
299
                    this.viewHTML = !( this.viewHTML );
 
300
                }
 
301
            },
 
302
 
 
303
            removeFormat : {
 
304
                visible : true,
 
305
                exec    : function()
 
306
                {
 
307
                    this.editorDoc.execCommand('removeFormat', false, []);
 
308
                    this.editorDoc.execCommand('unlink', false, []);
 
309
                }
 
310
            }
 
311
        }
 
312
    });
 
313
 
 
314
    $.extend(Wysiwyg.prototype,
 
315
    {
 
316
        original : null,
 
317
        options  : {},
 
318
 
 
319
        element  : null,
 
320
        editor   : null,
 
321
 
 
322
        init : function( element, options )
 
323
        {
 
324
            var self = this;
 
325
 
 
326
            this.editor = element;
 
327
            this.options = options || {};
 
328
 
 
329
            $.data(element, 'wysiwyg', this);
 
330
 
 
331
            var newX = element.width || element.clientWidth;
 
332
            var newY = element.height || element.clientHeight;
 
333
 
 
334
            if ( element.nodeName.toLowerCase() == 'textarea' )
 
335
            {
 
336
                this.original = element;
 
337
 
 
338
                if ( newX == 0 && element.cols )
 
339
                    newX = ( element.cols * 8 ) + 21;
 
340
 
 
341
                if ( newY == 0 && element.rows )
 
342
                    newY = ( element.rows * 16 ) + 16;
 
343
 
 
344
                var editor = this.editor = $('<iframe></iframe>').css({
 
345
                    minHeight : ( newY - 6 ).toString() + 'px',
 
346
                    width     : ( newX - 8 ).toString() + 'px'
 
347
                }).attr('id', $(element).attr('id') + 'IFrame');
 
348
 
 
349
                if ( $.browser.msie )
 
350
                {
 
351
                    this.editor
 
352
                        .css('height', ( newY ).toString() + 'px');
 
353
 
 
354
                    /**
 
355
                    var editor = $('<span></span>').css({
 
356
                        width     : ( newX - 6 ).toString() + 'px',
 
357
                        height    : ( newY - 8 ).toString() + 'px'
 
358
                    }).attr('id', $(element).attr('id') + 'IFrame');
 
359
 
 
360
                    editor.outerHTML = this.editor.outerHTML;
 
361
                     */
 
362
                }
 
363
            }
 
364
 
 
365
            var panel = this.panel = $('<ul></ul>').addClass('panel');
 
366
 
 
367
            this.appendControls();
 
368
            this.element = $('<div></div>').css({
 
369
                width : ( newX > 0 ) ? ( newX ).toString() + 'px' : '100%'
 
370
            }).addClass('wysiwyg')
 
371
              .append(panel)
 
372
              .append( $('<div><!-- --></div>').css({ clear : 'both' }) )
 
373
              .append(editor);
 
374
 
 
375
            $(element)
 
376
            // .css('display', 'none')
 
377
            .hide()
 
378
            .before(this.element);
 
379
 
 
380
            this.viewHTML = false;
 
381
 
 
382
            this.initialHeight = newY - 8;
 
383
 
 
384
            /**
 
385
             * @link http://code.google.com/p/jwysiwyg/issues/detail?id=52
 
386
             */
 
387
            this.initialContent = $(element).val();
 
388
 
 
389
            this.initFrame();
 
390
 
 
391
            if ( this.initialContent.length == 0 )
 
392
                this.setContent('');
 
393
 
 
394
            if ( this.options.autoSave )
 
395
                $('form').submit(function() { self.saveContent(); });
 
396
 
 
397
            $('form').bind('reset', function()
 
398
            {
 
399
                self.setContent( self.initialContent );
 
400
                self.saveContent();
 
401
            });
 
402
        },
 
403
 
 
404
        initFrame : function()
 
405
        {
 
406
            var self = this;
 
407
            var style = '';
 
408
 
 
409
            /**
 
410
             * @link http://code.google.com/p/jwysiwyg/issues/detail?id=14
 
411
             */
 
412
            if ( this.options.css && this.options.css.constructor == String )
 
413
                style = '<link rel="stylesheet" type="text/css" media="screen" href="' + this.options.css + '" />';
 
414
 
 
415
            this.editorDoc = $(this.editor).document();
 
416
            this.editorDoc_designMode = false;
 
417
 
 
418
            try {
 
419
                this.editorDoc.designMode = 'on';
 
420
                this.editorDoc_designMode = true;
 
421
            } catch ( e ) {
 
422
                // Will fail on Gecko if the editor is placed in an hidden container element
 
423
                // The design mode will be set ones the editor is focused
 
424
 
 
425
                $(this.editorDoc).focus(function()
 
426
                {
 
427
                    self.designMode();
 
428
                });
 
429
            }
 
430
 
 
431
            this.editorDoc.open();
 
432
            this.editorDoc.write(
 
433
                this.options.html
 
434
                    .replace(/INITIAL_CONTENT/, this.initialContent)
 
435
                    .replace(/STYLE_SHEET/, style)
 
436
            );
 
437
            this.editorDoc.close();
 
438
            this.editorDoc.contentEditable = 'true';
 
439
 
 
440
            if ( $.browser.msie )
 
441
            {
 
442
                /**
 
443
                 * Remove the horrible border it has on IE.
 
444
                 */
 
445
                setTimeout(function() { $(self.editorDoc.body).css('border', 'none'); }, 0);
 
446
            }
 
447
 
 
448
            $(this.editorDoc).click(function( event )
 
449
            {
 
450
                self.checkTargets( event.target ? event.target : event.srcElement);
 
451
            });
 
452
 
 
453
            /**
 
454
             * @link http://code.google.com/p/jwysiwyg/issues/detail?id=20
 
455
             */
 
456
            $(this.original).focus(function()
 
457
            {
 
458
                $(self.editorDoc.body).focus();
 
459
            });
 
460
 
 
461
            if ( this.options.autoSave )
 
462
            {
 
463
                /**
 
464
                 * @link http://code.google.com/p/jwysiwyg/issues/detail?id=11
 
465
                 */
 
466
                $(this.editorDoc).keydown(function() { self.saveContent(); })
 
467
                                 .keyup(function() { self.saveContent(); })
 
468
                                 .mousedown(function() { self.saveContent(); });
 
469
            }
 
470
 
 
471
            if ( this.options.css )
 
472
            {
 
473
                setTimeout(function()
 
474
                {
 
475
                    if ( self.options.css.constructor == String )
 
476
                    {
 
477
                        /**
 
478
                         * $(self.editorDoc)
 
479
                         * .find('head')
 
480
                         * .append(
 
481
                         *     $('<link rel="stylesheet" type="text/css" media="screen" />')
 
482
                         *     .attr('href', self.options.css)
 
483
                         * );
 
484
                         */
 
485
                    }
 
486
                    else
 
487
                        $(self.editorDoc).find('body').css(self.options.css);
 
488
                }, 0);
 
489
            }
 
490
 
 
491
            $(this.editorDoc).keydown(function( event )
 
492
            {
 
493
                if ( $.browser.msie && self.options.brIE && event.keyCode == 13 )
 
494
                {
 
495
                    var rng = self.getRange();
 
496
                        rng.pasteHTML('<br />');
 
497
                        rng.collapse(false);
 
498
                        rng.select();
 
499
 
 
500
                                return false;
 
501
                }
 
502
            });
 
503
        },
 
504
 
 
505
        designMode : function()
 
506
        {
 
507
            if ( !( this.editorDoc_designMode ) )
 
508
            {
 
509
                try {
 
510
                    this.editorDoc.designMode = 'on';
 
511
                    this.editorDoc_designMode = true;
 
512
                } catch ( e ) {}
 
513
            }
 
514
        },
 
515
 
 
516
        getSelection : function()
 
517
        {
 
518
            return ( window.getSelection ) ? window.getSelection() : document.selection;
 
519
        },
 
520
 
 
521
        getRange : function()
 
522
        {
 
523
            var selection = this.getSelection();
 
524
 
 
525
            if ( !( selection ) )
 
526
                return null;
 
527
 
 
528
            return ( selection.rangeCount > 0 ) ? selection.getRangeAt(0) : selection.createRange();
 
529
        },
 
530
 
 
531
        getContent : function()
 
532
        {
 
533
            return $( $(this.editor).document() ).find('body').html();
 
534
        },
 
535
 
 
536
        setContent : function( newContent )
 
537
        {
 
538
            $( $(this.editor).document() ).find('body').html(newContent);
 
539
        },
 
540
 
 
541
        saveContent : function()
 
542
        {
 
543
            if ( this.original )
 
544
            {
 
545
                var content = this.getContent();
 
546
 
 
547
                if ( this.options.rmUnwantedBr )
 
548
                    content = ( content.substr(-4) == '<br>' ) ? content.substr(0, content.length - 4) : content;
 
549
 
 
550
                $(this.original).val(content);
 
551
            }
 
552
        },
 
553
 
 
554
        appendMenu : function( cmd, args, className, fn )
 
555
        {
 
556
            var self = this;
 
557
            var args = args || [];
 
558
 
 
559
            $('<li></li>').append(
 
560
                $('<a><!-- --></a>').addClass(className || cmd)
 
561
            ).mousedown(function() {
 
562
                if ( fn ) fn.apply(self); else self.editorDoc.execCommand(cmd, false, args);
 
563
                if ( self.options.autoSave ) self.saveContent();
 
564
            }).appendTo( this.panel );
 
565
        },
 
566
 
 
567
        appendMenuSeparator : function()
 
568
        {
 
569
            $('<li class="separator"></li>').appendTo( this.panel );
 
570
        },
 
571
 
 
572
        appendControls : function()
 
573
        {
 
574
            for ( var name in this.options.controls )
 
575
            {
 
576
                var control = this.options.controls[name];
 
577
 
 
578
                if ( control.separator )
 
579
                {
 
580
                    if ( control.visible !== false )
 
581
                        this.appendMenuSeparator();
 
582
                }
 
583
                else if ( control.visible )
 
584
                {
 
585
                    this.appendMenu(
 
586
                        control.command || name, control.arguments || [],
 
587
                        control.className || control.command || name || 'empty', control.exec
 
588
                    );
 
589
                }
 
590
            }
 
591
        },
 
592
 
 
593
        checkTargets : function( element )
 
594
        {
 
595
            for ( var name in this.options.controls )
 
596
            {
 
597
                var control = this.options.controls[name];
 
598
                var className = control.className || control.command || name || 'empty';
 
599
 
 
600
                $('.' + className, this.panel).removeClass('active');
 
601
 
 
602
                if ( control.tags )
 
603
                {
 
604
                    var elm = element;
 
605
 
 
606
                    do {
 
607
                        if ( elm.nodeType != 1 )
 
608
                            break;
 
609
 
 
610
                        if ( $.inArray(elm.tagName.toLowerCase(), control.tags) != -1 )
 
611
                            $('.' + className, this.panel).addClass('active');
 
612
                    } while ( elm = elm.parentNode );
 
613
                }
 
614
 
 
615
                if ( control.css )
 
616
                {
 
617
                    var elm = $(element);
 
618
 
 
619
                    do {
 
620
                        if ( elm[0].nodeType != 1 )
 
621
                            break;
 
622
 
 
623
                        for ( var cssProperty in control.css )
 
624
                            if ( elm.css(cssProperty).toString().toLowerCase() == control.css[cssProperty] )
 
625
                                $('.' + className, this.panel).addClass('active');
 
626
                    } while ( elm = elm.parent() );
 
627
                }
 
628
            }
 
629
        },
 
630
 
 
631
        getElementByAttributeValue : function( tagName, attributeName, attributeValue )
 
632
        {
 
633
            var elements = this.editorDoc.getElementsByTagName(tagName);
 
634
 
 
635
            for ( var i = 0; i < elements.length; i++ )
 
636
            {
 
637
                var value = elements[i].getAttribute(attributeName);
 
638
 
 
639
                if ( $.browser.msie )
 
640
                {
 
641
                    /** IE add full path, so I check by the last chars. */
 
642
                    value = value.substr(value.length - attributeValue.length);
 
643
                }
 
644
 
 
645
                if ( value == attributeValue )
 
646
                    return elements[i];
 
647
            }
 
648
 
 
649
            return false;
 
650
        }
 
651
    });
 
652
})(jQuery);
 
 
b'\\ No newline at end of file'