MDL-64506 templates: Move BS2 labels to BS4 badges
[moodle.git] / lib / yui / src / dock / js / block.js
1 /* global BLOCK, LOGNS, DOCKEDITEM */
3 /**
4  * Dock JS.
5  *
6  * This file contains the block class used to manage blocks (both docked and not) for the dock.
7  *
8  * @module moodle-core-dock
9  */
11 /**
12  * Block.
13  *
14  * @namespace M.core.dock
15  * @class Block
16  * @constructor
17  * @extends Base
18  */
19 BLOCK = function() {
20     BLOCK.superclass.constructor.apply(this, arguments);
21 };
22 BLOCK.prototype = {
23     /**
24      * A content place holder used when the block has been docked.
25      * @property contentplaceholder
26      * @protected
27      * @type Node
28      */
29     contentplaceholder: null,
30     /**
31      * The skip link associated with this block.
32      * @property contentskipanchor
33      * @protected
34      * @type Node
35      */
36     contentskipanchor: null,
37     /**
38      * The cached content node for the actual block
39      * @property cachedcontentnode
40      * @protected
41      * @type Node
42      */
43     cachedcontentnode: null,
44     /**
45      * If true the user preference isn't updated
46      * @property skipsetposition
47      * @protected
48      * @type Boolean
49      */
50     skipsetposition: true,
51     /**
52      * The dock item associated with this block
53      * @property dockitem
54      * @protected
55      * @type DOCKEDITEM
56      */
57     dockitem: null,
58     /**
59      * Called during the initialisation process of the object.
60      * @method initializer
61      */
62     initializer: function() {
63         var node = Y.one('#inst' + this.get('id'));
64         if (!node) {
65             return false;
66         }
68         Y.log('Initialised block with instance id:' + this.get('id'), 'debug', LOGNS);
70         M.core.dock.ensureMoveToIconExists(node);
72         // Move the block straight to the dock if required
73         if (node.hasClass(CSS.dockonload)) {
74             node.removeClass(CSS.dockonload);
75             this.moveToDock();
76         }
77         this.skipsetposition = false;
78         return true;
79     },
80     /**
81      * Returns the class associated with this block.
82      * @method _getBlockClass
83      * @private
84      * @param {Node} node
85      * @return String
86      */
87     _getBlockClass: function(node) {
88         var block = node.getData('block'),
89             classes,
90             matches;
91         if (Y.Lang.isString(block) && block !== '') {
92             return block;
93         }
94         classes = node.getAttribute('className').toString();
95         matches = /(^| )block_([^ ]+)/.exec(classes);
96         if (matches) {
97             return matches[2];
98         }
99         return matches;
100     },
102     /**
103      * This function is responsible for moving a block from the page structure onto the dock.
104      * @method moveToDock
105      * @param {EventFacade} e
106      */
107     moveToDock: function(e) {
108         if (e) {
109             e.halt(true);
110         }
112         var dock = M.core.dock.get(),
113             id = this.get('id'),
114             blockcontent = Y.one('#inst' + id).one('.content'),
115             icon = (window.right_to_left()) ? 't/dock_to_block_rtl' : 't/dock_to_block',
116             breakchar = (location.href.match(/\?/)) ? '&' : '?',
117             blocktitle,
118             blockcommands,
119             movetoimg,
120             moveto;
122         if (!blockcontent) {
123             return;
124         }
126         Y.log('Moving block to the dock:' + this.get('id'), 'debug', LOGNS);
128         this.recordBlockState();
130         blocktitle = this.cachedcontentnode.one('.title h2').cloneNode(true);
132         // Build up the block commands.
133         // These should not actually added to the DOM.
134         blockcommands = this.cachedcontentnode.one('.title .commands');
135         if (blockcommands) {
136             blockcommands = blockcommands.cloneNode(true);
137         } else {
138             blockcommands = Y.Node.create('<div class="commands"></div>');
139         }
140         movetoimg = Y.Node.create('<img />').setAttrs({
141             alt: Y.Escape.html(M.util.get_string('undockitem', 'block')),
142             title: Y.Escape.html(M.util.get_string('undockblock', 'block', blocktitle.get('innerHTML'))),
143             src: M.util.image_url(icon, 'moodle')
144         });
145         moveto = Y.Node.create('<a class="moveto customcommand requiresjs"></a>').setAttrs({
146             href: Y.config.win.location.href + breakchar + 'dock=' + id
147         });
148         moveto.append(movetoimg);
149         blockcommands.append(moveto.append(movetoimg));
151         // Create a new dock item for the block
152         this.dockitem = new DOCKEDITEM({
153             block: this,
154             dock: dock,
155             blockinstanceid: id,
156             title: blocktitle,
157             contents: blockcontent,
158             commands: blockcommands,
159             blockclass: this._getBlockClass(Y.one('#inst' + id))
160         });
161         // Register an event so that when it is removed we can put it back as a block
162         dock.add(this.dockitem);
164         if (!this.skipsetposition) {
165             // save the users preference
166             M.util.set_user_preference('docked_block_instance_' + id, 1);
167         }
169         this.set('isDocked', true);
170     },
171     /**
172      * Records the block state and adds it to the docks holding area.
173      * @method recordBlockState
174      */
175     recordBlockState: function() {
176         var id = this.get('id'),
177             dock = M.core.dock.get(),
178             node = Y.one('#inst' + id),
179             skipanchor = node.previous();
180         // Disable the skip anchor when docking
181         if (skipanchor.hasClass('skip-block')) {
182             this.contentskipanchor = skipanchor;
183             this.contentskipanchor.hide();
184         }
185         this.cachedcontentnode = node;
186         this.contentplaceholder = Y.Node.create('<div class="block_dock_placeholder"></div>');
187         node.replace(this.contentplaceholder);
188         dock.addToHoldingArea(node);
189         node = null;
190     },
192     /**
193      * This function removes a block from the dock and puts it back into the page structure.
194      * @method returnToPage
195      * @return {Boolean}
196      */
197     returnToPage: function() {
198         var id = this.get('id');
200         Y.log('Moving block out of the dock:' + this.get('id'), 'debug', LOGNS);
202         // Enable the skip anchor when going back to block mode
203         if (this.contentskipanchor) {
204             this.contentskipanchor.show();
205         }
207         if (this.cachedcontentnode.one('.header')) {
208             this.cachedcontentnode.one('.header').insert(this.dockitem.get('contents'), 'after');
209         } else {
210             this.cachedcontentnode.insert(this.dockitem.get('contents'));
211         }
213         this.contentplaceholder.replace(this.cachedcontentnode);
214         this.cachedcontentnode = null;
216         M.util.set_user_preference('docked_block_instance_' + id, 0);
217         this.set('isDocked', false);
218         return true;
219     }
220 };
221 Y.extend(BLOCK, Y.Base, BLOCK.prototype, {
222     NAME: 'moodle-core-dock-block',
223     ATTRS: {
224         /**
225          * The block instance ID
226          * @attribute id
227          * @writeOnce
228          * @type Number
229          */
230         id: {
231             writeOnce: 'initOnly',
232             setter: function(value) {
233                 return parseInt(value, 10);
234             }
235         },
236         /**
237          * True if the block has been docked.
238          * @attribute isDocked
239          * @default false
240          * @type Boolean
241          */
242         isDocked: {
243             value: false
244         }
245     }
246 });