lissio 0.1.0.beta3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -1
- data/README.md +20 -22
- data/bin/lissio +112 -37
- data/lib/lissio.rb +2 -0
- data/lib/lissio/builder.rb +54 -0
- data/lib/lissio/server.rb +10 -5
- data/lissio.gemspec +3 -6
- data/opal/lissio/adapter/rest.rb +132 -60
- data/opal/lissio/adapter/storage.rb +30 -34
- data/opal/lissio/application.rb +5 -4
- data/opal/lissio/collection.rb +12 -8
- data/opal/lissio/component.rb +151 -38
- data/opal/lissio/component/alert.rb +39 -49
- data/opal/lissio/component/autocomplete.rb +318 -0
- data/opal/lissio/component/container.rb +4 -6
- data/opal/lissio/component/markdown.rb +147 -126
- data/opal/lissio/component/tooltip.rb +136 -148
- data/opal/lissio/model.rb +65 -25
- data/opal/lissio/router.rb +12 -2
- data/opal/lissio/version.rb +1 -1
- metadata +14 -26
@@ -63,19 +63,21 @@ class Storage < Adapter
|
|
63
63
|
self.class.storage
|
64
64
|
end
|
65
65
|
|
66
|
-
def self.fetch(id
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
def self.fetch(id)
|
67
|
+
if value = storage[id]
|
68
|
+
Promise.value(value)
|
69
|
+
else
|
70
|
+
Promise.error(:missing)
|
71
|
+
end
|
70
72
|
end
|
71
73
|
|
72
|
-
def create
|
73
|
-
|
74
|
-
key = id!
|
74
|
+
def create
|
75
|
+
key = id!
|
75
76
|
|
76
|
-
|
77
|
-
|
78
|
-
|
77
|
+
if key && storage[key]
|
78
|
+
Promise.error(:exists)
|
79
|
+
else
|
80
|
+
Promise.defer {
|
79
81
|
adapter.autoincrement.each {|name|
|
80
82
|
unless __send__ name
|
81
83
|
__send__ "#{name}=", adapter.autoincrement!(name, storage)
|
@@ -83,34 +85,28 @@ class Storage < Adapter
|
|
83
85
|
}
|
84
86
|
|
85
87
|
storage[id!] = self
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
}.defer
|
88
|
+
}
|
89
|
+
end
|
90
90
|
end
|
91
91
|
|
92
|
-
def save
|
93
|
-
|
94
|
-
|
92
|
+
def save
|
93
|
+
if storage[id!]
|
94
|
+
Promise.defer {
|
95
95
|
storage[id!] = self
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
101
|
-
}.defer
|
96
|
+
}
|
97
|
+
else
|
98
|
+
Promise.error(:missing)
|
99
|
+
end
|
102
100
|
end
|
103
101
|
|
104
102
|
def destroy(&block)
|
105
|
-
|
106
|
-
|
103
|
+
if storage[id!]
|
104
|
+
Promise.defer {
|
107
105
|
storage.delete(id!)
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
end
|
113
|
-
}.defer
|
106
|
+
}
|
107
|
+
else
|
108
|
+
Promise.error(:missing)
|
109
|
+
end
|
114
110
|
end
|
115
111
|
}
|
116
112
|
else
|
@@ -124,15 +120,15 @@ class Storage < Adapter
|
|
124
120
|
end
|
125
121
|
|
126
122
|
def self.fetch(*args, &block)
|
127
|
-
|
128
|
-
|
123
|
+
Promise.defer {
|
124
|
+
new(storage.map {|name, value|
|
129
125
|
next if Array === name && name.length == 2 && name.first == :__autoincrement__
|
130
126
|
|
131
127
|
if !adapter.filter || adapter.filter.call(value, *args)
|
132
128
|
value
|
133
129
|
end
|
134
130
|
}.compact)
|
135
|
-
}
|
131
|
+
}
|
136
132
|
end
|
137
133
|
}
|
138
134
|
end
|
data/opal/lissio/application.rb
CHANGED
@@ -9,7 +9,7 @@ class Application < Component
|
|
9
9
|
|
10
10
|
klass.include Singleton
|
11
11
|
|
12
|
-
$document.
|
12
|
+
$document.ready do
|
13
13
|
klass.start
|
14
14
|
end
|
15
15
|
end
|
@@ -39,6 +39,8 @@ class Application < Component
|
|
39
39
|
def_delegators :@router, :navigate, :route
|
40
40
|
|
41
41
|
def initialize
|
42
|
+
super()
|
43
|
+
|
42
44
|
@router = Lissio::Router.new(fragment: false)
|
43
45
|
end
|
44
46
|
|
@@ -54,10 +56,9 @@ class Application < Component
|
|
54
56
|
|
55
57
|
element :body
|
56
58
|
|
57
|
-
on :click, 'a[href^="/"]' do |e|
|
59
|
+
on :click, 'a[href^="/"], a[href="back"], a[href="forward"]' do |e|
|
58
60
|
unless e.alt? || e.ctrl? || e.meta? || e.shift?
|
59
|
-
e.
|
60
|
-
|
61
|
+
e.prevent
|
61
62
|
navigate e.target[:href] || e.target.ancestors('a').first[:href]
|
62
63
|
end
|
63
64
|
end
|
data/opal/lissio/collection.rb
CHANGED
@@ -28,9 +28,7 @@ class Collection
|
|
28
28
|
klass ? @model = klass : @model
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
block ? @parse = block : @parse
|
33
|
-
end
|
31
|
+
include Enumerable
|
34
32
|
|
35
33
|
extend Forwardable
|
36
34
|
def_delegators :class, :adapter, :model
|
@@ -41,10 +39,8 @@ class Collection
|
|
41
39
|
|
42
40
|
if data
|
43
41
|
@items = data.map {|datum|
|
44
|
-
|
45
|
-
|
46
|
-
if block = self.class.parse
|
47
|
-
block.call(datum)
|
42
|
+
if Model === datum
|
43
|
+
datum
|
48
44
|
else
|
49
45
|
model.new(datum)
|
50
46
|
end
|
@@ -52,7 +48,15 @@ class Collection
|
|
52
48
|
end
|
53
49
|
end
|
54
50
|
|
55
|
-
|
51
|
+
def [](id)
|
52
|
+
@items.find { |e| e.id! == id }
|
53
|
+
end
|
54
|
+
|
55
|
+
def replace(array)
|
56
|
+
@items = array
|
57
|
+
|
58
|
+
self
|
59
|
+
end
|
56
60
|
|
57
61
|
def each(&block)
|
58
62
|
return enum_for :each unless block
|
data/opal/lissio/component.rb
CHANGED
@@ -19,9 +19,19 @@ class Component
|
|
19
19
|
events = @events
|
20
20
|
|
21
21
|
klass.instance_eval {
|
22
|
-
@element = element
|
23
|
-
|
24
|
-
|
22
|
+
@element = element
|
23
|
+
|
24
|
+
if tag
|
25
|
+
@tag = tag.dup
|
26
|
+
@tag[:class] = @tag[:class].dup
|
27
|
+
end
|
28
|
+
|
29
|
+
if events
|
30
|
+
@events = events.dup
|
31
|
+
@events.each_key {|key|
|
32
|
+
@events[key] = @events[key].dup
|
33
|
+
}
|
34
|
+
end
|
25
35
|
}
|
26
36
|
end
|
27
37
|
|
@@ -30,9 +40,49 @@ class Component
|
|
30
40
|
end
|
31
41
|
|
32
42
|
def self.tag(options = nil)
|
43
|
+
return @tag unless options
|
44
|
+
|
45
|
+
@tag ||= {}
|
46
|
+
|
47
|
+
if cls = options.delete(:class)
|
48
|
+
@tag[:class] = Array(@tag[:class]).concat(Array(cls))
|
49
|
+
end
|
50
|
+
|
51
|
+
@tag.merge!(options)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.tag!(options = nil)
|
33
55
|
options ? @tag = options : @tag
|
34
56
|
end
|
35
57
|
|
58
|
+
def self.inheritance
|
59
|
+
ancestors.take_while {|klass|
|
60
|
+
klass != Component
|
61
|
+
}.map {|klass|
|
62
|
+
next unless klass.ancestors.include?(Component)
|
63
|
+
next unless klass.css
|
64
|
+
|
65
|
+
tag = klass.tag
|
66
|
+
element = klass.element
|
67
|
+
parent = klass.superclass
|
68
|
+
|
69
|
+
if parent != Component
|
70
|
+
next if element != parent.element
|
71
|
+
next if tag && !parent.tag
|
72
|
+
next if tag && (tag[:class] != parent.tag[:class] || tag[:id] != parent.tag[:id])
|
73
|
+
else
|
74
|
+
next if element
|
75
|
+
next if tag && (tag[:class] || tag[:id])
|
76
|
+
end
|
77
|
+
|
78
|
+
if klass.name
|
79
|
+
klass.name.gsub(/::/, '-').downcase
|
80
|
+
else
|
81
|
+
"lissio-#{klass.object_id}"
|
82
|
+
end
|
83
|
+
}.compact
|
84
|
+
end
|
85
|
+
|
36
86
|
def self.events
|
37
87
|
@events ||= Hash.new { |h, k| h[k] = [] }
|
38
88
|
end
|
@@ -40,16 +90,10 @@ class Component
|
|
40
90
|
def self.on(name, selector = nil, method = nil, &block)
|
41
91
|
if block
|
42
92
|
events[name] << [selector, block]
|
43
|
-
|
44
|
-
[name, selector, block]
|
45
93
|
elsif method
|
46
94
|
events[name] << [selector, method]
|
47
|
-
|
48
|
-
[name, selector, method]
|
49
95
|
else
|
50
|
-
events[name] << [nil,
|
51
|
-
|
52
|
-
[name, nil, method]
|
96
|
+
events[name] << [nil, selector]
|
53
97
|
end
|
54
98
|
end
|
55
99
|
|
@@ -85,23 +129,63 @@ class Component
|
|
85
129
|
end
|
86
130
|
end
|
87
131
|
|
88
|
-
def self.
|
132
|
+
def self.text(string = nil, &block)
|
133
|
+
if block
|
134
|
+
render {
|
135
|
+
element.inner_text = instance_exec(&block)
|
136
|
+
}
|
137
|
+
else
|
138
|
+
render {
|
139
|
+
element.inner_text = string
|
140
|
+
}
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.css!(content = nil, &block)
|
89
145
|
if content || block
|
90
|
-
@
|
146
|
+
@global.remove if @global
|
91
147
|
|
92
|
-
@
|
93
|
-
@
|
148
|
+
@global = CSS(content, &block)
|
149
|
+
@global.append_to($document.head)
|
94
150
|
else
|
95
|
-
CSS::StyleSheet.new(@
|
151
|
+
CSS::StyleSheet.new(@global) if @global
|
96
152
|
end
|
97
153
|
end
|
98
154
|
|
99
|
-
|
155
|
+
def self.css(&block)
|
156
|
+
if block
|
157
|
+
selector = if @tag && id = @tag[:id]
|
158
|
+
"##{id}"
|
159
|
+
elsif @tag && cls = @tag[:class]
|
160
|
+
".#{Array(cls).join('.')}"
|
161
|
+
elsif @element
|
162
|
+
@element
|
163
|
+
elsif self.name
|
164
|
+
".#{self.name.gsub(/::/, '-').downcase}"
|
165
|
+
else
|
166
|
+
".lissio-#{object_id}"
|
167
|
+
end
|
168
|
+
|
169
|
+
@local.remove if @local
|
100
170
|
|
101
|
-
|
102
|
-
|
171
|
+
@local = CSS do
|
172
|
+
rule selector do
|
173
|
+
if block.arity == 0
|
174
|
+
instance_exec(&block)
|
175
|
+
else
|
176
|
+
block.call(self)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
@local.append_to($document.head)
|
182
|
+
else
|
183
|
+
CSS::StyleSheet.new(@local) if @local
|
184
|
+
end
|
103
185
|
end
|
104
186
|
|
187
|
+
attr_accessor :parent
|
188
|
+
|
105
189
|
def tag
|
106
190
|
{ name: :div }.merge(self.class.tag || {})
|
107
191
|
end
|
@@ -121,17 +205,27 @@ class Component
|
|
121
205
|
end
|
122
206
|
|
123
207
|
elem.add_class(*tag[:class]) if tag[:class]
|
124
|
-
elem
|
208
|
+
elem.add_class(*self.class.inheritance)
|
125
209
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
210
|
+
tag.each {|name, value|
|
211
|
+
if name != :class && name != :name
|
212
|
+
elem[name] = value
|
213
|
+
end
|
214
|
+
}
|
215
|
+
|
216
|
+
[self.class.events, @events].compact.each {|events|
|
217
|
+
events.each {|name, blocks|
|
218
|
+
blocks.each {|selector, block|
|
219
|
+
if Symbol === block
|
220
|
+
elem.on name, selector do |*args|
|
221
|
+
__send__ block, *args
|
222
|
+
end
|
223
|
+
else
|
224
|
+
elem.on name, selector do |*args|
|
225
|
+
instance_exec(*args, &block)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
}
|
135
229
|
}
|
136
230
|
}
|
137
231
|
|
@@ -139,29 +233,49 @@ class Component
|
|
139
233
|
end
|
140
234
|
|
141
235
|
def on(name, selector = nil, method = nil, &block)
|
142
|
-
self.class.on(name, selector, method, &block)
|
143
|
-
|
144
236
|
if @element
|
145
237
|
if block
|
146
|
-
@element.on
|
238
|
+
@element.on name, selector do |*args|
|
147
239
|
instance_exec(*args, &block)
|
148
|
-
|
240
|
+
end
|
149
241
|
elsif method
|
150
|
-
@element.on
|
242
|
+
@element.on name, selector do |*args|
|
243
|
+
__send__ method, *args
|
244
|
+
end
|
151
245
|
else
|
152
|
-
@element.on
|
246
|
+
@element.on name do |*args|
|
247
|
+
__send__ method, *args
|
248
|
+
end
|
153
249
|
end
|
154
|
-
|
250
|
+
else
|
251
|
+
@events ||= Hash.new { |h, k| h[k] = [] }
|
155
252
|
|
156
|
-
|
253
|
+
if block
|
254
|
+
@events[name] << [selector, block]
|
255
|
+
elsif method
|
256
|
+
@events[name] << [selector, method]
|
257
|
+
else
|
258
|
+
@events[name] << [nil, selector]
|
259
|
+
end
|
260
|
+
end
|
157
261
|
end
|
158
262
|
|
159
263
|
# When overriding, remember to call super as last.
|
160
264
|
def render(*)
|
161
|
-
element.trigger :render, self
|
265
|
+
element.trigger! :render, self
|
162
266
|
element
|
163
267
|
end
|
164
268
|
|
269
|
+
def trigger(*args, &block)
|
270
|
+
element.trigger(*args, &block)
|
271
|
+
self
|
272
|
+
end
|
273
|
+
|
274
|
+
def trigger!(*args, &block)
|
275
|
+
element.trigger!(*args, &block)
|
276
|
+
self
|
277
|
+
end
|
278
|
+
|
165
279
|
def remove
|
166
280
|
@element.remove if @element
|
167
281
|
end
|
@@ -169,7 +283,6 @@ class Component
|
|
169
283
|
alias destroy remove
|
170
284
|
end
|
171
285
|
|
172
|
-
|
173
286
|
Browser::DOM::Builder.for Component do |_, item|
|
174
287
|
item.render
|
175
288
|
end
|
@@ -13,10 +13,21 @@ class Alert < Component
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def render
|
16
|
-
if
|
16
|
+
if Exception === @message
|
17
|
+
element << @message.inspect
|
18
|
+
element << DOM { br; br }
|
19
|
+
|
20
|
+
@message.backtrace.each {|line|
|
21
|
+
element << line
|
22
|
+
element << DOM { br }
|
23
|
+
}
|
24
|
+
elsif @options[:escape] == false
|
17
25
|
element.inner_html = @message
|
18
26
|
else
|
19
|
-
|
27
|
+
@message.each_line {|line|
|
28
|
+
element << line
|
29
|
+
element << DOM { br }
|
30
|
+
}
|
20
31
|
end
|
21
32
|
|
22
33
|
super
|
@@ -25,82 +36,61 @@ class Alert < Component
|
|
25
36
|
tag class: :alert
|
26
37
|
|
27
38
|
css do
|
28
|
-
|
29
|
-
border 1.px, :solid, :transparent
|
39
|
+
border 1.px, :solid, :transparent
|
30
40
|
|
31
|
-
|
41
|
+
padding 15.px
|
32
42
|
|
33
|
-
|
34
|
-
|
35
|
-
end
|
43
|
+
rule 'a' do
|
44
|
+
font weight: :bold
|
36
45
|
end
|
37
46
|
end
|
38
47
|
|
39
|
-
def self.customize(
|
40
|
-
if args.length == 1
|
41
|
-
options = args.first
|
42
|
-
else
|
43
|
-
name, options = args
|
44
|
-
end
|
45
|
-
|
46
|
-
name ||= "alert-custom-#{rand(10000)}"
|
47
|
-
options ||= {}
|
48
|
-
|
49
|
-
if self == Alert
|
50
|
-
inherited = []
|
51
|
-
else
|
52
|
-
inherited = class_names
|
53
|
-
end
|
54
|
-
|
48
|
+
def self.customize(options = {}, &block)
|
55
49
|
Class.new(self) {
|
56
|
-
define_singleton_method :class_names do
|
57
|
-
inherited + [name]
|
58
|
-
end
|
59
|
-
|
60
|
-
tag class: [:alert, name, *inherited]
|
61
|
-
|
62
50
|
css do
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
if value = options[:background] || options[:bg]
|
67
|
-
background color: value
|
68
|
-
end
|
51
|
+
if value = options[:background] || options[:bg]
|
52
|
+
background color: value
|
53
|
+
end
|
69
54
|
|
70
|
-
|
71
|
-
|
72
|
-
|
55
|
+
if value = options[:foreground] || options[:fg]
|
56
|
+
color value
|
57
|
+
end
|
73
58
|
|
74
|
-
|
75
|
-
|
76
|
-
|
59
|
+
if value = options[:border]
|
60
|
+
border color: value
|
61
|
+
end
|
77
62
|
|
78
|
-
|
79
|
-
|
80
|
-
end
|
63
|
+
if value = options[:padding]
|
64
|
+
padding value
|
81
65
|
end
|
66
|
+
|
67
|
+
if block.arity == 0
|
68
|
+
instance_exec(&block)
|
69
|
+
else
|
70
|
+
block.call(self)
|
71
|
+
end if block
|
82
72
|
end
|
83
73
|
}
|
84
74
|
end
|
85
75
|
|
86
|
-
Info = customize
|
76
|
+
Info = customize \
|
87
77
|
background: '#d9edf7',
|
88
78
|
foreground: '#3a87ad',
|
89
79
|
border: '#bce8f1'
|
90
80
|
|
91
|
-
Success = customize
|
81
|
+
Success = customize \
|
92
82
|
message: "The operation was successful.",
|
93
83
|
background: '#dff0d8',
|
94
84
|
foreground: '#468847',
|
95
85
|
border: '#d6e9c6'
|
96
86
|
|
97
|
-
Warning = customize
|
87
|
+
Warning = customize \
|
98
88
|
message: "Something might have gone wrong.",
|
99
89
|
background: '#fcf8e3',
|
100
90
|
foreground: '#c09853',
|
101
91
|
border: '#fbeed5'
|
102
92
|
|
103
|
-
Danger = customize
|
93
|
+
Danger = customize \
|
104
94
|
message: "An unexpected error has occurred.",
|
105
95
|
background: '#f2dede',
|
106
96
|
foreground: '#b94a48',
|