spiderfw 0.5.3 → 0.5.4
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/apps/core/components/public/js/jquery/plugins/asmselect/jquery.asmselect.css +64 -0
- data/apps/core/components/public/js/jquery/plugins/asmselect/jquery.asmselect.js +407 -0
- data/apps/core/components/public/js/jquery/plugins/autogrow/jquery.autogrow.js +132 -0
- data/apps/core/components/widgets/admin/admin.rb +1 -0
- data/apps/core/components/widgets/admin/admin.shtml +1 -1
- data/apps/core/components/widgets/list/list.rb +1 -1
- data/apps/core/forms/public/select.js +8 -0
- data/apps/core/forms/public/text_area.js +8 -0
- data/apps/core/forms/widgets/inputs/select/select.rb +0 -11
- data/apps/core/forms/widgets/inputs/select/select.shtml +2 -0
- data/apps/core/forms/widgets/inputs/text_area/text_area.rb +1 -1
- data/apps/core/forms/widgets/inputs/text_area/text_area.shtml +2 -1
- data/lib/spiderfw/cmd/commands/test.rb +0 -5
- data/lib/spiderfw/cmd/commands/webserver.rb +6 -2
- data/lib/spiderfw/controller/session/memory_session.rb +18 -19
- data/lib/spiderfw/model/base_model.rb +13 -0
- data/lib/spiderfw/model/identity_mapper.rb +3 -1
- data/lib/spiderfw/model/storage/db/adapters/oci8.rb +2 -2
- data/lib/spiderfw/model/storage/db/db_connection_pool.rb +54 -9
- data/spider.gemspec +2 -2
- metadata +7 -3
@@ -0,0 +1,64 @@
|
|
1
|
+
.asmContainer {
|
2
|
+
/* container that surrounds entire asmSelect widget */
|
3
|
+
}
|
4
|
+
|
5
|
+
.asmSelect {
|
6
|
+
/* the newly created regular 'select' */
|
7
|
+
display: inline;
|
8
|
+
}
|
9
|
+
|
10
|
+
.asmOptionDisabled {
|
11
|
+
/* disabled options in new select */
|
12
|
+
color: #999;
|
13
|
+
}
|
14
|
+
|
15
|
+
.asmHighlight {
|
16
|
+
/* the highlight span */
|
17
|
+
padding: 0;
|
18
|
+
margin: 0 0 0 1em;
|
19
|
+
}
|
20
|
+
|
21
|
+
.asmList {
|
22
|
+
/* html list that contains selected items */
|
23
|
+
margin: 1em 8em 2em 8em;
|
24
|
+
position: relative;
|
25
|
+
display: block;
|
26
|
+
padding-left: 0;
|
27
|
+
list-style: none;
|
28
|
+
clear: both;
|
29
|
+
}
|
30
|
+
|
31
|
+
.asmListItem {
|
32
|
+
/* li item from the html list above */
|
33
|
+
position: relative;
|
34
|
+
margin-left: 0;
|
35
|
+
padding-left: 0;
|
36
|
+
list-style: none;
|
37
|
+
background: #ddd;
|
38
|
+
border: 1px solid #bbb;
|
39
|
+
width: 100%;
|
40
|
+
margin: 0 0 -1px 0;
|
41
|
+
line-height: 1em;
|
42
|
+
}
|
43
|
+
|
44
|
+
.asmListItem:hover {
|
45
|
+
background-color: #e5e5e5;
|
46
|
+
}
|
47
|
+
|
48
|
+
.asmListItemLabel {
|
49
|
+
/* this is a span that surrounds the text in the item, except for the remove link */
|
50
|
+
padding: 5px;
|
51
|
+
display: block;
|
52
|
+
}
|
53
|
+
|
54
|
+
.asmListSortable .asmListItemLabel {
|
55
|
+
cursor: move;
|
56
|
+
}
|
57
|
+
|
58
|
+
.asmListItemRemove {
|
59
|
+
/* the remove link in each list item */
|
60
|
+
position: absolute;
|
61
|
+
right: 0;
|
62
|
+
top: 0;
|
63
|
+
padding: 5px;
|
64
|
+
}
|
@@ -0,0 +1,407 @@
|
|
1
|
+
/*
|
2
|
+
* Alternate Select Multiple (asmSelect) 1.0.4a beta - jQuery Plugin
|
3
|
+
* http://www.ryancramer.com/projects/asmselect/
|
4
|
+
*
|
5
|
+
* Copyright (c) 2009 by Ryan Cramer - http://www.ryancramer.com
|
6
|
+
*
|
7
|
+
* Dual licensed under the MIT (MIT-LICENSE.txt)
|
8
|
+
* and GPL (GPL-LICENSE.txt) licenses.
|
9
|
+
*
|
10
|
+
*/
|
11
|
+
|
12
|
+
(function($) {
|
13
|
+
|
14
|
+
$.fn.asmSelect = function(customOptions) {
|
15
|
+
|
16
|
+
var options = {
|
17
|
+
|
18
|
+
listType: 'ol', // Ordered list 'ol', or unordered list 'ul'
|
19
|
+
sortable: false, // Should the list be sortable?
|
20
|
+
highlight: false, // Use the highlight feature?
|
21
|
+
animate: false, // Animate the the adding/removing of items in the list?
|
22
|
+
addItemTarget: 'bottom', // Where to place new selected items in list: top or bottom
|
23
|
+
hideWhenAdded: false, // Hide the option when added to the list? works only in FF
|
24
|
+
debugMode: false, // Debug mode keeps original select visible
|
25
|
+
|
26
|
+
removeLabel: 'remove', // Text used in the "remove" link
|
27
|
+
highlightAddedLabel: 'Added: ', // Text that precedes highlight of added item
|
28
|
+
highlightRemovedLabel: 'Removed: ', // Text that precedes highlight of removed item
|
29
|
+
|
30
|
+
containerClass: 'asmContainer', // Class for container that wraps this widget
|
31
|
+
selectClass: 'asmSelect', // Class for the newly created <select>
|
32
|
+
optionDisabledClass: 'asmOptionDisabled', // Class for items that are already selected / disabled
|
33
|
+
listClass: 'asmList', // Class for the list ($ol)
|
34
|
+
listSortableClass: 'asmListSortable', // Another class given to the list when it is sortable
|
35
|
+
listItemClass: 'asmListItem', // Class for the <li> list items
|
36
|
+
listItemLabelClass: 'asmListItemLabel', // Class for the label text that appears in list items
|
37
|
+
removeClass: 'asmListItemRemove', // Class given to the "remove" link
|
38
|
+
highlightClass: 'asmHighlight' // Class given to the highlight <span>
|
39
|
+
|
40
|
+
};
|
41
|
+
|
42
|
+
$.extend(options, customOptions);
|
43
|
+
|
44
|
+
return this.each(function(index) {
|
45
|
+
|
46
|
+
var $original = $(this); // the original select multiple
|
47
|
+
var $container; // a container that is wrapped around our widget
|
48
|
+
var $select; // the new select we have created
|
49
|
+
var $ol; // the list that we are manipulating
|
50
|
+
var buildingSelect = false; // is the new select being constructed right now?
|
51
|
+
var ieClick = false; // in IE, has a click event occurred? ignore if not
|
52
|
+
var ignoreOriginalChangeEvent = false; // originalChangeEvent bypassed when this is true
|
53
|
+
|
54
|
+
function init() {
|
55
|
+
|
56
|
+
// initialize the alternate select multiple
|
57
|
+
|
58
|
+
// this loop ensures uniqueness, in case of existing asmSelects placed by ajax (1.0.3)
|
59
|
+
while($("#" + options.containerClass + index).size() > 0) index++;
|
60
|
+
|
61
|
+
$select = $("<select></select>")
|
62
|
+
.addClass(options.selectClass)
|
63
|
+
.attr('name', options.selectClass + index)
|
64
|
+
.attr('id', options.selectClass + index);
|
65
|
+
|
66
|
+
$selectRemoved = $("<select></select>");
|
67
|
+
|
68
|
+
$ol = $("<" + options.listType + "></" + options.listType + ">")
|
69
|
+
.addClass(options.listClass)
|
70
|
+
.attr('id', options.listClass + index);
|
71
|
+
|
72
|
+
$container = $("<div></div>")
|
73
|
+
.addClass(options.containerClass)
|
74
|
+
.attr('id', options.containerClass + index);
|
75
|
+
|
76
|
+
buildSelect();
|
77
|
+
|
78
|
+
$select.change(selectChangeEvent)
|
79
|
+
.click(selectClickEvent);
|
80
|
+
|
81
|
+
$original.change(originalChangeEvent)
|
82
|
+
.wrap($container).before($select).before($ol);
|
83
|
+
|
84
|
+
if(options.sortable) makeSortable();
|
85
|
+
|
86
|
+
if($.browser.msie && $.browser.version < 8) $ol.css('display', 'inline-block'); // Thanks Matthew Hutton
|
87
|
+
}
|
88
|
+
|
89
|
+
function makeSortable() {
|
90
|
+
|
91
|
+
// make any items in the selected list sortable
|
92
|
+
// requires jQuery UI sortables, draggables, droppables
|
93
|
+
|
94
|
+
$ol.sortable({
|
95
|
+
items: 'li.' + options.listItemClass,
|
96
|
+
handle: '.' + options.listItemLabelClass,
|
97
|
+
axis: 'y',
|
98
|
+
update: function(e, data) {
|
99
|
+
|
100
|
+
var updatedOptionId;
|
101
|
+
|
102
|
+
$(this).children("li").each(function(n) {
|
103
|
+
|
104
|
+
$option = $('#' + $(this).attr('rel'));
|
105
|
+
|
106
|
+
if($(this).is(".ui-sortable-helper")) {
|
107
|
+
updatedOptionId = $option.attr('id');
|
108
|
+
return;
|
109
|
+
}
|
110
|
+
|
111
|
+
$original.append($option);
|
112
|
+
});
|
113
|
+
|
114
|
+
if(updatedOptionId) triggerOriginalChange(updatedOptionId, 'sort');
|
115
|
+
}
|
116
|
+
|
117
|
+
}).addClass(options.listSortableClass);
|
118
|
+
}
|
119
|
+
|
120
|
+
function selectChangeEvent(e) {
|
121
|
+
|
122
|
+
// an item has been selected on the regular select we created
|
123
|
+
// check to make sure it's not an IE screwup, and add it to the list
|
124
|
+
|
125
|
+
if($.browser.msie && $.browser.version < 7 && !ieClick) return;
|
126
|
+
var id = $(this).children("option:selected").slice(0,1).attr('rel');
|
127
|
+
addListItem(id);
|
128
|
+
ieClick = false;
|
129
|
+
triggerOriginalChange(id, 'add'); // for use by user-defined callbacks
|
130
|
+
}
|
131
|
+
|
132
|
+
function selectClickEvent() {
|
133
|
+
|
134
|
+
// IE6 lets you scroll around in a select without it being pulled down
|
135
|
+
// making sure a click preceded the change() event reduces the chance
|
136
|
+
// if unintended items being added. there may be a better solution?
|
137
|
+
|
138
|
+
ieClick = true;
|
139
|
+
}
|
140
|
+
|
141
|
+
function originalChangeEvent(e) {
|
142
|
+
|
143
|
+
// select or option change event manually triggered
|
144
|
+
// on the original <select multiple>, so rebuild ours
|
145
|
+
|
146
|
+
if(ignoreOriginalChangeEvent) {
|
147
|
+
ignoreOriginalChangeEvent = false;
|
148
|
+
return;
|
149
|
+
}
|
150
|
+
|
151
|
+
$select.empty();
|
152
|
+
$ol.empty();
|
153
|
+
buildSelect();
|
154
|
+
|
155
|
+
// opera has an issue where it needs a force redraw, otherwise
|
156
|
+
// the items won't appear until something else forces a redraw
|
157
|
+
if($.browser.opera) $ol.hide().fadeIn("fast");
|
158
|
+
}
|
159
|
+
|
160
|
+
function buildSelect() {
|
161
|
+
|
162
|
+
// build or rebuild the new select that the user
|
163
|
+
// will select items from
|
164
|
+
|
165
|
+
buildingSelect = true;
|
166
|
+
|
167
|
+
// add a first option to be the home option / default selectLabel
|
168
|
+
$select.prepend("<option>" + $original.attr('title') + "</option>");
|
169
|
+
|
170
|
+
$original.children("option").each(function(n) {
|
171
|
+
|
172
|
+
var $t = $(this);
|
173
|
+
var id;
|
174
|
+
|
175
|
+
if(!$t.attr('id')) $t.attr('id', 'asm' + index + 'option' + n);
|
176
|
+
id = $t.attr('id');
|
177
|
+
|
178
|
+
if($t.is(":selected")) {
|
179
|
+
addListItem(id);
|
180
|
+
addSelectOption(id, true);
|
181
|
+
} else {
|
182
|
+
addSelectOption(id);
|
183
|
+
}
|
184
|
+
});
|
185
|
+
|
186
|
+
if(!options.debugMode) $original.hide(); // IE6 requires this on every buildSelect()
|
187
|
+
selectFirstItem();
|
188
|
+
buildingSelect = false;
|
189
|
+
}
|
190
|
+
|
191
|
+
function addSelectOption(optionId, disabled) {
|
192
|
+
|
193
|
+
// add an <option> to the <select>
|
194
|
+
// used only by buildSelect()
|
195
|
+
|
196
|
+
if(disabled == undefined) var disabled = false;
|
197
|
+
|
198
|
+
var $O = $('#' + optionId);
|
199
|
+
var $option = $("<option>" + $O.text() + "</option>")
|
200
|
+
.val($O.val())
|
201
|
+
.attr('rel', optionId);
|
202
|
+
|
203
|
+
if(disabled) disableSelectOption($option);
|
204
|
+
|
205
|
+
$select.append($option);
|
206
|
+
}
|
207
|
+
|
208
|
+
function selectFirstItem() {
|
209
|
+
|
210
|
+
// select the firm item from the regular select that we created
|
211
|
+
|
212
|
+
$select.children(":eq(0)").attr("selected", true);
|
213
|
+
}
|
214
|
+
|
215
|
+
function disableSelectOption($option) {
|
216
|
+
|
217
|
+
// make an option disabled, indicating that it's already been selected
|
218
|
+
// because safari is the only browser that makes disabled items look 'disabled'
|
219
|
+
// we apply a class that reproduces the disabled look in other browsers
|
220
|
+
|
221
|
+
$option.addClass(options.optionDisabledClass)
|
222
|
+
.attr("selected", false)
|
223
|
+
.attr("disabled", true);
|
224
|
+
|
225
|
+
if(options.hideWhenAdded) $option.hide();
|
226
|
+
if($.browser.msie) $select.hide().show(); // this forces IE to update display
|
227
|
+
}
|
228
|
+
|
229
|
+
function enableSelectOption($option) {
|
230
|
+
|
231
|
+
// given an already disabled select option, enable it
|
232
|
+
|
233
|
+
$option.removeClass(options.optionDisabledClass)
|
234
|
+
.attr("disabled", false);
|
235
|
+
|
236
|
+
if(options.hideWhenAdded) $option.show();
|
237
|
+
if($.browser.msie) $select.hide().show(); // this forces IE to update display
|
238
|
+
}
|
239
|
+
|
240
|
+
function addListItem(optionId) {
|
241
|
+
|
242
|
+
// add a new item to the html list
|
243
|
+
|
244
|
+
var $O = $('#' + optionId);
|
245
|
+
|
246
|
+
if(!$O) return; // this is the first item, selectLabel
|
247
|
+
|
248
|
+
var $removeLink = $("<a></a>")
|
249
|
+
.attr("href", "#")
|
250
|
+
.addClass(options.removeClass)
|
251
|
+
.prepend(options.removeLabel)
|
252
|
+
.click(function() {
|
253
|
+
dropListItem($(this).parent('li').attr('rel'));
|
254
|
+
return false;
|
255
|
+
});
|
256
|
+
|
257
|
+
var $itemLabel = $("<span></span>")
|
258
|
+
.addClass(options.listItemLabelClass)
|
259
|
+
.html($O.html());
|
260
|
+
|
261
|
+
var $item = $("<li></li>")
|
262
|
+
.attr('rel', optionId)
|
263
|
+
.addClass(options.listItemClass)
|
264
|
+
.append($itemLabel)
|
265
|
+
.append($removeLink)
|
266
|
+
.hide();
|
267
|
+
|
268
|
+
if(!buildingSelect) {
|
269
|
+
if($O.is(":selected")) return; // already have it
|
270
|
+
$O.attr('selected', true);
|
271
|
+
}
|
272
|
+
|
273
|
+
if(options.addItemTarget == 'top' && !buildingSelect) {
|
274
|
+
$ol.prepend($item);
|
275
|
+
if(options.sortable) $original.prepend($O);
|
276
|
+
} else {
|
277
|
+
$ol.append($item);
|
278
|
+
if(options.sortable) $original.append($O);
|
279
|
+
}
|
280
|
+
|
281
|
+
addListItemShow($item);
|
282
|
+
|
283
|
+
disableSelectOption($("[rel=" + optionId + "]", $select));
|
284
|
+
|
285
|
+
if(!buildingSelect) {
|
286
|
+
setHighlight($item, options.highlightAddedLabel);
|
287
|
+
selectFirstItem();
|
288
|
+
if(options.sortable) $ol.sortable("refresh");
|
289
|
+
}
|
290
|
+
|
291
|
+
}
|
292
|
+
|
293
|
+
function addListItemShow($item) {
|
294
|
+
|
295
|
+
// reveal the currently hidden item with optional animation
|
296
|
+
// used only by addListItem()
|
297
|
+
|
298
|
+
if(options.animate && !buildingSelect) {
|
299
|
+
$item.animate({
|
300
|
+
opacity: "show",
|
301
|
+
height: "show"
|
302
|
+
}, 100, "swing", function() {
|
303
|
+
$item.animate({
|
304
|
+
height: "+=2px"
|
305
|
+
}, 50, "swing", function() {
|
306
|
+
$item.animate({
|
307
|
+
height: "-=2px"
|
308
|
+
}, 25, "swing");
|
309
|
+
});
|
310
|
+
});
|
311
|
+
} else {
|
312
|
+
$item.show();
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
316
|
+
function dropListItem(optionId, highlightItem) {
|
317
|
+
|
318
|
+
// remove an item from the html list
|
319
|
+
|
320
|
+
if(highlightItem == undefined) var highlightItem = true;
|
321
|
+
var $O = $('#' + optionId);
|
322
|
+
|
323
|
+
$O.attr('selected', false);
|
324
|
+
$item = $ol.children("li[rel=" + optionId + "]");
|
325
|
+
|
326
|
+
dropListItemHide($item);
|
327
|
+
enableSelectOption($("[rel=" + optionId + "]", options.removeWhenAdded ? $selectRemoved : $select));
|
328
|
+
|
329
|
+
if(highlightItem) setHighlight($item, options.highlightRemovedLabel);
|
330
|
+
|
331
|
+
triggerOriginalChange(optionId, 'drop');
|
332
|
+
|
333
|
+
}
|
334
|
+
|
335
|
+
function dropListItemHide($item) {
|
336
|
+
|
337
|
+
// remove the currently visible item with optional animation
|
338
|
+
// used only by dropListItem()
|
339
|
+
|
340
|
+
if(options.animate && !buildingSelect) {
|
341
|
+
|
342
|
+
$prevItem = $item.prev("li");
|
343
|
+
|
344
|
+
$item.animate({
|
345
|
+
opacity: "hide",
|
346
|
+
height: "hide"
|
347
|
+
}, 100, "linear", function() {
|
348
|
+
$prevItem.animate({
|
349
|
+
height: "-=2px"
|
350
|
+
}, 50, "swing", function() {
|
351
|
+
$prevItem.animate({
|
352
|
+
height: "+=2px"
|
353
|
+
}, 100, "swing");
|
354
|
+
});
|
355
|
+
$item.remove();
|
356
|
+
});
|
357
|
+
|
358
|
+
} else {
|
359
|
+
$item.remove();
|
360
|
+
}
|
361
|
+
}
|
362
|
+
|
363
|
+
function setHighlight($item, label) {
|
364
|
+
|
365
|
+
// set the contents of the highlight area that appears
|
366
|
+
// directly after the <select> single
|
367
|
+
// fade it in quickly, then fade it out
|
368
|
+
|
369
|
+
if(!options.highlight) return;
|
370
|
+
|
371
|
+
$select.next("#" + options.highlightClass + index).remove();
|
372
|
+
|
373
|
+
var $highlight = $("<span></span>")
|
374
|
+
.hide()
|
375
|
+
.addClass(options.highlightClass)
|
376
|
+
.attr('id', options.highlightClass + index)
|
377
|
+
.html(label + $item.children("." + options.listItemLabelClass).slice(0,1).text());
|
378
|
+
|
379
|
+
$select.after($highlight);
|
380
|
+
|
381
|
+
$highlight.fadeIn("fast", function() {
|
382
|
+
setTimeout(function() { $highlight.fadeOut("slow"); }, 50);
|
383
|
+
});
|
384
|
+
}
|
385
|
+
|
386
|
+
function triggerOriginalChange(optionId, type) {
|
387
|
+
|
388
|
+
// trigger a change event on the original select multiple
|
389
|
+
// so that other scripts can pick them up
|
390
|
+
|
391
|
+
ignoreOriginalChangeEvent = true;
|
392
|
+
$option = $("#" + optionId);
|
393
|
+
|
394
|
+
$original.trigger('change', [{
|
395
|
+
'option': $option,
|
396
|
+
'value': $option.val(),
|
397
|
+
'id': optionId,
|
398
|
+
'item': $ol.children("[rel=" + optionId + "]"),
|
399
|
+
'type': type
|
400
|
+
}]);
|
401
|
+
}
|
402
|
+
|
403
|
+
init();
|
404
|
+
});
|
405
|
+
};
|
406
|
+
|
407
|
+
})(jQuery);
|
@@ -0,0 +1,132 @@
|
|
1
|
+
/*
|
2
|
+
* Auto Expanding Text Area (1.2.2)
|
3
|
+
* by Chrys Bader (www.chrysbader.com)
|
4
|
+
* chrysb@gmail.com
|
5
|
+
*
|
6
|
+
* Special thanks to:
|
7
|
+
* Jake Chapa - jake@hybridstudio.com
|
8
|
+
* John Resig - jeresig@gmail.com
|
9
|
+
*
|
10
|
+
* Copyright (c) 2008 Chrys Bader (www.chrysbader.com)
|
11
|
+
* Licensed under the GPL (GPL-LICENSE.txt) license.
|
12
|
+
*
|
13
|
+
*
|
14
|
+
* NOTE: This script requires jQuery to work. Download jQuery at www.jquery.com
|
15
|
+
*
|
16
|
+
*/
|
17
|
+
|
18
|
+
(function(jQuery) {
|
19
|
+
|
20
|
+
var self = null;
|
21
|
+
|
22
|
+
jQuery.fn.autogrow = function(o)
|
23
|
+
{
|
24
|
+
return this.each(function() {
|
25
|
+
new jQuery.autogrow(this, o);
|
26
|
+
});
|
27
|
+
};
|
28
|
+
|
29
|
+
|
30
|
+
/**
|
31
|
+
* The autogrow object.
|
32
|
+
*
|
33
|
+
* @constructor
|
34
|
+
* @name jQuery.autogrow
|
35
|
+
* @param Object e The textarea to create the autogrow for.
|
36
|
+
* @param Hash o A set of key/value pairs to set as configuration properties.
|
37
|
+
* @cat Plugins/autogrow
|
38
|
+
*/
|
39
|
+
|
40
|
+
jQuery.autogrow = function (e, o)
|
41
|
+
{
|
42
|
+
this.options = o || {};
|
43
|
+
this.dummy = null;
|
44
|
+
this.interval = null;
|
45
|
+
this.line_height = this.options.lineHeight || parseInt(jQuery(e).css('line-height'));
|
46
|
+
this.min_height = this.options.minHeight || parseInt(jQuery(e).css('min-height'));
|
47
|
+
this.max_height = this.options.maxHeight || parseInt(jQuery(e).css('max-height'));;
|
48
|
+
this.textarea = jQuery(e);
|
49
|
+
|
50
|
+
if(this.line_height == NaN)
|
51
|
+
this.line_height = 0;
|
52
|
+
|
53
|
+
// Only one textarea activated at a time, the one being used
|
54
|
+
this.init();
|
55
|
+
};
|
56
|
+
|
57
|
+
jQuery.autogrow.fn = jQuery.autogrow.prototype = {
|
58
|
+
autogrow: '1.2.2'
|
59
|
+
};
|
60
|
+
|
61
|
+
jQuery.autogrow.fn.extend = jQuery.autogrow.extend = jQuery.extend;
|
62
|
+
|
63
|
+
jQuery.autogrow.fn.extend({
|
64
|
+
|
65
|
+
init: function() {
|
66
|
+
var self = this;
|
67
|
+
this.textarea.css({overflow: 'hidden', display: 'block'});
|
68
|
+
this.textarea.bind('focus', function() { self.startExpand() } ).bind('blur', function() { self.stopExpand() });
|
69
|
+
this.checkExpand();
|
70
|
+
},
|
71
|
+
|
72
|
+
startExpand: function() {
|
73
|
+
var self = this;
|
74
|
+
this.interval = window.setInterval(function() {self.checkExpand()}, 400);
|
75
|
+
},
|
76
|
+
|
77
|
+
stopExpand: function() {
|
78
|
+
clearInterval(this.interval);
|
79
|
+
},
|
80
|
+
|
81
|
+
checkExpand: function() {
|
82
|
+
|
83
|
+
if (this.dummy == null)
|
84
|
+
{
|
85
|
+
this.dummy = jQuery('<div></div>');
|
86
|
+
this.dummy.css({
|
87
|
+
'font-size' : this.textarea.css('font-size'),
|
88
|
+
'font-family': this.textarea.css('font-family'),
|
89
|
+
'width' : this.textarea.css('width'),
|
90
|
+
'padding' : this.textarea.css('padding'),
|
91
|
+
'line-height': this.line_height + 'px',
|
92
|
+
'overflow-x' : 'hidden',
|
93
|
+
'position' : 'absolute',
|
94
|
+
'top' : 0,
|
95
|
+
'left' : -9999
|
96
|
+
}).appendTo('body');
|
97
|
+
}
|
98
|
+
|
99
|
+
// Strip HTML tags
|
100
|
+
var html = this.textarea.val().replace(/(<|>)/g, '');
|
101
|
+
|
102
|
+
// IE is different, as per usual
|
103
|
+
if ($.browser.msie)
|
104
|
+
{
|
105
|
+
html = html.replace(/\n/g, '<BR>new');
|
106
|
+
}
|
107
|
+
else
|
108
|
+
{
|
109
|
+
html = html.replace(/\n/g, '<br>new');
|
110
|
+
}
|
111
|
+
|
112
|
+
if (this.dummy.html() != html)
|
113
|
+
{
|
114
|
+
this.dummy.html(html);
|
115
|
+
|
116
|
+
if (this.max_height > 0 && (this.dummy.height() + this.line_height > this.max_height))
|
117
|
+
{
|
118
|
+
this.textarea.css('overflow-y', 'auto');
|
119
|
+
}
|
120
|
+
else
|
121
|
+
{
|
122
|
+
this.textarea.css('overflow-y', 'hidden');
|
123
|
+
if (this.textarea.height() < this.dummy.height() + this.line_height || (this.dummy.height() < this.textarea.height()))
|
124
|
+
{
|
125
|
+
this.textarea.animate({height: (this.dummy.height() + this.line_height) + 'px'}, 100);
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
});
|
132
|
+
})(jQuery);
|
@@ -229,7 +229,7 @@ module Spider; module Components
|
|
229
229
|
def parse_runtime_content(doc, src_path='')
|
230
230
|
doc = super
|
231
231
|
return doc if doc.children.empty?
|
232
|
-
doc.root.
|
232
|
+
doc.root.children_of_type('sublist').each do |sl|
|
233
233
|
raise ArgumentError, "Sublist of #{@id} does not have an id" unless sl['id']
|
234
234
|
@requested_sublists ||= []
|
235
235
|
@requested_sublists << sl
|
@@ -2,6 +2,14 @@ Spider.defineWidget('Spider.Forms.Select', 'Spider.Forms.Input', {
|
|
2
2
|
|
3
3
|
autoInit: true,
|
4
4
|
|
5
|
+
ready: function(){
|
6
|
+
if (this.el.is('select[multiple]')) this.el.asmSelect({
|
7
|
+
removeLabel: 'togli',
|
8
|
+
highlightAddedLabel: 'Aggiunto: ',
|
9
|
+
highlightRemovedLabel: 'Tolto: '
|
10
|
+
});
|
11
|
+
},
|
12
|
+
|
5
13
|
onConnectedChange: function(connected, val){
|
6
14
|
var params = {};
|
7
15
|
params[connected] = val;
|
@@ -6,7 +6,6 @@ module Spider; module Forms
|
|
6
6
|
is_attr_accessor :multiple
|
7
7
|
is_attr_accessor :blank_option, :type => TrueClass, :default => true
|
8
8
|
is_attr_accessor :condition
|
9
|
-
is_attr_accessor :show_element
|
10
9
|
attr_accessor :data
|
11
10
|
|
12
11
|
def widget_init(action='')
|
@@ -42,7 +41,6 @@ module Spider; module Forms
|
|
42
41
|
@scene.data.condition.and(conn_cond)
|
43
42
|
end
|
44
43
|
@scene.values = {}
|
45
|
-
@scene.strings = {}
|
46
44
|
debug("SELECT VALUE:")
|
47
45
|
debug(@value)
|
48
46
|
@scene.selected = {}
|
@@ -54,18 +52,9 @@ module Spider; module Forms
|
|
54
52
|
end
|
55
53
|
@scene.data.each_index do |i|
|
56
54
|
@scene.values[i] = @model.primary_keys.map{|k| @scene.data[i][k] }.join(',')
|
57
|
-
@scene.strings[i] = format_string(@scene.data[i])
|
58
55
|
end
|
59
56
|
super
|
60
57
|
end
|
61
|
-
|
62
|
-
def format_string(obj)
|
63
|
-
if (@show_element)
|
64
|
-
return obj.get(@show_element).to_s
|
65
|
-
else
|
66
|
-
return obj.to_s
|
67
|
-
end
|
68
|
-
end
|
69
58
|
|
70
59
|
|
71
60
|
def value=(val)
|
@@ -1,6 +1,8 @@
|
|
1
1
|
<select name="{ @value_param }" sp:attr-if="@multiple,multiple" class="">
|
2
2
|
<tpl:asset type="js" src="input.js" />
|
3
3
|
<tpl:asset type="js" src="select.js" />
|
4
|
+
<tpl:asset type="js" app="core/components" src="js/jquery/plugins/asmselect/jquery.asmselect.js" if="@multiple" />
|
5
|
+
<tpl:asset type="css" app="core/components" src="js/jquery/plugins/asmselect/jquery.asmselect.css" if="@multiple" />
|
4
6
|
<option sp:if="@blank_option"> </option>
|
5
7
|
<option sp:each_index="@data |i|" value="{ @values[i] }" sp:attr-if="@selected[values[i]],selected">
|
6
8
|
{ @data[i].to_s }
|
@@ -1 +1,2 @@
|
|
1
|
-
<textarea name="{ @name }" rows="{ @rows }" cols="{ @cols }"
|
1
|
+
<textarea name="{ @name }" rows="{ @rows }" cols="{ @cols }"><tpl:asset type="js" src="text_area.js" />
|
2
|
+
<tpl:asset type="js" app="core/components" src="js/jquery/plugins/autogrow/jquery.autogrow.js" />{ @value }</textarea>
|
@@ -30,11 +30,6 @@ class TestCommand < CmdParse::Command
|
|
30
30
|
|
31
31
|
self_cmd = CmdParse::Command.new('self', false)
|
32
32
|
self_cmd.short_desc = _("Run framework tests")
|
33
|
-
self_cmd.options = CmdParse::OptionParserWrapper.new do |opt|
|
34
|
-
opt.on("--files", _("Run only files containing the given string (or strings, comma separated)"), "-f"){ |f|
|
35
|
-
@files = f
|
36
|
-
}
|
37
|
-
end
|
38
33
|
self_cmd.set_execution_block do
|
39
34
|
require 'test/unit/collector/dir'
|
40
35
|
require 'test/unit'
|
@@ -40,6 +40,7 @@ class WebServerCommand < CmdParse::Command
|
|
40
40
|
raise "Can't use cgi mode with SSL" if @ssl && @cgi
|
41
41
|
@port ||= Spider.conf.get('webserver.port')
|
42
42
|
@server_name ||= Spider.conf.get('http.server')
|
43
|
+
@pid_file = Spider.paths[:var]+'/run/server.pid'
|
43
44
|
puts _("Using webserver %s") % @server_name if $verbose
|
44
45
|
puts _("Listening on port %s") % @port if $verbose
|
45
46
|
server = Spider::HTTP.const_get(servers[@server_name]).new
|
@@ -62,6 +63,10 @@ class WebServerCommand < CmdParse::Command
|
|
62
63
|
server.shutdown
|
63
64
|
ssl_server.shutdown if ssl_server
|
64
65
|
Spider.shutdown
|
66
|
+
begin
|
67
|
+
File.unlink(@pid_file)
|
68
|
+
rescue Errno::ENOENT
|
69
|
+
end
|
65
70
|
}
|
66
71
|
trap('TERM', &do_shutdown)
|
67
72
|
trap('INT', &do_shutdown)
|
@@ -71,12 +76,11 @@ class WebServerCommand < CmdParse::Command
|
|
71
76
|
}
|
72
77
|
if (@daemonize)
|
73
78
|
forked = Spider.fork do
|
74
|
-
File.
|
79
|
+
File.open(@pid_file, 'w') do |f|
|
75
80
|
f.write(Process.pid)
|
76
81
|
end
|
77
82
|
$0 = 'spider-server'
|
78
83
|
start.call
|
79
|
-
@runner.join
|
80
84
|
end
|
81
85
|
Process.detach(forked)
|
82
86
|
else
|
@@ -9,43 +9,42 @@ module Spider
|
|
9
9
|
|
10
10
|
def setup
|
11
11
|
unless @sessions
|
12
|
-
@
|
12
|
+
@mutex ||= Mutex.new
|
13
13
|
@sessions ||= Hash.new
|
14
14
|
end
|
15
15
|
super
|
16
16
|
end
|
17
17
|
|
18
18
|
def []=(sid, data)
|
19
|
-
@
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
@mutex.synchronize {
|
20
|
+
@sessions[sid] = {
|
21
|
+
:data => data,
|
22
|
+
:mtime => Time.now
|
23
|
+
}
|
23
24
|
}
|
24
|
-
@sync.lock(Sync::UN)
|
25
25
|
end
|
26
26
|
|
27
27
|
def [](sid)
|
28
28
|
check_purge
|
29
|
-
@
|
30
|
-
|
31
|
-
|
32
|
-
sess
|
29
|
+
@mutex.synchronize{
|
30
|
+
@sessions[sid] ? @sessions[sid][:data] : nil
|
31
|
+
}
|
33
32
|
end
|
34
33
|
|
35
34
|
def purge(life)
|
36
|
-
@
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
@mutex.synchronize{
|
36
|
+
@sessions.each do |sid, session|
|
37
|
+
if (session[:mtime] + life < Time.now)
|
38
|
+
@sessions.delete(sid)
|
39
|
+
end
|
40
40
|
end
|
41
|
-
|
42
|
-
@sync.lock(Sync::UN)
|
41
|
+
}
|
43
42
|
end
|
44
43
|
|
45
44
|
def delete(sid)
|
46
|
-
@
|
47
|
-
|
48
|
-
|
45
|
+
@mutex.synchronize{
|
46
|
+
@sessions.delete(sid)
|
47
|
+
}
|
49
48
|
end
|
50
49
|
|
51
50
|
end
|
@@ -196,6 +196,8 @@ module Spider; module Model
|
|
196
196
|
parts = attributes[:integrated_from].split('.')
|
197
197
|
attributes[:integrated_from] = @elements[parts[0].to_sym]
|
198
198
|
attributes[:integrated_from_element] = parts[1].to_sym if parts[1]
|
199
|
+
elsif (attributes[:integrated_from].is_a?(Symbol))
|
200
|
+
attributes[:integrated_from] = @elements[attributes[:integrated_from]]
|
199
201
|
end
|
200
202
|
if (!attributes[:integrated_from_element])
|
201
203
|
attributes[:integrated_from_element] = name
|
@@ -503,6 +505,11 @@ module Spider; module Model
|
|
503
505
|
# this will not have the desired effect; remove and redefine the element instead.
|
504
506
|
def self.element_attributes(element_name, attributes)
|
505
507
|
elements[element_name].attributes.merge!(attributes)
|
508
|
+
if attributes[:primary_key] && !@primary_keys.include?(elements[element_name])
|
509
|
+
@primary_keys << elements[element_name]
|
510
|
+
elsif !attributes[:primary_key]
|
511
|
+
@primary_keys.delete(elements[element_name])
|
512
|
+
end
|
506
513
|
end
|
507
514
|
|
508
515
|
# Defines a multiple element. Equivalent to calling
|
@@ -982,6 +989,12 @@ module Spider; module Model
|
|
982
989
|
end
|
983
990
|
if (values)
|
984
991
|
if (values.is_a? Hash)
|
992
|
+
values.keys.select{ |k|
|
993
|
+
k = k.name if k.is_a?(Element)
|
994
|
+
self.class.elements[k.to_sym] && self.class.elements[k.to_sym].primary_key?
|
995
|
+
}.each do |k|
|
996
|
+
set!(k, values[k])
|
997
|
+
end
|
985
998
|
values.each do |key, val|
|
986
999
|
set!(key, val)
|
987
1000
|
end
|
@@ -26,13 +26,15 @@ module Spider; module Model
|
|
26
26
|
def get(model, values)
|
27
27
|
@objects[model] ||= {}
|
28
28
|
pks = {}
|
29
|
+
has_pks = false
|
29
30
|
model.primary_keys.each do |k|
|
30
31
|
# dereference integrated primary keys
|
31
32
|
pks[k.name] = (k.integrated? && values[k.integrated_from.name]) ?
|
32
33
|
values[k.integrated_from.name].get(k.integrated_from_element) :
|
33
34
|
values[k.name]
|
34
|
-
|
35
|
+
has_pks = true if pks[k.name]
|
35
36
|
end
|
37
|
+
raise IdentityMapperException, "Can't get without all primary keys" unless has_pks
|
36
38
|
pks.extend(HashComparison)
|
37
39
|
obj = (@objects[model][pks] ||= model.new(pks))
|
38
40
|
pks.each{ |k, v| obj.element_loaded(k) }
|
@@ -111,7 +111,7 @@ module Spider; module Model; module Storage; module Db
|
|
111
111
|
return value.to_datetime if type == DateTime
|
112
112
|
return value.to_date # FIXME: check what is returned, here we espect an OCI8::Date
|
113
113
|
when 'Spider::DataTypes::Text'
|
114
|
-
value =
|
114
|
+
value = value.read if value.respond_to?(:read)
|
115
115
|
end
|
116
116
|
return super(type, value)
|
117
117
|
end
|
@@ -245,7 +245,7 @@ module Spider; module Model; module Storage; module Db
|
|
245
245
|
# end
|
246
246
|
transformed = "O#{replace_cnt += 1}"
|
247
247
|
replaced_fields[field.to_s] = transformed
|
248
|
-
if (field.type == 'CLOB')
|
248
|
+
if (field.is_a?(Spider::Model::Storage::Db::Field) && field.type == 'CLOB')
|
249
249
|
field = "CAST(#{field} as varchar2(100))"
|
250
250
|
end
|
251
251
|
query[:keys] << "#{field} AS #{transformed}"
|
@@ -17,6 +17,7 @@ module Spider; module Model; module Storage; module Db
|
|
17
17
|
@retry = Spider.conf.get('storage.db.pool.retry')
|
18
18
|
@connections = []
|
19
19
|
@free_connections = []
|
20
|
+
@thread_connections = {}
|
20
21
|
# if Spider.runmode == 'devel'
|
21
22
|
# Thread.new do
|
22
23
|
# loop do
|
@@ -38,12 +39,16 @@ module Spider; module Model; module Storage; module Db
|
|
38
39
|
def get_connection
|
39
40
|
Thread.current[:db_connections] ||= {}
|
40
41
|
@connection_mutex.synchronize do
|
42
|
+
#Spider.logger.debug("DB Pool (#{Thread.current}): trying to get connection")
|
41
43
|
if conn = Thread.current[:db_connections][@connection_params]
|
42
|
-
#
|
44
|
+
#Spider.logger.debug("DB Pool (#{Thread.current}): returning thread connection #{conn}")
|
43
45
|
@free_connections.delete(conn)
|
44
46
|
conn
|
45
47
|
else
|
46
|
-
|
48
|
+
conn = _checkout
|
49
|
+
Thread.current[:db_connections][@connection_params] = conn
|
50
|
+
@thread_connections[Thread.current.object_id] = [conn, Time.now]
|
51
|
+
conn
|
47
52
|
end
|
48
53
|
end
|
49
54
|
end
|
@@ -56,10 +61,11 @@ module Spider; module Model; module Storage; module Db
|
|
56
61
|
|
57
62
|
def release(conn)
|
58
63
|
@connection_mutex.synchronize do
|
59
|
-
#
|
64
|
+
#Spider.logger.debug("DB Pool (#{Thread.current}): releasing #{conn}")
|
60
65
|
@free_connections << conn
|
61
|
-
@queue.signal
|
62
66
|
Thread.current[:db_connections].delete(@connection_params)
|
67
|
+
@thread_connections.delete(Thread.current.object_id)
|
68
|
+
@queue.signal
|
63
69
|
end
|
64
70
|
end
|
65
71
|
|
@@ -79,6 +85,9 @@ module Spider; module Model; module Storage; module Db
|
|
79
85
|
|
80
86
|
private
|
81
87
|
|
88
|
+
def _release
|
89
|
+
end
|
90
|
+
|
82
91
|
def _checkout
|
83
92
|
# Spider.logger.debug("DB Pool (#{Thread.current}): checkout (max: #{@max_size})")
|
84
93
|
1.upto(@retry) do
|
@@ -89,18 +98,54 @@ module Spider; module Model; module Storage; module Db
|
|
89
98
|
else
|
90
99
|
Spider.logger.debug "#{Thread.current} WAITING FOR CONNECTION, #{@queue.count_waiters} IN QUEUE"
|
91
100
|
unless @queue.wait(@timeout)
|
92
|
-
|
101
|
+
clear_stale_connections
|
102
|
+
create_new_connection if @free_connections.empty? && @connections.length < @max_size
|
103
|
+
if @free_connections.empty?
|
104
|
+
Spider.logger.error "#{Thread.current} GOT TIRED WAITING, #{@queue.count_waiters} IN QUEUE"
|
105
|
+
raise StorageException, "Unable to get a db connection in #{@timeout} seconds" if @timeout
|
106
|
+
end
|
93
107
|
end
|
94
108
|
end
|
95
109
|
else
|
96
110
|
# Spider.logger.debug("DB Pool (#{Thread.current}): had free connection")
|
97
111
|
end
|
98
112
|
conn = @free_connections.pop
|
99
|
-
|
100
|
-
|
113
|
+
while conn && !@provider.connection_alive?(conn)
|
114
|
+
Spider.logger.warn("DB Pool (#{Thread.current}): connection #{conn} dead")
|
115
|
+
remove_connection(conn)
|
116
|
+
conn = nil
|
117
|
+
conn = @free_connections.pop unless @free_connections.empty?
|
118
|
+
end
|
119
|
+
if conn
|
120
|
+
#Spider.logger.debug("DB Pool (#{Thread.current}): returning #{conn} (#{@free_connections.length} free)")
|
101
121
|
return conn
|
102
|
-
|
103
|
-
|
122
|
+
end
|
123
|
+
end
|
124
|
+
raise StorageException, "#{Thread.current} unable to get a connection after #{@retry} retries."
|
125
|
+
end
|
126
|
+
|
127
|
+
def clear_stale_connections
|
128
|
+
@connection_mutex.synchronize do
|
129
|
+
keys = Set.new(@thread_connections.keys)
|
130
|
+
Thread.list.each do |thread|
|
131
|
+
keys.delete(thread.object_id) if thread.alive?
|
132
|
+
end
|
133
|
+
keys.each do |thread_id|
|
134
|
+
conn, time = @thread_connections[thread_id]
|
135
|
+
Spider.logger.error("Thread #{thread_id} died without releasing connection #{conn} (acquired at #{time})")
|
136
|
+
if @provider.connection_alive?(conn)
|
137
|
+
@free_connections << conn
|
138
|
+
else
|
139
|
+
remove_connection(conn)
|
140
|
+
end
|
141
|
+
@thread_connections.delete(thread_id)
|
142
|
+
end
|
143
|
+
@thread_connections.each do |thread_id, conn_data|
|
144
|
+
conn, time = conn_data
|
145
|
+
diff = Time.now - time
|
146
|
+
if diff > 60
|
147
|
+
Spider.logger.warn("Thread #{thread_id} has been holding connection #{conn} for #{diff} seconds.")
|
148
|
+
end
|
104
149
|
end
|
105
150
|
end
|
106
151
|
end
|
data/spider.gemspec
CHANGED
@@ -2,7 +2,7 @@ require 'rake'
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "spiderfw"
|
5
|
-
s.version = "0.5.
|
5
|
+
s.version = "0.5.4"
|
6
6
|
s.date = "2010-02-18"
|
7
7
|
s.summary = "A (web) framework"
|
8
8
|
s.email = "abmajor7@gmail.com"
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.default_executable = 'spider'
|
29
29
|
s.add_dependency("cmdparse", ["> 2.0.0"])
|
30
30
|
s.add_dependency("gettext", ["> 2.0.0"])
|
31
|
-
s.add_dependency("hpricot", ["
|
31
|
+
s.add_dependency("hpricot", ["= 0.6"])
|
32
32
|
s.add_dependency("json", ["> 1.1"])
|
33
33
|
s.add_dependency("uuid", ["> 2.0"])
|
34
34
|
s.add_dependency("rufus-scheduler", ["> 1.0"])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spiderfw
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Pirlik
|
@@ -38,9 +38,9 @@ dependencies:
|
|
38
38
|
version_requirement:
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- - "
|
41
|
+
- - "="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: "0.
|
43
|
+
version: "0.6"
|
44
44
|
version:
|
45
45
|
- !ruby/object:Gem::Dependency
|
46
46
|
name: json
|
@@ -367,6 +367,9 @@ files:
|
|
367
367
|
- apps/core/components/public/js/jquery/jquery-ui/index.html
|
368
368
|
- apps/core/components/public/js/jquery/jquery-ui/js/jquery-1.3.2.min.js
|
369
369
|
- apps/core/components/public/js/jquery/jquery-ui/js/jquery-ui-1.7.2.custom.min.js
|
370
|
+
- apps/core/components/public/js/jquery/plugins/asmselect/jquery.asmselect.css
|
371
|
+
- apps/core/components/public/js/jquery/plugins/asmselect/jquery.asmselect.js
|
372
|
+
- apps/core/components/public/js/jquery/plugins/autogrow/jquery.autogrow.js
|
370
373
|
- apps/core/components/public/js/jquery/plugins/jquery-autocomplete/changelog.txt
|
371
374
|
- apps/core/components/public/js/jquery/plugins/jquery-autocomplete/jquery.autocomplete.css
|
372
375
|
- apps/core/components/public/js/jquery/plugins/jquery-autocomplete/jquery.autocomplete.js
|
@@ -511,6 +514,7 @@ files:
|
|
511
514
|
- apps/core/forms/public/input.js
|
512
515
|
- apps/core/forms/public/search_select.js
|
513
516
|
- apps/core/forms/public/select.js
|
517
|
+
- apps/core/forms/public/text_area.js
|
514
518
|
- apps/core/forms/tags/element_label.erb
|
515
519
|
- apps/core/forms/tags/element_row.erb
|
516
520
|
- apps/core/forms/tags/row.erb
|