editmode 1.0.22 → 1.1.5

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
  SHA256:
3
- metadata.gz: 98935fb2e9c9e599ba4dde0dfc6331211932cfddec983bb7b7327ae3acbb255f
4
- data.tar.gz: 315beb50a0c8b829be8d6e78aa4f181f7e564418ab77c2d0a888c0bdeaf1661e
3
+ metadata.gz: 6cd3f1671097d61c5ea8a0cec5c6dda55f9417221c712020d0aaa5e9474f6f85
4
+ data.tar.gz: c102afb1932ae31933b7e6d4d0d2361b2853c8b4d0e0c863fcf915650c509f6b
5
5
  SHA512:
6
- metadata.gz: 4370f2a10ebb61fd87eed89ffd31c919d7f51e2adf363021135676624048bbbcc3941d7a643e8c9520a830cb943ddbce4a27e3a8ef50d1bac94bb440024885c0
7
- data.tar.gz: fdcca7d3fa91637b3c41f3b14af29e7c1cb2839d5dd9db06c9edfb4c4b415d7e80f5899621f829c6a7ee9607895349681f54df576dd0b581d07361917dafbaa6
6
+ metadata.gz: b45d8499eff5c5a1864baff10963aee1dac5d2c453d99583099fcbb1ffd86d62ae8a611da3427a86e88f262927afb4f0b8182ac06300550ecdf87398858cfe20
7
+ data.tar.gz: 12d16710fdeaffde83efedc2e15fb8035b7b3bd9412296541171510b2669ca913bc47469f3b9ab65606aae24ab47ccd8a3975c32a884372bfaae18048ffeaf52
data/README.md CHANGED
@@ -1,20 +1,125 @@
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
- # Editmode Rails Gem
6
+ # EditMode for Rails
3
7
 
4
- To be completed
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
- ## How It Works
9
- - Autoload editmode.js
10
- - Expose view helper
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 |`optional` The number of collection items you want to display |
98
+ | tags | array |`optional` Filter collection items based on tags listed in this parameter |
11
99
 
12
- ## Helper methods
13
- - chunk_display
14
- - raw_chunk
15
- - chunk_list (coming soon)
16
100
 
17
101
  ## Caching
18
- - All chunks cached by default using Rails.cache
19
- - GET /editmode/clear_cache?identifier={} to clear cache
102
+ In order to keep your application speedy, Editmode minimizes the amount of network calls it makes by caching content where it can.
103
+
104
+ #### What's cached
105
+ - Any embedded content returned by the `e`, `E`, `f`, or `F` view helpers.
106
+
107
+ #### Expiring the cache
108
+
109
+ The editmode gem exposes a cache expiration endpoint in your application at `/editmode/clear_cache`.
110
+
111
+ 1. GET `/editmode/clear_cache?identifier={chunk_id}` clears the cache for a specific chunk.
112
+ 2. GET `/editmode/clear_cache?full=1` clears the full Editmode cache.
113
+
114
+ - Editmode.js will automatically hit this endpoint when you update a chunk through your frontend.
115
+ - You can configure cache expiration webhooks in Editmode.com to ensure your application is notified when content changes happen on Editmode.com
116
+
117
+ The cache expiration endpoint is currently **not** authenticated.
118
+
119
+ ## Disabling editmode.js auto-include
120
+
121
+ To disable automatic insertion for a particular controller or action you can:
122
+ ```ruby
123
+ skip_after_action :editmode_auto_include
124
+ ```
20
125
 
@@ -4,6 +4,10 @@ class EditmodeController < ApplicationController
4
4
  if params[:full]
5
5
  Rails.cache.clear
6
6
  render status: 200, json: {:response => "success"}
7
+ elsif params[:collection]
8
+ cache_id = "collection_#{params[:identifier]}"
9
+ Rails.cache.delete_matched("#{cache_id}*")
10
+ render status: 200, json: {:response => "success"}
7
11
  elsif params[:variable_cache_project_id]
8
12
  project_id = params[:variable_cache_project_id]
9
13
  Rails.cache.delete("chunk_#{project_id}_variables")
@@ -10,6 +10,7 @@ require 'editmode/engine' if defined?(Rails)
10
10
  module Editmode
11
11
  class << self
12
12
  include Editmode::ActionViewExtensions::EditmodeHelper
13
+ include Editmode::Helper
13
14
 
14
15
  def project_id=(id)
15
16
  config.project_id = id
@@ -1,8 +1,10 @@
1
+ require 'editmode/helper'
2
+
1
3
  module Editmode
2
4
  module ActionViewExtensions
3
5
  module EditmodeHelper
4
-
5
6
  require 'httparty'
7
+ include Editmode::Helper
6
8
 
7
9
  def api_version
8
10
  # Todo Add Header Version
@@ -12,12 +14,12 @@ module Editmode
12
14
  ENV["EDITMODE_OVERRIDE_API_URL"] || "https://api.editmode.com"
13
15
  end
14
16
 
15
- def chunk_collection(collection_identifier, **options)
17
+ def chunk_collection(collection_identifier, **options, &block)
16
18
  branch_params = params[:em_branch_id].present? ? "branch_id=#{params[:em_branch_id]}" : ""
17
19
  branch_id = params[:em_branch_id].presence
18
20
  tags = options[:tags].presence || []
19
21
  limit = options[:limit].presence
20
-
22
+
21
23
  begin
22
24
  url_params = {
23
25
  :collection_identifier => collection_identifier,
@@ -30,24 +32,43 @@ module Editmode
30
32
  url.path = '/chunks'
31
33
  url.query = url_params
32
34
 
33
- response = HTTParty.get(url)
35
+ cache_identifier = "collection_#{collection_identifier}#{branch_id}#{limit}#{tags.join}"
36
+ cached_content_present = Rails.cache.exist?(cache_identifier)
37
+
38
+ if !cached_content_present
39
+ response = HTTParty.get(url)
40
+ response_received = true if response.code == 200
41
+ end
42
+
43
+ if !cached_content_present && !response_received
44
+ raise "No response received"
45
+ else
34
46
 
35
- raise "No response received" unless response.code == 200
36
- chunks = response["chunks"]
47
+ chunks = Rails.cache.fetch(cache_identifier) do
48
+ response['chunks']
49
+ end
37
50
 
38
- return chunks
51
+ if chunks.any?
52
+ content_tag :div, class: "chunks-collection-wrapper", data: {chunk_collection_identifier: collection_identifier} do
53
+ chunks.each do |chunk|
54
+ @custom_field_chunk = chunk
55
+ yield
56
+ end
57
+ end
58
+ end
59
+ end
39
60
  rescue => error
40
61
  puts error
41
62
  return []
42
63
  end
43
64
  end
65
+ alias_method :c, :chunk_collection
44
66
 
45
- def chunk_field_value(parent_chunk_object, custom_field_identifier,options={})
46
-
67
+ def chunk_field_value(parent_chunk_object, custom_field_identifier, options = {})
47
68
  begin
48
69
  chunk_identifier = parent_chunk_object["identifier"]
49
- custom_field_item = parent_chunk_object["content"].detect {|f| f["custom_field_identifier"] == custom_field_identifier }
50
-
70
+ custom_field_item = parent_chunk_object["content"].detect {|f| f["custom_field_identifier"] == custom_field_identifier || f["custom_field_name"] == custom_field_identifier }
71
+
51
72
  if custom_field_item.present?
52
73
  render_chunk_content(
53
74
  custom_field_item["identifier"],
@@ -60,15 +81,14 @@ module Editmode
60
81
  puts errors
61
82
  content_tag(:span, "&nbsp".html_safe)
62
83
  end
63
-
64
84
  end
65
85
 
66
- def render_chunk_content(chunk_identifier,chunk_content,chunk_type,options={})
86
+ def render_chunk_content(chunk_identifier, chunk_content, chunk_type,options = {})
67
87
 
68
88
  begin
69
89
  # Always sanitize the content!!
70
- chunk_content = ActionController::Base.helpers.sanitize(chunk_content)
71
-
90
+ chunk_content = ActionController::Base.helpers.sanitize(chunk_content) unless chunk_type == 'rich_text'
91
+
72
92
  css_class = options[:class]
73
93
 
74
94
  if chunk_type == "image"
@@ -86,7 +106,7 @@ module Editmode
86
106
  case display_type
87
107
  when "span"
88
108
  if chunk_type == "rich_text"
89
- content_tag("em-span", :class => "editmode-richtext-editor #{css_class}", :data => chunk_data.merge!({:chunk_editable => true}) ) do
109
+ content = content_tag("em-span", :class => "editmode-richtext-editor #{css_class}", :data => chunk_data.merge!({:chunk_editable => true}) ) do
90
110
  chunk_content.html_safe
91
111
  end
92
112
  else
@@ -104,7 +124,7 @@ module Editmode
104
124
 
105
125
  end
106
126
 
107
- def chunk_display(label,identifier,options={},&block)
127
+ def chunk_display(label, identifier, options = {}, &block)
108
128
  branch_id = params[:em_branch_id]
109
129
  # This method should never show an error.
110
130
  # If anything goes wrong fetching content
@@ -113,7 +133,7 @@ module Editmode
113
133
  begin
114
134
  branch_params = branch_id.present? ? "branch_id=#{branch_id}" : ""
115
135
  cache_identifier = "chunk_#{identifier}#{branch_id}"
116
- url = "#{api_root_url}/chunks/#{identifier}?#{branch_params}"
136
+ url = "#{api_root_url}/chunks/#{identifier}?project_id=#{Editmode.project_id}&#{branch_params}"
117
137
  cached_content_present = Rails.cache.exist?(cache_identifier)
118
138
 
119
139
  if !cached_content_present
@@ -144,10 +164,20 @@ module Editmode
144
164
  # maintain layout
145
165
  content_tag("em-span", "&nbsp".html_safe)
146
166
  end
167
+ end
168
+ alias_method :chunk, :chunk_display
169
+
147
170
 
171
+ def render_custom_field(label, options={})
172
+ chunk_field_value(@custom_field_chunk, label, options)
148
173
  end
174
+ alias_method :F, :render_custom_field
175
+
176
+ def render_chunk(identifier, options = {}, &block)
177
+ chunk_display('label', identifier, options, &block)
178
+ end
179
+ alias_method :E, :render_chunk
149
180
 
150
- alias_method :chunk, :chunk_display
151
181
 
152
182
  def variable_parse!(content, variables, values)
153
183
  tokens = content.scan(/\{{(.*?)\}}/)
@@ -3,13 +3,15 @@ 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,
7
- :response, :content
6
+ :variable_fallbacks, :chunk_type, :project_id,
7
+ :response
8
+
9
+ attr_writer :content
8
10
 
9
11
  def initialize(identifier, **options)
10
12
  @identifier = identifier
11
13
  @branch_id = options[:branch_id].presence
12
- @variable_values = options[:values].presence || {}
14
+ @variable_values = options[:variables].presence || {}
13
15
  get_content
14
16
  end
15
17
 
@@ -18,7 +20,7 @@ module Editmode
18
20
  if chunk_type == 'collection_item'
19
21
  if field.present?
20
22
  field.downcase!
21
- field_content = content.detect {|f| f["custom_field_identifier"].downcase == field || f["custom_field_name"].downcase == field }
23
+ field_content = @content.detect {|f| f["custom_field_identifier"].downcase == field || f["custom_field_name"].downcase == field }
22
24
  if field_content.present?
23
25
  result = field_content['content']
24
26
  result = variable_parse!(result, variable_fallbacks, variable_values)
@@ -29,15 +31,29 @@ module Editmode
29
31
  raise require_field_id
30
32
  end
31
33
  else
32
- raise "undefined method field for chunk_type: #{chunk_type}"
34
+ raise NoMethodError.new "undefined method 'field` for chunk_type: #{chunk_type} \n"
33
35
  end
34
- result ||= content
36
+ result || @content
37
+ end
38
+
39
+ def content
40
+ raise NoMethodError.new "undefined method 'content` for chunk_type: collection_item \nDid you mean? field" if chunk_type == 'collection_item'
41
+
42
+ variable_parse!(@content, variable_fallbacks, variable_values)
35
43
  end
36
44
 
37
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
+
38
54
  def get_content
39
55
  branch_params = branch_id.present? ? "branch_id=#{branch_id}" : ""
40
- url = "#{api_root_url}/chunks/#{identifier}?#{branch_params}"
56
+ url = "#{api_root_url}/chunks/#{identifier}?project_id=#{Editmode.project_id}&#{branch_params}"
41
57
 
42
58
  cache_identifier = "chunk_value_#{identifier}#{branch_id}"
43
59
  cached_content_present = Rails.cache.exist?(cache_identifier)
@@ -50,16 +66,16 @@ module Editmode
50
66
  if !cached_content_present && !response_received
51
67
  raise no_response_received(identifier)
52
68
  else
53
- @response = Rails.cache.fetch(cache_identifier) do
54
- http_response
69
+ cached_response = Rails.cache.fetch(cache_identifier) do
70
+ http_response.to_json
55
71
  end
56
72
 
73
+ @response = json?(cached_response) ? JSON.parse(cached_response) : cached_response
74
+
57
75
  @content = response['content']
58
76
  @chunk_type = response['chunk_type']
59
77
  @project_id = response['project_id']
60
- @variable_fallbacks = Rails.cache.fetch("chunk_#{project_id}_variables") do
61
- response['variable_fallbacks']
62
- end
78
+ @variable_fallbacks = response['variable_fallbacks']
63
79
  end
64
80
  end
65
81
 
@@ -1,8 +1,10 @@
1
- module Editmode
1
+ require 'editmode/chunk_value'
2
+ require 'editmode/helper'
2
3
 
4
+ module Editmode
3
5
  class Engine < Rails::Engine
4
-
5
-
6
+ ActionController::Base.class_eval do
7
+ include Editmode::Helper
8
+ end
6
9
  end
7
-
8
10
  end
@@ -0,0 +1,36 @@
1
+ module Editmode
2
+ module Helper
3
+ # Render non-editable content
4
+ def e(identifier, *args)
5
+ field, options = parse_arguments(args)
6
+ begin
7
+ chunk = Editmode::ChunkValue.new(identifier, options)
8
+
9
+ if chunk.chunk_type == 'collection_item'
10
+ chunk.field(field)
11
+ else
12
+ chunk.content
13
+ end
14
+ rescue => er
15
+ raise er
16
+ end
17
+ end
18
+
19
+ def render_custom_field_raw(label, options={})
20
+ e(@custom_field_chunk["identifier"], label, options)
21
+ end
22
+ alias_method :f, :render_custom_field_raw
23
+
24
+ def parse_arguments(args)
25
+ field = nil
26
+ options = {}
27
+ if args[0].class.name == 'String'
28
+ field = args[0]
29
+ options = args[1] || {}
30
+ elsif args[0].class.name == 'Hash'
31
+ options = args[0] || {}
32
+ end
33
+ return field, options
34
+ end
35
+ end
36
+ end
@@ -18,6 +18,7 @@ module Editmode
18
18
 
19
19
  str = <<-EDITMODE_SCRIPT
20
20
  <script>window.chunksProjectIdentifier = '#{Editmode.project_id}'</script>
21
+ <script>window.editmodeENV = '#{ENV["EDITMODE_ENV"] || 'production'}'</script>
21
22
  <script src="#{script_url}" async ></script>
22
23
  EDITMODE_SCRIPT
23
24
 
@@ -26,7 +27,7 @@ module Editmode
26
27
  end
27
28
 
28
29
  def script_url
29
- ENV["EDITMODE_OVERRIDE_SCRIPT_URL"] || "https://static.editmode.com/editmode@^1.0.0/dist/editmode.js"
30
+ ENV["EDITMODE_OVERRIDE_SCRIPT_URL"] || "https://static.editmode.com/editmode@2.0.0/dist/editmode.js"
30
31
  end
31
32
 
32
33
  end
@@ -1,3 +1,3 @@
1
1
  module Editmode
2
- VERSION = "1.0.22"
2
+ VERSION = "1.1.5"
3
3
  end
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.0.22
4
+ version: 1.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Ennis
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-15 00:00:00.000000000 Z
11
+ date: 2020-09-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -84,6 +84,7 @@ files:
84
84
  - lib/editmode/auto_include_filter.rb
85
85
  - lib/editmode/chunk_value.rb
86
86
  - lib/editmode/engine.rb
87
+ - lib/editmode/helper.rb
87
88
  - lib/editmode/railtie.rb
88
89
  - lib/editmode/script_tag.rb
89
90
  - lib/editmode/version.rb
@@ -93,7 +94,7 @@ homepage: https://github.com/tonyennis145/editmode-rails
93
94
  licenses:
94
95
  - MIT
95
96
  metadata: {}
96
- post_install_message:
97
+ post_install_message:
97
98
  rdoc_options: []
98
99
  require_paths:
99
100
  - lib
@@ -109,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
110
  version: '0'
110
111
  requirements: []
111
112
  rubygems_version: 3.0.8
112
- signing_key:
113
+ signing_key:
113
114
  specification_version: 4
114
115
  summary: Editmode allows you to turn plain text in your rails app into easily inline-editable
115
116
  bits of content that can be managed by anyone with no technical knowledge