hera_cms 0.1.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +67 -0
- data/Rakefile +22 -0
- data/app/assets/config/hera_cms_manifest.js +1 -0
- data/app/assets/images/hera_cms/hera_white.png +0 -0
- data/app/assets/javascripts/hera_cms/application.js +1 -0
- data/app/assets/stylesheets/hera_cms/application.css +154 -0
- data/app/assets/stylesheets/hera_cms/links.css +4 -0
- data/app/controllers/hera_cms/application_controller.rb +5 -0
- data/app/controllers/hera_cms/base_controller.rb +9 -0
- data/app/controllers/hera_cms/dashboard_controller.rb +6 -0
- data/app/controllers/hera_cms/links_controller.rb +56 -0
- data/app/helpers/hera_cms/application_helper.rb +4 -0
- data/app/helpers/hera_cms/links_helper.rb +4 -0
- data/app/helpers/hera_cms/tag_helper.rb +121 -0
- data/app/jobs/hera_cms/application_job.rb +4 -0
- data/app/mailers/hera_cms/application_mailer.rb +6 -0
- data/app/models/hera_cms/application_record.rb +31 -0
- data/app/models/hera_cms/image.rb +7 -0
- data/app/models/hera_cms/link.rb +8 -0
- data/app/models/hera_cms/text.rb +7 -0
- data/app/views/hera_cms/dashboard/home.html.erb +6 -0
- data/app/views/hera_cms/layouts/hera_cms/application.html.erb +15 -0
- data/app/views/hera_cms/shared/_hera_edit.js +302 -0
- data/app/views/hera_cms/shared/_navbar.html.erb +13 -0
- data/app/views/layouts/hera_cms/application.html.erb +15 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20201202150007_create_hera_cms_links.rb +13 -0
- data/db/migrate/20201202152559_create_hera_cms_texts.rb +12 -0
- data/db/migrate/20201203104012_create_hera_cms_images.rb +13 -0
- data/lib/generators/hera_cms/install_generator.rb +22 -0
- data/lib/generators/hera_cms/templates/config.rb.tt +2 -0
- data/lib/generators/hera_cms/templates/install.rb.tt +38 -0
- data/lib/hera_cms.rb +28 -0
- data/lib/hera_cms/engine.rb +34 -0
- data/lib/hera_cms/railtie.rb +4 -0
- data/lib/hera_cms/version.rb +3 -0
- data/lib/tasks/hera_cms_tasks.rake +32 -0
- metadata +201 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
module HeraCms
|
2
|
+
class ApplicationRecord < ActiveRecord::Base
|
3
|
+
self.abstract_class = true
|
4
|
+
def self.identify(identifier)
|
5
|
+
self.find_by(identifier: identifier)
|
6
|
+
end
|
7
|
+
|
8
|
+
def editable?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def update_seed
|
13
|
+
model = self.class.model_name.plural
|
14
|
+
file_name = "hera_database_seed.yml"
|
15
|
+
directory_path = File.join(Rails.root, 'db', 'hera_cms')
|
16
|
+
@file_path = File.join(directory_path, file_name)
|
17
|
+
|
18
|
+
Dir.mkdir(directory_path) unless File.exists?(directory_path)
|
19
|
+
|
20
|
+
elements = File.exists?(@file_path) ? YAML.load(File.read(@file_path)) : {}
|
21
|
+
|
22
|
+
elements[model] = {} unless elements.key?(model)
|
23
|
+
|
24
|
+
elements[model][self.identifier] = self.as_json.without("id", "created_at", "updated_at")
|
25
|
+
|
26
|
+
|
27
|
+
File.open(@file_path, "w") { |file| file.write(elements.to_yaml) }
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,302 @@
|
|
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
|
+
console.log(data);
|
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 = mediaForm(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
|
+
console.log(relativeX);
|
193
|
+
console.log(screenWidth/2);
|
194
|
+
if(relativeX > screenWidth / 2){
|
195
|
+
formBox.style.left = "-308px";
|
196
|
+
}else{
|
197
|
+
formBox.style.right = "-308px";
|
198
|
+
};
|
199
|
+
if(relativeY > screenHeight / 2){
|
200
|
+
formBox.style.top = "-150px";
|
201
|
+
}else{
|
202
|
+
formBox.style.bottom = "-150px";
|
203
|
+
};
|
204
|
+
wrappedEditable.removeEventListener('mouseenter', displayEditor);
|
205
|
+
wrappedEditable.removeEventListener('mouseleave', hideEditor);
|
206
|
+
|
207
|
+
// Adds button to destroy wrapper and the form
|
208
|
+
let destroyButton = document.createElement("p");
|
209
|
+
destroyButton.className = "form-destroy";
|
210
|
+
destroyButton.innerHTML = "x";
|
211
|
+
destroyButton.addEventListener('click', () => {
|
212
|
+
if (wrapper.parentNode) {
|
213
|
+
newEditable = wrapper.parentNode.replaceChild(editable, wrapper);
|
214
|
+
wrapper.removeChild(formBox);
|
215
|
+
editable.classList.remove('hera-highlight-layer');
|
216
|
+
bodyLayer.classList.remove('hera-clickable');
|
217
|
+
allowEdit();
|
218
|
+
}
|
219
|
+
});
|
220
|
+
|
221
|
+
|
222
|
+
let bodyLayer = document.querySelector('.hera-background-layer');
|
223
|
+
bodyLayer.classList.add('hera-clickable');
|
224
|
+
bodyLayer.addEventListener('click', () => {
|
225
|
+
destroyButton.click();
|
226
|
+
});
|
227
|
+
|
228
|
+
form.appendChild(destroyButton);
|
229
|
+
form.addEventListener('submit', sendRequest);
|
230
|
+
}
|
231
|
+
|
232
|
+
const linkForm = (form, editable) => {
|
233
|
+
|
234
|
+
// Creates text input for the content of the element and appends it to the form
|
235
|
+
i = document.createElement("input");
|
236
|
+
i.setAttribute('type', "text");
|
237
|
+
i.setAttribute('name', "link[path]");
|
238
|
+
i.setAttribute('value', editable);
|
239
|
+
|
240
|
+
form.appendChild(i);
|
241
|
+
|
242
|
+
return form;
|
243
|
+
}
|
244
|
+
|
245
|
+
const mediaForm = (form, editable) => {
|
246
|
+
|
247
|
+
// Creates text input for the content of the element and appends it to the form
|
248
|
+
i = document.createElement("input");
|
249
|
+
i.setAttribute('type', "file");
|
250
|
+
i.setAttribute('name', "media[upload]");
|
251
|
+
|
252
|
+
form.appendChild(i);
|
253
|
+
|
254
|
+
i = document.createElement("input");
|
255
|
+
i.setAttribute('type', "hidden");
|
256
|
+
i.setAttribute('name', "media[upload_cache]");
|
257
|
+
|
258
|
+
form.appendChild(i);
|
259
|
+
|
260
|
+
return form;
|
261
|
+
}
|
262
|
+
|
263
|
+
const textForm = (form, editable) => {
|
264
|
+
|
265
|
+
// Creates text input for the content of the element and appends it to the form
|
266
|
+
i = document.createElement("textarea");
|
267
|
+
i.setAttribute('type', "text");
|
268
|
+
i.setAttribute('name', "text[inner_text]");
|
269
|
+
i.innerHTML = editable.innerText;
|
270
|
+
i.setAttribute('value', editable.innerText);
|
271
|
+
|
272
|
+
form.appendChild(i);
|
273
|
+
|
274
|
+
return form;
|
275
|
+
}
|
276
|
+
|
277
|
+
const formForm = (form, editable) => {
|
278
|
+
console.log(editable)
|
279
|
+
console.log(form)
|
280
|
+
i = document.createElement("input");
|
281
|
+
i.setAttribute('type', "text");
|
282
|
+
i.setAttribute('name', "form[send_to]");
|
283
|
+
i.setAttribute('value', editable.getAttribute("data-mail"))
|
284
|
+
form.appendChild(i)
|
285
|
+
return form
|
286
|
+
}
|
287
|
+
|
288
|
+
|
289
|
+
const createElementFromHTML = (htmlString) => {
|
290
|
+
// Creates a node element from a HTML string
|
291
|
+
const div = document.createElement('div');
|
292
|
+
div.innerHTML = htmlString.trim();
|
293
|
+
|
294
|
+
return div.firstChild;
|
295
|
+
}
|
296
|
+
|
297
|
+
|
298
|
+
// Selects the view's edit button and adds listener to toggle between edit and view mode
|
299
|
+
const editButton = document.getElementById('hera-edit-button');
|
300
|
+
if (editButton) {
|
301
|
+
editButton.addEventListener('click', toggleEditLoader)
|
302
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<%= stylesheet_link_tag 'hera_cms/application', media: 'all' %>
|
2
|
+
|
3
|
+
<div class="hera-navbar">
|
4
|
+
<%= image_tag("hera_cms/hera_white.png") %>
|
5
|
+
<div class="margin-auto-center">
|
6
|
+
Modo Edição:
|
7
|
+
<button id="hera-edit-button" data-mode="view">Off</button>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<%= javascript_tag do %>
|
12
|
+
<%= render(partial: 'hera_cms/shared/hera_edit', handlers: [], formats: [:js]) %>
|
13
|
+
<% end %>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateHeraCmsLinks < ActiveRecord::Migration[6.0]
|
2
|
+
def change
|
3
|
+
create_table :hera_cms_links do |t|
|
4
|
+
t.string :identifier
|
5
|
+
t.string :path
|
6
|
+
t.string :inner_text, default: ""
|
7
|
+
t.string :classes, default: ""
|
8
|
+
t.string :style, default: ""
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|