rsence 2.1.7 → 2.1.8
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.
- data/INSTALL.rdoc +8 -4
- data/VERSION +1 -1
- data/js/controls/stringview/stringview.js +16 -2
- data/js/controls/textcontrol/textcontrol.js +69 -4
- data/js/core/elem/elem.js +6 -0
- data/js/foundation/control/eventresponder/eventresponder.js +27 -1
- data/js/foundation/eventmanager/eventmanager.js +34 -16
- data/js/foundation/view/morphanimation/morphanimation.js +9 -5
- data/js/foundation/view/view.js +28 -4
- data/js/lists/checkboxlist/checkboxlist.js +9 -0
- data/js/lists/listitems/listitems.js +16 -0
- data/js/lists/radiobuttonlist/radiobuttonlist.js +17 -1
- data/js/menus/minimenu/minimenu.js +9 -5
- data/lib/http/request.rb +6 -1
- data/lib/http/response.rb +3 -1
- data/plugins/client_pkg/lib/client_pkg_serve.rb +191 -157
- data/setup/welcome/gui/welcome.yaml +1 -1
- metadata +5 -5
data/INSTALL.rdoc
CHANGED
@@ -84,7 +84,7 @@ Replace the +\my_projects+ path with the path to the directory where you want to
|
|
84
84
|
* Using just defaults, the following URL should work: http://127.0.0.1:8001
|
85
85
|
|
86
86
|
==== Windows limitations
|
87
|
-
If you install the sqlite dll and the sqlite3
|
87
|
+
If you install the sqlite dll and the sqlite3 gem, you'll gain persistent sessions and this warning message will disappear:
|
88
88
|
`Warning: Session database is not available. Can't use persistent sessions`
|
89
89
|
|
90
90
|
It's not a dependency in the default install, because it's not strictly required and makes the first installation much easier. Also, you can use any other database supported by Sequel instead of Sqlite.
|
@@ -134,10 +134,10 @@ This not only enables SessionStorage (persistent sessions between RSence restart
|
|
134
134
|
* *jscompress*:: C-optimized Javascript compression and obfuscation library developed for RSence specifically
|
135
135
|
* *html_min*:: C-optimized HTML whitespace removal library developed for RSence specfically
|
136
136
|
* *cssmin*:: CSS whitespace removal library
|
137
|
-
* *sequel*[http://
|
137
|
+
* *sequel*[http://sequel.rubyforge.org/]
|
138
138
|
* Generic SQL database ORM
|
139
139
|
* A Sequel driver for your preferred database is also needed:
|
140
|
-
* *sqlite3
|
140
|
+
* *sqlite3*:: SQLite[http://www.sqlite.org] is a light-weight SQL library. Recommended for development and small projects.
|
141
141
|
* Other database adapters compatible with Sequel are fine. Just configure RSence accordingly.
|
142
142
|
* *highline*:: Console-based menu prompt system by the init command.
|
143
143
|
* rmagick
|
@@ -151,6 +151,7 @@ The primary installation method of RSence is via RubyGems.
|
|
151
151
|
|
152
152
|
To ensure your RubyGems is up-to-date, run:
|
153
153
|
sudo gem update --system
|
154
|
+
* gem update --system is disabled in Debian based systems, such as Ubuntu. It's okay to skip on these systems.
|
154
155
|
|
155
156
|
Even if RubyGems is up-to-date, ensure your installed gems are up-to-date, some of these are updated frequently. This will also update RSence release versions to the most recent version, if installed.
|
156
157
|
sudo gem update
|
@@ -160,8 +161,11 @@ Even if RubyGems is up-to-date, ensure your installed gems are up-to-date, some
|
|
160
161
|
This will install RSence via RubyGems, the preferred method. All dependencies are installed too, except for the ones you already might have installed.
|
161
162
|
gem install rsence
|
162
163
|
|
164
|
+
Debian/Ubuntu users need to include /var/lib/gems/1.8/bin into PATH either by adding it directly there or by making a symbolic link:
|
165
|
+
sudo ln -s /var/lib/gems/1.8/bin/rsence /usr/local/bin/rsence
|
166
|
+
|
163
167
|
Optionally, you might want to contribute to RSence development, just clone or fork the GIT repository on Github:
|
164
|
-
|
168
|
+
http://github.com/rsence/rsence
|
165
169
|
|
166
170
|
When installed, ensure it works by exploring the help of the 'rsence' command, like:
|
167
171
|
rsence
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1.
|
1
|
+
2.1.8
|
@@ -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
|
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
|
-
*
|
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,50 @@ 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
|
+
if(_this._clipboardEventTimer){
|
76
|
+
clearTimeout( this._clipboardEventTimer );
|
77
|
+
}
|
78
|
+
_this._clipboardEventTimer = setTimeout( function(){_this.clipboardEvent();}, 200 );
|
79
|
+
return true;
|
80
|
+
};
|
81
|
+
},
|
82
|
+
|
83
|
+
_updateValueFromField: function(){
|
84
|
+
this.setValue(
|
85
|
+
this.validateText(
|
86
|
+
this.getTextFieldValue()
|
87
|
+
)
|
88
|
+
);
|
89
|
+
},
|
90
|
+
|
91
|
+
_clipboardEventTimer: null,
|
92
|
+
clipboardEvent: function(){
|
93
|
+
this._updateValueFromField();
|
94
|
+
clearTimeout( this._clipboardEventTimer );
|
95
|
+
this._clipboardEventTimer = null;
|
96
|
+
},
|
97
|
+
|
98
|
+
_changeEventFn: null,
|
99
|
+
_clearChangeEventFn: function(){
|
100
|
+
if( this._changeEventFn ){
|
101
|
+
Event.stopObserving( ELEM.get(this.markupElemIds.value), 'paste', this._changeEventFn );
|
102
|
+
Event.stopObserving( ELEM.get(this.markupElemIds.value), 'cut', this._changeEventFn );
|
103
|
+
this._changeEventFn = null;
|
104
|
+
}
|
105
|
+
},
|
106
|
+
_setChangeEventFn: function(){
|
107
|
+
if( this._changeEventFn ){
|
108
|
+
this._clearChangeEventFn();
|
109
|
+
}
|
110
|
+
this._changeEventFn = this._getChangeEventFn();
|
111
|
+
Event.observe( ELEM.get(this.markupElemIds.value), 'paste', this._changeEventFn );
|
112
|
+
Event.observe( ELEM.get(this.markupElemIds.value), 'cut', this._changeEventFn );
|
113
|
+
},
|
114
|
+
|
64
115
|
/** = Description
|
65
116
|
* Special event for text entry components.
|
66
117
|
* Called when the input field gains focus.
|
@@ -68,6 +119,7 @@ HTextControl = HControl.extend({
|
|
68
119
|
**/
|
69
120
|
textFocus: function(){
|
70
121
|
this.hasTextFocus = true;
|
122
|
+
this._setChangeEventFn();
|
71
123
|
return true;
|
72
124
|
},
|
73
125
|
|
@@ -78,12 +130,19 @@ HTextControl = HControl.extend({
|
|
78
130
|
**/
|
79
131
|
textBlur: function(){
|
80
132
|
this.hasTextFocus = false;
|
133
|
+
this._clearChangeEventFn();
|
134
|
+
this._updateValueFromField();
|
81
135
|
if(this.options.refreshOnBlur){
|
82
136
|
this.refreshValue();
|
83
137
|
}
|
84
138
|
return true;
|
85
139
|
},
|
86
|
-
|
140
|
+
|
141
|
+
onIdle: function(){
|
142
|
+
this.hasTextFocus && this._updateValueFromField();
|
143
|
+
this.base();
|
144
|
+
},
|
145
|
+
|
87
146
|
/** = Description
|
88
147
|
* refreshValue function
|
89
148
|
*
|
@@ -148,6 +207,11 @@ HTextControl = HControl.extend({
|
|
148
207
|
return '---'+Math.round((1+Math.random())*10000)+'---';
|
149
208
|
},
|
150
209
|
|
210
|
+
die: function(){
|
211
|
+
this._clearChangeEventFn();
|
212
|
+
this.base();
|
213
|
+
},
|
214
|
+
|
151
215
|
/** = Description
|
152
216
|
* Returns the selection (or text cursor position) of the input element
|
153
217
|
* as an +Array+ like +[ startOffset, endOffset ]+.
|
@@ -283,7 +347,8 @@ HNumericTextControl = HTextControl.extend({
|
|
283
347
|
|
284
348
|
defaultEvents: {
|
285
349
|
mouseWheel: true,
|
286
|
-
textEnter: true
|
350
|
+
textEnter: true,
|
351
|
+
contextMenu: true
|
287
352
|
},
|
288
353
|
|
289
354
|
/** Uses the mouseWheel event to step up/down the value.
|
data/js/core/elem/elem.js
CHANGED
@@ -1016,6 +1016,9 @@ ELEM = {
|
|
1016
1016
|
if (_key === 'opacity') {
|
1017
1017
|
_this.setOpacity(_id, _value);
|
1018
1018
|
}
|
1019
|
+
else if ( !_elems[_id] ){
|
1020
|
+
console.log('ELEM#setStyle: Not a element! id:',_id,', key:',_key,', value:', _value);
|
1021
|
+
}
|
1019
1022
|
else {
|
1020
1023
|
_this._setElementStyle( _elems[_id], _key, _cached[_key] );
|
1021
1024
|
}
|
@@ -1203,6 +1206,9 @@ ELEM = {
|
|
1203
1206
|
if (_key === 'opacity') {
|
1204
1207
|
_this.setOpacity(_id, _cached[_key]);
|
1205
1208
|
}
|
1209
|
+
else if ( !_elem ){
|
1210
|
+
console.log('ELEM#_flushStyleCache: Not a element! id:',_id,', key:',_key,', value:', _value);
|
1211
|
+
}
|
1206
1212
|
else {
|
1207
1213
|
_this._setElementStyle( _elem, _key, _cached[_key] );
|
1208
1214
|
}
|
@@ -153,7 +153,8 @@ HEventResponder = HClass.extend({
|
|
153
153
|
textEnter: false,
|
154
154
|
click: false,
|
155
155
|
resize: false,
|
156
|
-
doubleClick: false
|
156
|
+
doubleClick: false,
|
157
|
+
contextMenu: false
|
157
158
|
} ).extend( this.defaultEvents ).extend( _events?_events:{} ).nu();
|
158
159
|
}
|
159
160
|
this.events.ctrl = this;
|
@@ -284,6 +285,24 @@ HEventResponder = HClass.extend({
|
|
284
285
|
return this;
|
285
286
|
},
|
286
287
|
|
288
|
+
/** = Description
|
289
|
+
* Registers or releases event listening for contextMenu events depending on
|
290
|
+
* the value of the flag argument.
|
291
|
+
*
|
292
|
+
* = Parameters
|
293
|
+
* +_flag+:: Set the contextMenu event listening on/off (true/false) for
|
294
|
+
* the component instance.
|
295
|
+
*
|
296
|
+
* = Returns
|
297
|
+
* +self+
|
298
|
+
*
|
299
|
+
**/
|
300
|
+
setContextMenu: function(_flag) {
|
301
|
+
this.events.contextMenu = _flag;
|
302
|
+
this.setEvents();
|
303
|
+
return this;
|
304
|
+
},
|
305
|
+
|
287
306
|
/** = Description
|
288
307
|
* Registers or releases event listening for mouseUp events depending on the
|
289
308
|
* value of the flag argument.
|
@@ -537,6 +556,13 @@ HEventResponder = HClass.extend({
|
|
537
556
|
**/
|
538
557
|
doubleClick: function(x,y,_isLeftButton){},
|
539
558
|
|
559
|
+
/** = Description
|
560
|
+
* Default contextMenu event responder method. Does nothing by default.
|
561
|
+
* Extend to return true to allow the default action of the browser.
|
562
|
+
*
|
563
|
+
**/
|
564
|
+
contextMenu: function(x,y,_isLeftButton){},
|
565
|
+
|
540
566
|
/** = Description
|
541
567
|
* Default mouseDown event responder method. Does nothing by default.
|
542
568
|
*
|
@@ -28,7 +28,8 @@ EVENT = {
|
|
28
28
|
mouseWheel: false,
|
29
29
|
resize: false,
|
30
30
|
textEnter: false,
|
31
|
-
doubleClick: false
|
31
|
+
doubleClick: false,
|
32
|
+
contextMenu: false
|
32
33
|
},
|
33
34
|
|
34
35
|
/** = Description
|
@@ -841,14 +842,13 @@ EVENT = {
|
|
841
842
|
**/
|
842
843
|
doubleClick: function(e) {
|
843
844
|
var _this = EVENT,
|
844
|
-
_didEndDrag = false,
|
845
845
|
x = _this.status[_this.crsrX],
|
846
846
|
y = _this.status[_this.crsrY],
|
847
847
|
_elemId,
|
848
848
|
_ctrl,
|
849
849
|
i = 0;
|
850
850
|
_this._modifiers(e);
|
851
|
-
// Check for
|
851
|
+
// Check for doubleClick listeners.
|
852
852
|
for (i = 0; i !== _this.focused.length; i++) {
|
853
853
|
if (_this.focused[i] === true) {
|
854
854
|
if (_this.focusOptions[i].doubleClick === true) {
|
@@ -890,20 +890,38 @@ EVENT = {
|
|
890
890
|
}
|
891
891
|
},
|
892
892
|
|
893
|
-
|
893
|
+
/** Mid-level context menu manager.
|
894
|
+
* Gets called on the onContextMenu event.
|
895
|
+
* Delegates the following call to the high-level event receivers of all
|
896
|
+
* enabled controls registered, depending on the events they registered:
|
897
|
+
* - contextMenu
|
898
|
+
*
|
899
|
+
* Just make a component return true to allow the browser's default action.
|
900
|
+
*
|
901
|
+
**/
|
894
902
|
contextMenu: function(e) {
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
903
|
+
var _this = EVENT,
|
904
|
+
x = _this.status[_this.crsrX],
|
905
|
+
y = _this.status[_this.crsrY],
|
906
|
+
_preventDefault = true,
|
907
|
+
_elemId,
|
908
|
+
_ctrl,
|
909
|
+
i = 0;
|
910
|
+
_this._modifiers(e);
|
911
|
+
// Check for contextMenu listeners.
|
912
|
+
for (i = 0; i !== _this.focused.length; i++) {
|
913
|
+
if (_this.focused[i] === true) {
|
914
|
+
if (_this.focusOptions[i].contextMenu === true) {
|
915
|
+
if( _this.focusOptions[i].ctrl.contextMenu() ){
|
916
|
+
_preventDefault = false;
|
917
|
+
}
|
918
|
+
}
|
919
|
+
}
|
920
|
+
}
|
921
|
+
if( _preventDefault ){
|
922
|
+
Event.stop( e );
|
923
|
+
}
|
924
|
+
return true;
|
907
925
|
},
|
908
926
|
|
909
927
|
|
@@ -168,7 +168,9 @@ HMorphAnimation = HClass.extend({
|
|
168
168
|
// --Moves the view for one step. This gets called repeatedly when the animation++
|
169
169
|
// --is happening.++
|
170
170
|
_animateStep: function(_obj) {
|
171
|
-
var
|
171
|
+
var
|
172
|
+
_time = new Date().getTime(),
|
173
|
+
i;
|
172
174
|
if (_time < _obj.startTime + _obj.duration) {
|
173
175
|
var _cTime = _time - _obj.startTime;
|
174
176
|
|
@@ -189,14 +191,16 @@ HMorphAnimation = HClass.extend({
|
|
189
191
|
if(_unit){
|
190
192
|
_propNow += _unit;
|
191
193
|
}
|
192
|
-
ELEM.setStyle(this.elemId,_key, _propNow);
|
194
|
+
ELEM.setStyle( this.elemId, _key, _propNow );
|
193
195
|
}
|
194
196
|
}
|
195
|
-
|
196
|
-
|
197
|
+
}
|
198
|
+
else {
|
197
199
|
// Animation is done, clear the interval and finalize the animation.
|
198
200
|
for (i = 0; i < _obj.props.length; i++) {
|
199
|
-
ELEM.setStyle(
|
201
|
+
ELEM.setStyle(
|
202
|
+
this.elemId,
|
203
|
+
_obj.props[i].prop,
|
200
204
|
_obj.props[i].to + _obj.props[i].unit);
|
201
205
|
}
|
202
206
|
this._animationDone = true;
|
data/js/foundation/view/view.js
CHANGED
@@ -1047,6 +1047,20 @@ HView = HClass.extend({
|
|
1047
1047
|
},
|
1048
1048
|
|
1049
1049
|
setStyles: function(_styles){
|
1050
|
+
var _stylesObjType = COMM.Values.type(_styles);
|
1051
|
+
if(_stylesObjType==='a'){
|
1052
|
+
this.setStylesArray(_styles);
|
1053
|
+
}
|
1054
|
+
else if(_stylesObjType==='h'){
|
1055
|
+
this.setStylesHash(_styles);
|
1056
|
+
}
|
1057
|
+
else {
|
1058
|
+
console.log('HView#setStyles: Invalid data, expected array or hash; type: '+h+', data:',_styles);
|
1059
|
+
}
|
1060
|
+
return this;
|
1061
|
+
},
|
1062
|
+
|
1063
|
+
setStylesArray: function(_styles){
|
1050
1064
|
var
|
1051
1065
|
_styleItem, _styleKey, _styleValue, i = 0;
|
1052
1066
|
for(;i<_styles.length;i++){
|
@@ -1058,6 +1072,16 @@ HView = HClass.extend({
|
|
1058
1072
|
return this;
|
1059
1073
|
},
|
1060
1074
|
|
1075
|
+
setStylesHash: function(_styles){
|
1076
|
+
var
|
1077
|
+
_styleKey, _styleValue;
|
1078
|
+
for(_styleKey in _styles){
|
1079
|
+
_styleValue = _styles[_styleKey];
|
1080
|
+
this.setStyle(_styleKey,_styleValue);
|
1081
|
+
}
|
1082
|
+
return this;
|
1083
|
+
},
|
1084
|
+
|
1061
1085
|
/** = Description
|
1062
1086
|
* Returns a style of the main DOM element of the component.
|
1063
1087
|
* Utilizes +ELEM+ cache to perform the action.
|
@@ -1252,6 +1276,9 @@ HView = HClass.extend({
|
|
1252
1276
|
this.stopAnimation();
|
1253
1277
|
// Delete the children first.
|
1254
1278
|
var _childViewId, i;
|
1279
|
+
if(!this.views){
|
1280
|
+
console.log('HView#die: no subviews for component name: ',this.componentName,', self:',this);
|
1281
|
+
}
|
1255
1282
|
while (this.views.length !== 0) {
|
1256
1283
|
_childViewId = this.views[0];
|
1257
1284
|
this.destroyView(_childViewId);
|
@@ -1365,10 +1392,7 @@ HView = HClass.extend({
|
|
1365
1392
|
// Could be cached.
|
1366
1393
|
var _bounds = new HRect(this.rect);
|
1367
1394
|
|
1368
|
-
_bounds.
|
1369
|
-
_bounds.left = 0;
|
1370
|
-
_bounds.bottom -= _bounds.top;
|
1371
|
-
_bounds.top = 0;
|
1395
|
+
_bounds.offsetTo(0,0);
|
1372
1396
|
|
1373
1397
|
return _bounds;
|
1374
1398
|
},
|
@@ -129,12 +129,21 @@ HCheckboxList = HControl.extend({
|
|
129
129
|
this.refreshValue();
|
130
130
|
},
|
131
131
|
|
132
|
+
_listItemResponder: null,
|
133
|
+
setListItemResponder: function(_listItemResponder){
|
134
|
+
this._listItemResponder = _listItemResponder;
|
135
|
+
},
|
136
|
+
|
132
137
|
/** = Description
|
133
138
|
* Sets listItems and ListItemViews to null and calls
|
134
139
|
* the inherited destructor.
|
135
140
|
*
|
136
141
|
**/
|
137
142
|
die: function(){
|
143
|
+
if(this._listItemResponder){
|
144
|
+
this._listItemResponder.die();
|
145
|
+
this._listItemResponder = null;
|
146
|
+
}
|
138
147
|
this.listItems = null;
|
139
148
|
this.listItemViews = null;
|
140
149
|
this.base();
|
@@ -28,6 +28,12 @@ HListItems = HValueResponder.extend({
|
|
28
28
|
|
29
29
|
constructor: function( _rect, _parent, _options ){
|
30
30
|
this.parent = _parent;
|
31
|
+
if ( this.parent.setListItemResponder ){
|
32
|
+
this.parent.setListItemResponder( this );
|
33
|
+
}
|
34
|
+
else {
|
35
|
+
console.log('Warning; parent does not respond to setListItemResponder');
|
36
|
+
}
|
31
37
|
if (_options instanceof Object) {
|
32
38
|
if (_options['valueObj'] !== undefined) {
|
33
39
|
_options.valueObj.bind( this );
|
@@ -38,6 +44,16 @@ HListItems = HValueResponder.extend({
|
|
38
44
|
}
|
39
45
|
}
|
40
46
|
},
|
47
|
+
|
48
|
+
die: function() {
|
49
|
+
var _this = this;
|
50
|
+
if(_this.valueObj){
|
51
|
+
_this.valueObj.unbind(_this);
|
52
|
+
_this.valueObj = null;
|
53
|
+
}
|
54
|
+
_this.value = null;
|
55
|
+
},
|
56
|
+
|
41
57
|
_warningMessage: function(_messageText){
|
42
58
|
console.log("Warning; HListItems: "+_messageText);
|
43
59
|
},
|
@@ -66,13 +66,26 @@ HRadioButtonList = HControl.extend({
|
|
66
66
|
);
|
67
67
|
},
|
68
68
|
|
69
|
+
_listItemResponder: null,
|
70
|
+
setListItemResponder: function(_listItemResponder){
|
71
|
+
this._listItemResponder = _listItemResponder;
|
72
|
+
},
|
73
|
+
|
69
74
|
/** = Description
|
70
75
|
* Destructor. Sets listItems and listItemViews to null and initiates
|
71
76
|
* destructor for radioButtonIndexValue.
|
72
77
|
*
|
73
78
|
**/
|
74
79
|
die: function(){
|
80
|
+
if(this._listItemResponder){
|
81
|
+
this._listItemResponder.die();
|
82
|
+
this._listItemResponder = null;
|
83
|
+
}
|
84
|
+
this.radioButtonIndexValue && this.radioButtonIndexValue.die();
|
75
85
|
this.listItems = null;
|
86
|
+
for(var i=0;i<this.listItemViews.length;i++){
|
87
|
+
this.listItemViews[i].die();
|
88
|
+
}
|
76
89
|
this.listItemViews = null;
|
77
90
|
this.radioButtonIndexValue && this.radioButtonIndexValue.die();
|
78
91
|
this.base();
|
@@ -90,6 +103,9 @@ HRadioButtonList = HControl.extend({
|
|
90
103
|
},
|
91
104
|
refresh: function(){
|
92
105
|
var _listItems = this.parent.listItems;
|
106
|
+
if(_listItems === undefined || _listItems === null){
|
107
|
+
return;
|
108
|
+
}
|
93
109
|
if(_listItems[ this.value ] !== undefined){
|
94
110
|
this.parent.setValue( _listItems[ this.value ][0] );
|
95
111
|
}
|
@@ -100,7 +116,7 @@ HRadioButtonList = HControl.extend({
|
|
100
116
|
|
101
117
|
refreshValue: function(){
|
102
118
|
var _value = this.value;
|
103
|
-
if ( this.listItems.length !== 0 && this['valueMatrix'] !== undefined ) {
|
119
|
+
if ( this.listItems && this.listItems.length !== 0 && this['valueMatrix'] !== undefined ) {
|
104
120
|
if ( this.radioButtonResponder === false ){
|
105
121
|
this.radioButtonIndexValue = HValue.nu( false, 0 );
|
106
122
|
this.radioButtonIndexValue.bind( this.valueMatrix );
|
@@ -56,10 +56,12 @@ HMiniMenu = HRadioButtonList.extend({
|
|
56
56
|
|
57
57
|
refreshValue: function(){
|
58
58
|
this.base();
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
if(this.listItems && this.listItems.length !== 0 && this['valueMatrix'] !== undefined ) {
|
60
|
+
for(var i=0;i<this.listItems.length;i++){
|
61
|
+
if(this.listItems[i][0]===this.value){
|
62
|
+
this.setLabel( this.listItems[i][1] );
|
63
|
+
return;
|
64
|
+
}
|
63
65
|
}
|
64
66
|
}
|
65
67
|
},
|
@@ -97,8 +99,10 @@ HMiniMenu = HRadioButtonList.extend({
|
|
97
99
|
},
|
98
100
|
|
99
101
|
die: function(){
|
100
|
-
this.
|
102
|
+
this.valueMatrix = null;
|
103
|
+
var _menuItemView = this.menuItemView;
|
101
104
|
this.base();
|
105
|
+
_menuItemView.die();
|
102
106
|
},
|
103
107
|
|
104
108
|
drawSubviews: function(){
|
data/lib/http/request.rb
CHANGED
@@ -17,8 +17,13 @@ module RSence
|
|
17
17
|
# than the Rack::Request it's extending.
|
18
18
|
class Request < Rack::Request
|
19
19
|
attr_reader :header, :path, :query
|
20
|
+
class RequestHeader < Hash
|
21
|
+
def [](key)
|
22
|
+
super(key.downcase)
|
23
|
+
end
|
24
|
+
end
|
20
25
|
def initialize(env)
|
21
|
-
@header =
|
26
|
+
@header = RequestHeader.new
|
22
27
|
super
|
23
28
|
env2header()
|
24
29
|
@path = path_info()
|
data/lib/http/response.rb
CHANGED
@@ -17,13 +17,15 @@ module RSence
|
|
17
17
|
# Adds the + method "operator" to an extended Array.
|
18
18
|
# Used for pushing http body data.
|
19
19
|
class ResponseBody < Array
|
20
|
+
|
20
21
|
def push( body_data )
|
21
22
|
super( sanitize_body_data( body_data ) )
|
22
23
|
end
|
23
24
|
def sanitize_body_data( body_data )
|
24
|
-
if body_data.class == String
|
25
|
+
if body_data.class == String or body_data.class == GZString
|
25
26
|
return body_data
|
26
27
|
elsif body_data.respond_to?(:to_s)
|
28
|
+
warn "WARNING: RSence::Response::ResponseBody -> body_data is not a string. It's a #{body_data.class}, with the following contents: #{body_data.inspect}" if RSence.args[:verbose]
|
27
29
|
return body_data.to_s
|
28
30
|
else
|
29
31
|
warn "Invalid response data: #{body_data.inspect[0..100]}"
|
@@ -21,204 +21,238 @@ module ClientPkgServe
|
|
21
21
|
return time.gmtime.strftime('%a, %d %b %Y %H:%M:%S %Z')
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
def get( request, response, session )
|
26
|
-
|
24
|
+
def build_busy_wait
|
27
25
|
while @build_busy
|
28
26
|
puts "-- build not finished, waiting.. --"
|
29
27
|
sleep 0.1
|
30
28
|
end
|
31
|
-
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_headers( response )
|
32
32
|
# Sets the response date header to the current time:
|
33
33
|
response['Date'] = httime( Time.now )
|
34
34
|
|
35
35
|
# Controls caching with headers based on the configuration
|
36
36
|
if ::RSence.config[:cache_maximize]
|
37
37
|
response['Expires'] = httime(Time.now+::RSence.config[:cache_expire])
|
38
|
-
|
39
38
|
else
|
40
39
|
response['Cache-Control'] = 'no-cache'
|
41
40
|
end
|
42
|
-
|
43
|
-
|
41
|
+
end
|
42
|
+
|
43
|
+
def check_ua( request )
|
44
|
+
support_gzip = (request.header.has_key?('Accept-Encoding') and request.header['Accept-Encoding'].include?('gzip'))
|
44
45
|
support_gzip = false if ::RSence.config[:no_gzip]
|
45
|
-
if request.header.has_key?('
|
46
|
-
ua = request.header['
|
46
|
+
if request.header.has_key?('User-Agent')
|
47
|
+
ua = request.header['User-Agent']
|
47
48
|
is_symbian = ua.include?("SymbianOS")
|
48
49
|
is_safari = ((not is_symbian) and ua.include?("WebKit"))
|
49
50
|
is_msie = ((not ua.include?("Opera")) and ua.include?("MSIE"))
|
50
51
|
is_msie6 = ((not ua.include?("Opera")) and ua.include?("MSIE 6.0"))
|
51
52
|
end
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
request_path = request_uri.split( '/' )
|
57
|
-
|
58
|
-
## Requested type of client resource (js/themes)
|
59
|
-
req_type = request_path[2]
|
60
|
-
|
61
|
-
if not ['js','themes'].include? req_type
|
62
|
-
req_rev = req_type
|
63
|
-
req_type = request_path[3]
|
64
|
-
request_path.delete_at(2)
|
53
|
+
if is_safari
|
54
|
+
version = ua.split( 'WebKit/' )[1].split('.')[0].to_i
|
55
|
+
else
|
56
|
+
version = 0 # not used for others
|
65
57
|
end
|
58
|
+
return {
|
59
|
+
:symbian => is_symbian,
|
60
|
+
:safari => is_safari,
|
61
|
+
:msie => is_msie,
|
62
|
+
:msie6 => is_msie6,
|
63
|
+
:version => version
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def support_gzip?( ua )
|
68
|
+
doesnt_support = ( ua[:msie6] or ua[:symbian] or (ua[:safari] and ua[:version] < 533) )
|
69
|
+
return ( not doesnt_support )
|
70
|
+
end
|
71
|
+
|
72
|
+
def serve_htc( request, response, request_path )
|
73
|
+
req_file = request_path[3]
|
66
74
|
|
67
|
-
|
68
|
-
|
69
|
-
|
75
|
+
# this file is a part of iefix, it injects calls to
|
76
|
+
# the ie rendering engine to override stupid behavior
|
77
|
+
# when changing element properties
|
78
|
+
if request_path.include?('ie_css_element.htc')
|
79
|
+
response.status = 200
|
80
|
+
response['Content-Type'] = 'text/x-component'
|
81
|
+
## Usually, we don't need it, because the client framework does calls when needed
|
82
|
+
response.body = %{<PUBLIC:COMPONENT lightWeight="true"></PUBLIC:COMPONENT>}
|
70
83
|
|
71
|
-
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
## Enable it to call iefix automatically whenever element properties are changed
|
81
|
-
#response.body = %{<PUBLIC:COMPONENT lightWeight="true">\r\n<script type="text/javascript">\r\ntry{element.attachEvent("onpropertychange",iefix.htcElementEntry);}catch(e){}\r\n</script>\r\n</PUBLIC:COMPONENT>}
|
84
|
+
## Enable it to call iefix automatically whenever element properties are changed
|
85
|
+
#response.body = %{<PUBLIC:COMPONENT lightWeight="true">\r\n<script type="text/javascript">\r\ntry{element.attachEvent("onpropertychange",iefix.htcElementEntry);}catch(e){}\r\n</script>\r\n</PUBLIC:COMPONENT>}
|
86
|
+
|
87
|
+
# this file is a part of iefix, it injects calls to
|
88
|
+
# the ie rendering engine to override stupid behavior
|
89
|
+
# when changing style properties
|
90
|
+
elsif request_path.include?('ie_css_style.htc')
|
91
|
+
response.status = 200
|
92
|
+
response['Content-Type'] = 'text/x-component'
|
82
93
|
|
83
|
-
|
84
|
-
|
85
|
-
# when changing style properties
|
86
|
-
elsif request_path.include?('ie_css_style.htc')
|
87
|
-
response.status = 200
|
88
|
-
response['Content-Type'] = 'text/x-component'
|
89
|
-
|
90
|
-
## Usually, we don't need it, because the client framework does calls when needed
|
91
|
-
response.body = %{<PUBLIC:COMPONENT lightWeight="true"></PUBLIC:COMPONENT>}
|
92
|
-
|
93
|
-
## Enable it to call iefix automatically whenever element properties are changed
|
94
|
-
#response.body = %{<PUBLIC:COMPONENT lightWeight="true">\r\n<script type="text/javascript">\r\ntry{element.attachEvent("onreadystatechange",iefix.htcStyleEntry);}catch(e){}\r\n</script>\r\n</PUBLIC:COMPONENT>}
|
94
|
+
## Usually, we don't need it, because the client framework does calls when needed
|
95
|
+
response.body = %{<PUBLIC:COMPONENT lightWeight="true"></PUBLIC:COMPONENT>}
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
97
|
+
## Enable it to call iefix automatically whenever element properties are changed
|
98
|
+
#response.body = %{<PUBLIC:COMPONENT lightWeight="true">\r\n<script type="text/javascript">\r\ntry{element.attachEvent("onreadystatechange",iefix.htcStyleEntry);}catch(e){}\r\n</script>\r\n</PUBLIC:COMPONENT>}
|
99
|
+
|
100
|
+
# Other htc requests are invalid
|
101
|
+
else
|
102
|
+
response.status = 503
|
103
|
+
response.body = '503 - Invalid Request'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def serve_js( request, response, request_path, ua )
|
108
|
+
# the file-specific identifier ('core', 'basic' etc)
|
109
|
+
req_file = request_path[3][0..-4]
|
110
|
+
|
111
|
+
if not @client_cache.js_cache.has_key?( req_file )
|
112
|
+
response.status = 404
|
113
|
+
response.body = '/* 404 - Not Found */'
|
114
|
+
else
|
104
115
|
|
116
|
+
response.status = 200
|
117
|
+
response['Content-Type'] = 'text/javascript; charset=utf-8'
|
105
118
|
|
106
|
-
#
|
107
|
-
|
119
|
+
# these browsers have issues with gzipped js content
|
120
|
+
support_gzip = support_gzip?( ua )
|
108
121
|
|
109
|
-
if
|
110
|
-
response
|
111
|
-
response
|
122
|
+
if support_gzip
|
123
|
+
#response['Transfer-Encoding'] = 'chunked,gzip'
|
124
|
+
response['Last-Modified'] = @client_cache.last_modified
|
125
|
+
body = @client_cache.gz_cache[ req_file ]+"\r\n\r\n"
|
126
|
+
response['Content-Length'] = body.bytesize.to_s
|
127
|
+
response['Content-Encoding'] = 'gzip'
|
128
|
+
response.body = body
|
112
129
|
else
|
113
130
|
|
114
|
-
response
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
support_gzip = false if (is_safari or is_msie or is_symbian)
|
131
|
+
response['Last-Modified'] = @client_cache.last_modified
|
132
|
+
body = @client_cache.js_cache[ req_file ]
|
133
|
+
response['Content-Length'] = body.bytesize.to_s
|
134
|
+
response.body = body
|
119
135
|
|
120
|
-
if support_gzip
|
121
|
-
#response['Transfer-Encoding'] = 'chunked,gzip'
|
122
|
-
response['Last-Modified'] = @client_cache.last_modified
|
123
|
-
body = @client_cache.gz_cache[ req_file ]+"\r\n\r\n"
|
124
|
-
response['Content-Length'] = body.bytesize.to_s
|
125
|
-
response['Content-Encoding'] = 'gzip'
|
126
|
-
response.body = body
|
127
|
-
else
|
128
|
-
|
129
|
-
response['Last-Modified'] = @client_cache.last_modified
|
130
|
-
body = @client_cache.js_cache[ req_file ]
|
131
|
-
response['Content-Length'] = body.bytesize.to_s
|
132
|
-
response.body = body
|
133
|
-
|
134
|
-
end
|
135
136
|
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def serve_theme( request, response, request_path, ua )
|
141
|
+
# Get the name of the theme
|
142
|
+
theme_name = request_path[3]
|
136
143
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
144
|
+
# Get the theme resource type (html/css/gfx)
|
145
|
+
theme_part = request_path[4].to_sym
|
146
|
+
|
147
|
+
# Get the theme resource identifier
|
148
|
+
req_file = request_path[5]
|
149
|
+
|
150
|
+
# checks for theme name
|
151
|
+
has_theme = @client_cache.theme_cache.has_key?( theme_name )
|
152
|
+
|
153
|
+
# checks for theme part (css/html/gfx)
|
154
|
+
has_theme_part = ( has_theme and @client_cache.theme_cache[theme_name].has_key?( theme_part ) )
|
155
|
+
|
156
|
+
# checks for theme file
|
157
|
+
has_theme_file = ( has_theme_part and @client_cache.theme_cache[theme_name][theme_part].has_key?( req_file ) )
|
158
|
+
|
159
|
+
if not has_theme_file and req_file == 'common.css'
|
160
|
+
response.status = 200
|
161
|
+
response['Content-Type'] = 'text/css'
|
162
|
+
response.body = ''
|
163
|
+
end
|
164
|
+
|
165
|
+
if not has_theme
|
166
|
+
response.status = 404
|
167
|
+
response.body = '404 - Theme Not Found'
|
168
|
+
puts "Theme #{theme_name} not found, avail: #{@client_cache.theme_cache.keys.join(', ')}" if RSence.args[:verbose]
|
169
|
+
elsif not has_theme_part
|
170
|
+
response.status = 503
|
171
|
+
response.body = '503 - Invalid Theme Part Request'
|
172
|
+
elsif not has_theme_file
|
173
|
+
response.status = 404
|
174
|
+
response.body = '404 - Theme Resource Not Found'
|
175
|
+
puts "File not found, avail: #{@client_cache.theme_cache[theme_name][theme_part].keys.join(', ')}" if RSence.args[:verbose]
|
176
|
+
else
|
155
177
|
|
156
|
-
|
157
|
-
# checks for theme file
|
158
|
-
has_theme_file = has_theme_part and @client_cache.theme_cache[theme_name][theme_part].has_key?( req_file )
|
178
|
+
response.status = 200
|
159
179
|
|
180
|
+
file_ext = req_file.split('.')[-1]
|
181
|
+
response['Content-Type'] = {
|
182
|
+
'html' => 'text/html; charset=utf-8',
|
183
|
+
'css' => 'text/css; charset=utf-8',
|
184
|
+
'png' => 'image/png',
|
185
|
+
'jpg' => 'image/jpeg',
|
186
|
+
'gif' => 'image/gif',
|
187
|
+
'swf' => 'application/x-shockwave-flash'
|
188
|
+
}[file_ext]
|
160
189
|
|
161
|
-
if
|
162
|
-
|
163
|
-
|
164
|
-
|
190
|
+
if theme_part == :gfx
|
191
|
+
support_gzip = false
|
192
|
+
else
|
193
|
+
support_gzip = support_gzip?( ua )
|
165
194
|
end
|
166
195
|
|
167
|
-
if
|
168
|
-
response
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
response.
|
173
|
-
response.body = '503 - Invalid Theme Part Request'
|
174
|
-
elsif not has_theme_file
|
175
|
-
response.status = 404
|
176
|
-
response.body = '404 - Theme Resource Not Found'
|
177
|
-
puts "File not found, avail: #{@client_cache.theme_cache[theme_name][theme_part].keys.join(', ')}" if RSence.args[:verbose]
|
196
|
+
if support_gzip
|
197
|
+
response['Last-Modified'] = @client_cache.last_modified
|
198
|
+
body = @client_cache.theme_cache[theme_name][theme_part][ req_file+'.gz' ]
|
199
|
+
response['Content-Length'] = body.bytesize.to_s
|
200
|
+
response['Content-Encoding'] = 'gzip'
|
201
|
+
response.body = body
|
178
202
|
else
|
179
203
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
'css' => 'text/css; charset=utf-8',
|
186
|
-
'png' => 'image/png',
|
187
|
-
'jpg' => 'image/jpeg',
|
188
|
-
'gif' => 'image/gif',
|
189
|
-
'swf' => 'application/x-shockwave-flash'
|
190
|
-
}[file_ext]
|
191
|
-
|
192
|
-
support_gzip = false if theme_part == :gfx
|
193
|
-
support_gzip = false if (is_safari or is_msie or is_symbian)
|
194
|
-
|
195
|
-
if support_gzip
|
196
|
-
response['Last-Modified'] = @client_cache.last_modified
|
197
|
-
body = @client_cache.theme_cache[theme_name][theme_part][ req_file+'.gz' ]
|
198
|
-
response['Content-Length'] = body.bytesize.to_s
|
199
|
-
response['Content-Encoding'] = 'gzip'
|
200
|
-
response.body = body
|
201
|
-
else
|
202
|
-
|
203
|
-
# Special IE6 condition to serve gifs instead of png's, because it works much better
|
204
|
-
# than using the ActiveX alpha filter hack
|
205
|
-
if is_msie6 and req_file[-4..-1] == '.png'
|
206
|
-
ie6_req_png2gif = req_file.gsub('.png','-ie6.gif')
|
207
|
-
req_file = ie6_req_png2gif if @client_cache.theme_cache[theme_name][theme_part].include?(ie6_req_png2gif)
|
208
|
-
end
|
209
|
-
|
210
|
-
response['Last-Modified'] = @client_cache.last_modified
|
211
|
-
body = @client_cache.theme_cache[theme_name][theme_part][ req_file ]
|
212
|
-
if body.nil?
|
213
|
-
warn "ClientPkgServe#get: empty body for #{request.path}"
|
214
|
-
body = ''
|
215
|
-
end
|
216
|
-
response['Content-Length'] = body.bytesize.to_s
|
217
|
-
response.body = body
|
218
|
-
|
204
|
+
# Special IE6 condition to serve gifs instead of png's, because it works much better
|
205
|
+
# than using the ActiveX alpha filter hack
|
206
|
+
if ua[:msie6] and req_file[-4..-1] == '.png'
|
207
|
+
ie6_req_png2gif = req_file.gsub('.png','-ie6.gif')
|
208
|
+
req_file = ie6_req_png2gif if @client_cache.theme_cache[theme_name][theme_part].include?(ie6_req_png2gif)
|
219
209
|
end
|
220
|
-
end
|
221
210
|
|
211
|
+
response['Last-Modified'] = @client_cache.last_modified
|
212
|
+
body = @client_cache.theme_cache[theme_name][theme_part][ req_file ]
|
213
|
+
if body.nil?
|
214
|
+
warn "ClientPkgServe#get: empty body for #{request.path}"
|
215
|
+
body = ''
|
216
|
+
end
|
217
|
+
response['Content-Length'] = body.bytesize.to_s
|
218
|
+
response.body = body
|
219
|
+
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
## Responds to get-requests
|
225
|
+
def get( request, response, session )
|
226
|
+
|
227
|
+
build_busy_wait
|
228
|
+
|
229
|
+
ua = check_ua( request )
|
230
|
+
|
231
|
+
set_headers( response )
|
232
|
+
|
233
|
+
## Split path into an array for determining what to serve
|
234
|
+
request_uri = '/'+request.path.match( /^#{::RSence.config[:broker_urls][:h]}(.*)$/ )[1]
|
235
|
+
|
236
|
+
request_path = request_uri.split( '/' )
|
237
|
+
|
238
|
+
## Requested type of client resource (js/themes)
|
239
|
+
req_type = request_path[2]
|
240
|
+
|
241
|
+
unless ['js','themes'].include? req_type
|
242
|
+
req_rev = req_type
|
243
|
+
req_type = request_path[3]
|
244
|
+
request_path.delete_at(2)
|
245
|
+
end
|
246
|
+
|
247
|
+
## Special rules for the special browser
|
248
|
+
if request.path.end_with?('.htc')
|
249
|
+
serve_htc( request, response, request_path )
|
250
|
+
## Serve compiled client javascript component files:
|
251
|
+
elsif req_type == 'js'
|
252
|
+
serve_js( request, response, request_path, ua )
|
253
|
+
## Serve client theme files
|
254
|
+
elsif req_type == 'themes'
|
255
|
+
serve_theme( request, response, request_path, ua )
|
222
256
|
end
|
223
257
|
|
224
258
|
end
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
class: RSence.GUIApp
|
19
19
|
# Each class takes a number of options for its constructor.
|
20
20
|
options:
|
21
|
-
|
21
|
+
label: Welcome App
|
22
22
|
# The subviews use the class defined above as their parent component.
|
23
23
|
subviews:
|
24
24
|
# The sheet is used as the main visual container for the gui in this app.
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rsence
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 2.1.
|
9
|
+
- 8
|
10
|
+
version: 2.1.8
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Riassence Inc.
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-01-
|
18
|
+
date: 2011-01-28 00:00:00 +02:00
|
19
19
|
default_executable: rsence
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -403,7 +403,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
403
403
|
requirements: []
|
404
404
|
|
405
405
|
rubyforge_project: rsence-
|
406
|
-
rubygems_version: 1.4.
|
406
|
+
rubygems_version: 1.4.2
|
407
407
|
signing_key:
|
408
408
|
specification_version: 3
|
409
409
|
summary: Release 2.1 version of the RSence framework.
|