source: Dev/branches/rest-dojo-ui/client/dojox/widget/Portlet.js @ 274

Last change on this file since 274 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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