Skip to content

Commit 75cfcdf

Browse files
author
Nils Henning
committed
[WIP][FEATURE] cable component
1 parent 231a4a0 commit 75cfcdf

File tree

25 files changed

+595
-180
lines changed

25 files changed

+595
-180
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
matestack-ui-core (1.0.0)
4+
matestack-ui-core (1.0.1)
55
cells-haml
66
cells-rails
77
haml

app/concepts/matestack/ui/core/async/async.js

Lines changed: 7 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ const componentDef = {
99
data: function(){
1010
return {
1111
asyncTemplate: null,
12-
asyncTemplateDOMelement: null,
1312
showing: true,
1413
loading: false,
1514
hideAfterTimeout: null,
@@ -48,29 +47,6 @@ const componentDef = {
4847
self.rerender()
4948
}, parseInt(this.componentConfig["defer"]));
5049
},
51-
update: function(payload){
52-
let position = "beforeend"
53-
54-
if(this.componentConfig["position"] === "begin"){
55-
position = "afterbegin"
56-
}
57-
if(this.componentConfig["position"] === "end"){
58-
position = "beforeend"
59-
}
60-
61-
if(payload.new_element != undefined){
62-
this.asyncTemplateDOMelement.insertAdjacentHTML(
63-
position,
64-
payload.new_element
65-
)
66-
}
67-
68-
if(payload.remove_element_by_id != undefined){
69-
this.asyncTemplateDOMelement.querySelector('#' + payload.remove_element_by_id).remove()
70-
}
71-
72-
this.asyncTemplate = this.asyncTemplateDOMelement.outerHTML
73-
},
7450
rerender: function(){
7551
var self = this;
7652
self.loading = true;
@@ -93,33 +69,16 @@ const componentDef = {
9369
self.asyncTemplate = template;
9470
})
9571
.catch(function(error){
72+
console.log(error)
9673
matestackEventHub.$emit('async_rerender_error', { id: self.componentConfig["component_key"] })
9774
})
9875
}
9976
},
10077
created: function () {
101-
102-
this.asyncTemplateDOMelement = document.querySelector("#" + this.componentConfig["id"])
103-
this.asyncTemplate = this.asyncTemplateDOMelement.outerHTML;
104-
10578
const self = this
106-
if(this.componentConfig["show_on"] != undefined){
107-
this.showing = false
108-
var show_events = this.componentConfig["show_on"].split(",")
109-
show_events.forEach(show_event => matestackEventHub.$on(show_event.trim(), self.show));
110-
}
111-
if(this.componentConfig["hide_on"] != undefined){
112-
var hide_events = this.componentConfig["hide_on"].split(",")
113-
hide_events.forEach(hide_event => matestackEventHub.$on(hide_event.trim(), self.hide));
114-
}
115-
if(this.componentConfig["rerender_on"] != undefined){
116-
var rerender_events = this.componentConfig["rerender_on"].split(",")
117-
rerender_events.forEach(rerender_event => matestackEventHub.$on(rerender_event.trim(), self.rerender));
118-
}
119-
if(this.componentConfig["update_on"] != undefined){
120-
var update_events = this.componentConfig["update_on"].split(",")
121-
update_events.forEach(update_event => matestackEventHub.$on(update_event.trim(), self.update));
122-
}
79+
self.registerEvents(this.componentConfig['show_on'], self.show)
80+
self.registerEvents(this.componentConfig['hide_on'], self.hide)
81+
self.registerEvents(this.componentConfig['rerender_on'], self.rerender)
12382
if(this.componentConfig["show_on"] != undefined){
12483
this.showing = false
12584
}
@@ -137,21 +96,9 @@ const componentDef = {
13796
beforeDestroy: function() {
13897
const self = this
13998
clearTimeout(self.hideAfterTimeout)
140-
matestackEventHub.$off(this.componentConfig["rerender_on"], self.rerender);
141-
matestackEventHub.$off(this.componentConfig["show_on"], self.show);
142-
matestackEventHub.$off(this.componentConfig["hide_on"], self.hide);
143-
if(this.componentConfig["show_on"] != undefined){
144-
var shown_events = this.componentConfig["show_on"].split(",")
145-
shown_events.forEach(show_event => matestackEventHub.$off(show_event.trim(), self.show));
146-
}
147-
if(this.componentConfig["hide_on"] != undefined){
148-
var hiden_events = this.componentConfig["hide_on"].split(",")
149-
hiden_events.forEach(hide_event => matestackEventHub.$off(hide_event.trim(), self.hide));
150-
}
151-
if(this.componentConfig["rerender_on"] != undefined){
152-
var rerender_events = this.componentConfig["rerender_on"].split(",")
153-
rerender_events.forEach(rerender_event => matestackEventHub.$off(rerender_event.trim(), self.rerender));
154-
}
99+
self.removeEvents(this.componentConfig["show_on"], self.show)
100+
self.removeEvents(this.componentConfig["hide_on"], self.hide)
101+
self.removeEvents(this.componentConfig["rerender_on"], self.rerender)
155102
},
156103
components: {
157104
VRuntimeTemplate: VRuntimeTemplate

app/concepts/matestack/ui/core/async/async.rb

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
11
module Matestack::Ui::Core::Async
2-
class Async < Matestack::Ui::Core::Component::Rerender
2+
class Async < Matestack::Ui::Core::Component::Dynamic
33
vue_js_component_name "matestack-ui-core-async"
44

5-
requires :id # will be required in 1.0.0
5+
requires :id # required since 1.1.0
66

77
def initialize(*args)
88
super
9-
ActiveSupport::Deprecation.warn(
10-
'Calling async components without id is deprecated. Instead provide a unique id for async components.'
11-
) if id.blank?
12-
@component_config[:component_key] = id || "async_#{Digest::SHA256.hexdigest(caller[3])}"
13-
if @included_config.present? && @included_config[:isolated_parent_class].present?
14-
@component_config[:parent_class] = @included_config[:isolated_parent_class]
9+
component_config[:component_key] = id
10+
if included_config.present? && included_config[:isolated_parent_class].present?
11+
component_config[:parent_class] = included_config[:isolated_parent_class]
1512
end
1613
end
1714

1815
def children_wrapper_attributes
1916
html_attributes.merge({
2017
"v-if": "showing",
21-
id: @component_config[:component_key]
18+
id: component_config[:component_key]
2219
})
2320
end
2421

@@ -33,7 +30,7 @@ def render_content
3330
end
3431

3532
def get_component_key
36-
@component_config[:component_key]
33+
component_config[:component_key]
3734
end
3835

3936
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
%component{dynamic_tag_attributes}
2+
%div{class: "matestack-cable-component-container", "v-bind:class": "{ 'loading': loading === true }"}
3+
%div{class: "matestack-cable-component-wrapper", "v-if": "cableTemplate == null", "v-bind:class": "{ 'loading': loading === true }"}
4+
= render_content
5+
%div{class: "matestack-cable-component-wrapper", "v-if": "cableTemplate != null", "v-bind:class": "{ 'loading': loading === true }"}
6+
%v-runtime-template{":template":"cableTemplate"}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import Vue from 'vue/dist/vue.esm'
2+
import VRuntimeTemplate from "v-runtime-template"
3+
import matestackEventHub from '../js/event-hub'
4+
import componentMixin from '../component/component'
5+
6+
const componentDef = {
7+
mixins: [componentMixin],
8+
data: function(){
9+
return {
10+
cableTemplate: null,
11+
cableTemplateDomElement: null,
12+
loading: false,
13+
event: {
14+
data: {}
15+
}
16+
}
17+
},
18+
methods: {
19+
append: function(payload){
20+
var html = this.formatPayload(payload)
21+
this.cableTemplateDomElement.insertAdjacentHTML(
22+
'beforeend',
23+
html.join('')
24+
)
25+
this.updateCableTemplate()
26+
},
27+
prepend: function(payload){
28+
var html = this.formatPayload(payload)
29+
this.cableTemplateDomElement.insertAdjacentHTML(
30+
'afterbegin',
31+
html.join('')
32+
)
33+
this.updateCableTemplate()
34+
},
35+
delete: function(payload){
36+
var ids = this.formatPayload(payload)
37+
ids.forEach(id =>
38+
this.cableTemplateDomElement.querySelector('#' + id).remove()
39+
)
40+
this.updateCableTemplate()
41+
},
42+
update: function(payload){
43+
const self = this
44+
var html = this.formatPayload(payload)
45+
html.forEach(function(elem){
46+
var dom_elem = document.createElement('div')
47+
dom_elem.innerHTML = elem
48+
var id = dom_elem.firstChild.id
49+
var old_elem = self.cableTemplateDomElement.querySelector('#' + id)
50+
old_elem.parentNode.replaceChild(dom_elem.firstChild, old_elem)
51+
})
52+
this.updateCableTemplate()
53+
},
54+
replace: function(payload){
55+
var html = this.formatPayload(payload)
56+
this.cableTemplateDomElement.innerHTML = html.join('')
57+
this.updateCableTemplate()
58+
},
59+
updateCableTemplate: function(){
60+
this.cableTemplate = this.cableTemplateDomElement.outerHTML
61+
},
62+
formatPayload: function(payload){
63+
if(!Array.isArray(payload.data)){
64+
return [payload.data]
65+
}
66+
return payload.data
67+
},
68+
},
69+
created: function () {
70+
this.cableTemplateDomElement = document.querySelector("#" + this.componentConfig["id"])
71+
this.cableTemplate = this.cableTemplateDomElement.outerHTML
72+
const self = this
73+
var events = this.componentConfig['append_on']
74+
this.registerEvents(this.componentConfig['append_on'], self.append)
75+
this.registerEvents(this.componentConfig['prepend_on'], self.prepend)
76+
this.registerEvents(this.componentConfig['delete_on'], self.delete)
77+
this.registerEvents(this.componentConfig['update_on'], self.update)
78+
this.registerEvents(this.componentConfig['replace_on'], self.replace)
79+
},
80+
beforeDestroy: function() {
81+
const self = this
82+
this.removeEvents(this.componentConfig['append_on'], self.append)
83+
this.removeEvents(this.componentConfig['prepend_on'], self.prepend)
84+
this.removeEvents(this.componentConfig['delete_on'], self.delete)
85+
this.removeEvents(this.componentConfig['update_on'], self.update)
86+
this.removeEvents(this.componentConfig['replace_on'], self.replace)
87+
},
88+
components: {
89+
VRuntimeTemplate: VRuntimeTemplate
90+
}
91+
}
92+
93+
let component = Vue.component('matestack-ui-core-cable', componentDef)
94+
95+
export default componentDef
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module Matestack::Ui::Core::Cable
2+
class Cable < Matestack::Ui::Core::Component::Dynamic
3+
vue_js_component_name 'matestack-ui-core-cable'
4+
5+
requires :id
6+
7+
def response
8+
component_config[:component_key] = id
9+
end
10+
11+
def show
12+
render :cable
13+
end
14+
15+
def render_content
16+
render :children_wrapper do
17+
render :children
18+
end
19+
end
20+
21+
def children_wrapper_attributes
22+
html_attributes.merge({
23+
id: component_config[:component_key]
24+
})
25+
end
26+
27+
end
28+
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
%div{ children_wrapper_attributes.merge(class: "matestack-cable-component-root") }
2+
=yield

app/concepts/matestack/ui/core/component/base.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ def set_included_config config
9898
def get_included_config
9999
@included_config
100100
end
101+
alias :included_config :get_included_config
102+
103+
def component_config
104+
@component_config
105+
end
101106

102107
# TODO: modifies/recreates view lookup paths on every invocation?!
103108
# At least memoize it I guess...
Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
1+
import matestackEventHub from '../js/event-hub'
2+
13
const componentMixin = {
2-
props: ['componentConfig', 'params']
4+
props: ['componentConfig', 'params'],
5+
methods: {
6+
registerEvents: function(events, callback){
7+
if(events != undefined){
8+
var event_names = events.split(",")
9+
event_names.forEach(event_name => matestackEventHub.$on(event_name.trim(), callback));
10+
}
11+
},
12+
removeEvents: function(events, callback){
13+
if(events != undefined){
14+
var event_names = events.split(",")
15+
event_names.forEach(event_name => matestackEventHub.$off(event_name.trim(), callback));
16+
}
17+
}
18+
}
19+
320
}
421

522
export default componentMixin

app/concepts/matestack/ui/core/component/dynamic.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def dynamic_tag_attributes
1616
"is": get_vue_js_name,
1717
"ref": component_id,
1818
":params": params.except(:controller, :action).to_json,
19-
":component-config": @component_config.to_json,
19+
":component-config": component_config.to_json,
2020
"inline-template": true,
2121
}
2222
attrs.merge!(options[:attributes]) unless options[:attributes].nil?

0 commit comments

Comments
 (0)