sibu 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c6ac6fcc8741cda28364f1a319bfa2d24dc605ef
4
- data.tar.gz: ebc4761b97ed9186af7322a5cc51de3f7c5d2988
3
+ metadata.gz: 7635dae443f7cd9cea480558c4d28d1595e8b0dd
4
+ data.tar.gz: dd93b5227313bcd4f6863191261a6fae389b5310
5
5
  SHA512:
6
- metadata.gz: 28bbc4e555c5e63c7bc0316366a2ebcaf3cbe353358ac3894cc127b37a573651cba3c47d7f9f29ee3cb9f750713668234ab29bf7496326618dfcae7663f8882b
7
- data.tar.gz: 3afce7820f8452e608f62c2825cd2ad4c6cf2e6eb008152690a66b8a00ab26481754bfa2a48192262bbbecf1f649277884652ac8dca79d88eb4f720725e2fc40
6
+ metadata.gz: 0525e546145a52500ae365f916c992e8dbb02bb1473dc7e94ef1b3b77975bb77e0b7d1e1f66ab717fcf7dfb5403616d1513cc6a4e035f535d8025f90d8f5bcec
7
+ data.tar.gz: b208922425d9433c712b40356f8be17fb67b32fbd3391028e5ef4b19415c2ed94f7e006d8813b57589a64883bcef70c8d371f4d9bf37bfdb5bf8a4f287aba1d7
@@ -1,3 +1,4 @@
1
1
  //= require jquery
2
2
  //= require jquery_ujs
3
+ //= require tinymce-jquery
3
4
  //= require_self
@@ -1,33 +1,11 @@
1
- sb-edit,
2
- [class*='sb-'] {
3
- position: relative;
4
-
5
- &:hover > .sb-overlay {
1
+ sb-edit {
2
+ .sb-edit-active {
6
3
  cursor: pointer;
7
- display: flex;
8
- }
9
- }
10
-
11
- .sb-overlay {
12
- position: absolute;
13
- top: 0;
14
- left: 0;
15
- z-index: 999;
16
- width: 100%;
17
- height: 100%;
18
- display: none;
19
- flex-wrap: wrap;
20
- align-items: center;
21
- justify-content: center;
22
- text-align: center;
23
-
24
- > * {
25
- flex: 1 1 0%;
26
4
  }
27
5
  }
28
6
 
29
7
  #edit_panel {
30
- position: absolute;
8
+ position: fixed;
31
9
  left: 0;
32
10
  bottom: 0;
33
11
  width: 100%;
@@ -16,6 +16,7 @@ module Sibu
16
16
  @site = Sibu::Site.find_by_domain(request.domain)
17
17
  if @site
18
18
  @page = @site.page(params[:path])
19
+ @links = @site.internal_links
19
20
  view_template = @page ? 'show' : @site.not_found
20
21
  else
21
22
  view_template = Rails.application.config.sibu[:not_found]
@@ -23,6 +24,7 @@ module Sibu
23
24
  else
24
25
  @site = Sibu::Site.find(params[:site_id])
25
26
  @page = Sibu::Page.find(params[:id])
27
+ @links = @site.internal_links
26
28
  view_template = 'show'
27
29
  end
28
30
 
@@ -60,7 +62,8 @@ module Sibu
60
62
 
61
63
  def edit_content
62
64
  @page = Sibu::Page.find(params[:page_id])
63
- @site = @page.site if @page
65
+ @site = Sibu::Site.includes(:pages).find(@page.site_id) if @page
66
+ @links = @site.internal_links if @site
64
67
  render :edit_content, layout: 'sibu/edit_content'
65
68
  end
66
69
 
@@ -68,7 +71,7 @@ module Sibu
68
71
  end
69
72
 
70
73
  def update_element
71
- @updated = @entity.update_element(@section_id, @element_id, element_params)
74
+ @updated = @entity.update_element(@section_id, element_params)
72
75
  end
73
76
 
74
77
  def edit_section
@@ -81,7 +84,7 @@ module Sibu
81
84
 
82
85
  def set_page
83
86
  @page = Sibu::Page.find(params[:id])
84
- @site = @page.site if @page
87
+ @site = Sibu::Site.includes(:pages).find(@page.site_id) if @page
85
88
  end
86
89
 
87
90
  def set_site
@@ -20,8 +20,7 @@ module Sibu
20
20
 
21
21
  def create
22
22
  @site = Sibu::Site.new(site_params)
23
- @site.init_data(:default)
24
- if @site.save
23
+ if @site.save_and_init(:default)
25
24
  redirect_to sites_url, notice: "Le site a bien été créé."
26
25
  else
27
26
  flash.now[:alert] = "Une erreur s'est produite lors de la création du site."
@@ -1,5 +1,7 @@
1
1
  module Sibu
2
2
  module PagesHelper
3
+ include Sibu::Engine.routes.url_helpers
4
+
3
5
  def link_path(page_id)
4
6
  p = @site.page_by_id(page_id)
5
7
  p ? (@site.domain.blank? ? site_page_path(@site.id, p.id) : "/#{p.path}") : "#"
@@ -12,5 +14,67 @@ module Sibu
12
14
  def page_languages
13
15
  [['Français', 'fr'], ['Anglais', 'en']]
14
16
  end
17
+
18
+ [:h1, :h2, :h3, :h4, :h5, :h6, :p, :span, :div, :label].each do |t|
19
+ define_method(t) do |id_or_elt, html_opts = {}|
20
+ content = id_or_elt.is_a?(Hash) ? (id_or_elt || {"text" => "Texte à modifier"}) : (select(id_or_elt) || {"text" => "Texte à modifier"})
21
+ html_opts.merge!({class: "sb-#{t} #{html_opts[:class]}", data: {id: id_or_elt.is_a?(Hash) ? id_or_elt["id"] : id_or_elt}}) if action_name != 'show'
22
+ content_tag(t, raw(content["text"]).html_safe, html_opts)
23
+ end
24
+ end
25
+
26
+ def sb
27
+ self
28
+ end
29
+
30
+ def select(id)
31
+ @sb_entity.section(@sb_section).select {|elt| elt["id"] == id}.first
32
+ end
33
+
34
+ def site_section(id, &block)
35
+ @sb_entity = @site
36
+ @sb_section = id
37
+ capture(self, &block)
38
+ end
39
+
40
+ def section(id, &block)
41
+ @sb_entity = @page
42
+ @sb_section = id
43
+ capture(self, &block)
44
+ end
45
+
46
+ def each
47
+ # Todo : init array when empty
48
+ @sb_entity.section(@sb_section).each do |elt|
49
+ yield(elt.except("elements"), elt["elements"])
50
+ end
51
+ end
52
+
53
+ def each_elements
54
+ @sb_entity.section(@sb_section).each do |elt|
55
+ yield(*elt["elements"])
56
+ end
57
+ end
58
+
59
+ def img(id_or_elt, html_opts = {})
60
+ content = id_or_elt.is_a?(Hash) ? (id_or_elt || {"src" => "/default.jpg"}) : (select(id_or_elt) || {"src" => "/default.jpg"})
61
+ opts = action_name == 'show' ? html_opts.merge({class: "sb-img #{html_opts[:class]}", data: {id: id_or_elt.is_a?(Hash) ? id_or_elt["id"] : id_or_elt}}) : html_opts
62
+ content_tag(:img, nil, content.except("id").merge(opts))
63
+ end
64
+
65
+ def link(id_or_elt, html_opts = {}, &block)
66
+ content = id_or_elt.is_a?(Hash) ? (id_or_elt || {"value" => "", "text" => "Nouveau lien"}) : (select(id_or_elt) || {"value" => "", "text" => "Nouveau lien"})
67
+ val = content["value"] || ""
68
+ if val.to_s.include?('http')
69
+ href = val
70
+ else
71
+ href = @links.keys.include?(val) ? (action_name == 'show' ? site_page_path(@site.id, val) : site_page_edit_content_path(@site.id, val)) : '#'
72
+ end
73
+ if block_given?
74
+ content_tag(:a, {href: href}.merge(html_opts), &block)
75
+ else
76
+ content_tag(:a, content["text"], {href: href}.merge(html_opts))
77
+ end
78
+ end
15
79
  end
16
80
  end
@@ -2,34 +2,47 @@ module Sibu
2
2
  module SectionsConcern
3
3
  include ActiveSupport::Concern
4
4
 
5
- def section(*ids)
6
- if ids.length == 1
5
+ def section(id)
6
+ # elts = nil
7
+ # if ids.length == 1
7
8
  s = nil
8
9
  if sections.blank?
9
10
  self.sections = {}
10
11
  else
11
- s = sections[ids[0]]
12
+ s = sections[id]
12
13
  end
13
14
  if s.nil?
14
15
  s = []
15
- self.sections[ids[0]] = s
16
+ self.sections[id] = s
16
17
  save
17
18
  end
18
19
  s
19
- elsif ids.length == 2
20
- s = section(ids[0])
21
- sub = s.select {|elt| elt["id"] == ids[1]}
22
- unless sub
23
- sub = {"id" => ids[1], "elements" => []}
24
- self.sections[ids[0]] << sub
25
- save
26
- end
27
- sub
20
+ # elsif ids.length == 2
21
+ # s = section(ids[0])
22
+ # sub = s.select {|elt| elt["id"] == ids[1]}
23
+ # unless sub
24
+ # sub = {"id" => ids[1], "elements" => []}
25
+ # self.sections[ids[0]] << sub
26
+ # save
27
+ # end
28
+ # elts = sub
29
+ # end
30
+ # elts.blank? ? {"default" => {}} : Hash[elts.map {|e| [e["id"], e.except("id")]}]
31
+ end
32
+
33
+ def subsection(id, subid)
34
+ s = section(id)
35
+ sub = s.select {|elt| elt["id"] == ids[1]}
36
+ unless sub
37
+ sub = {"id" => ids[1], "elements" => []}
38
+ self.sections[ids[0]] << sub
39
+ save
28
40
  end
41
+ elts = sub
29
42
  end
30
43
 
31
44
  def element(section_id, element_id)
32
- elt = section(section_id).select {|e| e["id"] == element_id}.first
45
+ elt = section(section_id)[element_id]
33
46
  elt || {}
34
47
  end
35
48
 
@@ -37,17 +50,13 @@ module Sibu
37
50
  end
38
51
 
39
52
  # Note : only 2 levels supported for now
40
- def update_element(*ids, value)
41
- updated = nil
42
- if ids.length > 1
43
- if self.sections[ids[0]].any? {|elt| elt["id"] == ids[1]}
44
- self.sections[ids[0]].map! {|elt| elt["id"] == ids[1] ? elt.value : elt}
45
- else
46
- self.sections[ids[0]] << {"id" => ids[1]}.merge(value)
47
- end
48
- updated = value if save
53
+ def update_element(section_id, value)
54
+ if self.sections[section_id].any? {|elt| elt["id"] == value["id"]}
55
+ self.sections[section_id].map! {|elt| elt["id"] == value["id"] ? value : elt}
56
+ else
57
+ self.sections[section_id] << value
49
58
  end
50
- updated
59
+ value if save
51
60
  end
52
61
  end
53
62
  end
@@ -23,12 +23,30 @@ module Sibu
23
23
  pages.where(id: page_id).first
24
24
  end
25
25
 
26
- def init_data(source)
26
+ def save_and_init(source)
27
+ ActiveRecord::Base.transaction do
28
+ save!
29
+ init_pages(source)
30
+ init_sections(source)
31
+ end
32
+ end
33
+
34
+ def internal_links
35
+ Hash[pages.collect {|p| [p.id, p.path]}]
36
+ end
37
+
38
+ def init_pages(source)
27
39
  site_data = Rails.application.config.sibu[:site_data][source]
28
- self.sections = site_data.sections
29
40
  site_data.pages.each do |p|
30
41
  self.pages << Sibu::Page.new(p)
31
42
  end
43
+ save!
44
+ end
45
+
46
+ def init_sections(source)
47
+ site_data = Rails.application.config.sibu[:site_data][source]
48
+ self.sections = site_data.sections(self)
49
+ save!
32
50
  end
33
51
  end
34
52
  end
@@ -8,7 +8,7 @@
8
8
  <%= javascript_include_tag 'sibu/sibu' %>
9
9
  <% if @site %>
10
10
  <%= stylesheet_link_tag @site.site_template.path, media: "all" %>
11
- <%= javascript_include_tag @site.site_template.path %>
11
+ <%= javascript_include_tag "#{@site.site_template.path}-core" %>
12
12
  <% end %>
13
13
  <%= csrf_meta_tags %>
14
14
  </head>
@@ -23,26 +23,64 @@
23
23
  <div id="edit_panel" class="sibu_view"></div>
24
24
 
25
25
  <script>
26
- $(function() {
27
- initOverlays();
28
- });
29
-
30
- function initOverlays() {
31
- var elts = $("[class*='sb-']");
32
- elts.each(function() {
33
- var elt = $(this);
34
- elt.find(".sb-overlay").remove();
35
- var section = elt.parents("sb-edit").first();
36
- var eltId = elt.data("id"), sectionId = section.data("id"), entity = section.data("entity");
37
- elt.append(
38
- '<div class="sb-overlay sibu_panel">' +
39
- '<a href="<%= edit_element_site_page_path(@site.id, @page.id) %>?element_id=' + eltId + '&section_id=' + sectionId +
40
- '&entity=' + entity + '" data-remote="true">Modifier</a>' +
41
- '</div>'
42
- );
43
- });
44
-
45
- }
26
+ $(function () {
27
+ initOverlays();
28
+ });
29
+
30
+ function initOverlays() {
31
+ const textTags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'p', 'span'];
32
+
33
+ var elts = $("[class*='sb-']");
34
+ elts.each(function () {
35
+ var previous;
36
+ var elt = $(this), tag = elt.prop("tagName").toLowerCase(), width = elt.width(),
37
+ height = elt.height(), display = elt.css("display"), padding = elt.css("padding"), margin = elt.css("margin");
38
+ var section = elt.parents("sb-edit").first();
39
+ var eltId = elt.data("id"), sectionId = section.data("id"), entity = section.data("entity");
40
+ var overlayElt = $(editOverlay(width, height, display, padding, margin));
41
+ bindMouseEnter(elt, overlayElt, eltId, sectionId, entity);
42
+ });
43
+
44
+ function bindMouseEnter(element, overlay, elementId, sectionId, entity) {
45
+ element.mouseenter(function () {
46
+ overlay.replaceAll(element);
47
+ overlay.addClass("sb-edit-active sibu_panel");
48
+ overlay.click(function() {
49
+ editContent(elementId, sectionId, entity)
50
+ });
51
+ bindMouseLeave(element, overlay, elementId, sectionId, entity);
52
+ });
53
+ }
54
+
55
+ function bindMouseLeave(element, overlay, elementId, sectionId, entity) {
56
+ overlay.mouseleave(function() {
57
+ overlay.removeClass("sb-edit-active sibu_panel");
58
+ element.replaceAll(overlay);
59
+ bindMouseEnter(element, overlay, elementId, sectionId, entity);
60
+ });
61
+ }
62
+
63
+ function editOverlay(width, height, display, padding, margin) {
64
+ return '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
65
+ 'style="box-sizing: content-box; display: ' + display + '; padding: ' + padding + '; margin: ' + margin + ';"' +
66
+ 'viewBox="0 0 ' + width + ' ' + height + '" width="' + width + 'px" height="' + height + 'px">' +
67
+ '<rect width="' + width + '" height="' + height + '" x="0" y="0" fill="#dedede"/>' +
68
+ '</svg>';
69
+ }
70
+
71
+ function editContent(eltId, sectionId, entity) {
72
+ $.ajax({
73
+ url: "<%= edit_element_site_page_path(@site.id, @page.id) %>",
74
+ method: "GET",
75
+ data: {
76
+ element_id: eltId,
77
+ section_id: sectionId,
78
+ entity: entity
79
+ }
80
+ })
81
+ }
82
+
83
+ }
46
84
  </script>
47
85
  <%= yield :scripts %>
48
86
  </body>
@@ -3,11 +3,10 @@
3
3
  <div class="sibu_form">
4
4
  <%= form_tag(update_element_site_page_path(@site.id, @page.id), method: :patch, remote: true) do |f| %>
5
5
  <div class="sibu_field">
6
- <%= label_tag 'element[text]', 'Texte' %>
7
- <%= text_area_tag 'element[text]' %>
6
+ <%= text_area_tag 'element[text]', '', class: 'tinymce' %>
8
7
  </div>
8
+ <%= hidden_field_tag 'element[id]', @element_id %>
9
9
  <%= hidden_field_tag :section_id, @section_id %>
10
- <%= hidden_field_tag :element_id, @element_id %>
11
10
  <%= hidden_field_tag :entity, @entity_type %>
12
11
  <div class="sibu_actions">
13
12
  <%= submit_tag 'Valider' %>
@@ -15,5 +14,3 @@
15
14
  </div>
16
15
  <% end %>
17
16
  </div>
18
-
19
-
@@ -1,4 +1,12 @@
1
1
  var editPanel = $("#edit_panel");
2
2
  editPanel.html("<%= j(render 'edit_panel') %>");
3
- editPanel.find("#element").val("<%= @entity.element(@section_id, @element_id)["text"] %>");
4
- editPanel.slideDown("fast");
3
+ editPanel.find("#element_text").val("<%= j(raw @entity.element(@section_id, @element_id)["text"]) %>");
4
+ editPanel.slideDown("fast");
5
+ tinyMCE.remove();
6
+ tinyMCE.init({
7
+ selector: 'textarea.tinymce',
8
+ branding: false,
9
+ menubar: false,
10
+ toolbar: 'bold italic underline alignleft aligncenter alignright alignjustify',
11
+ forced_root_block : false
12
+ });
@@ -2,6 +2,5 @@
2
2
  $("#edit_panel #edit_msg").html("<p class='sibu_alert'>Une erreur s'est produite lors de l'enregistrement.</p>");
3
3
  <% else %>
4
4
  $("#edit_panel").slideUp();
5
- $("sb-edit[data-id='<%= @section_id %>']").find("[data-id='<%= @element_id %>']").text("<%= @updated["text"] %>");
6
- initOverlays();
5
+ $("sb-edit[data-id='<%= @section_id %>']").find("[data-id='<%= @updated["id"] %>']").html("<%= j(raw @updated["text"]) %>");
7
6
  <% end %>
@@ -0,0 +1,6 @@
1
+ default:
2
+ toolbar:
3
+ - styleselect | bold italic
4
+ - link
5
+ plugins:
6
+ - link
data/lib/sibu/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sibu
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sibu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean-Baptiste Vilain
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-29 00:00:00.000000000 Z
11
+ date: 2018-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -56,30 +56,30 @@ dependencies:
56
56
  name: jquery-rails
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 4.3.1
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 4.3.1
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: tinymce-rails
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 4.7.6
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: 4.7.6
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: tinymce-rails-langs
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -145,8 +145,8 @@ files:
145
145
  - app/views/sibu/sites/show.html.erb
146
146
  - app/views/sibu/sites/update.html.erb
147
147
  - config/initializers/shrine.rb
148
- - config/initializers/tag_helper.rb
149
148
  - config/routes.rb
149
+ - config/tinymce.yml
150
150
  - db/migrate/20180124095041_create_sibu_sites.rb
151
151
  - db/migrate/20180124095213_create_sibu_pages.rb
152
152
  - db/migrate/20180124145030_create_sibu_site_templates.rb
@@ -1,75 +0,0 @@
1
- module ActionView
2
- module Helpers
3
- module TagHelper
4
- # Todo : handle default values => sections can be totally empty or have at least 1 elt
5
- # If "emptyable", how do we add the 1st elt ? If not, how do we provide a default value ?
6
- class SectionHelper
7
- include ActionView::Helpers::TagHelper
8
-
9
- attr_reader :entity_type
10
-
11
- [:h1, :h2, :h3, :h4, :h5, :h6, :p, :span, :div].each do |t|
12
- define_method(t) do |id, html_opts = {}|
13
- html_opts.merge!({class: "sb-#{t} #{html_opts[:class]}", data: {id: id}}) if @edit
14
- content_tag(t, (@elements.dig(id, "text") || "Texte à modifier"), html_opts)
15
- end
16
- end
17
-
18
- def initialize(*ids, entity, edit_mode)
19
- @id = ids.join('|')
20
- @entity_type = entity.is_a?(Sibu::Page) ? 'page' : 'site'
21
- elts = entity.section(*ids)
22
- @elements = elts.blank? ? {"default" => {}} : Hash[elts.map {|e| [e["id"], e.except("id")]}]
23
- @edit = edit_mode
24
- end
25
-
26
- # Note : add sb-img back - see how the extra div could be removed
27
- def img(id, html_opts = {})
28
- content = id == "default" ? {"src" => "/default.jpg"} : (@elements[id] || {"src" => "/default.jpg"})
29
- if @edit
30
- content_tag(:div, content_tag(:img, nil, content.merge(html_opts)), {class: "rel h100 #{html_opts[:class]}", data: {id: id}})
31
- else
32
- content_tag(:img, nil, content.merge(html_opts))
33
- end
34
- end
35
-
36
- def lnk(id)
37
- @elements[id] || {"value" => "", "text" => "Nouveau lien"}
38
- end
39
-
40
- # def subsection(id, &block)
41
- # section
42
- # s = SectionHelper.new(id, @entity_type, @elements[id], @edit)
43
- # if !@edit
44
- # capture(s, &block)
45
- # else
46
- # "<sb-edit data-id='#{id}' data-entity='#{@entity_type}'>#{capture(s, &block)}</sb-edit>".html_safe
47
- # end
48
- # end
49
-
50
- def elements(&block)
51
- @elements.each_pair(&block)
52
- end
53
- end
54
-
55
- def section(id, entity = @page, &block)
56
- s = SectionHelper.new(id, entity, action_name != 'show')
57
- if action_name == 'show'
58
- capture(s, &block)
59
- else
60
- "<sb-edit data-id='#{id}' data-entity='#{s.entity_type}'>#{capture(s, &block)}</sb-edit>".html_safe
61
- end
62
- end
63
-
64
- def subsection(id, sub_id, entity = @page, &block)
65
- entity_type = entity.is_a?(Sibu::Page) ? 'page' : 'site'
66
- s = SectionHelper.new(id, sub_id, entity, action_name != 'show')
67
- # if action_name == 'show'
68
- capture(s, &block)
69
- # else
70
- # "<sb-edit data-id='#{id}' data-entity='#{s.entity_type}'>#{capture(s, &block)}</sb-edit>".html_safe
71
- # end
72
- end
73
- end
74
- end
75
- end