wedgeio 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.
@@ -0,0 +1,92 @@
1
+ module Wedge
2
+ module Plugins
3
+ class History < Component
4
+ config.name :history_plugin
5
+ end
6
+ end
7
+ end
8
+
9
+ if RUBY_ENGINE == 'opal'
10
+ require 'wedge/plugins/location'
11
+
12
+ module Browser
13
+ # {Window} instances are {Native} objects used to wrap native window instances.
14
+ #
15
+ # Generally, you will want to use the top level {::Window} instance, which
16
+ # wraps `window` from the main page.
17
+ class Window
18
+ include Native
19
+
20
+ # @!attribute [r] history
21
+ # @return [History] the history for this window
22
+ def history
23
+ History.new(`#@native.history`) if `#@native.history`
24
+ end
25
+ end
26
+
27
+ # {History} allows manipulation of the session history.
28
+ #
29
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/History
30
+ class History
31
+ include Native
32
+
33
+ # @!attribute [r] length
34
+ # @return [Integer] how many items are in the history
35
+ alias_native :length
36
+
37
+ # Go back in the history.
38
+ #
39
+ # @param number [Integer] how many items to go back
40
+ def back(number = 1)
41
+ `History.go(-number)`
42
+ end
43
+
44
+ # Go forward in the history.
45
+ #
46
+ # @param number [Integer] how many items to go forward
47
+ def forward(number = 1)
48
+ `History.go(number)`
49
+ end
50
+
51
+ # Push an item in the history.
52
+ #
53
+ # @param item [String] the item to push in the history
54
+ # @param data [Object] additional state to push
55
+ def push(item, data = nil)
56
+ data = `null` if data.nil?
57
+
58
+ `History.pushState(jQuery.parseJSON(data.$to_json()), null, item)`
59
+ end
60
+
61
+ # Replace the current history item with another.
62
+ #
63
+ # @param item [String] the item to replace with
64
+ # @param data [Object] additional state to replace
65
+ def replace(item, data = nil)
66
+ data = `null` if data.nil?
67
+
68
+ `History.replaceState(data, null, item)`
69
+ end
70
+
71
+ def get_state
72
+ Native(`History.getState()`)
73
+ end
74
+
75
+ # @!attribute [r] current
76
+ # @return [String] the current item
77
+ def current
78
+ $window.location.path
79
+ end
80
+
81
+ def change &block
82
+ %x{
83
+ History.Adapter.bind(window,'statechange',function(e){
84
+ var state = History.getState();
85
+ state = #{Native(`state`)}
86
+ return #{block.call(`state`)}
87
+ });
88
+ }
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,78 @@
1
+ module Browser
2
+
3
+ # Allows manipulation of a location, usually from {Window} and {DOM::Document}.
4
+ #
5
+ # @see https://developer.mozilla.org/en-US/docs/Web/API/Location
6
+ class Location
7
+ include Native
8
+
9
+ # Change the location.
10
+ #
11
+ # @param url [String, #to_s] the URL to go to
12
+ def assign(url)
13
+ `#@native.assign(#{url.to_s})`
14
+ end
15
+
16
+ # Replace the current URL.
17
+ #
18
+ # @param url [String, #to_s] the URL to go to
19
+ def replace(url)
20
+ `#@native.replace(#{url.to_s})`
21
+ end
22
+
23
+ # Reload the page.
24
+ #
25
+ # @param force [Boolean] whether to force the reload
26
+ def reload(force = false)
27
+ `#@native.reload(force)`
28
+ end
29
+
30
+ # Convert the location to a string.
31
+ def to_s
32
+ `#@native.toString()`
33
+ end
34
+
35
+ # @!attribute fragment
36
+ # @return [String] the hash fragment of the location URI
37
+ alias_native :fragment, :hash
38
+ alias_native :fragment=, :hash=
39
+
40
+ # @!attribute host
41
+ # @return [String] the host part of the location URI
42
+ alias_native :host
43
+ alias_native :host=
44
+
45
+ # @!attribute uri
46
+ # @return [String] the whole location URI
47
+ alias_native :uri, :href
48
+ alias_native :uri=, :href=
49
+
50
+ # @!attribute path
51
+ # @return [String] the path part of the location URI
52
+ alias_native :path, :pathname
53
+ alias_native :path=, :pathname=
54
+
55
+ # @!attribute port
56
+ # @return [Integer] the port part of the location URI
57
+ alias_native :port
58
+ alias_native :port=
59
+
60
+ # @!attribute scheme
61
+ # @return [String] the scheme part of the location URI
62
+ alias_native :scheme, :protocol
63
+ alias_native :scheme=, :protocol=
64
+
65
+ # @!attribute query
66
+ # @return [String] the query part of the location URI
67
+ alias_native :query, :search
68
+ alias_native :query=, :search=
69
+ end
70
+
71
+ class Window
72
+ # @!attribute [r] location
73
+ # @return [Location] the location for the window
74
+ def location
75
+ Location.new(`#@native.location`) if `#@native.location`
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,65 @@
1
+ module Wedge
2
+ module Plugins
3
+ class Pjax < Component
4
+ config.name :pjax, :pjax_plugin
5
+ config.requires :history_plugin
6
+
7
+ class Nanobar
8
+ include Native
9
+
10
+ alias_native :go
11
+ alias_native :start
12
+ alias_native :finish
13
+
14
+ def initialize options = {}
15
+ `var Nanobar=function(){"use strict";var t,i,e,s,h,n,o={width:"100%",height:"4px",zIndex:9999,top:"0"},a={width:0,height:"100%",clear:"both",transition:"height .3s"};return t=function(t,i){var e;for(e in i)t.style[e]=i[e];t.style["float"]="left"},s=function(){var t=this,i=this.width-this.here;.1>i&&i>-.1?(h.call(this,this.here),this.moving=!1,100==this.width&&(this.el.style.height=0,setTimeout(function(){t.cont.el.removeChild(t.el)},300))):(h.call(this,this.width-i/4),setTimeout(function(){t.go()},16))},h=function(t){this.width=t,this.el.style.width=this.width+"%"},n=function(){var t=new i(this);this.bars.unshift(t)},i=function(i){this.el=document.createElement("div"),this.el.style.backgroundColor=i.opts.bg,this.width=0,this.here=0,this.moving=!1,this.cont=i,t(this.el,a),i.el.appendChild(this.el)},i.prototype.go=function(t){t?(this.here=t,this.moving||(this.moving=!0,s.call(this))):this.moving&&s.call(this)},e=function(i){var e,s,h=this.opts=i||{};h.bg=h.bg||"#000",this.bars=[],e=this.el=document.createElement("div"),t(this.el,o),h.id&&(e.id=h.id),h.className&&(e.className=h.className),e.style.position=h.target?"relative":"fixed",h.target?(s=h.target,s.insertBefore(e,h.target.firstChild)):(s=document.getElementsByTagName("body")[0],s.appendChild(e)),s.className="nanobar-custom-parent",n.call(this)},e.prototype.go=function(t){this.bars[0].go(t),100==t&&n.call(this)},e.prototype.start=function(){(function(){var t=this.bars[0],i=function(){setTimeout(function(){var e=t.here+Math.round(10*Math.random());t.here>=99||(e>99&&(e=99),t.go(e),i())},500)};t.go(10),i()}).call(this)},e.prototype.finish=function(){this.go(100)},e}();`
16
+ super `new Nanobar(options)`
17
+ end
18
+ end if client?
19
+
20
+ def progress_bar
21
+ $pjax_progress_bar
22
+ end
23
+
24
+ def get href = false
25
+ $pjax_progress_bar = Nanobar.new({bg: '#f99f22'}.to_n)
26
+ progress_bar.start
27
+ `$(document).trigger('page:click')`
28
+ $window.history.push href, pjax: true
29
+ end
30
+
31
+ on :click, 'a' do |el, evt|
32
+ href = el.attr 'href'
33
+
34
+ unless href =~ /^#/i || href =~ /^javascript:/i || el.attr('target') == '_blank'
35
+ evt.prevent_default
36
+ get href
37
+ end
38
+ end
39
+
40
+ on :history_change do |e|
41
+ if e.data.pjax
42
+ progress_bar.start
43
+ `$(document).trigger('page:request')`
44
+ HTTP.get(e.url) do |response|
45
+ res = Native(response.xhr)
46
+ html = res.responseText
47
+ # grab and add the body
48
+ matches = html.match(/<body[^>]*>((.|[\n\r])*)<\/body>/im)
49
+ dom.find('body').html matches[1]
50
+ # grab and eval the scripts
51
+ matches = html.match(/<script>((.|[\n\r])*)<\/script>/im)
52
+ # `eval(#{matches[0]})`
53
+ (matches[1] || '').split('</script>').each do |script|
54
+ # script = script.sub('<script>', '')
55
+ script = script.strip.sub('</html>', '').sub('<script>', '')
56
+ `jQuery.globalEval(script);`
57
+ end
58
+ progress_bar.finish
59
+ `$('html, body').animate({ scrollTop: 0 }, 0); $(document).trigger('page:load');`
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,251 @@
1
+ module Wedge
2
+ module Plugins
3
+ class Form < Component
4
+ # Provides a base implementation for extensible validation routines.
5
+ # {Scrivener::Validations} currently only provides the following assertions:
6
+ #
7
+ # * assert
8
+ # * assert_present
9
+ # * assert_format
10
+ # * assert_numeric
11
+ # * assert_url
12
+ # * assert_email
13
+ # * assert_member
14
+ # * assert_length
15
+ # * assert_decimal
16
+ # * assert_equal
17
+ #
18
+ # The core tenets that Scrivener::Validations advocates can be summed up in a
19
+ # few bullet points:
20
+ #
21
+ # 1. Validations are much simpler and better done using composition rather
22
+ # than macros.
23
+ # 2. Error messages should be kept separate and possibly in the view or
24
+ # presenter layer.
25
+ # 3. It should be easy to write your own validation routine.
26
+ #
27
+ # Other validations are simply added on a per-model or per-project basis.
28
+ #
29
+ # @example
30
+ #
31
+ # class Quote
32
+ # attr_accessor :title
33
+ # attr_accessor :price
34
+ # attr_accessor :date
35
+ #
36
+ # def validate
37
+ # assert_present :title
38
+ # assert_numeric :price
39
+ # assert_format :date, /\A[\d]{4}-[\d]{1,2}-[\d]{1,2}\z
40
+ # end
41
+ # end
42
+ #
43
+ # s = Quote.new
44
+ # s.valid?
45
+ # # => false
46
+ #
47
+ # s.errors
48
+ # # => { :title => [:not_present],
49
+ # :price => [:not_numeric],
50
+ # :date => [:format] }
51
+ #
52
+ module Validations
53
+ def server? &block
54
+ RUBY_ENGINE == 'ruby'
55
+ end
56
+ alias :server :server?
57
+
58
+ def client?
59
+ RUBY_ENGINE == 'opal'
60
+ end
61
+ alias :client :client?
62
+
63
+ def self.server? &block
64
+ RUBY_ENGINE == 'ruby'
65
+ end
66
+ alias :server :server?
67
+
68
+ def self.client?
69
+ RUBY_ENGINE == 'opal'
70
+ end
71
+ alias :client :client?
72
+
73
+ # Check if the current model state is valid. Each call to {#valid?} will
74
+ # reset the {#errors} array.
75
+ #
76
+ # All validations should be declared in a `validate` method.
77
+ #
78
+ # @example
79
+ #
80
+ # class Login
81
+ # attr_accessor :username
82
+ # attr_accessor :password
83
+ #
84
+ # def validate
85
+ # assert_present :user
86
+ # assert_present :password
87
+ # end
88
+ # end
89
+ #
90
+ def valid?
91
+ errors.clear
92
+ validate
93
+ errors.empty?
94
+ end
95
+
96
+ # Base validate implementation. Override this method in subclasses.
97
+ def validate
98
+ end
99
+
100
+ # Hash of errors for each attribute in this model.
101
+ def errors
102
+ @errors ||= Hash.new { |hash, key| hash[key] = [] }
103
+ end
104
+
105
+ protected
106
+
107
+ # Allows you to do a validation check against a regular expression.
108
+ # It's important to note that this internally calls {#assert_present},
109
+ # therefore you need not structure your regular expression to check
110
+ # for a non-empty value.
111
+ #
112
+ # @param [Symbol] att The attribute you want to verify the format of.
113
+ # @param [Regexp] format The regular expression with which to compare
114
+ # the value of att with.
115
+ # @param [Array<Symbol, Symbol>] error The error that should be returned
116
+ # when the validation fails.
117
+ def assert_format(att, format, error = [att, :format])
118
+ if assert_present(att, error)
119
+ assert(_attributes.send(att).to_s.match(format), error)
120
+ end
121
+ end
122
+
123
+ # The most basic and highly useful assertion. Simply checks if the
124
+ # value of the attribute is empty.
125
+ #
126
+ # @param [Symbol] att The attribute you wish to verify the presence of.
127
+ # @param [Array<Symbol, Symbol>] error The error that should be returned
128
+ # when the validation fails.
129
+ def assert_present(att, error = [att, :not_present])
130
+ if att.is_a? Array
131
+ att.each { |a| assert_present(a, error = [a, :not_present])}
132
+ else
133
+ if klass = _form[att]
134
+ options = {}
135
+ options[:key] = _options[:key] if _options.key? :key
136
+
137
+ f = klass.new(_attributes.send(att).attributes, options)
138
+ assert(f.valid?, [att, f.errors])
139
+ else
140
+ assert(!_attributes.send(att).to_s.empty?, error)
141
+ end
142
+ end
143
+ end
144
+
145
+ # Checks if all the characters of an attribute is a digit.
146
+ #
147
+ # @param [Symbol] att The attribute you wish to verify the numeric format.
148
+ # @param [Array<Symbol, Symbol>] error The error that should be returned
149
+ # when the validation fails.
150
+ def assert_numeric(att, error = [att, :not_numeric])
151
+ if assert_present(att, error)
152
+ if client?
153
+ assert_format(att, /^\-?\d+$/, error)
154
+ else
155
+ assert_format(att, /\A\-?\d+\z/, error)
156
+ end
157
+ end
158
+ end
159
+
160
+ if client?
161
+ URL = /^(http|https):\/\/([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}|(2 5[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3} |localhost)(:[0-9]{1,5})?(\/.*)?$/i
162
+ else
163
+ URL = /\A(http|https):\/\/([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}|(2 5[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3} |localhost)(:[0-9]{1,5})?(\/.*)?\z/i
164
+ end
165
+
166
+ def assert_url(att, error = [att, :not_url])
167
+ if assert_present(att, error)
168
+ assert_format(att, URL, error)
169
+ end
170
+ end
171
+
172
+ if client?
173
+ EMAIL = /^[a-z0-9!\#$%&'*\/=\?^{|}+_-]+(?:\.[a-z0-9!\#$%&'*\/=\?^{|}+_-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i
174
+ else
175
+ EMAIL = /\A[a-z0-9!\#$%&'*\/=\?^{|}+_-]+(?:\.[a-z0-9!\#$%&'*\/=\?^{|}+_-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z/i
176
+ end
177
+
178
+ def assert_email(att, error = [att, :not_email])
179
+ if assert_present(att, error)
180
+ assert_format(att, EMAIL, error)
181
+ end
182
+ end
183
+
184
+ def assert_member(att, set, err = [att, :not_valid])
185
+ assert(set.include?(_attributes.send(att)), err)
186
+ end
187
+
188
+ def assert_length(att, range, error = [att, :not_in_range])
189
+ if assert_present(att, error)
190
+ val = _attributes.send(att).to_s
191
+ assert range.include?(val.length), error
192
+ end
193
+ end
194
+
195
+ if client?
196
+ DECIMAL = /^\-?(\d+)?(\.\d+)?$/
197
+ else
198
+ DECIMAL = /\A\-?(\d+)?(\.\d+)?\z/
199
+ end
200
+
201
+ def assert_decimal(att, error = [att, :not_decimal])
202
+ assert_format att, DECIMAL, error
203
+ end
204
+
205
+ # Check that the attribute has the expected value. It uses === for
206
+ # comparison, so type checks are possible too. Note that in order
207
+ # to make the case equality work, the check inverts the order of
208
+ # the arguments: `assert_equal :foo, Bar` is translated to the
209
+ # expression `Bar === send(:foo)`.
210
+ #
211
+ # @example
212
+ #
213
+ # def validate
214
+ # assert_equal :status, "pending"
215
+ # assert_equal :quantity, Fixnum
216
+ # end
217
+ #
218
+ # @param [Symbol] att The attribute you wish to verify for equality.
219
+ # @param [Object] value The value you want to test against.
220
+ # @param [Array<Symbol, Symbol>] error The error that should be returned
221
+ # when the validation fails.
222
+ def assert_equal(att, value, error = [att, :not_equal])
223
+ assert value === _attributes.send(att), error
224
+ end
225
+
226
+ # The grand daddy of all assertions. If you want to build custom
227
+ # assertions, or even quick and dirty ones, you can simply use this method.
228
+ #
229
+ # @example
230
+ #
231
+ # class CreatePost
232
+ # attr_accessor :slug
233
+ # attr_accessor :votes
234
+ #
235
+ # def validate
236
+ # assert_slug :slug
237
+ # assert votes.to_i > 0, [:votes, :not_valid]
238
+ # end
239
+ #
240
+ # protected
241
+ # def assert_slug(att, error = [att, :not_slug])
242
+ # assert send(att).to_s =~ /\A[a-z\-0-9]+\z/, error
243
+ # end
244
+ # end
245
+ def assert(value, error)
246
+ value or errors[error.first].push(error.last) && false
247
+ end
248
+ end
249
+ end
250
+ end
251
+ end