hera_cms 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +87 -10
- data/app/assets/javascripts/hera_cms/application.js +310 -1
- data/app/models/hera_cms/application_record.rb +2 -0
- data/app/models/hera_cms/image.rb +0 -1
- data/app/models/hera_cms/link.rb +0 -1
- data/app/models/hera_cms/text.rb +0 -1
- data/app/views/hera_cms/dashboard/home.html.erb +4 -0
- data/app/views/hera_cms/shared/_navbar.html.erb +1 -3
- data/lib/generators/hera_cms/install_generator.rb +1 -1
- data/lib/generators/hera_cms/templates/install.rb.tt +0 -6
- data/lib/hera_cms.rb +4 -3
- data/lib/hera_cms/version.rb +1 -1
- metadata +2 -3
- data/app/views/hera_cms/shared/_hera_edit.js +0 -312
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5aa9efe0f53f57f3455978481d5b469a58b470f651db6c9b9de10167bdd6910e
|
4
|
+
data.tar.gz: b5ed7cb6d61b33f38d40448a12737ccc95aa577f240f2970872edd95de9814e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f1d9b6b41a4e272cb4df3e1a84aba88d10ec26f10458c42206f12af256c7db0451642e0767720d6eb1d5e0ffffc56bf77feef62b9a498526c41102ba568e1ed
|
7
|
+
data.tar.gz: '0798a46a9aa7ed5d8dd557e1cd37a82be450d17fbc852cacf89fa4071248a396672376581d3120f1ed12ea84f51c966490a1222f2318f8028c84772037a6687f'
|
data/README.md
CHANGED
@@ -1,13 +1,7 @@
|
|
1
|
-
---- STILL IN DEVELOPMENT ----
|
2
|
-
---- If you want to contribute, feel free to open an issue or contact me at rayan@hortatech.com.br ----
|
3
|
-
|
4
1
|
# HeraCms
|
5
2
|
|
6
3
|
Hera aims to enable you to easily add Content Managment to your Rails projects, with a very friendly user interface.
|
7
4
|
|
8
|
-
## Usage
|
9
|
-
We use some tables to store the editable content of your website, in order for it to be updatable dynamically by the website owner.
|
10
|
-
|
11
5
|
## Installation
|
12
6
|
|
13
7
|
1. Add this line to your application's Gemfile:
|
@@ -16,13 +10,13 @@ gem 'hera_cms'
|
|
16
10
|
```
|
17
11
|
2. Execute:
|
18
12
|
```bash
|
19
|
-
|
13
|
+
bundle
|
20
14
|
```
|
21
15
|
|
22
16
|
3. The Hera Installer will generate some migrations, that you need to run:
|
23
17
|
```bash
|
24
|
-
|
25
|
-
|
18
|
+
rails g hera_cms:install
|
19
|
+
rails db:migrate
|
26
20
|
```
|
27
21
|
|
28
22
|
## Configuration
|
@@ -60,8 +54,91 @@ Then, you need to add the Hera navbar to your layout. Here is also highly recomm
|
|
60
54
|
|
61
55
|
```
|
62
56
|
|
57
|
+
## Usage
|
58
|
+
We use hera_cms tables to store the editable content of your website, in order for it to be updatable dynamically by the website owner.
|
59
|
+
|
60
|
+
There are 3 types of editable content you can use: Links, Texts and Images
|
61
|
+
|
62
|
+
### Links
|
63
|
+
|
64
|
+
To add an editable link to the view, you first need to create it in the rails console
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
# rails console
|
68
|
+
pry(main)> HeraCms::Link.create(identifier: 'home-link-main', inner_text: "HortaTech", path: 'https://www.hortatech.com.br')
|
69
|
+
|
70
|
+
```
|
71
|
+
|
72
|
+
Then you can just add it to the view using the Hera Link Helper, passing the correct identifier
|
73
|
+
|
74
|
+
```erb
|
75
|
+
<!-- app/views/pages/home.html.erb -->
|
76
|
+
<!-- ... -->
|
77
|
+
|
78
|
+
<%= hera_link 'home-link-main' %>
|
79
|
+
|
80
|
+
<!-- ... -->
|
81
|
+
|
82
|
+
```
|
83
|
+
|
84
|
+
Alternatively, you can create links passing a block, similar to the link_to rails helper
|
85
|
+
|
86
|
+
```erb
|
87
|
+
<!-- app/views/pages/home.html.erb -->
|
88
|
+
<!-- ... -->
|
89
|
+
|
90
|
+
<%= hera_link 'home-link-main', class: 'main-link' do %>
|
91
|
+
<div class="card">
|
92
|
+
<p>Lorem ipsum</p>
|
93
|
+
</div>
|
94
|
+
<% end %>
|
95
|
+
|
96
|
+
<!-- ... -->
|
97
|
+
|
98
|
+
```
|
99
|
+
|
100
|
+
|
101
|
+
### Texts
|
102
|
+
|
103
|
+
To add an editable text to the view, it is exactly like addings links. You first need to create it in the rails console
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
# rails console
|
107
|
+
pry(main)> HeraCms::Text.create(identifier: 'home-description', inner_text: "These are not the droids you're looking for")
|
108
|
+
|
109
|
+
```
|
110
|
+
|
111
|
+
Then you can just add it to the view using the Hera Text Helper, passing the correct identifier
|
112
|
+
|
113
|
+
```erb
|
114
|
+
<!-- app/views/pages/home.html.erb -->
|
115
|
+
<!-- ... -->
|
116
|
+
|
117
|
+
<%= hera_text 'home-description', html_tag: :p %>
|
118
|
+
|
119
|
+
<!-- ... -->
|
120
|
+
|
121
|
+
```
|
122
|
+
|
123
|
+
### Images
|
124
|
+
|
125
|
+
Coming soon...
|
126
|
+
|
127
|
+
## Production Database
|
128
|
+
|
129
|
+
In order to facilitate you not have to duplicate all of your created records from development to production, we use a YAML file to store all record's information from development, located at db/hera_cms/hera_database_seed.yml
|
130
|
+
|
131
|
+
After you finish developing your application and want to build it in production, you can just run this command in production to replicate your created Hera Links, Texts and Images to your production database
|
132
|
+
|
133
|
+
```bash
|
134
|
+
rails hera_cms:populate_database
|
135
|
+
```
|
136
|
+
|
63
137
|
## Contributing
|
64
|
-
|
138
|
+
|
139
|
+
---- GEM STILL IN DEVELOPMENT ----
|
140
|
+
|
141
|
+
If you want to contribute, feel free to open an issue or contact me at rayan@hortatech.com.br
|
65
142
|
|
66
143
|
## License
|
67
144
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -1 +1,310 @@
|
|
1
|
-
// Hera
|
1
|
+
// console.log('Loading Hera CMS Javascript');
|
2
|
+
|
3
|
+
let editables = document.querySelectorAll('.hera-editable')
|
4
|
+
|
5
|
+
const AUTH_TOKEN = document.querySelector('meta[name=csrf-token]').attributes['content'].value;
|
6
|
+
|
7
|
+
const allowEdit = () => {
|
8
|
+
// Add listeners for all editables [edit mode]
|
9
|
+
editables.forEach((editable) => {
|
10
|
+
editable.addEventListener('mouseenter', displayEditor);
|
11
|
+
editable.addEventListener('mouseleave', hideEditor);
|
12
|
+
});
|
13
|
+
};
|
14
|
+
|
15
|
+
const lockEdit = () => {
|
16
|
+
// Remove listeners for all editables [view mode]
|
17
|
+
editables.forEach((editable) => {
|
18
|
+
editable.removeEventListener('mouseenter', displayEditor);
|
19
|
+
editable.removeEventListener('mouseleave', hideEditor);
|
20
|
+
});
|
21
|
+
};
|
22
|
+
|
23
|
+
const toggleOff = () => {
|
24
|
+
// Remove open forms and remove highlights that could be still active [switching from edit to view mode]
|
25
|
+
let formBox = document.querySelector(".hera-form-box");
|
26
|
+
if(formBox){
|
27
|
+
formBox.parentNode.removeChild(formBox);
|
28
|
+
};
|
29
|
+
|
30
|
+
editables.forEach((editable) => {
|
31
|
+
if (editable.classList.contains('hera-highlight-layer')){
|
32
|
+
editable.classList.remove('hera-highlight-layer');
|
33
|
+
}
|
34
|
+
});
|
35
|
+
// Swap wrapper with editable one (?)
|
36
|
+
let wrapper = document.querySelector('.hera-editable-wrapper');
|
37
|
+
if(wrapper){
|
38
|
+
wrapper.parentNode.replaceChild(wrapper.firstChild, wrapper);
|
39
|
+
};
|
40
|
+
};
|
41
|
+
|
42
|
+
|
43
|
+
const toggleEditLoader = (e) => {
|
44
|
+
// Select all editable elements on the page
|
45
|
+
editables = document.querySelectorAll('.hera-editable')
|
46
|
+
|
47
|
+
// Switches between Edit Mode and View mode
|
48
|
+
// In edit mode, all editable links, texts and images need the following:
|
49
|
+
// 1. One edit button that appears on hover
|
50
|
+
// 2. When you click it, it opens a form that enables you to change the value of the content
|
51
|
+
// This events can only exist on edit mode. On view mode nothing happens.
|
52
|
+
|
53
|
+
const button = e.target;
|
54
|
+
if (button.dataset["mode"] === "edit") {
|
55
|
+
// console.log('Switching to view mode');
|
56
|
+
button.innerText = "Off"
|
57
|
+
button.dataset["mode"] = "view"
|
58
|
+
button.classList.toggle("hera-edit-button-on");
|
59
|
+
toggleOff();
|
60
|
+
|
61
|
+
const layer = document.querySelector(".hera-background-layer");
|
62
|
+
document.body.removeChild(layer);
|
63
|
+
// const slickerLayer = document.querySelector(".slicker-layer");
|
64
|
+
// const slider = document.querySelector('.slick-track');
|
65
|
+
// slider.removeChild(slickerLayer);
|
66
|
+
lockEdit();
|
67
|
+
}
|
68
|
+
else if (button.dataset["mode"] === "view") {
|
69
|
+
// console.log('Switching to edit mode');
|
70
|
+
button.innerText = "On"
|
71
|
+
button.classList.toggle("hera-edit-button-on");
|
72
|
+
button.dataset["mode"] = "edit"
|
73
|
+
const layer = document.createElement("div");
|
74
|
+
layer.classList.add('hera-background-layer');
|
75
|
+
// const slickerLayer = document.createElement("div");
|
76
|
+
// slickerLayer.classList.add('hera-slicker-layer');
|
77
|
+
// const slider = document.querySelector('.slick-track');
|
78
|
+
// slider.appendChild(slickerLayer);
|
79
|
+
document.body.appendChild(layer);
|
80
|
+
allowEdit();
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
const displayEditor = (e) => {
|
85
|
+
// Shows the edit button for an element
|
86
|
+
// highlith the field to be edited
|
87
|
+
e.target.classList.add('hera-highlight-layer');
|
88
|
+
e.target.addEventListener('click', createForm);
|
89
|
+
}
|
90
|
+
|
91
|
+
const hideEditor = (e) => {
|
92
|
+
// Removes the edit button for an element
|
93
|
+
// remove highlighted field
|
94
|
+
e.target.classList.remove('hera-highlight-layer');
|
95
|
+
e.target.removeEventListener('click', createForm);
|
96
|
+
}
|
97
|
+
|
98
|
+
const sendRequest = (e) => {
|
99
|
+
e.preventDefault();
|
100
|
+
form = e.target;
|
101
|
+
|
102
|
+
let url = form.action + "?&authenticity_token=" + encodeURIComponent(AUTH_TOKEN);
|
103
|
+
|
104
|
+
options = {
|
105
|
+
method: "PUT",
|
106
|
+
body: new FormData(form)
|
107
|
+
};
|
108
|
+
|
109
|
+
// console.log("fetching");
|
110
|
+
fetch(url, options)
|
111
|
+
.then(response => response.json())
|
112
|
+
.then((data) => {
|
113
|
+
window.location.replace(data.redirect);
|
114
|
+
});
|
115
|
+
|
116
|
+
// console.log('end');
|
117
|
+
}
|
118
|
+
|
119
|
+
const createForm = (e) => {
|
120
|
+
// Create a form to update the content of element in the database, using its dataset
|
121
|
+
|
122
|
+
// Prevent the link click when clicks on the form, and the default form behavior
|
123
|
+
e.stopImmediatePropagation();
|
124
|
+
e.preventDefault();
|
125
|
+
e.target.removeEventListener('click', createForm);
|
126
|
+
lockEdit();
|
127
|
+
|
128
|
+
// Selects the element to be edited
|
129
|
+
const editable = e.currentTarget
|
130
|
+
|
131
|
+
// Creates the base form using rails autenthicity token
|
132
|
+
let form = document.createElement("form");
|
133
|
+
|
134
|
+
// Updates the form action to the proper element update route, using the datase
|
135
|
+
form.action = `/hera_cms/${editable.dataset['editableType']}/${editable.dataset['editableId']}`;
|
136
|
+
|
137
|
+
form.enctype = 'multipart/form-data';
|
138
|
+
|
139
|
+
// Add a hidden input field to properly utilize the PATCH method
|
140
|
+
|
141
|
+
let i = document.createElement("input");
|
142
|
+
i.setAttribute('type', "hidden");
|
143
|
+
i.setAttribute('name', "_method");
|
144
|
+
i.setAttribute('value', 'patch');
|
145
|
+
|
146
|
+
form.appendChild(i);
|
147
|
+
|
148
|
+
// Add the proper inputs for each type of editable
|
149
|
+
|
150
|
+
switch (editable.dataset['editableType']) {
|
151
|
+
case 'links':
|
152
|
+
form = linkForm(form, editable);
|
153
|
+
break;
|
154
|
+
case 'media_index':
|
155
|
+
form = imageForm(form, editable);
|
156
|
+
break;
|
157
|
+
case 'texts':
|
158
|
+
form = textForm(form, editable);
|
159
|
+
break;
|
160
|
+
case 'forms':
|
161
|
+
form = formForm(form, editable);
|
162
|
+
break;
|
163
|
+
default:
|
164
|
+
console.log(`Tipo ${editable.dataset['editableType']} não identificado.`)
|
165
|
+
}
|
166
|
+
|
167
|
+
// Add form submit button
|
168
|
+
let s = document.createElement("input");
|
169
|
+
s.setAttribute('type', "submit");
|
170
|
+
s.setAttribute('value', "Atualizar");
|
171
|
+
|
172
|
+
form.appendChild(s);
|
173
|
+
|
174
|
+
// Add editable wrapper with form inside
|
175
|
+
let wrapper = document.createElement("div");
|
176
|
+
wrapper.className = "hera-editable-wrapper " + editable.className;
|
177
|
+
editable.parentNode.insertBefore(wrapper ,editable);
|
178
|
+
|
179
|
+
wrappedEditable = wrapper.appendChild(editable);
|
180
|
+
|
181
|
+
// Creates and initializes the modal
|
182
|
+
let formBox = document.createElement('div');
|
183
|
+
formBox.classList.add("hera-form-box");
|
184
|
+
formBox.appendChild(form);
|
185
|
+
wrapper.appendChild(formBox);
|
186
|
+
let boxPositionY = wrapper.getBoundingClientRect().top + 150;
|
187
|
+
let boxPositionX = wrapper.getBoundingClientRect().left + 150;
|
188
|
+
let screenHeight = window.screen.height;
|
189
|
+
let screenWidth = window.screen.width;
|
190
|
+
let relativeY = (boxPositionY / screenHeight) * screenHeight;
|
191
|
+
let relativeX = boxPositionX / screenWidth * screenWidth;
|
192
|
+
|
193
|
+
if(relativeX > screenWidth / 2){
|
194
|
+
formBox.style.left = "-308px";
|
195
|
+
}else{
|
196
|
+
formBox.style.right = "-308px";
|
197
|
+
};
|
198
|
+
if(relativeY > screenHeight / 2){
|
199
|
+
formBox.style.top = "-150px";
|
200
|
+
}else{
|
201
|
+
formBox.style.bottom = "-150px";
|
202
|
+
};
|
203
|
+
wrappedEditable.removeEventListener('mouseenter', displayEditor);
|
204
|
+
wrappedEditable.removeEventListener('mouseleave', hideEditor);
|
205
|
+
|
206
|
+
// Adds button to destroy wrapper and the form
|
207
|
+
let destroyButton = document.createElement("p");
|
208
|
+
destroyButton.className = "form-destroy";
|
209
|
+
destroyButton.innerHTML = "x";
|
210
|
+
destroyButton.addEventListener('click', () => {
|
211
|
+
if (wrapper.parentNode) {
|
212
|
+
newEditable = wrapper.parentNode.replaceChild(editable, wrapper);
|
213
|
+
wrapper.removeChild(formBox);
|
214
|
+
editable.classList.remove('hera-highlight-layer');
|
215
|
+
bodyLayer.classList.remove('hera-clickable');
|
216
|
+
allowEdit();
|
217
|
+
}
|
218
|
+
});
|
219
|
+
|
220
|
+
|
221
|
+
let bodyLayer = document.querySelector('.hera-background-layer');
|
222
|
+
bodyLayer.classList.add('hera-clickable');
|
223
|
+
bodyLayer.addEventListener('click', () => {
|
224
|
+
destroyButton.click();
|
225
|
+
});
|
226
|
+
|
227
|
+
form.appendChild(destroyButton);
|
228
|
+
form.addEventListener('submit', sendRequest);
|
229
|
+
}
|
230
|
+
|
231
|
+
const linkForm = (form, editable) => {
|
232
|
+
|
233
|
+
// Creates text input for the content of the element and appends it to the form
|
234
|
+
pathInput = document.createElement("input");
|
235
|
+
pathInput.setAttribute('type', "text");
|
236
|
+
pathInput.setAttribute('name', "link[path]");
|
237
|
+
pathInput.setAttribute('autocomplete', "off");
|
238
|
+
pathInput.setAttribute('value', editable);
|
239
|
+
|
240
|
+
form.appendChild(pathInput);
|
241
|
+
|
242
|
+
// Creates text input for the content of the element and appends it to the form
|
243
|
+
innerTextInput = document.createElement("input");
|
244
|
+
innerTextInput.setAttribute('type', "text");
|
245
|
+
innerTextInput.setAttribute('name', "link[inner_text]");
|
246
|
+
innerTextInput.setAttribute('autocomplete', "off");
|
247
|
+
innerTextInput.innerHTML = editable.innerText;
|
248
|
+
innerTextInput.setAttribute('value', editable.innerText);
|
249
|
+
|
250
|
+
form.appendChild(innerTextInput);
|
251
|
+
return form;
|
252
|
+
}
|
253
|
+
|
254
|
+
const imageForm = (form, editable) => {
|
255
|
+
|
256
|
+
// Creates text input for the content of the element and appends it to the form
|
257
|
+
i = document.createElement("input");
|
258
|
+
i.setAttribute('type', "file");
|
259
|
+
i.setAttribute('name', "media[upload]");
|
260
|
+
|
261
|
+
form.appendChild(i);
|
262
|
+
|
263
|
+
i = document.createElement("input");
|
264
|
+
i.setAttribute('type', "hidden");
|
265
|
+
i.setAttribute('name', "media[upload_cache]");
|
266
|
+
|
267
|
+
form.appendChild(i);
|
268
|
+
|
269
|
+
return form;
|
270
|
+
}
|
271
|
+
|
272
|
+
const textForm = (form, editable) => {
|
273
|
+
|
274
|
+
// Creates text input for the content of the element and appends it to the form
|
275
|
+
i = document.createElement("textarea");
|
276
|
+
i.setAttribute('type', "text");
|
277
|
+
i.setAttribute('name', "text[inner_text]");
|
278
|
+
i.setAttribute('autocomplete', "off");
|
279
|
+
i.innerHTML = editable.innerText;
|
280
|
+
i.setAttribute('value', editable.innerText);
|
281
|
+
|
282
|
+
form.appendChild(i);
|
283
|
+
|
284
|
+
return form;
|
285
|
+
}
|
286
|
+
|
287
|
+
const formForm = (form, editable) => {
|
288
|
+
i = document.createElement("input");
|
289
|
+
i.setAttribute('type', "text");
|
290
|
+
i.setAttribute('name', "form[send_to]");
|
291
|
+
i.setAttribute('value', editable.getAttribute("data-mail"))
|
292
|
+
form.appendChild(i)
|
293
|
+
return form
|
294
|
+
}
|
295
|
+
|
296
|
+
|
297
|
+
const createElementFromHTML = (htmlString) => {
|
298
|
+
// Creates a node element from a HTML string
|
299
|
+
const div = document.createElement('div');
|
300
|
+
div.innerHTML = htmlString.trim();
|
301
|
+
|
302
|
+
return div.firstChild;
|
303
|
+
}
|
304
|
+
|
305
|
+
|
306
|
+
// Selects the view's edit button and adds listener to toggle between edit and view mode
|
307
|
+
const editButton = document.getElementById('hera-edit-button');
|
308
|
+
if (editButton) {
|
309
|
+
editButton.addEventListener('click', toggleEditLoader)
|
310
|
+
}
|
data/app/models/hera_cms/link.rb
CHANGED
data/app/models/hera_cms/text.rb
CHANGED
data/lib/hera_cms.rb
CHANGED
@@ -12,9 +12,10 @@ module HeraCms
|
|
12
12
|
|
13
13
|
# mattr_accessor :app_root
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
class << self
|
16
|
+
# attr_accessor :s3_bucket
|
17
|
+
attr_accessor :image_upload, :upload_service
|
18
|
+
end
|
18
19
|
|
19
20
|
# Yield self on setup for nice config blocks
|
20
21
|
def self.setup
|
data/lib/hera_cms/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hera_cms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rayan Castro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-02-
|
11
|
+
date: 2021-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -160,7 +160,6 @@ files:
|
|
160
160
|
- app/models/hera_cms/text.rb
|
161
161
|
- app/views/hera_cms/dashboard/home.html.erb
|
162
162
|
- app/views/hera_cms/layouts/hera_cms/application.html.erb
|
163
|
-
- app/views/hera_cms/shared/_hera_edit.js
|
164
163
|
- app/views/hera_cms/shared/_navbar.html.erb
|
165
164
|
- app/views/layouts/hera_cms/application.html.erb
|
166
165
|
- config/routes.rb
|
@@ -1,312 +0,0 @@
|
|
1
|
-
console.log('Hera CMS Javascript ON :)');
|
2
|
-
|
3
|
-
let editables = document.querySelectorAll('.hera-editable')
|
4
|
-
|
5
|
-
const AUTH_TOKEN = document.querySelector('meta[name=csrf-token]').attributes['content'].value;
|
6
|
-
|
7
|
-
const allowEdit = () => {
|
8
|
-
// Add listeners for all editables [edit mode]
|
9
|
-
editables.forEach((editable) => {
|
10
|
-
editable.addEventListener('mouseenter', displayEditor);
|
11
|
-
editable.addEventListener('mouseleave', hideEditor);
|
12
|
-
});
|
13
|
-
};
|
14
|
-
|
15
|
-
const lockEdit = () => {
|
16
|
-
// Remove listeners for all editables [view mode]
|
17
|
-
editables.forEach((editable) => {
|
18
|
-
editable.removeEventListener('mouseenter', displayEditor);
|
19
|
-
editable.removeEventListener('mouseleave', hideEditor);
|
20
|
-
});
|
21
|
-
};
|
22
|
-
|
23
|
-
const toggleOff = () => {
|
24
|
-
// Remove open forms and remove highlights that could be still active [switching from edit to view mode]
|
25
|
-
let formBox = document.querySelector(".hera-form-box");
|
26
|
-
if(formBox){
|
27
|
-
formBox.parentNode.removeChild(formBox);
|
28
|
-
};
|
29
|
-
|
30
|
-
editables.forEach((editable) => {
|
31
|
-
if (editable.classList.contains('hera-highlight-layer')){
|
32
|
-
editable.classList.remove('hera-highlight-layer');
|
33
|
-
}
|
34
|
-
});
|
35
|
-
// Swap wrapper with editable one (?)
|
36
|
-
let wrapper = document.querySelector('.hera-editable-wrapper');
|
37
|
-
if(wrapper){
|
38
|
-
wrapper.parentNode.replaceChild(wrapper.firstChild, wrapper);
|
39
|
-
};
|
40
|
-
};
|
41
|
-
|
42
|
-
|
43
|
-
const toggleEditLoader = (e) => {
|
44
|
-
// Select all editable elements on the page
|
45
|
-
editables = document.querySelectorAll('.hera-editable')
|
46
|
-
|
47
|
-
// Switches between Edit Mode and View mode
|
48
|
-
// In edit mode, all editable links, texts and images need the following:
|
49
|
-
// 1. One edit button that appears on hover
|
50
|
-
// 2. When you click it, it opens a form that enables you to change the value of the content
|
51
|
-
// This events can only exist on edit mode. On view mode nothing happens.
|
52
|
-
|
53
|
-
const button = e.target;
|
54
|
-
if (button.dataset["mode"] === "edit") {
|
55
|
-
console.log('Switching to view mode');
|
56
|
-
button.innerText = "Off"
|
57
|
-
button.dataset["mode"] = "view"
|
58
|
-
button.classList.toggle("hera-edit-button-on");
|
59
|
-
toggleOff();
|
60
|
-
|
61
|
-
const layer = document.querySelector(".hera-background-layer");
|
62
|
-
document.body.removeChild(layer);
|
63
|
-
// const slickerLayer = document.querySelector(".slicker-layer");
|
64
|
-
// const slider = document.querySelector('.slick-track');
|
65
|
-
// slider.removeChild(slickerLayer);
|
66
|
-
lockEdit();
|
67
|
-
}
|
68
|
-
else if (button.dataset["mode"] === "view") {
|
69
|
-
console.log('Switching to edit mode');
|
70
|
-
button.innerText = "On"
|
71
|
-
button.classList.toggle("hera-edit-button-on");
|
72
|
-
button.dataset["mode"] = "edit"
|
73
|
-
const layer = document.createElement("div");
|
74
|
-
layer.classList.add('hera-background-layer');
|
75
|
-
// const slickerLayer = document.createElement("div");
|
76
|
-
// slickerLayer.classList.add('hera-slicker-layer');
|
77
|
-
// const slider = document.querySelector('.slick-track');
|
78
|
-
// slider.appendChild(slickerLayer);
|
79
|
-
document.body.appendChild(layer);
|
80
|
-
allowEdit();
|
81
|
-
}
|
82
|
-
}
|
83
|
-
|
84
|
-
const displayEditor = (e) => {
|
85
|
-
// Shows the edit button for an element
|
86
|
-
// highlith the field to be edited
|
87
|
-
e.target.classList.add('hera-highlight-layer');
|
88
|
-
e.target.addEventListener('click', createForm);
|
89
|
-
}
|
90
|
-
|
91
|
-
const hideEditor = (e) => {
|
92
|
-
// Removes the edit button for an element
|
93
|
-
// remove highlighted field
|
94
|
-
e.target.classList.remove('hera-highlight-layer');
|
95
|
-
e.target.removeEventListener('click', createForm);
|
96
|
-
}
|
97
|
-
|
98
|
-
const sendRequest = (e) => {
|
99
|
-
e.preventDefault();
|
100
|
-
form = e.target;
|
101
|
-
|
102
|
-
let url = form.action + "?&authenticity_token=" + encodeURIComponent(AUTH_TOKEN);
|
103
|
-
|
104
|
-
options = {
|
105
|
-
method: "PUT",
|
106
|
-
body: new FormData(form)
|
107
|
-
};
|
108
|
-
|
109
|
-
console.log("fetching");
|
110
|
-
fetch(url, options)
|
111
|
-
.then(response => response.json())
|
112
|
-
.then((data) => {
|
113
|
-
window.location.replace(data.redirect);
|
114
|
-
});
|
115
|
-
|
116
|
-
console.log('end');
|
117
|
-
}
|
118
|
-
|
119
|
-
const createForm = (e) => {
|
120
|
-
// Create a form to update the content of element in the database, using its dataset
|
121
|
-
|
122
|
-
// Prevent the link click when clicks on the form, and the default form behavior
|
123
|
-
e.stopImmediatePropagation();
|
124
|
-
e.preventDefault();
|
125
|
-
e.target.removeEventListener('click', createForm);
|
126
|
-
lockEdit();
|
127
|
-
|
128
|
-
// Selects the element to be edited
|
129
|
-
const editable = e.currentTarget
|
130
|
-
|
131
|
-
// Creates the base form using rails autenthicity token
|
132
|
-
let form = document.createElement("form");
|
133
|
-
|
134
|
-
// Updates the form action to the proper element update route, using the datase
|
135
|
-
form.action = `/hera_cms/${editable.dataset['editableType']}/${editable.dataset['editableId']}`;
|
136
|
-
|
137
|
-
form.enctype = 'multipart/form-data';
|
138
|
-
|
139
|
-
// Add a hidden input field to properly utilize the PATCH method
|
140
|
-
|
141
|
-
let i = document.createElement("input");
|
142
|
-
i.setAttribute('type', "hidden");
|
143
|
-
i.setAttribute('name', "_method");
|
144
|
-
i.setAttribute('value', 'patch');
|
145
|
-
|
146
|
-
form.appendChild(i);
|
147
|
-
|
148
|
-
// Add the proper inputs for each type of editable
|
149
|
-
|
150
|
-
switch (editable.dataset['editableType']) {
|
151
|
-
case 'links':
|
152
|
-
form = linkForm(form, editable);
|
153
|
-
break;
|
154
|
-
case 'media_index':
|
155
|
-
form = imageForm(form, editable);
|
156
|
-
break;
|
157
|
-
case 'texts':
|
158
|
-
form = textForm(form, editable);
|
159
|
-
break;
|
160
|
-
case 'forms':
|
161
|
-
form = formForm(form, editable);
|
162
|
-
break;
|
163
|
-
default:
|
164
|
-
console.log(`Tipo ${editable.dataset['editableType']} não identificado.`)
|
165
|
-
}
|
166
|
-
|
167
|
-
// Add form submit button
|
168
|
-
let s = document.createElement("input");
|
169
|
-
s.setAttribute('type', "submit");
|
170
|
-
s.setAttribute('value', "Atualizar");
|
171
|
-
|
172
|
-
form.appendChild(s);
|
173
|
-
|
174
|
-
// Add editable wrapper with form inside
|
175
|
-
let wrapper = document.createElement("div");
|
176
|
-
wrapper.className = "hera-editable-wrapper " + editable.className;
|
177
|
-
editable.parentNode.insertBefore(wrapper ,editable);
|
178
|
-
|
179
|
-
wrappedEditable = wrapper.appendChild(editable);
|
180
|
-
|
181
|
-
// Creates and initializes the modal
|
182
|
-
let formBox = document.createElement('div');
|
183
|
-
formBox.classList.add("hera-form-box");
|
184
|
-
formBox.appendChild(form);
|
185
|
-
wrapper.appendChild(formBox);
|
186
|
-
let boxPositionY = wrapper.getBoundingClientRect().top + 150;
|
187
|
-
let boxPositionX = wrapper.getBoundingClientRect().left + 150;
|
188
|
-
let screenHeight = window.screen.height;
|
189
|
-
let screenWidth = window.screen.width;
|
190
|
-
let relativeY = (boxPositionY / screenHeight) * screenHeight;
|
191
|
-
let relativeX = boxPositionX / screenWidth * screenWidth;
|
192
|
-
|
193
|
-
if(relativeX > screenWidth / 2){
|
194
|
-
formBox.style.left = "-308px";
|
195
|
-
}else{
|
196
|
-
formBox.style.right = "-308px";
|
197
|
-
};
|
198
|
-
if(relativeY > screenHeight / 2){
|
199
|
-
formBox.style.top = "-150px";
|
200
|
-
}else{
|
201
|
-
formBox.style.bottom = "-150px";
|
202
|
-
};
|
203
|
-
wrappedEditable.removeEventListener('mouseenter', displayEditor);
|
204
|
-
wrappedEditable.removeEventListener('mouseleave', hideEditor);
|
205
|
-
|
206
|
-
// Adds button to destroy wrapper and the form
|
207
|
-
let destroyButton = document.createElement("p");
|
208
|
-
destroyButton.className = "form-destroy";
|
209
|
-
destroyButton.innerHTML = "x";
|
210
|
-
destroyButton.addEventListener('click', () => {
|
211
|
-
if (wrapper.parentNode) {
|
212
|
-
newEditable = wrapper.parentNode.replaceChild(editable, wrapper);
|
213
|
-
wrapper.removeChild(formBox);
|
214
|
-
editable.classList.remove('hera-highlight-layer');
|
215
|
-
bodyLayer.classList.remove('hera-clickable');
|
216
|
-
allowEdit();
|
217
|
-
}
|
218
|
-
});
|
219
|
-
|
220
|
-
|
221
|
-
let bodyLayer = document.querySelector('.hera-background-layer');
|
222
|
-
bodyLayer.classList.add('hera-clickable');
|
223
|
-
bodyLayer.addEventListener('click', () => {
|
224
|
-
destroyButton.click();
|
225
|
-
});
|
226
|
-
|
227
|
-
form.appendChild(destroyButton);
|
228
|
-
form.addEventListener('submit', sendRequest);
|
229
|
-
}
|
230
|
-
|
231
|
-
const linkForm = (form, editable) => {
|
232
|
-
|
233
|
-
// Creates text input for the content of the element and appends it to the form
|
234
|
-
pathInput = document.createElement("input");
|
235
|
-
pathInput.setAttribute('type', "text");
|
236
|
-
pathInput.setAttribute('name', "link[path]");
|
237
|
-
pathInput.setAttribute('autocomplete', "off");
|
238
|
-
pathInput.setAttribute('value', editable);
|
239
|
-
|
240
|
-
form.appendChild(pathInput);
|
241
|
-
|
242
|
-
// Creates text input for the content of the element and appends it to the form
|
243
|
-
innerTextInput = document.createElement("input");
|
244
|
-
innerTextInput.setAttribute('type', "text");
|
245
|
-
innerTextInput.setAttribute('name', "link[inner_text]");
|
246
|
-
innerTextInput.setAttribute('autocomplete', "off");
|
247
|
-
innerTextInput.innerHTML = editable.innerText;
|
248
|
-
innerTextInput.setAttribute('value', editable.innerText);
|
249
|
-
|
250
|
-
form.appendChild(innerTextInput);
|
251
|
-
return form;
|
252
|
-
}
|
253
|
-
|
254
|
-
const imageForm = (form, editable) => {
|
255
|
-
|
256
|
-
// Creates text input for the content of the element and appends it to the form
|
257
|
-
i = document.createElement("input");
|
258
|
-
i.setAttribute('type', "file");
|
259
|
-
i.setAttribute('name', "media[upload]");
|
260
|
-
|
261
|
-
form.appendChild(i);
|
262
|
-
|
263
|
-
i = document.createElement("input");
|
264
|
-
i.setAttribute('type', "hidden");
|
265
|
-
i.setAttribute('name', "media[upload_cache]");
|
266
|
-
|
267
|
-
form.appendChild(i);
|
268
|
-
|
269
|
-
return form;
|
270
|
-
}
|
271
|
-
|
272
|
-
const textForm = (form, editable) => {
|
273
|
-
|
274
|
-
// Creates text input for the content of the element and appends it to the form
|
275
|
-
i = document.createElement("textarea");
|
276
|
-
i.setAttribute('type', "text");
|
277
|
-
i.setAttribute('name', "text[inner_text]");
|
278
|
-
i.setAttribute('autocomplete', "off");
|
279
|
-
i.innerHTML = editable.innerText;
|
280
|
-
i.setAttribute('value', editable.innerText);
|
281
|
-
|
282
|
-
form.appendChild(i);
|
283
|
-
|
284
|
-
return form;
|
285
|
-
}
|
286
|
-
|
287
|
-
const formForm = (form, editable) => {
|
288
|
-
console.log(editable)
|
289
|
-
console.log(form)
|
290
|
-
i = document.createElement("input");
|
291
|
-
i.setAttribute('type', "text");
|
292
|
-
i.setAttribute('name', "form[send_to]");
|
293
|
-
i.setAttribute('value', editable.getAttribute("data-mail"))
|
294
|
-
form.appendChild(i)
|
295
|
-
return form
|
296
|
-
}
|
297
|
-
|
298
|
-
|
299
|
-
const createElementFromHTML = (htmlString) => {
|
300
|
-
// Creates a node element from a HTML string
|
301
|
-
const div = document.createElement('div');
|
302
|
-
div.innerHTML = htmlString.trim();
|
303
|
-
|
304
|
-
return div.firstChild;
|
305
|
-
}
|
306
|
-
|
307
|
-
|
308
|
-
// Selects the view's edit button and adds listener to toggle between edit and view mode
|
309
|
-
const editButton = document.getElementById('hera-edit-button');
|
310
|
-
if (editButton) {
|
311
|
-
editButton.addEventListener('click', toggleEditLoader)
|
312
|
-
}
|