sombrero 0.0.1 → 0.0.2
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/.gitignore +1 -0
- data/Rakefile +1 -2
- data/app/.gitignore +6 -0
- data/app/.pryrc +1 -0
- data/app/Gemfile +6 -0
- data/app/Rakefile +1 -0
- data/app/base/base_controller.rb +3 -0
- data/app/base/boot.rb +2 -0
- data/app/base/helpers/application_helpers.rb +1 -0
- data/app/base/load_controllers.rb +2 -0
- data/app/base/rtcp_controller.rb +22 -0
- data/app/config/config.rb +11 -0
- data/app/config/config.yml +11 -0
- data/app/config/env/development.yml +0 -0
- data/app/config/env/production.yml +0 -0
- data/app/config/env/stage.yml +0 -0
- data/app/config/env/test.yml +0 -0
- data/app/config.ru +3 -0
- data/app/core/Gemfile +5 -0
- data/app/core/boot.rb +17 -0
- data/app/core/client/activity_observer.coffee +37 -0
- data/app/core/client/api.coffee +248 -0
- data/app/core/client/channels.coffee +37 -0
- data/app/core/client/load.coffee +20 -0
- data/app/core/client/page.coffee +68 -0
- data/app/core/client/polyfills/array.compact.coffee +4 -0
- data/app/core/client/polyfills/array.compact_join.coffee +4 -0
- data/app/core/client/polyfills/number.to_money.coffee +3 -0
- data/app/core/client/polyfills/string.capitalize.coffee +4 -0
- data/app/core/client/polyfills/string.strip.coffee +5 -0
- data/app/core/client/polyfills.coffee +6 -0
- data/app/core/client/render.coffee +57 -0
- data/app/core/client/util/alert.coffee +50 -0
- data/app/core/client/util/datetime.coffee +47 -0
- data/app/core/client/util.coffee +38 -0
- data/app/core/generate_controllers_map.rb +4 -0
- data/app/core/generate_webpack_setup.rb +4 -0
- data/app/core/load.rb +5 -0
- data/app/core/load_controllers.rb +16 -0
- data/app/package.json +5 -0
- data/app/webpack.config.js +51 -0
- data/bin/sombrero +5 -0
- data/docker/Dockerfile +5 -0
- data/docker/base/Dockerfile +3 -0
- data/docker/base/build +10 -0
- data/docker/base/build.sh +25 -0
- data/docker/cleanup +7 -0
- data/docker/run +68 -0
- data/docker/skel/build.sh +1 -0
- data/docker/skel/config.yml +24 -0
- data/docker/skel/prepare_build.sh +5 -0
- data/docker/skel/start.sh +1 -0
- data/docker/start +7 -0
- data/lib/sombrero/{version.rb → app.rb} +3 -1
- data/lib/sombrero/base_controller.rb +5 -0
- data/lib/sombrero/cli/app/install.rb +38 -0
- data/lib/sombrero/cli/app/update.rb +20 -0
- data/lib/sombrero/cli/app.rb +10 -0
- data/lib/sombrero/cli/docker/build.rb +170 -0
- data/lib/sombrero/cli/docker/install.rb +23 -0
- data/lib/sombrero/cli/docker.rb +14 -0
- data/lib/sombrero/cli.rb +128 -0
- data/lib/sombrero/rtcp_controller.rb +93 -0
- data/lib/sombrero.rb +110 -2
- data/sombrero.gemspec +6 -1
- metadata +91 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e63221dd6689f29ae064f7b74182f25a1953226
|
4
|
+
data.tar.gz: 80792a8594b681d53d42e9c2a001aef3b9507e2d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9dc87a61ae7064de27c0e339eb4efee3933a73eda9060ec79a7bc860791bb7eceac2cd35d3459f5c7c3f8487ad7cd6cc85bd40c35b5b455041ad294cc0efb7c2
|
7
|
+
data.tar.gz: 7217715f408adbeb81d1bc30e4b9807e354837c9e518b74a664396ce0c3b999396fe3a13c293b607ba851107b1568d2f779dc80d3c5bfcb1089aca764ee31c5d
|
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
require
|
2
|
-
task :default => :spec
|
1
|
+
require 'bundler/gem_tasks'
|
data/app/.gitignore
ADDED
data/app/.pryrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path('../core/load', __FILE__)
|
data/app/Gemfile
ADDED
data/app/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path('../core/boot', __FILE__)
|
data/app/base/boot.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# this file will be loaded before other files found in helpers/ folder
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class RTCPController < BaseController
|
2
|
+
map Cfg.baseurl + '__rtcp__'
|
3
|
+
|
4
|
+
private
|
5
|
+
# called after socket connection established.
|
6
|
+
def connected
|
7
|
+
end
|
8
|
+
|
9
|
+
# data sent to client after connection established.
|
10
|
+
def initialization_data
|
11
|
+
{}
|
12
|
+
end
|
13
|
+
|
14
|
+
# merged into original env when calling a controller
|
15
|
+
def rtcp_env
|
16
|
+
{}
|
17
|
+
end
|
18
|
+
|
19
|
+
# called when socket connection closed
|
20
|
+
def disconnected
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# === Cfg is a required reserved hard-coded constant. === #
|
2
|
+
# === If you change it the entire app will broke. === #
|
3
|
+
|
4
|
+
# loading .yml configs from current directory. config.yml will be loaded first.
|
5
|
+
Cfg = Sombrero.load_config(File.expand_path('..', __FILE__))
|
6
|
+
|
7
|
+
# it is highly recommended to freeze configs so they stay unaltered on runtime.
|
8
|
+
Cfg.freeze
|
9
|
+
|
10
|
+
# loading any .rb files in current dir. this one will be skipped automatically.
|
11
|
+
Dir[File.expand_path('../**/*.rb', __FILE__)].each {|f| require(f)}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# module SystemRequiredConfigs # Do NOT Remove!
|
2
|
+
baseurl: /
|
3
|
+
app:
|
4
|
+
url:
|
5
|
+
development: /app
|
6
|
+
production: /app
|
7
|
+
dir: ./public
|
8
|
+
# end
|
9
|
+
|
10
|
+
# put here configs that will be the same on all environments.
|
11
|
+
# environment-aware configs should be set in config/env/ files.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/app/config.ru
ADDED
data/app/core/Gemfile
ADDED
data/app/core/boot.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# DO NOT EDIT THIS FILE, all updates will be lost on next update.
|
2
|
+
# edit base/boot.rb instead.
|
3
|
+
|
4
|
+
Dir.chdir File.expand_path('../..', __FILE__) do
|
5
|
+
require './base/boot'
|
6
|
+
|
7
|
+
require 'bundler/setup'
|
8
|
+
Bundler.require(:default)
|
9
|
+
Bundler.require(RocketIO.environment)
|
10
|
+
|
11
|
+
require './config/config'
|
12
|
+
|
13
|
+
require './base/helpers/application_helpers'
|
14
|
+
Dir['./base/helpers/**/*.rb'].each {|f| require(f)}
|
15
|
+
|
16
|
+
require './base/load'
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
_ =
|
2
|
+
debounce: require('lodash/debounce')
|
3
|
+
isFunction: require('lodash/isFunction')
|
4
|
+
#end
|
5
|
+
|
6
|
+
ONLINE = 'online'
|
7
|
+
AWAY = 'away'
|
8
|
+
OFFLINE = 'offline'
|
9
|
+
|
10
|
+
module.exports = (consider_idle_after, report_status = ->) ->
|
11
|
+
is_idle = false
|
12
|
+
idle_time = 0
|
13
|
+
|
14
|
+
if report_status && !_.isFunction(report_status)
|
15
|
+
throw new Error('activity_observer expects second argument to be a function')
|
16
|
+
|
17
|
+
activity_detected = ->
|
18
|
+
report_status(ONLINE) if is_idle
|
19
|
+
is_idle = false
|
20
|
+
idle_time = 0
|
21
|
+
true
|
22
|
+
#end
|
23
|
+
|
24
|
+
|
25
|
+
tictac = ->
|
26
|
+
return if is_idle
|
27
|
+
idle_time += 1
|
28
|
+
is_idle = idle_time >= consider_idle_after
|
29
|
+
if is_idle
|
30
|
+
report_status(AWAY)
|
31
|
+
#end
|
32
|
+
|
33
|
+
|
34
|
+
window.onload = document.onmousemove = document.onkeypress = _.debounce(activity_detected, 500)
|
35
|
+
window.onunload = -> report_status(OFFLINE)
|
36
|
+
window.setInterval(tictac, 1000)
|
37
|
+
#end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
_ =
|
2
|
+
isObject: require('lodash/isObject')
|
3
|
+
last: require('lodash/last')
|
4
|
+
has: require('lodash/has')
|
5
|
+
isFunction: require('lodash/isFunction')
|
6
|
+
isArray: require('lodash/isArray')
|
7
|
+
forEach: require('lodash/forEach')
|
8
|
+
#end
|
9
|
+
|
10
|
+
ReconnectingWebSocket = require('reconnectingwebsocket')
|
11
|
+
QueryString = require('qs')
|
12
|
+
|
13
|
+
Page = require('./page')
|
14
|
+
Load = require('./load')
|
15
|
+
Channels = require('./channels')
|
16
|
+
Controllers = require('../../controllers.json')
|
17
|
+
|
18
|
+
App =
|
19
|
+
connected: false
|
20
|
+
listeners: {}
|
21
|
+
call_on_reconnect: []
|
22
|
+
rtcp_serial: 0
|
23
|
+
#end
|
24
|
+
|
25
|
+
App.urlify = (url) ->
|
26
|
+
fn = (args...) ->
|
27
|
+
args.unshift(url)
|
28
|
+
q = ''
|
29
|
+
if _.isObject(_.last(args))
|
30
|
+
q = '?' + QueryString.stringify(args.pop())
|
31
|
+
'/' + args.join('/').replace(/^\/+/, '') + q
|
32
|
+
fn.toString = -> url
|
33
|
+
fn
|
34
|
+
#end
|
35
|
+
|
36
|
+
|
37
|
+
App.controller_loader = (controller) ->
|
38
|
+
->
|
39
|
+
|
40
|
+
url = [App.app_url, controller.path].join('/') + '.js'
|
41
|
+
window.exports = {}
|
42
|
+
window.module = {url: url, exports: window.exports}
|
43
|
+
|
44
|
+
done = ->
|
45
|
+
unless api = window.module.exports
|
46
|
+
throw new Error("Looks like #{url} does not contain a CommonJS module")
|
47
|
+
|
48
|
+
unless window.module && window.module.url == url
|
49
|
+
throw new Error("Looks like #{url} exports was overridden while downloading the script")
|
50
|
+
|
51
|
+
Core.on_controller_loaded(controller, api)
|
52
|
+
#end
|
53
|
+
|
54
|
+
failed = ->
|
55
|
+
console.log("Error loading #{controller.name}")
|
56
|
+
#end
|
57
|
+
|
58
|
+
Load.script(url, done, failed)
|
59
|
+
#end
|
60
|
+
|
61
|
+
|
62
|
+
App.controllers = ->
|
63
|
+
controllers = {}
|
64
|
+
|
65
|
+
Controllers.forEach (controller) ->
|
66
|
+
|
67
|
+
controller.url = App.urlify(controller.url)
|
68
|
+
controller.load = App.controller_loader(controller)
|
69
|
+
|
70
|
+
if _.isArray(controller.api)
|
71
|
+
api = {}
|
72
|
+
|
73
|
+
_.forEach controller.api, (meth) ->
|
74
|
+
api[meth] = (args...) ->
|
75
|
+
cb = if _.isFunction(_.last(args)) then args.pop() else null
|
76
|
+
App.send_rtcp_message(controller.url, meth, args, cb)
|
77
|
+
#end
|
78
|
+
|
79
|
+
controller.api = api
|
80
|
+
#end
|
81
|
+
|
82
|
+
Page.Api controller.url_pattern, (context, next) ->
|
83
|
+
controller.load()
|
84
|
+
#end
|
85
|
+
|
86
|
+
if controller.name
|
87
|
+
controllers[controller.name] = controller
|
88
|
+
#end
|
89
|
+
|
90
|
+
controllers
|
91
|
+
#end
|
92
|
+
|
93
|
+
|
94
|
+
App.onmessage = (evt) ->
|
95
|
+
msg = JSON.parse(evt.data)
|
96
|
+
|
97
|
+
unless typeof msg == 'object'
|
98
|
+
throw new Error("Wrong message format, #{typeof msg} given, Object expected")
|
99
|
+
|
100
|
+
if msg.error
|
101
|
+
throw new Error(msg.error)
|
102
|
+
|
103
|
+
if msg.channel
|
104
|
+
return Core.on_channel_message(msg)
|
105
|
+
|
106
|
+
if msg.controller
|
107
|
+
return App.handle_rpc_message(msg)
|
108
|
+
|
109
|
+
unless typeof msg.serial == 'number'
|
110
|
+
throw new Error('Received a message without or with a wrong serial')
|
111
|
+
|
112
|
+
if msg.serial < 0
|
113
|
+
throw new Error('A subzero serial received')
|
114
|
+
|
115
|
+
unless _.has(msg, 'data')
|
116
|
+
throw new Error('Received a message without data')
|
117
|
+
|
118
|
+
if msg.data.__rtcp_error__
|
119
|
+
return App.handle_standard_message(msg)
|
120
|
+
|
121
|
+
if msg.serial == 0
|
122
|
+
return App.handle_initialization_message(msg)
|
123
|
+
|
124
|
+
return App.handle_standard_message(msg)
|
125
|
+
#end
|
126
|
+
|
127
|
+
|
128
|
+
App.handle_initialization_message = (msg) ->
|
129
|
+
|
130
|
+
# avoid repetitive bootstraping on reconnects
|
131
|
+
return if App.initialized
|
132
|
+
App.initialized = true
|
133
|
+
App.app_url = msg.data.app_url
|
134
|
+
|
135
|
+
Core.on_initialize(msg)
|
136
|
+
|
137
|
+
Page.Api.start()
|
138
|
+
#end
|
139
|
+
|
140
|
+
|
141
|
+
App.handle_standard_message = (msg) ->
|
142
|
+
return unless listener = App.listeners[msg.serial]
|
143
|
+
|
144
|
+
delete App.listeners[msg.serial]
|
145
|
+
|
146
|
+
return unless _.isFunction(listener)
|
147
|
+
|
148
|
+
return listener(msg.data.__rtcp_error__) if msg.data.__rtcp_error__
|
149
|
+
|
150
|
+
if _.isArray(msg.data)
|
151
|
+
listener(null, msg.data...)
|
152
|
+
else
|
153
|
+
listener(null, msg.data)
|
154
|
+
#end
|
155
|
+
#end
|
156
|
+
|
157
|
+
|
158
|
+
App.handle_rpc_message = (msg) ->
|
159
|
+
unless Core.controllers[msg.controller]
|
160
|
+
throw new Error('Unknown controller called')
|
161
|
+
|
162
|
+
Core.controllers[msg.controller].load (api) ->
|
163
|
+
|
164
|
+
unless method = api[msg.method]
|
165
|
+
throw new Error('Unknown method called')
|
166
|
+
|
167
|
+
if args = msg.arguments
|
168
|
+
args = [args] unless _.isArray(args)
|
169
|
+
else
|
170
|
+
args = []
|
171
|
+
|
172
|
+
method.apply(api, args)
|
173
|
+
#end
|
174
|
+
|
175
|
+
|
176
|
+
App.send_rtcp_message = (controller, method, args, callback) ->
|
177
|
+
unless App.connected
|
178
|
+
App.call_on_reconnect.push(-> App.send_rtcp_message(controller, method, args, callback))
|
179
|
+
Core.connect() if App.explicitly_disconnected
|
180
|
+
return
|
181
|
+
#end
|
182
|
+
|
183
|
+
if _.isFunction(controller)
|
184
|
+
controller = controller()
|
185
|
+
#end
|
186
|
+
|
187
|
+
App.rtcp_serial += 1
|
188
|
+
data =
|
189
|
+
controller: controller
|
190
|
+
method: method
|
191
|
+
arguments: args
|
192
|
+
serial: App.rtcp_serial
|
193
|
+
#end
|
194
|
+
|
195
|
+
if callback
|
196
|
+
App.listeners[App.rtcp_serial] = callback
|
197
|
+
data.reply = true
|
198
|
+
#end
|
199
|
+
|
200
|
+
App.socket.send(JSON.stringify(data), binary: true)
|
201
|
+
#end
|
202
|
+
|
203
|
+
|
204
|
+
Core =
|
205
|
+
on_socket_open: ->
|
206
|
+
on_socket_close: ->
|
207
|
+
on_initialize: ->
|
208
|
+
on_controller_loaded: ->
|
209
|
+
|
210
|
+
on_channel_message: Channels.on_message
|
211
|
+
subscribe: Channels.subscribe
|
212
|
+
unsubscribe: Channels.unsubscribe
|
213
|
+
|
214
|
+
controllers: App.controllers()
|
215
|
+
send_rtcp_message: App.send_rtcp_message
|
216
|
+
|
217
|
+
connect: (url = '__rtcp__')->
|
218
|
+
|
219
|
+
return if typeof window.WebSocket == 'undefined'
|
220
|
+
protocol = if window.location.protocol.toLowerCase() == 'https:' then 'wss' else 'ws'
|
221
|
+
App.socket = new ReconnectingWebSocket("#{protocol}://#{window.location.host}/#{url}")
|
222
|
+
|
223
|
+
App.socket.onopen = ->
|
224
|
+
App.connected = true
|
225
|
+
_.forEach App.call_on_reconnect, (fn) ->
|
226
|
+
try
|
227
|
+
fn()
|
228
|
+
#end
|
229
|
+
App.call_on_reconnect = []
|
230
|
+
Core.on_socket_open(App.socket)
|
231
|
+
#end
|
232
|
+
|
233
|
+
App.socket.onerror = App.socket.onclose = ->
|
234
|
+
App.connected = false
|
235
|
+
Core.on_socket_close()
|
236
|
+
#end
|
237
|
+
|
238
|
+
App.socket.onmessage = App.onmessage
|
239
|
+
#end
|
240
|
+
|
241
|
+
disconnect: ->
|
242
|
+
App.explicitly_disconnected = true
|
243
|
+
App.socket.close()
|
244
|
+
#end
|
245
|
+
|
246
|
+
#end
|
247
|
+
|
248
|
+
module.exports = Core
|
@@ -0,0 +1,37 @@
|
|
1
|
+
_ =
|
2
|
+
isRegExp: require('lodash/isRegExp')
|
3
|
+
#end
|
4
|
+
|
5
|
+
subscriptions = {}
|
6
|
+
awaiting_subscriptions = {}
|
7
|
+
|
8
|
+
module.exports =
|
9
|
+
on_message: (msg) ->
|
10
|
+
# if there is a handler, call it
|
11
|
+
if handler = subscriptions[msg.channel]
|
12
|
+
delete subscriptions[msg.channel] if msg.unsubscribe
|
13
|
+
handler(msg.data) if msg.data
|
14
|
+
else
|
15
|
+
# otherwise store message for when handler defined to handle it straight away
|
16
|
+
awaiting_subscriptions[msg.channel] = msg.data
|
17
|
+
#end
|
18
|
+
|
19
|
+
|
20
|
+
subscribe: (channel, handler) ->
|
21
|
+
# if there is a awaiting subscription handle it right away
|
22
|
+
if msg = awaiting_subscriptions[channel]
|
23
|
+
delete awaiting_subscriptions[channel]
|
24
|
+
return handler(msg)
|
25
|
+
# otherwise subscribe
|
26
|
+
subscriptions[channel] = handler
|
27
|
+
#end
|
28
|
+
|
29
|
+
|
30
|
+
unsubscribe: (channel) ->
|
31
|
+
if _.isRegExp(channel)
|
32
|
+
for c in Object.keys(subscriptions).filter((c) -> channel.text(c))
|
33
|
+
delete subscriptions[c]
|
34
|
+
else
|
35
|
+
delete subscriptions[channel]
|
36
|
+
#end
|
37
|
+
#end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module.exports =
|
2
|
+
|
3
|
+
script: (url, done, failed) ->
|
4
|
+
script = document.createElement('script')
|
5
|
+
script.async = true
|
6
|
+
script.onload = done
|
7
|
+
script.onerror = failed
|
8
|
+
script.src = url
|
9
|
+
document.getElementsByTagName('head')[0].appendChild(script)
|
10
|
+
#end
|
11
|
+
|
12
|
+
|
13
|
+
stylesheet: (url, done) ->
|
14
|
+
link = document.createElement('link')
|
15
|
+
link.onload = done
|
16
|
+
link.type = 'text/css'
|
17
|
+
link.rel = 'stylesheet'
|
18
|
+
link.href = url
|
19
|
+
document.getElementsByTagName('head')[0].appendChild(link)
|
20
|
+
#end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
_ =
|
2
|
+
isFunction: require('lodash/isFunction')
|
3
|
+
isObject: require('lodash/isObject')
|
4
|
+
isArray: require('lodash/isArray')
|
5
|
+
has: require('lodash/has')
|
6
|
+
#end
|
7
|
+
|
8
|
+
QueryString = require('qs')
|
9
|
+
Api = require('page')
|
10
|
+
|
11
|
+
page = ->
|
12
|
+
|
13
|
+
this.navigate = (path, options) ->
|
14
|
+
if _.isFunction(path)
|
15
|
+
path = path()
|
16
|
+
|
17
|
+
if !path || _.isObject(path)
|
18
|
+
options = path
|
19
|
+
path = window.location.pathname
|
20
|
+
|
21
|
+
options = {} unless _.isObject(options)
|
22
|
+
|
23
|
+
if _.isArray(options.path)
|
24
|
+
path = '/' + options.path
|
25
|
+
.filter((x) -> x)
|
26
|
+
.map((x) -> String(x))
|
27
|
+
.join('/')
|
28
|
+
.replace(/\/+/, '/')
|
29
|
+
.replace(/^\//, '')
|
30
|
+
|
31
|
+
if _.isObject(options.params)
|
32
|
+
path = path + '?' + QueryString.stringify(options.params)
|
33
|
+
|
34
|
+
if options.reload
|
35
|
+
Api.stop()
|
36
|
+
window.location = path
|
37
|
+
|
38
|
+
parser = document.createElement('a')
|
39
|
+
parser.href = path
|
40
|
+
if parser.hostname
|
41
|
+
unless parser.hostname == location.hostname
|
42
|
+
throw new Error('Guess what! Someone tries to navigate out!')
|
43
|
+
|
44
|
+
args = [
|
45
|
+
path,
|
46
|
+
(if _.has(options, 'state') then options.state else {}),
|
47
|
+
(if _.has(options, 'dispatch') then options.dispatch else true),
|
48
|
+
(if _.has(options, 'push') then options.push else true)
|
49
|
+
]
|
50
|
+
Api.show.apply(this, args)
|
51
|
+
|
52
|
+
this.update_params()
|
53
|
+
#end
|
54
|
+
|
55
|
+
|
56
|
+
this.update_params = ->
|
57
|
+
this.params = QueryString.parse(window.location.search.slice(1))
|
58
|
+
this.path_params = window.location.pathname.replace(/^\/+|\/+$/g, '').split(/\/+/).filter((x) -> x.length > 0)
|
59
|
+
#end
|
60
|
+
|
61
|
+
this.update_params()
|
62
|
+
|
63
|
+
this
|
64
|
+
#end
|
65
|
+
|
66
|
+
page.Api = Api
|
67
|
+
|
68
|
+
module.exports = page
|
@@ -0,0 +1,57 @@
|
|
1
|
+
_ =
|
2
|
+
extend: require('lodash/extend')
|
3
|
+
has: require('lodash/has')
|
4
|
+
isFunction: require('lodash/isFunction')
|
5
|
+
#end
|
6
|
+
|
7
|
+
extend = (data) ->
|
8
|
+
_.extend({}, data || {}, api.global_data || {})
|
9
|
+
#end
|
10
|
+
|
11
|
+
api = (opts) ->
|
12
|
+
api.default_el || throw new Error('Render.default_el not set')
|
13
|
+
opts.data = extend(opts.data)
|
14
|
+
opts.el = opts.el || api.default_el
|
15
|
+
opts.magic = if _.has(opts, 'magic') then opts.magic else true
|
16
|
+
|
17
|
+
ractive = new api.Ractive(opts)
|
18
|
+
|
19
|
+
for h,f of api.global_handlers || {}
|
20
|
+
ractive.on(h, f)
|
21
|
+
|
22
|
+
ractive
|
23
|
+
#end
|
24
|
+
|
25
|
+
api.Ractive = require('ractive')
|
26
|
+
|
27
|
+
api.global_data = {}
|
28
|
+
api.global_handlers = {}
|
29
|
+
api.default_el = null
|
30
|
+
|
31
|
+
api.component = (opts) ->
|
32
|
+
data = opts.data
|
33
|
+
opts.data = ->
|
34
|
+
if _.isFunction(data)
|
35
|
+
extend(data())
|
36
|
+
else
|
37
|
+
extend(data)
|
38
|
+
#end
|
39
|
+
|
40
|
+
opts.magic = if _.has(opts, 'magic') then opts.magic else true
|
41
|
+
|
42
|
+
oninit = opts.oninit
|
43
|
+
opts.oninit = ->
|
44
|
+
for h,f of api.global_handlers || {}
|
45
|
+
this.on(h, f)
|
46
|
+
oninit?()
|
47
|
+
#end
|
48
|
+
api.Ractive.extend(opts)
|
49
|
+
#end
|
50
|
+
|
51
|
+
|
52
|
+
api.string = (opts = {}) ->
|
53
|
+
opts.data = extend(opts.data)
|
54
|
+
new api.Ractive(opts).toHTML()
|
55
|
+
#end
|
56
|
+
|
57
|
+
module.exports = api
|