effective_regions 1.0.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +580 -0
- data/Rakefile +23 -0
- data/app/assets/images/effective/templates/image_and_title.png +0 -0
- data/app/assets/javascripts/effective/snippets/current_user_info.js.coffee +24 -0
- data/app/controllers/effective/regions_controller.rb +154 -0
- data/app/helpers/effective_regions_helper.rb +108 -0
- data/app/models/concerns/acts_as_regionable.rb +34 -0
- data/app/models/effective/access_denied.rb +17 -0
- data/app/models/effective/region.rb +44 -0
- data/app/models/effective/snippets/current_user_info.rb +12 -0
- data/app/models/effective/snippets/snippet.rb +69 -0
- data/app/models/effective/templates/image_and_title.rb +13 -0
- data/app/models/effective/templates/template.rb +26 -0
- data/app/views/effective/snippets/_current_user_info.html.haml +10 -0
- data/app/views/effective/templates/_image_and_title.html.haml +5 -0
- data/config/routes.rb +19 -0
- data/db/migrate/01_create_effective_regions.rb.erb +23 -0
- data/lib/effective_regions.rb +57 -0
- data/lib/effective_regions/engine.rb +27 -0
- data/lib/effective_regions/version.rb +3 -0
- data/lib/generators/effective_regions/install_generator.rb +32 -0
- data/lib/generators/templates/README +1 -0
- data/lib/generators/templates/effective_regions.rb +71 -0
- data/lib/tasks/effective_regions_tasks.rake +4 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +59 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +16 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +20 -0
- data/spec/dummy/log/test.log +2 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/effective_regions_spec.rb +7 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/factories.rb +1 -0
- metadata +199 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3da3a25db0858892dedca323cbf867a7e9017961
|
4
|
+
data.tar.gz: c9ddf036366111755f3af12e9a748600256289b8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a72c5adc99f5cdc4711514efdcb461356962f97d51ee25496575b81798eaf750a7e27bf21eee61317375992e243f84af3cb9d041c19059be8b19717481f777ff
|
7
|
+
data.tar.gz: d57234452b3c5881ed25ba0c96edb822ba709c2ae862d1133a960035ce8d09c9ef8db1e9fafcb65b87f724d945e7576ea73ca659ffe82aa1ed92788fe2154735
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2014 Code and Effect Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,580 @@
|
|
1
|
+
# Effective Regions
|
2
|
+
|
3
|
+
Create editable content regions within your existing, ordinary ActionView::Base views, and update content with an actually-good full-screen WYSIWYG editor.
|
4
|
+
|
5
|
+
Define and Insert Snippets (mini model-view components) that intelligently render content based on the user selected attributes.
|
6
|
+
|
7
|
+
Specify and Insert pre-defined HTML-only templates for small pieces of common HTML.
|
8
|
+
|
9
|
+
Uses the actually-good fullscreen editor [effective_ckeditor](https://github.com/code-and-effect/effective_ckeditor) to achieve near perfect WYSIWYG editting of content regions.
|
10
|
+
|
11
|
+
|
12
|
+
## Getting Started
|
13
|
+
|
14
|
+
Add to your Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'effective_regions'
|
18
|
+
```
|
19
|
+
|
20
|
+
Run the bundle command to install it:
|
21
|
+
|
22
|
+
```console
|
23
|
+
bundle install
|
24
|
+
```
|
25
|
+
|
26
|
+
Then run the generator:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
rails generate effective_regions:install
|
30
|
+
```
|
31
|
+
|
32
|
+
The generator will install an initializer which describes all configuration options and creates a database migration.
|
33
|
+
|
34
|
+
If you want to tweak the database table name (to use something other than the default 'regions'), manually adjust both the configuration file and the migration now.
|
35
|
+
|
36
|
+
Then migrate the database:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
rake db:migrate
|
40
|
+
```
|
41
|
+
|
42
|
+
Add the following helper to your application layout in the `<head>..</head>` section. This will have the effect of loading the appropriate javascript & stylesheets only when in 'edit mode'.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
effective_regions_include_tags
|
46
|
+
```
|
47
|
+
|
48
|
+
Do not add anything to your asset pipeline javascripts or stylesheets.
|
49
|
+
|
50
|
+
|
51
|
+
## Usage
|
52
|
+
|
53
|
+
### Regions
|
54
|
+
|
55
|
+
Regions can be global, in which each is referenced by a unique name, or belong to a specific object.
|
56
|
+
|
57
|
+
If desired, permissions can be configured such that some users may edit global regions but not object regions or vice versa.
|
58
|
+
|
59
|
+
The regions can be created with or without default content. The default content is displayed only when no editable content has been entered.
|
60
|
+
|
61
|
+
The names for the regions are to be created on the fly, so you can just make up new names as you go along.
|
62
|
+
|
63
|
+
It's super easy to add an effective_region into any regular view, anywhere you want a dynamic content area.
|
64
|
+
|
65
|
+
The following is an example of a global region:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
%h2 This is a header
|
69
|
+
%p= effective_region :footer_left
|
70
|
+
```
|
71
|
+
|
72
|
+
and another example of the same region with some default content:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
%h2 This is a header
|
76
|
+
%p
|
77
|
+
= effective_region :footer_left do
|
78
|
+
%p Default content
|
79
|
+
%p to display when footer_left is empty
|
80
|
+
```
|
81
|
+
|
82
|
+
Anywhere in your application, in any layout or view, refering to `:footer_left` will render the same piece of content.
|
83
|
+
|
84
|
+
Effective Regions can also belong to a specific object:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
%h2= effective_region(@event, :title)
|
88
|
+
|
89
|
+
%p
|
90
|
+
= effective_region @event, :summary do
|
91
|
+
%p= truncate(@event.excerpt)
|
92
|
+
%small
|
93
|
+
created on
|
94
|
+
= @event.created_at
|
95
|
+
|
96
|
+
%p= effective_region(@event, :body)
|
97
|
+
```
|
98
|
+
|
99
|
+
Here each `@event` will have a unique `:title`, `:summary` and `:body` regions.
|
100
|
+
|
101
|
+
|
102
|
+
### Restricting Editable Content
|
103
|
+
|
104
|
+
Using a regular `effective_region` tells the full-screen editor that any kind of HTML content and all available Snippets are allowed.
|
105
|
+
|
106
|
+
This is not always desirable - sometimes you want to lock down the content available to a specific region.
|
107
|
+
|
108
|
+
To allow text-only entry with no HTML or snippets, use `simple_effective_region`:
|
109
|
+
|
110
|
+
```haml
|
111
|
+
%h2
|
112
|
+
= simple_effective_region @event, :title do
|
113
|
+
Default Title
|
114
|
+
```
|
115
|
+
|
116
|
+
The above example ensures that the full-screen editor will only accept a simple title. No HTML is allowed. No Snippets are allowed. No newlines or ENTER keypresses are allowed.
|
117
|
+
|
118
|
+
This gives the user full control of the content, and allows the design and presentation to remain entirely in the hands of the developer.
|
119
|
+
|
120
|
+
Similarly, you may want to allow only Snippets to be inserted into a specific region:
|
121
|
+
|
122
|
+
```haml
|
123
|
+
%div
|
124
|
+
= snippet_effective_region :sidebar_mentions
|
125
|
+
```
|
126
|
+
|
127
|
+
only one type of snippet to be allowed:
|
128
|
+
|
129
|
+
```haml
|
130
|
+
%div
|
131
|
+
= snippet_effective_region(:sidebar_mentions, :snippets => [:mention])
|
132
|
+
```
|
133
|
+
|
134
|
+
or allow full content entry, but only a subset of the available Snippets:
|
135
|
+
|
136
|
+
```haml
|
137
|
+
%div
|
138
|
+
= effective_region(:sidebar_mentions, :snippets => [:mention])
|
139
|
+
```
|
140
|
+
|
141
|
+
### Before Save Callback
|
142
|
+
|
143
|
+
Sometimes you may want to programmatically massage the content being assigned from the editor.
|
144
|
+
|
145
|
+
One use case for this would be to replace a tweet `@someone` mention with a full url to the appropriate twitter page.
|
146
|
+
|
147
|
+
Found in the `config/initializers/effective_regions.rb` file, the `config.before_save_method` hook exists for just such a purpose.
|
148
|
+
|
149
|
+
This method is called when a User clicks the 'Save' button in the full screen editor.
|
150
|
+
|
151
|
+
It will be called once for each region immediately before the regions are saved to the database.
|
152
|
+
|
153
|
+
This is not an ActiveRecord `before_save` callback and there is no way to cancel the save.
|
154
|
+
|
155
|
+
This method is run on the `controller.view_context`, so you have access to all your regular view helpers as well as the `request` object.
|
156
|
+
|
157
|
+
The second argument, `parent`, will be the `Effective::Region`'s parent `regionable` object, or the symbol `:global`.
|
158
|
+
|
159
|
+
If you are gsub'ing the `region.content` String value or altering the `region.snippets` Hash values, those changes will not be immediately visible on the front-end.
|
160
|
+
|
161
|
+
If you need the User to immediately see these changes, have your Proc or function return the symbol `:refresh`.
|
162
|
+
|
163
|
+
Returning the symbol `:refresh` will instruct javascript to perform a full page refresh after the Save is complete.
|
164
|
+
|
165
|
+
Warning: Don't change the `region.title` value or the `region.regionable` parent object, as this will just orphan the region.
|
166
|
+
|
167
|
+
Use via Proc:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
config.before_save_method = Proc.new do |region, parent|
|
171
|
+
region.content = region.content.gsub('force', 'horse') if region.title == 'body'
|
172
|
+
:refresh
|
173
|
+
end
|
174
|
+
```
|
175
|
+
|
176
|
+
or to use via custom method:
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
config.before_save_method = :my_region_before_save_method
|
180
|
+
```
|
181
|
+
|
182
|
+
And then in your application_controller.rb:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
def my_region_before_save_method(region, parent)
|
186
|
+
if region.title == 'body' && request.fullpath == posts_path
|
187
|
+
region.content = region.content.gsub('force', 'horse')
|
188
|
+
:refresh
|
189
|
+
end
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
or to disable completely:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
config.before_save_method = false
|
197
|
+
```
|
198
|
+
|
199
|
+
|
200
|
+
## Authorization
|
201
|
+
|
202
|
+
All authorization checks are handled via the config.authorization_method found in the effective_regions.rb initializer.
|
203
|
+
|
204
|
+
It is intended for flow through to CanCan, but that is not required.
|
205
|
+
|
206
|
+
The authorization method can be defined as:
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
EffectiveRegions.setup do |config|
|
210
|
+
config.authorization_method = Proc.new { |controller, action, resource| can?(action, resource) }
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
or as a method:
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
EffectiveRegions.setup do |config|
|
218
|
+
config.authorization_method = :authorize_effective_regions
|
219
|
+
end
|
220
|
+
```
|
221
|
+
|
222
|
+
and then in your application_controller.rb:
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
def authorize_effective_regions(action, resource)
|
226
|
+
can?(action, resource)
|
227
|
+
end
|
228
|
+
```
|
229
|
+
|
230
|
+
There are 3 different levels of permissions to be considered:
|
231
|
+
|
232
|
+
1 - Can I use the editor at all?
|
233
|
+
|
234
|
+
can :edit, Effective::Region
|
235
|
+
|
236
|
+
2 - Can I update the Effective::Region global regions?
|
237
|
+
|
238
|
+
can :update, Effective::Region
|
239
|
+
|
240
|
+
3 - Can I update the individual objects which define `acts_as_regionable`
|
241
|
+
|
242
|
+
can :update, ActsAsRegionableObject # This would be your Event, Post, or Page, or whatever.
|
243
|
+
|
244
|
+
If the method or proc returns false (user is not authorized) an `Effective::AccessDenied` exception will be raised
|
245
|
+
|
246
|
+
You can rescue from this exception by adding the following to your application_controller.rb
|
247
|
+
|
248
|
+
```ruby
|
249
|
+
rescue_from Effective::AccessDenied do |exception|
|
250
|
+
respond_to do |format|
|
251
|
+
format.html { render 'static_pages/access_denied', :status => 403 }
|
252
|
+
format.any { render :text => 'Access Denied', :status => 403 }
|
253
|
+
end
|
254
|
+
end
|
255
|
+
```
|
256
|
+
|
257
|
+
## Snippets
|
258
|
+
|
259
|
+
Snippets are intelligent pieces of content that can be dropped into an effective_region through the full-screen editor's 'Insert Snippet' dropdown.
|
260
|
+
|
261
|
+
They are based on [CKEditor Widgets](http://docs.ckeditor.com/#!/guide/dev_widgets) but override some of the Widget internals to instead use the server to render content, allowing us to render Rails objects based on the user selected options.
|
262
|
+
|
263
|
+
To implement a Snippet, you must write 3 files: a model, a view, and a javascript options file.
|
264
|
+
|
265
|
+
|
266
|
+
## Simple Snippet Example
|
267
|
+
|
268
|
+
We are going to create a Snippet called `current_user_info`.
|
269
|
+
|
270
|
+
When the snippet is inserted, the user may choose whether the `.email`, `.first_name` or `.last_name` methods will be called on the `current_user` object.
|
271
|
+
|
272
|
+
These examples use HAML, but ERB or SLIM will work the same way.
|
273
|
+
|
274
|
+
### The Model
|
275
|
+
|
276
|
+
A model that extends from `Effective::Snippets::Snippet`
|
277
|
+
|
278
|
+
Any snippet models defined in app/models/effective/snippets/*.rb will be automatically detected and usable.
|
279
|
+
|
280
|
+
The models here are not ActiveRecord objects, and instead rely on [virtus](https://github.com/solnic/virtus) for the `attribute` functionality.
|
281
|
+
|
282
|
+
Any number of configurable options can be specified, but in this example we only have one.
|
283
|
+
|
284
|
+
This model file is defined in app/models/effective/snippets/current_user_info.rb
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
module Effective
|
288
|
+
module Snippets
|
289
|
+
class CurrentUserInfo < Snippet
|
290
|
+
attribute :display_method, String
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
```
|
295
|
+
|
296
|
+
### The View
|
297
|
+
|
298
|
+
The view must be defined as a partial and should be placed in app/views/effective/snippets/_current_user_info.html.haml
|
299
|
+
|
300
|
+
```haml
|
301
|
+
- if current_user.blank?
|
302
|
+
= 'Not logged in'
|
303
|
+
|
304
|
+
- elsif current_user_info.display_method == 'email'
|
305
|
+
= current_user.email
|
306
|
+
|
307
|
+
- elsif current_user_info.display_method == 'first_name'
|
308
|
+
= current_user.first_name
|
309
|
+
|
310
|
+
- elsif current_user_info.display_method == 'last_name'
|
311
|
+
= current_user.last_name
|
312
|
+
```
|
313
|
+
|
314
|
+
Or for the meta-programmers, instead of the above, we could:
|
315
|
+
|
316
|
+
```haml
|
317
|
+
= (current_user.send(current_user_info.display_method) rescue 'Not logged in')
|
318
|
+
```
|
319
|
+
|
320
|
+
In the above example, `current_user_info` is the snippet object, and `current_user` is the (probably Devise) User object.
|
321
|
+
|
322
|
+
|
323
|
+
### The Javascript Options File
|
324
|
+
|
325
|
+
This file defines the dialog that CKEditor will present when inserting a new Snippet.
|
326
|
+
|
327
|
+
This must follow the CKEditor Widget Dialog Window Definition specification, which you can learn more about at:
|
328
|
+
|
329
|
+
http://docs.ckeditor.com/#!/guide/widget_sdk_tutorial_2
|
330
|
+
|
331
|
+
http://docs.ckeditor.com/#!/api/CKEDITOR.dialog.definition
|
332
|
+
|
333
|
+
The javascript file must be placed in app/assets/javascripts/effective/snippets/current_user_info.js.coffee
|
334
|
+
|
335
|
+
```Coffeescript
|
336
|
+
CKEDITOR.dialog.add 'current_user_info', (editor) -> # Must match the class name of the snippet
|
337
|
+
title: 'Current User Info',
|
338
|
+
minWidth: 200,
|
339
|
+
minHeight: 100,
|
340
|
+
contents: [
|
341
|
+
{
|
342
|
+
id: 'current_user_info', # Just an html id, doesn't really matter what is here
|
343
|
+
elements: [
|
344
|
+
{ # elements Array should contain one Hash for each Snippet attribute
|
345
|
+
id: 'display_method',
|
346
|
+
type: 'select',
|
347
|
+
label: 'Current User Info',
|
348
|
+
items: [
|
349
|
+
['E-mail', 'email'],
|
350
|
+
['First Name', 'first_name'],
|
351
|
+
['Last Name', 'last_name']
|
352
|
+
],
|
353
|
+
setup: (widget) -> this.setValue(widget.data.display_method),
|
354
|
+
commit: (widget) -> widget.setData('display_method', this.getValue())
|
355
|
+
}
|
356
|
+
]
|
357
|
+
}
|
358
|
+
]
|
359
|
+
```
|
360
|
+
|
361
|
+
Please note, this file should not be included into the asset pipeline. It's a standalone javascript file that is read (just once, and then cached) by CKEditor when the Insert Snippet is triggered.
|
362
|
+
|
363
|
+
You may be thinking that this file won't be available due to asset digesting, but there is a custom `assets:precompile` enhancement task in the [effective_ckeditor](https://github.com/code-and-effect/effective_ckeditor) gem (a dependency of this gem) that ensures these snippet options files are available at the non-digested file path. This just works and is not something you need to worry about.
|
364
|
+
|
365
|
+
### Summary
|
366
|
+
|
367
|
+
We have created a simple Snippet to display the current_user's email, first_name or last_name.
|
368
|
+
|
369
|
+
When any logged in user visits this page, their specific instance of current_user will be called, and they will see their own email, first or last name.
|
370
|
+
|
371
|
+
Once the Snippet is inserted, the user editting the page can double-click the Snippet and set the display_method to something else.
|
372
|
+
|
373
|
+
|
374
|
+
## Advanced Snippet Example
|
375
|
+
|
376
|
+
The above, simple, example works great because `current_user` is something always available to the application.
|
377
|
+
|
378
|
+
In this next example we are going to create a Snippet to insert a summary and link to a `Post` which is created using the standard Rails CRUD workflow.
|
379
|
+
|
380
|
+
We must use an AJAX request to query all current Posts, rather than just the ones available at compile/deploy time.
|
381
|
+
|
382
|
+
### The Model
|
383
|
+
|
384
|
+
This snippet model is defined in app/models/effective/snippets/post.rb
|
385
|
+
|
386
|
+
```ruby
|
387
|
+
module Effective
|
388
|
+
module Snippets
|
389
|
+
class Post < Snippet
|
390
|
+
attribute :post_id, Integer
|
391
|
+
|
392
|
+
def post_object
|
393
|
+
# We're using ::Post to refer to the app/models/post.rb rather than the Effective::Snippets::Post
|
394
|
+
@post ||= ::Post.find_by_id(post_id)
|
395
|
+
end
|
396
|
+
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
```
|
401
|
+
|
402
|
+
### The View
|
403
|
+
|
404
|
+
This view partial is defined in app/views/effective/snippets/_post.html.haml
|
405
|
+
|
406
|
+
Some advanced snippet partials work best with CKEditor when you can start them with a parent div. This one isn't advanced enough to actually matter.
|
407
|
+
|
408
|
+
```haml
|
409
|
+
.post
|
410
|
+
%h3= post.post_object.title
|
411
|
+
%small
|
412
|
+
This is post number
|
413
|
+
= post.post_object.id
|
414
|
+
created on
|
415
|
+
= post.created_at
|
416
|
+
|
417
|
+
%p= post.post_object.summary
|
418
|
+
```
|
419
|
+
|
420
|
+
### The Javascript Options File
|
421
|
+
|
422
|
+
The javascript file should be placed in app/assets/javascripts/effective/snippets/post.js.coffee
|
423
|
+
|
424
|
+
```Coffeescript
|
425
|
+
getPosts = ->
|
426
|
+
posts = []
|
427
|
+
|
428
|
+
$.ajax
|
429
|
+
url: '/effective/snippets/posts'
|
430
|
+
type: 'GET'
|
431
|
+
dataType: 'json'
|
432
|
+
async: false
|
433
|
+
complete: (data) -> posts = data.responseJSON
|
434
|
+
|
435
|
+
posts
|
436
|
+
|
437
|
+
CKEDITOR.dialog.add 'post', (editor) ->
|
438
|
+
title: 'Post'
|
439
|
+
minWidth: 200,
|
440
|
+
minHeight: 100,
|
441
|
+
contents: [
|
442
|
+
{
|
443
|
+
id: 'post',
|
444
|
+
elements: [
|
445
|
+
{
|
446
|
+
id: 'post_id',
|
447
|
+
type: 'select',
|
448
|
+
label: 'Post',
|
449
|
+
items: getPosts(), # This only runs once, when the Dialog is created.
|
450
|
+
setup: (widget) -> this.setValue(widget.data.post_id)
|
451
|
+
commit: (widget) -> widget.setData('post_id', this.getValue())
|
452
|
+
}
|
453
|
+
]
|
454
|
+
}
|
455
|
+
]
|
456
|
+
```
|
457
|
+
|
458
|
+
So when the Snippet dialog for an 'Insert Snippet' -> Post is opened, an AJAX request to the server is made, and the list of Posts is read.
|
459
|
+
|
460
|
+
### The Controller
|
461
|
+
|
462
|
+
This controller is in no way part of the effective_regions/effective_ckeditor magic. It's just a one-off controller action.
|
463
|
+
|
464
|
+
For consistency with the other file paths (which do matter), I have namespaced the action under effective/snippets/, but this could be any valid rails route.
|
465
|
+
|
466
|
+
This controller is defined in app/controllers/effective/snippets/posts_controller.rb
|
467
|
+
|
468
|
+
```ruby
|
469
|
+
module Effective
|
470
|
+
module Snippets
|
471
|
+
class PostsController < ApplicationController
|
472
|
+
respond_to :json
|
473
|
+
|
474
|
+
def index
|
475
|
+
authorize! :index, Post # CanCan authorization here
|
476
|
+
|
477
|
+
@posts = Post.order(:title).map { |post| [post.title, post.id] }.to_json
|
478
|
+
|
479
|
+
respond_with @posts
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
```
|
485
|
+
|
486
|
+
and then in your routes.rb:
|
487
|
+
|
488
|
+
```ruby
|
489
|
+
get '/effective/snippets/posts', :to => 'effective/snippets/posts#index'
|
490
|
+
```
|
491
|
+
|
492
|
+
### Default Content
|
493
|
+
|
494
|
+
We can pre-populate an effective_region's default content with some posts. These posts will be displayed until a user edits that region and selects some specific posts.
|
495
|
+
|
496
|
+
```haml
|
497
|
+
%h2 Posts
|
498
|
+
|
499
|
+
= snippet_effective_region :sidebar_posts, :snippets => [:post] do
|
500
|
+
- Post.order(:created_at).first(5).each do |post|
|
501
|
+
= render_snippet Effective::Snippets::Post.new(:post_id => post.id)
|
502
|
+
```
|
503
|
+
|
504
|
+
|
505
|
+
### Summary
|
506
|
+
|
507
|
+
This Snippet makes an AJAX request to the server and receives a JSON response containing all the Posts. The Posts are displayed in a select drop-down, and when one is chosen, inserted into the given region.
|
508
|
+
|
509
|
+
|
510
|
+
## Templates
|
511
|
+
|
512
|
+
Templates are small pieces of reusable HTML that can be inserted into an `effective_region` with just one or two clicks.
|
513
|
+
|
514
|
+
Unlike snippets, there are no configurable options or anything. They're just pieces of raw HTML that can be dropped in and then immediately editted.
|
515
|
+
|
516
|
+
While handy, they were implemented as a bit of an after-thought, and will probably be refactored in future versions of effective_regions.
|
517
|
+
|
518
|
+
They take the form of two files, a model and a view.
|
519
|
+
|
520
|
+
### The Model
|
521
|
+
|
522
|
+
A model extends from `Effective::Templates::Template`
|
523
|
+
|
524
|
+
Any template models defined in app/models/effective/templates/*.rb will be automatically detected and usable.
|
525
|
+
|
526
|
+
The model here is very minimalistic. It's basically just to inform the full-screen editor that a View with the same name exists.
|
527
|
+
|
528
|
+
This model is defined at app/models/effective/templates/two_column.rb
|
529
|
+
|
530
|
+
```ruby
|
531
|
+
module Effective
|
532
|
+
module Templates
|
533
|
+
class TwoColumn < Template
|
534
|
+
def description
|
535
|
+
'Two Column Area'
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
end
|
540
|
+
```
|
541
|
+
|
542
|
+
### The View
|
543
|
+
|
544
|
+
The view is defined at app/models/effective/templates/_two_column.html.haml
|
545
|
+
|
546
|
+
```haml
|
547
|
+
.row
|
548
|
+
.col-sm-6
|
549
|
+
%p Left Column
|
550
|
+
.col-sm-6
|
551
|
+
%p Right column
|
552
|
+
```
|
553
|
+
|
554
|
+
## License
|
555
|
+
|
556
|
+
MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
|
557
|
+
|
558
|
+
Code and Effect is the product arm of [AgileStyle](http://www.agilestyle.com/), an Edmonton-based shop that specializes in building custom web applications with Ruby on Rails.
|
559
|
+
|
560
|
+
|
561
|
+
## Testing
|
562
|
+
|
563
|
+
The test suite for this gem is unfortunately not yet complete.
|
564
|
+
|
565
|
+
Run tests by:
|
566
|
+
|
567
|
+
```ruby
|
568
|
+
rake spec
|
569
|
+
```
|
570
|
+
|
571
|
+
|
572
|
+
## Contributing
|
573
|
+
|
574
|
+
1. Fork it
|
575
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
576
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
577
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
578
|
+
5. Bonus points for test coverage
|
579
|
+
6. Create new Pull Request
|
580
|
+
|