~andreserl/maas/packaging_precise_rebase

« back to all changes in this revision

Viewing changes to debian/extras/jslibs/yui/editor-bidi/editor-bidi-debug.js

  • Committer: Andres Rodriguez
  • Date: 2013-03-20 18:12:30 UTC
  • mfrom: (145.2.22 precise.sru)
  • Revision ID: andreserl@ubuntu.com-20130320181230-6l5guc0nhlv2z4p7
Re-base againts latest quantal released branch towards SRU

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
YUI 3.5.1 (build 22)
 
3
Copyright 2012 Yahoo! Inc. All rights reserved.
 
4
Licensed under the BSD License.
 
5
http://yuilibrary.com/license/
 
6
*/
 
7
YUI.add('editor-bidi', function(Y) {
 
8
 
 
9
 
 
10
    /**
 
11
     * Plugin for Editor to support BiDirectional (bidi) text operations.
 
12
     * @class Plugin.EditorBidi
 
13
     * @extends Base
 
14
     * @constructor
 
15
     * @module editor
 
16
     * @submodule editor-bidi
 
17
     */
 
18
 
 
19
 
 
20
    var EditorBidi = function() {
 
21
        EditorBidi.superclass.constructor.apply(this, arguments);
 
22
    }, HOST = 'host', DIR = 'dir', BODY = 'BODY', NODE_CHANGE = 'nodeChange',
 
23
    B_C_CHANGE = 'bidiContextChange', FIRST_P = BODY + ' > p', STYLE = 'style';
 
24
 
 
25
    Y.extend(EditorBidi, Y.Base, {
 
26
        /**
 
27
        * Place holder for the last direction when checking for a switch
 
28
        * @private
 
29
        * @property lastDirection
 
30
        */
 
31
        lastDirection: null,
 
32
        /**
 
33
        * Tells us that an initial bidi check has already been performed
 
34
        * @private
 
35
        * @property firstEvent
 
36
        */
 
37
        firstEvent: null,
 
38
 
 
39
        /**
 
40
        * Method checks to see if the direction of the text has changed based on a nodeChange event.
 
41
        * @private
 
42
        * @method _checkForChange
 
43
        */
 
44
        _checkForChange: function() {
 
45
            var host = this.get(HOST),
 
46
                inst = host.getInstance(),
 
47
                sel = new inst.EditorSelection(),
 
48
                node, direction;
 
49
            
 
50
            if (sel.isCollapsed) {
 
51
                node = EditorBidi.blockParent(sel.focusNode);
 
52
                if (node) {
 
53
                    direction = node.getStyle('direction');
 
54
                    if (direction !== this.lastDirection) {
 
55
                        host.fire(B_C_CHANGE, { changedTo: direction });
 
56
                        this.lastDirection = direction;
 
57
                    }
 
58
                }
 
59
            } else {
 
60
                host.fire(B_C_CHANGE, { changedTo: 'select' });
 
61
                this.lastDirection = null;
 
62
            }
 
63
        },
 
64
 
 
65
        /**
 
66
        * Checked for a change after a specific nodeChange event has been fired.
 
67
        * @private
 
68
        * @method _afterNodeChange
 
69
        */
 
70
        _afterNodeChange: function(e) { 
 
71
            // If this is the first event ever, or an event that can result in a context change
 
72
            if (this.firstEvent || EditorBidi.EVENTS[e.changedType]) {
 
73
                this._checkForChange();
 
74
                this.firstEvent = false;
 
75
            }
 
76
        },
 
77
 
 
78
        /**
 
79
        * Checks for a direction change after a mouseup occurs.
 
80
        * @private
 
81
        * @method _afterMouseUp
 
82
        */
 
83
        _afterMouseUp: function(e) {
 
84
            this._checkForChange();
 
85
            this.firstEvent = false;
 
86
        },
 
87
        initializer: function() {
 
88
            var host = this.get(HOST);
 
89
 
 
90
            this.firstEvent = true;
 
91
            
 
92
            host.after(NODE_CHANGE, Y.bind(this._afterNodeChange, this));
 
93
            host.after('dom:mouseup', Y.bind(this._afterMouseUp, this));
 
94
        }
 
95
    }, {
 
96
        /**
 
97
        * The events to check for a direction change on
 
98
        * @property EVENTS
 
99
        * @static
 
100
        */
 
101
        EVENTS: {
 
102
            'backspace-up': true,
 
103
            'pageup-up': true,
 
104
            'pagedown-down': true,
 
105
            'end-up': true,
 
106
            'home-up': true,
 
107
            'left-up': true,
 
108
            'up-up': true,
 
109
            'right-up': true,
 
110
            'down-up': true,
 
111
            'delete-up': true
 
112
        },
 
113
 
 
114
        /**
 
115
        * More elements may be needed. BODY *must* be in the list to take care of the special case.
 
116
        * 
 
117
        * blockParent could be changed to use inst.EditorSelection.BLOCKS
 
118
        * instead, but that would make Y.Plugin.EditorBidi.blockParent
 
119
        * unusable in non-RTE contexts (it being usable is a nice
 
120
        * side-effect).
 
121
        * @property BLOCKS
 
122
        * @static
 
123
        */
 
124
        //BLOCKS: Y.EditorSelection.BLOCKS+',LI,HR,' + BODY,
 
125
        BLOCKS: Y.EditorSelection.BLOCKS,
 
126
        /**
 
127
        * Template for creating a block element
 
128
        * @static
 
129
        * @property DIV_WRAPPER
 
130
        */
 
131
        DIV_WRAPPER: '<DIV></DIV>',
 
132
        /**
 
133
        * Returns a block parent for a given element
 
134
        * @static
 
135
        * @method blockParent
 
136
        */
 
137
        blockParent: function(node, wrap) {
 
138
            var parent = node, divNode, firstChild;
 
139
            
 
140
            if (!parent) {
 
141
                parent = Y.one(BODY);
 
142
            }
 
143
            
 
144
            if (!parent.test(EditorBidi.BLOCKS)) {
 
145
                parent = parent.ancestor(EditorBidi.BLOCKS);
 
146
            }
 
147
            if (wrap && parent.test(BODY)) {
 
148
                // This shouldn't happen if the RTE handles everything
 
149
                // according to spec: we should get to a P before BODY. But
 
150
                // we don't want to set the direction of BODY even if that
 
151
                // happens, so we wrap everything in a DIV.
 
152
                
 
153
                // The code is based on YUI3's Y.EditorSelection._wrapBlock function.
 
154
                divNode = Y.Node.create(EditorBidi.DIV_WRAPPER);
 
155
                parent.get('children').each(function(node, index) {
 
156
                    if (index === 0) {
 
157
                        firstChild = node;
 
158
                    } else {
 
159
                        divNode.append(node);
 
160
                    }
 
161
                });
 
162
                firstChild.replace(divNode);
 
163
                divNode.prepend(firstChild);
 
164
                parent = divNode;
 
165
            }
 
166
            return parent;
 
167
        },
 
168
        /**
 
169
        * The data key to store on the node.
 
170
        * @static
 
171
        * @property _NODE_SELECTED
 
172
        */
 
173
        _NODE_SELECTED: 'bidiSelected',
 
174
        /**
 
175
        * Generates a list of all the block parents of the current NodeList
 
176
        * @static
 
177
        * @method addParents
 
178
        */
 
179
        addParents: function(nodeArray) {
 
180
            var i, parent, addParent;
 
181
 
 
182
            for (i = 0; i < nodeArray.length; i += 1) {
 
183
                nodeArray[i].setData(EditorBidi._NODE_SELECTED, true);
 
184
            }
 
185
 
 
186
            // This works automagically, since new parents added get processed
 
187
            // later themselves. So if there's a node early in the process that
 
188
            // we haven't discovered some of its siblings yet, thus resulting in
 
189
            // its parent not added, the parent will be added later, since those
 
190
            // siblings will be added to the array and then get processed.
 
191
            for (i = 0; i < nodeArray.length; i += 1) {
 
192
                parent = nodeArray[i].get('parentNode');
 
193
 
 
194
                // Don't add the parent if the parent is the BODY element.
 
195
                // We don't want to change the direction of BODY. Also don't
 
196
                // do it if the parent is already in the list.
 
197
                if (!parent.test(BODY) && !parent.getData(EditorBidi._NODE_SELECTED)) {
 
198
                    addParent = true;
 
199
                    parent.get('children').some(function(sibling) {
 
200
                        if (!sibling.getData(EditorBidi._NODE_SELECTED)) {
 
201
                            addParent = false;
 
202
                            return true; // stop more processing
 
203
                        }
 
204
                    });
 
205
                    if (addParent) {
 
206
                        nodeArray.push(parent);
 
207
                        parent.setData(EditorBidi._NODE_SELECTED, true);
 
208
                    }
 
209
                }
 
210
            }   
 
211
 
 
212
            for (i = 0; i < nodeArray.length; i += 1) {
 
213
                nodeArray[i].clearData(EditorBidi._NODE_SELECTED);
 
214
            }
 
215
 
 
216
            return nodeArray;
 
217
        },
 
218
 
 
219
 
 
220
        /**
 
221
        * editorBidi
 
222
        * @static
 
223
        * @property NAME
 
224
        */
 
225
        NAME: 'editorBidi',
 
226
        /**
 
227
        * editorBidi
 
228
        * @static
 
229
        * @property NS
 
230
        */
 
231
        NS: 'editorBidi',
 
232
        ATTRS: {
 
233
            host: {
 
234
                value: false
 
235
            }
 
236
        },
 
237
        /**
 
238
        * Regex for testing/removing text-align style from an element
 
239
        * @static
 
240
        * @property RE_TEXT_ALIGN
 
241
        */
 
242
        RE_TEXT_ALIGN: /text-align:\s*\w*\s*;/,
 
243
        /**
 
244
        * Method to test a node's style attribute for text-align and removing it.
 
245
        * @static
 
246
        * @method removeTextAlign
 
247
        */
 
248
        removeTextAlign: function(n) {
 
249
            if (n) {
 
250
                if (n.getAttribute(STYLE).match(EditorBidi.RE_TEXT_ALIGN)) {
 
251
                    n.setAttribute(STYLE, n.getAttribute(STYLE).replace(EditorBidi.RE_TEXT_ALIGN, ''));
 
252
                }
 
253
                if (n.hasAttribute('align')) {
 
254
                    n.removeAttribute('align');
 
255
                }
 
256
            }
 
257
            return n;
 
258
        }
 
259
    });
 
260
    
 
261
    Y.namespace('Plugin');
 
262
    
 
263
    Y.Plugin.EditorBidi = EditorBidi;
 
264
 
 
265
    /**
 
266
     * bidi execCommand override for setting the text direction of a node.
 
267
     * This property is added to the `Y.Plugin.ExecCommands.COMMANDS`
 
268
     * collection.
 
269
     *
 
270
     * @for Plugin.ExecCommand
 
271
     * @property bidi
 
272
     */
 
273
    //TODO -- This should not add this command unless the plugin is added to the instance..
 
274
    Y.Plugin.ExecCommand.COMMANDS.bidi = function(cmd, direction) {
 
275
        var inst = this.getInstance(),
 
276
            sel = new inst.EditorSelection(),
 
277
            ns = this.get(HOST).get(HOST).editorBidi,
 
278
            returnValue, block,
 
279
            selected, selectedBlocks, dir;
 
280
 
 
281
        if (!ns) {
 
282
            Y.error('bidi execCommand is not available without the EditorBiDi plugin.');
 
283
            return;
 
284
        }
 
285
 
 
286
        inst.EditorSelection.filterBlocks();
 
287
 
 
288
        if (sel.isCollapsed) { // No selection
 
289
            block = EditorBidi.blockParent(sel.anchorNode);
 
290
            if (!block) {
 
291
                block = inst.one('body').one(inst.EditorSelection.BLOCKS);
 
292
            }
 
293
            //Remove text-align attribute if it exists
 
294
            block = EditorBidi.removeTextAlign(block);
 
295
            if (!direction) {
 
296
                //If no direction is set, auto-detect the proper setting to make it "toggle"
 
297
                dir = block.getAttribute(DIR);
 
298
                if (!dir || dir == 'ltr') {
 
299
                    direction = 'rtl';
 
300
                } else {
 
301
                    direction = 'ltr';
 
302
                }
 
303
            }
 
304
            block.setAttribute(DIR, direction);
 
305
            if (Y.UA.ie) {
 
306
                var b = block.all('br.yui-cursor');
 
307
                if (b.size() === 1 && block.get('childNodes').size() == 1) {
 
308
                    b.remove();
 
309
                }
 
310
            }
 
311
            returnValue = block;
 
312
        } else { // some text is selected
 
313
            selected = sel.getSelected();
 
314
            selectedBlocks = [];
 
315
            selected.each(function(node) {
 
316
                selectedBlocks.push(EditorBidi.blockParent(node));
 
317
            });
 
318
            selectedBlocks = inst.all(EditorBidi.addParents(selectedBlocks));
 
319
            selectedBlocks.each(function(n) {
 
320
                var d = direction;
 
321
                //Remove text-align attribute if it exists
 
322
                n = EditorBidi.removeTextAlign(n);
 
323
                if (!d) {
 
324
                    dir = n.getAttribute(DIR);
 
325
                    if (!dir || dir == 'ltr') {
 
326
                        d = 'rtl';
 
327
                    } else {
 
328
                        d = 'ltr';
 
329
                    }
 
330
                }
 
331
                n.setAttribute(DIR, d);
 
332
            });
 
333
            returnValue = selectedBlocks;
 
334
        }
 
335
        ns._checkForChange();
 
336
        return returnValue;
 
337
    };
 
338
 
 
339
 
 
340
 
 
341
 
 
342
}, '3.5.1' ,{skinnable:false, requires:['editor-base']});