rsence 2.0.9.23 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/INSTALL.rdoc +61 -49
  2. data/README.rdoc +20 -4
  3. data/VERSION +1 -1
  4. data/conf/default_conf.yaml +8 -0
  5. data/conf/rsence_command_strings.yaml +31 -20
  6. data/docs/ExampleGuiPlugin.rdoc +2 -2
  7. data/js/comm/comm.js +27 -5
  8. data/js/comm/transporter/transporter.js +1 -1
  9. data/js/comm/values/values.js +12 -5
  10. data/js/controls/button/button.js +12 -2
  11. data/js/controls/dialogs/alert_sheet/alert_sheet.js +13 -1
  12. data/js/controls/dialogs/confirm_sheet/confirm_sheet.js +13 -2
  13. data/js/controls/dialogs/sheet/sheet.js +35 -28
  14. data/js/controls/imageview/imageview.js +13 -13
  15. data/js/controls/progress/progressindicator/progressindicator.js +5 -5
  16. data/js/controls/sliders/slider/slider.js +4 -31
  17. data/js/controls/stepper/stepper.js +12 -19
  18. data/js/controls/textcontrol/textcontrol.js +0 -50
  19. data/js/controls/textcontrol/themes/default/textcontrol.html +1 -1
  20. data/js/controls/window/window.js +1 -1
  21. data/js/core/elem/elem.js +146 -160
  22. data/js/core/rsence_ns/rsence_ns.js +7 -0
  23. data/js/foundation/control/eventresponder/eventresponder.js +8 -7
  24. data/js/foundation/eventmanager/eventmanager.js +81 -48
  25. data/js/foundation/geom/rect/rect.js +1 -1
  26. data/js/foundation/json_renderer/json_renderer.js +4 -1
  27. data/js/foundation/system/system.js +37 -34
  28. data/js/foundation/view/morphanimation/morphanimation.js +53 -43
  29. data/js/foundation/view/view.js +119 -118
  30. data/js/lists/listitems/listitems.js +10 -10
  31. data/js/lists/propertylist/js.inc +0 -0
  32. data/js/lists/propertylist/propertylist.js +574 -0
  33. data/js/lists/propertylist/propertylisteditor/js.inc +0 -0
  34. data/js/lists/propertylist/propertylisteditor/propertylisteditor.js +233 -0
  35. data/js/lists/radiobuttonlist/radiobuttonlist.js +15 -8
  36. data/js/menus/minimenu/js.inc +0 -0
  37. data/js/menus/minimenu/minimenu.js +139 -0
  38. data/js/menus/minimenu/minimenuitem/js.inc +0 -0
  39. data/js/menus/minimenu/minimenuitem/minimenuitem.js +33 -0
  40. data/js/menus/minimenu/minimenuitem/themes/default/minimenuitem.css +45 -0
  41. data/js/menus/minimenu/minimenuitem/themes/default/minimenuitem.html +4 -0
  42. data/js/menus/minimenu/minimenuitem/themes/default/minimenuitem_checkmark.png +0 -0
  43. data/js/menus/minimenu/themes/default/minimenu.css +63 -0
  44. data/js/menus/minimenu/themes/default/minimenu.html +7 -0
  45. data/js/menus/minimenu/themes/default/minimenu.png +0 -0
  46. data/js/util/reloadapp/reloadapp.js +1 -1
  47. data/lib/conf/argv.rb +40 -11
  48. data/lib/daemon/daemon.rb +63 -22
  49. data/lib/plugins/gui_plugin.rb +28 -31
  50. data/lib/plugins/guiparser.rb +37 -7
  51. data/lib/plugins/plugin.rb +260 -28
  52. data/lib/plugins/plugin_base.rb +14 -0
  53. data/lib/plugins/plugin_plugins.rb +11 -1
  54. data/lib/plugins/pluginmanager.rb +127 -44
  55. data/lib/plugins/plugins.rb +10 -1
  56. data/lib/session/msg.rb +25 -1
  57. data/lib/session/sessionmanager.rb +11 -2
  58. data/lib/session/sessionstorage.rb +14 -14
  59. data/lib/transporter/transporter.rb +29 -13
  60. data/lib/values/hvalue.rb +30 -0
  61. data/plugins/client_pkg/info.yaml +2 -2
  62. data/plugins/{index_html → main}/img/loading.gif +0 -0
  63. data/plugins/{index_html → main}/img/riassence.gif +0 -0
  64. data/plugins/main/info.yaml +5 -4
  65. data/plugins/main/main.rb +180 -24
  66. data/plugins/{index_html → main}/tmpl/index.html +4 -2
  67. data/plugins/ticket/info.yaml +2 -2
  68. data/plugins/ticket/lib/upload.rb +57 -5
  69. data/plugins/ticket/ticket.rb +10 -4
  70. data/setup/welcome/info.yaml +2 -2
  71. data/setup/welcome/text/welcome.html +1 -1
  72. metadata +22 -11
  73. data/plugins/index_html/index_html.rb +0 -120
  74. data/plugins/index_html/info.yaml +0 -18
@@ -552,7 +552,7 @@ HView = HClass.extend({
552
552
  * ++
553
553
  **/
554
554
  _setCSS: function(_additional){
555
- var _cssStyle = 'display:none;overflow:hidden;visibility:hidden;';
555
+ var _cssStyle = 'overflow:hidden;visibility:hidden;';
556
556
  if(this.isAbsolute){
557
557
  _cssStyle += 'position:absolute;';
558
558
  } else {
@@ -568,20 +568,18 @@ HView = HClass.extend({
568
568
  * ++
569
569
  **/
570
570
  _getParentElemId: function(){
571
- var _parentElemId;
572
- // if the parent does not have an element:
573
- if(this.parent.elemId === undefined) {
574
- _parentElemId = 0;
575
- }
576
- // if a subview element is defined in the template, use it:
577
- else if(this.parent.markupElemIds&&this.parent.markupElemIds['subview']){
578
- _parentElemId = this.parent.markupElemIds['subview'];
571
+ var _parent = this.parent;
572
+ return ((_parent.elemId === undefined)?0:((_parent._getSubviewId===undefined)?0:_parent._getSubviewId()));
573
+ },
574
+
575
+ _getSubviewId: function(){
576
+ if(this.markupElemIds&&this.markupElemIds.subview!==undefined){
577
+ return this.markupElemIds.subview;
579
578
  }
580
- // otherwise, use main elemId
581
- else {
582
- _parentElemId = this.parent.elemId;
579
+ else if(this.elemId !== undefined) {
580
+ return this.elemId;
583
581
  }
584
- return _parentElemId;
582
+ return 0;
585
583
  },
586
584
 
587
585
  /** --
@@ -616,30 +614,52 @@ HView = HClass.extend({
616
614
  *
617
615
  **/
618
616
  drawRect: function() {
617
+ if(!this.rect.isValid){
618
+ console.log('invalid rect:',this.rect);//,ELEM.get(this.elemId));
619
+ }
620
+ if(!this.parent){
621
+ console.log('no parent:',ELEM.get(this.elemId));
622
+ }
619
623
  if (this.parent && this.rect.isValid) {
620
- var _this = this,
621
- _elemId = _this.elemId,
622
- _styl = ELEM.setStyle,
623
- _rect = _this.rect;
624
-
625
- _styl( _elemId, 'left', _this.flexLeft?(_rect.left+'px'):'auto', true);
626
- _styl( _elemId, 'top', _this.flexTop?(_rect.top+'px'):'auto', true);
627
- _styl( _elemId, 'right', _this.flexRight?(_this.flexRightOffset+'px'):'auto', true);
628
- _styl( _elemId, 'bottom', _this.flexBottom?(_this.flexBottomOffset+'px'):'auto', true);
629
- _styl( _elemId, 'width', (_this.flexLeft&&_this.flexRight)?'auto':(_rect.width+'px'), true);
630
- _styl( _elemId, 'height', (_this.flexTop&&_this.flexBottom)?'auto':(_rect.height+'px'), true);
631
-
624
+ var
625
+ i = 0,
626
+ _this = this,
627
+ _elemId = _this.elemId,
628
+ _styl = ELEM.setStyle,
629
+ _rect = _this.rect,
630
+ _auto = 'auto',
631
+ _left = _this.flexLeft?_rect.left:_auto,
632
+ _top = _this.flexTop?_rect.top:_auto,
633
+ _right = _this.flexRight?_this.flexRightOffset:_auto,
634
+ _bottom = _this.flexBottom?_this.flexBottomOffset:_auto,
635
+ _width = (_this.flexLeft&&_this.flexRight)?_auto:_rect.width,
636
+ _height = (_this.flexTop&&_this.flexBottom)?_auto:_rect.height,
637
+ _styles = [
638
+ [ 'left', _left ],
639
+ [ 'top', _top ],
640
+ [ 'right', _right ],
641
+ [ 'bottom', _bottom ],
642
+ [ 'width', _width ],
643
+ [ 'height', _height ],
644
+ [ 'display', _this.displayMode ]
645
+ ],
646
+ _key, _value;
632
647
  // Show the rectangle once it gets created, unless visibility was set to
633
648
  // hidden in the constructor.
634
- if(_this.isHidden === undefined || _this.isHidden === false) {
635
- _styl( _elemId, 'visibility', 'inherit', true);
649
+ if(!_this.isHidden) {
650
+ _styles.push( [ 'visibility', 'inherit' ] );
636
651
  }
637
-
638
- _styl( _elemId, 'display', _this.displayMode, true);
639
-
640
- _this._updateZIndex();
641
-
642
- if (_this._cachedLeft !== _rect.left || _this._cachedTop !== _rect.top) {
652
+ for(;i<_styles.length;i++){
653
+ _key = _styles[i][0];
654
+ _value = _styles[i][1];
655
+ if( i < 6 && _value !== _auto ){
656
+ _value += 'px';
657
+ }
658
+ _styl(_elemId,_key,_value,true);
659
+ }
660
+ (this.drown === false) && _this._updateZIndex();
661
+
662
+ if ( _this._cachedLeft !== _rect.left || _this._cachedTop !== _rect.top) {
643
663
  _this.invalidatePositionCache();
644
664
  _this._cachedLeft = _rect.left;
645
665
  _this._cachedTop = _rect.top;
@@ -688,15 +708,7 @@ HView = HClass.extend({
688
708
  }
689
709
  this.drawSubviews();
690
710
  if(this.options.style){
691
- var
692
- _style = this.options.style,
693
- _styleItem, _styleKey, _styleValue, i = 0;
694
- for(;i<_style.length;i++){
695
- _styleItem = _style[i];
696
- _styleKey = _styleItem[0];
697
- _styleValue = _styleItem[1];
698
- this.setStyle(_styleKey,_styleValue);
699
- }
711
+ this.setStyles( this.options.style );
700
712
  }
701
713
  if(this.options.html){
702
714
  this.setHTML(this.options.html);
@@ -756,7 +768,7 @@ HView = HClass.extend({
756
768
  **/
757
769
  markupElemNames: ['bg', 'label', 'state', 'control', 'value', 'subview'],
758
770
  drawMarkup: function() {
759
- ELEM.setStyle(this.elemId, 'display', 'none', true);
771
+ // ELEM.setStyle(this.elemId, 'display', 'none', true);
760
772
 
761
773
  // continue processing from here on:
762
774
  var _markupStatus = this._loadMarkup();
@@ -774,7 +786,7 @@ HView = HClass.extend({
774
786
  }
775
787
  }
776
788
 
777
- ELEM.setStyle(this.elemId, 'display', this.displayMode );
789
+ // ELEM.setStyle(this.elemId, 'display', this.displayMode );
778
790
  return this;
779
791
  },
780
792
 
@@ -818,8 +830,22 @@ HView = HClass.extend({
818
830
  * A string with the html escaped.
819
831
  **/
820
832
  escapeHTML: function( _html ) {
821
- return _html.replace(/&/gmi, '&amp;').replace(/>/gmi, '&gt;').replace(/</gmi, '&lt;');
822
- },
833
+ if( typeof _html !== 'string' ) {
834
+ return _html.toString();
835
+ }
836
+ for( var i=0, _reFrom, _reTo, _reArr = this._escapeHTMLArr; i < _reArr.length; i++ ){
837
+ _reFrom = _reArr[i][0];
838
+ _reTo = _reArr[i][1];
839
+ _html = _html.replace( _reFrom, _reTo );
840
+ }
841
+ return _html;
842
+ },
843
+ _escapeHTMLArr: [
844
+ [ new RegExp( /&/gmi ), '&amp;' ],
845
+ [ new RegExp( />/gmi ), '&gt;' ],
846
+ [ new RegExp( /</gmi ), '&lt;' ],
847
+ [ new RegExp( /\n/gmi ), '<br>' ]
848
+ ],
823
849
 
824
850
  /** = Description
825
851
  *
@@ -853,9 +879,18 @@ HView = HClass.extend({
853
879
  var _winSize = ELEM.windowSize();
854
880
  return [ _winSize[0], _winSize[1] ];
855
881
  }
856
- else{
857
- var _rect = this.parent.rect;
858
- return [ _rect.width, _rect.height ];
882
+ else {
883
+ var
884
+ _rect = this.parent.rect,
885
+ _width = _rect.width,
886
+ _height = _rect.height;
887
+ if (this.parent.flexLeft && this.parent.flexRight){
888
+ _width = parseInt( ELEM.getStyle(this.parent.elemId,'width',true), 10 );
889
+ }
890
+ if (this.parent.flexBottom && this.parent.flexTop){
891
+ _height = parseInt( ELEM.getStyle(this.parent.elemId,'height',true), 10 );
892
+ }
893
+ return [ _width, _height ];
859
894
  }
860
895
  },
861
896
 
@@ -866,17 +901,6 @@ HView = HClass.extend({
866
901
  return [ 0, 0, _parentSize[0], _parentSize[1] ];
867
902
  },
868
903
 
869
- parentSize: function(){
870
- var _parentElemId = this.parent.elemId;
871
- if ( _parentElemId === 0 ) {
872
- return ELEM.windowSize();
873
- }
874
- else {
875
- ELEM.flushLoop();
876
- return ELEM.getSize( _parentElemId );
877
- }
878
- },
879
-
880
904
  minWidth: 0,
881
905
  setMinWidth: function(_minWidth){
882
906
  this.minWidth = _minWidth;
@@ -926,7 +950,6 @@ HView = HClass.extend({
926
950
  _validHeight = (typeof _height === 'number'),
927
951
  _right,
928
952
  _bottom;
929
-
930
953
  if(_arrLen === 6){
931
954
  var
932
955
  _parentSize = this.parentSize(),
@@ -973,8 +996,8 @@ HView = HClass.extend({
973
996
  _validHeight && this.setMinHeight( _height );
974
997
  _bottom = _parentHeight - _bottomOffset;
975
998
  }
976
-
977
999
  this.rect = HRect.nu(_leftOffset,_topOffset,_right,_bottom);
1000
+
978
1001
  }
979
1002
  else {
980
1003
  console.log(_throwPrefix + 'the length has to be either 4 or 6.');
@@ -1007,7 +1030,19 @@ HView = HClass.extend({
1007
1030
  }
1008
1031
  return this;
1009
1032
  },
1010
-
1033
+
1034
+ setStyles: function(_styles){
1035
+ var
1036
+ _styleItem, _styleKey, _styleValue, i = 0;
1037
+ for(;i<_styles.length;i++){
1038
+ _styleItem = _styles[i];
1039
+ _styleKey = _styleItem[0];
1040
+ _styleValue = _styleItem[1];
1041
+ this.setStyle(_styleKey,_styleValue);
1042
+ }
1043
+ return this;
1044
+ },
1045
+
1011
1046
  /** = Description
1012
1047
  * Returns a style of the main DOM element of the component.
1013
1048
  * Utilizes +ELEM+ cache to perform the action.
@@ -1043,7 +1078,7 @@ HView = HClass.extend({
1043
1078
  if (!this['markupElemIds']){
1044
1079
  console.log('Warning, setStyleOfPart: no markupElemIds');
1045
1080
  }
1046
- else if (!this.markupElemIds[_partName]) {
1081
+ else if (this.markupElemIds[_partName]===undefined) {
1047
1082
  console.log('Warning, setStyleOfPart: partName "'+_partName+'" does not exist for viewId '+this.viewId+'.');
1048
1083
  }
1049
1084
  else {
@@ -1065,7 +1100,7 @@ HView = HClass.extend({
1065
1100
  *
1066
1101
  **/
1067
1102
  styleOfPart: function(_partName, _name) {
1068
- if (!this.markupElemIds[_partName]) {
1103
+ if (this.markupElemIds[_partName]===undefined) {
1069
1104
  console.log('Warning, styleOfPart: partName "'+_partName+'" does not exist for viewId '+this.viewId+'.');
1070
1105
  return '';
1071
1106
  }
@@ -1085,7 +1120,7 @@ HView = HClass.extend({
1085
1120
  *
1086
1121
  **/
1087
1122
  setMarkupOfPart: function( _partName, _value ) {
1088
- if (!this.markupElemIds[_partName]) {
1123
+ if (this.markupElemIds[_partName]===undefined) {
1089
1124
  console.log('Warning, setMarkupOfPart: partName "'+_partName+'" does not exist for viewId '+this.viewId+'.');
1090
1125
  }
1091
1126
  else {
@@ -1106,7 +1141,7 @@ HView = HClass.extend({
1106
1141
  *
1107
1142
  **/
1108
1143
  markupOfPart: function(_partName) {
1109
- if (!this.markupElemIds[_partName]) {
1144
+ if (this.markupElemIds[_partName]===undefined) {
1110
1145
  console.log('Warning, markupOfPart: partName "'+_partName+'" does not exist for viewId '+this.viewId+'.');
1111
1146
  return '';
1112
1147
  }
@@ -1121,16 +1156,12 @@ HView = HClass.extend({
1121
1156
  *
1122
1157
  **/
1123
1158
  hide: function() {
1124
- if(!this.isHidden) {
1125
- var _setStyl = ELEM.setStyle,
1126
- _elemId = this.elemId;
1127
- _setStyl(_elemId,'visibility', 'hidden');
1128
- // Required for the old, buggy Mozilla engines ( Firefox versions below 3.0 )
1129
- // At least text fields would show through from hidden parent elements.
1130
- // Disabled, because keeping the display as none causes hidden views to have no dimensions at all.
1131
- // _setStyl(_elemId,'display', 'none');
1132
- this.isHidden = true;
1133
- }
1159
+ ELEM.setStyle(this.elemId,'visibility', 'hidden', true);
1160
+ // Required for the old, buggy Mozilla engines ( Firefox versions below 3.0 )
1161
+ // At least text fields would show through from hidden parent elements.
1162
+ // Disabled, because keeping the display as none causes hidden views to have no dimensions at all.
1163
+ // ELEM.setStyle(this.elemId,'display', 'none');
1164
+ this.isHidden = true;
1134
1165
  return this;
1135
1166
  },
1136
1167
 
@@ -1142,13 +1173,9 @@ HView = HClass.extend({
1142
1173
  *
1143
1174
  **/
1144
1175
  show: function() {
1145
- if(this.isHidden) {
1146
- var _setStyl = ELEM.setStyle,
1147
- _elemId = this.elemId;
1148
- _setStyl(_elemId,'visibility', 'inherit');
1149
- _setStyl(_elemId,'display', this.displayMode);
1150
- this.isHidden = false;
1151
- }
1176
+ ELEM.setStyle(this.elemId,'display', this.displayMode, true);
1177
+ ELEM.setStyle(this.elemId,'visibility', 'inherit', true);
1178
+ this.isHidden = false;
1152
1179
  return this;
1153
1180
  },
1154
1181
 
@@ -1628,7 +1655,7 @@ HView = HClass.extend({
1628
1655
  ELEM.setCSS(_stringElem, "visibility:hidden;"+_extraCss);
1629
1656
  ELEM.setHTML(_stringElem, _string);
1630
1657
  // ELEM.flushLoop();
1631
- var _visibleSize=ELEM.getVisibleSize(_stringElem);
1658
+ var _visibleSize=ELEM.getSize(_stringElem);
1632
1659
  // console.log('visibleSize',_visibleSize);
1633
1660
  ELEM.del(_stringElem);
1634
1661
  return [_visibleSize[0]+_visibleSize[0]%2,_visibleSize[1]+_visibleSize[1]%2];
@@ -1649,20 +1676,13 @@ HView = HClass.extend({
1649
1676
  /** Returns the X coordinate that has the scrolled position calculated.
1650
1677
  **/
1651
1678
  pageX: function() {
1652
- var _x = 0,
1653
- _elem = this;
1654
- while(_elem) {
1655
- if(_elem.elemId && _elem.rect) {
1656
- _x += ELEM.get(_elem.elemId).offsetLeft;
1657
- _x -= ELEM.get(_elem.elemId).scrollLeft;
1658
- }
1659
- if(_elem.markupElemIds&&_elem.markupElemIds.subview){
1660
- _x += ELEM.get(_elem.markupElemIds.subview).offsetLeft;
1661
- _x -= ELEM.get(_elem.markupElemIds.subview).scrollLeft;
1662
- }
1663
- _elem = _elem.parent;
1664
- }
1665
- return _x;
1679
+ return ELEM._getVisibleLeftPosition( this.elemId );
1680
+ },
1681
+
1682
+ /** Returns the Y coordinate that has the scrolled position calculated.
1683
+ **/
1684
+ pageY: function() {
1685
+ return ELEM._getVisibleTopPosition( this.elemId );
1666
1686
  },
1667
1687
 
1668
1688
  /** = Description
@@ -1712,25 +1732,6 @@ HView = HClass.extend({
1712
1732
  return this;
1713
1733
  },
1714
1734
 
1715
- /** Returns the Y coordinate that has the scrolled position calculated.
1716
- **/
1717
- pageY: function() {
1718
- var _y = 0,
1719
- _elem = this;
1720
- while(_elem) {
1721
- if(_elem.elemId && _elem.rect) {
1722
- _y += ELEM.get(_elem.elemId).offsetTop;
1723
- _y -= ELEM.get(_elem.elemId).scrollTop;
1724
- }
1725
- if(_elem.markupElemIds&&_elem.markupElemIds.subview){
1726
- _y += ELEM.get(_elem.markupElemIds.subview).offsetTop;
1727
- _y -= ELEM.get(_elem.markupElemIds.subview).scrollTop;
1728
- }
1729
- _elem = _elem.parent;
1730
- }
1731
- return _y;
1732
- },
1733
-
1734
1735
  /** Returns the HPoint that has the scrolled position calculated.
1735
1736
  **/
1736
1737
  pageLocation: function() {
@@ -9,19 +9,19 @@
9
9
 
10
10
  /*** = Description
11
11
  ** HListItems is uses an array-packed list of hash objects as its value.
12
- ##
13
- ## == Value as Array of Hashes:
12
+ **
13
+ ** == Value as Array of Hashes:
14
14
  ** Each item in the array should have a 'label' and a 'value' key.
15
15
  ** The 'label' key of each item is used as the label for the HRadiobutton in the list.
16
16
  ** The 'value' key of each item is the value used for the output.
17
- ##
18
- ## == Value as Array of strings or numerals
19
- ## Each Item like with hash, except the item is both label and value. Each item should
20
- ## be unique.
21
- ##
22
- ## == Important
23
- ** The parent object of a HListItem needs to be a compatible hash, like HRadiobuttonList.
24
- ##
17
+ **
18
+ ** == Value as Array of strings or numerals
19
+ ** Each Item like with hash, except the item is both label and value. Each item should
20
+ ** be unique.
21
+ **
22
+ ** == Important
23
+ ** The parent object of a HListItem needs to be a compatible component, like HRadioButtonList.
24
+ **
25
25
  ***/
26
26
  var//RSence.Lists
27
27
  HListItems = HValueResponder.extend({
File without changes
@@ -0,0 +1,574 @@
1
+ /* RSence
2
+ * Copyright 2010 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
+ ** HPropertyList uses any JSON-compliant structure as its value and displays
11
+ ** its content hierarchically in three columns:
12
+ ** - Key
13
+ ** - Type
14
+ ** - Value
15
+ **
16
+ ** Its current purpose is to view JSON data in a structured way. I'll be
17
+ ** extended later as a full, generic JSON data editor.
18
+ **
19
+ ** NOTE: HPropertyList does not work in any version of Internet Explorer yet.
20
+ **
21
+ ***/
22
+ var//RSence.Lists
23
+ HPropertyList = HControl.extend({
24
+
25
+ defaultEvents: {
26
+ click: true
27
+ },
28
+
29
+ controlDefaults: HControlDefaults.extend({
30
+ keyColumnWidth: 100,
31
+ hideTypeColumn: false,
32
+ useEditor: false,
33
+ rowHeight: 15,
34
+ keyIndent: 8
35
+ }),
36
+
37
+ click: function(x,y){
38
+ if(this.options.useEditor){
39
+ var
40
+ clickY = y-this.contentView.pageY(),
41
+ itemNum = Math.floor(clickY/this.options.rowHeight);
42
+ if((clickY < 0) || (itemNum > this.valueTokens.length-1)){
43
+ this.editor.hide();
44
+ return;
45
+ }
46
+ this.editItem( itemNum );
47
+ }
48
+ },
49
+
50
+ keyColumnRight: function(){
51
+ return this.options.keyColumnWidth;
52
+ },
53
+ typeColumnLeft: function(){
54
+ return this.keyColumnRight();
55
+ },
56
+ typeColumnRight: function(){
57
+ return this.options.keyColumnWidth + 60;
58
+ },
59
+
60
+ valueColumnLeft: function(){
61
+ if(this.options.hideTypeColumn){
62
+ return this.keyColumnRight();
63
+ }
64
+ else {
65
+ return this.typeColumnRight();
66
+ }
67
+ },
68
+
69
+ drawSubviews: function(){
70
+
71
+ var borderAndBg = ELEM.make(this.elemId);
72
+ ELEM.setCSS(borderAndBg,'position:absolute;left:0;top:0;right:0;bottom:0;background-color:#e6e6e6;border:1px solid #999;');
73
+
74
+ this.markupElemIds = {
75
+ bg: borderAndBg
76
+ };
77
+
78
+ this.contentView = HScrollView.extend({
79
+ click: function(x,y){
80
+ this.parent.click(x,y);
81
+ return true;
82
+ }
83
+ }).nu(
84
+ [ 1, 25, null, null, 1, 1 ],
85
+ this, {
86
+ scrollY: 'auto',
87
+ scrollX: false,
88
+ events: {
89
+ click: true
90
+ }
91
+ }
92
+ );
93
+
94
+ var separatorParentElemId = ELEM.make(this.contentView.elemId);
95
+ ELEM.setCSS( separatorParentElemId, 'position:absolute;left:0;top:0;right:0;' );
96
+ this.separatortParentElemId = separatorParentElemId;
97
+
98
+ this.propertyItems = [];
99
+ // Editor initialization
100
+ if(this.options.useEditor){
101
+ this.editorValue = HValue.nu(
102
+ false, {
103
+ top: 0,
104
+ left: 0,
105
+ type: 'h',
106
+ name: '--',
107
+ value: {}
108
+ }
109
+ );
110
+ this.editor = HPropertyListEditor.nu(
111
+ [0,0,null,this.options.rowHeight+2,0,null],
112
+ this.contentView, {
113
+ propertyItems: this.propertyItems,
114
+ visible: false,
115
+ valueObj: this.editorValue
116
+ }
117
+ );
118
+ }
119
+
120
+ // Set row style heights from options
121
+ var rowHeightStyle = 'height:'+this.options.rowHeight+'px;';
122
+ this.keyRowStyle += rowHeightStyle;
123
+ this.typeRowStyle += rowHeightStyle;
124
+ this.valueRowStyle += rowHeightStyle;
125
+ this.rowSeparatorStyle += rowHeightStyle;
126
+
127
+ // Style common font style
128
+ this.contentView.setStyle('font-size','11px');
129
+
130
+ // Create the key column
131
+ this.keyColumn = HView.nu(
132
+ [ 0, 0, this.keyColumnRight(), 24 ],
133
+ this.contentView, {
134
+ style: [ [ 'border-right', '1px solid #999' ] ]
135
+ }
136
+ );
137
+
138
+ // Create the type column
139
+ if(!this.options.hideTypeColumn){
140
+ this.typeColumn = HView.nu(
141
+ [ this.typeColumnLeft(), 0, 60, 24 ],
142
+ this.contentView, {
143
+ style: [ [ 'border-right', '1px solid #999' ] ]
144
+ }
145
+ );
146
+ }
147
+
148
+ // Create the value column
149
+ this.valueColumn = HView.nu(
150
+ [ this.valueColumnLeft(), 0, 0, 24, 0, null ],
151
+ this.contentView
152
+ );
153
+
154
+ // Create the column headers
155
+ this.header = HView.extend({
156
+ drawSubviews: function(){
157
+ var
158
+ keyColumnWidth = this.parent.options.keyColumnWidth;
159
+ this.keyLabel = HView.nu(
160
+ [ 0, 0, this.parent.keyColumnRight(), 24 ],
161
+ this, {
162
+ html: '<b>Key</b>',
163
+ style: [
164
+ [ 'text-align', 'middle' ],
165
+ [ 'text-indent', '16px' ],
166
+ [ 'line-height', '24px' ],
167
+ [ 'font-size', '13px' ],
168
+ [ 'border-right', '3px double #999' ]
169
+ ]
170
+ }
171
+ );
172
+ if(!this.parent.options.hideTypeColumn){
173
+ this.typeLabel = HView.nu(
174
+ [ this.parent.typeColumnLeft(), 0, 60, 24 ],
175
+ this, {
176
+ html: '<b>Type</b>',
177
+ style: [
178
+ [ 'text-align', 'middle' ],
179
+ [ 'text-indent', '8px' ],
180
+ [ 'line-height', '24px' ],
181
+ [ 'font-size', '13px' ],
182
+ [ 'padding-right', '1px' ],
183
+ [ 'border-right', '1px solid #999' ]
184
+ ]
185
+ }
186
+ );
187
+ }
188
+ this.valueLabel = HView.nu(
189
+ [ this.parent.valueColumnLeft(), 0, 80, 24, 0, null ],
190
+ this, {
191
+ html: '<b>Value</b>',
192
+ style: [
193
+ [ 'text-align', 'middle' ],
194
+ [ 'text-indent', '8px' ],
195
+ [ 'line-height', '24px' ],
196
+ [ 'font-size', '13px' ]
197
+ ]
198
+ }
199
+ );
200
+ }
201
+ }).nu(
202
+ [ 0, 0, null, 24, 0, null ],
203
+ this, {
204
+ style: [ [ 'border-bottom', '1px solid #999' ] ]
205
+ }
206
+ );
207
+
208
+ // Create the resize control (invisible, just above the first column separator)
209
+ this.resizeColumns = HControl.extend({
210
+ drag: function(x,y){
211
+ var
212
+ parent = this.parent,
213
+ options = parent.options,
214
+ keyColumnWidth = x - parent.pageX(),
215
+ parentWidth = parent.rect.width;
216
+
217
+ if(keyColumnWidth < 80){
218
+ keyColumnWidth = 80;
219
+ }
220
+ else if ( keyColumnWidth > parentWidth-140 ){
221
+ keyColumnWidth = parentWidth - 140;
222
+ }
223
+
224
+ // Set the dragger itself
225
+ this.rect.offsetTo( keyColumnWidth-1, 0 ); this.drawRect();
226
+
227
+ // Resize the key column
228
+ options.keyColumnWidth = keyColumnWidth;
229
+
230
+ var
231
+ keyColumn = parent.keyColumn,
232
+ keyLabel = parent.header.keyLabel,
233
+ keyRight = parent.keyColumnRight();
234
+ keyColumn.rect.setRight( keyRight );
235
+ keyLabel.rect.setRight( keyRight );
236
+
237
+ var
238
+ valueColumn = parent.valueColumn,
239
+ valueLabel = parent.header.valueLabel,
240
+ valueLeft = parent.valueColumnLeft();
241
+
242
+ valueColumn.rect.setLeft( valueLeft );
243
+ valueLabel.rect.setLeft( valueLeft );
244
+
245
+ // Redraw the rects
246
+ keyColumn.drawRect();
247
+ keyLabel.drawRect();
248
+ valueColumn.drawRect();
249
+ valueLabel.drawRect();
250
+
251
+ // Resize the type column
252
+ if(!options.hideTypeColumn){
253
+ var
254
+ typeColumn = parent.typeColumn,
255
+ typeLabel = parent.header.typeLabel,
256
+ typeLeft = parent.typeColumnLeft(),
257
+ typeRight = parent.typeColumnRight();
258
+
259
+ typeColumn.rect.setLeft( typeLeft );
260
+ typeColumn.rect.setRight( typeRight );
261
+
262
+ typeLabel.rect.setLeft( typeLeft, 0 );
263
+ typeLabel.rect.setRight( typeRight, 0 );
264
+
265
+ typeColumn.drawRect();
266
+ typeLabel.drawRect();
267
+ }
268
+
269
+ if(options.useEditor){
270
+ parent.editor.resizeKeyColumn();
271
+ }
272
+
273
+ }
274
+ }).nu(
275
+ [ this.keyColumnRight(), 0, 5, 25 ],
276
+ this, {
277
+ events: { draggable: true },
278
+ style: [
279
+ [ 'cursor', 'ew-resize' ]
280
+ ]
281
+ }
282
+ );
283
+
284
+ },
285
+
286
+ // Tokenize arrays
287
+ arrayTokens: function( arr, name ){
288
+ this.addToken( 'a', name, '('+arr.length+' items)' );
289
+ this.nodeProperties.left += this.options.keyIndent;
290
+ var i = 0, val, type;
291
+ for( ; i < arr.length; i++ ){
292
+ val = arr[i];
293
+ type = this.itemType( val );
294
+ if( type == 'h' ){
295
+ this.hashTokens( val, i );
296
+ }
297
+ else if ( type == 'a' ){
298
+ this.arrayTokens( val, i );
299
+ }
300
+ else {
301
+ this.addToken( type, i, val );
302
+ }
303
+ }
304
+ this.nodeProperties.left -= this.options.keyIndent;
305
+ },
306
+
307
+ // Get length of hash
308
+ hashLen: function( hash ){
309
+ var count = 0;
310
+ for( var item in hash ){
311
+ count += 1;
312
+ }
313
+ return count;
314
+ },
315
+
316
+ // Sort hash keys
317
+ hashSortedKeys: function( hash ){
318
+ var
319
+ keys = [],
320
+ key;
321
+ for( key in hash ){
322
+ keys.push( key );
323
+ }
324
+ return keys.sort();
325
+ },
326
+
327
+ // Tokenize hashes
328
+ hashTokens: function( hash, name ){
329
+ this.addToken( 'h', name, '('+this.hashLen( hash )+' items)' );
330
+ this.nodeProperties.left += this.options.keyIndent;
331
+ var key, val, type, i = 0, keys = this.hashSortedKeys( hash );
332
+ for( ; i < keys.length; i++ ){
333
+ key = keys[i];
334
+ val = hash[key];
335
+ type = this.itemType( val );
336
+ if( type == 'h' ){
337
+ this.hashTokens( val, key );
338
+ }
339
+ else if ( type == 'a' ){
340
+ this.arrayTokens( val, key );
341
+ }
342
+ else {
343
+ this.addToken( type, key, val );
344
+ }
345
+ }
346
+ this.nodeProperties.left -= this.options.keyIndent;
347
+ },
348
+
349
+ // Adds a taken
350
+ addToken: function( type, name, value ){
351
+ this.valueTokens.push( {
352
+ top: this.nodeProperties.top,
353
+ left: this.nodeProperties.left,
354
+ type: type,
355
+ name: name,
356
+ value: value
357
+ } );
358
+ this.nodeProperties.top += this.options.rowHeight;
359
+ },
360
+
361
+ // Returns type of item
362
+ itemType: function( item ){
363
+ return COMM.Values.type( item );
364
+ },
365
+
366
+ // Translation from type code to type name
367
+ typeNames: {
368
+ h: 'Hash',
369
+ a: 'Array',
370
+ s: 'String',
371
+ n: 'Number',
372
+ b: 'Boolean',
373
+ '~': 'Null',
374
+ '-': 'Undefined'
375
+ },
376
+
377
+ // Style for the key rows
378
+ keyRowStyle: "position:absolute;padding-top:2px;right:0px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;",
379
+
380
+ // Creates row in key column
381
+ addKeyColumnControl: function( token, i ){
382
+ var elemId;
383
+ if( i >= this.propertyItems.length ){
384
+ elemId = ELEM.make( this.keyColumn.elemId );
385
+ this.propertyItems.push( elemId );
386
+ ELEM.setCSS( elemId, 'top:'+token.top+'px;'+this.keyRowStyle );
387
+ }
388
+ else {
389
+ elemId = this.propertyItems[i];
390
+ }
391
+ ELEM.setStyle( elemId, 'left', (token.left+10)+'px' );
392
+ if( token.type === 'h' || token.type === 'a' ){
393
+ ELEM.setStyle( elemId, 'font-weight', 'bold' );
394
+ }
395
+ else {
396
+ ELEM.setStyle( elemId, 'font-weight', 'inherit' );
397
+ }
398
+ ELEM.setHTML( elemId, token.name );
399
+ },
400
+
401
+ // Style for the type rows
402
+ typeRowStyle: "position:absolute;padding-top:2px;left:8px;width:72px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;",
403
+
404
+ // Creates row in the type column
405
+ addTypeColumnControl: function( token, i ){
406
+ var elemId;
407
+ if( i >= this.propertyItems.length ){
408
+ elemId = ELEM.make( this.typeColumn.elemId );
409
+ this.propertyItems.push( elemId );
410
+ ELEM.setCSS( elemId, 'top:'+token.top+'px;'+this.typeRowStyle );
411
+ }
412
+ else {
413
+ elemId = this.propertyItems[i];
414
+ }
415
+ ELEM.setHTML( elemId, this.typeNames[token.type] );
416
+ },
417
+
418
+ // Style for the value rows
419
+ valueRowStyle: "position:absolute;padding-top:2px;left:8px;right:0px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;",
420
+
421
+ // Creates row in the value column
422
+ addValueColumnControl: function( token, i ){
423
+ var elemId, value;
424
+ if( i >= this.propertyItems.length ){
425
+ elemId = ELEM.make( this.valueColumn.elemId );
426
+ this.propertyItems.push( elemId );
427
+ ELEM.setCSS( elemId, 'top:'+token.top+'px;'+this.valueRowStyle );
428
+ }
429
+ else {
430
+ elemId = this.propertyItems[i];
431
+ }
432
+ if( token.type === 'h' || token.type === 'a' ){
433
+ ELEM.setStyle( elemId, 'font-style', 'italic' );
434
+ }
435
+ else {
436
+ ELEM.setStyle( elemId, 'font-style', 'inherit' );
437
+ }
438
+ value = token.value;
439
+ if(value===true){
440
+ value = 'true';
441
+ }
442
+ else if(value===false){
443
+ value = 'false';
444
+ }
445
+ else if(value===undefined){
446
+ value = 'undefined';
447
+ }
448
+ else if(value===null){
449
+ value = 'null';
450
+ }
451
+ ELEM.setHTML( elemId, value );
452
+ },
453
+
454
+ // Row separator style
455
+ rowSeparatorStyle: "position:absolute;left:1px;right:1px;font-size:0px;height:1px;overflow:hidden;border-bottom:1px solid #999;",
456
+
457
+ // Adds row separator
458
+ addRowSeparator: function( token, i, even ){
459
+ if( i >= this.propertyItems.length ){
460
+ var elemId = ELEM.make( this.separatortParentElemId );
461
+ this.propertyItems.push( elemId );
462
+ ELEM.setCSS( elemId, 'top:'+token.top+'px;'+this.rowSeparatorStyle+'background-color:'+(even?'#f6f6f6':'#e6e6e6')+';' );
463
+ }
464
+ },
465
+
466
+ // Destructor, deletes extra elements created
467
+ die: function(){
468
+ var
469
+ i=0,
470
+ propLen = this.propertyItems.length,
471
+ elemId;
472
+ for(;i<propLen;i++){
473
+ elemId = this.propertyItems.pop();
474
+ ELEM.del( elemId );
475
+ }
476
+ this.base();
477
+ },
478
+
479
+ // Currently selected item
480
+ selectedItem: 0,
481
+ editNextItem: function(){
482
+ this.editItem(this.selectedItem+1);
483
+ },
484
+ editPrevItem: function(){
485
+ this.editItem(this.selectedItem-1);
486
+ },
487
+ editItem: function(itemNum){
488
+
489
+ if(itemNum>this.valueTokens.length-1){
490
+ itemNum = this.valueTokens.length-1;
491
+ }
492
+ else if(itemNum < 0){
493
+ itemNum = 0;
494
+ }
495
+
496
+ var
497
+ targetY = (itemNum*this.options.rowHeight)-1,
498
+ elem = ELEM.get( this.contentView.elemId ),
499
+ scrollTop = elem.scrollTop,
500
+ contentHeight = this.contentView.rect.height;
501
+
502
+ if(targetY > (scrollTop+contentHeight-45)){
503
+ elem.scrollTop = scrollTop+45;
504
+ }
505
+ else if(targetY < scrollTop+45){
506
+ elem.scrollTop = scrollTop-45;
507
+ }
508
+
509
+ this.selectedItem = itemNum;
510
+ this.editorValue.set( COMM.Values.clone(this.valueTokens[itemNum]) );
511
+ this.editor.show();
512
+ EVENT.changeActiveControl(this.editor);
513
+ this.editor.offsetTo( 0, targetY );
514
+ this.editor.bringToFront();
515
+ },
516
+
517
+ // Starts tokenizing, when the value is changed.
518
+ refreshValue: function(){
519
+ if(this['propertyItems']===undefined){
520
+ return;
521
+ }
522
+ this.valueTokens = [];
523
+ this.nodeProperties = {
524
+ top: 0,
525
+ left: 8
526
+ };
527
+ var rootType = this.itemType( this.value );
528
+ if( rootType == 'h' ){
529
+ this.hashTokens( this.value, 'Root' );
530
+ }
531
+ else if( rootType == 'a' ){
532
+ this.arrayTokens( this.value, 'Root' );
533
+ }
534
+ else {
535
+ this.addToken( rootType, 'Root', this.value );
536
+ }
537
+
538
+ var i, token;
539
+ if(this['propertyItems'] === undefined){
540
+ this.propertyItems = [];
541
+ }
542
+ var colHeight = 0, colId = 0;
543
+ for( i = 0; i < this.valueTokens.length; i ++ ) {
544
+ token = this.valueTokens[i];
545
+ this.addRowSeparator( token, colId, (i%2===0) ); colId++;
546
+ this.addKeyColumnControl( token, colId ); colId++;
547
+ if(!this.options.hideTypeColumn){
548
+ this.addTypeColumnControl( token, colId ); colId++;
549
+ }
550
+ this.addValueColumnControl( token, colId ); colId++;
551
+ colHeight = token.top+this.options.rowHeight;
552
+ }
553
+ var propItemsLen = this.propertyItems.length, elemId;
554
+ for( i = colId; i < propItemsLen; i++ ){
555
+ elemId = this.propertyItems.pop();
556
+ ELEM.del( elemId );
557
+ }
558
+ this.keyColumn.bringToFront();
559
+ if(!this.options.hideTypeColumn){
560
+ this.typeColumn.bringToFront();
561
+ }
562
+ this.valueColumn.bringToFront();
563
+ this.resizeColumns.bringToFront();
564
+ this.keyColumn.rect.setHeight( colHeight );
565
+ this.keyColumn.drawRect();
566
+ if(!this.options.hideTypeColumn){
567
+ this.typeColumn.rect.setHeight( colHeight );
568
+ this.typeColumn.drawRect();
569
+ }
570
+ this.valueColumn.rect.setHeight( colHeight );
571
+ this.valueColumn.drawRect();
572
+ ELEM.setStyle(this.separatortParentElemId,'height',(colHeight+25)+'px');
573
+ }
574
+ });