source: Dev/trunk/src/client/dojox/widget/_CalendarBase.js

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

Added Dojo 1.9.3 release.

File size: 10.9 KB
Line 
1define([
2        "dijit/_WidgetBase",
3        "dijit/_TemplatedMixin",
4        "dijit/_Container",
5        "dijit/_WidgetsInTemplateMixin",
6        "dijit/typematic",
7        "dojo/_base/declare",
8        "dojo/date",
9        "dojo/date/stamp",
10        "dojo/date/locale",
11        "dojo/dom-style",
12        "dojo/dom-class",
13        "dojo/_base/fx",
14        "dojo/on",
15        "dojo/_base/array",
16        "dojo/_base/lang",
17        "dojo/text!./Calendar/Calendar.html"
18], function(_WidgetBase, _TemplatedMixin, _Container, _WidgetsInTemplateMixin, dijitTypematic,
19                declare, dojoDate, stamp, dojoDateLocale, domStyle, domClass, fx, on, array, lang, template){
20        return declare("dojox.widget._CalendarBase", [_WidgetBase, _TemplatedMixin, _Container, _WidgetsInTemplateMixin], {
21                // summary:
22                //              The Root class for all _Calendar extensions
23
24                // templateString: String
25                //              The template to be used to construct the widget.
26                templateString: template,
27
28                // _views: Array
29                //              The list of mixin views available on this calendar.
30                _views: null,
31
32                // useFx: Boolean
33                //              Specifies if visual effects should be applied to the widget.
34                //              The default behavior of the widget does not contain any effects.
35                //              The dojox.widget.CalendarFx package is needed for these.
36                useFx: true,
37
38                // value: Date
39                //              The currently selected Date
40                value: new Date(),
41
42                constraints: null,
43
44                // footerFormat: String
45                //              The date format of the date displayed in the footer.    Can be
46                //              'short', 'medium', and 'long'
47                footerFormat: "medium",
48
49                constructor: function(){
50                        this._views = [];
51                        this.value = new Date();
52                },
53
54                _setConstraintsAttr: function(constraints){
55                        // summary:
56                        //              Sets minimum and maximum constraints
57                        var c = this.constraints = constraints;
58                        if(c){
59                                if(typeof c.min == "string"){
60                                        c.min = stamp.fromISOString(c.min);
61                                }
62                                if(typeof c.max == "string"){
63                                        c.max = stamp.fromISOString(c.max);
64                                }
65                        }
66                },
67
68                postMixInProperties: function () {
69                        this.inherited(arguments);
70                        this.value = this.parseInitialValue(this.value);
71                },
72
73                parseInitialValue: function(value){
74                        if (!value || value === -1){
75                                return new Date();
76                        }else if(value.getFullYear){
77                                return value;
78                        }else if (!isNaN(value)) {
79                                if (typeof this.value == "string") {
80                                        value = parseInt(value);
81                                }
82                                value = this._makeDate(value);
83                        }
84                        return value;
85                },
86
87                _makeDate: function(value){
88                        return value;//new Date(value);
89                },
90
91                postCreate: function(){
92                        // summary:
93                        //              Instantiates the mixin views
94
95                        this.displayMonth = new Date(this.get('value'));
96
97                        if(this._isInvalidDate(this.displayMonth)){
98                                this.displayMonth = new Date();
99                        }
100
101                        var mixin = {
102                                parent: this,
103                                _getValueAttr: lang.hitch(this, function(){return new Date(this._internalValue || this.value);}),
104                                _getDisplayMonthAttr: lang.hitch(this, function(){return new Date(this.displayMonth);}),
105                                _getConstraintsAttr: lang.hitch(this, function(){return this.constraints;}),
106                                getLang: lang.hitch(this, function(){return this.lang;}),
107                                isDisabledDate: lang.hitch(this, this.isDisabledDate),
108                                getClassForDate: lang.hitch(this, this.getClassForDate),
109                                addFx: this.useFx ? lang.hitch(this, this.addFx) : function(){}
110                        };
111
112                        //Add the mixed in views.
113                        array.forEach(this._views, function(widgetType){
114                                var widget = new widgetType(mixin).placeAt(this);
115
116                                var header = widget.getHeader();
117                                if(header){
118                                //place the views's header node in the header of the main widget
119                                        this.header.appendChild(header);
120
121                                        //hide the header node of the widget
122                                        domStyle.set(header, "display", "none");
123                                }
124                                //Hide all views
125                                domStyle.set(widget.domNode, "visibility", "hidden");
126
127                                //Listen for the values in a view to be selected
128                                widget.on("valueSelected", lang.hitch(this, "_onDateSelected"));
129                                widget.set("value", this.get('value'));
130                        }, this);
131
132                        if(this._views.length < 2){
133                                domStyle.set(this.header, "cursor", "auto");
134                        }
135
136                        this.inherited(arguments);
137
138                        // Cache the list of children widgets.
139                        this._children = this.getChildren();
140
141                        this._currentChild = 0;
142
143                        //Populate the footer with today's date.
144                        var today = new Date();
145
146                        this.footer.innerHTML = "Today: "
147                                + dojoDateLocale.format(today, {
148                                        formatLength:this.footerFormat,
149                                        selector:'date',
150                                        locale:this.lang});
151
152                        on(this.footer, "click", lang.hitch(this, "goToToday"));
153
154                        var first = this._children[0];
155
156                        domStyle.set(first.domNode, "top", "0px");
157                        domStyle.set(first.domNode, "visibility", "visible");
158
159                        var header = first.getHeader();
160                        if(header){
161                                domStyle.set(first.getHeader(), "display", "");
162                        }
163
164                        domClass.toggle(this.container, "no-header", !first.useHeader);
165
166                        first.onDisplay();
167
168                        var _this = this;
169
170                        var typematic = function(nodeProp, dateProp, adj){
171                                dijitTypematic.addMouseListener(_this[nodeProp], _this, function(count){
172                                        if(count >= 0){ _this._adjustDisplay(dateProp, adj);}
173                                }, 0.8, 500);
174                        };
175                        typematic("incrementMonth", "month", 1);
176                        typematic("decrementMonth", "month", -1);
177                        this._updateTitleStyle();
178                },
179
180                addFx: function(query, fromNode){
181                        // Stub function than can be overridden to add effects.
182                },
183
184                _isInvalidDate: function(/*Date*/ value){
185                        // summary:
186                        //              Runs various tests on the value, checking for invalid conditions
187                        // tags:
188                        //              private
189                        return !value || isNaN(value) || typeof value != "object" || value.toString() == this._invalidDate;
190                },
191
192                _setValueAttr: function(/*Date*/ value){
193                        // summary:
194                        //              Set the current date and update the UI. If the date is disabled, the selection will
195                        //              not change, but the display will change to the corresponding month.
196                        if(!value){
197                                value = new Date();
198                        }
199                        if(!value["getFullYear"]){
200                                value = stamp.fromISOString(value + "");
201                        }
202                        if(this._isInvalidDate(value)){
203                                return false;
204                        }
205                        if(!this.value || dojoDate.compare(value, this.value)){
206                                value = new Date(value);
207                                this.displayMonth = new Date(value);
208                                this._internalValue = value;
209                                if(!this.isDisabledDate(value, this.lang) && this._currentChild == 0){
210                                        this.value = value;
211                                        this.onChange(value);
212                                }
213                                if (this._children && this._children.length > 0) {
214                                        this._children[this._currentChild].set("value", this.value);
215                                }
216                                return true;
217                        }
218                        return false;
219                },
220
221                isDisabledDate: function(/*Date*/date, /*String?*/locale){
222                        // summary:
223                        //              May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend`
224                        var c = this.constraints;
225                        var compare = dojoDate.compare;
226                        return c && (c.min && (compare(c.min, date, "date") > 0) ||
227                                                                (c.max && compare(c.max, date, "date") < 0));
228                },
229
230                onValueSelected: function(/*Date*/date){
231                        // summary:
232                        //              A date cell was selected. It may be the same as the previous value.
233                },
234
235                _onDateSelected: function(date, formattedValue, force){
236                        this.displayMonth = date;
237
238                        this.set("value", date);
239                        //Only change the selected value if it was chosen from the
240                        //first child.
241                        if(!this._transitionVert(-1)){
242                                if(!formattedValue && formattedValue !== 0){
243                                        formattedValue = this.get('value');
244                                }
245                                this.onValueSelected(formattedValue);
246                        }
247
248                },
249
250                onChange: function(/*Date*/date){
251                        // summary:
252                        //              Called only when the selected date has changed
253                },
254
255                onHeaderClick: function(e){
256                        // summary:
257                        //              Transitions to the next view.
258                        this._transitionVert(1);
259                },
260
261                goToToday: function(){
262                        this.set("value", new Date());
263                        this.onValueSelected(this.get('value'));
264                },
265
266                _transitionVert: function(/*Number*/direction){
267                        // summary:
268                        //              Animates the views to show one and hide another, in a
269                        //              vertical direction.
270                        //              If 'direction' is 1, then the views slide upwards.
271                        //              If 'direction' is -1, the views slide downwards.
272                        var curWidget = this._children[this._currentChild];
273                        var nextWidget = this._children[this._currentChild + direction];
274                        if(!nextWidget){return false;}
275
276                        domStyle.set(nextWidget.domNode, "visibility", "visible");
277
278                        var height = domStyle.get(this.containerNode, "height");
279                        nextWidget.set("value", this.displayMonth);
280
281                        if(curWidget.header){
282                                domStyle.set(curWidget.header, "display", "none");
283                        }
284                        if(nextWidget.header){
285                                domStyle.set(nextWidget.header, "display", "");
286                        }
287                        domStyle.set(nextWidget.domNode, "top", (height * -1) + "px");
288                        domStyle.set(nextWidget.domNode, "visibility", "visible");
289
290                        this._currentChild += direction;
291
292                        var height1 = height * direction;
293                        var height2 = 0;
294                        domStyle.set(nextWidget.domNode, "top", (height1 * -1) + "px");
295
296                        // summary:
297                        //              Slides two nodes vertically.
298                        var anim1 = fx.animateProperty({
299                                node: curWidget.domNode,
300                                properties: {top: height1},
301                                onEnd: function(){
302                                        domStyle.set(curWidget.domNode, "visibility", "hidden");
303                                }
304                        });
305                        var anim2 = fx.animateProperty({
306                                node: nextWidget.domNode,
307                                properties: {top: height2},
308                                onEnd: function(){
309                                        nextWidget.onDisplay();
310                                }
311                        });
312
313                        domClass.toggle(this.container, "no-header", !nextWidget.useHeader);
314
315                        anim1.play();
316                        anim2.play();
317                        curWidget.onBeforeUnDisplay();
318                        nextWidget.onBeforeDisplay();
319
320                        this._updateTitleStyle();
321                        return true;
322                },
323
324                _updateTitleStyle: function(){
325                        domClass.toggle(this.header, "navToPanel", this._currentChild < this._children.length -1);
326                },
327
328                _slideTable: function(/*String*/widget, /*Number*/direction, /*Function*/callback){
329                        // summary:
330                        //              Animates the horizontal sliding of a table.
331                        var table = widget.domNode;
332
333                        //Clone the existing table
334                        var newTable = table.cloneNode(true);
335                        var left = domStyle.get(table, "width");
336
337                        table.parentNode.appendChild(newTable);
338
339                        //Place the existing node either to the left or the right of the new node,
340                        //depending on which direction it is to slide.
341                        domStyle.set(table, "left", (left * direction) + "px");
342
343                        //Call the function that generally populates the new cloned node with new data.
344                        //It may also attach event listeners.
345                        callback();
346
347                        //Animate the two nodes.
348                        var anim1 = fx.animateProperty({node: newTable, properties:{left: left * direction * -1}, duration: 500, onEnd: function(){
349                                newTable.parentNode.removeChild(newTable);
350                        }});
351                        var anim2 = fx.animateProperty({node: table, properties:{left: 0}, duration: 500});
352
353                        anim1.play();
354                        anim2.play();
355                },
356
357                _addView: function(view){
358                        //Insert the view at the start of the array.
359                        this._views.push(view);
360                },
361
362                getClassForDate: function(/*Date*/dateObject, /*String?*/locale){
363                        // summary:
364                        //              May be overridden to return CSS classes to associate with the date entry for the given dateObject,
365                        //              for example to indicate a holiday in specified locale.
366
367        /*=====
368                        return ""; // String
369        =====*/
370                },
371
372                _adjustDisplay: function(/*String*/part, /*int*/amount, noSlide){
373                        // summary:
374                        //              This function overrides the base function defined in dijit/Calendar.
375                        //              It changes the displayed years, months and days depending on the inputs.
376                        var child = this._children[this._currentChild];
377
378                        var month = this.displayMonth = child.adjustDate(this.displayMonth, amount);
379
380                        this._slideTable(child, amount, function(){
381                                child.set("value", month);
382                        });
383                }
384        });
385});
Note: See TracBrowser for help on using the repository browser.