sibu 0.9.5 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +81 -4
  3. data/app/assets/javascripts/sibu/sibu.js.erb +17 -3
  4. data/app/assets/javascripts/tabs/van11y-accessible-tab-panel-aria.js +122 -124
  5. data/app/assets/stylesheets/sibu/defaults.scss +72 -80
  6. data/app/assets/stylesheets/sibu/sibu.css +20 -1
  7. data/app/controllers/sibu/application_controller.rb +8 -0
  8. data/app/controllers/sibu/pages_controller.rb +11 -4
  9. data/app/controllers/sibu/sites_controller.rb +6 -1
  10. data/app/helpers/sibu/application_helper.rb +1 -1
  11. data/app/helpers/sibu/pages_helper.rb +97 -16
  12. data/app/models/sibu/page.rb +0 -1
  13. data/app/models/sibu/site.rb +7 -0
  14. data/app/models/sibu/site_template.rb +1 -1
  15. data/app/views/layouts/sibu/edit_content.html.erb +220 -126
  16. data/app/views/sibu/images/edit.js.erb +5 -3
  17. data/app/views/sibu/pages/_code_edit_panel.html.erb +4 -3
  18. data/app/views/sibu/pages/_form.html.erb +8 -0
  19. data/app/views/sibu/pages/_link_edit_panel.html.erb +6 -6
  20. data/app/views/sibu/pages/_map_edit_panel.html.erb +3 -2
  21. data/app/views/sibu/pages/_media_edit_panel.html.erb +2 -2
  22. data/app/views/sibu/pages/_new_section_panel.html.erb +1 -1
  23. data/app/views/sibu/pages/_paragraph_edit_panel.html.erb +2 -2
  24. data/app/views/sibu/pages/_text_edit_panel.html.erb +2 -2
  25. data/app/views/sibu/pages/child_element.js.erb +2 -2
  26. data/app/views/sibu/pages/clone_element.js.erb +2 -2
  27. data/app/views/sibu/pages/create_section.js.erb +1 -1
  28. data/app/views/sibu/pages/delete_element.js.erb +1 -1
  29. data/app/views/sibu/pages/delete_section.js.erb +1 -1
  30. data/app/views/sibu/pages/edit.html.erb +1 -1
  31. data/app/views/sibu/pages/edit_element.js.erb +68 -66
  32. data/app/views/sibu/pages/edit_section.js.erb +6 -5
  33. data/app/views/sibu/pages/index.html.erb +3 -3
  34. data/app/views/sibu/pages/new_section.js.erb +22 -13
  35. data/app/views/sibu/pages/update_element.js.erb +2 -2
  36. data/app/views/sibu/pages/update_section.js.erb +3 -3
  37. data/app/views/sibu/sites/index.html.erb +1 -1
  38. data/db/migrate/20200401130601_add_ref_to_site_templates.rb +5 -0
  39. data/lib/sibu/engine.rb +0 -2
  40. data/lib/sibu/version.rb +1 -1
  41. metadata +3 -18
  42. data/app/views/sibu/pages/destroy.html.erb +0 -2
  43. data/app/views/sibu/pages/update.html.erb +0 -2
@@ -238,101 +238,93 @@ $sibu-color3 : #333 !default;
238
238
  }
239
239
 
240
240
  #sections_panel {
241
- position: relative;
242
-
243
- &:before {
244
- box-shadow: 0 -15px 15px -15px inset;
245
- content: " ";
246
- width: 100%;
247
- left: 0;
248
- top: -15px;
249
- position: absolute;
250
- z-index: 0;
251
- height: 15px;
252
- opacity: 0.4;
253
- color: $sibu-color3;
254
- }
255
-
256
- .sibu_sections_tabs, .tabs {
257
- height: 100%;
258
- }
259
-
260
- .sibu_sections {
241
+ .sibu_site_content {
261
242
  padding: 2rem;
262
243
  max-height: 60vh;
263
244
  overflow-y: scroll;
264
245
 
265
- .tabs__list {
266
- margin: 0;
267
- padding: 0;
268
- display: table;
269
- width: 100%;
270
- }
271
- .tabs__item {
272
- display: table-cell;
273
- > a {
274
- text-decoration: none;
275
- }
276
- }
246
+ & > .sibu_sections_tabs {
247
+ height: 100%;
277
248
 
278
- .tabs__link {
279
- display: inline-block;
280
- cursor: pointer;
281
- margin-bottom: -2px;
282
- padding: 1rem 2.5rem;
283
- border-bottom: 4px solid transparent;
284
- color: $sibu-color1;
285
- text-decoration: none;
286
- border-radius: 0 0 0 0;
287
- transition: .25s;
288
- transition-property: color, border, background-color;
289
- font-size: 2rem;
290
- &:focus {
291
- border-bottom-color: $sibu-color2;
292
- color: $sibu-color2;
293
- outline: 0;
294
- }
295
- }
249
+ & > .tabs {
250
+ height: 100%;
296
251
 
297
- [aria-selected="true"].tabs__link {
298
- border-bottom-color: $sibu-color2;
299
- color: $sibu-color2;
300
- outline: 0;
301
- }
252
+ & > .tabs__list {
253
+ margin: 0;
254
+ padding: 0;
255
+ display: table;
256
+ width: 100%;
302
257
 
303
- .tabs__content {
304
- padding: 2rem 0;
305
- background-color: white;
306
- max-height: calc(100% - 40px);
307
- overflow-y: scroll;
258
+ .tabs__item {
259
+ display: table-cell;
308
260
 
309
- > * {
310
- padding: 4px 0;
311
- margin: 0 1rem 2rem 1rem;
312
- min-height: auto;
313
- box-shadow: 0 0 5px #cdcdcd;
261
+ > a {
262
+ text-decoration: none;
263
+ }
264
+ }
314
265
 
315
- &:hover {
316
- cursor: pointer;
317
- outline: dashed $sibu-color2 4px;
318
- outline-offset: -5px;
319
- }
266
+ .tabs__link {
267
+ display: inline-block;
268
+ cursor: pointer;
269
+ margin-bottom: -2px;
270
+ padding: 1rem 2.5rem;
271
+ border-bottom: 4px solid transparent;
272
+ color: $sibu-color1;
273
+ text-decoration: none;
274
+ border-radius: 0 0 0 0;
275
+ transition: .25s;
276
+ transition-property: color, border, background-color;
277
+ font-size: 2rem;
278
+
279
+ &:focus {
280
+ border-bottom-color: $sibu-color2;
281
+ color: $sibu-color2;
282
+ outline: 0;
283
+ }
284
+ }
320
285
 
321
- &.selected {
322
- outline: solid $sibu-color1 5px;
323
- outline-offset: -5px;
286
+ [aria-selected="true"].tabs__link {
287
+ border-bottom-color: $sibu-color2;
288
+ color: $sibu-color2;
289
+ outline: 0;
290
+ }
324
291
  }
325
292
 
326
- > * {
327
- margin-top: 0 !important;
328
- margin-bottom: 0 !important;
293
+ & > .tabs__content {
294
+ padding: 2rem 0;
295
+ background-color: white;
296
+ max-height: calc(100% - 40px);
297
+ overflow-y: scroll;
298
+
299
+ > * {
300
+ padding: 4px 0;
301
+ margin: 0 1rem 2rem 1rem;
302
+ min-height: auto;
303
+ box-shadow: 0 0 5px #cdcdcd;
304
+
305
+ &:hover {
306
+ cursor: pointer;
307
+ outline: dashed $sibu-color2 4px;
308
+ outline-offset: -5px;
309
+ }
310
+
311
+ &.selected {
312
+ outline: solid $sibu-color1 5px;
313
+ outline-offset: -5px;
314
+ }
315
+
316
+ > * {
317
+ margin-top: 0 !important;
318
+ margin-bottom: 0 !important;
319
+ }
320
+ }
321
+
322
+ &[aria-hidden="true"] {
323
+ display: none;
324
+ }
329
325
  }
330
326
  }
331
327
  }
332
-
333
- [aria-hidden="true"].tabs__content {
334
- display: none;
335
- }
336
328
  }
337
329
 
338
330
  .sibu_actions {
@@ -3,10 +3,21 @@
3
3
  *= require_self
4
4
  */
5
5
 
6
- .sibu_content_panel {
6
+ body.sibu_edit_content, .sibu_content_panel {
7
7
  position: relative
8
8
  }
9
9
 
10
+ body.sibu_edit_content > .sibu_panel:first-child {
11
+ position: fixed;
12
+ width: 100%;
13
+ z-index: 999999;
14
+ top: 0;
15
+ }
16
+
17
+ body.sibu_edit_content > .sibu_content_panel {
18
+ padding-top: 60px;
19
+ }
20
+
10
21
  .sb-editable {
11
22
  cursor: pointer;
12
23
  outline: dashed rgba(94, 219, 255, 0.8) 3px;
@@ -63,6 +74,10 @@
63
74
  background-color: white;
64
75
  }
65
76
 
77
+ #edit_panel.active, #sections_panel.active {
78
+ display: block;
79
+ }
80
+
66
81
  #element_actions button {
67
82
  display: none;
68
83
  }
@@ -78,6 +93,10 @@
78
93
  cursor: pointer;
79
94
  }
80
95
 
96
+ #edit_overlays > *:hover {
97
+ opacity: 1;
98
+ }
99
+
81
100
  .sb-editing [data-type] {
82
101
  min-width: 1em;
83
102
  min-height: 0.5em;
@@ -10,5 +10,13 @@ module Sibu
10
10
  def sibu_user
11
11
  send(conf[:current_user])
12
12
  end
13
+
14
+ def check_site_ownership!
15
+ if conf[:multi_user] && conf[:admin_filter]
16
+ unless @site.nil? || @site.user_id == sibu_user.id || conf[:admin_filter].call(sibu_user)
17
+ redirect_to main_app.root_url, alert: "Vous n'êtes pas autorisé(e) à consulter cette page."
18
+ end
19
+ end
20
+ end
13
21
  end
14
22
  end
@@ -2,6 +2,7 @@ require_dependency "sibu/application_controller"
2
2
 
3
3
  module Sibu
4
4
  class PagesController < ApplicationController
5
+ before_action :compile_assets, only: [:show, :edit_content]
5
6
  before_action :set_page, only: [:edit, :update, :destroy, :duplicate, :edit_element, :update_element, :clone_element,
6
7
  :delete_element, :child_element, :new_section, :create_section, :edit_section,
7
8
  :update_section, :delete_section]
@@ -10,6 +11,7 @@ module Sibu
10
11
  :child_element, :new_section, :create_section, :edit_section,
11
12
  :update_section, :delete_section]
12
13
  before_action :set_online, only: [:show, :edit]
14
+
13
15
  skip_before_action Rails.application.config.sibu[:auth_filter], only: [:show]
14
16
 
15
17
  def index
@@ -44,7 +46,7 @@ module Sibu
44
46
  end
45
47
 
46
48
  def new
47
- @page = Sibu::Page.new(site_id: @site.id)
49
+ @page = Sibu::Page.new(site_id: @site.id, source: 'Saisie manuelle')
48
50
  end
49
51
 
50
52
  def create
@@ -101,9 +103,9 @@ module Sibu
101
103
  @content_type = params[:content_type]
102
104
  @links = @site.pages_path_by_id if @site
103
105
  @element = @entity.element(*@section_id.split('|'), *@element_id.split('|'))
104
- @repeat = params[:repeat]
106
+ @repeat = params[:repeat] == 'true'
107
+ @children = params[:children] == 'true'
105
108
  @size = params[:size].blank? ? :medium : params[:size].to_sym
106
- @children = params[:children]
107
109
  end
108
110
 
109
111
  def update_element
@@ -146,7 +148,6 @@ module Sibu
146
148
  end
147
149
 
148
150
  def update_section
149
- # {"utf8"=>"✓", "section"=>{"color"=>"#AFCA0B", "filters"=>"school_camps"}, "section_id"=>"cs1536301729", "refresh"=>"true", "commit"=>"Valider", "site_id"=>"3", "id"=>"1392"}
150
151
  @entity.section(params[:section_id]).merge!(section_params)
151
152
  logger.debug @entity.section(params[:section_id])
152
153
  @updated = @entity.save
@@ -161,10 +162,12 @@ module Sibu
161
162
  def set_page
162
163
  @page = Sibu::Page.find(params[:id])
163
164
  @site = Sibu::Site.includes(:pages).find(@page.site_id) if @page
165
+ check_site_ownership!
164
166
  end
165
167
 
166
168
  def set_site
167
169
  @site = Sibu::Site.find(params[:site_id])
170
+ check_site_ownership!
168
171
  end
169
172
 
170
173
  def set_edit_context
@@ -193,5 +196,9 @@ module Sibu
193
196
  def show_params
194
197
  params.permit!
195
198
  end
199
+
200
+ def compile_assets
201
+ Sibu::DynamicStyle.new(params[:site_id]).compile if Rails.env.development? && conf[:custom_styles] && !params[:site_id].blank?
202
+ end
196
203
  end
197
204
  end
@@ -6,7 +6,11 @@ module Sibu
6
6
  skip_before_action Rails.application.config.sibu[:auth_filter], only: [:show]
7
7
 
8
8
  def index
9
- @sites = Sibu::Site.for_user(sibu_user).order(:name, :version)
9
+ if conf[:admin_filter].call(sibu_user)
10
+ @sites = Sibu::Site.all.order(:name, :version)
11
+ else
12
+ @sites = Sibu::Site.for_user(sibu_user).order(:name, :version)
13
+ end
10
14
  end
11
15
 
12
16
  def show
@@ -70,6 +74,7 @@ module Sibu
70
74
 
71
75
  def set_site
72
76
  @site = Sibu::Site.find(params[:id])
77
+ check_site_ownership!
73
78
  end
74
79
 
75
80
  def site_params
@@ -5,7 +5,7 @@ module Sibu
5
5
  end
6
6
 
7
7
  def sibu_user
8
- send(Rails.application.config.sibu[:current_user])
8
+ send(conf[:current_user])
9
9
  end
10
10
  end
11
11
  end
@@ -7,6 +7,10 @@ module Sibu
7
7
  p ? (request.host == conf[:host] ? site_page_path(@site.id, p.id) : (conf[:deployment_path] ? "/#{conf[:deployment_path]}/#{p.path}" : "/#{p.path}")) : "#"
8
8
  end
9
9
 
10
+ def is_current_page(link_val)
11
+ /\d+/.match?(link_val) && link_val.to_i == @page.id
12
+ end
13
+
10
14
  def sections_templates
11
15
  @site.site_template.available_sections
12
16
  end
@@ -35,27 +39,78 @@ module Sibu
35
39
  end
36
40
  end
37
41
 
38
- [:h1, :h2, :h3, :h4, :h5, :h6, :span].each do |t|
39
- define_method(t) do |elt, html_opts = {}|
40
- defaults = {"id" => elt.is_a?(Hash) ? elt["id"] : elt, "text" => Sibu::DEFAULT_TEXT}
42
+ [:h1, :h2, :h3, :h4, :h5, :h6, :span, :p, :li].each do |t|
43
+ define_method(t) do |elt, opts = {}, &block|
44
+ t_id = elt.is_a?(Hash) ? elt["id"] : elt
45
+ defaults = {"id" => t_id, "text" => (t == :p ? Sibu::DEFAULT_PARAGRAPH : Sibu::DEFAULT_TEXT)}
41
46
  content = defaults.merge(elt.is_a?(Hash) ? elt : (select_element(elt) || {}))
42
- html_opts.merge!({data: {id: elt_id(elt), type: "text"}}) if action_name != 'show'
43
- content_tag(t, raw(content["text"]).html_safe, html_opts)
47
+ html_opts = {"id" => t_id}.merge(opts.except(:repeat, :children).stringify_keys)
48
+ @sb_section = (@sb_section || []) + [t_id]
49
+ if action_name != 'show'
50
+ html_opts.merge!({
51
+ "data-id" => @sb_section[1..-1].join('|'),
52
+ "data-type" => (t == :p ? "paragraph" : "text"),
53
+ "data-repeat" => opts.delete(:repeat),
54
+ "data-children" => opts.delete(:children)
55
+ })
56
+ end
57
+ if block
58
+ if t == :p
59
+ html_output = content_tag(:div, content_tag(t, capture(content, nested_elements(elt), &block)), html_opts)
60
+ else
61
+ html_output = content_tag(t, capture(content, nested_elements(t_id), &block), html_opts)
62
+ end
63
+ else
64
+ if t == :p
65
+ html_output = content_tag(:div, content_tag(t, raw(content["text"]).html_safe), html_opts)
66
+ else
67
+ html_output = content_tag(t, raw(content["text"]).html_safe, html_opts)
68
+ end
69
+ end
70
+ @sb_section -= [t_id]
71
+ html_output
44
72
  end
45
73
  end
46
74
 
47
- def p(elt, opts = {})
48
- repeat = opts.delete(:repeat)
49
- defaults = {"id" => elt.is_a?(Hash) ? elt["id"] : elt, "text" => Sibu::DEFAULT_PARAGRAPH}
50
- content = defaults.merge(elt.is_a?(Hash) ? elt : (select_element(elt) || {}))
51
- opts.merge!({data: {id: elt_id(elt), repeat: repeat, type: "paragraph"}}) if action_name != 'show'
52
- content_tag(:div, content_tag(:p, raw(content["text"]).html_safe), opts)
75
+ [:div, :section, :article, :aside, :header, :footer, :nav, :main, :ul, :ol, :wrapper].each do |t|
76
+ define_method(t) do |elt, opts = {}, &block|
77
+ t_id = elt.is_a?(Hash) ? elt["id"] : elt
78
+ @sb_section = (@sb_section || []) + [t_id]
79
+ html_opts = {"id" => t_id}.merge(opts.except(:repeat, :children).stringify_keys)
80
+ if action_name != 'show'
81
+ html_opts.merge!({
82
+ "data-id" => @sb_section[1..-1].join('|'),
83
+ "data-type" => "group",
84
+ "data-repeat" => opts.delete(:repeat),
85
+ "data-children" => opts.delete(:children)
86
+ })
87
+ end
88
+ html_output = t == :wrapper ? capture(current_elt(elt), nested_elements(t_id), &block) : content_tag(t, capture(current_elt(elt), nested_elements(t_id), &block), html_opts)
89
+ @sb_section -= [t_id]
90
+ html_output
91
+ end
53
92
  end
54
93
 
55
94
  def sb
56
95
  self
57
96
  end
58
97
 
98
+ def join_tokens(tokens, suffix)
99
+ (tokens + [suffix]).select {|t| !t.blank?}.join("|")
100
+ end
101
+
102
+ # Note : the best option is probably a "section" helper that is instantiated from the section hash
103
+ # and that provides all the logic for elements manipulation (ex: section.h3(), section.elements, section.elements(nested_id), etc...)
104
+ # That will also remove the entity type references (site / page) from the partials (but is still has to be figured out by Sibu)
105
+ # Note : add "each_with_elements" and "elements" on section/elts enumerables
106
+ def nested_elements(elt_or_id)
107
+ element_id = elt_id(elt_or_id)
108
+ element_id_tokens = (@sb_section + element_id.split("|")).uniq
109
+ nested_elts = @sb_entity.elements(*element_id_tokens)
110
+ nested_elts.blank? ? [{"id" => element_id.split("|").last, "data-id" => join_tokens(element_id_tokens[1..-1], "#{element_id}0")}] :
111
+ nested_elts.map {|e| e.merge({"data-id" => join_tokens(element_id_tokens[1..-1], e['id'])})}
112
+ end
113
+
59
114
  def select_element(id)
60
115
  @sb_entity.element(*@sb_section, id)
61
116
  end
@@ -133,9 +188,28 @@ module Sibu
133
188
 
134
189
  alias site sb_site
135
190
 
191
+ def render_page_section(s)
192
+ @sb_section = [s['id']]
193
+ @sb_entity = @page
194
+ render partial: "shared/#{@site.section_template(s)}",
195
+ locals: {sibu: self, sibu_section: s, sibu_attrs: sibu_attributes(s).html_safe}
196
+ end
197
+
198
+ # Page sections attrs
199
+ def sibu_attributes(section)
200
+ action_name != 'show' ? ('data-sb-id="' + section['id'] + '" data-sb-entity="page"') : ''
201
+ end
202
+
203
+ # Site sections attrs
204
+ def sibu_attrs(section_id)
205
+ @sb_section = [section_id]
206
+ @sb_entity = @site
207
+ action_name != 'show' ? ('data-sb-id="' + section_id + '" data-sb-entity="site"').html_safe : ''
208
+ end
209
+
136
210
  def section(id, tag, html_opts = {}, &block)
137
211
  @sb_section = [id]
138
- opts = action_name != 'show' ? html_opts.merge({"data-sb-id" => id, "data-sb-repeat" => @sb_entity != @site, "data-sb-entity" => @sb_entity == @site ? 'site' : 'page'}) : html_opts
212
+ opts = action_name != 'show' ? html_opts.merge({"data-sb-id" => id, "data-sb-entity" => @sb_entity == @site ? 'site' : 'page'}) : html_opts
139
213
  content_tag(tag, capture(self, &block), opts)
140
214
  end
141
215
 
@@ -156,7 +230,8 @@ module Sibu
156
230
  repeat = html_opts.delete(:repeat)
157
231
  children = html_opts.delete(:children)
158
232
  defaults = {"id" => elt_id(elt), "value" => "", "text" => Sibu::DEFAULT_TEXT}
159
- content = defaults.merge(elt.is_a?(Hash) ? elt : (select_element(elt) || {}))
233
+ link_elt = current_elt(elt)
234
+ content = defaults.merge(link_elt)
160
235
  val = content.delete("value") || ""
161
236
  text = content.delete("text")
162
237
  html_opts.merge!({data: {id: elt_id(elt), type: "link", repeat: repeat, children: children}}) if action_name != 'show'
@@ -172,16 +247,18 @@ module Sibu
172
247
  else
173
248
  content["href"] = @links.keys.include?(val.to_s) ? (action_name == 'show' ? link_path(val) : site_page_edit_content_path(@site.id, val)) : '#'
174
249
  end
175
- # Note : sends elts in given order
176
250
  if block_given?
177
- content_tag(:a, capture(*([raw(text)] + elts(elt)), &block), content.merge(html_opts).except("elements"))
251
+ @sb_section = (@sb_section || []) + [elt_id(elt)]
252
+ html_output = content_tag(:a, capture(link_elt, elts(elt), &block), content.merge(html_opts).except("elements"))
253
+ @sb_section -= [elt_id(elt)]
254
+ html_output
178
255
  else
179
256
  content_tag(:a, raw(text), content.merge(html_opts).except("elements"))
180
257
  end
181
258
  end
182
259
 
183
260
  def interactive_map(elt, html_opts = {})
184
- defaults = {"data-lat" => "45.68854", "data-lng" => "5.91587", "data-title" => Sibu::DEFAULT_TEXT}
261
+ defaults = {"data-lat" => "46.1988027", "data-lng" => "5.1748288", "data-title" => Sibu::DEFAULT_TEXT}
185
262
  content = defaults.merge(elt.is_a?(Hash) ? elt : (select_element(elt) || {"id" => elt}))
186
263
  html_opts.merge!({data: {id: elt_id(elt), type: "map"}}) if action_name != 'show'
187
264
  content_tag(:div, nil, content.merge(html_opts))
@@ -191,6 +268,10 @@ module Sibu
191
268
  elt.is_a?(Hash) ? (elt["data-id"] || elt["id"]) : elt
192
269
  end
193
270
 
271
+ def current_elt(elt)
272
+ (elt.is_a?(Hash) ? elt : (select_element(elt) || {})).except('elements')
273
+ end
274
+
194
275
  def default_content(type)
195
276
  case type
196
277
  when "text"