locomotive_cms 0.0.3.1 → 0.0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,6 +7,7 @@ class ContentInstance
7
7
  include CustomFields::ProxyClassEnabler
8
8
 
9
9
  ## fields (dynamic fields) ##
10
+ field :_slug
10
11
  field :_position_in_list, :type => Integer, :default => 0
11
12
 
12
13
  ## validations ##
@@ -16,6 +17,7 @@ class ContentInstance
16
17
  embedded_in :content_type, :inverse_of => :contents
17
18
 
18
19
  ## callbacks ##
20
+ before_save :set_slug
19
21
  before_create :add_to_list_bottom
20
22
 
21
23
  ## named scopes ##
@@ -29,16 +31,29 @@ class ContentInstance
29
31
 
30
32
  protected
31
33
 
34
+ def set_slug
35
+ _alias = self.highlighted_field_alias
36
+ self._slug = self.send(_alias).parameterize('_')
37
+ end
38
+
32
39
  def add_to_list_bottom
33
40
  Rails.logger.debug "add_to_list_bottom"
34
41
  self._position_in_list = self.content_type.contents.size
35
42
  end
36
43
 
37
44
  def require_highlighted_field
38
- _alias = self.content_type.highlighted_field._alias.to_sym
45
+ _alias = self.highlighted_field_alias
39
46
  if self.send(_alias).blank?
40
47
  self.errors.add(_alias, :blank)
41
48
  end
42
49
  end
43
50
 
51
+ def highlighted_field_value
52
+ self.send(self.content_type.highlighted_field._name)
53
+ end
54
+
55
+ def highlighted_field_alias
56
+ self.content_type.highlighted_field._alias.to_sym
57
+ end
58
+
44
59
  end
@@ -0,0 +1,32 @@
1
+ module Models
2
+ module Extensions
3
+ module Page
4
+ module Templatized
5
+
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+
10
+ belongs_to_related :content_type
11
+
12
+ field :templatized, :type => Boolean, :default => false
13
+
14
+ field :content_type_visible_column
15
+
16
+ before_validate :set_slug_if_templatized
17
+ end
18
+
19
+ module InstanceMethods
20
+
21
+ def set_slug_if_templatized
22
+ self.slug = 'content_type_template' if self.templatized?
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+
@@ -6,6 +6,7 @@ class Page
6
6
  include Models::Extensions::Page::Tree
7
7
  include Models::Extensions::Page::Parts
8
8
  include Models::Extensions::Page::Render
9
+ include Models::Extensions::Page::Templatized
9
10
 
10
11
  ## fields ##
11
12
  field :title
@@ -31,8 +32,8 @@ class Page
31
32
 
32
33
  ## named scopes ##
33
34
  named_scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb
34
- named_scope :index, :where => { :slug => 'index', :depth => 0, :published => true }
35
- named_scope :not_found, :where => { :slug => '404', :depth => 0, :published => true }
35
+ named_scope :index, :where => { :slug => 'index', :depth => 0 }
36
+ named_scope :not_found, :where => { :slug => '404', :depth => 0 }
36
37
  named_scope :published, :where => { :published => true }
37
38
 
38
39
  ## behaviours ##
@@ -45,8 +45,6 @@ class AssetUploader < CarrierWave::Uploader::Base
45
45
  end
46
46
  end
47
47
 
48
- puts "content_type = #{value}"
49
-
50
48
  model.content_type = value
51
49
  end
52
50
 
@@ -1,7 +1,6 @@
1
1
  - if contents.empty?
2
2
  %p.no-items= t('.no_items', :url => new_admin_content_url(@content_type.slug))
3
3
  - else
4
- - puts contents.inspect
5
4
  %ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position_in_list'}" }
6
5
  - contents.each do |content|
7
6
  %li.content{ :id => "content-#{content._id}" }
@@ -1,5 +1,8 @@
1
1
  - title link_to(@account.name.blank? ? @account.name_was : @account.name, '#', :rel => 'my_account_name', :title => t('.ask_for_name'), :class => 'editable')
2
2
 
3
+ - content_for :head do
4
+ = javascript_include_tag 'admin/account'
5
+
3
6
  - content_for :submenu do
4
7
  = render 'admin/shared/menu/settings'
5
8
 
@@ -11,8 +11,13 @@
11
11
  - if not @page.index? and not @page.not_found?
12
12
  = f.input :parent_id, :as => :select, :collection => parent_pages_options, :include_blank => false
13
13
 
14
- = f.input :slug, :required => false, :hint => @page.slug.blank? ? '&nbsp;' : @page.url, :input_html => { :data_url => get_path_admin_pages_url, :disabled => @page.index? || @page.not_found? }
15
-
14
+ = f.input :slug, :required => false, :hint => @page.slug.blank? ? '&nbsp;' : @page.url, :input_html => { :data_url => get_path_admin_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized?}" }
15
+
16
+ = f.custom_input :templatized, :css => 'toggle' do
17
+ = f.check_box :templatized
18
+
19
+ = f.input :content_type_id, :as => :select, :collection => current_site.content_types.all.to_a, :include_blank => false, :wrapper_html => { :style => "#{'display: none' unless @page.templatized?}" }
20
+
16
21
  = f.custom_input :published, :css => 'toggle' do
17
22
  = f.check_box :published
18
23
 
@@ -1,4 +1,4 @@
1
- %li{ :id => "item-#{page.id}", :class => "#{'not-found' if page.not_found? }"}
1
+ %li{ :id => "item-#{page.id}", :class => "#{'not-found' if page.not_found? } #{'templatized' if page.templatized?}"}
2
2
  - if not page.index? and not page.children.empty?
3
3
  = image_tag 'admin/list/icons/node_closed.png', :class => 'toggler'
4
4
  %em
@@ -10,7 +10,7 @@
10
10
 
11
11
  = stylesheet_link_tag 'admin/layout', 'admin/jquery/ui', 'admin/plugins/toggle', 'admin/menu', 'admin/buttons', 'admin/formtastic', 'admin/formtastic_changes', 'admin/application', :media => 'screen', :cache => Rails.env.production? && !Locomotive.heroku?
12
12
 
13
- = javascript_include_tag 'admin/jquery', 'admin/jquery.ui', 'admin/rails', 'admin/utils', 'admin/plugins/shortcut', 'admin/plugins/toggle', 'admin/plugins/growl', 'admin/plugins/cookie', 'admin/application', 'admin/locales/datepicker_fr', :cache => Rails.env.production? && !Locomotive.heroku?
13
+ = javascript_include_tag 'admin/jquery', 'admin/jquery.ui', 'admin/rails', 'admin/utils', 'admin/plugins/subscribe', 'admin/plugins/shortcut', 'admin/plugins/toggle', 'admin/plugins/growl', 'admin/plugins/cookie', 'admin/application', 'admin/locales/datepicker_fr', :cache => Rails.env.production? && !Locomotive.heroku?
14
14
 
15
15
  %script{ :type => 'text/javascript' }
16
16
  = find_and_preserve(growl_message)
@@ -268,6 +268,7 @@ en:
268
268
  page:
269
269
  published: "Only authenticated accounts can view unpublished pages."
270
270
  cache_strategy: "Cache the page for better performance. The 'Simple' choice is a good compromise."
271
+ templatized: "Use the page as a template for a model you defined."
271
272
  snippet:
272
273
  slug: "You need to know it in order to insert the snippet inside a page or a layout"
273
274
  site:
@@ -290,6 +290,7 @@ fr:
290
290
  page:
291
291
  published: "Seuls les administrateurs authentifiés peuvent voir une page non publiée."
292
292
  cache_strategy: "Cache la page pour de meilleure performance. L'option 'Simple' est le meilleur compromis."
293
+ templatized: "Utilise la page comme un template pour un modèle défini."
293
294
  snippet:
294
295
  slug: "Utilisé pour insérer le snippet dans une page ou un gabarit."
295
296
  site:
@@ -10,7 +10,6 @@ require 'locomotive/httparty'
10
10
  require 'locomotive/inherited_resources'
11
11
  require 'locomotive/admin_responder'
12
12
 
13
- require 'redcloth'
14
13
  require 'mongo_session_store/mongoid'
15
14
 
16
15
  module Locomotive
@@ -8,6 +8,8 @@ require 'formtastic'
8
8
  require 'mongoid'
9
9
  require 'mongoid_acts_as_tree'
10
10
  require 'httparty'
11
+ require 'redcloth'
12
+ require 'actionmailer_with_request'
11
13
 
12
14
  # FIXME: get rid of it once custom_fields is a gem
13
15
  require File.dirname(__FILE__) + '/../../vendor/plugins/custom_fields/init.rb'
@@ -11,7 +11,9 @@ module Locomotive
11
11
  end
12
12
  end
13
13
 
14
-
14
+ def highlighted_field_value
15
+ @source.highlighted_field_value
16
+ end
15
17
 
16
18
  end
17
19
  end
@@ -3,7 +3,15 @@ module Locomotive
3
3
  module Drops
4
4
  class Page < Base
5
5
 
6
- liquid_attributes << :title << :slug
6
+ # liquid_attributes << :title << :slug
7
+
8
+ def title
9
+ @source.templatized? ? @context['content_instance'].highlighted_field_value : @source.title
10
+ end
11
+
12
+ def slug
13
+ @source.templatized? ? @source.content_type.slug.singularize : @source.slug
14
+ end
7
15
 
8
16
  def children
9
17
  @children ||= liquify(*@source.children)
@@ -29,10 +29,12 @@ module Locomotive
29
29
 
30
30
  source = context.registers[@site_or_page.to_sym]
31
31
 
32
+ puts "#{@site_or_page.to_sym} / source = #{source.inspect}"
33
+
32
34
  if source.respond_to?(:name) # site ?
33
- source = source.pages.first # start from home page
35
+ source = source.pages.index.first # start from home page
34
36
  else
35
- source = source.parent
37
+ source = source.parent || source
36
38
  end
37
39
 
38
40
  output = %{<ul id="nav">}
@@ -23,13 +23,28 @@ module Locomotive
23
23
  path.gsub!(/^\//, '')
24
24
  path = 'index' if path.blank?
25
25
 
26
- if page = current_site.pages.where(:fullpath => path).first
26
+ if path != 'index'
27
+ dirname = File.dirname(path).gsub(/^\.$/, '') # also look for templatized page path
28
+ path = [path, File.join(dirname, 'content_type_template').gsub(/^\//, '')]
29
+ end
30
+
31
+ # TODO: path is not correctly built + find content instance in order to render a 404 page if not found
32
+
33
+ if page = current_site.pages.any_in(:fullpath => [*path]).first
27
34
  if not page.published? and current_admin.nil?
28
35
  page = nil
36
+ else
37
+ if page.templatized?
38
+ @content_instance = page.content_type.contents.where(:_slug => File.basename(path.first)).first
39
+
40
+ if @content_instance.nil? # content instance not found
41
+ page = nil
42
+ end
43
+ end
29
44
  end
30
45
  end
31
46
 
32
- page || current_site.pages.not_found.first
47
+ page || current_site.pages.not_found.published.first
33
48
  end
34
49
 
35
50
  def locomotive_context
@@ -43,6 +58,11 @@ module Locomotive
43
58
  'current_page' => self.params[:page]
44
59
  }
45
60
 
61
+ if @page.templatized? # add instance from content type
62
+ assigns['content_instance'] = @content_instance
63
+ assigns[@page.content_type.slug.singularize] = @content_instance # just here to help to write readable liquid code
64
+ end
65
+
46
66
  registers = { :controller => self, :site => current_site, :page => @page }
47
67
 
48
68
  ::Liquid::Context.new(assigns, registers)
@@ -0,0 +1,5 @@
1
+ $(document).ready(function() {
2
+ $.subscribe('form.saved.success', function(event, data) {
3
+ $('#global-actions-bar a:first').html($('#my_account_name').val());
4
+ }, []);
5
+ });
@@ -31,6 +31,19 @@ $(document).ready(function() {
31
31
  }
32
32
  });
33
33
 
34
+ // templatized feature
35
+
36
+ $.subscribe('toggle.page_templatized.checked', function(event, data) {
37
+ $('#page_slug_input').hide();
38
+ $('#page_content_type_id_input').show();
39
+ }, []);
40
+
41
+ $.subscribe('toggle.page_templatized.unchecked', function(event, data) {
42
+ $('#page_slug_input').show();
43
+ $('#page_slug').val(makeSlug($('#page_title').val())).addClass('touched');
44
+ $('#page_content_type_id_input').hide();
45
+ }, []);
46
+
34
47
  // automatic slug from page title
35
48
  $('#page_title').keypress(function() {
36
49
  var input = $(this);
@@ -36,6 +36,7 @@ jQuery.fn.saveWithShortcut = function() {
36
36
  form.find('li.error input').eq(0).focus();
37
37
  } else {
38
38
  $.growl('success', data.notice);
39
+ $.publish('form.saved.success', [data]);
39
40
  }
40
41
  };
41
42
 
@@ -0,0 +1,367 @@
1
+ /*
2
+ * jquery.subscribe.1.1
3
+ *
4
+ * Implementation of publish/subcription framework for jQuery
5
+ * Requires use of jQuery. Tested with jQuery 1.3 and above
6
+ *
7
+ *
8
+ * Copyright (c) 2008 Eric Chijioke (obinna a-t g mail dot c o m)
9
+ *
10
+ *
11
+ * Dual licensed under the MIT and GPL licenses:
12
+ * http://www.opensource.org/licenses/mit-license.php
13
+ * http://www.gnu.org/licenses/gpl.html
14
+ *
15
+ * Release Notes:
16
+ *
17
+ * version 1.1:
18
+ *
19
+ * Fixed unexpected behavior which can occur when a script in a embedded page (page loaded in div,tab etc.) subscribes a handler for a topic using
20
+ * the jQuery subscribe ($.subscribe) or a no-id element but this subscribe plugin is not reloaded within that embedded page (for example, when
21
+ * script is included in containing page) . In this case, if the embedded page is reloaded without reloading the entire page (and plugin), the
22
+ * subscription could be made multiple times for the topic, which will call the handler multiple times each time the topic is published.
23
+ * Code has been added to prevent this when the subscription is made using the non-element subscribe ($.subscribe()), which assures that only one
24
+ * subscription is made for a topic for a given window/frame. To prevent this from happening for an element subscription ($elem.subscribe()), make
25
+ * sure that the element has an id attribute.
26
+ */
27
+
28
+
29
+ (function($){
30
+
31
+ _subscribe_topics = {};
32
+ _subscribe_handlers = {};
33
+
34
+ _subscribe_getDocumentWindow = function(document){
35
+
36
+ return document.parentWindow || document.defaultView;
37
+ };
38
+
39
+ $.fn.extend({
40
+
41
+ /**
42
+ * Creates a new topic without any subscribers.
43
+ * Not usually used explicitly
44
+ */
45
+ createTopic : function(topic) {
46
+ if(topic && !_subscribe_topics[topic]) {
47
+
48
+ _subscribe_topics[topic] = {};
49
+ _subscribe_topics[topic].objects = {};
50
+ _subscribe_topics[topic].objects['__noId__'] = [];
51
+ }
52
+
53
+ return this;
54
+ },
55
+
56
+ /**
57
+ * Destroy an existing topic and unsubscribe all subscribers
58
+ */
59
+ destroyTopic : function(topic) {
60
+
61
+ if(topic && _subscribe_topics[topic]) {
62
+
63
+ for(i in _subscribe_topics[topic].objects) {
64
+
65
+ var object = _subscribe_topics[topic].objects[i];
66
+
67
+ if($.isArray(object)) { // handle '__noId__' elements
68
+
69
+ if(object.length > 0) {
70
+
71
+ for(j in object) {
72
+
73
+ object[j].unbind(topic);
74
+ }
75
+ }
76
+
77
+ } else {
78
+
79
+ object.unbind(topic,data);
80
+ }
81
+ }
82
+ }
83
+
84
+ delete _subscribe_topics[topic];
85
+
86
+ return this;
87
+ },
88
+
89
+ /**
90
+ * Subscribes an object to particular topic with a handler.
91
+ * When the topic is published, this handler will be executed.
92
+ *
93
+ * Parameters:
94
+ * -topic- is the string name of the topic
95
+ * -handler- is a handler function and is of the form function(event, data), in which the 'this' refers to the element itself.
96
+ * handler can be a function or can be a string referring to a function previously registered using the $.subscribeHandler() function
97
+ * Note: returning 'false' from the handler will prevent subsequent handlers from being executed on this element during
98
+ * this call.
99
+ * -data- (optional) is additional data that is passed to the event handler as event.data when the topic is published
100
+ *
101
+ * Note: Unexpected behavior can occur when a script in a embedded page (page loaded in div,tab etc.) subscribes a handler for a topic using
102
+ * the jQuery subscribe ($.subscribe) or a no-id element but this subscribe plugin is not reloaded within that embedded page (for example, when
103
+ * script is included in containing page) . In this case, if the embedded page is reloaded without reloading the entire page (and plugin), the
104
+ * subscription could be made multiple times for the topic, which will call the handler multiple times each time the topic is published.
105
+ * Code has been added to prevent this when the subscription is made using the non-element subscribe ($.subscribe()), which assures that only one
106
+ * subscription is made for a topic for a given window/frame. To prevent this from happening for an element subscription ($elem.subscribe()), make
107
+ * sure that the element has an id attribute.
108
+ */
109
+ subscribe : function(topic, handler, data) {
110
+
111
+ if(this[0] && topic && handler) {
112
+
113
+ this.createTopic(topic);
114
+
115
+ if(this.attr('id')) {
116
+
117
+ _subscribe_topics[topic].objects[this.attr('id')] = this;
118
+
119
+ } else {
120
+
121
+ //do not subscribe the same window/frame document multiple times, this causes unexpected behavior of executing embedded scripts multiple times
122
+ var noIdObjects = _subscribe_topics[topic].objects['__noId__'];
123
+
124
+ if(this[0].nodeType == 9) { //if document is being bound (the case for non-element jQuery subscribing ($.subscribe)
125
+
126
+ for ( var index in noIdObjects) {
127
+
128
+ var noIdObject = noIdObjects[index];
129
+
130
+ if(noIdObject[0].nodeType == 9 && _subscribe_getDocumentWindow(this[0]).frameElement == _subscribe_getDocumentWindow(noIdObject[0]).frameElement ) {
131
+
132
+ return this;
133
+ }
134
+ }
135
+ }
136
+
137
+ var exists = false;
138
+ for(var i = 0; i < noIdObjects.length; i++){
139
+ if(noIdObjects[i] == this){
140
+ exists = true;
141
+ break;
142
+ }
143
+ }
144
+
145
+ if(!exists) {
146
+
147
+ _subscribe_topics[topic].objects['__noId__'].push(this);
148
+ }
149
+ }
150
+
151
+ if(typeof(handler) == 'function') {
152
+
153
+ this.bind(topic, data, handler);
154
+
155
+ } else if(typeof(handler) == 'string' && typeof(_subscribe_handlers[handler]) == 'function') {
156
+
157
+ this.bind(topic, data, _subscribe_handlers[handler]);
158
+ }
159
+ }
160
+
161
+ return this;
162
+ },
163
+
164
+ /**
165
+ * Remove a subscription of an element to a topic.
166
+ * This will unbind stop all handlers from executing on this element when the topic
167
+ * is published
168
+ */
169
+ unsubscribe : function(topic) {
170
+
171
+ if(topic) {
172
+
173
+ if(_subscribe_topics[topic]) {
174
+
175
+ if(this.attr('id')) {
176
+
177
+ var object = _subscribe_topics[topic].objects[this.attr('id')];
178
+
179
+ if(object) {
180
+
181
+ delete _subscribe_topics[topic].objects[this.attr('id')];
182
+ }
183
+
184
+ } else {
185
+
186
+ var noIdObjects = _subscribe_topics[topic].objects['__noId__'];
187
+
188
+ for(var i = 0; i < noIdObjects.length; i++){
189
+
190
+ if(noIdObjects[i] == this){
191
+
192
+ subscribe_topics[topic].objects['__noId__'].splice(index,1);
193
+ break;
194
+ }
195
+ }
196
+ }
197
+ }
198
+
199
+ this.unbind(topic);
200
+ }
201
+
202
+ return this;
203
+ },
204
+
205
+ /**
206
+ * Publishes a topic (triggers handlers on all topic subscribers)
207
+ * This ends up calling any subscribed handlers which are functions of the form function (event, data)
208
+ * where: event - is a standard jQuery event object
209
+ * data - is the data parameter that was passed to this publish() method
210
+ * event.data - is the data parameter passed to the subscribe() function when this published topic was subscribed to
211
+ * event.target - is the dom element that subscribed to the event (or the document element if $.subscribe() was used)
212
+ *
213
+ * Parameters:
214
+ * -topic- is the string name of the topic
215
+ * -data- (optional) is additional data that is passed to the event handler 'data' parameter when the topic is published
216
+ * handler can be a function or can be a string referring to a function previously registered using the $.subscribeHandler() function
217
+ * -originalEvent- (optional) may be passed in a reference to an event which triggered this publishing. This will be passed as the
218
+ * 'originalEvent' field of the triggered event which will allow for controlling the propagation of higher level events
219
+ * from within the topic handler. In other words, this allows one to cancel execution of all subsequent handlers on the originalEvent
220
+ * for this element by return 'false' from a handler that is subscribed to the topic published here. This can be especially useful
221
+ * in conjunction with publishOnEvent(), where a topic is published when an event executes (such as a click) and we want our
222
+ * handler logic prevent additional topics from being published (For example if our topic displays a 'delete confirm' dialog on click and
223
+ * the user cancels, we may want to prevent subsequent topics bound to the original click event from being published).
224
+ */
225
+ publish : function(topic, data, originalEvent) {
226
+
227
+ if(topic) {
228
+
229
+ this.createTopic(topic);
230
+
231
+ //if an orginal event exists, need to modify the event object to prevent execution of all
232
+ //other handlers if the result of the handler is false (which calls stopPropagation())
233
+
234
+ var subscriberStopPropagation = function(){
235
+
236
+ this.isImmediatePropagationStopped = function(){
237
+ return true;
238
+ };
239
+
240
+ (new $.Event).stopPropagation();
241
+
242
+ if(this.originalEvent) {
243
+
244
+ this.originalEvent.isImmediatePropagationStopped = function(){
245
+ return true;
246
+ };
247
+
248
+ this.originalEvent.stopPropagation = subscriberStopPropagation;
249
+ }
250
+ }
251
+
252
+ var event = jQuery.Event(topic);
253
+ $.extend(event,{originalEvent: originalEvent, stopPropagation: subscriberStopPropagation});
254
+
255
+ for(i in _subscribe_topics[topic].objects) {
256
+
257
+ var object = _subscribe_topics[topic].objects[i];
258
+
259
+ if($.isArray(object)) { // handle '__noId__' elements (if any)
260
+
261
+ if(object.length > 0) {
262
+
263
+ for(j in object) {
264
+
265
+ object[j].trigger( event,data);
266
+ }
267
+ }
268
+
269
+ } else {
270
+
271
+ object.trigger( event,data);
272
+ }
273
+ }
274
+
275
+ }
276
+
277
+ return this;
278
+ },
279
+
280
+ /**
281
+ * Binds an objects event handler to a publish call
282
+ *
283
+ * Upon the event triggering, this ends up calling any subscribed handlers which are functions of the form function (event, data)
284
+ * where: event- is a standard jQuery event object
285
+ * event.data- is the data parameter passed to the subscribe() function when this published topic was subscribed to
286
+ * data- is the data parameter that was passed to this publishOnEvent() method
287
+ * Parameters:
288
+ * -event- is the string name of the event upon which to publish the topic
289
+ * -topic- is the string name of the topic to publish when the event occurs
290
+ * -data- (optional) is additional data which will be passed in to the publish() method ant hen available as the second ('data')
291
+ * parameter to the topic handler
292
+ */
293
+ publishOnEvent : function(event, topic, data) {
294
+
295
+ if(event && topic) {
296
+
297
+ this.createTopic(topic);
298
+
299
+ this.bind(event, data, function (e) {
300
+
301
+ $(this).publish(topic, e.data, e);
302
+ });
303
+ }
304
+
305
+ return this;
306
+ }
307
+ });
308
+
309
+ /**
310
+ * Make publish(), createTopic() and destroyTopic() callable without an element context
311
+ * Often don't need a context to subscribe, publish, create or destroy a topic.
312
+ * We will call from the document context
313
+ */
314
+ $.extend({
315
+
316
+ /**
317
+ * Subscribe an event handler to a topic without an element context
318
+ *
319
+ * Note: Caution about subscribing using same document to topic multiple time (maybe by loading subscribe script multiple times)
320
+ *
321
+ */
322
+ subscribe : function(topic, handler, data) {
323
+ return $(window).subscribe(topic, handler, data);
324
+
325
+ },
326
+
327
+ /**
328
+ * Unsubscribe an event handler for a topic without an element context
329
+ *
330
+ */
331
+ unsubscribe : function(topic, handler, data) {
332
+
333
+ return $(window).unsubscribe(topic, handler, data);
334
+
335
+ },
336
+
337
+ /**
338
+ * Register a handler function which can then be referenced by name when calling subscribe()
339
+ */
340
+ subscribeHandler: function(name, handler) {
341
+
342
+ if(name && handler && typeof(handler) == "function") {
343
+
344
+ _subscribe_handlers[name] = handler;
345
+ }
346
+
347
+ return $(window);
348
+ },
349
+
350
+ publish: function(topic, data) {
351
+
352
+ return $(window).publish(topic,data);
353
+ },
354
+
355
+ createTopic: function(topic) {
356
+
357
+ return $(window).createTopic(topic);
358
+ },
359
+
360
+ destroyTopic: function(topic) {
361
+
362
+ return $(window).destroyTopic(topic);
363
+ }
364
+
365
+ });
366
+
367
+ })(jQuery);
@@ -64,6 +64,8 @@
64
64
  $(element).parent().css("background-color", settings.off_bg_color);
65
65
  $(element).parent().parent().prev().removeAttr("checked");
66
66
  $(element).removeClass("left").addClass("right");
67
+
68
+ $.publish('toggle.' + $(element).parent().parent().prev().attr('id') + '.unchecked', []);
67
69
  });
68
70
 
69
71
  }else{
@@ -78,6 +80,7 @@
78
80
  $(element).parent().parent().prev().attr("checked","checked");
79
81
  $(element).removeClass("right").addClass("left");
80
82
 
83
+ $.publish('toggle.' + $(element).parent().parent().prev().attr('id') + '.checked', []);
81
84
  });
82
85
 
83
86
  }
@@ -1,7 +1,7 @@
1
1
  $(document).ready(function() {
2
2
 
3
3
  var defaultValue = $('fieldset.editable-list li.template input[type=text]').val();
4
-
4
+
5
5
  /* __ fields ___ */
6
6
  $('fieldset.editable-list li.template input[type=text]').focus(function() {
7
7
  if ($(this).hasClass('void') && $(this).parents('li').hasClass('template'))
@@ -32,5 +32,8 @@ $(document).ready(function() {
32
32
  e.preventDefault();
33
33
  e.stopPropagation();
34
34
  });
35
-
35
+
36
+ $.subscribe('form.saved.success', function(event, data) {
37
+ $('#header h1 a').html($('#current_site_name').val());
38
+ }, []);
36
39
  });
@@ -117,7 +117,7 @@ ul.assets li.asset.last {
117
117
  margin-right: 0px;
118
118
  }
119
119
 
120
- ul.assets li.asset h4 { margin: 0px; height: 30px; }
120
+ ul.assets li.asset h4 { margin: 0px; height: 30px; border-bottom: 1px solid #ccced7; }
121
121
 
122
122
  ul.assets li.asset h4 a {
123
123
  position: relative;
@@ -205,6 +205,11 @@ div#uploadAssetsInputQueue { display: none; }
205
205
  cursor: move;
206
206
  }
207
207
 
208
+ #pages-list ul.folder li.templatized em {
209
+ background-position: left -62px;
210
+ cursor: pointer;
211
+ }
212
+
208
213
  #pages-list li .toggler {
209
214
  position: absolute;
210
215
  top: 9px;
@@ -60,7 +60,7 @@ form.formtastic fieldset.foldable.folded legend span em {
60
60
  form.formtastic fieldset.foldable ol {
61
61
  clear: both;
62
62
  width: 100%;
63
- overflow: hidden;
63
+ overflow: hidden;
64
64
  }
65
65
 
66
66
  form.formtastic fieldset.foldable.folded ol { display: none; }
@@ -80,6 +80,7 @@ form.formtastic fieldset.inputs ol {
80
80
  padding-top: 15px;
81
81
  padding-bottom: 5px;
82
82
  background: #ebedf4 url(/images/admin/form/footer.png) no-repeat 0 bottom;
83
+ border-top: 1px solid #ccced7;
83
84
  }
84
85
 
85
86
  @media screen and (-webkit-min-device-pixel-ratio:0) {
@@ -2,6 +2,7 @@
2
2
  background: #ebedf4 url(/images/admin/form/footer.png) no-repeat 0 bottom;
3
3
  width: 880px;
4
4
  padding: 20px 20px;
5
+ border-top: 1px solid #ccced7;
5
6
  }
6
7
 
7
8
  #page-parts {
@@ -12,6 +13,12 @@
12
13
  height: 30px;
13
14
  }
14
15
 
16
+ #page-parts .nav {
17
+ position: relative;
18
+ top: 1px;
19
+ z-index: 990;
20
+ }
21
+
15
22
  #page-parts .nav a {
16
23
  float: left;
17
24
  display: block;
@@ -52,19 +52,19 @@ describe 'Locomotive rendering system' do
52
52
 
53
53
  it 'should retrieve the index page /' do
54
54
  @controller.request.fullpath = '/'
55
- @controller.current_site.pages.expects(:where).with({ :fullpath => 'index' }).returns([@page])
55
+ @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{index} }).returns([@page])
56
56
  @controller.send(:locomotive_page).should_not be_nil
57
57
  end
58
58
 
59
59
  it 'should also retrieve the index page (index.html)' do
60
60
  @controller.request.fullpath = '/index.html'
61
- @controller.current_site.pages.expects(:where).with({ :fullpath => 'index' }).returns([@page])
61
+ @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{index} }).returns([@page])
62
62
  @controller.send(:locomotive_page).should_not be_nil
63
63
  end
64
64
 
65
65
  it 'should retrieve it based on the full path' do
66
66
  @controller.request.fullpath = '/about_us/team.html'
67
- @controller.current_site.pages.expects(:where).with({ :fullpath => 'about_us/team' }).returns([@page])
67
+ @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{about_us/team about_us/content_type_template} }).returns([@page])
68
68
  @controller.send(:locomotive_page).should_not be_nil
69
69
  end
70
70
 
@@ -74,6 +74,31 @@ describe 'Locomotive rendering system' do
74
74
  @controller.send(:locomotive_page).should be_true
75
75
  end
76
76
 
77
+ context 'templatized page' do
78
+
79
+ before(:each) do
80
+ @content_type = Factory.build(:content_type, :site => nil)
81
+ @page.templatized = true
82
+ @page.content_type = @content_type
83
+ @controller.request.fullpath = '/projects/edeneo.html'
84
+ @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{projects/edeneo projects/content_type_template} }).returns([@page])
85
+ end
86
+
87
+ it 'sets the content_instance variable' do
88
+ @content_type.contents.stubs(:where).returns([42])
89
+ @controller.send(:locomotive_page).should_not be_nil
90
+ @controller.instance_variable_get(:@content_instance).should == 42
91
+ end
92
+
93
+ it 'returns the 404 page if the instance does not exist' do
94
+ @content_type.contents.stubs(:where).returns([])
95
+ @controller.current_site.pages.expects(:not_found).returns([true])
96
+ @controller.send(:locomotive_page).should be_true
97
+ @controller.instance_variable_get(:@content_instance).should be_nil
98
+ end
99
+
100
+ end
101
+
77
102
  context 'non published page' do
78
103
 
79
104
  before(:each) do
@@ -83,7 +108,7 @@ describe 'Locomotive rendering system' do
83
108
 
84
109
  it 'should return the 404 page if the page has not been published yet' do
85
110
  @controller.request.fullpath = '/contact'
86
- @controller.current_site.pages.expects(:where).with({ :fullpath => 'contact' }).returns([@page])
111
+ @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{contact content_type_template} }).returns([@page])
87
112
  @controller.current_site.pages.expects(:not_found).returns([true])
88
113
  @controller.send(:locomotive_page).should be_true
89
114
  end
@@ -91,7 +116,7 @@ describe 'Locomotive rendering system' do
91
116
  it 'should not return the 404 page if the page has not been published yet and admin is logged in' do
92
117
  @controller.current_admin = true
93
118
  @controller.request.fullpath = '/contact'
94
- @controller.current_site.pages.expects(:where).with({ :fullpath => 'contact' }).returns([@page])
119
+ @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{contact content_type_template} }).returns([@page])
95
120
  @controller.send(:locomotive_page).should == @page
96
121
  end
97
122
 
@@ -333,4 +333,26 @@ describe Page do
333
333
  end
334
334
 
335
335
  end
336
+
337
+ describe 'templatized extension' do
338
+
339
+ before(:each) do
340
+ @page = Factory.build(:page, :site => nil, :templatized => true, :content_type_id => 42)
341
+ ContentType.stubs(:find).returns(Factory.build(:content_type, :site => nil))
342
+ end
343
+
344
+ it 'is considered as a templatized page' do
345
+ @page.templatized?.should be_true
346
+ end
347
+
348
+ it 'fills in the slug field' do
349
+ @page.valid?
350
+ @page.slug.should == 'content_type_template'
351
+ end
352
+
353
+ it 'does forget to set the content type id' do
354
+ @page.content_type_id.should == '42'
355
+ end
356
+
357
+ end
336
358
  end
metadata CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
6
6
  - 0
7
7
  - 0
8
8
  - 3
9
- - 1
10
- version: 0.0.3.1
9
+ - 3
10
+ version: 0.0.3.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Didier Lafforgue
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-07-15 00:00:00 +02:00
18
+ date: 2010-07-16 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -345,6 +345,7 @@ files:
345
345
  - app/models/extensions/asset/vignette.rb
346
346
  - app/models/extensions/page/parts.rb
347
347
  - app/models/extensions/page/render.rb
348
+ - app/models/extensions/page/templatized.rb
348
349
  - app/models/extensions/page/tree.rb
349
350
  - app/models/layout.rb
350
351
  - app/models/liquid_template.rb
@@ -812,6 +813,7 @@ files:
812
813
  - public/images/admin/plugins/toggle_handle_right-bg.png
813
814
  - public/images/admin/plugins/toggle_shadow-bg.png
814
815
  - public/images/admin/rails.png
816
+ - public/javascripts/admin/account.js
815
817
  - public/javascripts/admin/application.js
816
818
  - public/javascripts/admin/asset_collections.js
817
819
  - public/javascripts/admin/assets.js
@@ -859,6 +861,7 @@ files:
859
861
  - public/javascripts/admin/plugins/plupload/plupload.silverlight.xap
860
862
  - public/javascripts/admin/plugins/scrollTo.js
861
863
  - public/javascripts/admin/plugins/shortcut.js
864
+ - public/javascripts/admin/plugins/subscribe.js
862
865
  - public/javascripts/admin/plugins/tiny_mce/langs/en.js
863
866
  - public/javascripts/admin/plugins/tiny_mce/license.txt
864
867
  - public/javascripts/admin/plugins/tiny_mce/plugins/advhr/css/advhr.css