spiderfw 0.5.10 → 0.5.11
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/CHANGELOG +6 -0
- data/Rakefile +4 -1
- data/VERSION +1 -0
- data/apps/core/auth/controllers/login_controller.rb +10 -1
- data/apps/core/auth/controllers/mixins/auth_helper.rb +4 -2
- data/apps/core/auth/views/login.shtml +1 -1
- data/apps/core/components/_init.rb +1 -1
- data/apps/core/components/public/css/spider.css +0 -1
- data/apps/core/components/public/js/jquery/plugins/jquery.form.js +2 -1
- data/apps/core/components/public/js/list.js +14 -126
- data/apps/core/components/public/js/plugins/plugin.js +7 -0
- data/apps/core/components/public/js/plugins/sortable.js +124 -0
- data/apps/core/components/public/js/spider.js +212 -51
- data/apps/core/components/widgets/list/list.shtml +1 -0
- data/apps/core/components/widgets/table/table.rb +1 -1
- data/apps/core/components/widgets/table/table.shtml +3 -3
- data/apps/core/components/widgets/tabs/tabs.rb +70 -22
- data/apps/core/components/widgets/tabs/tabs.shtml +8 -2
- data/apps/core/forms/widgets/inputs/file_input/file_input.rb +4 -1
- data/data/locale/it/LC_MESSAGES/cms.mo +0 -0
- data/data/locale/it/LC_MESSAGES/spider.mo +0 -0
- data/data/locale/it/LC_MESSAGES/spider_files.mo +0 -0
- data/data/locale/it/LC_MESSAGES/spider_images.mo +0 -0
- data/lib/spiderfw.rb +3 -1
- data/lib/spiderfw/config/configuration.rb +3 -1
- data/lib/spiderfw/controller/controller.rb +8 -0
- data/lib/spiderfw/controller/mixins/static_content.rb +14 -2
- data/lib/spiderfw/controller/mixins/visual.rb +25 -25
- data/lib/spiderfw/controller/page_controller.rb +3 -0
- data/lib/spiderfw/controller/request.rb +4 -1
- data/lib/spiderfw/controller/session.rb +7 -6
- data/lib/spiderfw/create.rb +10 -1
- data/lib/spiderfw/model/base_model.rb +104 -57
- data/lib/spiderfw/model/condition.rb +9 -1
- data/lib/spiderfw/model/data_type.rb +15 -0
- data/lib/spiderfw/model/datatypes/uuid.rb +5 -0
- data/lib/spiderfw/model/extended_models/managed.rb +2 -2
- data/lib/spiderfw/model/mappers/db_mapper.rb +46 -21
- data/lib/spiderfw/model/mappers/mapper.rb +34 -8
- data/lib/spiderfw/model/mixins/list.rb +2 -0
- data/lib/spiderfw/model/mixins/tree.rb +2 -1
- data/lib/spiderfw/model/mixins/versioned.rb +12 -9
- data/lib/spiderfw/model/model.rb +72 -0
- data/lib/spiderfw/model/query_set.rb +7 -0
- data/lib/spiderfw/model/storage/base_storage.rb +5 -1
- data/lib/spiderfw/model/storage/db/adapters/mysql.rb +5 -2
- data/lib/spiderfw/model/storage/db/adapters/oci8.rb +9 -3
- data/lib/spiderfw/model/storage/db/db_storage.rb +8 -5
- data/lib/spiderfw/model/sync.rb +12 -6
- data/lib/spiderfw/requires.rb +1 -0
- data/lib/spiderfw/templates/blocks/parent_context.rb +26 -0
- data/lib/spiderfw/templates/blocks/widget.rb +17 -7
- data/lib/spiderfw/templates/layout.rb +11 -1
- data/lib/spiderfw/templates/template.rb +36 -3
- data/lib/spiderfw/templates/template_blocks.rb +36 -26
- data/lib/spiderfw/utils/annotations.rb +2 -1
- data/lib/spiderfw/utils/thread_out.rb +15 -0
- data/lib/spiderfw/widget/widget.rb +58 -16
- data/spider.gemspec +3 -0
- metadata +143 -48
data/CHANGELOG
ADDED
data/Rakefile
CHANGED
@@ -5,7 +5,10 @@ require 'pathname'
|
|
5
5
|
def check_app_path(full, partial)
|
6
6
|
p = Pathname.new(full)
|
7
7
|
rel = p.relative_path_from(Pathname.new(Spider.paths[:core_apps]))
|
8
|
-
return rel.to_s == partial
|
8
|
+
return true if rel.to_s == partial
|
9
|
+
rel = p.relative_path_from(Pathname.new(Spider.paths[:apps]))
|
10
|
+
return true if rel.to_s == partial
|
11
|
+
return false
|
9
12
|
end
|
10
13
|
|
11
14
|
desc "Update pot/po files. To update a single app, call rake updatepo[app_relative_path], where app_relative_path is the path relative to the apps folder (or 'spider')."
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.5.11
|
@@ -10,6 +10,10 @@ module Spider; module Auth
|
|
10
10
|
nil
|
11
11
|
end
|
12
12
|
|
13
|
+
def self.logout_redirect
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
13
17
|
def self.users=(val)
|
14
18
|
@user_classes = val
|
15
19
|
end
|
@@ -85,7 +89,12 @@ module Spider; module Auth
|
|
85
89
|
def logout
|
86
90
|
@request.session[:auth] = nil
|
87
91
|
@scene.did_logout = true
|
88
|
-
|
92
|
+
red = self.class.logout_redirect
|
93
|
+
if red
|
94
|
+
redirect(red)
|
95
|
+
else
|
96
|
+
redirect('index')
|
97
|
+
end
|
89
98
|
end
|
90
99
|
|
91
100
|
end
|
@@ -11,7 +11,9 @@ module Spider; module Auth
|
|
11
11
|
|
12
12
|
def before(action='', *arguments)
|
13
13
|
@request.extend(RequestMethods)
|
14
|
-
|
14
|
+
super
|
15
|
+
return if action.index(Spider::Auth.route_url) == 0
|
16
|
+
return if respond_to?(:serving_static?) && serving_static?
|
15
17
|
self.class.auth_require_users.each do |req|
|
16
18
|
klasses, params = req
|
17
19
|
klasses = [klasses] unless klasses.is_a?(Array)
|
@@ -64,7 +66,7 @@ module Spider; module Auth
|
|
64
66
|
end
|
65
67
|
@request.user = user
|
66
68
|
end
|
67
|
-
|
69
|
+
|
68
70
|
end
|
69
71
|
|
70
72
|
def try_rescue(exc)
|
@@ -16,7 +16,7 @@ require 'apps/core/components/widgets/crud/crud'
|
|
16
16
|
require 'apps/core/components/widgets/menu/menu'
|
17
17
|
require 'apps/core/components/widgets/admin/admin'
|
18
18
|
require 'apps/core/components/widgets/confirm/confirm'
|
19
|
-
|
19
|
+
require 'apps/core/components/widgets/tabs/tabs'
|
20
20
|
require 'apps/core/components/widgets/list/list'
|
21
21
|
require 'apps/core/components/widgets/switcher/switcher'
|
22
22
|
require 'apps/core/components/widgets/month_calendar/month_calendar'
|
@@ -373,8 +373,9 @@ $.fn.ajaxSubmit = function(options) {
|
|
373
373
|
* the form itself.
|
374
374
|
*/
|
375
375
|
$.fn.ajaxForm = function(options) {
|
376
|
-
return this.ajaxFormUnbind().bind('submit.form-plugin', function() {
|
376
|
+
return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
|
377
377
|
$(this).ajaxSubmit(options);
|
378
|
+
e.stopPropagation();
|
378
379
|
return false;
|
379
380
|
}).bind('click.form-plugin', function(e) {
|
380
381
|
var $el = $(e.target);
|
@@ -1,6 +1,8 @@
|
|
1
1
|
Spider.defineWidget('Spider.Components.List', {
|
2
2
|
|
3
3
|
autoInit: '.wdgt-Spider-Components-List',
|
4
|
+
|
5
|
+
includePlugins: [Spider.Sortable],
|
4
6
|
|
5
7
|
startup: function(){
|
6
8
|
},
|
@@ -12,7 +14,16 @@ Spider.defineWidget('Spider.Components.List', {
|
|
12
14
|
this.listTagName = this.listEl.get(0).tagName;
|
13
15
|
if (this.el.hasClass('collapsed')) options.collapsed = true;
|
14
16
|
if (this.el.hasClass('tree')) $(this.listTagName, this.el).treeview(options);
|
15
|
-
if (this.el.hasClass('sortable'))
|
17
|
+
if (this.el.hasClass('sortable')){
|
18
|
+
this.plugin(Spider.Sortable);
|
19
|
+
this.makeSortable({
|
20
|
+
listEl: this.listEl,
|
21
|
+
handle: '> span.desc',
|
22
|
+
helper: function(e,item) {
|
23
|
+
return $("<div class='treeview-helper'>"+item.find("span.desc").html()+"</div>");
|
24
|
+
}
|
25
|
+
});
|
26
|
+
}
|
16
27
|
|
17
28
|
};
|
18
29
|
this.ajaxify($('form, .paginator a', this.el));
|
@@ -22,141 +33,18 @@ Spider.defineWidget('Spider.Components.List', {
|
|
22
33
|
update: function(){
|
23
34
|
},
|
24
35
|
|
25
|
-
|
26
|
-
makeSortable: function(){
|
27
|
-
var options = {
|
28
|
-
items: '>li',
|
29
|
-
helper: function(e,item) {
|
30
|
-
return $("<div class='treeview-helper'>"+item.find("span.desc").html()+"</div>");
|
31
|
-
},
|
32
|
-
handle: '> span.desc',
|
33
|
-
update: this.handleSort.bind(this),
|
34
|
-
receive: this.handleReceive.bind(this)
|
35
|
-
};
|
36
|
-
if (this.el.hasClass('tree')){
|
37
|
-
options = $.extend(options, {
|
38
|
-
//revert: true,
|
39
|
-
sortIndication: {
|
40
|
-
down: function(item) {
|
41
|
-
item.before($('<li id="list-sort-indicator" />'));
|
42
|
-
},
|
43
|
-
up: function(item) {
|
44
|
-
item.after($('<li id="list-sort-indicator" />'));
|
45
|
-
},
|
46
|
-
remove: function(item) {
|
47
|
-
$('#list-sort-indicator').remove();
|
48
|
-
}
|
49
|
-
},
|
50
|
-
start: function(e, ui) {
|
51
|
-
console.log("Tree start:");
|
52
|
-
console.log(e);
|
53
|
-
console.log(ui);
|
54
|
-
// ui.instance.element.treeview({update: ui.item});
|
55
|
-
},
|
56
|
-
update: this.handleTreeUpdate.bind(this)
|
57
|
-
});
|
58
|
-
this.listEl.sortableTree(options);
|
59
|
-
// handles drops on non-subtrees nodes
|
60
|
-
// debugger;
|
61
|
-
$('.desc', this.el).droppable({
|
62
|
-
accept: "li",
|
63
|
-
hoverClass: "drop",
|
64
|
-
tolerance: "pointer",
|
65
|
-
// greedy: true,
|
66
|
-
drop: this.handleTreeDrop.bind(this)
|
67
|
-
// over: function(e,ui) {
|
68
|
-
// ui.helper.css("outline", "1px dotted green");
|
69
|
-
// },
|
70
|
-
// out: function(e,ui) {
|
71
|
-
// ui.helper.css("outline", "1px dotted red");
|
72
|
-
// }
|
73
|
-
});
|
74
|
-
}
|
75
|
-
else{
|
76
|
-
this.listEl.sortable(options);
|
77
|
-
}
|
78
|
-
},
|
79
|
-
|
80
|
-
handleSort: function(e, ui){
|
81
|
-
if (ui.sender) return; // handled by handleReceive
|
82
|
-
var item = ui.item;
|
83
|
-
var pos = this.findLiPosition(item);
|
84
|
-
if (pos == -1) return;
|
85
|
-
if (this.listEl.data('sortable').fromOutside){ // hack to work around strange jquery ui behaviour...
|
86
|
-
return this.acceptFromSender(null, ui.item, pos);
|
87
|
-
}
|
88
|
-
this.remote('sort', this.getSortItemId(item), pos);
|
89
|
-
},
|
90
|
-
|
91
|
-
|
92
|
-
handleReceive: function(e, ui){
|
93
|
-
if (ui.sender == ui.item){
|
94
|
-
// the item is received from a draggable, not from a list. For some reason the receiver is not
|
95
|
-
// yet ready to find the position; will call acceptFromSender from handleSort.
|
96
|
-
return;
|
97
|
-
}
|
98
|
-
var pos = this.findLiPosition(ui.item);
|
99
|
-
return this.acceptFromSender(ui.sender, ui.item, pos);
|
100
|
-
},
|
101
|
-
|
102
|
-
handleTreeUpdate: function(e, ui){
|
103
|
-
var parentId = this.getItemId(ui.item.parents('li.tree').eq(0));
|
104
|
-
var prevId = this.getItemId(ui.item.prev('li.tree'));
|
105
|
-
this.remote('tree_sort', this.getItemId(ui.item), parentId, prevId);
|
106
|
-
},
|
107
|
-
|
108
|
-
handleTreeDrop: function(e, ui){
|
109
|
-
if (e.target.parentNode == ui.draggable[0]) return false; //dropped over itself
|
110
|
-
console.log('dropped inside');
|
111
|
-
var dropLi = $(e.target.parentNode);
|
112
|
-
var subUl = $("> "+this.listTagName, dropLi);
|
113
|
-
if (subUl.length == 0){
|
114
|
-
subUl = $("<"+this.listTagName+" />").appendTo(dropLi);
|
115
|
-
this.el.treeview({add: e.target.parentNode});
|
116
|
-
}
|
117
|
-
subUl.append(ui.draggable);
|
118
|
-
var parentId = this.getItemId($(e.target).parents('li.tree').eq(0));
|
119
|
-
var prevId = null;
|
120
|
-
this.remote('tree_sort', this.getItemId(ui.draggable), parentId, prevId);
|
121
|
-
return false;
|
122
|
-
},
|
123
|
-
|
124
|
-
acceptFromSender: function(sender, item, pos){
|
125
|
-
console.error("Accept from sender must be implemented by the widget instance");
|
126
|
-
},
|
127
|
-
|
128
|
-
getItemId: function(li){
|
129
|
-
return $('> .dataobject-key', li).text();
|
130
|
-
},
|
131
|
-
|
132
36
|
getItemById: function(id){
|
133
37
|
var found = null;
|
134
38
|
var self = this;
|
135
39
|
$('>li', this.listEl).each(function(){
|
136
|
-
|
40
|
+
$this = $(this);
|
41
|
+
if ($this.dataObjectKey == id){
|
137
42
|
found = $(this);
|
138
43
|
return false;
|
139
44
|
}
|
140
45
|
});
|
141
46
|
return found;
|
142
47
|
},
|
143
|
-
|
144
|
-
getSortItemId: function(li){
|
145
|
-
var k = $('> .sort-key', li);
|
146
|
-
if (k.length > 0) return k.text();
|
147
|
-
return this.getItemId(li);
|
148
|
-
},
|
149
|
-
|
150
|
-
findLiPosition: function(item){
|
151
|
-
var cnt = 1;
|
152
|
-
var li = $('> li', this.listEl);
|
153
|
-
li.each(function(){
|
154
|
-
if (this == item.get(0)) return false;
|
155
|
-
cnt++;
|
156
|
-
});
|
157
|
-
if (cnt > li.length) return -1; // the row was dropped outside
|
158
|
-
return cnt;
|
159
|
-
},
|
160
48
|
|
161
49
|
sortResult: function(res){
|
162
50
|
console.log(res);
|
@@ -0,0 +1,124 @@
|
|
1
|
+
Spider.Sortable = Spider.Plugin.extend({
|
2
|
+
|
3
|
+
|
4
|
+
makeSortable: function(options){
|
5
|
+
var options = $.extend({
|
6
|
+
listSelector: 'ul',
|
7
|
+
items: '>li',
|
8
|
+
update: this.handleSort.bind(this),
|
9
|
+
receive: this.handleReceive.bind(this)
|
10
|
+
}, options);
|
11
|
+
this.listEl = options.listEl;
|
12
|
+
if (!this.listEl) this.listEl = $(options.listSelector, this.el);
|
13
|
+
if (this.el.hasClass('tree')){
|
14
|
+
options = $.extend(options, {
|
15
|
+
//revert: true,
|
16
|
+
sortIndication: {
|
17
|
+
down: function(item) {
|
18
|
+
item.before($('<li id="list-sort-indicator" />'));
|
19
|
+
},
|
20
|
+
up: function(item) {
|
21
|
+
item.after($('<li id="list-sort-indicator" />'));
|
22
|
+
},
|
23
|
+
remove: function(item) {
|
24
|
+
$('#list-sort-indicator').remove();
|
25
|
+
}
|
26
|
+
},
|
27
|
+
start: function(e, ui) {
|
28
|
+
console.log("Tree start:");
|
29
|
+
console.log(e);
|
30
|
+
console.log(ui);
|
31
|
+
// ui.instance.element.treeview({update: ui.item});
|
32
|
+
},
|
33
|
+
update: this.handleTreeUpdate.bind(this)
|
34
|
+
});
|
35
|
+
this.listEl.sortableTree(options);
|
36
|
+
// handles drops on non-subtrees nodes
|
37
|
+
// debugger;
|
38
|
+
$('.desc', this.el).droppable({
|
39
|
+
accept: "li",
|
40
|
+
hoverClass: "drop",
|
41
|
+
tolerance: "pointer",
|
42
|
+
// greedy: true,
|
43
|
+
drop: this.handleTreeDrop.bind(this)
|
44
|
+
// over: function(e,ui) {
|
45
|
+
// ui.helper.css("outline", "1px dotted green");
|
46
|
+
// },
|
47
|
+
// out: function(e,ui) {
|
48
|
+
// ui.helper.css("outline", "1px dotted red");
|
49
|
+
// }
|
50
|
+
});
|
51
|
+
}
|
52
|
+
else{
|
53
|
+
this.listEl.sortable(options);
|
54
|
+
}
|
55
|
+
},
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
handleSort: function(e, ui){
|
60
|
+
if (ui.sender) return; // handled by handleReceive
|
61
|
+
var item = ui.item;
|
62
|
+
var pos = this.findLiPosition(item);
|
63
|
+
if (pos == -1) return;
|
64
|
+
if (this.listEl.data('sortable').fromOutside){ // hack to work around strange jquery ui behaviour...
|
65
|
+
return this.acceptFromSender(null, ui.item, pos);
|
66
|
+
}
|
67
|
+
this.remote('sort', this.getSortItemId(item), pos);
|
68
|
+
},
|
69
|
+
|
70
|
+
|
71
|
+
handleReceive: function(e, ui){
|
72
|
+
if (ui.sender == ui.item){
|
73
|
+
// the item is received from a draggable, not from a list. For some reason the receiver is not
|
74
|
+
// yet ready to find the position; will call acceptFromSender from handleSort.
|
75
|
+
return;
|
76
|
+
}
|
77
|
+
var pos = this.findLiPosition(ui.item);
|
78
|
+
return this.acceptFromSender(ui.sender, ui.item, pos);
|
79
|
+
},
|
80
|
+
|
81
|
+
handleTreeUpdate: function(e, ui){
|
82
|
+
var parentId = ui.item.parents('li.tree').eq(0).dataObjectKey();
|
83
|
+
var prevId = ui.item.prev('li.tree').dataObjectKey();
|
84
|
+
this.remote('tree_sort', this.getItemId(ui.item), parentId, prevId);
|
85
|
+
},
|
86
|
+
|
87
|
+
handleTreeDrop: function(e, ui){
|
88
|
+
if (e.target.parentNode == ui.draggable[0]) return false; //dropped over itself
|
89
|
+
console.log('dropped inside');
|
90
|
+
var dropLi = $(e.target.parentNode);
|
91
|
+
var subUl = $("> "+this.listTagName, dropLi);
|
92
|
+
if (subUl.length == 0){
|
93
|
+
subUl = $("<"+this.listTagName+" />").appendTo(dropLi);
|
94
|
+
this.el.treeview({add: e.target.parentNode});
|
95
|
+
}
|
96
|
+
subUl.append(ui.draggable);
|
97
|
+
var parentId = $(e.target).parents('li.tree').eq(0).dataObjectKey();
|
98
|
+
var prevId = null;
|
99
|
+
this.remote('tree_sort', ui.draggable.dataObjectKey(), parentId, prevId);
|
100
|
+
return false;
|
101
|
+
},
|
102
|
+
|
103
|
+
acceptFromSender: function(sender, item, pos){
|
104
|
+
console.error("Accept from sender must be implemented by the widget instance");
|
105
|
+
},
|
106
|
+
|
107
|
+
findLiPosition: function(item){
|
108
|
+
var cnt = 1;
|
109
|
+
var li = $('> li', this.listEl);
|
110
|
+
li.each(function(){
|
111
|
+
if (this == item.get(0)) return false;
|
112
|
+
cnt++;
|
113
|
+
});
|
114
|
+
if (cnt > li.length) return -1; // the row was dropped outside
|
115
|
+
return cnt;
|
116
|
+
},
|
117
|
+
|
118
|
+
getSortItemId: function(li){
|
119
|
+
var k = $('> .sort-key', li);
|
120
|
+
if (k.length > 0) return k.text();
|
121
|
+
return li.dataObjectKey();
|
122
|
+
}
|
123
|
+
|
124
|
+
});
|
@@ -7,7 +7,7 @@ function $W(path){
|
|
7
7
|
if (Spider.widgets[path]) return Spider.widgets[path];
|
8
8
|
var wdgt_id = path.replace(/\//g, '-');
|
9
9
|
var wdgt = $('#'+wdgt_id);
|
10
|
-
if (
|
10
|
+
if (wdgt.length == 0) return null;
|
11
11
|
return Spider.Widget.initFromEl(wdgt);
|
12
12
|
}
|
13
13
|
|
@@ -23,6 +23,8 @@ Spider.Widget = Class.extend({
|
|
23
23
|
init: function(container, path, config){
|
24
24
|
this.el = container;
|
25
25
|
this.path = path;
|
26
|
+
var pathParts = path.split('/');
|
27
|
+
this.widgetId = pathParts[pathParts.length - 1];
|
26
28
|
this.backend = new Spider.WidgetBackend(this);
|
27
29
|
this.readyFunctions = [];
|
28
30
|
config = $.extend({}, config);
|
@@ -30,15 +32,26 @@ Spider.Widget = Class.extend({
|
|
30
32
|
this.model = config.model;
|
31
33
|
Spider.widgets[path] = this;
|
32
34
|
this.events = [];
|
35
|
+
this.onWidgetCallbacks = {};
|
36
|
+
this.widgets = {};
|
37
|
+
this.findWidgets();
|
33
38
|
this.startup();
|
34
39
|
this.ready();
|
35
40
|
this.applyReady();
|
41
|
+
this.plugins = [];
|
42
|
+
if (this.includePlugins) for (var i=0; i<this.includePlugins.length; i++){
|
43
|
+
this.plugin(this.includePlugins[i]);
|
44
|
+
}
|
36
45
|
},
|
37
46
|
|
38
47
|
remote: function(){
|
39
48
|
var args = Array.prototype.slice.call(arguments);
|
40
49
|
var method = args.shift();
|
41
|
-
|
50
|
+
var options = {};
|
51
|
+
if ($.isFunction(args[args.length-1])){
|
52
|
+
options.callback = args.pop();
|
53
|
+
}
|
54
|
+
return this.backend.send(method, args, options);
|
42
55
|
},
|
43
56
|
|
44
57
|
onReady: function(callback){
|
@@ -53,9 +66,17 @@ Spider.Widget = Class.extend({
|
|
53
66
|
},
|
54
67
|
|
55
68
|
reload: function(params, callback){
|
69
|
+
if (!callback && $.isFunction(params)){
|
70
|
+
callback = params;
|
71
|
+
params = {};
|
72
|
+
}
|
56
73
|
$C.loadWidget(this.path, params, callback);
|
57
74
|
},
|
58
75
|
|
76
|
+
isLoaded: function(){
|
77
|
+
return !this.el.is(':empty');
|
78
|
+
},
|
79
|
+
|
59
80
|
startup: function(){},
|
60
81
|
ready: function(){},
|
61
82
|
update: function(){},
|
@@ -63,6 +84,7 @@ Spider.Widget = Class.extend({
|
|
63
84
|
replaceHTML: function(html){
|
64
85
|
var el = $(html);
|
65
86
|
this.el.html(el.html());
|
87
|
+
this.findWidgets();
|
66
88
|
this.update();
|
67
89
|
this.ready();
|
68
90
|
Spider.newHTML(this.el);
|
@@ -72,11 +94,34 @@ Spider.Widget = Class.extend({
|
|
72
94
|
|
73
95
|
replaceEl: function(el){
|
74
96
|
this.el = el;
|
97
|
+
this.findWidgets();
|
75
98
|
this.update();
|
76
99
|
this.ready();
|
77
100
|
this.applyReady();
|
78
101
|
},
|
79
102
|
|
103
|
+
findWidgets: function(){
|
104
|
+
var self = this;
|
105
|
+
$('.widget', this.el).filter(function(index){
|
106
|
+
if ($(this).parents('.widget').get(0) == self.el.get(0)) return true;
|
107
|
+
return false;
|
108
|
+
}).each(function(){
|
109
|
+
var $this = $(this);
|
110
|
+
var w = $this.spiderWidget();
|
111
|
+
if (!self.widgets[w.widgetId]) self.addWidget(w.widgetId, w);
|
112
|
+
else self.widgets[w.widgetId].replaceEl($this);
|
113
|
+
});
|
114
|
+
},
|
115
|
+
|
116
|
+
addWidget: function(id, w){
|
117
|
+
this.widgets[id] = w;
|
118
|
+
if (this.onWidgetCallbacks[id]){
|
119
|
+
for (var i=0; i<this.onWidgetCallbacks[id].length; i++){
|
120
|
+
this.onWidgetCallbacks[id][i].call(this, w);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
},
|
124
|
+
|
80
125
|
paramName: function(key){
|
81
126
|
var pathParts = this.path.split('/');
|
82
127
|
var param = "_w";
|
@@ -91,69 +136,111 @@ Spider.Widget = Class.extend({
|
|
91
136
|
},
|
92
137
|
|
93
138
|
|
139
|
+
ajaxifyAll: function(options){
|
140
|
+
var els = $('form:not(.ajaxified), a:not(.ajaxified)', this.el);
|
141
|
+
if (!options) options = {};
|
142
|
+
if (options.filter) els = els.filter(options.filter);
|
143
|
+
if (options.not) els = els.not(options.not);
|
144
|
+
this.ajaxify(els, options);
|
145
|
+
},
|
146
|
+
|
147
|
+
findWidgetsAjaxifiable: function(options){
|
148
|
+
var selfEl = this.el.get(0);
|
149
|
+
return $('form:not(.ajaxified), a:not(.ajaxified)', this.el).filter(function(index){
|
150
|
+
var p = $(this).parent();
|
151
|
+
while (p){
|
152
|
+
if (p.is('.widget')){
|
153
|
+
if (p.get(0) == selfEl) return true;
|
154
|
+
return false;
|
155
|
+
}
|
156
|
+
p = p.parent();
|
157
|
+
}
|
158
|
+
return false;
|
159
|
+
});
|
160
|
+
},
|
161
|
+
|
162
|
+
|
94
163
|
ajaxify: function(el, options){
|
95
164
|
var w = this;
|
165
|
+
if (!el || !el.eq){
|
166
|
+
options = el;
|
167
|
+
el = this.findWidgetsAjaxifiable();
|
168
|
+
}
|
96
169
|
if (!options) options = {};
|
97
170
|
el.each(function(){
|
98
171
|
var $this = $(this);
|
99
172
|
if (this.tagName == 'FORM'){
|
100
|
-
w.ajaxifyForm($(this));
|
173
|
+
w.ajaxifyForm($(this), options);
|
101
174
|
}
|
102
175
|
else if (this.tagName == 'A'){
|
103
|
-
|
104
|
-
if (options.before){
|
105
|
-
var res = options.before.apply(this);
|
106
|
-
if (res === false) return false ;
|
107
|
-
}
|
108
|
-
e.preventDefault();
|
109
|
-
var a = $(e.target);
|
110
|
-
var url = $(this).attr('href');
|
111
|
-
var parts = url.split('?');
|
112
|
-
url = parts[0]; //+'.json';
|
113
|
-
url += '?';
|
114
|
-
if (parts[1]) url += parts[1]+'&';
|
115
|
-
url += '_wt='+w.path;
|
116
|
-
w.setLoading();
|
117
|
-
$.ajax({
|
118
|
-
url: url,
|
119
|
-
type: 'GET',
|
120
|
-
dataType: 'html',
|
121
|
-
success: function(res){
|
122
|
-
w.replaceHTML(res);
|
123
|
-
w.removeLoading();
|
124
|
-
}
|
125
|
-
});
|
126
|
-
});
|
176
|
+
w.ajaxifyLink($(this), options);
|
127
177
|
}
|
128
178
|
});
|
129
179
|
|
130
180
|
},
|
131
181
|
|
132
|
-
ajaxifyForm: function(form){
|
133
|
-
var w = this;
|
182
|
+
ajaxifyForm: function(form, options){
|
134
183
|
var isForm = form.get(0).tagName == 'FORM';
|
135
|
-
|
184
|
+
if (!options) options = {};
|
185
|
+
$('input[type=submit]', form).addClass('ajaxified').bind('click.ajaxify', function(e){
|
186
|
+
var $this = $(this);
|
187
|
+
var w = $this.parentWidget();
|
136
188
|
e.preventDefault();
|
137
189
|
w.setLoading();
|
138
|
-
var submitName = $
|
139
|
-
var submitValue = $
|
190
|
+
var submitName = $this.attr('name');
|
191
|
+
var submitValue = $this.val();
|
140
192
|
form.ajaxSubmit({
|
141
193
|
dataType: 'html',
|
142
194
|
semantic: !isForm,
|
143
195
|
beforeSubmit: function(data, form, options){
|
144
196
|
data.push({name: submitName, value: submitValue});
|
145
197
|
data.push({name: '_wt', value: w.path});
|
198
|
+
if (options.before) options.before();
|
146
199
|
},
|
147
200
|
success: function(res){
|
148
201
|
w.replaceHTML(res);
|
149
202
|
w.removeLoading();
|
203
|
+
if (options.onLoad) options.onLoad(form);
|
204
|
+
w.trigger('ajaxifyLoad', form);
|
205
|
+
}
|
206
|
+
});
|
207
|
+
});
|
208
|
+
},
|
209
|
+
|
210
|
+
ajaxifyLink: function(a, options){
|
211
|
+
var w = this;
|
212
|
+
if (!options) options = {};
|
213
|
+
a.addClass('ajaxified').bind('click.ajaxify', function(e){
|
214
|
+
if (options.before){
|
215
|
+
var res = options.before.apply(w);
|
216
|
+
if (res === false) return false ;
|
217
|
+
}
|
218
|
+
e.preventDefault();
|
219
|
+
var a = $(e.target);
|
220
|
+
var url = $(this).attr('href');
|
221
|
+
var parts = url.split('?');
|
222
|
+
url = parts[0]; //+'.json';
|
223
|
+
url += '?';
|
224
|
+
if (parts[1]) url += parts[1]+'&';
|
225
|
+
url += '_wt='+w.path;
|
226
|
+
if (options.before) options.before();
|
227
|
+
w.setLoading();
|
228
|
+
$.ajax({
|
229
|
+
url: url,
|
230
|
+
type: 'GET',
|
231
|
+
dataType: 'html',
|
232
|
+
success: function(res){
|
233
|
+
w.replaceHTML(res);
|
234
|
+
w.removeLoading();
|
235
|
+
if (options.onLoad) options.onLoad(a);
|
236
|
+
w.trigger('ajaxifyLoad', a);
|
150
237
|
}
|
151
238
|
});
|
152
239
|
});
|
153
240
|
},
|
154
241
|
|
155
242
|
setLoading: function(){
|
156
|
-
if (this.el.is(':empty')){
|
243
|
+
if (this.el.is(':empty') || this.el.children().hasClass('empty-placeholder')){
|
157
244
|
this.el.addClass('loading-empty');
|
158
245
|
}
|
159
246
|
else{
|
@@ -201,18 +288,73 @@ Spider.Widget = Class.extend({
|
|
201
288
|
},
|
202
289
|
|
203
290
|
bind: function(eventName, callback){
|
204
|
-
|
205
|
-
|
291
|
+
var handleObj = {
|
292
|
+
callback: callback
|
293
|
+
};
|
294
|
+
if ( eventName.indexOf(".") > -1 ) {
|
295
|
+
var namespaces = eventName.split(".");
|
296
|
+
eventName = namespaces.shift();
|
297
|
+
handleObj.namespace = namespaces.slice(0).sort().join(".");
|
206
298
|
}
|
207
|
-
this.events[eventName].
|
299
|
+
if (!this.events[eventName]) this.events[eventName] = [];
|
300
|
+
this.events[eventName].push(handleObj);
|
208
301
|
},
|
209
302
|
|
303
|
+
on: function(eventName, callback){ return this.bind(eventName, callback); },
|
304
|
+
|
210
305
|
trigger: function(eventName){
|
306
|
+
if ( eventName.indexOf(".") > -1 ) {
|
307
|
+
var namespaces = eventName.split(".");
|
308
|
+
eventName = namespaces.shift();
|
309
|
+
namespace = namespaces.slice(0).sort().join(".");
|
310
|
+
}
|
211
311
|
if (!this.events[eventName]) return;
|
212
312
|
var args = Array.prototype.slice.call(arguments, 1);
|
213
313
|
for (var i=0; i < this.events[eventName].length; i++){
|
214
|
-
this.events[eventName][i].apply(this, args);
|
314
|
+
this.events[eventName][i].callback.apply(this, args);
|
315
|
+
}
|
316
|
+
},
|
317
|
+
|
318
|
+
unbind: function(eventName){
|
319
|
+
var namespace = null;
|
320
|
+
if ( eventName.indexOf(".") > -1 ) {
|
321
|
+
var namespaces = eventName.split(".");
|
322
|
+
eventName = namespaces.shift();
|
323
|
+
namespace = namespaces.slice(0).sort().join(".");
|
215
324
|
}
|
325
|
+
if (namespace){
|
326
|
+
for (var i=0; i<this.events[eventName].length; i++){
|
327
|
+
if (this.events[eventName][i].namespace == namespace){
|
328
|
+
this.events[eventName].splice(i);
|
329
|
+
}
|
330
|
+
}
|
331
|
+
}
|
332
|
+
else this.events[eventName] = [];
|
333
|
+
},
|
334
|
+
|
335
|
+
plugin: function(pClass, prop){
|
336
|
+
if (prop) pClass = pClass.extend(prop);
|
337
|
+
this.plugins[pClass] = new pClass(this);
|
338
|
+
var plugin = this.plugins[pClass];
|
339
|
+
for (var name in pClass.prototype){
|
340
|
+
if (name.substring(0, 1) == '_') continue;
|
341
|
+
if (typeof pClass.prototype[name] == "function" && !this[name]){
|
342
|
+
this[name] = function(name){
|
343
|
+
return function(){
|
344
|
+
return plugin[name].apply(this, arguments);
|
345
|
+
};
|
346
|
+
}(name);
|
347
|
+
}
|
348
|
+
}
|
349
|
+
},
|
350
|
+
|
351
|
+
widget: function(id){
|
352
|
+
return this.widgets[id];
|
353
|
+
},
|
354
|
+
|
355
|
+
onWidget: function(id, callback){
|
356
|
+
if (!this.onWidgetCallbacks[id]) this.onWidgetCallbacks[id] = [];
|
357
|
+
this.onWidgetCallbacks[id].push(callback);
|
216
358
|
}
|
217
359
|
|
218
360
|
|
@@ -276,20 +418,29 @@ Spider.WidgetBackend = Class.extend({
|
|
276
418
|
},
|
277
419
|
|
278
420
|
send: function(method, args, options){
|
279
|
-
|
280
|
-
for (var i=0; i<args.length; i++){
|
281
|
-
url += '&_wp[]='+args[i];
|
282
|
-
}
|
283
|
-
var data = {};
|
284
|
-
var callback = this.widget[method+'_response'];
|
285
|
-
if (!callback) callback = function(){};
|
421
|
+
if (!options) options = {};
|
286
422
|
var defaults = {
|
287
|
-
url: url,
|
288
423
|
type: 'POST',
|
289
|
-
|
290
|
-
data: data
|
424
|
+
dataType: 'json'
|
291
425
|
};
|
292
426
|
options = $.extend(defaults, options);
|
427
|
+
if (!options.format) options.format = options.dataType;
|
428
|
+
var url = this.baseUrl;
|
429
|
+
var data = {};
|
430
|
+
if ($.isPlainObject(args[0])) data = args[0];
|
431
|
+
else data = {'_wp': args};
|
432
|
+
$.extend(data, {
|
433
|
+
'_wt': this.widget.path,
|
434
|
+
'_we': method,
|
435
|
+
'_wf': options.format
|
436
|
+
});
|
437
|
+
var callback = this.widget[method+'_response'];
|
438
|
+
if (!callback) callback = options.callback;
|
439
|
+
if (!callback) callback = function(){};
|
440
|
+
delete(options.callback);
|
441
|
+
options.success = callback;
|
442
|
+
options.data = data;
|
443
|
+
options.url = url;
|
293
444
|
$.ajax(options);
|
294
445
|
}
|
295
446
|
|
@@ -327,6 +478,7 @@ Spider.defineWidget = function(name, parent, w){
|
|
327
478
|
});
|
328
479
|
});
|
329
480
|
}
|
481
|
+
return widget;
|
330
482
|
};
|
331
483
|
|
332
484
|
Spider.Controller = Class.extend({
|
@@ -335,8 +487,14 @@ Spider.Controller = Class.extend({
|
|
335
487
|
var url = ''+document.location;
|
336
488
|
var slashPos = url.lastIndexOf('/');
|
337
489
|
url = url.substr(0, slashPos);
|
338
|
-
this.url
|
490
|
+
this.setUrl(url);
|
339
491
|
},
|
492
|
+
|
493
|
+
setUrl: function(url){
|
494
|
+
this.url = url;
|
495
|
+
this.publicUrl = this.url+'/public'; // FIXME
|
496
|
+
this.homeUrl = this.url+'/_h';
|
497
|
+
},
|
340
498
|
|
341
499
|
remote: function(method, params, callback, options){
|
342
500
|
var args = Array.prototype.slice.call(arguments);
|
@@ -345,8 +503,9 @@ Spider.Controller = Class.extend({
|
|
345
503
|
var defaults = {
|
346
504
|
url: url,
|
347
505
|
type: 'POST',
|
348
|
-
|
349
|
-
data: params
|
506
|
+
success: callback,
|
507
|
+
data: params,
|
508
|
+
dataType: 'json'
|
350
509
|
};
|
351
510
|
options = $.extend(defaults, options);
|
352
511
|
$.ajax(options);
|
@@ -431,7 +590,9 @@ $(document).ready(function(){
|
|
431
590
|
|
432
591
|
$.fn.spiderWidget = function(){
|
433
592
|
if (!this.attr('id')) return;
|
434
|
-
|
593
|
+
var path = Spider.Widget.pathFromId(this.attr('id'));
|
594
|
+
if (Spider.widgets[path]) return Spider.widgets[path];
|
595
|
+
return Spider.Widget.initFromEl(this);
|
435
596
|
};
|
436
597
|
|
437
598
|
$.fn.parentWidget = function(){
|