effective_bootstrap 0.9.19 → 0.9.24

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04b7e635983b64f81aecbaf7d6c716f0d908d1685a643b2e88d1f335e2cfe679
4
- data.tar.gz: 3441003e31c25feb10896739a58373f2e9f0b81d640413a1c6043196df5e7429
3
+ metadata.gz: 9e3b9c4a0be1d9efbe01b7cc9d4fbd40cc9c2b5be9b069e4ed38603bdf650316
4
+ data.tar.gz: 013a278ce24f5a45c44be26d57943ae5c263a97182175964b47adb6ad8705fc5
5
5
  SHA512:
6
- metadata.gz: 03f84fa9001e3dbe3844d9d4d1d811d0369d3020ee367b3297bd1639dfe42f2b9a184c7047e2286eff65af730f005c629c6cbc110472f1e3aab9df6b9d6b0c4f
7
- data.tar.gz: 4095a858d118ebe4b31b0195afcc57ca2078b3a3c8cdd2eb930f93e68af7bd03aa355d3f86fc256e057e2ef5f70ea0e2a241ca4be3eb89385f851a95d4f4e379
6
+ metadata.gz: 8be225273013f47a0cb79e8d5849d494c13005393db8128bbe935b7f3c9d3d35b1b1d430239770f97bdb13b4e109386996c8c99a0e0b167c5160daaaff1cbc57
7
+ data.tar.gz: '08db95e5b85da09ffe4db682d0936f571ad2ffa8253eb21fd7f00e41880b54a7c56c900ff218a7cdf162b7c72c2f804aed3a6e3bc2b58bd43f46b687dc3bd166'
@@ -23,5 +23,6 @@
23
23
  //= require ./effective_phone/input
24
24
  //= require ./effective_price/input
25
25
  //= require ./effective_radio/input
26
+ //= require ./effective_rich_text_area/input
26
27
  //= require ./effective_select/input
27
28
  //= require ./effective_select_or_text/input
@@ -4,6 +4,7 @@ this.EffectiveForm ||= new class
4
4
  remote_form_commit: '' # String containing the last params[:commit]
5
5
  remote_form_payload: '' # String containing html from server side render of this form
6
6
  remote_form_flash: '' # Array of Arrays
7
+ remote_form_redirect: '' # String containing the redirect path (optional)
7
8
 
8
9
  validate: (form) ->
9
10
  valid = form.checkValidity()
@@ -73,6 +74,11 @@ this.EffectiveForm ||= new class
73
74
  $target = $target.closest('form') unless $target.is('form')
74
75
  $form = ''
75
76
 
77
+ if @remote_form_redirect.length > 0
78
+ window.location.href = @remote_form_redirect
79
+ @remote_form_redirect = ''
80
+ return
81
+
76
82
  if @remote_form_payload.length > 0
77
83
  $payload = $("<div>#{@remote_form_payload}</div>")
78
84
  $form = $payload.find("form[data-remote-index='#{$target.data('remote-index')}']")
@@ -160,7 +166,7 @@ this.EffectiveForm ||= new class
160
166
  # This displays the spinner here, and directs any flash messages before and after loadRemoteForm
161
167
  $(document).on 'click', '.form-actions a[data-remote],.form-actions button[type=submit]', (event) ->
162
168
  EffectiveForm.setCurrentSubmit($(@).parent())
163
- EffectiveForm.spin()
169
+ EffectiveForm.spin() unless $(@).attr('data-confirm')
164
170
 
165
171
  # This actually attached the handlers to a remote ajax form when it or an action inside it triggers a remote thing.
166
172
  $(document).on 'ajax:beforeSend', 'form[data-remote]', (event) ->
@@ -3,7 +3,7 @@ assignPositions = (target) ->
3
3
  return unless $hasMany.length > 0
4
4
 
5
5
  $fields = $hasMany.children('.has-many-fields:not(.marked-for-destruction)')
6
- positions = $fields.find("input[name$='[position]']").map(-> this.value).get()
6
+ positions = $fields.find("input[name$='[position]'][type=hidden]").map(-> this.value).get()
7
7
 
8
8
  if positions.length > 0
9
9
  index = Math.min.apply(Math, positions) || 0
@@ -35,7 +35,7 @@ $(document).on 'click', '[data-effective-form-has-many-add]', (event) ->
35
35
  return unless $hasMany.length > 0
36
36
 
37
37
  uid = (new Date).valueOf()
38
- template = $obj.data('effective-form-has-many-template').replace(/HASMANYINDEX/g, uid)
38
+ template = atob($obj.data('effective-form-has-many-template')).replace(/HASMANYINDEX/g, uid)
39
39
 
40
40
  $fields = $(template).hide().fadeIn('fast')
41
41
  EffectiveBootstrap.initialize($fields)
@@ -0,0 +1,171 @@
1
+ // https://github.com/lazaronixon/trix-extensions/blob/master/app/javascript/richtext.js
2
+
3
+ if(window.Trix) {
4
+
5
+ addHeadingAttributes()
6
+ addForegroundColorAttributes()
7
+ addBackgroundColorAttributes()
8
+
9
+ addEventListener('trix-initialize', function (event) { new RichText(event.target) })
10
+
11
+ addEventListener('trix-action-invoke', function (event) {
12
+ if (event.actionName == 'x-horizontal-rule') insertHorizontalRule()
13
+
14
+ function insertHorizontalRule() {
15
+ event.target.editor.insertAttachment(buildHorizontalRule())
16
+ }
17
+
18
+ function buildHorizontalRule() {
19
+ return new Trix.Attachment({ content: '<hr>', contentType: 'vnd.rubyonrails.horizontal-rule.html' })
20
+ }
21
+ })
22
+
23
+ class RichText {
24
+ constructor(element) {
25
+ this.element = element
26
+
27
+ this.insertHeadingElements()
28
+ this.insertDividerElements()
29
+ this.insertColorElements()
30
+ }
31
+
32
+ insertHeadingElements() {
33
+ this.removeOriginalHeadingButton()
34
+ this.insertNewHeadingButton()
35
+ this.insertHeadingDialog()
36
+ }
37
+
38
+ removeOriginalHeadingButton() {
39
+ this.buttonGroupBlockTools.removeChild(this.originalHeadingButton)
40
+ }
41
+
42
+ insertNewHeadingButton() {
43
+ this.buttonGroupBlockTools.insertAdjacentHTML("afterbegin", this.headingButtonTemplate)
44
+ }
45
+
46
+ insertHeadingDialog() {
47
+ this.dialogsElement.insertAdjacentHTML("beforeend", this.dialogHeadingTemplate)
48
+ }
49
+
50
+ insertDividerElements() {
51
+ this.quoteButton.insertAdjacentHTML("afterend", this.horizontalButtonTemplate)
52
+ }
53
+
54
+ insertColorElements() {
55
+ this.insertColorButton()
56
+ this.insertDialogColor()
57
+ }
58
+
59
+ insertColorButton() {
60
+ this.buttonGroupTextTools.insertAdjacentHTML("beforeend", this.colorButtonTemplate)
61
+ }
62
+
63
+ insertDialogColor() {
64
+ this.dialogsElement.insertAdjacentHTML("beforeend", this.dialogColorTemplate)
65
+ }
66
+
67
+ get buttonGroupBlockTools() {
68
+ return this.toolbarElement.querySelector("[data-trix-button-group=block-tools]")
69
+ }
70
+
71
+ get buttonGroupTextTools() {
72
+ return this.toolbarElement.querySelector("[data-trix-button-group=text-tools]")
73
+ }
74
+
75
+ get dialogsElement() {
76
+ return this.toolbarElement.querySelector("[data-trix-dialogs]")
77
+ }
78
+
79
+ get originalHeadingButton() {
80
+ return this.toolbarElement.querySelector("[data-trix-attribute=heading1]")
81
+ }
82
+
83
+ get quoteButton() {
84
+ return this.toolbarElement.querySelector("[data-trix-attribute=quote]")
85
+ }
86
+
87
+ get toolbarElement() {
88
+ return this.element.toolbarElement
89
+ }
90
+
91
+ get horizontalButtonTemplate() {
92
+ return '<button type="button" class="trix-button trix-button--icon trix-button--icon-horizontal-rule" data-trix-action="x-horizontal-rule" tabindex="-1" title="Divider">Divider</button>'
93
+ }
94
+
95
+ get headingButtonTemplate() {
96
+ return '<button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-action="x-heading" title="Heading" tabindex="-1">Heading</button>'
97
+ }
98
+
99
+ get colorButtonTemplate() {
100
+ return '<button type="button" class="trix-button trix-button--icon trix-button--icon-color" data-trix-action="x-color" title="Color" tabindex="-1">Color</button>'
101
+ }
102
+
103
+ get dialogHeadingTemplate() {
104
+ return `
105
+ <div class="trix-dialog trix-dialog--heading" data-trix-dialog="x-heading" data-trix-dialog-attribute="x-heading">
106
+ <div class="trix-dialog__link-fields">
107
+ <input type="text" name="x-heading" class="trix-dialog-hidden__input" data-trix-input>
108
+ <div class="trix-button-group">
109
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="heading1">H1</button>
110
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="heading2">H2</button>
111
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="heading3">H3</button>
112
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="heading4">H4</button>
113
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="heading5">H5</button>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ `
118
+ }
119
+
120
+ get dialogColorTemplate() {
121
+ return `
122
+ <div class="trix-dialog trix-dialog--color" data-trix-dialog="x-color" data-trix-dialog-attribute="x-color">
123
+ <div class="trix-dialog__link-fields">
124
+ <input type="text" name="x-color" class="trix-dialog-hidden__input" data-trix-input>
125
+ <div class="trix-button-group">
126
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="fgColor1" data-trix-method="hideDialog"></button>
127
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="fgColor2" data-trix-method="hideDialog"></button>
128
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="fgColor3" data-trix-method="hideDialog"></button>
129
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="fgColor4" data-trix-method="hideDialog"></button>
130
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="fgColor5" data-trix-method="hideDialog"></button>
131
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="fgColor6" data-trix-method="hideDialog"></button>
132
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="fgColor7" data-trix-method="hideDialog"></button>
133
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="fgColor8" data-trix-method="hideDialog"></button>
134
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="fgColor9" data-trix-method="hideDialog"></button>
135
+ </div>
136
+ <div class="trix-button-group">
137
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="bgColor1" data-trix-method="hideDialog"></button>
138
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="bgColor2" data-trix-method="hideDialog"></button>
139
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="bgColor3" data-trix-method="hideDialog"></button>
140
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="bgColor4" data-trix-method="hideDialog"></button>
141
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="bgColor5" data-trix-method="hideDialog"></button>
142
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="bgColor6" data-trix-method="hideDialog"></button>
143
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="bgColor7" data-trix-method="hideDialog"></button>
144
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="bgColor8" data-trix-method="hideDialog"></button>
145
+ <button type="button" class="trix-button trix-button--dialog" data-trix-attribute="bgColor9" data-trix-method="hideDialog"></button>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ `
150
+ }
151
+ }
152
+
153
+ function addHeadingAttributes() {
154
+ Array.from(["h1", "h2", "h3", "h4", "h5"]).forEach((tagName, i) => {
155
+ Trix.config.blockAttributes[`heading${(i + 1)}`] = { tagName: tagName, terminal: true, breakOnReturn: true, group: false }
156
+ })
157
+ }
158
+
159
+ function addForegroundColorAttributes() {
160
+ Array.from(["rgb(136, 118, 38)", "rgb(185, 94, 6)", "rgb(207, 0, 0)", "rgb(216, 28, 170)", "rgb(144, 19, 254)", "rgb(5, 98, 185)", "rgb(17, 138, 15)", "rgb(148, 82, 22)", "rgb(102, 102, 102)"]).forEach((color, i) => {
161
+ Trix.config.textAttributes[`fgColor${(i + 1)}`] = { style: { color: color }, inheritable: true, parser: e => e.style.color == color }
162
+ })
163
+ }
164
+
165
+ function addBackgroundColorAttributes() {
166
+ Array.from(["rgb(250, 247, 133)", "rgb(255, 240, 219)", "rgb(255, 229, 229)", "rgb(255, 228, 247)", "rgb(242, 237, 255)", "rgb(225, 239, 252)", "rgb(228, 248, 226)", "rgb(238, 226, 215)", "rgb(242, 242, 242)"]).forEach((color, i) => {
167
+ Trix.config.textAttributes[`bgColor${(i + 1)}`] = { style: { backgroundColor: color }, inheritable: true, parser: e => e.style.backgroundColor == color }
168
+ })
169
+ }
170
+
171
+ }
@@ -0,0 +1,20 @@
1
+ if(window.Trix) {
2
+
3
+ window.Trix.config.blockAttributes.default.tagName = 'p';
4
+ window.Trix.config.blockAttributes.default.breakOnReturn = true;
5
+
6
+ window.Trix.Block.prototype.breaksOnReturn = function() {
7
+ const attr = this.getLastAttribute();
8
+ const config = Trix.getBlockConfig(attr ? attr : 'default');
9
+ return config ? config.breakOnReturn : false;
10
+ };
11
+
12
+ window.Trix.LineBreakInsertion.prototype.shouldInsertBlockBreak = function() {
13
+ if(this.block.hasAttributes() && this.block.isListItem() && !this.block.isEmpty()) {
14
+ return this.startLocation.offset > 0
15
+ } else {
16
+ return !this.shouldBreakFormattedBlock() ? this.breaksOnReturn : false;
17
+ }
18
+ };
19
+
20
+ }
@@ -0,0 +1,2 @@
1
+ //= require ./initialize
2
+ //= require ./extensions
@@ -0,0 +1,90 @@
1
+ trix-toolbar {
2
+ // http://www.asiteaboutnothing.net/c_decode-url.html
3
+ // background-image: url("data:image/svg+xml,***encoded data***");
4
+
5
+ .trix-button--icon-horizontal-rule::before { background-image: url("data:image/svg+xml,%3Csvg%20enable-background%3D%22new%200%200%2024%2024%22%20viewBox%3D%220%200%2024%2024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cg%20fill%3D%22%23000%22%3E%3Cpath%20d%3D%22m0%2013h24v-2h-24z%22%2F%3E%3Cpath%20d%3D%22m5%208.5h14v-3h-14z%22%2F%3E%3Cpath%20d%3D%22m5%2018.5h14v-3h-14z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"); }
6
+ .trix-button--icon-color::before { background-image: url("data:image/svg+xml,%3Csvg%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%20width%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22m16.56%2011.94-8.94-8.94-1.41%201.41%202.38%202.38-5.15%205.15c-.59.59-.59%201.54%200%202.12l5.5%205.5c.29.29.68.44%201.06.44s.77-.15%201.06-.44l5.5-5.5c.59-.58.59-1.53%200-2.12zm-11.35%201.06%204.79-4.79%204.79%204.79zm13.79%202.5s-2%202.17-2%203.5c0%201.1.9%202%202%202s2-.9%202-2c0-1.33-2-3.5-2-3.5z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E%0A"); }
7
+
8
+ .trix-dialog--heading { max-width: 160px; }
9
+
10
+ .trix-dialog--color {
11
+ max-width: 265px;
12
+
13
+ .trix-dialog__link-fields { flex-direction: column; }
14
+
15
+ .trix-button-group {
16
+ margin: 1px;
17
+
18
+ button {
19
+ width: 28px;
20
+ &:after { content: "Ab"; }
21
+ &.trix-active::after { content: "✓"; }
22
+ }
23
+
24
+ [data-trix-attribute=fgColor1] { color: rgb(136, 118, 38) }
25
+ [data-trix-attribute=fgColor2] { color: rgb(136, 118, 38) }
26
+ [data-trix-attribute=fgColor3] { color: rgb(207, 0, 0) }
27
+ [data-trix-attribute=fgColor4] { color: rgb(216, 28, 170) }
28
+ [data-trix-attribute=fgColor5] { color: rgb(144, 19, 254) }
29
+ [data-trix-attribute=fgColor6] { color: rgb(5, 98, 185) }
30
+ [data-trix-attribute=fgColor7] { color: rgb(17, 138, 15) }
31
+ [data-trix-attribute=fgColor8] { color: rgb(148, 82, 22) }
32
+ [data-trix-attribute=fgColor9] { color: rgb(102, 102, 102) }
33
+
34
+ [data-trix-attribute=bgColor1] { background-color: rgb(250, 247, 133) }
35
+ [data-trix-attribute=bgColor2] { background-color: rgb(255, 240, 219) }
36
+ [data-trix-attribute=bgColor3] { background-color: rgb(255, 229, 229) }
37
+ [data-trix-attribute=bgColor4] { background-color: rgb(255, 228, 247) }
38
+ [data-trix-attribute=bgColor5] { background-color: rgb(242, 237, 255) }
39
+ [data-trix-attribute=bgColor6] { background-color: rgb(225, 239, 252) }
40
+ [data-trix-attribute=bgColor7] { background-color: rgb(228, 248, 226) }
41
+ [data-trix-attribute=bgColor8] { background-color: rgb(238, 226, 215) }
42
+ [data-trix-attribute=bgColor9] { background-color: rgb(242, 242, 242) }
43
+ }
44
+ }
45
+
46
+ .trix-dialog {
47
+ padding: 5px;
48
+
49
+ .trix-dialog-hidden__input {
50
+ position: absolute;
51
+ z-index: -1;
52
+ opacity: 0;
53
+ }
54
+ }
55
+ }
56
+
57
+ trix-editor {
58
+ [data-trix-mutable].attachment[data-trix-content-type~="vnd.rubyonrails.horizontal-rule.html"] {
59
+ box-shadow: 0 0 0 2px highlight;
60
+ }
61
+ }
62
+
63
+ .trix-content {
64
+ h1, h2, h3, h4, h5, h6 {
65
+ line-height: 1.2;
66
+ margin: 0;
67
+ }
68
+
69
+ h1 { font-size: 36px; }
70
+ h2 { font-size: 26px; }
71
+ h3 { font-size: 18px; }
72
+ h4 { font-size: 18px; }
73
+ h5 { font-size: 14px; }
74
+ h6 { font-size: 12px; }
75
+
76
+ .attachment { width: 100%; }
77
+
78
+ .attachment--content.attachment--horizontal-rule,
79
+ .attachment--content[data-trix-content-type~='vnd.rubyonrails.horizontal-rule.html'] {
80
+ padding: 1.5em 0 0.5em !important;
81
+ margin-bottom: 0.5em
82
+ }
83
+
84
+ .attachment--content.attachment--horizontal-rule hr,
85
+ .attachment--content[data-trix-content-type~='vnd.rubyonrails.horizontal-rule.html'] hr {
86
+ margin: 0;
87
+ width: 20%;
88
+ border-color: currentColor
89
+ }
90
+ }
@@ -1,25 +1,2 @@
1
- .effective_rich_text_area {
2
- height: 100%;
3
- border-color: #ccc;
4
-
5
- &:hover,
6
- &:active,
7
- &:focus, {
8
- border-color: #ccc;
9
- outline: 0px !important;
10
- -webkit-appearance: none;
11
- box-shadow: none !important;
12
- }
13
- }
14
-
15
- // Bootstrap 4 Feedback client side
16
- .was-validated .form-control:invalid ~ .trix-content, { border-color: #dc3545 !important; }
17
- .was-validated .form-control:valid ~ .trix-content { border-color: #28a745 !important; }
18
- .was-validated .form-control:invalid ~ trix-toolbar, { border-color: #dc3545 !important; }
19
- .was-validated .form-control:valid ~ trix-toolbar { border-color: #28a745 !important; }
20
-
21
- // Bootstrap 4 Server side feedback
22
- .form-control.is-invalid ~ .trix-content { border-color: #dc3545 !important; }
23
- .form-control.is-invalid ~ trix-toolbar { border-color: #dc3545 !important; }
24
- .form-control.is-valid ~ .trix-content { border-color: #28a745 !important; }
25
- .form-control.is-valid ~ trix-toolbar { border-color: #28a745 !important; }
1
+ @import 'rich_text_area';
2
+ @import 'extensions';
@@ -0,0 +1,30 @@
1
+ .effective_rich_text_area {
2
+ height: 100%;
3
+ border-color: #ccc;
4
+
5
+ &:hover,
6
+ &:active,
7
+ &:focus, {
8
+ border-color: #ccc;
9
+ outline: 0px !important;
10
+ -webkit-appearance: none;
11
+ box-shadow: none !important;
12
+ }
13
+ }
14
+
15
+ // Trix image caption
16
+ .trix-content {
17
+ figcaption.attachment__caption { display: none; }
18
+ }
19
+
20
+ // Bootstrap 4 Feedback client side
21
+ .was-validated .form-control:invalid ~ .trix-content, { border-color: #dc3545 !important; }
22
+ .was-validated .form-control:valid ~ .trix-content { border-color: #28a745 !important; }
23
+ .was-validated .form-control:invalid ~ trix-toolbar, { border-color: #dc3545 !important; }
24
+ .was-validated .form-control:valid ~ trix-toolbar { border-color: #28a745 !important; }
25
+
26
+ // Bootstrap 4 Server side feedback
27
+ .form-control.is-invalid ~ .trix-content { border-color: #dc3545 !important; }
28
+ .form-control.is-invalid ~ trix-toolbar { border-color: #dc3545 !important; }
29
+ .form-control.is-valid ~ .trix-content { border-color: #28a745 !important; }
30
+ .form-control.is-valid ~ trix-toolbar { border-color: #28a745 !important; }
@@ -411,7 +411,9 @@ module EffectiveBootstrapHelper
411
411
 
412
412
  @_tab_active = nil if @_tab_active == :first
413
413
 
414
- if @_tab_mode == :tablist # Inserting the label into the tablist top
414
+ if @_tab_mode == :tablist_vertical
415
+ content_tag(:a, label, id: ('tab-' + controls), class: ['nav-link', ('active' if active)].compact.join(' '), href: '#' + controls, 'aria-controls': controls, 'aria-selected': active.to_s, 'data-toggle': 'tab', role: 'tab')
416
+ elsif @_tab_mode == :tablist # Inserting the label into the tablist top
415
417
  content_tag(:li, class: 'nav-item') do
416
418
  content_tag(:a, label, id: ('tab-' + controls), class: ['nav-link', ('active' if active)].compact.join(' '), href: '#' + controls, 'aria-controls': controls, 'aria-selected': active.to_s, 'data-toggle': 'tab', role: 'tab')
417
419
  end
@@ -423,6 +425,29 @@ module EffectiveBootstrapHelper
423
425
  end
424
426
  end
425
427
 
428
+ def vertical_tabs(active: nil, unique: false, list: {}, content: {}, &block)
429
+ raise 'expected a block' unless block_given?
430
+
431
+ @_tab_mode = :tablist_vertical
432
+ @_tab_active = (active || :first)
433
+ @_tab_unique = ''.object_id if unique
434
+
435
+ content_tag(:div, class: 'row border') do
436
+ content_tag(:div, class: 'col-3 border-right') do
437
+ content_tag(:div, {class: 'nav flex-column nav-pills my-2', role: 'tablist', 'aria-orientation': :vertical}.merge(list)) do
438
+ yield # Yield to tab the first time
439
+ end
440
+ end +
441
+ content_tag(:div, class: 'col-9') do
442
+ content_tag(:div, {class: 'tab-content my-2'}.merge(content)) do
443
+ @_tab_mode = :content
444
+ @_tab_active = (active || :first)
445
+ yield # Yield to tab the second time
446
+ end
447
+ end
448
+ end
449
+ end
450
+
426
451
  def merge_class_key(hash, value)
427
452
  return { :class => value } unless hash.kind_of?(Hash)
428
453
 
@@ -150,7 +150,7 @@ module Effective
150
150
  html.gsub!("#{name}_attributes][#{index}]", "#{name}_attributes][HASMANYINDEX]")
151
151
  html.gsub!("#{name}_attributes_#{index}_", "#{name}_attributes_HASMANYINDEX_")
152
152
 
153
- html.html_safe
153
+ Base64.encode64(html)
154
154
  end
155
155
 
156
156
  def link_to_add(block)
@@ -0,0 +1,3 @@
1
+ <figure class="attachment attachment--content attachment--<%= content_attachment.name %>">
2
+ <%= render "action_text/attachables/content_attachments/#{content_attachment.name.underscore}" %>
3
+ </figure>
@@ -11,5 +11,11 @@ module EffectiveBootstrap
11
11
  app.config.assets.precompile += ['effective_bootstrap_manifest.js', 'icons/*']
12
12
  end
13
13
 
14
+ initializer 'effective_bootstrap.action_text' do |app|
15
+ if defined?(ActionText)
16
+ ActionText::ContentHelper.allowed_attributes << 'style'
17
+ end
18
+ end
19
+
14
20
  end
15
21
  end
@@ -1,3 +1,3 @@
1
1
  module EffectiveBootstrap
2
- VERSION = '0.9.19'.freeze
2
+ VERSION = '0.9.24'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_bootstrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.19
4
+ version: 0.9.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-11 00:00:00.000000000 Z
11
+ date: 2021-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -451,6 +451,9 @@ files:
451
451
  - app/assets/javascripts/effective_price/input.js
452
452
  - app/assets/javascripts/effective_radio/initialize.js.coffee
453
453
  - app/assets/javascripts/effective_radio/input.js
454
+ - app/assets/javascripts/effective_rich_text_area/extensions.js
455
+ - app/assets/javascripts/effective_rich_text_area/initialize.js
456
+ - app/assets/javascripts/effective_rich_text_area/input.js
454
457
  - app/assets/javascripts/effective_select/initialize.js.coffee
455
458
  - app/assets/javascripts/effective_select/input.js
456
459
  - app/assets/javascripts/effective_select/overrides.js.coffee
@@ -605,7 +608,9 @@ files:
605
608
  - app/assets/stylesheets/effective_file/input.scss
606
609
  - app/assets/stylesheets/effective_has_many/input.scss
607
610
  - app/assets/stylesheets/effective_radio/input.scss
611
+ - app/assets/stylesheets/effective_rich_text_area/extensions.scss
608
612
  - app/assets/stylesheets/effective_rich_text_area/input.scss
613
+ - app/assets/stylesheets/effective_rich_text_area/rich_text_area.scss
609
614
  - app/assets/stylesheets/effective_select/bootstrap-theme.css
610
615
  - app/assets/stylesheets/effective_select/input.scss
611
616
  - app/assets/stylesheets/effective_select/overrides.scss
@@ -660,6 +665,8 @@ files:
660
665
  - app/models/effective/form_logics/hide_if.rb
661
666
  - app/models/effective/form_logics/show_if.rb
662
667
  - app/models/effective/form_logics/show_if_any.rb
668
+ - app/views/action_text/attachables/_content_attachment.html.erb
669
+ - app/views/action_text/attachables/content_attachments/_horizontal_rule.html.erb
663
670
  - app/views/effective/style_guide/__fields.html.haml
664
671
  - app/views/effective/style_guide/__inline_fields.html.haml
665
672
  - app/views/effective/style_guide/_effective_form_with.html.haml