rsence-pre 2.1.0.21 → 2.1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/INSTALL.rdoc +61 -46
  2. data/README.rdoc +17 -1
  3. data/VERSION +1 -1
  4. data/conf/rsence_command_strings.yaml +16 -16
  5. data/js/comm/sessionwatcher/sessionwatcher.js +5 -4
  6. data/js/comm/transporter/transporter.js +62 -4
  7. data/js/comm/values/values.js +62 -0
  8. data/js/controls/button/themes/default/button.css +7 -7
  9. data/js/controls/imageview/imageview.js +15 -6
  10. data/js/controls/stringview/stringview.js +16 -2
  11. data/js/controls/textcontrol/textcontrol.js +56 -3
  12. data/js/core/elem/elem.js +38 -12
  13. data/js/datetime/timesheet/timesheet.js +141 -32
  14. data/js/datetime/timesheet_item/timesheet_item.js +82 -22
  15. data/js/foundation/application/application.js +10 -4
  16. data/js/foundation/control/control.js +5 -3
  17. data/js/foundation/control/dyncontrol/dyncontrol.js +17 -3
  18. data/js/foundation/control/eventresponder/eventresponder.js +31 -2
  19. data/js/foundation/eventmanager/eventmanager.js +202 -74
  20. data/js/foundation/json_renderer/json_renderer.js +5 -2
  21. data/js/foundation/system/system.js +13 -11
  22. data/js/foundation/view/morphanimation/morphanimation.js +9 -5
  23. data/js/foundation/view/view.js +22 -10
  24. data/js/lists/propertylist/propertylist.js +5 -0
  25. data/js/menus/minimenu/minimenu.js +3 -8
  26. data/lib/conf/default.rb +0 -3
  27. data/lib/http/broker.rb +6 -5
  28. data/lib/http/rackup.rb +3 -3
  29. data/lib/http/response.rb +28 -2
  30. data/lib/session/msg.rb +30 -18
  31. data/lib/transporter/transporter.rb +4 -0
  32. data/lib/values/hvalue.rb +4 -134
  33. data/lib/values/valuemanager.rb +36 -22
  34. data/plugins/client_pkg/lib/client_pkg_serve.rb +195 -152
  35. data/plugins/main/main.rb +8 -10
  36. data/plugins/ticket/lib/common.rb +4 -4
  37. data/plugins/ticket/lib/favicon.rb +1 -1
  38. data/plugins/ticket/lib/rsrc.rb +1 -1
  39. data/plugins/ticket/lib/upload.rb +2 -2
  40. data/plugins/ticket/ticket.rb +3 -3
  41. data/setup/welcome/gui/welcome.yaml +1 -1
  42. metadata +10 -11
  43. data/lib/util/ruby19_fixes.rb +0 -18
@@ -32,10 +32,13 @@ HImageView = HControl.extend({
32
32
  })),
33
33
 
34
34
  _makeScaleToFit: function(_parentId){
35
- this.elemId = ELEM.make(_parentId,'img');
36
- ELEM.setAttr(this.elemId,'src',this.getImgSrc());
37
- ELEM.setAttr(this.elemId,'alt',this.label);
38
- ELEM.setAttr(this.elemId,'title',this.label);
35
+ this.elemId = ELEM.make( _parentId, 'img', {
36
+ attrs: [
37
+ [ 'src', this.getImgSrc() ],
38
+ [ 'alt', this.label ],
39
+ [ 'title', this.label ]
40
+ ]
41
+ } );
39
42
  },
40
43
  _makeScaleToOriginal: function(_parentId){
41
44
  this.elemId = ELEM.make(_parentId,'div');
@@ -58,11 +61,17 @@ HImageView = HControl.extend({
58
61
  *
59
62
  **/
60
63
  refreshValue: function(){
64
+ var _src = this.getImgSrc();
61
65
  if(this.options.scaleToFit){
62
- ELEM.setAttr(this.elemId,'src',this.getImgSrc());
66
+ if(ELEM.getAttr(this.elemId,'src')!==_src){
67
+ ELEM.setAttr(this.elemId,'src',_src);
68
+ }
63
69
  }
64
70
  else{
65
- ELEM.setStyle(this.elemId,'background-image','url('+this.getImgSrc()+')');
71
+ var _url = 'url('+this.getImgSrc()+')';
72
+ if(ELEM.getStyle(this.elemId,'background-image') != _url){
73
+ ELEM.setStyle(this.elemId,'background-image',_url);
74
+ }
66
75
  }
67
76
  },
68
77
 
@@ -22,8 +22,21 @@ HStringView = HControl.extend({
22
22
 
23
23
  componentName: "stringview",
24
24
 
25
+ defaultEvents: {
26
+ contextMenu: true
27
+ },
28
+
29
+ /** = Description
30
+ * HStringView allows the default contextMenu action.
31
+ *
32
+ **/
33
+ contextMenu: function(){
34
+ return true;
35
+ },
36
+
25
37
  /** = Description
26
- * setStyle function
38
+ * The setStyle method of HStringView applies only to the value
39
+ * element (not the whole component).
27
40
  *
28
41
  **/
29
42
  setStyle: function(_name, _value, _cacheOverride) {
@@ -35,7 +48,8 @@ HStringView = HControl.extend({
35
48
  },
36
49
 
37
50
  /** = Description
38
- * refreshLable function
51
+ * The refreshLabel of HStringView sets a tool tip.
52
+ * Applied by the setLabel method and the label attribute of options.
39
53
  *
40
54
  **/
41
55
  refreshLabel: function() {
@@ -22,7 +22,8 @@ HTextControl = HControl.extend({
22
22
  componentName: "textcontrol",
23
23
 
24
24
  defaultEvents: {
25
- textEnter: true
25
+ textEnter: true,
26
+ contextMenu: true
26
27
  },
27
28
 
28
29
  controlDefaults: (HControlDefaults.extend({
@@ -30,6 +31,13 @@ HTextControl = HControl.extend({
30
31
  refreshOnInput: true
31
32
  })),
32
33
 
34
+ /** = Description
35
+ * The contextMenu event for text input components is not prevented by default.
36
+ **/
37
+ contextMenu: function(){
38
+ return true;
39
+ },
40
+
33
41
  /** = Description
34
42
  * The refreshLabel method sets the title property of the text
35
43
  * field, essentially creating a tooltip using the label.
@@ -60,7 +68,49 @@ HTextControl = HControl.extend({
60
68
  /** This flag is true, when the text input field has focus.
61
69
  **/
62
70
  hasTextFocus: false,
63
-
71
+
72
+ _getChangeEventFn: function(){
73
+ var _this = this;
74
+ return function(e){
75
+ _this.setValue(
76
+ _this.validateText(
77
+ _this.getTextFieldValue()
78
+ )
79
+ );
80
+ if(e.type === 'paste'){
81
+ console.log('event: paste, e:', e);
82
+ if(_this._clipboardPasteTimer){
83
+ clearTimeout( this._clipboardPasteTimer );
84
+ }
85
+ this._clipboardPasteTimer = setTimeout( function(){_this.clipboardPaste();}, 200 );
86
+ }
87
+ return true;
88
+ };
89
+ },
90
+
91
+ _clipboardPasteTimer: null,
92
+ clipboardPaste: function(){
93
+ clearTimeout( this._clipboardPasteTimer ); this._clipboardPasteTimer = null;
94
+ console.log('paste event, value now:',this.value);
95
+ },
96
+
97
+ _changeEventFn: null,
98
+ _clearChangeEventFn: function(){
99
+ if( this._changeEventFn ){
100
+ Event.stopObserving( ELEM.get(this.markupElemIds.value), 'change', this._changeEventFn );
101
+ Event.stopObserving( ELEM.get(this.markupElemIds.value), 'paste', this._changeEventFn );
102
+ this._changeEventFn = null;
103
+ }
104
+ },
105
+ _setChangeEventFn: function(){
106
+ if( this._changeEventFn ){
107
+ this._clearChangeEventFn();
108
+ }
109
+ this._changeEventFn = this._getChangeEventFn();
110
+ Event.observe( ELEM.get(this.markupElemIds.value), 'change', this._changeEventFn );
111
+ Event.observe( ELEM.get(this.markupElemIds.value), 'paste', this._changeEventFn );
112
+ },
113
+
64
114
  /** = Description
65
115
  * Special event for text entry components.
66
116
  * Called when the input field gains focus.
@@ -68,6 +118,7 @@ HTextControl = HControl.extend({
68
118
  **/
69
119
  textFocus: function(){
70
120
  this.hasTextFocus = true;
121
+ this._setChangeEventFn();
71
122
  return true;
72
123
  },
73
124
 
@@ -78,6 +129,7 @@ HTextControl = HControl.extend({
78
129
  **/
79
130
  textBlur: function(){
80
131
  this.hasTextFocus = false;
132
+ this._clearChangeEventFn();
81
133
  if(this.options.refreshOnBlur){
82
134
  this.refreshValue();
83
135
  }
@@ -283,7 +335,8 @@ HNumericTextControl = HTextControl.extend({
283
335
 
284
336
  defaultEvents: {
285
337
  mouseWheel: true,
286
- textEnter: true
338
+ textEnter: true,
339
+ contextMenu: true
287
340
  },
288
341
 
289
342
  /** Uses the mouseWheel event to step up/down the value.
data/js/core/elem/elem.js CHANGED
@@ -12,6 +12,12 @@
12
12
  var//RSence.Core
13
13
  BROWSER_TYPE = {
14
14
 
15
+ /* Any browser on Mac OS X */
16
+ mac: false,
17
+
18
+ /* Any browser on Windows */
19
+ win: false,
20
+
15
21
  /* Any version of Microsoft Internet Explorer */
16
22
  ie: false,
17
23
 
@@ -774,7 +780,6 @@ ELEM = {
774
780
  _key = _currTodo.pop();
775
781
  _val = _attrCache[_key];
776
782
  _elem.setAttribute(_key, _val);
777
- //_elem[_key]=_val;
778
783
  }
779
784
  },
780
785
 
@@ -827,7 +832,7 @@ ELEM = {
827
832
  _attrTodo = _this._attrTodo[_id],
828
833
  _attrCache = _this._attrCache[_id],
829
834
  _differs = _value !== _this.getAttr(_id, _key);
830
- if (_differs) {
835
+ if (_differs || _bypass) {
831
836
  _attrCache[_key] = _value;
832
837
  if (_bypass) {
833
838
  _this._elements[_id].setAttribute(_key, _value);
@@ -1043,11 +1048,15 @@ ELEM = {
1043
1048
  * +_tagName+:: The tag name of the element.
1044
1049
  * (Optional, default: 'DIV')
1045
1050
  *
1051
+ * +_options+:: Options to set before appending child to parent.
1052
+ * Supported option attrs: [[key,value],[key,value]]
1053
+ * (Optional, rarely necessary except when creating IMG tags)
1054
+ *
1046
1055
  * = Returns
1047
1056
  * The new ELEM ID.
1048
1057
  *
1049
1058
  **/
1050
- make: function(_targetId, _tagName) {
1059
+ make: function(_targetId, _tagName, _options) {
1051
1060
  if (_targetId === undefined) {
1052
1061
  _targetId = 0;
1053
1062
  }
@@ -1084,9 +1093,22 @@ ELEM = {
1084
1093
  }
1085
1094
  }
1086
1095
  _elem = document.createElement(_tagName);
1087
- _this._elements[_targetId].appendChild(_elem);
1088
1096
  _id = _this._add(_elem);
1089
1097
  _this._initCache(_id);
1098
+ if(_options!==undefined){
1099
+ if(_options.attrs){
1100
+ var
1101
+ i = 0,
1102
+ _key, _value;
1103
+ for( ; i<_options.attrs.length; i++ ){
1104
+ _key = _options.attrs[i][0];
1105
+ _value = _options.attrs[i][1];
1106
+ _elem[_key] = _value;
1107
+ _this.setAttr( _id, _key, _value );
1108
+ }
1109
+ }
1110
+ }
1111
+ _this._elements[_targetId].appendChild(_elem);
1090
1112
  return _id;
1091
1113
  },
1092
1114
 
@@ -1258,10 +1280,11 @@ ELEM = {
1258
1280
 
1259
1281
  /* Checks browser versions and starts the document load check */
1260
1282
  _warmup: function() {
1261
- var _this = ELEM,
1262
- _ua = navigator.userAgent,
1263
- _isIE = (document.all && (_ua.indexOf("Opera") === -1)),
1264
- _browserType = BROWSER_TYPE;
1283
+ var
1284
+ _this = ELEM,
1285
+ _ua = navigator.userAgent,
1286
+ _isIE = (document.all && (_ua.indexOf("Opera") === -1)),
1287
+ _browserType = BROWSER_TYPE;
1265
1288
  _browserType.opera = _ua.indexOf("Opera") !== -1;
1266
1289
  _browserType.safari = _ua.indexOf("KHTML") !== -1;
1267
1290
  _browserType.symbian = _ua.indexOf("SymbianOS") !== -1;
@@ -1272,6 +1295,9 @@ ELEM = {
1272
1295
  _browserType.ie8 = _isIE && (_ua.indexOf("MSIE 8") !== -1);
1273
1296
  _browserType.ie9 = _isIE && (_ua.indexOf("MSIE 9") !== -1);
1274
1297
 
1298
+ _browserType.mac = (_ua.indexOf("Macintosh") !== -1);
1299
+ _browserType.win = (_ua.indexOf("Windows") !== -1);
1300
+
1275
1301
  // Experimental; don't treat IE9 as an IE at all.
1276
1302
  // NOTE: IE9 Beta does still not behave like a standard web browser.
1277
1303
  // It will probably require as much tuning as earlier IE versions.
@@ -1316,9 +1342,9 @@ ELEM = {
1316
1342
  var _ie_script = document.getElementById("__ie_onload");
1317
1343
  _ie_script.onreadystatechange = function() {
1318
1344
  if ((this.readyState === "complete") && true) {
1319
- clearTimeout(ELEM._domLoadTimer);
1320
- ELEM._domLoadStatus = true;
1321
- ELEM._init();
1345
+ clearTimeout(_this._domLoadTimer);
1346
+ _this._domLoadStatus = true;
1347
+ _this._init();
1322
1348
  }
1323
1349
  };
1324
1350
  // the event will trigger on ie, so we don't have to keep on polling:
@@ -1353,7 +1379,7 @@ ELEM = {
1353
1379
  _this._init();
1354
1380
  }
1355
1381
  else {
1356
- _this._domLoadTimer = setTimeout('ELEM._domWaiter()', _this.ELEMTickerInterval * 10);
1382
+ _this._domLoadTimer = setTimeout(_this._domWaiter, 10 ); // (_this.ELEMTickerInterval * 10));
1357
1383
  }
1358
1384
  }
1359
1385
  };
@@ -11,10 +11,41 @@
11
11
  ***/
12
12
  var//RSence.DateTime
13
13
  HTimeSheet = HControl.extend({
14
+
14
15
  componentName: 'timesheet',
16
+
17
+ /* Default amount of pixels per hour. Override with options when necessary. */
15
18
  pxPerHour: 24,
19
+
20
+ /* Default amount of pixels from left. Override with options when necessary. */
16
21
  itemOffsetLeft: 36,
22
+
23
+ /* Default amount of pixels from right. Override with options when necessary. */
17
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
+
18
49
  /** = Description
19
50
  * Redraws the timesheet.
20
51
  *
@@ -82,16 +113,7 @@ HTimeSheet = HControl.extend({
82
113
  if(origY>maxY){
83
114
  origY = maxY;
84
115
  }
85
- var item = HTimeSheetItem.nu(
86
- this.createItemRect(origY,lineHeight),
87
- this, {
88
- label: 'New Item',
89
- events: {
90
- draggable: true
91
- }
92
- }
93
- );
94
- this.dragItem = item;
116
+ this.dragItem = this.createTimeSheetItem( { label: this.options.newItemLabel }, origY, lineHeight, 'create' );
95
117
  },
96
118
 
97
119
  /** = Description
@@ -103,9 +125,29 @@ HTimeSheet = HControl.extend({
103
125
  *
104
126
  **/
105
127
  startDrag: function(x,y){
106
- this.createItem(y-this.pageY());
107
- EVENT.startDragging( this.dragItem );
128
+ this._startDragTime = new Date().getTime();
129
+ this._startDragCoords = [x,y];
130
+ return true;
108
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
+
109
151
  listItemViews: false,
110
152
 
111
153
  /** = Description
@@ -128,10 +170,13 @@ HTimeSheet = HControl.extend({
128
170
  *
129
171
  **/
130
172
  createItemRect: function(_origY, _lineHeight){
131
- var _left = this.itemOffsetLeft,
132
- _top = _origY,
133
- _right = this.rect.width - this.itemOffsetRight,
134
- _bottom = _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
+ }
135
180
  return HRect.nu( _left, _top, _right, _bottom );
136
181
  },
137
182
 
@@ -144,40 +189,104 @@ HTimeSheet = HControl.extend({
144
189
  this.base();
145
190
  },
146
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
+
147
230
  /** = Description
148
231
  * Redraws and refreshes the values on timesheet.
149
232
  *
150
233
  **/
151
234
  refreshValue: function(){
152
- var _data = this.value, i;
235
+ var
236
+ _data = this.value,
237
+ i;
153
238
  if(this.listItemViews === false){
154
239
  this.listItemViews = [];
155
240
  }
156
- if(this.listItemViews.length !== 0){
241
+ else if(this.listItemViews.length > 0){
157
242
  for( i=0; i<this.listItemViews.length; i++){
158
243
  this.listItemViews[i].die();
159
244
  }
160
245
  this.listItemViews = [];
161
246
  }
162
- if(_data instanceof Array){
163
- var _value, _label, _item;
247
+ if(_data instanceof Array && _data.length > 0){
248
+ var
249
+ _value,
250
+ _item;
164
251
  for( i=0; i<_data.length; i++){
165
252
  _value = _data[i];
166
- _label = _value['label'];
167
- _item = HTimeSheetItem.nu(
168
- this.createItemRect( 0, 12 ),
169
- this, {
170
- label: _label,
171
- value: _value,
172
- events: {
173
- draggable: true
174
- }
175
- }
176
- );
177
- _item.dragMode = 'normal';
253
+ _item = this.createTimeSheetItem( _value );
178
254
  this.listItemViews.push( _item );
179
255
  }
180
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
+ }
181
290
  }
182
291
  });
183
292
 
@@ -11,11 +11,31 @@
11
11
  ***/
12
12
  var//RSence.DateTime
13
13
  HTimeSheetItem = HControl.extend({
14
+
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. */
15
18
  dragMode: 'create',
19
+
20
+ /* The previous coordinate. Used to detect double-drag as double-click */
16
21
  prevXY: [0,0],
22
+
23
+ /* The time at the previous coordinate. Used to detect double-drag as double-click. */
17
24
  prevXYTime: 0,
18
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
+
19
39
  /** = Description
20
40
  * Dragging is used to change coordinates.
21
41
  *
@@ -31,13 +51,8 @@ HTimeSheetItem = HControl.extend({
31
51
  _xEquals = (Math.round(this.prevXY[0]/4) === Math.round(x/4)),
32
52
  _yEquals = (Math.round(this.prevXY[1]/4) === Math.round(y/4)),
33
53
  _noTimeout = ((_timeNow - this.prevXYTime) < 500);
34
- if( _xEquals && _yEquals && _noTimeout ) {
35
- if( this.parent['editor'] ){
36
- var _editor = this.parent.editor;
37
- _editor.setTimeSheetItem(this);
38
- _editor.bringToFront();
39
- _editor.show();
40
- }
54
+ if( _xEquals && _yEquals && _noTimeout ) { // doubleClick
55
+ return true;
41
56
  }
42
57
  else {
43
58
  var _diffTop = this.rect.top - this.origY,
@@ -60,6 +75,17 @@ HTimeSheetItem = HControl.extend({
60
75
  return true;
61
76
  },
62
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
+
63
89
  /** = Description
64
90
  * Label setter function.
65
91
  *
@@ -203,23 +229,27 @@ HTimeSheetItem = HControl.extend({
203
229
  *
204
230
  **/
205
231
  endDrag: function(x,y){
206
- var _pxPerHour = Math.floor(this.parent.pxPerHour),
207
- _value;
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
+ }
208
239
  if(this.dragMode === 'create'){
209
240
  this.parent.listItemViews.push( this );
210
- _value = {
211
- 'timeBegin': this.rect.top/_pxPerHour,
212
- 'timeEnd': this.rect.bottom/_pxPerHour,
213
- 'label': this.label
214
- };
241
+ _value = {};
242
+ this._setValueTop( _value );
243
+ this._setValueBottom( _value );
244
+ this._setValueLabel( _value );
215
245
  if(this.parent['editor']){
216
246
  this.parent.editor.createItem( _value );
217
247
  }
218
248
  }
219
249
  else {
220
250
  _value = COMM.Values.clone( this.value );
221
- _value['timeBegin'] = this.rect.top/_pxPerHour;
222
- _value['timeEnd'] = this.rect.bottom/_pxPerHour;
251
+ this._setValueTop( _value );
252
+ this._setValueBottom( _value );
223
253
  if(this.parent['editor']){
224
254
  this.parent.editor.modifyItem( _value );
225
255
  }
@@ -229,17 +259,47 @@ HTimeSheetItem = HControl.extend({
229
259
  return true;
230
260
  },
231
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
+
232
286
  /** = Description
233
287
  * Refreshes the object's label and place on the HTimeSheet.
234
288
  *
235
289
  **/
236
290
  refreshValue: function(){
237
- var _value = this.value,
238
- _pxPerHour = this.parent.pxPerHour;
239
- if((_value instanceof Object) && !(_value instanceof Array)){
240
- this.setLabel( _value['label'] );
241
- this.rect.setTop( _value['timeBegin'] * _pxPerHour );
242
- this.rect.setBottom( _value['timeEnd'] * _pxPerHour );
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 );
243
303
  this.drawRect();
244
304
  }
245
305
  }
@@ -187,10 +187,16 @@ HApplication = HClass.extend({
187
187
  * resistant. Do not extend.
188
188
  **/
189
189
  _startIdle: function(){
190
- HSystem.busyApps[ this.appId ] = true;
191
- this.onIdle();
192
- this._pollViews();
193
- HSystem.busyApps[ this.appId ] = false;
190
+ var _this = this;
191
+ HSystem.busyApps[ _this.appId ] = true;
192
+ this._busyTimer = setTimeout(
193
+ function(){
194
+ _this.onIdle();
195
+ _this._pollViews();
196
+ HSystem.busyApps[ _this.appId ] = false;
197
+ },
198
+ 10
199
+ );
194
200
  },
195
201
 
196
202
  /** = Description