ezframe 0.0.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 +7 -0
- data/.gitignore +12 -0
- data/.rubocop.yml +44 -0
- data/Gemfile +5 -0
- data/README.md +37 -0
- data/Rakefile +6 -0
- data/example/auth/Gemfile +8 -0
- data/example/auth/asset/css/materialize.min.css +13 -0
- data/example/auth/asset/js/common.js +200 -0
- data/example/auth/asset/js/htmlgen.js +79 -0
- data/example/auth/columns/user.yml +12 -0
- data/example/auth/config.ru +26 -0
- data/example/auth/config/view_conf.yml +3 -0
- data/example/auth/pages/app.rb +61 -0
- data/example/auth/template/base.html +12 -0
- data/example/chat/Gemfile +9 -0
- data/example/chat/asset/css/materialize.min.css +13 -0
- data/example/chat/asset/js/common.js +200 -0
- data/example/chat/asset/js/htmlgen.js +79 -0
- data/example/chat/columns/belong.yml +6 -0
- data/example/chat/columns/channel.yml +3 -0
- data/example/chat/columns/talk.yml +6 -0
- data/example/chat/columns/user.yml +12 -0
- data/example/chat/config.ru +23 -0
- data/example/chat/config/view_conf.yml +3 -0
- data/example/chat/pages/app.rb +59 -0
- data/example/chat/template/base.html +12 -0
- data/example/todo/Gemfile +8 -0
- data/example/todo/asset/css/datatable.css +54 -0
- data/example/todo/asset/css/materialize.min.css +13 -0
- data/example/todo/asset/js/common.js +135 -0
- data/example/todo/asset/js/datatable.js +1814 -0
- data/example/todo/asset/js/htmlgen.js +79 -0
- data/example/todo/asset/js/init.js +3 -0
- data/example/todo/asset/js/materialize.min.js +6 -0
- data/example/todo/asset/js/mydatatable.js +9 -0
- data/example/todo/asset/js/mymaterialize.js +22 -0
- data/example/todo/columns/todo.yml +9 -0
- data/example/todo/config.ru +15 -0
- data/example/todo/config/view_conf.yml +3 -0
- data/example/todo/pages/app.rb +93 -0
- data/example/todo/template/base.html +12 -0
- data/exe/console +14 -0
- data/exe/create_table.rb +11 -0
- data/exe/myrackup +5 -0
- data/ezframe.gemspec +43 -0
- data/lib/ezframe.rb +28 -0
- data/lib/ezframe/auth.rb +68 -0
- data/lib/ezframe/column_set.rb +174 -0
- data/lib/ezframe/column_type.rb +220 -0
- data/lib/ezframe/config.rb +33 -0
- data/lib/ezframe/controller.rb +63 -0
- data/lib/ezframe/database.rb +48 -0
- data/lib/ezframe/hthash.rb +116 -0
- data/lib/ezframe/html.rb +84 -0
- data/lib/ezframe/materialize.rb +109 -0
- data/lib/ezframe/model.rb +54 -0
- data/lib/ezframe/page_base.rb +109 -0
- data/lib/ezframe/page_kit.rb +84 -0
- data/lib/ezframe/pages.rb +8 -0
- data/lib/ezframe/server.rb +15 -0
- data/lib/ezframe/template.rb +25 -0
- data/lib/ezframe/util.rb +86 -0
- data/lib/ezframe/version.rb +3 -0
- metadata +236 -0
data/lib/ezframe/html.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ezframe
|
4
|
+
class Html
|
5
|
+
class << self
|
6
|
+
def convert(ht_h = {})
|
7
|
+
return "" if ht_h.nil? || ht_h.to_s.empty?
|
8
|
+
return ht_h.to_html if ht_h.respond_to?(:to_html)
|
9
|
+
return ht_h.to_s if ht_h.is_a?(String) || ht_h.is_a?(Symbol) || ht_h.is_a?(Integer) || ht_h.is_a?(Time)
|
10
|
+
return ht_h.map { |args| convert(args) }.join if ht_h.is_a?(Array)
|
11
|
+
|
12
|
+
tag = ht_h[:tag]
|
13
|
+
case tag
|
14
|
+
when "select"
|
15
|
+
return select(ht_h) if ht_h[:items]
|
16
|
+
when "icon"
|
17
|
+
tag = "i"
|
18
|
+
end
|
19
|
+
opt_s, child_s = join_attributes(ht_h)
|
20
|
+
if child_s.length.positive?
|
21
|
+
return "<#{tag} #{opt_s}>\n#{child_s}\n</#{tag}>\n"
|
22
|
+
end
|
23
|
+
"<#{tag} #{opt_s}/>"
|
24
|
+
end
|
25
|
+
|
26
|
+
def join_attributes(attrs)
|
27
|
+
child_s = ""
|
28
|
+
opt_a = attrs.map do |k, v|
|
29
|
+
case k
|
30
|
+
when :child
|
31
|
+
child_s = convert(v)
|
32
|
+
next
|
33
|
+
when :tag, :final
|
34
|
+
next
|
35
|
+
when :key
|
36
|
+
"name=\"#{v}\"" if attrs[:tag].to_sym == :input
|
37
|
+
next
|
38
|
+
else
|
39
|
+
if v.is_a?(Array)
|
40
|
+
"#{k}=\"#{v.join(" ")}\""
|
41
|
+
elsif v.nil?
|
42
|
+
nil
|
43
|
+
else
|
44
|
+
"#{k}=\"#{v}\""
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
[opt_a.compact.join(" "), child_s]
|
49
|
+
end
|
50
|
+
|
51
|
+
def select(ht_h = {})
|
52
|
+
attr = ht_h.clone
|
53
|
+
items = attr[:items]
|
54
|
+
if items.is_a?(Hash)
|
55
|
+
option_a = ht_h[:items].map do |k, v|
|
56
|
+
h = { tag: "option", value: k }
|
57
|
+
if v.is_a?(Array)
|
58
|
+
v, selected = v
|
59
|
+
h[:selected] = "selected" if selected
|
60
|
+
end
|
61
|
+
h[:child] = v
|
62
|
+
h
|
63
|
+
end
|
64
|
+
elsif items.is_a?(Array)
|
65
|
+
option_a = items.map do |v|
|
66
|
+
h = { tag: "option", value: v[0], child: v[1] }
|
67
|
+
if %w[selected default].include?(v[2])
|
68
|
+
h[:selected] = "selected"
|
69
|
+
end
|
70
|
+
h
|
71
|
+
end
|
72
|
+
else
|
73
|
+
warn "unknown items: #{ht_h.inspect}"
|
74
|
+
end
|
75
|
+
attr[:tag] = "select"
|
76
|
+
attr[:child] = option_a
|
77
|
+
attr[:name] = attr[:key]
|
78
|
+
attr[:final] = true
|
79
|
+
attr.delete(:items)
|
80
|
+
Html.convert(attr)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ezframe
|
4
|
+
class Materialize
|
5
|
+
class << self
|
6
|
+
def into_html_header
|
7
|
+
str =<<~EOHEAD2
|
8
|
+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
9
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
|
10
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
|
11
|
+
EOHEAD2
|
12
|
+
|
13
|
+
css_files = Dir["./asset/css/*.css"]||[]
|
14
|
+
css_a = css_files.map do |file|
|
15
|
+
file.gsub!("./asset", "")
|
16
|
+
"<link href=\"#{file}\" rel=\"stylesheet\">\n"
|
17
|
+
end
|
18
|
+
js_files = Dir["./asset/js/*.js"]||[]
|
19
|
+
js_a = js_files.map do |file|
|
20
|
+
file.gsub!("./asset", "")
|
21
|
+
"<script src=\"#{file}\"></script>\n"
|
22
|
+
end
|
23
|
+
str+(css_a+js_a).join
|
24
|
+
end
|
25
|
+
|
26
|
+
def into_bottom_of_body
|
27
|
+
""
|
28
|
+
# Dir["./asset/js"].each do ||
|
29
|
+
# <<~EOBOT
|
30
|
+
# <script src="/js/htmlgen.js"></script>
|
31
|
+
# <script src="/js/common.js"></script>
|
32
|
+
# EOBOT
|
33
|
+
end
|
34
|
+
|
35
|
+
def convert(ht_h)
|
36
|
+
return nil unless ht_h
|
37
|
+
return ht_h if (ht_h.kind_of?(Hash) && ht_h[:final])
|
38
|
+
new_h = ht_h.clone
|
39
|
+
if ht_h.kind_of?(Array)
|
40
|
+
new_h = ht_h.map { |v| convert(v) }
|
41
|
+
elsif ht_h.kind_of?(Hash)
|
42
|
+
case ht_h[:tag].to_sym
|
43
|
+
when :input, :select
|
44
|
+
new_h = input(ht_h) if "hidden" != ht_h[:type]
|
45
|
+
return new_h
|
46
|
+
when :checkbox
|
47
|
+
return checkbox(ht_h)
|
48
|
+
when :radio
|
49
|
+
return radio(ht_h)
|
50
|
+
when :icon
|
51
|
+
return icon(ht_h)
|
52
|
+
when :form
|
53
|
+
return new_h = form(ht_h)
|
54
|
+
when :table
|
55
|
+
new_h.add_class(%w[striped highlight])
|
56
|
+
end
|
57
|
+
new_h[:child] = convert(ht_h[:child]) if ht_h[:child]
|
58
|
+
end
|
59
|
+
return new_h
|
60
|
+
end
|
61
|
+
|
62
|
+
def icon(ht_h)
|
63
|
+
new_h = ht_h.clone
|
64
|
+
mylog "[warn] no name attribute for icon ht_h: #{ht_h.inspect}" unless new_h[:name]
|
65
|
+
new_h.add_class("material-icons")
|
66
|
+
new_h.update({ tag: "i", child: ht_h[:name] })
|
67
|
+
new_h.delete(:name)
|
68
|
+
return new_h
|
69
|
+
end
|
70
|
+
|
71
|
+
def form(ht_h)
|
72
|
+
new_h = ht_h.clone
|
73
|
+
new_h[:child] = convert(new_h[:child])
|
74
|
+
return new_h
|
75
|
+
end
|
76
|
+
|
77
|
+
def input(ht_h)
|
78
|
+
ht_h[:name] ||= ht_h[:key]
|
79
|
+
width_s = "s#{ht_h[:width_s] || 12}"
|
80
|
+
ht_h.delete(:witdth_s)
|
81
|
+
label = Ht.label(for: ht_h[:key], child: ht_h[:label], final: true )
|
82
|
+
cls = ["input-field", "col", width_s]
|
83
|
+
new_h = Ht.div(class: cls, child: [ht_h, label])
|
84
|
+
new_h = Ht.div(child: new_h, class: "row")
|
85
|
+
return new_h
|
86
|
+
end
|
87
|
+
|
88
|
+
def checkbox(ht_h)
|
89
|
+
ht_h[:tag] = "input"
|
90
|
+
ht_h[:type] = "checkbox"
|
91
|
+
Ht.label(child: [ht_h, { tag: "span", child: ht_h[:value] }])
|
92
|
+
end
|
93
|
+
|
94
|
+
def radio(ht_h)
|
95
|
+
ht_h[:tag] = "input"
|
96
|
+
ht_h[:type] = "radio"
|
97
|
+
Ht.label(child: [ht_h, { tag: "span", child: ht_h[:label] }])
|
98
|
+
end
|
99
|
+
|
100
|
+
def add_sibling(dest, elem)
|
101
|
+
if dest.is_a?(Array)
|
102
|
+
dest.push(elem)
|
103
|
+
else
|
104
|
+
[dest, elem]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
module Ezframe
|
6
|
+
class Model
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def init_column_sets
|
10
|
+
@base_column_sets = ColumnSets.new
|
11
|
+
@base_column_sets.load_files('./columns')
|
12
|
+
end
|
13
|
+
|
14
|
+
def init_db
|
15
|
+
@base_db = Database.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def init
|
19
|
+
unless @base_column_sets
|
20
|
+
init_column_sets
|
21
|
+
init_db
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_clone
|
26
|
+
new(@base_column_sets.deep_dup, @base_db)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_accessor :column_sets, :db
|
31
|
+
|
32
|
+
def initialize(column_sets, db)
|
33
|
+
@column_sets, @db = column_sets, db
|
34
|
+
@column_sets.model = self
|
35
|
+
# @column_sets.each {|name, colset| colset.model = self }
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_tables
|
39
|
+
@column_sets.tables.each do |table_name, column_set|
|
40
|
+
begin
|
41
|
+
create_one_table(table_name, column_set)
|
42
|
+
rescue => e
|
43
|
+
mylog("*** #{e.inspect}\n#{$@.inspect}")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_one_table(table_name, column_set)
|
49
|
+
col_h = column_set.get_hash(:db_type)
|
50
|
+
mylog "create_one_table: col_h=#{col_h.inspect}"
|
51
|
+
@db.create_table(table_name, col_h)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "uri"
|
5
|
+
|
6
|
+
require_relative "util"
|
7
|
+
|
8
|
+
module Ezframe
|
9
|
+
class PageBase
|
10
|
+
class << self
|
11
|
+
def get_class(keys)
|
12
|
+
keys = [keys] if keys.is_a?(String)
|
13
|
+
klass = (%w[Ezframe] + keys.map { |k| k.to_camel }).join("::")
|
14
|
+
if Object.const_defined?(klass)
|
15
|
+
return Object.const_get(klass)
|
16
|
+
end
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def decide_route(path_info)
|
21
|
+
default_class = Config[:default_page_class]||"App"
|
22
|
+
default_method = Config[:default_page_method]||"default"
|
23
|
+
path_parts = path_info.split('/').drop(1)
|
24
|
+
case path_parts.length
|
25
|
+
when 0
|
26
|
+
[get_class(default_class), default_method]
|
27
|
+
when 1
|
28
|
+
klass = get_class(path_parts)
|
29
|
+
if klass
|
30
|
+
return [klass, default_method]
|
31
|
+
else
|
32
|
+
return [get_class(default_class), parth_parts[0]]
|
33
|
+
end
|
34
|
+
else
|
35
|
+
klass = get_class(path_parts)
|
36
|
+
if klass
|
37
|
+
[klass, default_method]
|
38
|
+
else
|
39
|
+
method = path_parts.pop
|
40
|
+
klass = get_class(path_parts)
|
41
|
+
[klass, method]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
attr_accessor :auth
|
48
|
+
|
49
|
+
def initialize(request = nil, model = nil)
|
50
|
+
@model = model if model
|
51
|
+
if request
|
52
|
+
@request = request
|
53
|
+
@params = parse_query_string(request.env["QUERY_STRING"])
|
54
|
+
@params.update(request.params)
|
55
|
+
mylog "params=#{@params.inspect}" if @params.length > 0
|
56
|
+
@id, @key = @params[:id], @params[:key]
|
57
|
+
@env = @request.env
|
58
|
+
@session = @env["rack.x-session"]
|
59
|
+
if request.post?
|
60
|
+
parse_json_body
|
61
|
+
mylog "json=#{@json.inspect}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
@auth = nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse_query_string(str)
|
68
|
+
query_a = URI::decode_www_form(str)
|
69
|
+
res_h = {}
|
70
|
+
query_a.map { |a| res_h[a[0].to_sym] = a[1] }
|
71
|
+
res_h
|
72
|
+
end
|
73
|
+
|
74
|
+
def common_page(opts = {})
|
75
|
+
args = {
|
76
|
+
title: opts[:title],
|
77
|
+
body: opts[:body],
|
78
|
+
into_html_header: Materialize.into_html_header,
|
79
|
+
into_bottom_of_body: Materialize.into_bottom_of_body,
|
80
|
+
}
|
81
|
+
EzView::Template.fill_template("template/base.html", args)
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_json_body
|
85
|
+
body = @request.body.read
|
86
|
+
return {} if !body || body.length==0
|
87
|
+
begin
|
88
|
+
@json = JSON.parse(body)
|
89
|
+
rescue => e
|
90
|
+
mylog "ERROR: #{e.class}:#{e.message}\n#{e.backtrace}"
|
91
|
+
return nil
|
92
|
+
end
|
93
|
+
@json = @json.recursively_symbolize_keys if @json.is_a?(Hash) || @json.is_a?(Array)
|
94
|
+
return @json
|
95
|
+
end
|
96
|
+
|
97
|
+
def warden
|
98
|
+
@request.env["warden"]
|
99
|
+
end
|
100
|
+
|
101
|
+
def login?
|
102
|
+
!!warden.user
|
103
|
+
end
|
104
|
+
|
105
|
+
def user
|
106
|
+
warden.user
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ezframe
|
4
|
+
module PageKit
|
5
|
+
class IndexTable
|
6
|
+
def initialize(attr = {})
|
7
|
+
@attribute = attr
|
8
|
+
end
|
9
|
+
|
10
|
+
def make_table(row_a)
|
11
|
+
column_set = @attribute[:column_set]
|
12
|
+
table_a = row_a.map do |row_h|
|
13
|
+
column_set.values = row_h
|
14
|
+
id = column_set[:id].value
|
15
|
+
value_a = @attribute[:column_header].map do |key|
|
16
|
+
col = column_set[key]
|
17
|
+
checkbox_key = @attribute[:add_checkbox]
|
18
|
+
if checkbox_key && key == checkbox_key
|
19
|
+
text = add_checkbox(col)
|
20
|
+
else
|
21
|
+
text = col.view
|
22
|
+
end
|
23
|
+
deco = @attribute[:decorate_column]
|
24
|
+
if deco
|
25
|
+
text = deco.call(key, id, text)
|
26
|
+
# mylog "deco: #{text}"
|
27
|
+
end
|
28
|
+
td = { tag: "td", child: text }
|
29
|
+
# td.update(@attribute[:onclick_rows].call(id, text)) if @attribute[:onclick_rows]
|
30
|
+
td
|
31
|
+
end
|
32
|
+
tr = { tag: "tr", child: value_a }
|
33
|
+
if @attribute[:onclick_rows]
|
34
|
+
tr[:id] = elem_id = "tr_#{id}"
|
35
|
+
# tr.update(@attribute[:onclick_rows].call(id))
|
36
|
+
end
|
37
|
+
tr
|
38
|
+
end
|
39
|
+
{ tag: "table", child: [make_header, table_a] }
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_checkbox(col)
|
43
|
+
{ tag: "checkbox", name: "checkbox_#{col.key}_#{col.value}", value: col.value, label: col.view }
|
44
|
+
end
|
45
|
+
|
46
|
+
def make_header
|
47
|
+
column_set = @attribute[:column_set]
|
48
|
+
th_a = @attribute[:column_header].map do |key|
|
49
|
+
col = column_set[key]
|
50
|
+
if col
|
51
|
+
{ tag: "th", child: col.label }
|
52
|
+
else
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
if @attribute[:add_checkbox]
|
57
|
+
end
|
58
|
+
{ tag: "tr", child: th_a }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Tab
|
63
|
+
def self.base_hthash(link_list)
|
64
|
+
size = 12 / link_list.length
|
65
|
+
tabs = link_list.map do |link|
|
66
|
+
{ tag: "li", class: ["tab", "s#{size}"], child: link }
|
67
|
+
end
|
68
|
+
ul = { tag: "ul", class: %w[tabs], child: tabs }
|
69
|
+
div = { tag: "div", class: %w[row s12], child: ul }
|
70
|
+
{ tag: "div", class: %w[row], child: div }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Card
|
75
|
+
def self.base_hthash(title: "", content: "")
|
76
|
+
multi_div([%w[row], %w[col s12], %w[card blue-grey darken-1], %w[card-content white-text]],
|
77
|
+
[
|
78
|
+
{ tag: "span", class: %w[card-tite], child: title },
|
79
|
+
{ tag: "p", child: content },
|
80
|
+
])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|