sombrero 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|