fron 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 +7 -0
- data/docs/application.md +7 -0
- data/docs/configuration.md +29 -0
- data/docs/controllers.md +35 -0
- data/docs/routing.md +63 -0
- data/fron.gemspec +20 -0
- data/lib/fron.rb +4 -0
- data/lib/fron/version.rb +3 -0
- data/opal/fron.rb +5 -0
- data/opal/fron/core-ext/hash.rb +17 -0
- data/opal/fron/core.rb +10 -0
- data/opal/fron/core/adapters/local-storage.rb +41 -0
- data/opal/fron/core/adapters/rails.rb +48 -0
- data/opal/fron/core/application.rb +39 -0
- data/opal/fron/core/component.rb +81 -0
- data/opal/fron/core/configuration.rb +26 -0
- data/opal/fron/core/controller.rb +41 -0
- data/opal/fron/core/eventable.rb +31 -0
- data/opal/fron/core/logger.rb +8 -0
- data/opal/fron/core/model.rb +68 -0
- data/opal/fron/core/router.rb +81 -0
- data/opal/fron/dom.rb +11 -0
- data/opal/fron/dom/document.rb +20 -0
- data/opal/fron/dom/element.rb +102 -0
- data/opal/fron/dom/event.rb +70 -0
- data/opal/fron/dom/fragment.rb +9 -0
- data/opal/fron/dom/modules/classlist.rb +27 -0
- data/opal/fron/dom/modules/dimensions.rb +37 -0
- data/opal/fron/dom/modules/events.rb +19 -0
- data/opal/fron/dom/node.rb +79 -0
- data/opal/fron/dom/style.rb +21 -0
- data/opal/fron/dom/text.rb +9 -0
- data/opal/fron/dom/window.rb +23 -0
- data/opal/fron/request.rb +3 -0
- data/opal/fron/request/request.rb +51 -0
- data/opal/fron/request/response.rb +36 -0
- data/opal/fron/storage.rb +1 -0
- data/opal/fron/storage/local-storage.rb +18 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ee70da4161fdf883ebd912c124c53c5a8bb8ada5
|
4
|
+
data.tar.gz: ab1e9096d251fc25a772e8b9fcf9798b1b8deda4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cdddc4a004ae3e9160e82fa001db6f41199038d72e47426a4953ce40dbf2f681c0ba2dacd4f9fd31e66a8140c372590fadbe6004a0049b4f5ad1fd51b3592698
|
7
|
+
data.tar.gz: d265e541022bfb84a9299c6b9ca24386738ba932f5679cfe37fe5b3bd959734aa2bf20f39ec3930cb101619a61d36dc754c84fa77a40daf5bea375b932fa3d07
|
data/docs/application.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Configuration
|
2
|
+
Application configuration utility.
|
3
|
+
|
4
|
+
## Title
|
5
|
+
The layout of the application can be set with the 'title' DSL.
|
6
|
+
|
7
|
+
## Layout
|
8
|
+
The layout of the application can be set with the 'layout' DSL.
|
9
|
+
|
10
|
+
This DSL takes a block and runs it in the context of the main application component, with the injection poin for controllers as the argument.
|
11
|
+
|
12
|
+
## Routes
|
13
|
+
For using routes see the [routing documentation]().
|
14
|
+
|
15
|
+
## Example
|
16
|
+
```ruby
|
17
|
+
class TestApplication < Application
|
18
|
+
config.title = 'Test Application'
|
19
|
+
|
20
|
+
config.layout do |main|
|
21
|
+
component :header, 'header'
|
22
|
+
self << main
|
23
|
+
end
|
24
|
+
|
25
|
+
config.routes do
|
26
|
+
map SiteController
|
27
|
+
end
|
28
|
+
end
|
29
|
+
```
|
data/docs/controllers.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Controllers
|
2
|
+
Controllers are responsible for parts of the application, it handles state / view changes for itself only.
|
3
|
+
|
4
|
+
## Base Component
|
5
|
+
The base component can be specified with the `base` DSL method.
|
6
|
+
|
7
|
+
The base component is the "page" wthich is injected into the document when a route matches this controller. It is accessible with the `@base` attribute. It must be a subclass of `Component`.
|
8
|
+
|
9
|
+
## Global Events
|
10
|
+
A controller can listen on Global Events with the `on` DSL.
|
11
|
+
|
12
|
+
The first argument is the event to listen to and the second argument is the method to run when the event triggered. Globa Events can be trigger like so:
|
13
|
+
```ruby
|
14
|
+
Eventable.trigger 'load'
|
15
|
+
```
|
16
|
+
|
17
|
+
## Routes
|
18
|
+
For using routes see the [routing documentation]().
|
19
|
+
|
20
|
+
## Example
|
21
|
+
```ruby
|
22
|
+
class TestController < Controller
|
23
|
+
base BaseComponent
|
24
|
+
|
25
|
+
on :load, :loaded
|
26
|
+
|
27
|
+
def loaded
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def test
|
32
|
+
puts @base
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
data/docs/routing.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# Routing
|
2
|
+
There are two leves of routing:
|
3
|
+
|
4
|
+
* Application level: This defines which controller is responsibe for specified paths
|
5
|
+
* Controller level: This defines which actions / sub controllers on the controller are called for specified paths
|
6
|
+
|
7
|
+
## Applications Routes
|
8
|
+
Routes are defined in the Application Configuration with the `routes` DSL method.
|
9
|
+
|
10
|
+
You can define controllers for specific paths, for example the following `map 'users/', UserController` will delegate all paths under the `users/` to the `UserController`. The controller only recieves the portion of the path which remains after the matched path.
|
11
|
+
|
12
|
+
## Controller Routes
|
13
|
+
Routes are defined with the `route` DSL method.
|
14
|
+
|
15
|
+
The first argument is the path, the second argument is the action / sub controller to be called. The path can contain parameter identifiers such as `:name`. These will be passed along to the action as a hash in the first parameter.
|
16
|
+
|
17
|
+
## Before Filters
|
18
|
+
Before filters can be added to the controllers actions with the `beforeFilter` DSL method.
|
19
|
+
|
20
|
+
The first argument is the action to be called, the second argument is an array of methods which before the action should be called.
|
21
|
+
|
22
|
+
## Example
|
23
|
+
```ruby
|
24
|
+
class TestApplication < Application
|
25
|
+
config.routes do
|
26
|
+
# Both 'users/new' and 'users/10' will be
|
27
|
+
# handled by an instance of UserController
|
28
|
+
map 'users/', UserController
|
29
|
+
|
30
|
+
# Anything else will be handled by
|
31
|
+
# an instance of IndexController
|
32
|
+
map IndexController
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class CommentsController < Controller
|
37
|
+
...
|
38
|
+
end
|
39
|
+
|
40
|
+
class UserController < Controller
|
41
|
+
# users/new -> UserController#authorize -> UserController#new
|
42
|
+
route 'new', :new
|
43
|
+
# users/10/comments -> CommentsController with params[:id] = 10
|
44
|
+
route ':id/comments/', CommentsController
|
45
|
+
# users/10 -> UserController#authorize -> USerController#user with params[:id] = 10
|
46
|
+
route ':id', :user
|
47
|
+
|
48
|
+
beforeFilter :authorize, [:new,:user]
|
49
|
+
|
50
|
+
def new
|
51
|
+
...
|
52
|
+
end
|
53
|
+
|
54
|
+
def user(params)
|
55
|
+
puts params[:id]
|
56
|
+
...
|
57
|
+
end
|
58
|
+
|
59
|
+
def authorize
|
60
|
+
...
|
61
|
+
end
|
62
|
+
end
|
63
|
+
```
|
data/fron.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/fron/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'fron'
|
6
|
+
s.version = Fron::VERSION
|
7
|
+
s.author = 'Gusztav Szikszai'
|
8
|
+
s.email = 'gusztav.szikszai@digitalnatives.hu'
|
9
|
+
s.homepage = ''
|
10
|
+
s.summary = 'Frontend Application Framework'
|
11
|
+
s.description = 'Frontend Application Framework that uses Opal'
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.require_paths = ['lib']
|
17
|
+
|
18
|
+
s.add_runtime_dependency 'opal', ['~> 0.6.2']
|
19
|
+
s.add_development_dependency 'opal-rspec', '~> 0.3.0.beta3'
|
20
|
+
end
|
data/lib/fron.rb
ADDED
data/lib/fron/version.rb
ADDED
data/opal/fron.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Hash
|
2
|
+
def to_query_string
|
3
|
+
r = []
|
4
|
+
each do |key,value|
|
5
|
+
r << `encodeURIComponent(#{key})+"="+encodeURIComponent(#{value})`
|
6
|
+
end
|
7
|
+
r.join "&"
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_form_data
|
11
|
+
r = `new FormData()`
|
12
|
+
each do |key,value|
|
13
|
+
`r.append(#{key},#{value})`
|
14
|
+
end
|
15
|
+
r
|
16
|
+
end
|
17
|
+
end
|
data/opal/fron/core.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require './core/logger'
|
2
|
+
require './core/component'
|
3
|
+
require './core/adapters/rails'
|
4
|
+
require './core/adapters/local-storage'
|
5
|
+
require './core/configuration'
|
6
|
+
require './core/eventable'
|
7
|
+
require './core/model'
|
8
|
+
require './core/router'
|
9
|
+
require './core/controller'
|
10
|
+
require './core/application'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
module Fron
|
5
|
+
module Adapters
|
6
|
+
class LocalAdapter
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def all(&block)
|
12
|
+
block.call LocalStorage.all
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(id, &block)
|
16
|
+
block.call LocalStorage.get id
|
17
|
+
end
|
18
|
+
|
19
|
+
def set(id, data, &block)
|
20
|
+
id = SecureRandom.uuid unless id
|
21
|
+
data[:id] = id
|
22
|
+
unless (errors = validate data)
|
23
|
+
LocalStorage.set id, data
|
24
|
+
block.call nil
|
25
|
+
else
|
26
|
+
block.call errors
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate(data)
|
31
|
+
errors = {}
|
32
|
+
@options[:fields].map do |field|
|
33
|
+
next unless data[field] == ""
|
34
|
+
errors[field] = ["can't be blank"]
|
35
|
+
valid = false
|
36
|
+
end
|
37
|
+
errors.keys.length == 0 ? nil : errors
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Fron
|
2
|
+
module Adapters
|
3
|
+
class RailsAdapter
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@options = options
|
7
|
+
@request = Request.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def all(&block)
|
11
|
+
setUrl nil
|
12
|
+
@request.get { |response| block.call response.json }
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(id,&block)
|
16
|
+
setUrl id
|
17
|
+
@request.get { |response| block.call response.json }
|
18
|
+
end
|
19
|
+
|
20
|
+
def set(id,data,&block)
|
21
|
+
setUrl id
|
22
|
+
method = id ? 'put' : 'post'
|
23
|
+
@request.send(method,transform(data)) do |response|
|
24
|
+
block.call case response.status
|
25
|
+
when 201, 204
|
26
|
+
nil
|
27
|
+
when 422
|
28
|
+
response.json
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def setUrl(id)
|
36
|
+
base = @options[:endpoint] + "/" + @options[:resources]
|
37
|
+
base += id ? "/" + id.to_s : ".json"
|
38
|
+
@request.url = base
|
39
|
+
end
|
40
|
+
|
41
|
+
def transform(data)
|
42
|
+
newdata = data.dup
|
43
|
+
newdata.keys.each{ |key| newdata["#{@options[:resource]}[#{key}]"] = newdata.delete key}
|
44
|
+
newdata
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Fron
|
2
|
+
class Application
|
3
|
+
class << self
|
4
|
+
def config
|
5
|
+
@configuration ||= Configuration.new
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@routeMap = []
|
11
|
+
DOM::Document.title = config.title
|
12
|
+
instance_eval &config.routeBlock
|
13
|
+
@router = Router.new @routeMap, config
|
14
|
+
|
15
|
+
DOM::Window.on 'load' do
|
16
|
+
config.stylesheets.map do |sheet|
|
17
|
+
link = DOM::Element.new("link[rel=stylesheet][type=text/css][href=#{sheet}]")
|
18
|
+
link.on 'load' do
|
19
|
+
config.logger.info "External stylesheet loaded: #{sheet}"
|
20
|
+
end
|
21
|
+
DOM::Document.head << link
|
22
|
+
end
|
23
|
+
end
|
24
|
+
config.logger.info "Initialized Applicationation!"
|
25
|
+
config.logger.info "Inserting application to DOM!"
|
26
|
+
DOM::Document.body << config.app
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def map(*args)
|
32
|
+
@routeMap << Router.map(*args)
|
33
|
+
end
|
34
|
+
|
35
|
+
def config
|
36
|
+
self.class.config
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Fron
|
2
|
+
class Component < DOM::Element
|
3
|
+
attr_reader :model
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :events
|
7
|
+
attr_accessor :tagname
|
8
|
+
attr_accessor :components
|
9
|
+
|
10
|
+
def tag(tag)
|
11
|
+
@tagname = tag
|
12
|
+
end
|
13
|
+
|
14
|
+
def on(*args)
|
15
|
+
@events ||= []
|
16
|
+
@events << args
|
17
|
+
end
|
18
|
+
|
19
|
+
def component(*args,&block)
|
20
|
+
attr_reader args[0]
|
21
|
+
@components ||= []
|
22
|
+
@components << ( args << block )
|
23
|
+
end
|
24
|
+
|
25
|
+
def delegate(method,target)
|
26
|
+
define_method(method) do
|
27
|
+
instance_variable_get("@#{target}").send(method)
|
28
|
+
end
|
29
|
+
|
30
|
+
define_method(method+"=") do |value|
|
31
|
+
instance_variable_get("@#{target}").send(method+"=",value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(*args)
|
37
|
+
case args.length
|
38
|
+
when 1
|
39
|
+
@model = args[0]
|
40
|
+
when 2
|
41
|
+
tag, @model = args
|
42
|
+
end
|
43
|
+
|
44
|
+
super tag || self.class.tagname || self.class.name.split("::").last
|
45
|
+
|
46
|
+
applyEvents
|
47
|
+
createComponents
|
48
|
+
|
49
|
+
return if !respond_to?(:render) || !@model
|
50
|
+
@model.on 'change' do render end
|
51
|
+
render
|
52
|
+
end
|
53
|
+
|
54
|
+
def component(name,comp,&block)
|
55
|
+
c = comp.is_a?(Class) ? comp.new(@model) : Component.new(comp, @model)
|
56
|
+
c.instance_eval(&block) if block
|
57
|
+
self << c
|
58
|
+
self.instance_variable_set "@#{name}", c
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def createComponents
|
64
|
+
return unless self.class.components
|
65
|
+
self.class.components.each do |args|
|
66
|
+
component args[0], args[1], &args[2]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def applyEvents
|
71
|
+
return unless self.class.events
|
72
|
+
self.class.events.each do |args|
|
73
|
+
if args.length == 3
|
74
|
+
delegate(args[0], args[1]) { |e| self.method(args[2]).call e }
|
75
|
+
else
|
76
|
+
on(args[0]) { |e| self.method(args[1]).call e }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Fron
|
2
|
+
class Configuration
|
3
|
+
class App < Component
|
4
|
+
end
|
5
|
+
class Yield < Component
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_accessor :title, :stylesheets, :logger
|
9
|
+
attr_reader :routeBlock, :main, :app
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@main = Yield.new
|
13
|
+
@app = App.new
|
14
|
+
|
15
|
+
DOM::Document.body.empty
|
16
|
+
end
|
17
|
+
|
18
|
+
def routes(&block)
|
19
|
+
@routeBlock = block
|
20
|
+
end
|
21
|
+
|
22
|
+
def layout(&block)
|
23
|
+
@app.instance_exec @main, &block
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|