opal-ferro 0.10.1 → 0.10.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/CHANGELOG.md +7 -0
- data/README.md +1 -1
- data/docs/GettingStarted.md +43 -0
- data/lib/opal-ferro/version.rb +1 -1
- data/opal/opal-ferro/elements/ferro_inline.js.rb +14 -1
- data/opal/opal-ferro/ferro_base_element.js.rb +11 -3
- data/opal/opal-ferro/ferro_compositor.js.rb +77 -0
- data/opal/opal-ferro/ferro_document.js.rb +20 -2
- data/opal/opal-ferro/ferro_elementary.js.rb +14 -0
- data/opal/opal-ferro/ferro_factory.js.rb +43 -2
- data/opal/opal-ferro.rb +1 -0
- data/opal-ferro.gemspec +6 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2d8c1d43bb035ec89c3ec3b1508845063b0b941f4384d353de5cfd496349f93
|
4
|
+
data.tar.gz: 3090d75958d6331a6957cd7e92406bf4e718ece68ee9b2dc0e7e92d1d0e64052
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed7efe3c96aaede6364c1c9c8519ebd071e8d8b6c5643134a55064ea5156600961fd2acd007da5e2faddce2bd6962712c351e790cfe99ca5997c0b2016450e41
|
7
|
+
data.tar.gz: ecd0acb39193f98faabb31da93383d9de08b1fccfb03cde7c34784661d3eaa2ff292aa4f069c7456f3ab2a786c330b832fe99797145c584e55d52c8e1d64962c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# 0.10.2 - June 1, 2018
|
2
|
+
|
3
|
+
[0.10.2]: https://github.com/easydatawarehousing/opal-ferro/compare/v0.10.1...v0.10.2
|
4
|
+
|
5
|
+
- Added the style compositor to map Ruby classnames to CSS classnames
|
6
|
+
- Fixed: don't add clicks on an anchor to the browser history when the href is empty
|
7
|
+
|
1
8
|
# 0.10.1 - March 31, 2018
|
2
9
|
|
3
10
|
- Added documentation (using Yard)
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Opal-Ferro
|
2
2
|
|
3
3
|
[](http://rubydoc.org/gems/opal-ferro)
|
4
|
-
[](https://github.com/easydatawarehousing/opal-ferro/releases)
|
5
5
|
[](#license)
|
6
6
|
|
7
7
|
Ferro is a small Ruby library on top of [Opal](http://opalrb.com/)
|
data/docs/GettingStarted.md
CHANGED
@@ -15,6 +15,7 @@ just beautiful and simple Ruby code. Front-End-Ruby-ROcks!
|
|
15
15
|
* [Creation lifecycle](#lifecycle)
|
16
16
|
* [Navigating the Master Object Model](#navigating)
|
17
17
|
* [Styling Ferro elements](#styling)
|
18
|
+
* [Using a compositor to style elements](#compositor)
|
18
19
|
* [More information](#more)
|
19
20
|
|
20
21
|
<a name="ferro"></a>
|
@@ -174,6 +175,48 @@ one for its Ruby superclass `FerroFormButton`.
|
|
174
175
|
These classnames are _dasherized_. In CSS you can reference these
|
175
176
|
classnames as `demo-button` and `ferro-form-button`.
|
176
177
|
|
178
|
+
<a name="compositor"></a>
|
179
|
+
|
180
|
+
## Using a compositor to style elements
|
181
|
+
|
182
|
+
There is alternative way to add styling to generated DOM objects.
|
183
|
+
In your `Document` you can set a `Compositor` object.
|
184
|
+
A compositor maps Ruby class names to a list of CSS class names.
|
185
|
+
When a Ferro object is created its class name is looked up in the
|
186
|
+
compositor mapping. If found the list of CSS classes will be added
|
187
|
+
to the corresponding DOM element.
|
188
|
+
The mapping is simply a Ruby Hash. The keys are Ruby class names,
|
189
|
+
the values are CSS class names.
|
190
|
+
Optionally you can use the theme parameter to create different
|
191
|
+
mappings per theme. Use the `Document.switch_compositor_theme`
|
192
|
+
method to switch themes at run time.
|
193
|
+
Add the compositor like this:
|
194
|
+
|
195
|
+
class Document < Ferro::Document
|
196
|
+
def before_create
|
197
|
+
@compositor = AppCompositor.new :dark
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
The theme parameter is optional. A simple mapping might look like this:
|
202
|
+
|
203
|
+
class MyCompositor < Ferro::Compositor
|
204
|
+
|
205
|
+
def map(theme)
|
206
|
+
m = {
|
207
|
+
'Document' => %w{black bg-white sans-serif},
|
208
|
+
'Banner' => %w{w-100},
|
209
|
+
}
|
210
|
+
|
211
|
+
if theme == :dark
|
212
|
+
m['Document'] = %w{white bg-black sans-serif}
|
213
|
+
end
|
214
|
+
|
215
|
+
m
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
|
177
220
|
<a name="more"></a>
|
178
221
|
|
179
222
|
## More information
|
data/lib/opal-ferro/version.rb
CHANGED
@@ -26,6 +26,8 @@ module Ferro
|
|
26
26
|
# elements. Leave option blank to create <ul> elements.
|
27
27
|
class List < BaseElement
|
28
28
|
|
29
|
+
attr_reader :items
|
30
|
+
|
29
31
|
# Internal method.
|
30
32
|
def _before_create
|
31
33
|
@domtype = @options.has_key?(:type) ? :ol : :ul
|
@@ -98,11 +100,22 @@ module Ferro
|
|
98
100
|
def _before_create
|
99
101
|
@domtype = :a
|
100
102
|
@href = @options[:href]
|
103
|
+
@push = @href.to_s != ''
|
101
104
|
end
|
102
105
|
|
103
106
|
# Internal method.
|
104
107
|
def _after_create
|
105
|
-
`#{@element}.addEventListener("click",function(e){
|
108
|
+
`#{@element}.addEventListener("click", function(e) {
|
109
|
+
e.preventDefault();
|
110
|
+
|
111
|
+
if (#{@push}) {
|
112
|
+
history.pushState(null, null, #{@href});
|
113
|
+
}
|
114
|
+
|
115
|
+
#{clicked};
|
116
|
+
|
117
|
+
document.activeElement.blur();
|
118
|
+
})`
|
106
119
|
end
|
107
120
|
|
108
121
|
# Set a new html reference for this item.
|
@@ -86,7 +86,11 @@ module Ferro
|
|
86
86
|
# @param [String] state The state name to add to the element
|
87
87
|
# @param [value] value The initial enabled/disabled state value
|
88
88
|
def add_state(state, value = false)
|
89
|
-
@states[state] = [
|
89
|
+
@states[state] = [
|
90
|
+
factory.composite_state(self.class.name, state),
|
91
|
+
value
|
92
|
+
]
|
93
|
+
|
90
94
|
classify_state @states[state]
|
91
95
|
end
|
92
96
|
|
@@ -121,9 +125,13 @@ module Ferro
|
|
121
125
|
# @param [String] state The state name
|
122
126
|
def classify_state(state)
|
123
127
|
if state[1]
|
124
|
-
|
128
|
+
state[0].each do |name|
|
129
|
+
`#{element}.classList.add(#{name})`
|
130
|
+
end
|
125
131
|
else
|
126
|
-
|
132
|
+
state[0].each do |name|
|
133
|
+
`#{element}.classList.remove(#{name})`
|
134
|
+
end
|
127
135
|
end
|
128
136
|
end
|
129
137
|
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Ferro
|
2
|
+
# Composite styling for DOM objects.
|
3
|
+
class Compositor
|
4
|
+
|
5
|
+
attr_reader :current_theme
|
6
|
+
|
7
|
+
# Create the style compositor.
|
8
|
+
#
|
9
|
+
# @param [Symbol] theme Optional styling theme
|
10
|
+
def initialize(theme = nil)
|
11
|
+
@current_theme = theme
|
12
|
+
end
|
13
|
+
|
14
|
+
# Override this method to define a hash containing the mapping
|
15
|
+
# of Ruby classnames to an array of css classnames.
|
16
|
+
# To use the same styling on multiple objects: return the name
|
17
|
+
# of the object containing the styling as a String
|
18
|
+
# (see css_classes_for method).
|
19
|
+
#
|
20
|
+
# This hash may also contain the mapping for states.
|
21
|
+
# A state name is: <Ruby class name>::<state>.
|
22
|
+
# For instance 'MenuLink::active'.
|
23
|
+
def map
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
# Map a Ruby classname to an array of css classnames.
|
28
|
+
# If the mapping result is a string: recursively lookup
|
29
|
+
# the mapping for that string.
|
30
|
+
#
|
31
|
+
# @param [String] classname Ruby classname
|
32
|
+
# @return [Array] A list of CSS class names
|
33
|
+
def css_classes_for(classname)
|
34
|
+
css_classes_for_map classname, mapping
|
35
|
+
end
|
36
|
+
|
37
|
+
# Internal method to get mapping from selected map.
|
38
|
+
def css_classes_for_map(classname, map)
|
39
|
+
css = map[classname]
|
40
|
+
css.class == String ? css_classes_for_map(css, map) : (css || [])
|
41
|
+
end
|
42
|
+
|
43
|
+
# Internal method to switch to a new theme.
|
44
|
+
def switch_theme(root_element, theme)
|
45
|
+
old_map = @mapping
|
46
|
+
new_map = map(theme)
|
47
|
+
|
48
|
+
root_element.each_child do |e|
|
49
|
+
old_classes = css_classes_for_map e.class.name, old_map
|
50
|
+
new_classes = css_classes_for_map e.class.name, new_map
|
51
|
+
update_element_css_classes(e, old_classes, new_classes)
|
52
|
+
|
53
|
+
old_classes = css_classes_for_map e.class.superclass.name, old_map
|
54
|
+
new_classes = css_classes_for_map e.class.superclass.name, new_map
|
55
|
+
update_element_css_classes(e, old_classes, new_classes)
|
56
|
+
end
|
57
|
+
|
58
|
+
@mapping = new_map
|
59
|
+
end
|
60
|
+
|
61
|
+
# Internal method to add/remove CSS classes for an object.
|
62
|
+
def update_element_css_classes(obj, old_classes, new_classes)
|
63
|
+
(old_classes - new_classes).each do |name|
|
64
|
+
`#{obj.element}.classList.remove(#{name})`
|
65
|
+
end
|
66
|
+
|
67
|
+
(new_classes - old_classes).each do |name|
|
68
|
+
`#{obj.element}.classList.add(#{name})`
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Internal method to cache the mapping.
|
73
|
+
def mapping
|
74
|
+
@mapping ||= map(@current_theme)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -12,10 +12,14 @@ module Ferro
|
|
12
12
|
|
13
13
|
include Elementary
|
14
14
|
|
15
|
+
attr_reader :sym, :children, :compositor
|
16
|
+
|
15
17
|
# Create the document and start the creation
|
16
18
|
# process (casading).
|
17
19
|
def initialize
|
18
|
-
@
|
20
|
+
@compositor = nil
|
21
|
+
@sym = :document
|
22
|
+
@children = {}
|
19
23
|
creation
|
20
24
|
end
|
21
25
|
|
@@ -31,7 +35,7 @@ module Ferro
|
|
31
35
|
|
32
36
|
# Returns the one and only instance of the factory.
|
33
37
|
def factory
|
34
|
-
@factory ||= Factory.new
|
38
|
+
@factory ||= Factory.new(self, @compositor)
|
35
39
|
end
|
36
40
|
|
37
41
|
# The document class is the root element.
|
@@ -44,6 +48,20 @@ module Ferro
|
|
44
48
|
self
|
45
49
|
end
|
46
50
|
|
51
|
+
# Returns the domtype of the document instance.
|
52
|
+
def domtype
|
53
|
+
:body
|
54
|
+
end
|
55
|
+
|
56
|
+
# Switch to a new theme for the compositor,
|
57
|
+
# this will remove/add CSS classes for all
|
58
|
+
# elements as needed.
|
59
|
+
#
|
60
|
+
# param [Symbol] theme The new theme name
|
61
|
+
def switch_compositor_theme(theme)
|
62
|
+
@compositor.switch_theme(self, theme) if @compositor
|
63
|
+
end
|
64
|
+
|
47
65
|
# Returns the one and only instance of the router.
|
48
66
|
def router
|
49
67
|
@router ||= Router.new(method(:page404))
|
@@ -97,6 +97,20 @@ module Ferro
|
|
97
97
|
@children.delete(sym)
|
98
98
|
end
|
99
99
|
|
100
|
+
# Recursively iterate all child elements
|
101
|
+
#
|
102
|
+
# param [Block] block A block to execute for every child element
|
103
|
+
# and the element itself
|
104
|
+
def each_child(&block)
|
105
|
+
if block_given?
|
106
|
+
block.call self
|
107
|
+
|
108
|
+
@children.each do |_, child|
|
109
|
+
child.each_child(&block)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
100
114
|
# Remove a DOM element.
|
101
115
|
def destroy
|
102
116
|
`#{parent.element}.removeChild(#{element})`
|
@@ -6,14 +6,19 @@ module Ferro
|
|
6
6
|
|
7
7
|
# Creates the factory. Do not create a factory directly, instead
|
8
8
|
# call the 'factory' method that is available in all Ferro classes
|
9
|
-
|
9
|
+
#
|
10
|
+
# @param [Object] target The Ruby class instance
|
11
|
+
# @param [Compositor] compositor A style-compositor object or nil
|
12
|
+
def initialize(target, compositor)
|
13
|
+
@compositor = compositor
|
10
14
|
@body = `document.body`
|
11
15
|
`while (document.body.firstChild) {document.body.removeChild(document.body.firstChild);}`
|
16
|
+
composite_classes(target, @body, false)
|
12
17
|
end
|
13
18
|
|
14
19
|
# Create a DOM element.
|
15
20
|
#
|
16
|
-
# @param [
|
21
|
+
# @param [Object] target The Ruby class instance
|
17
22
|
# @param [String] type Type op DOM element to create
|
18
23
|
# @param [String] parent The Ruby parent element
|
19
24
|
# @param [Hash] options Options to pass to the element.
|
@@ -38,6 +43,9 @@ module Ferro
|
|
38
43
|
`#{element}.classList.add(#{dasherize(target.class.superclass.name)})`
|
39
44
|
end
|
40
45
|
|
46
|
+
# Add classes defined by compositor
|
47
|
+
composite_classes(target, element, target.class.superclass != BaseElement)
|
48
|
+
|
41
49
|
# Set ruby object_id as default element id
|
42
50
|
if !options.has_key?(:id)
|
43
51
|
`#{element}.id = #{target.object_id}`
|
@@ -79,5 +87,38 @@ module Ferro
|
|
79
87
|
return class_name if class_name !~ /-/
|
80
88
|
class_name.gsub(/(?:-|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.strip
|
81
89
|
end
|
90
|
+
|
91
|
+
# Convert a state-name to a list of CSS class names.
|
92
|
+
#
|
93
|
+
# @param [String] class_name Ruby class name
|
94
|
+
# @param [String] state State name
|
95
|
+
# @return [String] A list of CSS class names
|
96
|
+
def composite_state(class_name, state)
|
97
|
+
if @compositor
|
98
|
+
list = @compositor.css_classes_for("#{class_name}::#{state}")
|
99
|
+
return list if !list.empty?
|
100
|
+
end
|
101
|
+
|
102
|
+
[ dasherize(state) ]
|
103
|
+
end
|
104
|
+
|
105
|
+
# Internal method
|
106
|
+
# Composite CSS classes from Ruby class name
|
107
|
+
def composite_classes(target, element, add_superclass)
|
108
|
+
if @compositor
|
109
|
+
composite_for(target.class.name, element)
|
110
|
+
|
111
|
+
if add_superclass
|
112
|
+
composite_for(target.class.superclass.name, element)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Internal method
|
118
|
+
def composite_for(classname, element)
|
119
|
+
@compositor.css_classes_for(classname).each do |name|
|
120
|
+
`#{element}.classList.add(#{name})`
|
121
|
+
end
|
122
|
+
end
|
82
123
|
end
|
83
124
|
end
|
data/opal/opal-ferro.rb
CHANGED
data/opal-ferro.gemspec
CHANGED
@@ -12,6 +12,12 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.summary = %q{Simplifying web-development: no more html, just beautiful and simple Ruby code.}
|
13
13
|
s.description = %q{Ferro is a small Ruby library on top of Opal that enables an object-oriented programming style for creating code that runs in the webbrowser. No more distractions like HTML and searching for DOM elements, just beautiful and simple Ruby code. Front-End-Ruby-ROcks!}
|
14
14
|
s.homepage = 'https://github.com/easydatawarehousing/opal-ferro'
|
15
|
+
s.metadata = {
|
16
|
+
"homepage_uri" => "https://github.com/easydatawarehousing/opal-ferro/",
|
17
|
+
"changelog_uri" => "https://github.com/easydatawarehousing/opal-ferro/blob/master/CHANGELOG.md",
|
18
|
+
"source_code_uri" => "https://github.com/easydatawarehousing/opal-ferro/",
|
19
|
+
"bug_tracker_uri" => "https://github.com/easydatawarehousing/opal-ferro/issues",
|
20
|
+
}
|
15
21
|
s.license = 'MIT'
|
16
22
|
|
17
23
|
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opal-ferro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivo Herweijer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: opal
|
@@ -110,6 +110,7 @@ files:
|
|
110
110
|
- opal/opal-ferro/elements/ferro_inline.js.rb
|
111
111
|
- opal/opal-ferro/elements/ferro_misc.js.rb
|
112
112
|
- opal/opal-ferro/ferro_base_element.js.rb
|
113
|
+
- opal/opal-ferro/ferro_compositor.js.rb
|
113
114
|
- opal/opal-ferro/ferro_document.js.rb
|
114
115
|
- opal/opal-ferro/ferro_elementary.js.rb
|
115
116
|
- opal/opal-ferro/ferro_factory.js.rb
|
@@ -119,7 +120,11 @@ files:
|
|
119
120
|
homepage: https://github.com/easydatawarehousing/opal-ferro
|
120
121
|
licenses:
|
121
122
|
- MIT
|
122
|
-
metadata:
|
123
|
+
metadata:
|
124
|
+
homepage_uri: https://github.com/easydatawarehousing/opal-ferro/
|
125
|
+
changelog_uri: https://github.com/easydatawarehousing/opal-ferro/blob/master/CHANGELOG.md
|
126
|
+
source_code_uri: https://github.com/easydatawarehousing/opal-ferro/
|
127
|
+
bug_tracker_uri: https://github.com/easydatawarehousing/opal-ferro/issues
|
123
128
|
post_install_message:
|
124
129
|
rdoc_options: []
|
125
130
|
require_paths:
|