locomotive_plugins 1.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,26 @@
1
+ ## 1.0.0
2
+
3
+ * Added liquid filters
4
+ * Added liquid tags
5
+ * Removed content type scoping (use liquid tags instead)
6
+
7
+ ## v0.2.1
8
+
9
+ * Added custom initialization for plugins
10
+
11
+ ## v0.2.0
12
+
13
+ * Added DBModel functionality
14
+
15
+ ## v0.1.1
16
+
17
+ * Fixed bug with non-string filepaths, such as Rails Pathname object
18
+
19
+ ## v0.1.0
20
+
21
+ * Plugins can supply a config UI in HTML or HAML
22
+ * Added config variable for plugins
23
+ * Added before_filters for plugins
24
+ * Setup plugin registration
25
+ * Added plugin liquid drops
26
+ * Added content_type_scope
data/README.md ADDED
@@ -0,0 +1,229 @@
1
+
2
+ # Locomotive Plugins [![Build Status](https://secure.travis-ci.org/colibri-software/locomotive_plugins.png)](https://secure.travis-ci.org/colibri-software/locomotive_plugins.png)
3
+
4
+ Create plugins for [Locomotive CMS](http://locomotivecms.com/).
5
+
6
+
7
+ ## Installation
8
+
9
+ To create a Locomotive Plugin, create a ruby gem and then install this gem:
10
+
11
+
12
+ gem install locomotive_plugins
13
+
14
+ Alternatively if you're using Bundler, add the following line to your Gemfile:
15
+
16
+ gem 'locomotive_plugins'
17
+
18
+ and run `bundle install`.
19
+
20
+ To install the plugin in LocomotiveCMS, simply [create a LocomotiveCMS
21
+ app](http://doc.locomotivecms.com/installation/getting_started) and add your
22
+ plugin gem to the app's Gemfile.
23
+
24
+
25
+ ## Usage
26
+
27
+ To create a plugin, create a class which includes the `Locomotive::Plugin`
28
+ module and register it as a plugin:
29
+
30
+ class BasicAuth
31
+ include Locomotive::Plugin
32
+ end
33
+
34
+ LocomotivePlugins.register_plugin(BasicAuth)
35
+
36
+ The plugin will automatically be registered under an ID which is its
37
+ underscored name, in this case, `basic_auth`. To register it under a
38
+ different ID, simply supply the ID in the `register_plugin` call:
39
+
40
+ LocomotivePlugins::register_plugin(BasicAuth, 'auth')
41
+
42
+ ### Initialization
43
+
44
+ To initialize a plugin object, do not override the `initialize` method because
45
+ this method is defined by the `Locomotive::Plugin` module and used by
46
+ Locomotive. Instead, override the `initialize_plugin` method.
47
+
48
+ class MyPlugin
49
+ include Locomotive::Plugin
50
+
51
+ def initialize_plugin
52
+ # Custom initialization code
53
+ end
54
+ end
55
+
56
+ ### Before filters
57
+
58
+ A plugin may add a before filter which is run before every page load on the
59
+ website being hosted in Locomotive CMS. The before filter has access to the
60
+ controller which is being invoked, and a config variable which is set within
61
+ the Locomotive UI.
62
+
63
+ class BasicAuth
64
+ include Locomotive::Plugin
65
+
66
+ before_filter :authenticate
67
+
68
+ def authenticate
69
+ if self.config[:use_basic_auth]
70
+ self.controller.authenticate_or_request_with_http_basic do |username, password|
71
+ username = USER_ID && password == PASSWORD
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ ### Liquid
78
+
79
+ #### Drops
80
+
81
+ A plugin can add a liquid drop which can be accessed from page templates in
82
+ LocomotiveCMS. To do so, override the `to_liquid` method.
83
+
84
+ Plugin code:
85
+
86
+ class BasicAuth
87
+ include Locomotive::Plugin
88
+
89
+ def to_liquid
90
+ { :userid => self.get_authenticated_user_id }
91
+ end
92
+ end
93
+
94
+ Liquid code:
95
+
96
+ <p>Your User ID is: {{ plugins.basic_auth.userid }}</p>
97
+
98
+ This liquid code assumes that the plugin has been registered under the default
99
+ ID as described above.
100
+
101
+ #### Filters
102
+
103
+ A plugin can add liquid filters:
104
+
105
+ module Filters
106
+
107
+ def add_http(input)
108
+ if input.start_with?('http://')
109
+ input
110
+ else
111
+ "http://#{input}"
112
+ end
113
+ end
114
+
115
+ end
116
+
117
+ class MyPlugin
118
+ include Locomotive::Plugin
119
+
120
+ def self.liquid_filters
121
+ Filters
122
+ end
123
+ end
124
+
125
+ Locomotive will automatically prefix the filter with the plugin ID in the
126
+ liquid code:
127
+
128
+ <a href="{{ page.link | my_plugin_add_http }}">Click here!</a>
129
+
130
+ #### Tags
131
+
132
+ A plugin may also supply custom liquid tags. The custom tag class may override
133
+ the `render_disabled` method to specify what should be rendered if the plugin
134
+ is not enabled. By default, this will be the empty string. For example:
135
+
136
+ # Note that Liquid::Block is a subclass of Liquid::Tag
137
+ class Paragraph < Liquid::Block
138
+ def render(context)
139
+ "<p>#{render_all(@nodelist, context)}</p>"
140
+ end
141
+
142
+ def render_disabled(context)
143
+ render_all(@nodelist, context)
144
+ end
145
+ end
146
+
147
+ class Newline < Liquid::Tag
148
+ def render(context)
149
+ "<br />"
150
+ end
151
+ end
152
+
153
+ class MyPlugin
154
+ include Locomotive::Plugin
155
+
156
+ def self.liquid_tags
157
+ {
158
+ :paragraph => Paragraph,
159
+ :newline => Newline
160
+ }
161
+ end
162
+ end
163
+
164
+ Locomotive will automatically prefix the tag with the plugin ID in the liquid
165
+ code. Consider the following liquid code:
166
+
167
+ {% my_plugin_paragraph %}Some Text{% endmy_plugin_paragraph %}
168
+ Some Text{% my_plugin_newline %}
169
+
170
+ When `MyPlugin` is enabled, the code will be rendered to:
171
+
172
+ <p>Some Text</p>
173
+ Some Text<br />
174
+
175
+ When `MyPlugin` is disabled, the code will be rendered to:
176
+
177
+ Some Text
178
+ Some Text
179
+
180
+ ### Config UI
181
+
182
+ Plugins can provide a UI for setting configuration attributes. The UI should be
183
+ written as a [Handlebars.js](http://handlebarsjs.com/) template. When the
184
+ template is rendered, it is supplied with the array of content types in the
185
+ CMS. This can be used, for example, to create a select box for selecting a
186
+ content type to be acted upon by the plugin.
187
+
188
+ A config UI can be specified by a plugin in a few ways. The preferred method is
189
+ to override the `config_template_file` method on the plugin class. This method
190
+ must return a path to an HTML or HAML file. For more fine-grained control over
191
+ how the string is generated, the `config_template_string` can be overridden to
192
+ directly supply the HTML string to be rendered.
193
+
194
+ Here's an example of an HTML config file:
195
+
196
+ <li>
197
+ <label name="my_plugin_config">My Plugin Config</label>
198
+ <input type="text" name="my_plugin_config">
199
+ <p class="inline-hints">My Hint</p>
200
+ </li>
201
+ <li>
202
+ <label name="content_type_slugs">Content Types</label>
203
+ <select name="content_type_slugs" multiple="multiple">
204
+ {{#each content_types}}
205
+ <option value="{{ this.slug }}"> {{ this.name }}</option>
206
+ {{/each}}
207
+ </select>
208
+ </li>
209
+
210
+ ### Database Models
211
+
212
+ Plugins can persist data in the database through the use of DBModels. A DBModel
213
+ has all the functionality of a Mongoid document. For example:
214
+
215
+ class VisitCount < Locomotive::Plugin::DBModel
216
+ field :count, default: 0
217
+ end
218
+
219
+ class VisitCounter
220
+ include Locomotive::Plugin
221
+
222
+ has_one :visit_count, VisitCount
223
+ before_filter :increment_count
224
+
225
+ def increment_count
226
+ build_visit_count unless visit_count
227
+ visit_count.count += 1
228
+ end
229
+ end
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
5
+ require 'version'
6
+
7
+ require 'bundler/gem_tasks'
8
+ Bundler::GemHelper.install_tasks
9
+
10
+ require 'rspec/core/rake_task'
11
+ RSpec::Core::RakeTask.new(:spec)
12
+
13
+ task default: :spec
@@ -0,0 +1,162 @@
1
+
2
+ Dir.glob(File.join(File.dirname(__FILE__), 'plugin', '**', '*.rb')) do |f|
3
+ require f
4
+ end
5
+
6
+ module Locomotive
7
+
8
+ # Include this module in a class which should be registered as a Locomotive
9
+ # plugin. See the documentation for the various methods which can be called
10
+ # or overridden to describe the plugin
11
+ module Plugin
12
+
13
+ include ConfigUI
14
+ include DBModels
15
+ include Liquid
16
+
17
+ # @private
18
+ def self.included(base)
19
+ self.add_db_model_class_methods(base)
20
+ self.add_liquid_tag_methods(base)
21
+ base.extend ClassMethods
22
+ end
23
+
24
+ module ClassMethods
25
+ # Add a before filter to be called by the underlying controller
26
+ #
27
+ # @param meth[Symbol] the method to call
28
+ #
29
+ # @example
30
+ # before_filter :my_method
31
+ def before_filter(meth)
32
+ @before_filters ||= []
33
+ @before_filters << meth
34
+ end
35
+
36
+ # Get list of before filters
37
+ #
38
+ # @return [Array<Symbol>] an array of the method symbols
39
+ def before_filters
40
+ @before_filters ||= []
41
+ end
42
+
43
+ # Override this method to provide a module or array of modules to include
44
+ # as liquid filters in the site. All public methods in the module will be
45
+ # included as filters after being prefixed with the plugin id
46
+ # (#\\{plugin_id}_#\\{method_name})
47
+ #
48
+ # @example
49
+ # class MyPlugin
50
+ # def self.liquid_filters
51
+ # [ MyFilters, MoreFilters ]
52
+ # end
53
+ # end
54
+ def liquid_filters
55
+ nil
56
+ end
57
+
58
+ # Override this method to specify the liquid tags supplied by this
59
+ # plugin. The return value must be a hash whose keys are the tag names
60
+ # and values are the tag classes. The tag names will be included in
61
+ # Locomotive's liquid renderer after being prefixed with the plugin id
62
+ # (#\\{plugin_id}_#\\{tag_name})
63
+ #
64
+ # @example
65
+ # class MyPlugin
66
+ # def self.liquid_tags
67
+ # { :my_tag => MyTag, :other_tag => OtherTag }
68
+ # end
69
+ # end
70
+ def liquid_tags
71
+ {}
72
+ end
73
+
74
+ # Create a +has_many+ mongoid relationship to objects of the given class.
75
+ # The given class should be derived from Locomotive::Plugin::DBModel.
76
+ # This will add the following methods to the plugin object:
77
+ #
78
+ # [#\\{name}] Returns a list of persisted objects
79
+ #
80
+ # [#\\{name}=] Setter for the list of persisted objects
81
+ #
82
+ # @param name[String] the name of the relationship
83
+ #
84
+ # @param klass[Class] the class of the objects to be stored
85
+ def has_many(name, klass)
86
+ self.create_has_many_relationship(name, klass)
87
+ end
88
+
89
+ # Create a +has_one+ mongoid relationship to an object of the given
90
+ # class. The given class should be derived from
91
+ # Locomotive::Plugin::DBModel. This will add the following methods to the
92
+ # plugin object:
93
+ #
94
+ # [#\\{name}] Returns the related object
95
+ #
96
+ # [#\\{name}=] Setter for the related object
97
+ #
98
+ # [build_#\\{name}] Builds the related object
99
+ #
100
+ # [create_#\\{name}] Builds and saves the related object
101
+ #
102
+ # @param name[String] the name of the relationship
103
+ #
104
+ # @param klass[Class] the class of the object to be stored
105
+ def has_one(name, klass)
106
+ self.create_has_one_relationship(name, klass)
107
+ end
108
+ end
109
+
110
+ # This variable is set by LocomotiveCMS. It contains the controller which
111
+ # is handling the current request
112
+ attr_accessor :controller
113
+
114
+ # This variable is set by LocomotiveCMS. It contains the current
115
+ # configuration hash for the plugin
116
+ attr_accessor :config
117
+
118
+ # Initialize by supplying the current config parameters. Note that this
119
+ # method should not be overridden for custom initialization of plugin
120
+ # objects. Instead, override the initialize_plugin method
121
+ def initialize(config)
122
+ self.config = config
123
+ self.load_or_create_db_model_container!
124
+ self.save_db_model_container
125
+ self.initialize_plugin
126
+ end
127
+
128
+ # Override this method to supply custom initialization code for the plugin
129
+ # object. <b>Do not override the normal +initialize+ method</b>
130
+ def initialize_plugin
131
+ end
132
+
133
+ # Get all before filters which have been added to the controller
134
+ def before_filters
135
+ self.class.before_filters
136
+ end
137
+
138
+ # Override this method to provide a liquid drop which should be available
139
+ # in the CMS
140
+ def to_liquid
141
+ nil
142
+ end
143
+
144
+ # Override this method to supply a path to the config UI template file.
145
+ # This file should be an HTML or HAML file using the Handlebars.js
146
+ # templating language.
147
+ def config_template_file
148
+ nil
149
+ end
150
+
151
+ # This method may be overridden to supply the raw HTML string to be used
152
+ # for the config UI. The HTML string may be a Handlebars.js template. By
153
+ # default, this method will use the file supplied by the
154
+ # +config_template_file+ method to construct the string (see
155
+ # #config_template_file)
156
+ def config_template_string
157
+ self.default_config_template_string
158
+ end
159
+
160
+ end
161
+
162
+ end
@@ -0,0 +1,26 @@
1
+
2
+ module Locomotive
3
+ module Plugin
4
+ # @private
5
+ module ConfigUI
6
+
7
+ protected
8
+
9
+ def default_config_template_string
10
+ filepath = self.config_template_file
11
+
12
+ if filepath
13
+ filepath = filepath.to_s
14
+ if filepath.end_with?('haml')
15
+ Haml::Engine.new(IO.read(filepath)).render
16
+ else
17
+ IO.read(filepath)
18
+ end
19
+ else
20
+ nil
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end