rsence 2.1.10 → 2.1.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -48,7 +48,7 @@ Event = {
48
48
  **/
49
49
  isLeftClick: function(e) {
50
50
  // IE: left 1, middle 4, right 2
51
- if (BROWSER_TYPE.ie) {
51
+ if (BROWSER_TYPE.ie && !BROWSER_TYPE.ie9) {
52
52
  return (e.button === 1 || e.button === 3 || e.button === 5);
53
53
  }
54
54
  else {
@@ -147,7 +147,7 @@ Event = {
147
147
 
148
148
  // Activates the garbage collector of Internet Explorer
149
149
  // when the document is unloaded:
150
- if (BROWSER_TYPE.ie) {
150
+ if (BROWSER_TYPE.ie && !BROWSER_TYPE.ie9) {
151
151
  Event.observe(window, "unload", Event.unloadCache, false);
152
152
  }
153
153
 
@@ -0,0 +1,292 @@
1
+ /* RSence
2
+ * Copyright 2009 Riassence Inc.
3
+ * http://riassence.com/
4
+ *
5
+ * You should have received a copy of the GNU General Public License along
6
+ * with this software package. If not, contact licensing@riassence.com
7
+ */
8
+
9
+ /*** = Description
10
+ ** HTimesheet is a simple timesheet control.
11
+ ***/
12
+ var//RSence.DateTime
13
+ HTimeSheet = HControl.extend({
14
+
15
+ componentName: 'timesheet',
16
+
17
+ /* Default amount of pixels per hour. Override with options when necessary. */
18
+ pxPerHour: 24,
19
+
20
+ /* Default amount of pixels from left. Override with options when necessary. */
21
+ itemOffsetLeft: 36,
22
+
23
+ /* Default amount of pixels from right. Override with options when necessary. */
24
+ itemOffsetRight: 0,
25
+
26
+ defaultEvents: {
27
+ draggable: true
28
+ },
29
+
30
+ controlDefaults: HControlDefaults.extend({
31
+ pxPerHour: null,
32
+ itemOffsetLeft: null,
33
+ itemOffsetRight: null,
34
+ itemMinHeight: 24,
35
+ newItemLabel: 'New Item',
36
+ constructor: function(_ctrl){
37
+ if(this.pxPerHour !== null){
38
+ _ctrl.pxPerHour = this.pxPerHour;
39
+ }
40
+ if(this.itemOffsetLeft !== null){
41
+ _ctrl.itemOffsetLeft = this.itemOffsetLeft;
42
+ }
43
+ if(this.itemOffsetRight !== null){
44
+ _ctrl.itemOffsetRight = this.itemOffsetRight;
45
+ }
46
+ }
47
+ }),
48
+
49
+ /** = Description
50
+ * Redraws the timesheet.
51
+ *
52
+ **/
53
+ refresh: function(){
54
+ if(this.drawn){
55
+ var _areaHeight = this.rect.height;
56
+ this.pxPerHour = (_areaHeight-(_areaHeight%48)) / 24;
57
+ if(this.options['hideLabel']){
58
+ this.setStyleOfPart( 'label', 'display', 'none' );
59
+ this.setStyleOfPart( 'state', 'left', '0px' );
60
+ this.itemOffsetLeft = 0;
61
+ }
62
+ else{
63
+ this.setStyleOfPart( 'label', 'height', (this.pxPerHour*24)+'px' );
64
+ }
65
+ this.setStyleOfPart( 'state', 'height', (this.pxPerHour*24)+'px' );
66
+ }
67
+ this.base();
68
+ },
69
+
70
+ /** = Description
71
+ * Refreshes the hour labels.
72
+ *
73
+ **/
74
+ refreshLabel: function(){
75
+ var hour = 1,
76
+ hours = [],
77
+ rowHeight = this.pxPerHour;
78
+ lineHeight = Math.round(this.pxPerHour/2);
79
+ for(; hour < 24; hour++){
80
+ hours.push('<div style="line-height:'+rowHeight+'px;height:'+rowHeight+'px;top:'+Math.round((hour*rowHeight)-lineHeight)+'px" class="timesheet_hours_row">'+hour+':00</div>');
81
+ }
82
+ this.markupElemIds && this.markupElemIds.label && ELEM.setHTML(this.markupElemIds.label,hours.join(''));
83
+ this.refreshState();
84
+ },
85
+
86
+ /** = Description
87
+ * Refreshes the lines which mark hours and half-hours.
88
+ *
89
+ **/
90
+ refreshState: function(){
91
+ var line = 0,
92
+ lines = [],
93
+ lineHeight = Math.round(this.pxPerHour/2);
94
+ for(; line < 48; line++){
95
+ lines.push('<div style="top:'+(line*lineHeight)+'px" class="timesheet_lines_row'+(line%2)+'"></div>');
96
+ }
97
+ this.markupElemIds && this.markupElemIds.label && ELEM.setHTML(this.markupElemIds.state,lines.join(''));
98
+ },
99
+ dragItem: false,
100
+
101
+ /** = Description
102
+ * Creates an item into timesheet with default label 'New Item'.
103
+ *
104
+ * = Parameters
105
+ * +origY+:: Y coordinate of the new item.
106
+ *
107
+ **/
108
+ createItem: function(origY){
109
+ var _lineHeight = Math.round(this.pxPerHour/2);
110
+ origY = Math.floor( origY / _lineHeight )*_lineHeight;
111
+ var maxY = _lineHeight*48,
112
+ lineHeight = Math.round(this.pxPerHour/2);
113
+ if(origY>maxY){
114
+ origY = maxY;
115
+ }
116
+ this.dragItem = this.createTimeSheetItem( { label: this.options.newItemLabel }, origY, lineHeight, 'create' );
117
+ },
118
+
119
+ /** = Description
120
+ * Dragging is used to mark items on the timesheet.
121
+ *
122
+ * = Parameters
123
+ * +x+:: x coordinate of the origin of drag
124
+ * +y+:: y coordinate of the origin of drag
125
+ *
126
+ **/
127
+ startDrag: function(x,y){
128
+ this._startDragTime = new Date().getTime();
129
+ this._startDragCoords = [x,y];
130
+ return true;
131
+ },
132
+
133
+ drag: function(x,y){
134
+ if(((new Date().getTime()) - this._startDragTime) < 200){
135
+ // only create when 200 ms has elapsed to enable clicking
136
+ return true;
137
+ }
138
+ if(this._startDragCoords[0]!==x && this._startDragCoords[1]!==y){
139
+ this.createItem(this._startDragCoords[1]-this.pageY());
140
+ EVENT.startDragging( this.dragItem );
141
+ return true;
142
+ }
143
+ },
144
+
145
+ click: function(x,y){
146
+ // deactivate all items
147
+ EVENT.changeActiveControl(this);
148
+ return true;
149
+ },
150
+
151
+ listItemViews: false,
152
+
153
+ /** = Description
154
+ * Sets the editor given as parameter as the editor of instance.
155
+ *
156
+ * = Parameters
157
+ * +_editor+::
158
+ *
159
+ **/
160
+ setEditor: function( _editor ){
161
+ this.editor = _editor;
162
+ },
163
+
164
+ /** = Description
165
+ * Returns HRect the size of given parameters and suitable for timesheet.
166
+ *
167
+ * = Parameters
168
+ * +_origY+:: Y coordinate.
169
+ * +_lineHeight+:: The height of item on time sheet.
170
+ *
171
+ **/
172
+ createItemRect: function(_origY, _lineHeight){
173
+ var _left = this.itemOffsetLeft+1,
174
+ _top = _origY+1,
175
+ _right = this.rect.width - this.itemOffsetRight - 1,
176
+ _bottom = _origY + _lineHeight - 2;
177
+ if( (_top - _bottom) < this.options.itemMinHeight ){
178
+ _bottom = _top + this.options.itemMinHeight;
179
+ }
180
+ return HRect.nu( _left, _top, _right, _bottom );
181
+ },
182
+
183
+ /** = Description
184
+ * Destructor; destroys the editor first and commences inherited die.
185
+ *
186
+ **/
187
+ die: function(){
188
+ this.editor.die();
189
+ this.base();
190
+ },
191
+
192
+ /** = Description
193
+ * Returns a new time sheet item control. By default returns an instance
194
+ * of HTimeSheetItem. Extend to use custom time sheet controls customized
195
+ * for application specific purposes.
196
+ *
197
+ * = Parameters
198
+ * *_value*:: A value object for the item.
199
+ * *_top*:: Top position, 0 by default.
200
+ * *_height*:: Height, same as half of +#pxPerHour+ by default.
201
+ * *_drogMode*:: Dragging mode. 'normal' or 'create'. Is 'normal' by default.
202
+ *
203
+ **/
204
+ createTimeSheetItem: function( _value, _top, _height, _dragMode ) {
205
+ if(_dragMode===undefined){
206
+ _dragMode = 'normal';
207
+ }
208
+ if(_top===undefined){
209
+ _top = 0;
210
+ }
211
+ if(_height===undefined){
212
+ _height = Math.round(this.pxPerHour/2);
213
+ }
214
+ var
215
+ _label = _value['label'],
216
+ _item = HTimeSheetItem.nu(
217
+ this.createItemRect( _top, _height ),
218
+ this, {
219
+ label: _label,
220
+ value: _value,
221
+ events: {
222
+ draggable: true
223
+ }
224
+ }
225
+ );
226
+ _item.dragMode = _dragMode;
227
+ return _item;
228
+ },
229
+
230
+ /** = Description
231
+ * Redraws and refreshes the values on timesheet.
232
+ *
233
+ **/
234
+ refreshValue: function(){
235
+ var
236
+ _data = this.value,
237
+ i;
238
+ if(this.listItemViews === false){
239
+ this.listItemViews = [];
240
+ }
241
+ else if(this.listItemViews.length > 0){
242
+ for( i=0; i<this.listItemViews.length; i++){
243
+ this.listItemViews[i].die();
244
+ }
245
+ this.listItemViews = [];
246
+ }
247
+ if(_data instanceof Array && _data.length > 0){
248
+ var
249
+ _value,
250
+ _item;
251
+ for( i=0; i<_data.length; i++){
252
+ _value = _data[i];
253
+ _item = this.createTimeSheetItem( _value );
254
+ this.listItemViews.push( _item );
255
+ }
256
+ }
257
+ var
258
+ _overlaps = [],
259
+ j;
260
+ for(i=0;i<this.listItemViews.length;i++){
261
+ for(j=0;j<this.listItemViews.length;j++){
262
+ if((i !== j) && (_overlaps.indexOf(i)===-1) && (_overlaps.indexOf(j)===-1)){
263
+ if(this.listItemViews[i].rect.intersects(this.listItemViews[j].rect)){
264
+ _overlaps.push(i);
265
+ }
266
+ }
267
+ }
268
+ }
269
+ var
270
+ _overlapCount = _overlaps.length+1,
271
+ _overlapLefts = {},
272
+ _itemWidth = ( this.rect.width - this.itemOffsetRight - this.itemOffsetLeft ),
273
+ _width = Math.floor( _itemWidth / _overlapCount),
274
+ _left = this.itemOffsetLeft;
275
+ for(j=0;j<_overlapCount;j++){
276
+ _overlapLefts[_overlaps[j]] = _left + (j*_width) + _width;
277
+ }
278
+ for(i=0;i<this.listItemViews.length;i++){
279
+ if(_overlaps.indexOf(i)===-1){
280
+ this.listItemViews[i].rect.setLeft(_left);
281
+ }
282
+ else {
283
+ this.listItemViews[i].rect.setLeft(_overlapLefts[i]);
284
+ }
285
+ this.listItemViews[i].rect.setWidth(_width);
286
+ }
287
+ for(i=0;i<this.listItemViews.length;i++){
288
+ this.listItemViews[i].drawRect();
289
+ }
290
+ }
291
+ });
292
+
@@ -0,0 +1,30 @@
1
+ .timesheet_hours_col {
2
+ position: absolute;
3
+ top: 0px; left: 0px; width: 32px;
4
+ font-family: Arial, sans-serif;
5
+ font-size: 11px;
6
+ color: #666;
7
+ vertical-align: middle;
8
+ text-align: right;
9
+ }
10
+ .timesheet_hours_row {
11
+ position: absolute;
12
+ left: 0px; width: 32px;
13
+ }
14
+ .timesheet_lines_col {
15
+ position: absolute;
16
+ top: 0px; left: 36px; right: 0px;
17
+ border-left: 1px solid #aaa;
18
+ border-bottom: 1px solid #aaa;
19
+ border-right: 1px solid #aaa;
20
+ }
21
+ .timesheet_lines_row0,
22
+ .timesheet_lines_row1 {
23
+ position: absolute;
24
+ left: 0px; right: 0px; height: 1px;
25
+ line-height: 1px; font-size: 0px;
26
+ background-color: #ccc;
27
+ }
28
+ .timesheet_lines_row0 {
29
+ background-color: #aaa;
30
+ }
@@ -0,0 +1,2 @@
1
+ <div class="timesheet_hours_col" id="label#{_ID}"></div>
2
+ <div class="timesheet_lines_col" id="state#{_ID}"></div>
@@ -0,0 +1,308 @@
1
+ /* RSence
2
+ * Copyright 2009 Riassence Inc.
3
+ * http://riassence.com/
4
+ *
5
+ * You should have received a copy of the GNU General Public License along
6
+ * with this software package. If not, contact licensing@riassence.com
7
+ */
8
+
9
+ /*** = Description
10
+ ** Item class to be used with HTimeSheet.
11
+ ***/
12
+ var//RSence.DateTime
13
+ HTimeSheetItem = HControl.extend({
14
+
15
+ componentName: 'timesheet_item',
16
+
17
+ /* Which mode the component is in. When created by dragging, acts in 'create' mode, otherwise is 'normal'. Can be overridden in options. */
18
+ dragMode: 'create',
19
+
20
+ /* The previous coordinate. Used to detect double-drag as double-click */
21
+ prevXY: [0,0],
22
+
23
+ /* The time at the previous coordinate. Used to detect double-drag as double-click. */
24
+ prevXYTime: 0,
25
+
26
+ defaultEvents: {
27
+ draggable: true,
28
+ click: true,
29
+ doubleClick: true
30
+ },
31
+
32
+ controlDefaults: HControlDefaults.extend({
33
+ dragMode: 'create',
34
+ constructor: function(_ctrl){
35
+ _ctrl.dragMode = this.dragMode;
36
+ }
37
+ }),
38
+
39
+ /** = Description
40
+ * Dragging is used to change coordinates.
41
+ *
42
+ * = Parameters
43
+ * +x+:: X coordinate at the start of drag.
44
+ * +y+:: Y coordinate at the start of drag.
45
+ *
46
+ **/
47
+ startDrag: function(x,y){
48
+ this.origY = y-this.parent.pageY();
49
+ if(this.dragMode === 'normal'){
50
+ var _timeNow = new Date().getTime(),
51
+ _xEquals = (Math.round(this.prevXY[0]/4) === Math.round(x/4)),
52
+ _yEquals = (Math.round(this.prevXY[1]/4) === Math.round(y/4)),
53
+ _noTimeout = ((_timeNow - this.prevXYTime) < 500);
54
+ if( _xEquals && _yEquals && _noTimeout ) { // doubleClick
55
+ return true;
56
+ }
57
+ else {
58
+ var _diffTop = this.rect.top - this.origY,
59
+ _diffBottom = this.rect.bottom - this.origY;
60
+ if(0 >= _diffTop && _diffTop >= -3){
61
+ this.dragMode = 'resize-top';
62
+ }
63
+ else if(0 <= _diffBottom && _diffBottom <= 4){
64
+ this.dragMode = 'resize-bottom';
65
+ }
66
+ else {
67
+ this.dragMode = 'move';
68
+ this.moveDiff = this.origY - this.rect.top;
69
+ }
70
+ this.bringToFront();
71
+ }
72
+ }
73
+ this.prevXY = [x,y];
74
+ this.prevXYTime = _timeNow;
75
+ return true;
76
+ },
77
+
78
+ doubleClick: function(x,y){
79
+ if( this.parent['editor'] ){
80
+ var _editor = this.parent.editor;
81
+ _editor.setTimeSheetItem(this);
82
+ _editor.bringToFront();
83
+ _editor.show();
84
+ return true;
85
+ }
86
+ return false;
87
+ },
88
+
89
+ /** = Description
90
+ * Label setter function.
91
+ *
92
+ * = Parameters
93
+ * +_label+:: New label
94
+ *
95
+ **/
96
+ setTimeSheetItemLabel: function(_label){
97
+ this.label = _label;
98
+ this.refreshLabel();
99
+ },
100
+
101
+ /** = Description
102
+ * Function used to calculate the right size for a new
103
+ * item created by dragging.
104
+ *
105
+ * = Parameters
106
+ * +_y+:: Y coordinate at the start of drag.
107
+ *
108
+ **/
109
+ dragCreate: function(_y){
110
+ var _negative = (_y < this.origY),
111
+ _lineHeight = Math.floor(this.parent.pxPerHour/2),
112
+ _top, _bottom, _diff;
113
+ if(_negative){
114
+ var _floorY = Math.floor(_y/_lineHeight)*_lineHeight,
115
+ _ceilYo = Math.ceil(this.origY/_lineHeight)*_lineHeight;
116
+ if(_floorY<0){_floorY=0;}
117
+ _diff = _floorY-_ceilYo;
118
+ if( _diff <= 0-_lineHeight ){
119
+ _top = _floorY;
120
+ _bottom = _ceilYo;
121
+ }
122
+ else if( _diff === 0 ){
123
+ _top = _floorY-_lineHeight;
124
+ _bottom = _ceilYo;
125
+ }
126
+ }
127
+ else {
128
+ var _ceilY = Math.ceil(_y/_lineHeight)*_lineHeight,
129
+ _floorYo = Math.floor(this.origY/_lineHeight)*_lineHeight;
130
+ if(_ceilY>(_lineHeight*48)){_ceilY=_lineHeight*48;}
131
+ _diff = _ceilY-_floorYo;
132
+ if( _diff >= _lineHeight ){
133
+ _top = _floorYo;
134
+ _bottom = _ceilY;
135
+ }
136
+ else if( _diff === 0 ){
137
+ _top = _floorYo;
138
+ _bottom = _ceilY+_lineHeight;
139
+ }
140
+ }
141
+ this.rect.setTop(_top);
142
+ this.rect.setBottom(_bottom);
143
+ },
144
+
145
+ /** = Description
146
+ * Resize top by dragging auxiliary function.
147
+ *
148
+ * = Parameters
149
+ * +_y+:: Y coordinate at the start of drag.
150
+ **/
151
+ dragResizeTop: function(_y){
152
+ var _lineHeight = Math.floor(this.parent.pxPerHour/2),
153
+ _top = Math.floor( _y/_lineHeight )*_lineHeight;
154
+ if(_top < 0){ _top = 0; }
155
+ if(_top+_lineHeight > this.rect.bottom){
156
+ _top = this.rect.bottom - _lineHeight;
157
+ }
158
+ this.rect.setTop( _top );
159
+ },
160
+
161
+ /** = Description
162
+ * Resize function for resizing the bottom of item.
163
+ *
164
+ * = Parameters
165
+ * +_y+:: Y coordinate at the start of drag.
166
+ *
167
+ **/
168
+ dragResizeBottom: function(_y){
169
+ var _lineHeight = Math.floor(this.parent.pxPerHour/2),
170
+ _bottom = Math.floor( _y/_lineHeight )*_lineHeight;
171
+ if(_bottom > _lineHeight*48){ _bottom = _lineHeight*48; }
172
+ if(_bottom-_lineHeight < this.rect.top){
173
+ _bottom = this.rect.top + _lineHeight;
174
+ }
175
+ this.rect.setBottom( _bottom );
176
+ },
177
+
178
+ /** = Description
179
+ * Move function for item by dragging and dropping.
180
+ *
181
+ * = Parameters
182
+ * +_y+:: Y coordinate at the start of drag.
183
+ *
184
+ **/
185
+ dragMove: function(_y){
186
+ var _lineHeight = Math.floor(this.parent.pxPerHour/2),
187
+ _top = Math.floor( (0-this.moveDiff+_y)/_lineHeight )*_lineHeight;
188
+ if(_top<0){_top = 0;}
189
+ if(_top+this.rect.height>_lineHeight*48){
190
+ _top = _lineHeight*48 - this.rect.height;
191
+ }
192
+ this.rect.offsetTo( this.rect.left, _top );
193
+ },
194
+
195
+ /** = Description
196
+ * Drag function for item. Decides whether the user wants to create a new
197
+ * item, resize top, resize bottom or move an existing item.
198
+ *
199
+ * = Parameters
200
+ * +x+:: X coordinate at the start of drag.
201
+ * +y+:: Y coordinate at the start of drag.
202
+ *
203
+ **/
204
+ drag: function(x,y){
205
+ var _pageY = this.parent.pageY(),
206
+ _y = y - _pageY;
207
+ if(this.dragMode === 'create'){
208
+ this.dragCreate(_y);
209
+ }
210
+ else if(this.dragMode === 'resize-top'){
211
+ this.dragResizeTop(_y);
212
+ }
213
+ else if(this.dragMode === 'resize-bottom'){
214
+ this.dragResizeBottom(_y);
215
+ }
216
+ else if(this.dragMode === 'move'){
217
+ this.dragMove(_y);
218
+ }
219
+ this.drawRect();
220
+ return true;
221
+ },
222
+
223
+ /** = Description
224
+ * Modifies the existing item's coordinates or creates a new one.
225
+ *
226
+ * = Parameters
227
+ * +x+:: X coordinate at the end of drag.
228
+ * +y+:: Y coordinate at the end of drag.
229
+ *
230
+ **/
231
+ endDrag: function(x,y){
232
+ var
233
+ _pxPerHour = Math.floor(this.parent.pxPerHour),
234
+ _value,
235
+ _yEquals = (Math.round(this.prevXY[1]/4) === Math.round(y/4));
236
+ if(_yEquals){ // nothing moved, just return.
237
+ return true;
238
+ }
239
+ if(this.dragMode === 'create'){
240
+ this.parent.listItemViews.push( this );
241
+ _value = {};
242
+ this._setValueTop( _value );
243
+ this._setValueBottom( _value );
244
+ this._setValueLabel( _value );
245
+ if(this.parent['editor']){
246
+ this.parent.editor.createItem( _value );
247
+ }
248
+ }
249
+ else {
250
+ _value = COMM.Values.clone( this.value );
251
+ this._setValueTop( _value );
252
+ this._setValueBottom( _value );
253
+ if(this.parent['editor']){
254
+ this.parent.editor.modifyItem( _value );
255
+ }
256
+ }
257
+ this.setValue( _value );
258
+ this.dragMode = 'normal';
259
+ return true;
260
+ },
261
+
262
+ _setValueTop: function( _value ) {
263
+ _value['timeBegin'] = this.rect.top/this.parent.pxPerHour;
264
+ },
265
+
266
+ _setValueBottom: function( _value ) {
267
+ _value['timeEnd'] = this.rect.bottom/this.parent.pxPerHour;
268
+ },
269
+
270
+ _setValueLabel: function( _value ) {
271
+ _value['label'] = this.label;
272
+ },
273
+
274
+ _getValueLabel: function( _value ){
275
+ return _value.label;
276
+ },
277
+
278
+ _getValueTop: function( _value ){
279
+ return (_value.timeBegin * this.parent.pxPerHour)+1;
280
+ },
281
+
282
+ _getValueBottom: function( _value ){
283
+ return (_value.timeEnd * this.parent.pxPerHour)-2;
284
+ },
285
+
286
+ /** = Description
287
+ * Refreshes the object's label and place on the HTimeSheet.
288
+ *
289
+ **/
290
+ refreshValue: function(){
291
+ if ( HVM.type(this.value) === 'h' ){
292
+ var
293
+ _label = this._getValueLabel( this.value ),
294
+ _top = this._getValueTop( this.value ),
295
+ _bottom = this._getValueBottom( this.value ),
296
+ _minHeight = this.parent.options.itemMinHeight;
297
+ this.setLabel( _label );
298
+ if( (_bottom - _top) < _minHeight ){
299
+ _bottom = _top + _minHeight;
300
+ }
301
+ this.rect.setTop( _top );
302
+ this.rect.setBottom( _bottom );
303
+ this.drawRect();
304
+ }
305
+ }
306
+ });
307
+
308
+