lissio 0.1.0.beta3 → 0.1.0
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 +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',
|