source: Dev/trunk/src/client/dojox/widget/Portlet.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

  • Property svn:executable set to *
File size: 9.8 KB
Line 
1define([
2        "dojo/_base/declare",
3        "dojo/_base/kernel",
4        "dojo/_base/lang",
5        "dojo/_base/array",
6        "dojo/_base/event",
7        "dojo/_base/connect",
8        "dojo/dom-style",
9        "dojo/dom-class",
10        "dojo/dom-construct",
11        "dojo/fx",
12        "dijit/registry",
13        "dijit/TitlePane",
14        "dijit/_Container",
15        "./PortletSettings",
16        "./PortletDialogSettings"
17        ], function(declare, kernel, lang, array, event, connect, domStyle, domClass, domConstruct, fx, registry,
18                                TitlePane, _Container, PortletSettings, PortletDialogSettings){
19       
20        kernel.experimental("dojox.widget.Portlet");
21       
22        return declare("dojox.widget.Portlet", [TitlePane, _Container],{
23                // summary:
24                //              A container widget that is designed to be contained
25                //              in a dojox.layout.GridContainer. Child widgets can insert
26                //              an icon into the title bar of the Portlet, which when
27                //              clicked, executes the "toggle" method of the child widget.
28                //              A child widget must specify the attribute
29                //              "portletIconClass", and the optional class
30                //              "portletIconHoverClass", as well as the
31                //              "toggle" function.
32
33                // resizeChildren: Boolean
34                //              If true, when the Portlet is resized, any child widgets
35                //              with a 'resize' method have that method called.
36                resizeChildren: true,
37
38                // closable: Boolean
39                //              If true, a close button is placed in the title bar,
40                //              and the Portlet can be hidden. If false, the Portlet
41                //              cannot be closed.
42                closable: true,
43
44                // _parents: Array
45                //               An array of all the StackContainer widgets that this Portlet
46                //              is contained in.        These are used to determine if the portlet
47                //              is visible or not.
48                _parents: null,
49
50                // _size: Object
51                //              Cache of the previous size of the portlet, used to determine
52                //              if the size has changed and if the child widgets should be
53                //              resized.
54                _size: null,
55
56                // dragRestriction: Boolean
57                //              To remove the drag capability.
58                dragRestriction : false,
59
60                buildRendering: function(){
61                        this.inherited(arguments);
62
63                        // Hide the portlet until it is fully constructed.
64                        domStyle.set(this.domNode, "visibility", "hidden");
65                },
66
67                postCreate: function(){
68                        this.inherited(arguments);
69
70                        // Add the portlet classes
71                        domClass.add(this.domNode, "dojoxPortlet");
72                        domClass.remove(this.arrowNode, "dijitArrowNode");
73                        domClass.add(this.arrowNode, "dojoxPortletIcon dojoxArrowDown");
74                        domClass.add(this.titleBarNode, "dojoxPortletTitle");
75                        domClass.add(this.hideNode, "dojoxPortletContentOuter");
76
77                        // Choose the class to add depending on if the portlet is draggable or not.
78                        domClass.add(this.domNode, "dojoxPortlet-" + (!this.dragRestriction ? "movable" : "nonmovable"));
79
80                        var _this = this;
81                        if(this.resizeChildren){
82                                // If children should be resized        when the portlet size changes,
83                                // listen for items being dropped, when the window is resized,
84                                // or when another portlet's size changes.
85
86                                this.subscribe("/dnd/drop", function(){_this._updateSize();});
87
88                                this.subscribe("/Portlet/sizechange", function(widget){_this.onSizeChange(widget);});
89                                this.connect(window, "onresize", function(){_this._updateSize();});
90
91                                // Subscribe to all possible child-selection events that could affect this
92                                // portlet
93                                var doSelectSubscribe = lang.hitch(this, function(id, lastId){
94                                        var widget = registry.byId(id);
95                                        if(widget.selectChild){
96                                                var s = this.subscribe(id + "-selectChild", function(child){
97                                                        var n = _this.domNode.parentNode;
98
99                                                        while(n){
100                                                                if(n == child.domNode){
101
102                                                                        // Only fire this once, as the widget is now visible
103                                                                        // at least once, so child measurements should be accurate.
104                                                                        _this.unsubscribe(s);
105                                                                        _this._updateSize();
106                                                                        break;
107                                                                }
108                                                                n = n.parentNode;
109                                                        }
110                                                });
111
112                                                // Record the StackContainer and child widget that this portlet
113                                                // is in, so it can figure out whether or not it is visible.
114                                                // If it is not visible, it will not update it's size dynamically.
115                                                var child = registry.byId(lastId);
116                                                if(widget && child){
117                                                        _this._parents.push({parent: widget, child: child});
118                                                }
119                                        }
120                                });
121                                var lastId;
122                                this._parents = [];
123
124                                // Find all parent widgets, and if they are StackContainers,
125                                // subscribe to their selectChild method calls.
126                                for(var p = this.domNode.parentNode; p != null; p = p.parentNode){
127                                        var id = p.getAttribute ? p.getAttribute("widgetId") : null;
128                                        if(id){
129                                                doSelectSubscribe(id, lastId);
130                                                lastId = id;
131                                        }
132                                }
133                        }
134
135                        // Prevent clicks on icons from causing a drag to start.
136                        this.connect(this.titleBarNode, "onmousedown", function(evt){
137                                if (domClass.contains(evt.target, "dojoxPortletIcon")) {
138                                        event.stop(evt);
139                                        return false;
140                                }
141                                return true;
142                        });
143
144                        // Inform all portlets that the size of this one has changed,
145                        // and therefore perhaps they have too
146                        this.connect(this._wipeOut, "onEnd", function(){_this._publish();});
147                        this.connect(this._wipeIn, "onEnd", function(){_this._publish();});
148
149                        if(this.closable){
150                                this.closeIcon = this._createIcon("dojoxCloseNode", "dojoxCloseNodeHover", lang.hitch(this, "onClose"));
151                                domStyle.set(this.closeIcon, "display", "");
152                        }
153                },
154
155                startup: function(){
156                        if(this._started){return;}
157
158                        var children = this.getChildren();
159                        this._placeSettingsWidgets();
160
161                        // Start up the children
162                        array.forEach(children, function(child){
163                                try{
164                                        if(!child.started && !child._started){
165                                                child.startup()
166                                        }
167                                }
168                                catch(e){
169                                        console.log(this.id + ":" + this.declaredClass, e);
170                                }
171                        });
172
173                        this.inherited(arguments);
174
175                        //this._updateSize();
176                        domStyle.set(this.domNode, "visibility", "visible");
177                },
178
179                _placeSettingsWidgets: function(){
180                        // summary:
181                        //              Checks all the children to see if they are instances
182                        //              of dojox.widget.PortletSettings. If they are,
183                        //              create an icon for them in the title bar which when clicked,
184                        //              calls their toggle() method.
185
186                        array.forEach(this.getChildren(), lang.hitch(this, function(child){
187                                if(child.portletIconClass && child.toggle && !child.get("portlet")){
188                                        this._createIcon(child.portletIconClass, child.portletIconHoverClass, lang.hitch(child, "toggle"));
189                                        domConstruct.place(child.domNode, this.containerNode, "before");
190                                        child.set("portlet", this);
191                                        this._settingsWidget = child;
192                                }
193                        }));
194                },
195
196                _createIcon: function(clazz, hoverClazz, fn){
197                        // summary:
198                        //              creates an icon in the title bar.
199
200                        var icon = domConstruct.create("div",{
201                                "class": "dojoxPortletIcon " + clazz,
202                                "waiRole": "presentation"
203                        });
204                        domConstruct.place(icon, this.arrowNode, "before");
205
206                        this.connect(icon, "onclick", fn);
207
208                        if(hoverClazz){
209                                this.connect(icon, "onmouseover", function(){
210                                        domClass.add(icon, hoverClazz);
211                                });
212                                this.connect(icon, "onmouseout", function(){
213                                        domClass.remove(icon, hoverClazz);
214                                });
215                        }
216                        return icon;
217                },
218
219                onClose: function(evt){
220                        // summary:
221                        //              Hides the portlet. Note that it does not
222                        //              persist this, so it is up to the client to
223                        //              listen to this method and persist the closed state
224                        //              in their own way.
225                        domStyle.set(this.domNode, "display", "none");
226                },
227
228                onSizeChange: function(widget){
229                        // summary:
230                        //              Updates the Portlet size if any other Portlet
231                        //              changes its size.
232                        if(widget == this){
233                                return;
234                        }
235                        this._updateSize();
236                },
237
238                _updateSize: function(){
239                        // summary:
240                        //              Updates the size of all child widgets.
241                        if(!this.open || !this._started || !this.resizeChildren){
242                                return;
243                        }
244
245                        if(this._timer){
246                                clearTimeout(this._timer);
247                        }
248                        // Delay applying the size change in case the size
249                        // changes very frequently, for performance reasons.
250                        this._timer = setTimeout(lang.hitch(this, function(){
251                                var size ={
252                                        w: domStyle.get(this.domNode, "width"),
253                                        h: domStyle.get(this.domNode, "height")
254                                };
255
256                                // If the Portlet is in a StackWidget, and it is not
257                                // visible, do not update the size, as it could
258                                // make child widgets miscalculate.
259                                for(var i = 0; i < this._parents.length; i++){
260                                        var p = this._parents[i];
261                                        var sel = p.parent.selectedChildWidget
262                                        if(sel && sel != p.child){
263                                                return;
264                                        }
265                                }
266
267                                if(this._size){
268                                        // If the size of the portlet hasn't changed, don't
269                                        // resize the children, as this can be expensive
270                                        if(this._size.w == size.w && this._size.h == size.h){
271                                                return;
272                                        }
273                                }
274                                this._size = size;
275
276                                var fns = ["resize", "layout"];
277                                this._timer = null;
278                                var kids = this.getChildren();
279
280                                array.forEach(kids, function(child){
281                                        for(var i = 0; i < fns.length; i++){
282                                                if(lang.isFunction(child[fns[i]])){
283                                                        try{
284                                                                child[fns[i]]();
285                                                        } catch(e){
286                                                                console.log(e);
287                                                        }
288                                                        break;
289                                                }
290                                        }
291                                });
292                                this.onUpdateSize();
293                        }), 100);
294                },
295
296                onUpdateSize: function(){
297                        // summary:
298                        //              Stub function called when the size is changed.
299                },
300
301                _publish: function(){
302                        // summary:
303                        //              Publishes an event that all other portlets listen to.
304                        //              This causes them to update their child widgets if their
305                        //              size has changed.
306                        connect.publish("/Portlet/sizechange",[this]);
307                },
308
309                _onTitleClick: function(evt){
310                        if(evt.target == this.arrowNode){
311                                this.inherited(arguments);
312                        }
313                },
314
315                addChild: function(child){
316                        // summary:
317                        //              Adds a child widget to the portlet.
318                        this._size = null;
319                        this.inherited(arguments);
320
321                        if(this._started){
322                                this._placeSettingsWidgets();
323                                this._updateSize();
324                        }
325                        if(this._started && !child.started && !child._started){
326                                child.startup();
327                        }
328                },
329
330                destroyDescendants: function(/*Boolean*/ preserveDom){
331                        this.inherited(arguments);
332                        if(this._settingsWidget){
333                                this._settingsWidget.destroyRecursive(preserveDom);
334                        }
335                },
336
337                destroy: function(){
338                        if(this._timer){
339                                clearTimeout(this._timer);
340                        }
341                        this.inherited(arguments);
342                },
343
344                _setCss: function(){
345                        this.inherited(arguments);
346                        domStyle.set(this.arrowNode, "display", this.toggleable ? "":"none");
347                }
348        });
349});
Note: See TracBrowser for help on using the repository browser.