editmode 1.1.4 → 1.1.9
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 +4 -4
- data/README.md +118 -11
- data/lib/editmode.rb +1 -1
- data/lib/editmode/action_view_extensions/editmode_helper.rb +61 -17
- data/lib/editmode/chunk_value.rb +17 -9
- data/lib/editmode/helper.rb +1 -1
- data/lib/editmode/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbdfaaca69c2832debd4fb728c6684b48abe8e9337cbaa8f4323a20cf175cf77
|
4
|
+
data.tar.gz: 51841cadd3a89aea58a0089b9e7c541a286f9da46fa2d7db0f32e9d7a07797ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9966ac6b514c9c237db8e2e1f77613431a365f2c4259565422892b9abdd749a2c294575bfd0e1242d9ac682a5340b940bacde295560fa1845e93ddd03ef500f1
|
7
|
+
data.tar.gz: fee7262f68522bb8e4f76d0de9f9da8c267c2a311105e89c72d7989408d46f124f6bbbf4170d712c0544aa4453b17f2837525c93f47da9afae2a729a0a2c47a5
|
data/README.md
CHANGED
@@ -1,20 +1,127 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<img src="https://editmode.s3-eu-west-1.amazonaws.com/static/editmode-full-navy-bg-transparent.png" width="260" />
|
3
|
+
</p>
|
4
|
+
<br />
|
1
5
|
|
2
|
-
#
|
6
|
+
# EditMode for Rails
|
3
7
|
|
4
|
-
|
8
|
+
Editmode is a smarter way to manage copy and other content in your rails app. It's syntax is similar to i18n, but it's built for copy updates, not internationalization (yet). It's built around the idea of moving your content out of your codebase.
|
5
9
|
|
6
10
|
## Installation
|
7
11
|
|
8
|
-
|
9
|
-
|
10
|
-
|
12
|
+
#### 1. Add the gem to your Gemfile:
|
13
|
+
```ruby
|
14
|
+
gem 'editmode'
|
15
|
+
```
|
16
|
+
And run `bundle install`.
|
17
|
+
|
18
|
+
#### 2. Create an initializer with your project_id
|
19
|
+
|
20
|
+
<small>Don't have a project id? Sign up for one [here](https://editmode.com/rails?s=ghreadme)</small>
|
21
|
+
|
22
|
+
```sh
|
23
|
+
rails generate editmode:config YOUR-PROJECT-ID
|
24
|
+
```
|
25
|
+
This command produces an initializer file
|
26
|
+
```ruby
|
27
|
+
# config/initializers/editmode.rb
|
28
|
+
Editmode.setup do |config|
|
29
|
+
config.project_id={project_id}
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
That's it, you're all set up. By default Editmode will now include editmode.js in every page of your rails application, unless you disable auto-include.
|
34
|
+
<hr/>
|
35
|
+
|
36
|
+
## Rendering Content
|
37
|
+
|
38
|
+
Editmode provides helper methods for use in your rails views and controllers.
|
39
|
+
|
40
|
+
### Render the content of a chunk
|
41
|
+
```erb
|
42
|
+
<%= e('cnk_x4ts............') %> # Using a chunk identifier
|
43
|
+
<%= e('marketing_page_headline') %> # Using a content key
|
44
|
+
```
|
45
|
+
|
46
|
+
### Render an *Editable* chunk. Wait, [what?](https://editmode.com/rails)
|
47
|
+
```erb
|
48
|
+
<%= E('cnk_x4ts............') %> # Using a chunk identifier
|
49
|
+
<%= E('marketing_page_headline') %> # Using a content key
|
50
|
+
```
|
51
|
+
|
52
|
+
### Content can also be accessed in Controllers
|
53
|
+
```ruby
|
54
|
+
@page_title = e("cnk_x4ts............") # Using a chunk identifier
|
55
|
+
@page_title = e("marketing_page_seo_title") # Using a content key
|
56
|
+
```
|
57
|
+
|
58
|
+
### Directly get the value of a custom field
|
59
|
+
This works when a chunk is part of a collection.
|
60
|
+
```ruby
|
61
|
+
@email_subject = e("welcome_email","Subject")
|
62
|
+
@email_content = e("welcome_email","Content")
|
63
|
+
```
|
64
|
+
|
65
|
+
### Working with variables
|
66
|
+
```ruby
|
67
|
+
variable_values = { first_name: "Dexter", last_name: "Morgan"}
|
68
|
+
|
69
|
+
# Assume chunk content is "Hi {{first_name}} {{last_name}}"
|
70
|
+
|
71
|
+
# Single Chunk with Variables
|
72
|
+
e("cnk_d36415052285997e079b", variables: variable_values)
|
73
|
+
|
74
|
+
# Collection Field with Variables
|
75
|
+
e("cnk_16e04a02d577afb610ce", "Email Content", variables: variable_values)
|
76
|
+
|
77
|
+
# Response: "Hi Dexter Morgan"
|
78
|
+
```
|
79
|
+
|
80
|
+
### Use collections for repeatable content
|
81
|
+
```erb
|
82
|
+
<%= c('col_j8fbs...') do |chunk| %>
|
83
|
+
<div class="user-profile">
|
84
|
+
<h3 class="name">
|
85
|
+
<%= F("Name") %>
|
86
|
+
</h3>
|
87
|
+
<p class="description">
|
88
|
+
<%= f("Description") %>
|
89
|
+
</p>
|
90
|
+
</div>
|
91
|
+
<% end %>
|
92
|
+
```
|
93
|
+
|
94
|
+
|Parameter|Type|Description|
|
95
|
+
|---|---|---|
|
96
|
+
| identifier | string | The first argument of `c` takes the id of the collection you want to loop through |
|
97
|
+
| limit | int/string |`optional` The number of collection items you want to display |
|
98
|
+
| tags | array |`optional` Filter collection items based on tags listed in this parameter |
|
99
|
+
| class | string | `optional` Class name(s) that will be added along with "chunks-collection-wrapper" to the main collection `<div>` element |
|
100
|
+
| item_class | string | `optional` Class name(s) that will be added along with "chunks-collection-item--wrapper" to all collection items |
|
11
101
|
|
12
|
-
## Helper methods
|
13
|
-
- chunk_display
|
14
|
-
- raw_chunk
|
15
|
-
- chunk_list (coming soon)
|
16
102
|
|
17
103
|
## Caching
|
18
|
-
|
19
|
-
|
104
|
+
In order to keep your application speedy, Editmode minimizes the amount of network calls it makes by caching content where it can.
|
105
|
+
|
106
|
+
#### What's cached
|
107
|
+
- Any embedded content returned by the `e`, `E`, `f`, or `F` view helpers.
|
108
|
+
|
109
|
+
#### Expiring the cache
|
110
|
+
|
111
|
+
The editmode gem exposes a cache expiration endpoint in your application at `/editmode/clear_cache`.
|
112
|
+
|
113
|
+
1. GET `/editmode/clear_cache?identifier={chunk_id}` clears the cache for a specific chunk.
|
114
|
+
2. GET `/editmode/clear_cache?full=1` clears the full Editmode cache.
|
115
|
+
|
116
|
+
- Editmode.js will automatically hit this endpoint when you update a chunk through your frontend.
|
117
|
+
- You can configure cache expiration webhooks in Editmode.com to ensure your application is notified when content changes happen on Editmode.com
|
118
|
+
|
119
|
+
The cache expiration endpoint is currently **not** authenticated.
|
120
|
+
|
121
|
+
## Disabling editmode.js auto-include
|
122
|
+
|
123
|
+
To disable automatic insertion for a particular controller or action you can:
|
124
|
+
```ruby
|
125
|
+
skip_after_action :editmode_auto_include
|
126
|
+
```
|
20
127
|
|
data/lib/editmode.rb
CHANGED
@@ -19,6 +19,9 @@ module Editmode
|
|
19
19
|
branch_id = params[:em_branch_id].presence
|
20
20
|
tags = options[:tags].presence || []
|
21
21
|
limit = options[:limit].presence
|
22
|
+
|
23
|
+
parent_class = options[:class] || ""
|
24
|
+
item_class = options[:item_class] || ""
|
22
25
|
|
23
26
|
begin
|
24
27
|
url_params = {
|
@@ -49,12 +52,22 @@ module Editmode
|
|
49
52
|
end
|
50
53
|
|
51
54
|
if chunks.any?
|
52
|
-
content_tag :div, class: "chunks-collection-wrapper", data: {chunk_collection_identifier: collection_identifier} do
|
55
|
+
content_tag :div, class: "chunks-collection-wrapper #{parent_class}", data: {chunk_collection_identifier: collection_identifier} do
|
53
56
|
chunks.each do |chunk|
|
54
57
|
@custom_field_chunk = chunk
|
55
|
-
|
58
|
+
concat(content_tag(:div, class: "chunks-collection-item--wrapper #{item_class}") do
|
59
|
+
yield
|
60
|
+
end)
|
56
61
|
end
|
57
|
-
|
62
|
+
|
63
|
+
# Placeholder element for new collection item
|
64
|
+
@custom_field_chunk = chunks.first.merge!({placeholder: true})
|
65
|
+
concat(content_tag(:div, class: "chunks-hide chunks-col-placeholder-wrapper") do
|
66
|
+
yield
|
67
|
+
end)
|
68
|
+
end
|
69
|
+
else
|
70
|
+
content_tag(:span, " ".html_safe)
|
58
71
|
end
|
59
72
|
end
|
60
73
|
rescue => error
|
@@ -67,14 +80,23 @@ module Editmode
|
|
67
80
|
def chunk_field_value(parent_chunk_object, custom_field_identifier, options = {})
|
68
81
|
begin
|
69
82
|
chunk_identifier = parent_chunk_object["identifier"]
|
70
|
-
custom_field_item = parent_chunk_object["content"].detect
|
83
|
+
custom_field_item = parent_chunk_object["content"].detect do |f|
|
84
|
+
f["custom_field_identifier"].try(:downcase) == custom_field_identifier.try(:downcase) || f["custom_field_name"].try(:downcase) == custom_field_identifier.try(:downcase)
|
85
|
+
end
|
86
|
+
|
87
|
+
options[:field] = custom_field_identifier
|
71
88
|
|
89
|
+
if parent_chunk_object[:placeholder]
|
90
|
+
custom_field_item["identifier"] = ""
|
91
|
+
custom_field_item["content"] = ""
|
92
|
+
end
|
93
|
+
|
72
94
|
if custom_field_item.present?
|
73
95
|
render_chunk_content(
|
74
96
|
custom_field_item["identifier"],
|
75
97
|
custom_field_item["content"],
|
76
98
|
custom_field_item["chunk_type"],
|
77
|
-
{ parent_identifier: chunk_identifier }.merge(options)
|
99
|
+
{ parent_identifier: chunk_identifier, custom_field_identifier: custom_field_identifier}.merge(options)
|
78
100
|
)
|
79
101
|
end
|
80
102
|
rescue => errors
|
@@ -88,6 +110,7 @@ module Editmode
|
|
88
110
|
begin
|
89
111
|
# Always sanitize the content!!
|
90
112
|
chunk_content = ActionController::Base.helpers.sanitize(chunk_content) unless chunk_type == 'rich_text'
|
113
|
+
chunk_content = variable_parse!(chunk_content, options[:variable_fallbacks], options[:variable_values])
|
91
114
|
|
92
115
|
css_class = options[:class]
|
93
116
|
|
@@ -99,9 +122,8 @@ module Editmode
|
|
99
122
|
|
100
123
|
chunk_data = { :chunk => chunk_identifier, :chunk_editable => false, :chunk_type => chunk_type }
|
101
124
|
|
102
|
-
if options[:parent_identifier].present?
|
103
|
-
|
104
|
-
end
|
125
|
+
chunk_data.merge!({parent_identifier: options[:parent_identifier]}) if options[:parent_identifier].present?
|
126
|
+
chunk_data.merge!({custom_field_identifier: options[:custom_field_identifier]}) if options[:custom_field_identifier].present?
|
105
127
|
|
106
128
|
case display_type
|
107
129
|
when "span"
|
@@ -115,6 +137,7 @@ module Editmode
|
|
115
137
|
end
|
116
138
|
end
|
117
139
|
when "image"
|
140
|
+
chunk_content = chunk_content.blank? || chunk_content == "/images/original/missing.png" ? 'https://www.editmode.com/upload.png' : chunk_content
|
118
141
|
image_tag(chunk_content, :data => chunk_data, :class => css_class)
|
119
142
|
end
|
120
143
|
rescue => errors
|
@@ -132,10 +155,11 @@ module Editmode
|
|
132
155
|
# prevent the page from loading.
|
133
156
|
begin
|
134
157
|
branch_params = branch_id.present? ? "branch_id=#{branch_id}" : ""
|
135
|
-
|
158
|
+
field = options[:field].presence || ""
|
159
|
+
cache_identifier = "chunk_#{identifier}#{branch_id}#{field}"
|
136
160
|
url = "#{api_root_url}/chunks/#{identifier}?project_id=#{Editmode.project_id}&#{branch_params}"
|
137
161
|
cached_content_present = Rails.cache.exist?(cache_identifier)
|
138
|
-
|
162
|
+
|
139
163
|
if !cached_content_present
|
140
164
|
response = HTTParty.get(url)
|
141
165
|
response_received = true if response.code == 200
|
@@ -144,15 +168,30 @@ module Editmode
|
|
144
168
|
if !cached_content_present && !response_received
|
145
169
|
raise "No response received"
|
146
170
|
else
|
147
|
-
|
171
|
+
if field.present? && response.present?
|
172
|
+
field_content = response["content"].detect {|f| f["custom_field_identifier"].downcase == field.downcase || f["custom_field_name"].downcase == field.downcase }
|
173
|
+
if field_content
|
174
|
+
content = field_content["content"]
|
175
|
+
type = field_content["chunk_type"]
|
176
|
+
identifier = field_content["identifier"]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
variable_fallbacks = Rails.cache.fetch("#{cache_identifier}_variables") do
|
181
|
+
response['variable_fallbacks'].presence || {}
|
182
|
+
end
|
183
|
+
|
148
184
|
chunk_content = Rails.cache.fetch(cache_identifier) do
|
149
|
-
response[
|
185
|
+
content.presence || response["content"]
|
150
186
|
end
|
151
187
|
|
152
188
|
chunk_type = Rails.cache.fetch("#{cache_identifier}_type") do
|
153
|
-
response['chunk_type']
|
189
|
+
type.presence || response['chunk_type']
|
154
190
|
end
|
155
191
|
|
192
|
+
options[:variable_fallbacks] = variable_fallbacks
|
193
|
+
options[:variable_values] = options[:variables].presence || {}
|
194
|
+
|
156
195
|
render_chunk_content(identifier,chunk_content,chunk_type, options)
|
157
196
|
|
158
197
|
end
|
@@ -168,18 +207,23 @@ module Editmode
|
|
168
207
|
alias_method :chunk, :chunk_display
|
169
208
|
|
170
209
|
|
171
|
-
def render_custom_field(
|
172
|
-
|
210
|
+
def render_custom_field(field_name, options={})
|
211
|
+
options[:variable_fallbacks] = @custom_field_chunk["variable_fallbacks"] || {}
|
212
|
+
options[:variable_values] = options[:variables] || {}
|
213
|
+
|
214
|
+
chunk_field_value(@custom_field_chunk, field_name, options)
|
173
215
|
end
|
174
216
|
alias_method :F, :render_custom_field
|
175
217
|
|
176
|
-
def render_chunk(identifier,
|
218
|
+
def render_chunk(identifier, *args, &block)
|
219
|
+
field, options = parse_arguments(args)
|
220
|
+
options[:field] = field
|
177
221
|
chunk_display('label', identifier, options, &block)
|
178
222
|
end
|
179
223
|
alias_method :E, :render_chunk
|
180
224
|
|
181
225
|
|
182
|
-
def variable_parse!(content, variables, values)
|
226
|
+
def variable_parse!(content, variables = {}, values = {})
|
183
227
|
tokens = content.scan(/\{{(.*?)\}}/)
|
184
228
|
if tokens.any?
|
185
229
|
tokens.flatten!
|
data/lib/editmode/chunk_value.rb
CHANGED
@@ -3,9 +3,9 @@ module Editmode
|
|
3
3
|
include Editmode::ActionViewExtensions::EditmodeHelper
|
4
4
|
|
5
5
|
attr_accessor :identifier, :variable_values, :branch_id,
|
6
|
-
:variable_fallbacks, :chunk_type, :project_id,
|
6
|
+
:variable_fallbacks, :chunk_type, :project_id,
|
7
7
|
:response
|
8
|
-
|
8
|
+
|
9
9
|
attr_writer :content
|
10
10
|
|
11
11
|
def initialize(identifier, **options)
|
@@ -31,18 +31,26 @@ module Editmode
|
|
31
31
|
raise require_field_id
|
32
32
|
end
|
33
33
|
else
|
34
|
-
raise
|
34
|
+
raise "undefined method 'field` for chunk_type: #{chunk_type} \n"
|
35
35
|
end
|
36
36
|
result || @content
|
37
37
|
end
|
38
38
|
|
39
39
|
def content
|
40
|
-
raise
|
40
|
+
raise "undefined method 'content` for chunk_type: collection_item \nDid you mean? field" if chunk_type == 'collection_item'
|
41
41
|
|
42
42
|
variable_parse!(@content, variable_fallbacks, variable_values)
|
43
43
|
end
|
44
44
|
|
45
45
|
private
|
46
|
+
|
47
|
+
def json?(json)
|
48
|
+
JSON.parse(json)
|
49
|
+
return true
|
50
|
+
rescue JSON::ParserError => e
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
|
46
54
|
def get_content
|
47
55
|
branch_params = branch_id.present? ? "branch_id=#{branch_id}" : ""
|
48
56
|
url = "#{api_root_url}/chunks/#{identifier}?project_id=#{Editmode.project_id}&#{branch_params}"
|
@@ -58,16 +66,16 @@ module Editmode
|
|
58
66
|
if !cached_content_present && !response_received
|
59
67
|
raise no_response_received(identifier)
|
60
68
|
else
|
61
|
-
|
62
|
-
http_response
|
69
|
+
cached_response = Rails.cache.fetch(cache_identifier) do
|
70
|
+
http_response.to_json
|
63
71
|
end
|
64
72
|
|
73
|
+
@response = json?(cached_response) ? JSON.parse(cached_response) : cached_response
|
74
|
+
|
65
75
|
@content = response['content']
|
66
76
|
@chunk_type = response['chunk_type']
|
67
77
|
@project_id = response['project_id']
|
68
|
-
@variable_fallbacks =
|
69
|
-
response['variable_fallbacks']
|
70
|
-
end
|
78
|
+
@variable_fallbacks = response['variable_fallbacks']
|
71
79
|
end
|
72
80
|
end
|
73
81
|
|
data/lib/editmode/helper.rb
CHANGED
data/lib/editmode/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: editmode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Ennis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|