spiderfw 0.5.3 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|