weaver 0.8.0 → 0.8.1
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.
- checksums.yaml +5 -5
- data/Rakefile +1 -1
- data/bin/console +3 -3
- data/exe/weaver +112 -122
- data/lib/weaver.rb +24 -2654
- data/lib/weaver/element_types/accordion.rb +122 -0
- data/lib/weaver/element_types/action.rb +38 -0
- data/lib/weaver/element_types/code.rb +81 -0
- data/lib/weaver/element_types/dynamic_table.rb +324 -0
- data/lib/weaver/element_types/dynamic_table_cell.rb +16 -0
- data/lib/weaver/element_types/form.rb +47 -0
- data/lib/weaver/element_types/form_elements.rb +297 -0
- data/lib/weaver/element_types/javascript_object.rb +28 -0
- data/lib/weaver/element_types/modal_dialog.rb +68 -0
- data/lib/weaver/element_types/panel.rb +124 -0
- data/lib/weaver/element_types/row.rb +117 -0
- data/lib/weaver/element_types/tabs.rb +75 -0
- data/lib/weaver/element_types/textfield_javascript.rb +58 -0
- data/lib/weaver/elements.rb +406 -0
- data/lib/weaver/page_types/center_page.rb +25 -0
- data/lib/weaver/page_types/empty_page.rb +26 -0
- data/lib/weaver/page_types/nav_page.rb +39 -0
- data/lib/weaver/page_types/nonnav_page.rb +35 -0
- data/lib/weaver/page_types/page.rb +234 -0
- data/lib/weaver/page_types/raw_page.rb +17 -0
- data/lib/weaver/page_types/sidenav_page.rb +119 -0
- data/lib/weaver/page_types/structured_page.rb +19 -0
- data/lib/weaver/page_types/topnav_page.rb +167 -0
- data/lib/weaver/version.rb +1 -1
- data/lib/weaver/weave.rb +44 -0
- data/weaver.gemspec +27 -24
- metadata +37 -13
@@ -0,0 +1,122 @@
|
|
1
|
+
module Weaver
|
2
|
+
# Accordion element
|
3
|
+
class Accordion
|
4
|
+
def initialize(page, anchors)
|
5
|
+
@anchors = anchors
|
6
|
+
@tabs = {}
|
7
|
+
@paneltype = :panel
|
8
|
+
@is_collapsed = false
|
9
|
+
@page = page
|
10
|
+
|
11
|
+
@anchors['accordia'] = [] unless @anchors['accordia']
|
12
|
+
|
13
|
+
accArray = @anchors['accordia']
|
14
|
+
|
15
|
+
@accordion_name = "accordion#{accArray.length}"
|
16
|
+
accArray << @accordion_name
|
17
|
+
end
|
18
|
+
|
19
|
+
def collapsed(isCollapsed)
|
20
|
+
@is_collapsed = isCollapsed
|
21
|
+
end
|
22
|
+
|
23
|
+
def type(type)
|
24
|
+
@paneltype = type
|
25
|
+
end
|
26
|
+
|
27
|
+
def tab(title, options = {}, &block)
|
28
|
+
@anchors['tabs'] = [] unless @anchors['tabs']
|
29
|
+
|
30
|
+
tabArray = @anchors['tabs']
|
31
|
+
|
32
|
+
elem = Elements.new(@page, @anchors)
|
33
|
+
elem.instance_eval(&block)
|
34
|
+
|
35
|
+
tabname = "tab#{tabArray.length}"
|
36
|
+
tabArray << tabname
|
37
|
+
|
38
|
+
@tabs[tabname] =
|
39
|
+
{
|
40
|
+
title: title,
|
41
|
+
elem: elem
|
42
|
+
}
|
43
|
+
|
44
|
+
if options[:mixpanel_event_name]
|
45
|
+
@tabs[tabname][:mixpanel_event_name] = options[:mixpanel_event_name]
|
46
|
+
end
|
47
|
+
|
48
|
+
if options[:mixpanel_event_props]
|
49
|
+
@tabs[tabname][:mixpanel_event_props] = options[:mixpanel_event_props]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def generate
|
54
|
+
tabbar = Elements.new(@page, @anchors)
|
55
|
+
|
56
|
+
tabs = @tabs
|
57
|
+
paneltype = @paneltype
|
58
|
+
accordion_name = @accordion_name
|
59
|
+
is_collapsed = @is_collapsed
|
60
|
+
|
61
|
+
tabbar.instance_eval do
|
62
|
+
div class: 'panel-group', id: accordion_name do
|
63
|
+
cls = 'panel-collapse collapse in'
|
64
|
+
cls = 'panel-collapse collapse' if is_collapsed
|
65
|
+
tabs.each do |anchor, value|
|
66
|
+
ibox do
|
67
|
+
type paneltype
|
68
|
+
body false
|
69
|
+
title do
|
70
|
+
div class: 'panel-title' do
|
71
|
+
options = {
|
72
|
+
"data-toggle": 'collapse',
|
73
|
+
"data-parent": "##{accordion_name}",
|
74
|
+
href: "##{anchor}"
|
75
|
+
}
|
76
|
+
|
77
|
+
if value[:mixpanel_event_name]
|
78
|
+
props = {}
|
79
|
+
if value[:mixpanel_event_props].is_a? Hash
|
80
|
+
props = value[:mixpanel_event_props]
|
81
|
+
end
|
82
|
+
options[:onclick] = "mixpanel.track('#{value[:mixpanel_event_name]}', #{props.to_json.tr('"', "'")})"
|
83
|
+
end
|
84
|
+
|
85
|
+
a options do
|
86
|
+
if value[:title].is_a? Symbol
|
87
|
+
icon value[:title]
|
88
|
+
else
|
89
|
+
text value[:title]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
extra do
|
96
|
+
div id: anchor, class: cls do
|
97
|
+
div class: 'panel-body' do
|
98
|
+
text value[:elem].generate
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
cls = 'panel-collapse collapse'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
tabbar.generate
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Add accordion to elements
|
114
|
+
class Elements
|
115
|
+
def accordion(&block)
|
116
|
+
acc = Accordion.new(@page, @anchors)
|
117
|
+
acc.instance_eval(&block)
|
118
|
+
|
119
|
+
@inner_content << acc.generate
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Weaver
|
2
|
+
class Action
|
3
|
+
def initialize(page, anchors, &block)
|
4
|
+
@page = page
|
5
|
+
@anchors = anchors
|
6
|
+
|
7
|
+
actionsArray = @anchors['action']
|
8
|
+
|
9
|
+
@anchors['action'] = [] unless @anchors['action']
|
10
|
+
|
11
|
+
actionsArray = @anchors['action']
|
12
|
+
|
13
|
+
@actionName = "action#{actionsArray.length}"
|
14
|
+
actionsArray << @actionName
|
15
|
+
|
16
|
+
@code = ''
|
17
|
+
|
18
|
+
instance_eval(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def script(code)
|
22
|
+
@code = code
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate
|
26
|
+
# puts @code
|
27
|
+
<<-FUNCTION
|
28
|
+
function #{@actionName}(caller, data) {
|
29
|
+
#{@code}
|
30
|
+
}
|
31
|
+
FUNCTION
|
32
|
+
end
|
33
|
+
|
34
|
+
def name
|
35
|
+
@actionName
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Weaver
|
2
|
+
class Code
|
3
|
+
def initialize(page, anchors, lang)
|
4
|
+
@page = page
|
5
|
+
@anchors = anchors
|
6
|
+
@content = ''
|
7
|
+
@options = {}
|
8
|
+
|
9
|
+
codeArray = @anchors['code']
|
10
|
+
|
11
|
+
@anchors['code'] = [] unless @anchors['code']
|
12
|
+
|
13
|
+
codeArray = @anchors['code']
|
14
|
+
|
15
|
+
@codeName = "code#{codeArray.length}"
|
16
|
+
codeArray << @codeName
|
17
|
+
|
18
|
+
@page.request_css 'css/plugins/codemirror/codemirror.css'
|
19
|
+
@page.request_js 'js/plugins/codemirror/codemirror.js'
|
20
|
+
|
21
|
+
language lang
|
22
|
+
end
|
23
|
+
|
24
|
+
def language(lang)
|
25
|
+
# TODO: improve langmap
|
26
|
+
langmap = {
|
27
|
+
javascript: { mime: 'text/javascript', file: 'javascript/javascript' }
|
28
|
+
}
|
29
|
+
|
30
|
+
if langmap[lang]
|
31
|
+
@options[:mode] = langmap[lang][:mime]
|
32
|
+
@page.request_js "js/plugins/codemirror/mode/#{langmap[lang][:file]}.js"
|
33
|
+
else
|
34
|
+
@options[:mode] = "text/x-#{lang}"
|
35
|
+
@page.request_js "js/plugins/codemirror/mode/#{lang}/#{lang}.js"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def content(text)
|
40
|
+
@content = text
|
41
|
+
end
|
42
|
+
|
43
|
+
def theme(name)
|
44
|
+
@options[:theme] = name
|
45
|
+
|
46
|
+
@page.request_css "css/plugins/codemirror/#{name}.css"
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate_script
|
50
|
+
@options[:lineNumbers] ||= true
|
51
|
+
@options[:matchBrackets] ||= true
|
52
|
+
@options[:styleActiveLine] ||= true
|
53
|
+
@options[:mode] ||= 'javascript'
|
54
|
+
@options[:readOnly] ||= true
|
55
|
+
|
56
|
+
<<-CODESCRIPT
|
57
|
+
$(document).ready(function()
|
58
|
+
{
|
59
|
+
CodeMirror.fromTextArea(document.getElementById("#{@codeName}"),
|
60
|
+
JSON.parse('#{@options.to_json}')
|
61
|
+
);
|
62
|
+
});
|
63
|
+
CODESCRIPT
|
64
|
+
end
|
65
|
+
|
66
|
+
def generate
|
67
|
+
content = @content
|
68
|
+
codeName = @codeName
|
69
|
+
|
70
|
+
elem = Elements.new(@page, @anchors)
|
71
|
+
|
72
|
+
elem.instance_eval do
|
73
|
+
textarea id: codeName do
|
74
|
+
text content
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
elem.generate
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'weaver/element_types/dynamic_table_cell'
|
2
|
+
module Weaver
|
3
|
+
# Tables that dynamically load data
|
4
|
+
class DynamicTable
|
5
|
+
def initialize(page, anchors, url, options = {}, &block)
|
6
|
+
@page = page
|
7
|
+
@anchors = anchors
|
8
|
+
@url = url
|
9
|
+
@options = options
|
10
|
+
@columns = nil
|
11
|
+
@query_object = nil
|
12
|
+
|
13
|
+
instance_eval(&block) if block
|
14
|
+
|
15
|
+
@options[:id] ||= @page.create_anchor 'dyn_table'
|
16
|
+
@table_name = @options[:id]
|
17
|
+
@head_name = "#{@table_name}_head"
|
18
|
+
@body_name = "#{@table_name}_body"
|
19
|
+
end
|
20
|
+
|
21
|
+
def column(name, options = {}, &block)
|
22
|
+
@columns = [] if @columns.nil?
|
23
|
+
|
24
|
+
title = options[:title] || name
|
25
|
+
format = nil
|
26
|
+
transform = nil
|
27
|
+
|
28
|
+
if options[:icon]
|
29
|
+
elem = Elements.new(@page, @anchors)
|
30
|
+
elem.instance_eval do
|
31
|
+
icon options[:icon]
|
32
|
+
text " #{title}"
|
33
|
+
end
|
34
|
+
title = elem.generate
|
35
|
+
end
|
36
|
+
|
37
|
+
if block
|
38
|
+
elem = DynamicTableCell.new(@page, @anchors)
|
39
|
+
elem.instance_eval(&block)
|
40
|
+
format = elem.generate
|
41
|
+
if elem.transform_script
|
42
|
+
func_name = @page.create_anchor 'transform'
|
43
|
+
@page.write_script_once <<-SCRIPT
|
44
|
+
document.transform_#{func_name} = function (input)
|
45
|
+
{
|
46
|
+
#{elem.transform_script}
|
47
|
+
}
|
48
|
+
SCRIPT
|
49
|
+
|
50
|
+
transform = func_name
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
@columns << { name: name, title: title, format: format, transform: transform }
|
55
|
+
end
|
56
|
+
|
57
|
+
def generate_table
|
58
|
+
table_name = @table_name
|
59
|
+
head_name = @head_name
|
60
|
+
body_name = @body_name
|
61
|
+
options = @options
|
62
|
+
|
63
|
+
columns = @columns || [{ title: 'Key' }, { title: 'Value' }]
|
64
|
+
|
65
|
+
elem = Elements.new(@page, @anchors)
|
66
|
+
elem.instance_eval do
|
67
|
+
table options do
|
68
|
+
thead id: head_name do
|
69
|
+
columns.each do |column, _|
|
70
|
+
if column.is_a? Hash
|
71
|
+
th column[:title].to_s
|
72
|
+
else
|
73
|
+
th column.to_s
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
tbody id: body_name do
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
elem.generate
|
84
|
+
end
|
85
|
+
|
86
|
+
def query(&block)
|
87
|
+
@query_object = JavaScriptObject.new(&block)
|
88
|
+
end
|
89
|
+
|
90
|
+
def generate_script
|
91
|
+
query_object_declaration = '{}'
|
92
|
+
query_string = ''
|
93
|
+
|
94
|
+
if @query_object
|
95
|
+
query_object_declaration = @query_object.generate
|
96
|
+
query_string = '+ "?" + $.param(query_object)'
|
97
|
+
end
|
98
|
+
|
99
|
+
member_expr = ''
|
100
|
+
member_expr = ".#{@options[:member]}" if @options[:member]
|
101
|
+
|
102
|
+
<<-DATATABLE_SCRIPT
|
103
|
+
|
104
|
+
function refresh_table_#{@table_name}()
|
105
|
+
{
|
106
|
+
var query_object = #{query_object_declaration};
|
107
|
+
|
108
|
+
$.get( "#{@url}" #{query_string}, function( returned_data )
|
109
|
+
{
|
110
|
+
var data = returned_data#{member_expr};
|
111
|
+
var data_object = {};
|
112
|
+
if (data !== null && typeof data === 'object')
|
113
|
+
{
|
114
|
+
data_object = data;
|
115
|
+
}
|
116
|
+
else
|
117
|
+
{
|
118
|
+
data_object = JSON.parse(data);
|
119
|
+
}
|
120
|
+
|
121
|
+
var head = $("##{@head_name}")
|
122
|
+
var body = $("##{@body_name}")
|
123
|
+
|
124
|
+
if($.isPlainObject(data_object))
|
125
|
+
{
|
126
|
+
for (var key in data_object)
|
127
|
+
{
|
128
|
+
var row = $('<tr>');
|
129
|
+
row.append($('<td>').text(key));
|
130
|
+
row.append($('<td>').text(data_object[key]));
|
131
|
+
body.append(row);
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
if ($.isArray(data_object))
|
136
|
+
{
|
137
|
+
|
138
|
+
var columnData = JSON.parse(#{@columns.to_json.inspect});
|
139
|
+
var columns = {};
|
140
|
+
var columnTitles = [];
|
141
|
+
head.empty();
|
142
|
+
if (#{@columns.nil?})
|
143
|
+
{
|
144
|
+
// Set up columns
|
145
|
+
for (var index in data_object)
|
146
|
+
{
|
147
|
+
for (var key in data_object[index])
|
148
|
+
{
|
149
|
+
columns[key] = Object.keys(columns).length;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
for (var key in columns)
|
153
|
+
{
|
154
|
+
columnTitles.push(key);
|
155
|
+
}
|
156
|
+
}
|
157
|
+
else
|
158
|
+
{
|
159
|
+
for (var key in columnData)
|
160
|
+
{
|
161
|
+
columns[columnData[key]["name"]] = Object.keys(columns).length;
|
162
|
+
columnTitles.push(columnData[key]["title"]);
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
var row = $('<tr>');
|
167
|
+
for (var key in columnTitles)
|
168
|
+
{
|
169
|
+
var columnTitle = $('<th>').html(columnTitles[key]);
|
170
|
+
row.append(columnTitle);
|
171
|
+
}
|
172
|
+
head.append(row);
|
173
|
+
|
174
|
+
for (var index in data_object)
|
175
|
+
{
|
176
|
+
var row = $('<tr>');
|
177
|
+
for (var columnIndex = 0; columnIndex < Object.keys(columns).length; columnIndex++) {
|
178
|
+
var cell_data = data_object[index][ Object.keys(columns)[columnIndex] ];
|
179
|
+
|
180
|
+
if (columnData && columnData[columnIndex]["format"])
|
181
|
+
{
|
182
|
+
var format = columnData[columnIndex]["format"];
|
183
|
+
var matches = format.match(/###.+?###/g)
|
184
|
+
|
185
|
+
var result = format;
|
186
|
+
for (var matchIndex in matches)
|
187
|
+
{
|
188
|
+
var member_name = matches[matchIndex].match(/[^#]+/)[0];
|
189
|
+
result = result.replaceAll(matches[matchIndex], data_object[index][member_name]);
|
190
|
+
}
|
191
|
+
|
192
|
+
if (columnData && columnData[columnIndex]["transform"])
|
193
|
+
{
|
194
|
+
result = document["transform_" + columnData[columnIndex]["transform"]](result);
|
195
|
+
}
|
196
|
+
row.append($('<td>').html( result ).data("object", data_object[index]) );
|
197
|
+
}
|
198
|
+
else
|
199
|
+
{
|
200
|
+
if (columnData && columnData[columnIndex]["transform"])
|
201
|
+
{
|
202
|
+
cell_data = document["transform_" + columnData[columnIndex]["transform"]](cell_data);
|
203
|
+
}
|
204
|
+
row.append($('<td>').text( cell_data ).data("object", data_object[index]) );
|
205
|
+
}
|
206
|
+
}
|
207
|
+
body.append(row);
|
208
|
+
}
|
209
|
+
}
|
210
|
+
|
211
|
+
});
|
212
|
+
}
|
213
|
+
|
214
|
+
refresh_table_#{@table_name}();
|
215
|
+
|
216
|
+
DATATABLE_SCRIPT
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Add tables to elements
|
221
|
+
class Elements
|
222
|
+
def table(options = {}, &block)
|
223
|
+
table_name = options[:id] || @page.create_anchor('table')
|
224
|
+
table_style = ''
|
225
|
+
|
226
|
+
table_style = options[:style] unless options[:style].nil?
|
227
|
+
|
228
|
+
classname = 'table'
|
229
|
+
|
230
|
+
classname += ' table-bordered' if options[:bordered]
|
231
|
+
classname += ' table-hover' if options[:hover]
|
232
|
+
classname += ' table-striped' if options[:striped]
|
233
|
+
|
234
|
+
table_options = {
|
235
|
+
class: classname,
|
236
|
+
id: table_name,
|
237
|
+
style: table_style
|
238
|
+
}
|
239
|
+
|
240
|
+
if options[:system] == :data_table
|
241
|
+
@page.request_js 'js/plugins/dataTables/jquery.dataTables.js'
|
242
|
+
@page.request_js 'js/plugins/dataTables/dataTables.bootstrap.js'
|
243
|
+
@page.request_js 'js/plugins/dataTables/dataTables.responsive.js'
|
244
|
+
@page.request_js 'js/plugins/dataTables/dataTables.tableTools.min.js'
|
245
|
+
|
246
|
+
@page.request_css 'css/plugins/dataTables/dataTables.bootstrap.css'
|
247
|
+
@page.request_css 'css/plugins/dataTables/dataTables.responsive.css'
|
248
|
+
@page.request_css 'css/plugins/dataTables/dataTables.tableTools.min.css'
|
249
|
+
|
250
|
+
@page.scripts << <<-DATATABLE_SCRIPT
|
251
|
+
$('##{table_name}').DataTable();
|
252
|
+
DATATABLE_SCRIPT
|
253
|
+
end
|
254
|
+
|
255
|
+
if options[:system] == :foo_table
|
256
|
+
table_options[:"data-filtering"] = true
|
257
|
+
table_options[:"data-sorting"] = true
|
258
|
+
table_options[:"data-paging"] = true
|
259
|
+
table_options[:"data-show-toggle"] = true
|
260
|
+
table_options[:"data-toggle-column"] = 'last'
|
261
|
+
|
262
|
+
table_options[:"data-paging-size"] = (options[:max_items_per_page] || 8).to_i.to_s
|
263
|
+
table_options[:class] = table_options[:class] + ' toggle-arrow-tiny'
|
264
|
+
|
265
|
+
@page.request_js 'js/plugins/footable/footable.all.min.js'
|
266
|
+
|
267
|
+
@page.request_css 'css/plugins/footable/footable.core.css'
|
268
|
+
|
269
|
+
@page.scripts << <<-DATATABLE_SCRIPT
|
270
|
+
$('##{table_name}').footable({
|
271
|
+
paging: {
|
272
|
+
size: #{(options[:max_items_per_page] || 8).to_i}
|
273
|
+
}
|
274
|
+
});
|
275
|
+
$('##{table_name}').append(this.html).trigger('footable_redraw');
|
276
|
+
|
277
|
+
|
278
|
+
|
279
|
+
DATATABLE_SCRIPT
|
280
|
+
|
281
|
+
@page.onload_scripts << <<-SCRIPT
|
282
|
+
SCRIPT
|
283
|
+
end
|
284
|
+
|
285
|
+
method_missing(:table, table_options, &block)
|
286
|
+
ul class: 'pagination'
|
287
|
+
end
|
288
|
+
|
289
|
+
def table_from_source(url, options = {}, &block)
|
290
|
+
dyn_table = DynamicTable.new(@page, @anchors, url, options, &block)
|
291
|
+
|
292
|
+
text dyn_table.generate_table
|
293
|
+
|
294
|
+
@page.scripts << dyn_table.generate_script
|
295
|
+
end
|
296
|
+
|
297
|
+
def table_from_hashes(hashes, options = {})
|
298
|
+
keys = {}
|
299
|
+
hashes.each do |hash|
|
300
|
+
hash.each do |key, _value|
|
301
|
+
keys[key] = ''
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
table options do
|
306
|
+
thead do
|
307
|
+
keys.each do |key, _|
|
308
|
+
th key.to_s
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
tbody do
|
313
|
+
hashes.each do |hash|
|
314
|
+
tr do
|
315
|
+
keys.each do |key, _|
|
316
|
+
td (hash[key]).to_s || ' '
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|