opal-ferro 0.10.0 → 0.10.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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +23 -0
- data/README.md +29 -0
- data/docs/GettingStarted.md +187 -0
- data/lib/opal-ferro/version.rb +10 -2
- data/opal/opal-ferro/elements/ferro_combos.js.rb +130 -0
- data/opal/opal-ferro/elements/ferro_components.js.rb +82 -0
- data/opal/opal-ferro/elements/ferro_form.js.rb +257 -0
- data/opal/opal-ferro/elements/ferro_inline.js.rb +137 -0
- data/opal/opal-ferro/elements/ferro_misc.js.rb +60 -0
- data/opal/opal-ferro/ferro_base_element.js.rb +187 -0
- data/opal/opal-ferro/ferro_document.js.rb +59 -35
- data/opal/opal-ferro/ferro_elementary.js.rb +99 -63
- data/opal/opal-ferro/ferro_factory.js.rb +69 -44
- data/opal/opal-ferro/ferro_router.js.rb +147 -88
- data/opal/opal-ferro/ferro_sequence.js.rb +20 -9
- data/opal/opal-ferro/ferro_xhr.js.rb +132 -69
- data/opal/opal-ferro.rb +6 -4
- data/opal-ferro.gemspec +1 -1
- metadata +26 -7
- data/opal/opal-ferro/ferro_base_elements.js.rb +0 -158
- data/opal/opal-ferro/ferro_components.js.rb +0 -92
- data/opal/opal-ferro/ferro_element.js.rb +0 -110
- data/opal/opal-ferro/ferro_form_elements.js.rb +0 -160
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0cf34d1239b6886601737690e639cadd7e0fd9971a73cb233eed18faf78ba764
|
4
|
+
data.tar.gz: 9d6f89cbc0c4fc22c095d0b3d057e1255ccbc28f2b6ae8da7cdca3222d6fae39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e92a9b4a555a1a8c9ae937b222a43880b3d650aefb5400fe08766cb8cdf7f4e3f95351ba8b267c3f7f6e1d08dc5967c465056bf911572cd2fd2c6a1c94b3e4d
|
7
|
+
data.tar.gz: 7de1f758372345527f612eeb744727c4c97282f706154979edc439f230f00a4fa043403c2785570dee947f625212b9041c9e691c8019c03ee8a34704074b386a
|
data/.gitignore
CHANGED
data/.yardopts
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# 0.10.1 - March 31, 2018
|
2
|
+
|
3
|
+
- Added documentation (using Yard)
|
4
|
+
- Modularized Ferro (breaking change), see below
|
5
|
+
- AJAX can now handle any type of request (not just get)
|
6
|
+
|
7
|
+
To upgrade from 0.10.0 to 0.10.1:
|
8
|
+
|
9
|
+
- replace FerroDocument with Ferro::Document
|
10
|
+
- replace FerroXhr with Ferro::Xhr
|
11
|
+
- replace FerroSequence with Ferro::Sequence
|
12
|
+
- replace FerroElementForm with Ferro::Form::Base
|
13
|
+
- replace FerroElementForm... with Ferro::Form::...
|
14
|
+
- replace FerroElementComponent with Ferro::Component::Base
|
15
|
+
- replace FerroElementComponent... with Ferro::Component::...
|
16
|
+
- replace FerroSearch with Ferro::Combo::Search
|
17
|
+
- replace FerroPullDown with Ferro::Combo::PullDown
|
18
|
+
- replace FerroElement... with Ferro::Element::...
|
19
|
+
|
20
|
+
|
21
|
+
# 0.10.0 - February 2, 2018
|
22
|
+
|
23
|
+
Initial version
|
data/README.md
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
# Opal-Ferro
|
2
|
+
|
3
|
+
[](http://rubydoc.org/gems/opal-ferro)
|
4
|
+
[](https://github.com/easydatawarehousing/opal-ferro/releases)
|
5
|
+
[](#license)
|
6
|
+
|
2
7
|
Ferro is a small Ruby library on top of [Opal](http://opalrb.com/)
|
3
8
|
that enables an object-oriented programming style for creating code
|
4
9
|
that runs in the webbrowser.
|
@@ -24,6 +29,17 @@ Or install it yourself:
|
|
24
29
|
Please see the [Ferro website](https://easydatawarehousing.github.io/ferro/)
|
25
30
|
for background information and examples.
|
26
31
|
|
32
|
+
## Versioning
|
33
|
+
Opal-Ferro follows the versioning scheme of [Opal](https://github.com/opal/opal).
|
34
|
+
The first two parts of the version number of Ferro imply compatibility
|
35
|
+
with the Opal version with that same number.
|
36
|
+
So Ferro 0.10.x should be compatible with and dependant on Opal 0.10.x.
|
37
|
+
|
38
|
+
## Roadmap
|
39
|
+
Please see the development roadmap
|
40
|
+
[here](https://github.com/easydatawarehousing/opal-ferro/wiki/Development-roadmap)
|
41
|
+
for the current wishlist of features to be added to Ferro.
|
42
|
+
|
27
43
|
## Development
|
28
44
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
29
45
|
To release a new version, update the version number in `version.rb`
|
@@ -38,6 +54,19 @@ This project is intended to be a safe, welcoming space for collaboration
|
|
38
54
|
and contributors are expected to adhere to the
|
39
55
|
[Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
40
56
|
|
57
|
+
## Documentation
|
58
|
+
Yard is used to generate documentation. In development start yard using:
|
59
|
+
|
60
|
+
yard server -r
|
61
|
+
|
62
|
+
Use this to list all undocumented items:
|
63
|
+
|
64
|
+
yard stats --list-undoc
|
65
|
+
|
66
|
+
To generate documentation for publication, cd into project root and use:
|
67
|
+
|
68
|
+
yardoc
|
69
|
+
|
41
70
|
## License
|
42
71
|
The gem is available as open source under the terms of the MIT License.
|
43
72
|
See LICENSE.txt
|
@@ -0,0 +1,187 @@
|
|
1
|
+
# @title Getting started with Opal-Ferro
|
2
|
+
|
3
|
+
# Getting started with Opal-Ferro
|
4
|
+
|
5
|
+
Ferro is a small Ruby library on top of [Opal](http://opalrb.com/)
|
6
|
+
that enables an object-oriented programming style for creating code
|
7
|
+
that runs in the webbrowser.
|
8
|
+
No more distractions like HTML and searching for DOM elements,
|
9
|
+
just beautiful and simple Ruby code. Front-End-Ruby-ROcks!
|
10
|
+
|
11
|
+
|
12
|
+
* [How does Ferro work](#ferro)
|
13
|
+
* [Creating the Master Object Model](#mom)
|
14
|
+
* [Adding elements](#demo)
|
15
|
+
* [Creation lifecycle](#lifecycle)
|
16
|
+
* [Navigating the Master Object Model](#navigating)
|
17
|
+
* [Styling Ferro elements](#styling)
|
18
|
+
* [More information](#more)
|
19
|
+
|
20
|
+
<a name="ferro"></a>
|
21
|
+
|
22
|
+
## How does Ferro work?
|
23
|
+
Ferro uses an object oriented programming style. You instantiate an object, that object
|
24
|
+
in turn instantiates more child objects and add these as instance variables to itself.
|
25
|
+
And so on, producing a hierarchy of object instances.
|
26
|
+
This is called the Master Object Model (MOM).
|
27
|
+
|
28
|
+
When an object is instanciated in the MOM, Ferro will add an element to the webbrowsers
|
29
|
+
Document Object Model (DOM). The MOM keeps a reference to every DOM element.
|
30
|
+
This erradicates the need for element lookups (jquery $ searches).
|
31
|
+
If you need an element you know where to find it in the MOM.
|
32
|
+
Getter methods are automatically added by Ferro for easy access to instance variables.
|
33
|
+
|
34
|
+
Each object in the MOM inherits from a Ferro class.
|
35
|
+
Which Ferro class you use determines what type of DOM element will be created.
|
36
|
+
All Ferro classes inherit from one base class: Ferro::BaseElement.
|
37
|
+
For most DOM elements in the html specs there is a corresponding Ferro class.
|
38
|
+
For instance if you need a html5 `<header>` element you would create a class that inherits
|
39
|
+
from Ferro::Component::Header.
|
40
|
+
Other html elements have a more abstract counterpart:
|
41
|
+
all text elements (`<p>`, `<h1>` .. `<h6>`) have one Ferro class `Ferro::Element::Text`.
|
42
|
+
The size of the text element is an option when you instantiate the object.
|
43
|
+
|
44
|
+
<a name="mom"></a>
|
45
|
+
|
46
|
+
## Creating the Master Object Model
|
47
|
+
|
48
|
+
First we need a class that inherits from FerroDocument.
|
49
|
+
This is the staring point for any Ferro application.
|
50
|
+
The Document instance will attach itself in the DOM to
|
51
|
+
`document.body`.
|
52
|
+
|
53
|
+
In the example below, the Document instance will create one child element.
|
54
|
+
|
55
|
+
class Document < Ferro::Document
|
56
|
+
|
57
|
+
# The cascade method is called after the Document
|
58
|
+
# has been created and is ready to create child
|
59
|
+
# objects.
|
60
|
+
def cascade
|
61
|
+
add_child :demo, Demo
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
To start the application one instance of the Document must be created.
|
66
|
+
In the `application.js` file (if you are using Rails for instance)
|
67
|
+
`Document.new` is called when the browser has loaded the necessary
|
68
|
+
files.
|
69
|
+
|
70
|
+
`document.addEventListener("DOMContentLoaded", function() {#{Document.new};})`
|
71
|
+
|
72
|
+
The backticks are Opal's way of entering _raw_ Javascript. Using
|
73
|
+
familiar Ruby string interpolation `#{}` a reference to `Document.new` can
|
74
|
+
be inserted.
|
75
|
+
This is the first and last line of Javascript that is needed.
|
76
|
+
Everyting else is Ruby code.
|
77
|
+
|
78
|
+
<a name="demo"></a>
|
79
|
+
|
80
|
+
## Adding elements
|
81
|
+
|
82
|
+
Let's look at a very simple example. We will define a small component
|
83
|
+
with a title and a button. The button should change the title text when clicked.
|
84
|
+
|
85
|
+
class Demo < Ferro::Component::Base
|
86
|
+
def cascade
|
87
|
+
# Add a title
|
88
|
+
add_child :title, Ferro::Element::Text, size: 4, content: 'Title'
|
89
|
+
|
90
|
+
# Add a button
|
91
|
+
add_child :btn, DemoButton, content: 'Click me'
|
92
|
+
end
|
93
|
+
|
94
|
+
def rotate_title
|
95
|
+
# We have access to the 'title' instance variable
|
96
|
+
txt = title.get_text
|
97
|
+
title.set_text (txt[1..-1] + txt[0]).capitalize
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class DemoButton < Ferro::Form::Button
|
102
|
+
def clicked
|
103
|
+
# Every element knows its parent
|
104
|
+
parent.rotate_title
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
The code in Demo _cascade_ method is equivalent to something like this,
|
109
|
+
which should look more familiar to a Ruby programmer:
|
110
|
+
|
111
|
+
class Demo
|
112
|
+
def initialize
|
113
|
+
@title = Ferro::Element::Text.new(size: 4, content: 'Title')
|
114
|
+
@btn = DemoButton.new(content: 'Click me')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
Just like above, the `add_child` method will create instance variables
|
119
|
+
`@title` and `@btn`. In Ferro we don't need to use the @.
|
120
|
+
|
121
|
+
<a name="lifecycle"></a>
|
122
|
+
|
123
|
+
## Creation lifecycle
|
124
|
+
|
125
|
+
Every Ferro class has 3 hooks into the object creation lifecycle:
|
126
|
+
|
127
|
+
- before_create
|
128
|
+
- after_create
|
129
|
+
- cascade
|
130
|
+
|
131
|
+
The first two are called just before and after the object itself
|
132
|
+
is created. The cascade hook is called when the object is ready
|
133
|
+
to create child objects.
|
134
|
+
In this example most of the action happens in the _cascade_ method.
|
135
|
+
|
136
|
+
By inheriting from _Ferro::Form::Button_, _DemoButton_ has access
|
137
|
+
to the click event handler. After a click occurred, it signals
|
138
|
+
its parent (_Demo_) to rotate the title text.
|
139
|
+
|
140
|
+
<a name="navigating"></a>
|
141
|
+
|
142
|
+
## Navigating the Master Object Model
|
143
|
+
|
144
|
+
There are two ways to navigate around the MOM: upward and downward.
|
145
|
+
Every object in the MOM knows its parent. If an event is received by an
|
146
|
+
object like a button, the parent of that object usually can handle the
|
147
|
+
event. The parent element can be accessed using the `parent` method.
|
148
|
+
|
149
|
+
Searching upward further than one parent quickly becomes difficult to
|
150
|
+
follow. So you can always search downward starting from the top.
|
151
|
+
Every object in the MOM can access the root object using the `root`
|
152
|
+
method. From the root you can access all MOM objects.
|
153
|
+
|
154
|
+
There is a shortcut to find an object starting from the nearest element
|
155
|
+
in the hierarchy that is a component. All semantical elements
|
156
|
+
(like header and section) are components. All objects that are children
|
157
|
+
of a component have immediate access to that component using the
|
158
|
+
`component` method.
|
159
|
+
|
160
|
+
<a name="styling"></a>
|
161
|
+
|
162
|
+
## Styling Ferro elements
|
163
|
+
|
164
|
+
The created elements still need some styling. Ferro uses a handy
|
165
|
+
naming convention: CSS classnames match Ruby classnames.
|
166
|
+
For example:
|
167
|
+
|
168
|
+
class DemoButton < Ferro::Form::Button
|
169
|
+
end
|
170
|
+
|
171
|
+
When we create this button in the MOM, its DOM counterpart receives
|
172
|
+
two classnames. One matching the Ruby classname `DemoButton` and
|
173
|
+
one for its Ruby superclass `FerroFormButton`.
|
174
|
+
These classnames are _dasherized_. In CSS you can reference these
|
175
|
+
classnames as `demo-button` and `ferro-form-button`.
|
176
|
+
|
177
|
+
<a name="more"></a>
|
178
|
+
|
179
|
+
## More information
|
180
|
+
|
181
|
+
Please see the [Ferro website](https://easydatawarehousing.github.io/ferro/)
|
182
|
+
for more information and examples.
|
183
|
+
The [source code](https://github.com/easydatawarehousing/ferro)
|
184
|
+
for that webapp is a good Ferro example in itself.
|
185
|
+
|
186
|
+
For some simple boilerplate code to get started with Ferro you can use
|
187
|
+
[this Rails example](https://github.com/easydatawarehousing/ferro-example-todolist).
|
data/lib/opal-ferro/version.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
+
# Ferro relies on Opal to run in the webbrowser.
|
1
2
|
module Opal
|
3
|
+
|
4
|
+
# This module contains all Ferro functionality.
|
2
5
|
module Ferro
|
3
|
-
|
6
|
+
# Opal-Ferro follows the versioning scheme of Opal.
|
7
|
+
# The first two parts of the version number of Ferro imply
|
8
|
+
# compatibility with the Opal version with that same number.
|
9
|
+
# So Ferro 0.10.x should be compatible with and dependant
|
10
|
+
# on Opal 0.10.x.
|
11
|
+
VERSION = "0.10.1"
|
4
12
|
end
|
5
|
-
end
|
13
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Ferro
|
2
|
+
|
3
|
+
# This module contains some combined elements.
|
4
|
+
module Combo
|
5
|
+
# Creates a form with a text input and a submit button.
|
6
|
+
# Specify option :button_text to set the submit button text.
|
7
|
+
# Specify option :placeholder to set a placeholder text for the input.
|
8
|
+
# Two states are defined: search-input-open, search-submit-open
|
9
|
+
# to define CSS rules.
|
10
|
+
class Search < Form::Base
|
11
|
+
|
12
|
+
# Internal method.
|
13
|
+
def _before_create
|
14
|
+
@button_text = option_replace :button_text, ' '
|
15
|
+
@placeholder = option_replace :placeholder, ' Search...'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Internal method.
|
19
|
+
def cascade
|
20
|
+
add_child :entry, SearchInput, { placeholder: @placeholder }
|
21
|
+
add_child :submit, SearchSubmit, { content: @button_text }
|
22
|
+
end
|
23
|
+
|
24
|
+
# Internal method.
|
25
|
+
def do_submit
|
26
|
+
value = entry.value.strip
|
27
|
+
submitted(value) if !value.empty?
|
28
|
+
|
29
|
+
entry.toggle_state :search_input_open
|
30
|
+
submit.toggle_state :search_submit_open
|
31
|
+
|
32
|
+
entry.value = nil
|
33
|
+
entry.set_focus if entry.state_active?(:search_input_open)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Override this method to specify what happens when
|
37
|
+
# submit button is clicked or enter key is pressed.
|
38
|
+
#
|
39
|
+
# @param [String] value The value of the text input.
|
40
|
+
def submitted(value);end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Internal class for use with {Search}.
|
44
|
+
class SearchInput < Form::Input
|
45
|
+
|
46
|
+
# Internal method.
|
47
|
+
def _after_create
|
48
|
+
add_state :search_input_open
|
49
|
+
super
|
50
|
+
end
|
51
|
+
|
52
|
+
# Internal method.
|
53
|
+
def entered
|
54
|
+
parent.do_submit
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Internal class for use with {Search}.
|
59
|
+
class SearchSubmit < Form::Button
|
60
|
+
|
61
|
+
# Internal method.
|
62
|
+
def _after_create
|
63
|
+
add_state :search_submit_open
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
# Internal method.
|
68
|
+
def clicked
|
69
|
+
parent.do_submit
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Creates a simple pull-down menu.
|
74
|
+
# Specify option :title to set the menu title text.
|
75
|
+
# Specify option :items as an Array of Ferro classes.
|
76
|
+
# Each class should be something clickable, for instance a
|
77
|
+
# FormBlock. These classes will be instanciated by
|
78
|
+
# this element.
|
79
|
+
class PullDown < BaseElement
|
80
|
+
|
81
|
+
# Internal method.
|
82
|
+
def _before_create
|
83
|
+
@title_text = option_replace :title, '='
|
84
|
+
@items = option_replace :items, []
|
85
|
+
super
|
86
|
+
end
|
87
|
+
|
88
|
+
# Internal method.
|
89
|
+
def _after_create
|
90
|
+
add_state :pull_down_open
|
91
|
+
super
|
92
|
+
end
|
93
|
+
|
94
|
+
# Internal method.
|
95
|
+
def cascade
|
96
|
+
add_child :title, PullDownTitle, { content: @title_text }
|
97
|
+
add_child :items, PullDownItems, { items: @items }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Internal class for use with {PullDown}.
|
102
|
+
# This element has a state: pull-down-open
|
103
|
+
# to define CSS rules.
|
104
|
+
class PullDownTitle < Form::Block
|
105
|
+
|
106
|
+
# Internal method.
|
107
|
+
def clicked
|
108
|
+
parent.toggle_state :pull_down_open
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Internal class for use with {PullDown}.
|
113
|
+
class PullDownItems < BaseElement
|
114
|
+
|
115
|
+
# Internal method.
|
116
|
+
def _before_create
|
117
|
+
@id = Sequence.new 'pdi_'
|
118
|
+
@itemlist = option_replace :items, []
|
119
|
+
super
|
120
|
+
end
|
121
|
+
|
122
|
+
# Internal method.
|
123
|
+
def cascade
|
124
|
+
@items = @itemlist.map do |item|
|
125
|
+
add_child @id.next, item
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Ferro
|
2
|
+
|
3
|
+
# This module contains all semantic elements.
|
4
|
+
module Component
|
5
|
+
# A generic component element.
|
6
|
+
# In the DOM creates a: <div>.
|
7
|
+
# All semantical elements inherit from this class.
|
8
|
+
class Base < BaseElement
|
9
|
+
|
10
|
+
# Return self when called by children / descendants.
|
11
|
+
def component
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates a semantical element.
|
17
|
+
# This is a component.
|
18
|
+
# In the DOM creates a: <header>.
|
19
|
+
class Header < Base
|
20
|
+
|
21
|
+
# Internal method.
|
22
|
+
def _before_create
|
23
|
+
@domtype = :header
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Creates a semantical element.
|
28
|
+
# This is a component.
|
29
|
+
# In the DOM creates a: <nav>.
|
30
|
+
class Navigation < Base
|
31
|
+
|
32
|
+
# Internal method.
|
33
|
+
def _before_create
|
34
|
+
@domtype = :nav
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Creates a semantical element.
|
39
|
+
# This is a component.
|
40
|
+
# In the DOM creates a: <section>.
|
41
|
+
class Section < Base
|
42
|
+
|
43
|
+
# Internal method.
|
44
|
+
def _before_create
|
45
|
+
@domtype = :section
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Creates a semantical element.
|
50
|
+
# This is a component.
|
51
|
+
# In the DOM creates a: <article>.
|
52
|
+
class Article < Base
|
53
|
+
|
54
|
+
# Internal method.
|
55
|
+
def _before_create
|
56
|
+
@domtype = :article
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates a semantical element.
|
61
|
+
# This is a component.
|
62
|
+
# In the DOM creates a: <aside>.
|
63
|
+
class Aside < Base
|
64
|
+
|
65
|
+
# Internal method.
|
66
|
+
def _before_create
|
67
|
+
@domtype = :aside
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Creates a semantical element.
|
72
|
+
# This is a component.
|
73
|
+
# In the DOM creates a: <footer>.
|
74
|
+
class Footer < Base
|
75
|
+
|
76
|
+
# Internal method.
|
77
|
+
def _before_create
|
78
|
+
@domtype = :footer
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|