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.
@@ -63,19 +63,21 @@ class Storage < Adapter
63
63
  self.class.storage
64
64
  end
65
65
 
66
- def self.fetch(id, &block)
67
- proc {
68
- block.call(storage[id] || :error)
69
- }.defer
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(&block)
73
- proc {
74
- key = id!
74
+ def create
75
+ key = id!
75
76
 
76
- if key && storage[key]
77
- block.call(:error) if block
78
- else
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
- block.call(:ok) if block
88
- end
89
- }.defer
88
+ }
89
+ end
90
90
  end
91
91
 
92
- def save(&block)
93
- proc {
94
- if storage[id!]
92
+ def save
93
+ if storage[id!]
94
+ Promise.defer {
95
95
  storage[id!] = self
96
-
97
- block.call(:ok) if block
98
- else
99
- block.call(:error) if block
100
- end
101
- }.defer
96
+ }
97
+ else
98
+ Promise.error(:missing)
99
+ end
102
100
  end
103
101
 
104
102
  def destroy(&block)
105
- proc {
106
- if storage[id!]
103
+ if storage[id!]
104
+ Promise.defer {
107
105
  storage.delete(id!)
108
-
109
- block.call(:ok) if block
110
- else
111
- block.call(:error) if block
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
- proc {
128
- block.call new(storage.map {|name, value|
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
- }.defer
131
+ }
136
132
  end
137
133
  }
138
134
  end
@@ -9,7 +9,7 @@ class Application < Component
9
9
 
10
10
  klass.include Singleton
11
11
 
12
- $document.on :load do
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.stop!
60
-
61
+ e.prevent
61
62
  navigate e.target[:href] || e.target.ancestors('a').first[:href]
62
63
  end
63
64
  end
@@ -28,9 +28,7 @@ class Collection
28
28
  klass ? @model = klass : @model
29
29
  end
30
30
 
31
- def self.parse(&block)
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
- next datum if Model === datum
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
- include Enumerable
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
@@ -19,9 +19,19 @@ class Component
19
19
  events = @events
20
20
 
21
21
  klass.instance_eval {
22
- @element = element if element
23
- @tag = tag if tag
24
- @events = events.clone if events
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, method]
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.css(content = nil, &block)
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
- @style.remove if @style
146
+ @global.remove if @global
91
147
 
92
- @style = CSS(content, &block)
93
- @style.append_to($document.head)
148
+ @global = CSS(content, &block)
149
+ @global.append_to($document.head)
94
150
  else
95
- CSS::StyleSheet.new(@style)
151
+ CSS::StyleSheet.new(@global) if @global
96
152
  end
97
153
  end
98
154
 
99
- attr_accessor :parent
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
- def initialize(parent = nil)
102
- @parent = parent
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[:id] = tag[:id] if tag[:id]
208
+ elem.add_class(*self.class.inheritance)
125
209
 
126
- self.class.events.each {|name, blocks|
127
- blocks.each {|selector, block|
128
- if block.is_a? Symbol
129
- elem.on(name, selector, &method(block))
130
- else
131
- elem.on(name, selector) {|*args|
132
- instance_exec(*args, &block)
133
- }
134
- end
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(name, selector) {|*args|
238
+ @element.on name, selector do |*args|
147
239
  instance_exec(*args, &block)
148
- }
240
+ end
149
241
  elsif method
150
- @element.on(name, selector, &method(method))
242
+ @element.on name, selector do |*args|
243
+ __send__ method, *args
244
+ end
151
245
  else
152
- @element.on(name, &method(method))
246
+ @element.on name do |*args|
247
+ __send__ method, *args
248
+ end
153
249
  end
154
- end
250
+ else
251
+ @events ||= Hash.new { |h, k| h[k] = [] }
155
252
 
156
- self
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 @options[:escape] == false
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
- element << @message
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
- rule '.alert' do
29
- border 1.px, :solid, :transparent
39
+ border 1.px, :solid, :transparent
30
40
 
31
- padding 15.px
41
+ padding 15.px
32
42
 
33
- rule 'a' do
34
- font weight: :bold
35
- end
43
+ rule 'a' do
44
+ font weight: :bold
36
45
  end
37
46
  end
38
47
 
39
- def self.customize(*args, &block)
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
- rule ".alert#{".#{inherited.join('.')}" unless inherited.empty?}.#{name}" do
64
- instance_exec(&block) if block
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
- if value = options[:foreground] || options[:fg]
71
- color value
72
- end
55
+ if value = options[:foreground] || options[:fg]
56
+ color value
57
+ end
73
58
 
74
- if value = options[:border]
75
- border color: value
76
- end
59
+ if value = options[:border]
60
+ border color: value
61
+ end
77
62
 
78
- if value = options[:padding]
79
- padding value
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 :info,
76
+ Info = customize \
87
77
  background: '#d9edf7',
88
78
  foreground: '#3a87ad',
89
79
  border: '#bce8f1'
90
80
 
91
- Success = customize :success,
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 :warning,
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 :danger,
93
+ Danger = customize \
104
94
  message: "An unexpected error has occurred.",
105
95
  background: '#f2dede',
106
96
  foreground: '#b94a48',