fie 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -6
- data/lib/fie/version.rb +1 -1
- data/lib/javascript/fie.js +49 -0
- data/lib/javascript/fie/action_cable/channel.js +25 -0
- data/lib/javascript/fie/cable.js +72 -0
- data/lib/javascript/fie/commander.js +46 -0
- data/lib/javascript/fie/listeners.js +117 -0
- data/lib/javascript/fie/pool.js +7 -0
- data/lib/javascript/fie/timer.js +15 -0
- data/lib/javascript/fie/util.js +25 -0
- data/vendor/javascript/fie.js +1 -10
- metadata +10 -15
- data/lib/opal/fie.rb +0 -24
- data/lib/opal/fie/cable.rb +0 -63
- data/lib/opal/fie/commander.rb +0 -50
- data/lib/opal/fie/diff_setup.rb +0 -31
- data/lib/opal/fie/expose_methods.rb +0 -27
- data/lib/opal/fie/listeners.rb +0 -129
- data/lib/opal/fie/native.rb +0 -5
- data/lib/opal/fie/native/action_cable_channel.rb +0 -35
- data/lib/opal/fie/native/element.rb +0 -116
- data/lib/opal/fie/native/event.rb +0 -17
- data/lib/opal/fie/native/timeout.rb +0 -24
- data/lib/opal/fie/pool.rb +0 -9
- data/lib/opal/fie/util.rb +0 -23
data/lib/opal/fie.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'opal/base'
|
2
|
-
require 'opal/mini'
|
3
|
-
|
4
|
-
require 'corelib/io'
|
5
|
-
require 'corelib/dir'
|
6
|
-
require 'corelib/file'
|
7
|
-
|
8
|
-
require 'corelib/unsupported'
|
9
|
-
|
10
|
-
module Fie
|
11
|
-
require_tree './fie'
|
12
|
-
|
13
|
-
include Fie::Native
|
14
|
-
|
15
|
-
DiffSetup.run
|
16
|
-
|
17
|
-
Element.document.add_event_listener('DOMContentLoaded') do
|
18
|
-
cable = Cable.new
|
19
|
-
|
20
|
-
ExposeMethods.run
|
21
|
-
|
22
|
-
Listeners.new(cable)
|
23
|
-
end
|
24
|
-
end
|
data/lib/opal/fie/cable.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'securerandom'
|
2
|
-
require 'fie/native'
|
3
|
-
require 'json'
|
4
|
-
|
5
|
-
module Fie
|
6
|
-
class Cable
|
7
|
-
include Fie::Native
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
connection_uuid = SecureRandom.uuid
|
11
|
-
commander_name = "#{ camelize(controller_name) }Commander"
|
12
|
-
|
13
|
-
@commander = Commander.new(channel_name: commander_name, identifier: connection_uuid, cable: self)
|
14
|
-
@pools = {}
|
15
|
-
end
|
16
|
-
|
17
|
-
def call_remote_function(element:, event_name:, function_name:, parameters:)
|
18
|
-
log_event(element: element, event_name: event_name, function_name: function_name, parameters: parameters)
|
19
|
-
|
20
|
-
function_parameters = {
|
21
|
-
caller: {
|
22
|
-
id: element.id,
|
23
|
-
class: element.class_name,
|
24
|
-
value: element.value
|
25
|
-
},
|
26
|
-
controller_name: controller_name,
|
27
|
-
action_name: action_name
|
28
|
-
}.merge(parameters)
|
29
|
-
|
30
|
-
@commander.perform(function_name, function_parameters)
|
31
|
-
end
|
32
|
-
|
33
|
-
def subscribe_to_pool(subject)
|
34
|
-
@pools[subject] = Pool.new(channel_name: 'Fie::Pools', identifier: subject, cable: self)
|
35
|
-
end
|
36
|
-
|
37
|
-
def commander
|
38
|
-
@commander
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
def log_event(element:, event_name:, function_name:, parameters:)
|
43
|
-
parameters = parameters.to_json
|
44
|
-
puts "Event #{ event_name } triggered by element #{ element.descriptor } is calling function #{ function_name } with parameters #{ parameters }"
|
45
|
-
end
|
46
|
-
|
47
|
-
def action_name
|
48
|
-
view_name_element['fie-action']
|
49
|
-
end
|
50
|
-
|
51
|
-
def controller_name
|
52
|
-
view_name_element['fie-controller']
|
53
|
-
end
|
54
|
-
|
55
|
-
def view_name_element
|
56
|
-
Element.body.query_selector('[fie-controller]:not([fie-controller=""])');
|
57
|
-
end
|
58
|
-
|
59
|
-
def camelize(string)
|
60
|
-
string.split('_').collect(&:capitalize).join
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
data/lib/opal/fie/commander.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'fie/native'
|
2
|
-
require 'diffhtml/dist/diffhtml.min'
|
3
|
-
|
4
|
-
module Fie
|
5
|
-
class Commander < Fie::Native::ActionCableChannel
|
6
|
-
include Fie::Native
|
7
|
-
|
8
|
-
def connected
|
9
|
-
super
|
10
|
-
|
11
|
-
@cable.call_remote_function \
|
12
|
-
element: Element.body,
|
13
|
-
function_name: 'initialize_state',
|
14
|
-
event_name: 'Upload State',
|
15
|
-
parameters: { view_variables: Util.view_variables }
|
16
|
-
end
|
17
|
-
|
18
|
-
def received(data)
|
19
|
-
process_command(data['command'], data['parameters'])
|
20
|
-
end
|
21
|
-
|
22
|
-
def process_command(command, parameters = {})
|
23
|
-
case command
|
24
|
-
when 'refresh_view'
|
25
|
-
$$.diff.innerHTML Element.fie_body.unwrapped_element, parameters['html']
|
26
|
-
@event.dispatch
|
27
|
-
when 'subscribe_to_pools'
|
28
|
-
parameters['subjects'].each do |subject|
|
29
|
-
@cable.subscribe_to_pool(subject)
|
30
|
-
end
|
31
|
-
when 'publish_to_pool'
|
32
|
-
subject = parameters['subject']
|
33
|
-
object = parameters['object']
|
34
|
-
sender_uuid = parameters['sender_uuid']
|
35
|
-
|
36
|
-
perform("pool_#{ subject }_callback", { object: object, sender_uuid: sender_uuid })
|
37
|
-
when 'publish_to_pool_lazy'
|
38
|
-
subject = parameters['subject']
|
39
|
-
object = parameters['object']
|
40
|
-
sender_uuid = parameters['sender_uuid']
|
41
|
-
|
42
|
-
perform("pool_#{ subject }_callback", { object: object, sender_uuid: sender_uuid, lazy: true })
|
43
|
-
when 'execute_function'
|
44
|
-
Util.exec_js(parameters['name'], parameters['arguments'])
|
45
|
-
else
|
46
|
-
puts "Command: #{ command }, Parameters: #{ parameters }"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
data/lib/opal/fie/diff_setup.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'es6-object-assign/dist/object-assign.min'
|
2
|
-
|
3
|
-
class DiffSetup
|
4
|
-
class << self
|
5
|
-
include Fie::Native
|
6
|
-
|
7
|
-
def run
|
8
|
-
$$.ObjectAssign.polyfill()
|
9
|
-
|
10
|
-
Native \
|
11
|
-
`diff.use(
|
12
|
-
Object.assign(_ => {}, {
|
13
|
-
syncTreeHook: (oldTree, newTree) => {
|
14
|
-
if (newTree.nodeName === 'input') {
|
15
|
-
let oldElement = document.querySelector('[name="' + newTree.attributes.name + '"]');
|
16
|
-
|
17
|
-
if (oldElement != undefined && oldElement.attributes['fie-ignore'] != undefined) {
|
18
|
-
newTree.nodeValue = oldElement.value;
|
19
|
-
newTree.attributes.value = oldElement.value;
|
20
|
-
newTree.attributes.autofocus = '';
|
21
|
-
newTree.attributes['fie-ignore'] = oldElement.attributes['fie-ignore'];
|
22
|
-
}
|
23
|
-
|
24
|
-
return newTree;
|
25
|
-
}
|
26
|
-
}
|
27
|
-
})
|
28
|
-
)`
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
class ExposeMethods
|
2
|
-
class << self
|
3
|
-
def run
|
4
|
-
Native(`window.Fie = {}`)
|
5
|
-
|
6
|
-
Native \
|
7
|
-
`window.Fie.executeCommanderMethod =
|
8
|
-
#{
|
9
|
-
-> (function_name, parameters = {}) do
|
10
|
-
cable.call_remote_function \
|
11
|
-
element: Element.body,
|
12
|
-
event_name: 'calling remote function',
|
13
|
-
function_name: function_name,
|
14
|
-
parameters: Hash.new(parameters)
|
15
|
-
end
|
16
|
-
}`
|
17
|
-
|
18
|
-
Native \
|
19
|
-
`window.Fie.addEventListener =
|
20
|
-
#{
|
21
|
-
-> (event_name, selector, block) do
|
22
|
-
Element.fie_body.add_event_listener(event_name, selector, &block)
|
23
|
-
end
|
24
|
-
}`
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/opal/fie/listeners.rb
DELETED
@@ -1,129 +0,0 @@
|
|
1
|
-
require 'fie/native'
|
2
|
-
require 'securerandom'
|
3
|
-
|
4
|
-
module Fie
|
5
|
-
class Listeners
|
6
|
-
include Fie::Native
|
7
|
-
|
8
|
-
def initialize(cable)
|
9
|
-
@cable = cable
|
10
|
-
@timer = Timeout.new(0) { 'hello' }
|
11
|
-
|
12
|
-
initialize_input_elements
|
13
|
-
initialize_fie_events [:click, :submit, :scroll, :keyup, :keydown, :enter]
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
def initialize_fie_events(event_names)
|
18
|
-
event_names.each do |fie_event_name|
|
19
|
-
selector = "[fie-#{ fie_event_name }]:not([fie-#{ fie_event_name }=''])"
|
20
|
-
|
21
|
-
event_name = fie_event_name
|
22
|
-
event_name = :keydown if event_name == :enter
|
23
|
-
|
24
|
-
Element.fie_body.add_event_listener(event_name, selector) do |event|
|
25
|
-
handle_fie_event(fie_event_name, event_name, event)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def handle_fie_event(fie_event_name, event_name, event)
|
31
|
-
event_is_valid = (fie_event_name == :enter && event.keyCode == 13) || fie_event_name != :enter
|
32
|
-
|
33
|
-
if event_is_valid
|
34
|
-
element = Element.new(element: event.target)
|
35
|
-
remote_function_name = element["fie-#{ fie_event_name }"]
|
36
|
-
function_parameters = JSON.parse(element['fie-parameters'] || {})
|
37
|
-
|
38
|
-
@timer.fast_forward
|
39
|
-
|
40
|
-
@cable.call_remote_function \
|
41
|
-
element: element,
|
42
|
-
function_name: remote_function_name,
|
43
|
-
event_name: event_name,
|
44
|
-
parameters: function_parameters
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def initialize_input_elements
|
49
|
-
typing_input_types = ['text', 'password', 'search', 'tel', 'url']
|
50
|
-
|
51
|
-
typing_input_selector = (['textarea'] + typing_input_types).reduce do |selector, input_type|
|
52
|
-
selector += ", input[type=#{ input_type }]"
|
53
|
-
end
|
54
|
-
|
55
|
-
non_typing_input_selector = (['input'] + typing_input_types).reduce do |selector, input_type|
|
56
|
-
selector += ":not([type=#{ input_type }])"
|
57
|
-
end
|
58
|
-
|
59
|
-
Element.fie_body.add_event_listener('keydown', typing_input_selector) do |event|
|
60
|
-
if event.keyCode == 13
|
61
|
-
event.target.blur
|
62
|
-
else
|
63
|
-
@timer.clear
|
64
|
-
|
65
|
-
input_element = Element.new(element: event.target)
|
66
|
-
|
67
|
-
@timer = Timeout.new(300) do
|
68
|
-
update_state_using_changelog(input_element)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
Element.fie_body.add_event_listener('focusin', typing_input_selector) do |event|
|
74
|
-
event.target.setAttribute('fie-ignore', SecureRandom.uuid)
|
75
|
-
end
|
76
|
-
|
77
|
-
Element.fie_body.add_event_listener('focusout', typing_input_selector) do |event|
|
78
|
-
event.target.removeAttribute('fie-ignore')
|
79
|
-
end
|
80
|
-
|
81
|
-
Element.fie_body.add_event_listener('change', non_typing_input_selector) do |event|
|
82
|
-
input_element = Element.new(element: event.target)
|
83
|
-
update_state_using_changelog(input_element)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def update_state_using_changelog(input_element)
|
88
|
-
objects_changelog = {}
|
89
|
-
|
90
|
-
changed_object_name = input_element.name.split('[')[0]
|
91
|
-
changed_object_key_chain = input_element.name.scan(Regexp.new '\[(.*?)\]').flatten
|
92
|
-
|
93
|
-
is_form_object = !changed_object_key_chain.empty? && !changed_object_name.nil?
|
94
|
-
is_fie_nested_object = Util.view_variables.include? changed_object_name
|
95
|
-
is_fie_form_object = is_form_object && is_fie_nested_object
|
96
|
-
|
97
|
-
is_fie_non_nested_object = Util.view_variables.include? input_element.name
|
98
|
-
|
99
|
-
if is_fie_form_object
|
100
|
-
build_changelog(changed_object_key_chain, changed_object_name, objects_changelog, input_element)
|
101
|
-
elsif is_fie_non_nested_object
|
102
|
-
objects_changelog[input_element.name] = input_element.value;
|
103
|
-
end
|
104
|
-
|
105
|
-
@cable.call_remote_function \
|
106
|
-
element: input_element,
|
107
|
-
function_name: 'modify_state_using_changelog',
|
108
|
-
event_name: 'Input Element Change',
|
109
|
-
parameters: { objects_changelog: objects_changelog }
|
110
|
-
end
|
111
|
-
|
112
|
-
def build_changelog(object_key_chain, object_name, changelog, input_element)
|
113
|
-
is_final_key = -> (key) { key == object_key_chain[-1] }
|
114
|
-
object_final_key_value = input_element.value
|
115
|
-
|
116
|
-
changelog[object_name] = {}
|
117
|
-
changelog = changelog[object_name]
|
118
|
-
|
119
|
-
object_key_chain.each do |key|
|
120
|
-
if is_final_key.call(key)
|
121
|
-
changelog[key] = object_final_key_value
|
122
|
-
else
|
123
|
-
changelog[key] = {}
|
124
|
-
changelog = changelog[key]
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
data/lib/opal/fie/native.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'fie/native'
|
2
|
-
|
3
|
-
module Fie
|
4
|
-
module Native
|
5
|
-
class ActionCableChannel
|
6
|
-
def initialize(channel_name:, identifier:, cable:)
|
7
|
-
@channel_name = channel_name
|
8
|
-
@identifier = identifier
|
9
|
-
@cable = cable
|
10
|
-
@event = Event.new('fieChanged')
|
11
|
-
|
12
|
-
@subscription = $$.App.cable.subscriptions.create(
|
13
|
-
{ channel: @channel_name, identifier: @identifier },
|
14
|
-
{
|
15
|
-
connected: -> { connected },
|
16
|
-
received: -> (data) { received Native(`#{data}`) }
|
17
|
-
}
|
18
|
-
)
|
19
|
-
end
|
20
|
-
|
21
|
-
def responds_to?(t)
|
22
|
-
true
|
23
|
-
end
|
24
|
-
|
25
|
-
def connected
|
26
|
-
perform('initialize_pools')
|
27
|
-
puts "Connected to #{ @channel_name } with identifier #{ @identifier }"
|
28
|
-
end
|
29
|
-
|
30
|
-
def perform(function_name, parameters = {})
|
31
|
-
@subscription.perform(function_name, parameters);
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,116 +0,0 @@
|
|
1
|
-
require 'native'
|
2
|
-
|
3
|
-
module Fie
|
4
|
-
module Native
|
5
|
-
class Element
|
6
|
-
include Native
|
7
|
-
|
8
|
-
def initialize(element: nil, selector: nil)
|
9
|
-
if selector.nil?
|
10
|
-
@element = element
|
11
|
-
elsif element.nil?
|
12
|
-
if selector == 'document'
|
13
|
-
@element = $$.document
|
14
|
-
else
|
15
|
-
@element = $$.document.querySelector(selector)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def [](name)
|
21
|
-
@element.getAttribute(name)
|
22
|
-
end
|
23
|
-
|
24
|
-
def []=(name, value)
|
25
|
-
@element.setAttribute(name, value)
|
26
|
-
end
|
27
|
-
|
28
|
-
def add_event_listener(event_name, selector = nil, &block)
|
29
|
-
@element.addEventListener(event_name) do |event|
|
30
|
-
event = Native(`#{ event }`)
|
31
|
-
|
32
|
-
if selector.nil?
|
33
|
-
yield event
|
34
|
-
else
|
35
|
-
if event.target.matches(selector)
|
36
|
-
yield event
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def innerHTML
|
43
|
-
@element.innerHTML
|
44
|
-
end
|
45
|
-
|
46
|
-
def query_selector(selector)
|
47
|
-
Element.new(element: @element.querySelector(selector))
|
48
|
-
end
|
49
|
-
|
50
|
-
def query_selector_all(selector)
|
51
|
-
entries = Native(`Array.prototype.slice.call(document.querySelectorAll(#{ selector }))`)
|
52
|
-
|
53
|
-
entries.map do |element|
|
54
|
-
Element.new(element: element)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def name
|
59
|
-
@element.name
|
60
|
-
end
|
61
|
-
|
62
|
-
def id
|
63
|
-
@element.id
|
64
|
-
end
|
65
|
-
|
66
|
-
def class_name
|
67
|
-
@element.className
|
68
|
-
end
|
69
|
-
|
70
|
-
def descriptor
|
71
|
-
descriptor = @element.tagName
|
72
|
-
|
73
|
-
id_is_blank =
|
74
|
-
id.nil? || id == ''
|
75
|
-
|
76
|
-
class_name_is_blank =
|
77
|
-
class_name.nil? || class_name == ''
|
78
|
-
|
79
|
-
if !id_is_blank
|
80
|
-
descriptor + "##{ id }"
|
81
|
-
elsif !class_name_is_blank
|
82
|
-
descriptor + ".#{ class_name }"
|
83
|
-
else
|
84
|
-
descriptor
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def value
|
89
|
-
@element.value
|
90
|
-
end
|
91
|
-
|
92
|
-
def unwrapped_element
|
93
|
-
@element
|
94
|
-
end
|
95
|
-
|
96
|
-
private
|
97
|
-
def node_list_to_array(node_list)
|
98
|
-
$$.Array.prototype.slice.call(node_list)
|
99
|
-
end
|
100
|
-
|
101
|
-
class << self
|
102
|
-
def document
|
103
|
-
Element.new(selector: 'document')
|
104
|
-
end
|
105
|
-
|
106
|
-
def body
|
107
|
-
Element.new(selector: 'body')
|
108
|
-
end
|
109
|
-
|
110
|
-
def fie_body
|
111
|
-
Element.new(selector: '[fie-body=true]')
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|