ivaldi-content-builder 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 567ce814b24744949448b8b0f6606b103ef35705
4
+ data.tar.gz: 6fb3b921848f31f5712e5780d6e6deff784361f0
5
+ SHA512:
6
+ metadata.gz: dbb75e538dbb9a7c322185e4f08564d88c088a7edc80e681bf1700f540ca7db6feaff5378c5a270db776e08b818ef45ce51fc110d05bcc0c38f1da6292654636
7
+ data.tar.gz: f382254a25d8c16f9c60b9adbb8fc259cfee8fd59d5d9e75b273c13aa756cdc7f9cb286a6874fa903a28da0165ccbfea29ad73ea8aeefe704298f9b8b7d6dec9
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Bas Schoenmakers
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ # IvaldiContentBuilder
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'ivaldi_content_builder'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install ivaldi_content_builder
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,33 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'IvaldiContentBuilder'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+
33
+ task default: :test
@@ -0,0 +1,349 @@
1
+ !(function(e, t) {
2
+ "function" == typeof define && define.amd
3
+ ? define([], t)
4
+ : "object" == typeof exports ? (module.exports = t()) : (e.sortable = t());
5
+ })(this, function() {
6
+ "use strict";
7
+ function e(e, t, n) {
8
+ var r = null;
9
+ return 0 === t
10
+ ? e
11
+ : function() {
12
+ var a = n || this,
13
+ o = arguments;
14
+ clearTimeout(r), (r = setTimeout(function() {
15
+ e.apply(a, o);
16
+ }, t));
17
+ };
18
+ }
19
+ var t,
20
+ n,
21
+ r = [],
22
+ a = [],
23
+ o = function(e, t, n) {
24
+ return void 0 === n
25
+ ? e && e.h5s && e.h5s.data && e.h5s.data[t]
26
+ : (
27
+ (e.h5s = e.h5s || {}),
28
+ (e.h5s.data = e.h5s.data || {}),
29
+ (e.h5s.data[t] = n),
30
+ void 0
31
+ );
32
+ },
33
+ i = function(e) {
34
+ e.h5s && delete e.h5s.data;
35
+ },
36
+ s = function(e, t) {
37
+ return (e.matches ||
38
+ e.matchesSelector ||
39
+ e.msMatchesSelector ||
40
+ e.mozMatchesSelector ||
41
+ e.webkitMatchesSelector ||
42
+ e.oMatchesSelector)
43
+ .call(e, t);
44
+ },
45
+ l = function(e, t) {
46
+ if (!t) return Array.prototype.slice.call(e);
47
+ for (var n = [], r = 0; r < e.length; ++r)
48
+ "string" == typeof t && s(e[r], t) && n.push(e[r]), t.indexOf(e[r]) !==
49
+ -1 && n.push(e[r]);
50
+ return n;
51
+ },
52
+ d = function(e, t, n) {
53
+ if (e instanceof Array) for (var r = 0; r < e.length; ++r) d(e[r], t, n);
54
+ else
55
+ e.addEventListener(t, n), (e.h5s = e.h5s || {}), (e.h5s.events =
56
+ e.h5s.events || {}), (e.h5s.events[t] = n);
57
+ },
58
+ c = function(e, t) {
59
+ if (e instanceof Array) for (var n = 0; n < e.length; ++n) c(e[n], t);
60
+ else
61
+ e.h5s &&
62
+ e.h5s.events &&
63
+ e.h5s.events[t] &&
64
+ (e.removeEventListener(t, e.h5s.events[t]), delete e.h5s.events[t]);
65
+ },
66
+ f = function(e, t, n) {
67
+ if (e instanceof Array) for (var r = 0; r < e.length; ++r) f(e[r], t, n);
68
+ else e.setAttribute(t, n);
69
+ },
70
+ u = function(e, t) {
71
+ if (e instanceof Array) for (var n = 0; n < e.length; ++n) u(e[n], t);
72
+ else e.removeAttribute(t);
73
+ },
74
+ p = function(e) {
75
+ var t = e.getClientRects()[0];
76
+ return { left: t.left + window.scrollX, top: t.top + window.scrollY };
77
+ },
78
+ h = function(e) {
79
+ c(e, "dragstart"), c(e, "dragend"), c(e, "selectstart"), c(
80
+ e,
81
+ "dragover"
82
+ ), c(e, "dragenter"), c(e, "drop");
83
+ },
84
+ g = function(e) {
85
+ c(e, "dragover"), c(e, "dragenter"), c(e, "drop");
86
+ },
87
+ m = function(e, t) {
88
+ (e.dataTransfer.effectAllowed = "move"), e.dataTransfer.setData(
89
+ "text",
90
+ ""
91
+ ), e.dataTransfer.setDragImage &&
92
+ e.dataTransfer.setDragImage(t.draggedItem, t.x, t.y);
93
+ },
94
+ v = function(e, t) {
95
+ return t.x || (t.x = parseInt(e.pageX - p(t.draggedItem).left)), t.y ||
96
+ (t.y = parseInt(e.pageY - p(t.draggedItem).top)), t;
97
+ },
98
+ y = function(e) {
99
+ return { draggedItem: e };
100
+ },
101
+ b = function(e, t) {
102
+ var n = y(t);
103
+ (n = v(e, n)), m(e, n);
104
+ },
105
+ E = function(e) {
106
+ i(e), u(e, "aria-dropeffect");
107
+ },
108
+ x = function(e) {
109
+ u(e, "aria-grabbed"), u(e, "draggable"), u(e, "role");
110
+ },
111
+ w = function(e, t) {
112
+ return (
113
+ e === t ||
114
+ (void 0 !== o(e, "connectWith") &&
115
+ o(e, "connectWith") === o(t, "connectWith"))
116
+ );
117
+ },
118
+ C = function(e, t) {
119
+ var n,
120
+ r = [];
121
+ if (!t) return e;
122
+ for (var a = 0; a < e.length; ++a)
123
+ (n = e[a].querySelectorAll(t)), (r = r.concat(
124
+ Array.prototype.slice.call(n)
125
+ ));
126
+ return r;
127
+ },
128
+ A = function(e) {
129
+ var t = o(e, "opts") || {},
130
+ n = l(q(e), t.items),
131
+ r = C(n, t.handle);
132
+ g(e), E(e), c(r, "mousedown"), h(n), x(n);
133
+ },
134
+ I = function(e) {
135
+ var t = o(e, "opts"),
136
+ n = l(q(e), t.items),
137
+ r = C(n, t.handle);
138
+ f(e, "aria-dropeffect", "move"), f(r, "draggable", "true");
139
+ var a = (document || window.document).createElement("span");
140
+ "function" != typeof a.dragDrop ||
141
+ t.disableIEFix ||
142
+ d(r, "mousedown", function() {
143
+ if (n.indexOf(this) !== -1) this.dragDrop();
144
+ else {
145
+ for (var e = this.parentElement; n.indexOf(e) === -1; )
146
+ e = e.parentElement;
147
+ e.dragDrop();
148
+ }
149
+ });
150
+ },
151
+ D = function(e) {
152
+ var t = o(e, "opts"),
153
+ n = l(q(e), t.items),
154
+ r = C(n, t.handle);
155
+ f(e, "aria-dropeffect", "none"), f(r, "draggable", "false"), c(
156
+ r,
157
+ "mousedown"
158
+ );
159
+ },
160
+ S = function(e) {
161
+ var t = o(e, "opts"),
162
+ n = l(q(e), t.items),
163
+ r = C(n, t.handle);
164
+ h(n), c(r, "mousedown"), g(e);
165
+ },
166
+ L = function(e) {
167
+ return e.parentElement
168
+ ? Array.prototype.indexOf.call(e.parentElement.children, e)
169
+ : 0;
170
+ },
171
+ O = function(e) {
172
+ return !!e.parentNode;
173
+ },
174
+ T = function(e, t) {
175
+ if ("string" != typeof e) return e;
176
+ var n = document.createElement(t);
177
+ return (n.innerHTML = e), n.firstChild;
178
+ },
179
+ W = function(e, t) {
180
+ e.parentElement.insertBefore(t, e);
181
+ },
182
+ M = function(e, t) {
183
+ e.parentElement.insertBefore(t, e.nextElementSibling);
184
+ },
185
+ N = function(e) {
186
+ e.parentNode && e.parentNode.removeChild(e);
187
+ },
188
+ P = function(e, t) {
189
+ var n = document.createEvent("Event");
190
+ return t && (n.detail = t), n.initEvent(e, !1, !0), n;
191
+ },
192
+ Y = function(e, t) {
193
+ a.forEach(function(n) {
194
+ w(e, n) && n.dispatchEvent(t);
195
+ });
196
+ },
197
+ q = function(e) {
198
+ return e.children;
199
+ },
200
+ z = function(i, c) {
201
+ var u = String(c);
202
+ return (c = (function(e) {
203
+ var t = {
204
+ connectWith: !1,
205
+ placeholder: null,
206
+ disableIEFix: !1,
207
+ placeholderClass: "sortable-placeholder",
208
+ draggingClass: "sortable-dragging",
209
+ hoverClass: !1,
210
+ debounce: 0
211
+ };
212
+ for (var n in e) t[n] = e[n];
213
+ return t;
214
+ })(c)), c &&
215
+ "function" == typeof c.getChildren &&
216
+ (q = c.getChildren), "string" == typeof i &&
217
+ (i = document.querySelectorAll(i)), i instanceof window.Element &&
218
+ (i = [i]), (i = Array.prototype.slice.call(i)), i.forEach(function(i) {
219
+ if (/enable|disable|destroy/.test(u)) return void z[u](i);
220
+ (c = o(i, "opts") || c), o(i, "opts", c), S(i);
221
+ var h,
222
+ g,
223
+ m = l(q(i), c.items),
224
+ v = c.placeholder;
225
+ if (
226
+ (
227
+ v ||
228
+ (v = document.createElement(
229
+ /^ul|ol$/i.test(i.tagName) ? "li" : "div"
230
+ )),
231
+ (v = T(v, i.tagName)),
232
+ v.classList.add.apply(v.classList, c.placeholderClass.split(" ")),
233
+ !i.getAttribute("data-sortable-id")
234
+ )
235
+ ) {
236
+ var y = a.length;
237
+ (a[y] = i), f(i, "data-sortable-id", y), f(
238
+ m,
239
+ "data-item-sortable-id",
240
+ y
241
+ );
242
+ }
243
+ if (
244
+ (
245
+ o(i, "items", c.items),
246
+ r.push(v),
247
+ c.connectWith && o(i, "connectWith", c.connectWith),
248
+ I(i),
249
+ f(m, "role", "option"),
250
+ f(m, "aria-grabbed", "false"),
251
+ c.hoverClass
252
+ )
253
+ ) {
254
+ var E = "sortable-over";
255
+ "string" == typeof c.hoverClass &&
256
+ (E = c.hoverClass), d(m, "mouseenter", function() {
257
+ this.classList.add(E);
258
+ }), d(m, "mouseleave", function() {
259
+ this.classList.remove(E);
260
+ });
261
+ }
262
+ d(m, "dragstart", function(e) {
263
+ e.stopImmediatePropagation(), (c.handle && !s(e.target, c.handle)) || "false" === this.getAttribute("draggable") || (b(e, this), this.classList.add(c.draggingClass), (t = this), f(t, "aria-grabbed", "true"), (h = L(t)), (n = parseInt(window.getComputedStyle(t).height)), (g = this.parentElement), Y(i, P("sortstart", { item: t, placeholder: v, startparent: g })));
264
+ }), d(m, "dragend", function() {
265
+ var e;
266
+ t &&
267
+ (
268
+ t.classList.remove(c.draggingClass),
269
+ f(t, "aria-grabbed", "false"),
270
+ (t.style.display = t.oldDisplay),
271
+ delete t.oldDisplay,
272
+ r.forEach(N),
273
+ (e = this.parentElement),
274
+ Y(i, P("sortstop", { item: t, startparent: g })),
275
+ (h === L(t) && g === e) ||
276
+ Y(
277
+ i,
278
+ P("sortupdate", {
279
+ item: t,
280
+ index: l(q(e), o(e, "items")).indexOf(t),
281
+ oldindex: m.indexOf(t),
282
+ elementIndex: L(t),
283
+ oldElementIndex: h,
284
+ startparent: g,
285
+ endparent: e
286
+ })
287
+ ),
288
+ (t = null),
289
+ (n = null)
290
+ );
291
+ }), d([i, v], "drop", function(e) {
292
+ var n;
293
+ w(i, t.parentElement) &&
294
+ (
295
+ e.preventDefault(),
296
+ e.stopPropagation(),
297
+ (n = r.filter(O)[0]),
298
+ M(n, t),
299
+ t.dispatchEvent(P("dragend"))
300
+ );
301
+ });
302
+ var x = e(function(e, a) {
303
+ if (t)
304
+ if (m.indexOf(e) !== -1) {
305
+ var o = parseInt(window.getComputedStyle(e).height),
306
+ i = L(v),
307
+ s = L(e);
308
+ if (
309
+ (c.forcePlaceholderSize && (v.style.height = n + "px"), o > n)
310
+ ) {
311
+ var d = o - n,
312
+ f = p(e).top;
313
+ if (i < s && a < f + d) return;
314
+ if (i > s && a > f + o - d) return;
315
+ }
316
+ void 0 === t.oldDisplay &&
317
+ (t.oldDisplay = t.style.display), (t.style.display =
318
+ "none"), i < s ? M(e, v) : W(e, v), r
319
+ .filter(function(e) {
320
+ return e !== v;
321
+ })
322
+ .forEach(N);
323
+ } else
324
+ r.indexOf(e) !== -1 ||
325
+ l(q(e), c.items).length ||
326
+ (r.forEach(N), e.appendChild(v));
327
+ }, c.debounce),
328
+ C = function(e) {
329
+ t &&
330
+ w(i, t.parentElement) &&
331
+ (
332
+ e.preventDefault(),
333
+ e.stopPropagation(),
334
+ (e.dataTransfer.dropEffect = "move"),
335
+ x(this, e.pageY)
336
+ );
337
+ };
338
+ d(m.concat(i), "dragover", C), d(m.concat(i), "dragenter", C);
339
+ }), i;
340
+ };
341
+ return (z.destroy = function(e) {
342
+ A(e);
343
+ }), (z.enable = function(e) {
344
+ I(e);
345
+ }), (z.disable = function(e) {
346
+ D(e);
347
+ }), z;
348
+ });
349
+ //# sourceMappingURL=html.sortable.min.js.map
@@ -0,0 +1,23 @@
1
+ //= require jquery
2
+ //= require jquery_ujs
3
+ //= require cocoon
4
+ //= require html.sortable.min
5
+
6
+ (function($) {
7
+ function setCorrectOrder() {
8
+ $("[data-ivaldi-content-blocks] .nested-fields").each(function(index) {
9
+ $(this).find("[data-sequence]").val(index);
10
+ });
11
+ }
12
+
13
+ $(document).on("ready page:load turbolinks:load", function() {
14
+ if ($("[data-ivaldi-content-blocks]").length > 0) {
15
+ sortable("[data-ivaldi-content-blocks]", {
16
+ placeholderClass: "sortable-placeholder",
17
+ forcePlaceholderSize: true
18
+ })[0].addEventListener("sortupdate", function(e) {
19
+ setCorrectOrder();
20
+ });
21
+ }
22
+ });
23
+ })(jQuery);
@@ -0,0 +1,52 @@
1
+ class PagesController < ApplicationController
2
+
3
+ before_action :pages_append_view_path
4
+
5
+ def index
6
+ @pages = Page.ordered
7
+ end
8
+
9
+ def new
10
+ @page = Page.new
11
+ end
12
+
13
+ def edit
14
+ @page = Page.find params[:id]
15
+ end
16
+
17
+ def create
18
+ @page = Page.new page_params
19
+ if @page.save
20
+ #TODO: set flash message?
21
+ redirect_to edit_page_url(@page.id)
22
+ else
23
+ render 'new'
24
+ end
25
+ end
26
+
27
+ def update
28
+ @page = Page.find params[:id]
29
+ if @page.update(page_params)
30
+ #TODO: set flash message?
31
+ redirect_to edit_page_url(@page.id)
32
+ else
33
+ render 'edit'
34
+ end
35
+ end
36
+
37
+ def destroy
38
+ @page.destroy
39
+ redirect_to admin_pages_url
40
+ end
41
+
42
+ protected
43
+
44
+ def pages_append_view_path
45
+ append_view_path IvaldiContentBuilder::Engine.root.join('app', 'views')
46
+ end
47
+
48
+ def page_params
49
+ ret = params.require(:page).permit!
50
+ end
51
+
52
+ end
@@ -0,0 +1,14 @@
1
+ class ContentBlock < ApplicationRecord
2
+ belongs_to :page
3
+ belongs_to :blockable, polymorphic: true, dependent: :destroy
4
+
5
+ accepts_nested_attributes_for :blockable, reject_if: :all_blank, allow_destroy: true
6
+ validates :blockable_type, presence: true
7
+
8
+ scope :ordered, -> { order(:sequence) }
9
+
10
+ def build_blockable(params)
11
+ self.blockable = blockable_type.constantize.new(params)
12
+ end
13
+
14
+ end
@@ -0,0 +1,9 @@
1
+ class Page < ApplicationRecord
2
+ has_many :content_blocks, dependent: :destroy
3
+ accepts_nested_attributes_for :content_blocks, reject_if: :all_blank,
4
+ allow_destroy: true
5
+
6
+ validates :title, presence: true
7
+
8
+ scope :ordered, -> { order(:title) }
9
+ end
@@ -0,0 +1 @@
1
+ <% #add fields_for for this type %>
@@ -0,0 +1,61 @@
1
+ <div class="nested-fields">
2
+ <div class="panel panel-default">
3
+ <% if f.object.blockable_type.present? %>
4
+ <div class="panel-heading u-cursor-move">
5
+ <%= link_to_remove_association f, class: 'pull-right', title: 'Verwijder' do %>
6
+ <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
7
+ <% end %>
8
+ <h3 class="panel-title">
9
+ <%= t("ivaldi_content_blocks.#{f.object.blockable_type}") %>
10
+ </h3>
11
+ </div>
12
+ <% end %>
13
+ <div class="panel-body">
14
+ <%= f.hidden_field :sequence, data: { sequence: true } %>
15
+ <div data-blockable-type>
16
+ <% if f.object.blockable_type.nil? %>
17
+
18
+ <% items = [] %>
19
+ <% if t('ivaldi_content_blocks').is_a? Hash %>
20
+ <% items = t('ivaldi_content_blocks').to_a %>
21
+ <% end %>
22
+
23
+ <%= f.collection_select :blockable_type,
24
+ items,
25
+ :first,
26
+ :last,
27
+ {
28
+ include_blank: 'Select type',
29
+ },
30
+ data: {
31
+ remote: true,
32
+ url: new_page_url
33
+ }
34
+ %>
35
+ <% end %>
36
+ </div>
37
+
38
+ <% t('ivaldi_content_blocks').keys.each do |blockable_type| %>
39
+
40
+ <% blockable = blockable_type.to_s.constantize.new %>
41
+
42
+ <% if f.object.blockable_type == blockable_type.to_s %>
43
+ <% blockable = f.object.blockable %>
44
+ <% elsif f.object.blockable_type.present? %>
45
+ <% next %>
46
+ <% end %>
47
+
48
+ <%= f.fields_for :blockable, blockable do |ff| %>
49
+ <div style="display: <%= f.object.blockable_type.nil? ? 'none' : 'block' %>;" data-content-block>
50
+ <%= render "ivaldi_content_blocks/#{blockable_type.to_s.underscore}_fields", f: ff %>
51
+ <% unless f.object.blockable_type.blank? %>
52
+ <%= f.hidden_field :blockable_type, value: f.object.blockable_type %>
53
+ <% end %>
54
+ <%= ff.hidden_field :_destroy, value: ff.object.new_record? ? 1 : 0, data: { 'field-type' => blockable_type } %>
55
+ </div>
56
+ <% end %>
57
+
58
+ <% end %>
59
+ </div>
60
+ </div>
61
+ </div>
@@ -0,0 +1,43 @@
1
+ <%= form_for @page do |f| %>
2
+ <div class="row">
3
+ <div class="col-lg-9">
4
+
5
+ <%= f.label :title %>
6
+ <%= f.text_field :title %>
7
+
8
+ <% unless @page.new_record? %>
9
+ <div class="form-group">
10
+ <div class="col-sm-12">
11
+ <div class="input-group">
12
+ <span class="input-group-addon">https://example.com/</span>
13
+ <%= f.label :slug %>
14
+ <%= f.text_field :slug %>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ <% end %>
19
+
20
+ <hr>
21
+
22
+ <div data-ivaldi-content-blocks>
23
+ <%= f.fields_for :content_blocks, @page.content_blocks.sort_by{ |cb| cb.sequence } do |content_block| %>
24
+ <div data-content-block-wrapper>
25
+ <%= render 'content_block_fields', f: content_block %>
26
+ </div>
27
+ <% end %>
28
+ </div>
29
+
30
+ <div class="well text-center">
31
+ <%= link_to_add_association 'Add block', f,
32
+ :content_blocks,
33
+ 'data-association-insertion-node' => '[data-ivaldi-content-blocks]',
34
+ 'data-association-insertion-method' => 'append'
35
+ %>
36
+ </div>
37
+
38
+ <%= f.submit %>
39
+
40
+ </div>
41
+
42
+ </div>
43
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <nav class="navbar navbar-static-top navbar-default">
2
+ <div class="container-fluid">
3
+ <div class="navbar-header">
4
+ <a href="<%= pages_path %>" class="navbar-brand">
5
+ &larr; Back
6
+ </a>
7
+ </span>
8
+ </div>
9
+ </div>
10
+ </nav>
11
+
12
+ <div class="container-fluid">
13
+ <div class="panel panel-default">
14
+ <div class="panel-heading">
15
+ <h3 class="panel-title">Edit page</h3>
16
+ </div>
17
+ <div class="panel-body">
18
+ <%= render 'form' %>
19
+ </div>
20
+ </div>
21
+ </div>
@@ -0,0 +1,34 @@
1
+ <nav class="navbar navbar-static-top navbar-default">
2
+ <div class="container-fluid">
3
+ <div class="navbar-header">
4
+ <span class="navbar-brand">
5
+ <%= @pages.count %> pages
6
+ </span>
7
+ </div>
8
+ <div class="collapse navbar-collapse">
9
+ <ul class="nav navbar-nav">
10
+ <li>
11
+ <a href="<%= new_page_path %>">
12
+ <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Nieuw
13
+ </a>
14
+ </li>
15
+ </ul>
16
+ </div>
17
+ </div>
18
+ </nav>
19
+
20
+ <div class="container-fluid">
21
+ <table class="table table-hover">
22
+ <thead>
23
+ <tr>
24
+ <th>Titel</th>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <% @pages.each do |page| %>
29
+ <tr>
30
+ <td><a href="<%= edit_page_path(page.id) %>"><%= page.title %></a></td>
31
+ </tr>
32
+ <% end %>
33
+ </table>
34
+ </div>
@@ -0,0 +1,21 @@
1
+ <nav class="navbar navbar-static-top navbar-default">
2
+ <div class="container-fluid">
3
+ <div class="navbar-header">
4
+ <a href="<%= pages_path %>" class="navbar-brand">
5
+ &larr; Back
6
+ </a>
7
+ </span>
8
+ </div>
9
+ </div>
10
+ </nav>
11
+
12
+ <div class="container-fluid">
13
+ <div class="panel panel-default">
14
+ <div class="panel-heading">
15
+ <h3 class="panel-title">New page</h3>
16
+ </div>
17
+ <div class="panel-body">
18
+ <%= render 'form' %>
19
+ </div>
20
+ </div>
21
+ </div>
@@ -0,0 +1,15 @@
1
+ <% blockable_id = params[:page][:content_blocks_attributes].keys.first %>
2
+
3
+ var content_block_id = <%= blockable_id %>;
4
+ var blockable_type = '<%= params[:page][:content_blocks_attributes][blockable_id]["blockable_type"] %>';
5
+
6
+ var destroy_input = jQuery('[name="page[content_blocks_attributes][' + content_block_id + '][blockable_attributes][_destroy]"][data-field-type="' + blockable_type + '"]');
7
+ var fieldset = destroy_input.closest('[data-ivaldi-content-blocks]');
8
+
9
+ destroy_input.val(0);
10
+ destroy_input.closest('[data-content-block]').show();
11
+
12
+ fieldset.find('[data-blockable-type]').hide();
13
+ fieldset.find('[data-content-block]:hidden').remove();
14
+
15
+ setCorrectOrder();
@@ -0,0 +1,16 @@
1
+ class CreateIvaldiContentBlocks < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :pages do |t|
4
+ t.string :title
5
+ t.string :slug
6
+ t.timestamps
7
+ end
8
+
9
+ create_table :content_blocks do |t|
10
+ t.references :page, foreign_key: true
11
+ t.references :blockable, polymorphic: true
12
+ t.integer :sequence, default: 0, null: false
13
+ t.timestamps
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ module Icb
2
+ class EjectGenerator < Rails::Generators::Base
3
+ def call
4
+ FileUtils.copy_entry '../../app/views/pages', 'app/views/pages'
5
+
6
+ FileUtils.copy_entry '../../app/controllers/pages_controller.rb', 'app/controllers/pages_controller.rb'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module Icb
2
+ class InstallGenerator < Rails::Generators::Base
3
+
4
+ def generate_migrations
5
+ timestamp = I18n.l Time.zone.now, format: '%Y%m%d%H%M%S'
6
+ create_file "db/migrate/#{timestamp}_create_ivaldi_content_blocks.rb",
7
+ File.read('../../db/migrate/create_ivaldi_content_blocks.rb')
8
+ end
9
+
10
+
11
+ end
12
+ end
@@ -0,0 +1,41 @@
1
+ module Icb
2
+ class NewBlockGenerator < Rails::Generators::Base
3
+
4
+ argument :attributes, type: :array
5
+
6
+ def call
7
+ @model_name = attributes.shift
8
+
9
+ create_migration
10
+ create_form_fields
11
+ add_field_to_translation
12
+ end
13
+
14
+ private
15
+
16
+ def create_migration
17
+ generate "model #{@model_name}", attributes.join(' ')
18
+ end
19
+
20
+ def create_form_fields
21
+ file_name = "app/views/ivaldi_content_blocks/_#{@model_name.underscore}_fields.html.erb"
22
+ create_file file_name, File.read('../../app/views/ivaldi_content_blocks/_field.html.erb')
23
+ end
24
+
25
+ def add_field_to_translation
26
+
27
+ file = File.open("./config/locales/#{I18n.locale}.yml")
28
+
29
+ translations = YAML.load_file(file)
30
+
31
+ if translations[I18n.locale.to_s][:ivaldi_content_blocks].nil?
32
+ translations[I18n.locale.to_s].merge!({ "ivaldi_content_blocks" => {} })
33
+ end
34
+
35
+ translations[I18n.locale.to_s]["ivaldi_content_blocks"].merge!(Hash[@model_name, @model_name])
36
+
37
+ File.open(file, 'w') {|f| f.write translations.to_yaml }
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module IvaldiContentBuilder
2
+ require 'ivaldi_content_builder/engine'
3
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'jquery-rails'
3
+ require 'cocoon'
4
+
5
+ module IvaldiContentBuilder
6
+ class Engine < Rails::Engine
7
+ config.autoload_paths += Dir["#{config.root}/app/**/"]
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :ivaldi_content_builder do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ivaldi-content-builder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Bas Schoenmakers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 5.1.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '5.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 5.1.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: cocoon
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.2'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.2'
47
+ - !ruby/object:Gem::Dependency
48
+ name: jquery-rails
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '4.3'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '4.3'
61
+ - !ruby/object:Gem::Dependency
62
+ name: sqlite3
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.3'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.3'
75
+ description: Create contentblocks and pages for admin environments.
76
+ email:
77
+ - bas@ivaldi.nl
78
+ executables: []
79
+ extensions: []
80
+ extra_rdoc_files: []
81
+ files:
82
+ - MIT-LICENSE
83
+ - README.md
84
+ - Rakefile
85
+ - app/assets/javascripts/html.sortable.min.js
86
+ - app/assets/javascripts/ivaldi_content_builder.js
87
+ - app/controllers/pages_controller.rb
88
+ - app/models/content_block.rb
89
+ - app/models/page.rb
90
+ - app/views/ivaldi_content_blocks/_field.html.erb
91
+ - app/views/pages/_content_block_fields.html.erb
92
+ - app/views/pages/_form.html.erb
93
+ - app/views/pages/edit.html.erb
94
+ - app/views/pages/index.html.erb
95
+ - app/views/pages/new.html.erb
96
+ - app/views/pages/new.js.erb
97
+ - db/migrate/create_ivaldi_content_blocks.rb
98
+ - lib/generators/icb/eject_generator.rb
99
+ - lib/generators/icb/install_generator.rb
100
+ - lib/generators/icb/new_block_generator.rb
101
+ - lib/ivaldi_content_builder.rb
102
+ - lib/ivaldi_content_builder/engine.rb
103
+ - lib/tasks/ivaldi_content_builder_tasks.rake
104
+ homepage: https://ivaldi.nl
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 2.6.11
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Create contentblocks and pages.
128
+ test_files: []