~bjornt/lazr-js/prefetch-yui-3.5

« back to all changes in this revision

Viewing changes to src-js/lazrjs/yui/editor/editor-base-debug.js

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-01-14 23:32:29 UTC
  • mfrom: (197.1.7 yui-3.3.0)
  • Revision ID: launchpad@pqm.canonical.com-20110114233229-r6i4cazdiiw18o7p
Upgrade to YUI 3.3.0 [r=mars]

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
3
Code licensed under the BSD License:
4
4
http://developer.yahoo.com/yui/license.html
5
 
version: 3.2.0
6
 
build: 2676
 
5
version: 3.3.0
 
6
build: 3167
7
7
*/
8
8
YUI.add('editor-base', function(Y) {
9
9
 
23
23
    
24
24
    var EditorBase = function() {
25
25
        EditorBase.superclass.constructor.apply(this, arguments);
26
 
    };
 
26
    }, LAST_CHILD = ':last-child', BODY = 'body';
27
27
 
28
28
    Y.extend(EditorBase, Y.Base, {
29
29
        /**
38
38
                use: EditorBase.USE,
39
39
                dir: this.get('dir'),
40
40
                extracss: this.get('extracss'),
 
41
                linkedcss: this.get('linkedcss'),
 
42
                defaultblock: this.get('defaultblock'),
41
43
                host: this
42
44
            }).plug(Y.Plugin.ExecCommand);
43
45
 
 
46
 
44
47
            frame.after('ready', Y.bind(this._afterFrameReady, this));
45
48
            frame.addTarget(this);
46
49
 
52
55
                defaultFn: this._defNodeChangeFn
53
56
            });
54
57
            
55
 
            this.plug(Y.Plugin.EditorPara);
 
58
            //this.plug(Y.Plugin.EditorPara);
56
59
        },
57
60
        destructor: function() {
58
61
            this.frame.destroy();
66
69
        * @param {Node} to The Node instance to copy the styles to
67
70
        */
68
71
        copyStyles: function(from, to) {
 
72
            if (from.test('a')) {
 
73
                //Don't carry the A styles
 
74
                return;
 
75
            }
69
76
            var styles = ['color', 'fontSize', 'fontFamily', 'backgroundColor', 'fontStyle' ],
70
77
                newStyles = {};
71
78
 
75
82
            if (from.ancestor('b,strong')) {
76
83
                newStyles.fontWeight = 'bold';
77
84
            }
 
85
            if (from.ancestor('u')) {
 
86
                if (!newStyles.textDecoration) {
 
87
                    newStyles.textDecoration = 'underline';
 
88
                }
 
89
            }
78
90
            to.setStyles(newStyles);
79
91
        },
80
92
        /**
84
96
        */
85
97
        _lastBookmark: null,
86
98
        /**
 
99
        * Resolves the e.changedNode in the nodeChange event if it comes from the document. If
 
100
        * the event came from the document, it will get the last child of the last child of the document
 
101
        * and return that instead.
 
102
        * @method _resolveChangedNode
 
103
        * @param {Node} n The node to resolve
 
104
        * @private
 
105
        */
 
106
        _resolveChangedNode: function(n) {
 
107
            var inst = this.getInstance(), lc, lc2, found;
 
108
            if (inst && n && n.test('html')) {
 
109
                lc = inst.one(BODY).one(LAST_CHILD);
 
110
                while (!found) {
 
111
                    if (lc) {
 
112
                        lc2 = lc.one(LAST_CHILD);
 
113
                        if (lc2) {
 
114
                            lc = lc2;
 
115
                        } else {
 
116
                            found = true;
 
117
                        }
 
118
                    } else {
 
119
                        found = true;
 
120
                    }
 
121
                }
 
122
                if (lc) {
 
123
                    if (lc.test('br')) {
 
124
                        if (lc.previous()) {
 
125
                            lc = lc.previous();
 
126
                        } else {
 
127
                            lc = lc.get('parentNode');
 
128
                        }
 
129
                    }
 
130
                    if (lc) {
 
131
                        n = lc;
 
132
                    }
 
133
                }
 
134
                
 
135
            }
 
136
            return n;
 
137
        },
 
138
        /**
87
139
        * The default handler for the nodeChange event.
88
140
        * @method _defNodeChangeFn
89
141
        * @param {Event} e The event
92
144
        _defNodeChangeFn: function(e) {
93
145
            var startTime = (new Date()).getTime();
94
146
            //Y.log('Default nodeChange function: ' + e.changedType, 'info', 'editor');
95
 
            var inst = this.getInstance(), sel;
 
147
            var inst = this.getInstance(), sel, cur,
 
148
                btag = inst.Selection.DEFAULT_BLOCK_TAG;
96
149
 
97
150
            if (Y.UA.ie) {
98
 
                sel = inst.config.doc.selection.createRange();
99
 
                this._lastBookmark = sel.getBookmark();
 
151
                try {
 
152
                    sel = inst.config.doc.selection.createRange();
 
153
                    if (sel.getBookmark) {
 
154
                        this._lastBookmark = sel.getBookmark();
 
155
                    }
 
156
                } catch (ie) {}
100
157
            }
101
158
 
 
159
            e.changedNode = this._resolveChangedNode(e.changedNode);
 
160
 
102
161
            /*
103
162
            * @TODO
104
163
            * This whole method needs to be fixed and made more dynamic.
108
167
            
109
168
            switch (e.changedType) {
110
169
                case 'keydown':
111
 
                    inst.Selection.cleanCursor();
112
 
                    break;
113
 
                case 'enter':
114
 
                    if (Y.UA.webkit) {
115
 
                        //Webkit doesn't support shift+enter as a BR, this fixes that.
116
 
                        if (e.changedEvent.shiftKey) {
117
 
                            this.execCommand('insertbr');
118
 
                            e.changedEvent.preventDefault();
 
170
                    if (!Y.UA.gecko) {
 
171
                        if (!EditorBase.NC_KEYS[e.changedEvent.keyCode] && !e.changedEvent.shiftKey && !e.changedEvent.ctrlKey && (e.changedEvent.keyCode !== 13)) {
 
172
                            //inst.later(100, inst, inst.Selection.cleanCursor);
119
173
                        }
120
174
                    }
121
175
                    break;
122
176
                case 'tab':
123
177
                    if (!e.changedNode.test('li, li *') && !e.changedEvent.shiftKey) {
124
 
                        e.changedEvent.preventDefault();
125
 
 
 
178
                        e.changedEvent.frameEvent.preventDefault();
126
179
                        Y.log('Overriding TAB key to insert HTML: HALTING', 'info', 'editor');
127
 
                        var sel = new inst.Selection();
128
 
                        sel.setCursor();
129
 
                        var cur = sel.getCursor();
130
 
                        cur.insert(EditorBase.TABKEY, 'before');
131
 
                        sel.focusCursor();
132
 
                    }
133
 
                    break;
134
 
                case 'enter-up':
135
 
                    if (e.changedNode.test('p')) {
136
 
                        var prev = e.changedNode.previous(), lc, lc2, found = false;
137
 
                        if (prev) {
138
 
                            lc = prev.one(':last-child');
139
 
                            while (!found) {
140
 
                                if (lc) {
141
 
                                    lc2 = lc.one(':last-child');
142
 
                                    if (lc2) {
143
 
                                        lc = lc2;
144
 
                                    } else {
145
 
                                        found = true;
146
 
                                    }
147
 
                                } else {
148
 
                                    found = true;
149
 
                                }
150
 
                            }
151
 
                            if (lc) {
152
 
                                this.copyStyles(lc, e.changedNode);
153
 
                            }
 
180
                        if (Y.UA.webkit) {
 
181
                            this.execCommand('inserttext', '\t');
 
182
                        } else if (Y.UA.gecko) {
 
183
                            this.frame.exec._command('inserthtml', '<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>');
 
184
                        } else if (Y.UA.ie) {
 
185
                            sel = new inst.Selection();
 
186
                            sel._selection.pasteHTML(EditorBase.TABKEY);
154
187
                        }
155
188
                    }
156
189
                    break;
157
190
            }
 
191
            if (Y.UA.webkit && e.commands && (e.commands.indent || e.commands.outdent)) {
 
192
                /**
 
193
                * When executing execCommand 'indent or 'outdent' Webkit applies
 
194
                * a class to the BLOCKQUOTE that adds left/right margin to it
 
195
                * This strips that style so it is just a normal BLOCKQUOTE
 
196
                */
 
197
                var bq = inst.all('.webkit-indent-blockquote');
 
198
                if (bq.size()) {
 
199
                    bq.setStyle('margin', '');
 
200
                }
 
201
            }
158
202
 
159
203
            var changed = this.getDomPath(e.changedNode, false),
160
204
                cmds = {}, family, fsize, classes = [],
174
218
 
175
219
                //Bold and Italic styles
176
220
                var s = el.currentStyle || el.style;
177
 
 
178
221
                if ((''+s.fontWeight) == 'bold') { //Cast this to a string
179
222
                    cmds.bold = 1;
180
223
                }
 
224
                if (Y.UA.ie) {
 
225
                    if (s.fontWeight > 400) {
 
226
                        cmds.bold = 1;
 
227
                    }
 
228
                }
181
229
                if (s.fontStyle == 'italic') {
182
230
                    cmds.italic = 1;
183
231
                }
199
247
                    }
200
248
                }
201
249
 
202
 
                fsize = n.getStyle('fontSize');
 
250
                fsize = EditorBase.NORMALIZE_FONTSIZE(n);
 
251
 
203
252
 
204
253
                var cls = el.className.split(' ');
205
254
 
209
258
                    }
210
259
                });
211
260
 
212
 
                fColor = EditorBase.FILTER_RGB(s.color);
 
261
                fColor = EditorBase.FILTER_RGB(n.getStyle('color'));
213
262
                var bColor2 = EditorBase.FILTER_RGB(s.backgroundColor);
214
263
                if (bColor2 !== 'transparent') {
215
 
                    bColor = bColor2;
 
264
                    if (bColor2 !== '') {
 
265
                        bColor = bColor2;
 
266
                    }
216
267
                }
217
268
                
218
269
            });
320
371
            
321
372
            this.frame.on('dom:mouseup', Y.bind(this._onFrameMouseUp, this));
322
373
            this.frame.on('dom:mousedown', Y.bind(this._onFrameMouseDown, this));
323
 
            /*
 
374
            this.frame.on('dom:keydown', Y.bind(this._onFrameKeyDown, this));
 
375
 
 
376
            if (Y.UA.ie) {
 
377
                this.frame.on('dom:activate', Y.bind(this._onFrameActivate, this));
 
378
                this.frame.on('dom:beforedeactivate', Y.bind(this._beforeFrameDeactivate, this));
 
379
            }
324
380
            this.frame.on('dom:keyup', Y.bind(this._onFrameKeyUp, this));
325
 
            this.frame.on('dom:keydown', Y.bind(this._onFrameKeyDown, this));
326
381
            this.frame.on('dom:keypress', Y.bind(this._onFrameKeyPress, this));
327
 
            */
328
 
            //this.frame.on('dom:keydown', Y.throttle(Y.bind(this._onFrameKeyDown, this), 500));
329
 
 
330
 
 
331
 
            this.frame.on('dom:keydown', Y.bind(this._onFrameKeyDown, this));
332
 
 
333
 
            if (Y.UA.ie) {
334
 
                this.frame.on('dom:activate', Y.bind(this._onFrameActivate, this));
335
 
                this.frame.on('dom:keyup', Y.throttle(Y.bind(this._onFrameKeyUp, this), 800));
336
 
                this.frame.on('dom:keypress', Y.throttle(Y.bind(this._onFrameKeyPress, this), 800));
337
 
            } else {
338
 
                this.frame.on('dom:keyup', Y.bind(this._onFrameKeyUp, this));
339
 
                this.frame.on('dom:keypress', Y.bind(this._onFrameKeyPress, this));
340
 
            }
341
382
 
342
383
            inst.Selection.filter();
343
384
            this.fire('ready');
344
385
        },
345
386
        /**
 
387
        * Caches the current cursor position in IE.
 
388
        * @method _beforeFrameDeactivate
 
389
        * @private
 
390
        */
 
391
        _beforeFrameDeactivate: function() {
 
392
            var inst = this.getInstance(),
 
393
                sel = inst.config.doc.selection.createRange();
 
394
            
 
395
            if ((!sel.compareEndPoints('StartToEnd', sel))) {
 
396
                sel.pasteHTML('<var id="yui-ie-cursor">');
 
397
            }
 
398
        },
 
399
        /**
346
400
        * Moves the cached selection bookmark back so IE can place the cursor in the right place.
347
401
        * @method _onFrameActivate
348
402
        * @private
349
403
        */
350
404
        _onFrameActivate: function() {
351
 
            if (this._lastBookmark) {
352
 
                Y.log('IE Activate handler, resetting cursor position', 'info', 'editor');
353
 
                var inst = this.getInstance(),
354
 
                    sel = inst.config.doc.selection.createRange(),
355
 
                    bk = sel.moveToBookmark(this._lastBookmark);
 
405
            var inst = this.getInstance(),
 
406
                sel = new inst.Selection(),
 
407
                range = sel.createRange(),
 
408
                cur = inst.all('#yui-ie-cursor');
356
409
 
357
 
                sel.collapse(true);
358
 
                sel.select();
359
 
                this._lastBookmark = null;
 
410
            if (cur.size()) {
 
411
                cur.each(function(n) {
 
412
                    n.set('id', '');
 
413
                    range.moveToElementText(n._node);
 
414
                    range.move('character', -1);
 
415
                    range.move('character', 1);
 
416
                    range.select();
 
417
                    range.text = '';
 
418
                    n.remove();
 
419
                });
360
420
            }
361
421
        },
362
422
        /**
381
441
        * @private
382
442
        */
383
443
        _currentSelection: null,
 
444
        /**
 
445
        * Holds the timer for selection clearing
 
446
        * @property _currentSelectionTimer
 
447
        * @private
 
448
        */
384
449
        _currentSelectionTimer: null,
 
450
        /**
 
451
        * Flag to determine if we can clear the selection or not.
 
452
        * @property _currentSelectionClear
 
453
        * @private
 
454
        */
385
455
        _currentSelectionClear: null,
386
456
        /**
387
457
        * Fires nodeChange event
389
459
        * @private
390
460
        */
391
461
        _onFrameKeyDown: function(e) {
 
462
            var inst, sel;
392
463
            if (!this._currentSelection) {
393
464
                if (this._currentSelectionTimer) {
394
465
                    this._currentSelectionTimer.cancel();
396
467
                this._currentSelectionTimer = Y.later(850, this, function() {
397
468
                    this._currentSelectionClear = true;
398
469
                });
399
 
                var inst = this.frame.getInstance(),
400
 
                    sel = new inst.Selection(e);
 
470
                
 
471
                inst = this.frame.getInstance();
 
472
                sel = new inst.Selection(e);
401
473
 
402
474
                this._currentSelection = sel;
403
475
            } else {
404
 
                var sel = this._currentSelection;
 
476
                sel = this._currentSelection;
405
477
            }
406
 
                var inst = this.frame.getInstance(),
407
 
                    sel = new inst.Selection();
408
 
 
409
 
                this._currentSelection = sel;
410
 
 
 
478
 
 
479
            inst = this.frame.getInstance();
 
480
            sel = new inst.Selection();
 
481
 
 
482
            this._currentSelection = sel;
 
483
            
411
484
            if (sel && sel.anchorNode) {
412
485
                this.fire('nodeChange', { changedNode: sel.anchorNode, changedType: 'keydown', changedEvent: e.frameEvent });
413
486
                if (EditorBase.NC_KEYS[e.keyCode]) {
552
625
    }, {
553
626
        /**
554
627
        * @static
 
628
        * @method NORMALIZE_FONTSIZE
 
629
        * @description Pulls the fontSize from a node, then checks for string values (x-large, x-small)
 
630
        * and converts them to pixel sizes. If the parsed size is different from the original, it calls
 
631
        * node.setStyle to update the node with a pixel size for normalization.
 
632
        */
 
633
        NORMALIZE_FONTSIZE: function(n) {
 
634
            var size = n.getStyle('fontSize'), oSize = size;
 
635
            
 
636
            switch (size) {
 
637
                case '-webkit-xxx-large':
 
638
                    size = '48px';
 
639
                    break;
 
640
                case 'xx-large':
 
641
                    size = '32px';
 
642
                    break;
 
643
                case 'x-large':
 
644
                    size = '24px';
 
645
                    break;
 
646
                case 'large':
 
647
                    size = '18px';
 
648
                    break;
 
649
                case 'medium':
 
650
                    size = '16px';
 
651
                    break;
 
652
                case 'small':
 
653
                    size = '13px';
 
654
                    break;
 
655
                case 'x-small':
 
656
                    size = '10px';
 
657
                    break;
 
658
            }
 
659
            if (oSize !== size) {
 
660
                n.setStyle('fontSize', size);
 
661
            }
 
662
            return size;
 
663
        },
 
664
        /**
 
665
        * @static
555
666
        * @property TABKEY
556
667
        * @description The HTML markup to use for the tabkey
557
668
        */
653
764
            * @attribute content
654
765
            */
655
766
            content: {
656
 
                value: '<br>',
 
767
                value: '<br class="yui-cursor">',
657
768
                setter: function(str) {
658
769
                    if (str.substr(0, 1) === "\n") {
659
770
                        Y.log('Stripping first carriage return from content before injecting', 'warn', 'editor');
660
771
                        str = str.substr(1);
661
772
                    }
662
773
                    if (str === '') {
663
 
                        str = '<br>';
 
774
                        str = '<br class="yui-cursor">';
 
775
                    }
 
776
                    if (str === ' ') {
 
777
                        if (Y.UA.gecko) {
 
778
                            str = '<br class="yui-cursor">';
 
779
                        }
664
780
                    }
665
781
                    return this.frame.set('content', str);
666
782
                },
677
793
                value: 'ltr'
678
794
            },
679
795
            /**
 
796
            * @attribute linkedcss
 
797
            * @description An array of url's to external linked style sheets
 
798
            * @type String
 
799
            */            
 
800
            linkedcss: {
 
801
                value: '',
 
802
                setter: function(css) {
 
803
                    if (this.frame) {
 
804
                        this.frame.set('linkedcss', css);
 
805
                    }
 
806
                    return css;
 
807
                }
 
808
            },
 
809
            /**
680
810
            * @attribute extracss
681
811
            * @description A string of CSS to add to the Head of the Editor
682
812
            * @type String
689
819
                    }
690
820
                    return css;
691
821
                }
 
822
            },
 
823
            /**
 
824
            * @attribute defaultblock
 
825
            * @description The default tag to use for block level items, defaults to: p
 
826
            * @type String
 
827
            */            
 
828
            defaultblock: {
 
829
                value: 'p'
692
830
            }
693
831
        }
694
832
    });
725
863
 
726
864
 
727
865
 
728
 
}, '3.2.0' ,{skinnable:false, requires:['base', 'frame', 'node', 'exec-command']});
 
866
}, '3.3.0' ,{requires:['base', 'frame', 'node', 'exec-command', 'selection', 'editor-para'], skinnable:false});