spiderfw 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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);
@@ -40,6 +40,7 @@ module Spider; module Components
40
40
  @scene.username = @request.user.to_s
41
41
  else
42
42
  @scene.username = _("guest")
43
+ @scene.guest = true
43
44
  end
44
45
  super
45
46
  end
@@ -6,7 +6,7 @@
6
6
  </div>
7
7
  <div class="tools">
8
8
  Benvenuto, { @username }.
9
- <a href="{ @logout_url }">Logout</a>
9
+ <a href="{ @logout_url }" sp:if="!@guest">Logout</a>
10
10
  </div>
11
11
  </div>
12
12
  <div class="current_section">
@@ -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.xpath('sublist', Template.xml_namespaces).each do |sl|
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;
@@ -0,0 +1,8 @@
1
+ Spider.defineWidget('Spider.Forms.TextArea', 'Spider.Forms.Input', {
2
+
3
+ autoInit: true,
4
+
5
+ ready: function(){
6
+ this.el.autogrow();
7
+ }
8
+ });
@@ -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 }
@@ -3,7 +3,7 @@ module Spider; module Forms
3
3
  class TextArea < Input
4
4
  tag 'textarea'
5
5
  is_attr_accessor :rows, :type => Fixnum, :default => 6
6
- is_attr_accessor :cols, :type => Fixnum, :default => 40
6
+ is_attr_accessor :cols, :type => Fixnum, :default => 80
7
7
 
8
8
  end
9
9
 
@@ -1 +1,2 @@
1
- <textarea name="{ @name }" rows="{ @rows }" cols="{ @cols }">{ @value }</textarea>
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.new(Spider.paths[:var]+'/run/server.pid', w) do |f|
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
- @sync ||= Sync.new
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
- @sync.lock(Sync::EX)
20
- @sessions[sid] = {
21
- :data => data,
22
- :mtime => Time.now
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
- @sync.lock(Sync::SH)
30
- sess = @sessions[sid] ? @sessions[sid][:data] : nil
31
- @sync.lock(Sync::UN)
32
- sess
29
+ @mutex.synchronize{
30
+ @sessions[sid] ? @sessions[sid][:data] : nil
31
+ }
33
32
  end
34
33
 
35
34
  def purge(life)
36
- @sync.lock(Sync::EX)
37
- @sessions.each do |sid, session|
38
- if (session[:mtime] + life < Time.now)
39
- @sessions.delete(sid)
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
- end
42
- @sync.lock(Sync::UN)
41
+ }
43
42
  end
44
43
 
45
44
  def delete(sid)
46
- @sync.lock(Sync::EX)
47
- @sessions.delete(sid)
48
- @sync.lock(Sync::UN)
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
- raise IdentityMapperException, "Can't get without all primary keys" unless pks[k.name]
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 = value ? value.read : ''
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
- # Spider.logger.debug("DB Pool (#{Thread.current}): returning thread connection #{conn}")
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
- Thread.current[:db_connections][@connection_params] = _checkout
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
- # Spider.logger.debug("DB Pool (#{Thread.current}): releasing #{conn}")
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
- raise StorageException, "Unable to get a db connection in #{@timeout} seconds" if @timeout
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
- if @provider.connection_alive?(conn)
100
- # Spider.logger.debug("DB Pool (#{Thread.current}): returning #{conn} (#{@free_connections.length} free)")
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
- else
103
- remove(conn)
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.3"
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", ["> 0.8"])
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.3
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.8"
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