netzke-basepack 0.12.9 → 1.0.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +75 -44
- data/Gemfile +4 -2
- data/LICENSE +2 -6
- data/README.md +22 -24
- data/javascripts/basepack.js +0 -8
- data/javascripts/{columns.js → grid/columns.js} +59 -71
- data/javascripts/grid/event_handlers.js +218 -0
- data/javascripts/netzkeremotecombo.js +5 -13
- data/javascripts/tristate.js +62 -0
- data/javascripts/xdatetime.js +8 -37
- data/lib/netzke-basepack.rb +3 -2
- data/lib/netzke/basepack.rb +1 -1
- data/lib/netzke/basepack/action_column.rb +6 -23
- data/lib/netzke/basepack/active_record.rb +0 -6
- data/lib/netzke/basepack/attr_config.rb +20 -11
- data/lib/netzke/basepack/attribute_config.rb +10 -0
- data/lib/netzke/basepack/attributes.rb +196 -0
- data/lib/netzke/basepack/column_config.rb +47 -39
- data/lib/netzke/basepack/columns.rb +127 -97
- data/lib/netzke/basepack/data_accessor.rb +7 -48
- data/lib/netzke/basepack/data_adapters/abstract_adapter.rb +15 -17
- data/lib/netzke/basepack/data_adapters/active_record_adapter.rb +111 -90
- data/lib/netzke/basepack/dynamic_tab_panel.rb +3 -5
- data/lib/netzke/basepack/dynamic_tab_panel/{javascripts → client}/dynamic_tab_panel.js +6 -5
- data/lib/netzke/basepack/field_config.rb +30 -19
- data/lib/netzke/basepack/fields.rb +22 -12
- data/lib/netzke/basepack/grid_live_search.rb +1 -4
- data/lib/netzke/basepack/grid_live_search/{javascripts → client}/grid_live_search.js +9 -7
- data/lib/netzke/basepack/item_persistence.rb +3 -3
- data/lib/netzke/basepack/item_persistence/events_plugin.rb +8 -10
- data/lib/netzke/basepack/paging_form.rb +7 -11
- data/lib/netzke/basepack/paging_form/{javascripts → client}/paging_form.js +4 -4
- data/lib/netzke/basepack/query_builder.rb +12 -10
- data/lib/netzke/basepack/query_builder/{javascripts → client}/query_builder.js +14 -12
- data/lib/netzke/basepack/record_form_window.rb +8 -8
- data/lib/netzke/basepack/search_panel.rb +4 -6
- data/lib/netzke/basepack/search_panel/{javascripts → client}/condition_field.js +13 -16
- data/lib/netzke/basepack/search_panel/{javascripts → client}/search_panel.js +7 -7
- data/lib/netzke/basepack/search_window.rb +6 -6
- data/lib/netzke/basepack/simple_app/{javascripts → client}/statusbar_ext.js +0 -0
- data/lib/netzke/basepack/version.rb +1 -1
- data/lib/netzke/form/base.rb +166 -0
- data/lib/netzke/{basepack/form/javascripts/form.js → form/base/client/base.js} +77 -38
- data/lib/netzke/form/base/client/readonly_mode.css +4 -0
- data/lib/netzke/{basepack/form/javascripts → form/base/client}/readonly_mode.js +5 -5
- data/lib/netzke/form/endpoints.rb +33 -0
- data/lib/netzke/form/services.rb +74 -0
- data/lib/netzke/grid/actions.rb +52 -0
- data/lib/netzke/grid/base.rb +289 -0
- data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/advanced_search.js +5 -1
- data/lib/netzke/{basepack/grid/javascripts/grid.js → grid/base/client/base.js} +61 -53
- data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/extensions.js +19 -13
- data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/remember_selection.js +0 -1
- data/lib/netzke/grid/client.rb +8 -0
- data/lib/netzke/grid/components.rb +55 -0
- data/lib/netzke/grid/configuration.rb +72 -0
- data/lib/netzke/grid/endpoints.rb +99 -0
- data/lib/netzke/grid/permissions.rb +18 -0
- data/lib/netzke/grid/services.rb +141 -0
- data/lib/netzke/tree/base.rb +173 -0
- data/lib/netzke/{basepack/tree/javascripts/tree.js → tree/base/client/base.js} +55 -26
- data/lib/netzke/{basepack/tree/javascripts → tree/base/client}/extensions.js +7 -7
- data/lib/netzke/tree/endpoints.rb +34 -0
- data/lib/netzke/{basepack/viewport.rb → viewport/base.rb} +3 -3
- data/lib/netzke/{basepack/window.rb → window/base.rb} +7 -8
- data/lib/netzke/window/base/client/base.js +26 -0
- data/locales/de.yml +49 -33
- data/locales/en.yml +32 -39
- data/locales/es.yml +39 -25
- data/locales/nl.yml +39 -25
- data/locales/ru.yml +38 -25
- data/locales/uk.yml +40 -26
- data/stylesheets/basepack.css +10 -0
- metadata +48 -45
- data/javascripts/mixins/grid_event_handlers.js +0 -139
- data/lib/netzke/basepack/accordion.rb +0 -45
- data/lib/netzke/basepack/active_record/relation_extensions.rb +0 -27
- data/lib/netzke/basepack/form.rb +0 -131
- data/lib/netzke/basepack/form/endpoints.rb +0 -35
- data/lib/netzke/basepack/form/services.rb +0 -74
- data/lib/netzke/basepack/form/stylesheets/readonly_mode.css +0 -14
- data/lib/netzke/basepack/grid.rb +0 -570
- data/lib/netzke/basepack/grid/endpoints.rb +0 -111
- data/lib/netzke/basepack/grid/javascripts/edit_in_form.js +0 -51
- data/lib/netzke/basepack/grid/services.rb +0 -148
- data/lib/netzke/basepack/tab_panel.rb +0 -22
- data/lib/netzke/basepack/tab_panel/javascripts/tab_panel.js +0 -11
- data/lib/netzke/basepack/tree.rb +0 -269
- data/lib/netzke/basepack/window/javascripts/window.js +0 -26
- data/lib/netzke/basepack/wrap_lazy_loaded.rb +0 -29
@@ -1,111 +0,0 @@
|
|
1
|
-
module Netzke
|
2
|
-
module Basepack
|
3
|
-
class Grid < Netzke::Base
|
4
|
-
module Endpoints
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
included do
|
8
|
-
endpoint :server_read do |data, this|
|
9
|
-
attempt_operation(:read, data, this)
|
10
|
-
end
|
11
|
-
|
12
|
-
endpoint :server_create do |data, this|
|
13
|
-
attempt_operation(:create, data, this)
|
14
|
-
end
|
15
|
-
|
16
|
-
endpoint :server_update do |data, this|
|
17
|
-
attempt_operation(:update, data, this)
|
18
|
-
end
|
19
|
-
|
20
|
-
endpoint :server_delete do |data, this|
|
21
|
-
attempt_operation(:destroy, data, this)
|
22
|
-
end
|
23
|
-
|
24
|
-
endpoint :server_save_columns do |cols, this|
|
25
|
-
state[:columns_order] = cols
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns options for a combobox
|
29
|
-
# params receive:
|
30
|
-
# +attr+ - column's name
|
31
|
-
# +query+ - what's typed-in in the combobox
|
32
|
-
# +id+ - selected record id
|
33
|
-
endpoint :get_combobox_options do |params, this|
|
34
|
-
column = final_columns.detect{ |c| c[:name] == params[:attr] }
|
35
|
-
this.data = data_adapter.combo_data(column, params[:query])
|
36
|
-
end
|
37
|
-
|
38
|
-
endpoint :move_rows do |params, this|
|
39
|
-
data_adapter.move_records(params)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Process the submit of multi-editing form ourselves
|
43
|
-
# TODO: refactor to let the form handle the validations
|
44
|
-
endpoint :multi_edit_window__multi_edit_form__netzke_submit do |params, this|
|
45
|
-
ids = ActiveSupport::JSON.decode(params.delete(:ids))
|
46
|
-
data = ids.collect{ |id| ActiveSupport::JSON.decode(params[:data]).merge("id" => id) }
|
47
|
-
|
48
|
-
data.map!{|el| el.delete_if{ |k,v| v.is_a?(String) && v.blank? }} # only interested in set values
|
49
|
-
|
50
|
-
res = attempt_operation(:update, data, this)
|
51
|
-
|
52
|
-
errors = []
|
53
|
-
res.each do |id, out|
|
54
|
-
errors << out[:error] if out[:error]
|
55
|
-
end
|
56
|
-
|
57
|
-
if errors.empty?
|
58
|
-
on_data_changed
|
59
|
-
this.netzke_set_result("ok")
|
60
|
-
this.on_submit_success
|
61
|
-
end
|
62
|
-
|
63
|
-
this.netzke_feedback(errors)
|
64
|
-
end
|
65
|
-
|
66
|
-
# The following two look a bit hackish, but serve to invoke on_data_changed when a form gets successfully
|
67
|
-
# submitted
|
68
|
-
endpoint :add_window__add_form__netzke_submit do |params, this|
|
69
|
-
this.merge!(component_instance(:add_window).
|
70
|
-
component_instance(:add_form).
|
71
|
-
invoke_endpoint(:netzke_submit, params))
|
72
|
-
on_data_changed if this.set_form_values.present?
|
73
|
-
this.delete(:set_form_values)
|
74
|
-
end
|
75
|
-
|
76
|
-
endpoint :edit_window__edit_form__netzke_submit do |params, this|
|
77
|
-
this.merge!(component_instance(:edit_window).
|
78
|
-
component_instance(:edit_form).
|
79
|
-
invoke_endpoint(:netzke_submit, params))
|
80
|
-
on_data_changed if this.set_form_values.present?
|
81
|
-
this.delete(:set_form_values)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# Operations:
|
86
|
-
# create, read, update, delete
|
87
|
-
def attempt_operation(op, data, this)
|
88
|
-
# if data is ActionController::Parameters and a scope is in the component config
|
89
|
-
# then ran this in an ActiveModel::ForbiddenAttributesError (rails 4 strong parameters)
|
90
|
-
# solution: in this case convert ActionController::Parameters to a Hash
|
91
|
-
if data.is_a?ActionController::Parameters
|
92
|
-
dataHash = {}
|
93
|
-
data.each do |k,v|
|
94
|
-
#preserve keys as symbol
|
95
|
-
dataHash[k.to_sym] = v
|
96
|
-
end
|
97
|
-
data = dataHash
|
98
|
-
end
|
99
|
-
if !config["prohibit_#{op}"]
|
100
|
-
res = send(op, data)
|
101
|
-
this.netzke_set_result res
|
102
|
-
res
|
103
|
-
else
|
104
|
-
this.netzke_feedback I18n.t("netzke.basepack.grid.cannot_#{op}")
|
105
|
-
this.netzke_set_result(data: [], total: 0)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
{
|
2
|
-
onEditInForm: function(){
|
3
|
-
var selModel = this.getSelectionModel();
|
4
|
-
if (selModel.getCount() > 1) {
|
5
|
-
var recordId = selModel.selected.first().getId();
|
6
|
-
this.netzkeLoadComponent("multi_edit_window", {
|
7
|
-
params: {record_id: recordId},
|
8
|
-
callback: function(w){
|
9
|
-
w.show();
|
10
|
-
var form = w.items.first();
|
11
|
-
form.on('apply', function(){
|
12
|
-
var ids = [];
|
13
|
-
selModel.selected.each(function(r){
|
14
|
-
ids.push(r.getId());
|
15
|
-
});
|
16
|
-
if (!form.baseParams) form.baseParams = {};
|
17
|
-
form.baseParams.ids = Ext.encode(ids);
|
18
|
-
}, this);
|
19
|
-
|
20
|
-
w.on('close', function(){
|
21
|
-
if (w.closeRes === "ok") {
|
22
|
-
this.store.load();
|
23
|
-
}
|
24
|
-
}, this);
|
25
|
-
}, scope: this});
|
26
|
-
} else {
|
27
|
-
var recordId = selModel.selected.first().getId();
|
28
|
-
this.netzkeLoadComponent("edit_window", {
|
29
|
-
clientConfig: {record_id: recordId},
|
30
|
-
callback: function(w){
|
31
|
-
w.show();
|
32
|
-
w.on('close', function(){
|
33
|
-
if (w.closeRes === "ok") {
|
34
|
-
this.store.load();
|
35
|
-
}
|
36
|
-
}, this);
|
37
|
-
}, scope: this});
|
38
|
-
}
|
39
|
-
},
|
40
|
-
|
41
|
-
onAddInForm: function(){
|
42
|
-
this.netzkeLoadComponent("add_window", {callback: function(w){
|
43
|
-
w.show();
|
44
|
-
w.on('close', function(){
|
45
|
-
if (w.closeRes === "ok") {
|
46
|
-
this.store.load();
|
47
|
-
}
|
48
|
-
}, this);
|
49
|
-
}, scope: this});
|
50
|
-
}
|
51
|
-
}
|
@@ -1,148 +0,0 @@
|
|
1
|
-
module Netzke
|
2
|
-
module Basepack
|
3
|
-
class Grid < Netzke::Base
|
4
|
-
# Implements Grid server-side operations. Used by the Endpoints module.
|
5
|
-
module Services
|
6
|
-
# Implementation for the "server_read" endpoint
|
7
|
-
def read(params = {})
|
8
|
-
{}.tap do |res|
|
9
|
-
records = get_records(params)
|
10
|
-
res[:data] = records.map{|r| data_adapter.record_to_array(r, final_columns(:with_meta => true))}
|
11
|
-
res[:total] = count_records(params) if config[:enable_pagination]
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
# Returns hash with results per client (temporary) id, e.g.:
|
16
|
-
#
|
17
|
-
# {
|
18
|
-
# 1: {errors: [], record: {title: 'New title'}},
|
19
|
-
# 2: {errors: ["Title must be present"], record: nil}
|
20
|
-
# }
|
21
|
-
def create(data)
|
22
|
-
data.inject({}) do |out, attrs|
|
23
|
-
id = attrs.delete('internal_id')
|
24
|
-
record = data_adapter.new_record
|
25
|
-
out.merge(id => update_record(record, attrs))
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# Receives an array of attribute hashes, e.g.:
|
30
|
-
#
|
31
|
-
# [{"id": 1, title: "New title"}, {"id": 2, title: ""}]
|
32
|
-
#
|
33
|
-
# Returns hash with results per id, e.g.:
|
34
|
-
#
|
35
|
-
# {
|
36
|
-
# 1: {errors: [], record: {title: 'New title'}},
|
37
|
-
# 2: {errors: ["Title must be present"], record: nil}
|
38
|
-
# }
|
39
|
-
def update(data)
|
40
|
-
data.inject({}) do |out, attrs|
|
41
|
-
id = attrs.delete(data_adapter.primary_key)
|
42
|
-
record = data_adapter.find_record(id, scope: config.scope)
|
43
|
-
record.nil? ? out.merge(id => {error: "Not allowed to edit record #{id}"}) : out.merge(id => update_record(record, attrs))
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Destroys records by ids
|
48
|
-
# Returns hash with results per id, e.g.:
|
49
|
-
#
|
50
|
-
# {
|
51
|
-
# 1: "ok",
|
52
|
-
# 2: "error: "This record could not be destroyed"
|
53
|
-
# }
|
54
|
-
def destroy(ids)
|
55
|
-
out = {}
|
56
|
-
|
57
|
-
ids.each {|id|
|
58
|
-
record = data_adapter.find_record(id, scope: config[:scope])
|
59
|
-
next if record.nil?
|
60
|
-
|
61
|
-
if record.destroy
|
62
|
-
out[id] = "ok"
|
63
|
-
else
|
64
|
-
out[id] = {error: record.errors.to_a.first}
|
65
|
-
end
|
66
|
-
}
|
67
|
-
|
68
|
-
out
|
69
|
-
end
|
70
|
-
|
71
|
-
# Returns an array of records.
|
72
|
-
def get_records(params)
|
73
|
-
params[:filters] = normalize_filters(params[:filters]) if params[:filters]
|
74
|
-
params[:query] = normalize_query(params[:query]) if params[:query].present?
|
75
|
-
if config[:enable_pagination]
|
76
|
-
params[:limit] = config[:rows_per_page]
|
77
|
-
else
|
78
|
-
params.delete(:limit)
|
79
|
-
end
|
80
|
-
params[:scope] = config[:scope] # note, params[:scope] becomes ActiveSupport::HashWithIndifferentAccess
|
81
|
-
|
82
|
-
data_adapter.get_records(params, final_columns)
|
83
|
-
end
|
84
|
-
|
85
|
-
def count_records(params)
|
86
|
-
params[:scope] = config[:scope] # note, params[:scope] becomes ActiveSupport::HashWithIndifferentAccess
|
87
|
-
|
88
|
-
data_adapter.count_records(params, final_columns)
|
89
|
-
end
|
90
|
-
|
91
|
-
# Override this method to react on each operation that caused changing of data
|
92
|
-
def on_data_changed
|
93
|
-
end
|
94
|
-
|
95
|
-
protected
|
96
|
-
|
97
|
-
def normalize_filters(filters)
|
98
|
-
filters.map do |f|
|
99
|
-
{ attr: f["property"], value: f["value"], operator: f["operator"] }.tap do |norm|
|
100
|
-
|
101
|
-
# Ext JS filters send us date in the American format
|
102
|
-
if f["value"].is_a?(String) && f["value"].match(/^(\d\d)\/(\d\d)\/(\d\d\d\d)$/)
|
103
|
-
norm[:value] = "#{$3}-#{$1}-#{$2}"
|
104
|
-
end
|
105
|
-
|
106
|
-
if filter_with = final_columns_hash[norm[:attr].to_sym][:filter_with]
|
107
|
-
norm[:proc] = filter_with
|
108
|
-
end
|
109
|
-
|
110
|
-
norm[:operator] = "contains" if f["type"] == "string"
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def normalize_query(or_query)
|
116
|
-
or_query.each do |and_query|
|
117
|
-
and_query.each do |q|
|
118
|
-
column_config = final_columns_hash[q[:attr].to_sym] || {}
|
119
|
-
if filter_with = column_config[:filter_with]
|
120
|
-
q[:proc] = filter_with
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def update_record(record, attrs)
|
127
|
-
attrs.each_pair do |k,v|
|
128
|
-
attr = final_columns_hash[k.to_sym]
|
129
|
-
next if attr.nil?
|
130
|
-
data_adapter.set_record_value_for_attribute(record, attr, v)
|
131
|
-
end
|
132
|
-
|
133
|
-
strong_attrs = config[:strong_default_attrs] || {}
|
134
|
-
|
135
|
-
strong_attrs.each_pair do |k,v|
|
136
|
-
data_adapter.set_record_value_for_attribute(record, {name: k.to_s}, v)
|
137
|
-
end
|
138
|
-
|
139
|
-
if record.save
|
140
|
-
{record: data_adapter.record_to_array(record, final_columns(:with_meta => true))}
|
141
|
-
else
|
142
|
-
{error: record.errors.to_a}
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Netzke
|
2
|
-
module Basepack
|
3
|
-
# = TabPanel
|
4
|
-
#
|
5
|
-
# Features:
|
6
|
-
# * Dynamically loads components for the tabs that get activated for the first time
|
7
|
-
# * (TODO) Provides the method markTabsOutdated to mark all inactive tabs as 'outdated', and calls "update" method on components in tabs when they get activated
|
8
|
-
# * (TODO) Stores the last active tab in persistent config
|
9
|
-
#
|
10
|
-
# ToDo:
|
11
|
-
# * Introduce a second or two delay before informing the server about a tab switched
|
12
|
-
class TabPanel < Netzke::Base
|
13
|
-
|
14
|
-
include WrapLazyLoaded
|
15
|
-
|
16
|
-
js_configure do |c|
|
17
|
-
c.extend = "Ext.tab.Panel"
|
18
|
-
c.mixin
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
{
|
2
|
-
initComponent: function(params){
|
3
|
-
this.callParent();
|
4
|
-
this.on('tabchange', function(self, tab){
|
5
|
-
if (tab && tab.wrappedComponent && !tab.items.first() && !tab.beingLoaded) {
|
6
|
-
tab.beingLoaded = true; // prevent more than one request per tab in case of fast clicking
|
7
|
-
this.netzkeLoadComponent(tab.wrappedComponent, {container: tab.id, callback: function(){tab.beingLoaded = false}});
|
8
|
-
}
|
9
|
-
}, this);
|
10
|
-
}
|
11
|
-
}
|
data/lib/netzke/basepack/tree.rb
DELETED
@@ -1,269 +0,0 @@
|
|
1
|
-
module Netzke
|
2
|
-
module Basepack
|
3
|
-
# Ext.tree.Panel-based component with the following features:
|
4
|
-
#
|
5
|
-
# * CRUD operations
|
6
|
-
# * Persistence of node expand/collapse state
|
7
|
-
# * (TODO) Node reordering by DnD
|
8
|
-
#
|
9
|
-
# == Simple example
|
10
|
-
#
|
11
|
-
# class Files < Netzke::Basepack::Tree
|
12
|
-
# def configure(c)
|
13
|
-
# super
|
14
|
-
# c.model = "FileRecord"
|
15
|
-
# c.columns = [
|
16
|
-
# {name: :name, xtype: :treecolumn}, # this column will show tree nodes
|
17
|
-
# :size
|
18
|
-
# ]
|
19
|
-
# end
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# == Instance configuration
|
23
|
-
#
|
24
|
-
# The following config options are supported:
|
25
|
-
#
|
26
|
-
# [model]
|
27
|
-
#
|
28
|
-
# Name of the ActiveRecord model that provides data to this Tree, e.g. "FileRecord"
|
29
|
-
# The model must respond to the following methods:
|
30
|
-
#
|
31
|
-
# * TreeModel.root - the root record
|
32
|
-
# * TreeModel#children - child records
|
33
|
-
#
|
34
|
-
# Note that the awesome_nested_set gem implements the above, so, feel free to use it.
|
35
|
-
#
|
36
|
-
# [columns]
|
37
|
-
#
|
38
|
-
# An array of columns to be displayed in the tree. See the "Columns" section in the `Netzke::Basepack::Grid`.
|
39
|
-
# Additionally, you probably will want to specify which column will have the tree nodes UI by providing the
|
40
|
-
# `xtype` config option set to `:treecolumn`.
|
41
|
-
#
|
42
|
-
# [root]
|
43
|
-
#
|
44
|
-
# By default, the component will pick whatever record is returned by `TreeModel.root`, and use it as the root
|
45
|
-
# record. However, sometimes the model table has multiple root records (whith `parent_id` set to `nil`), and all
|
46
|
-
# of them should be shown in the panel. To achive this, you can define the `root` config option,
|
47
|
-
# which will serve as a virtual root record for those records. You may set it to `true`, or a hash of
|
48
|
-
# attributes, e.g.:
|
49
|
-
#
|
50
|
-
# c.root = {name: 'Root', size: 1000}
|
51
|
-
#
|
52
|
-
# Note, that the root record can be hidden from the tree by specifying the `Ext.tree.Panel`'s `root_visible`
|
53
|
-
# config option set to `false`, which is probably what you want when you have multiple root records.
|
54
|
-
#
|
55
|
-
# [scope]
|
56
|
-
#
|
57
|
-
# Specifies how the records should be scoped.
|
58
|
-
#
|
59
|
-
# When it's a symbol, it's used as a scope name.
|
60
|
-
# When it's a string, it's a SQL statement (passed directly to +where+).
|
61
|
-
# When it's a hash, it's a conditions hash (passed directly to +where+).
|
62
|
-
# When it's an array, it's expanded into an SQL statement with arguments (passed directly to +where+), e.g.:
|
63
|
-
#
|
64
|
-
# scope: ["id > ?", 100])
|
65
|
-
#
|
66
|
-
# When it's a Proc, it gets the current relation passed as the only parameter and is expected to return a
|
67
|
-
# relation, e.g.:
|
68
|
-
#
|
69
|
-
# scope: ->(relation) { relation.where(user_id: 100) }
|
70
|
-
#
|
71
|
-
# == Persisting nodes' expand/collapse state
|
72
|
-
#
|
73
|
-
# If the model includes the `expanded` DB field, the expand/collapse state will get stored in the DB.
|
74
|
-
class Tree < Netzke::Base
|
75
|
-
NODE_ATTRS = {
|
76
|
-
boolean: %w[leaf checked expanded expandable qtip qtitle],
|
77
|
-
string: %w[icon icon_cls href href_target qtip qtitle]
|
78
|
-
}
|
79
|
-
|
80
|
-
include Netzke::Basepack::Grid::Endpoints
|
81
|
-
include Netzke::Basepack::Grid::Services
|
82
|
-
include Netzke::Basepack::Columns
|
83
|
-
include Netzke::Basepack::DataAccessor
|
84
|
-
|
85
|
-
js_configure do |c|
|
86
|
-
c.extend = "Ext.tree.Panel"
|
87
|
-
c.mixin
|
88
|
-
c.mixins << "Netzke.mixins.Basepack.Columns"
|
89
|
-
c.mixins << "Netzke.mixins.Basepack.GridEventHandlers"
|
90
|
-
c.translate *%w[are_you_sure confirmation]
|
91
|
-
c.require :extensions
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.server_side_config_options
|
95
|
-
super + [:model]
|
96
|
-
end
|
97
|
-
|
98
|
-
def configure(c)
|
99
|
-
set_defaults(c)
|
100
|
-
super
|
101
|
-
end
|
102
|
-
|
103
|
-
def columns
|
104
|
-
add_node_interface_methods(super)
|
105
|
-
end
|
106
|
-
|
107
|
-
def get_records(params)
|
108
|
-
if params[:id] == 'root'
|
109
|
-
data_adapter.find_root_records(config[:scope])
|
110
|
-
else
|
111
|
-
data_adapter.find_record_children(data_adapter.find_record(params[:id]), config[:scope])
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
# Override Grid::Services#read so we send records as key-value JSON (instead of array)
|
116
|
-
def read(params = {})
|
117
|
-
{}.tap do |res|
|
118
|
-
records = get_records(params)
|
119
|
-
res["children"] = records.map{|r| node_to_hash(r, final_columns(with_meta: true)).netzke_literalize_keys}
|
120
|
-
res["total"] = count_records(params) if config[:enable_pagination]
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def node_to_hash(record, columns)
|
125
|
-
data_adapter.record_to_hash(record, columns).tap do |hash|
|
126
|
-
if is_node_expanded?(record)
|
127
|
-
hash["children"] = record.children.extend_with(config.scope).map {|child| node_to_hash(child, columns).netzke_literalize_keys}
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def is_node_expanded?(record)
|
133
|
-
record.respond_to?(:expanded) && record.expanded?
|
134
|
-
end
|
135
|
-
|
136
|
-
def js_configure(c)
|
137
|
-
super
|
138
|
-
|
139
|
-
c.title = c.title || self.class.js_config.properties[:title] || data_class.name.pluralize
|
140
|
-
c.bbar = bbar
|
141
|
-
# c.context_menu = context_menu
|
142
|
-
c.columns = {items: js_columns}
|
143
|
-
c.columns_order = columns_order
|
144
|
-
c.pri = data_adapter.primary_key
|
145
|
-
|
146
|
-
if c.default_filters
|
147
|
-
populate_cols_with_filters(c)
|
148
|
-
end
|
149
|
-
|
150
|
-
c.root ||= data_adapter.record_to_hash(data_adapter.root, final_columns(with_meta: true)).netzke_literalize_keys
|
151
|
-
end
|
152
|
-
|
153
|
-
action :add do |a|
|
154
|
-
a.handler = "onAddRecord" # overriding naming conventions as Ext 4 grid has its own onAdd method
|
155
|
-
a.icon = :add
|
156
|
-
end
|
157
|
-
|
158
|
-
action :edit do |a|
|
159
|
-
# a.disabled = true
|
160
|
-
a.handler = :onEdit
|
161
|
-
a.icon = :table_edit
|
162
|
-
end
|
163
|
-
|
164
|
-
action :apply do |a|
|
165
|
-
a.disabled = config[:prohibit_update] && config[:prohibit_create]
|
166
|
-
a.icon = :tick
|
167
|
-
end
|
168
|
-
|
169
|
-
action :del do |a|
|
170
|
-
# a.disabled = true
|
171
|
-
a.icon = :table_row_delete
|
172
|
-
end
|
173
|
-
|
174
|
-
component :add_window do |c|
|
175
|
-
preconfigure_record_window(c)
|
176
|
-
c.title = "Add #{data_class.model_name.human}"
|
177
|
-
c.items = [:add_form]
|
178
|
-
c.form_config.record = data_class.new(columns_default_values)
|
179
|
-
end
|
180
|
-
|
181
|
-
component :edit_window do |c|
|
182
|
-
preconfigure_record_window(c)
|
183
|
-
c.title = "Edit #{data_class.model_name.human}"
|
184
|
-
c.items = [:edit_form]
|
185
|
-
end
|
186
|
-
|
187
|
-
component :multi_edit_window do |c|
|
188
|
-
preconfigure_record_window(c)
|
189
|
-
c.title = "Edit #{data_class.model_name.human.pluralize}"
|
190
|
-
c.items = [:multi_edit_form]
|
191
|
-
end
|
192
|
-
|
193
|
-
endpoint :add_window__add_form__netzke_submit do |params, this|
|
194
|
-
data = ActiveSupport::JSON.decode(params[:data])
|
195
|
-
data["parent_id"] = params["parent_id"]
|
196
|
-
this.merge!(component_instance(:add_window).
|
197
|
-
component_instance(:add_form).
|
198
|
-
submit(data, this))
|
199
|
-
on_data_changed if this.set_form_values.present?
|
200
|
-
this.delete(:set_form_values)
|
201
|
-
end
|
202
|
-
|
203
|
-
endpoint :server_update_node_state do |params, this|
|
204
|
-
node = data_adapter.find_record(params[:id])
|
205
|
-
if node.respond_to?(:expanded)
|
206
|
-
node.expanded = params[:expanded]
|
207
|
-
data_adapter.save_record(node)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
protected
|
212
|
-
|
213
|
-
def bbar
|
214
|
-
config.has_key?(:bbar) ? config[:bbar] : default_bbar
|
215
|
-
end
|
216
|
-
|
217
|
-
# Override to change the default bottom toolbar
|
218
|
-
def default_bbar
|
219
|
-
[:add, :edit, :apply, :del]
|
220
|
-
end
|
221
|
-
|
222
|
-
def preconfigure_record_window(c)
|
223
|
-
c.klass = RecordFormWindow
|
224
|
-
|
225
|
-
c.form_config = ActiveSupport::OrderedOptions.new.tap do |f|
|
226
|
-
f.model = config[:model]
|
227
|
-
f.persistent_config = config[:persistent_config]
|
228
|
-
f.strong_default_attrs = config[:strong_default_attrs]
|
229
|
-
f.mode = config[:mode]
|
230
|
-
f.items = default_fields_for_forms
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
private
|
235
|
-
|
236
|
-
# Adds attributes known to Ext.data.NodeInterface as meta columns (only those our model responds to)
|
237
|
-
def add_node_interface_methods(columns)
|
238
|
-
columns.clone.tap do |columns|
|
239
|
-
NODE_ATTRS.each do |type, attrs|
|
240
|
-
add_node_interface_methods_by_type!(columns, attrs, type)
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
def add_node_interface_methods_by_type!(columns, attrs, type)
|
246
|
-
attrs.each do |a|
|
247
|
-
next unless data_adapter.model_respond_to?(a.to_sym)
|
248
|
-
columns << {attr_type: type, name: a, meta: true}
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
def set_defaults(c)
|
253
|
-
# The nil? checks are needed because these can be already set in a subclass
|
254
|
-
c.enable_edit_in_form = true if c.enable_edit_in_form.nil?
|
255
|
-
c.enable_edit_inline = true if c.enable_edit_inline.nil?
|
256
|
-
c.enable_extended_search = true if c.enable_extended_search.nil?
|
257
|
-
c.enable_column_filters = true if c.enable_column_filters.nil?
|
258
|
-
c.enable_pagination = true if c.enable_pagination.nil?
|
259
|
-
c.rows_per_page = 30 if c.rows_per_page.nil?
|
260
|
-
c.tools = %w{ refresh } if c.tools.nil?
|
261
|
-
end
|
262
|
-
|
263
|
-
def self.server_side_config_options
|
264
|
-
super + [:scope]
|
265
|
-
end
|
266
|
-
|
267
|
-
end
|
268
|
-
end
|
269
|
-
end
|