spiderfw 0.5.10 → 0.5.11
Sign up to get free protection for your applications and to get access to all the features.
- 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(){
|