radiant-fabulator-extension 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING.markdown ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009-2010 Texas A&M University
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,21 @@
1
+ == Fabulator
2
+
3
+ Fabulator is an extension to the Radiant CMS for creating web applications
4
+ The applications are written in an XML language that describes the set
5
+ of application views and the data that triggers a move from one view
6
+ to the next, along with initial conditions for the application and data
7
+ transformations.
8
+
9
+ == Installation
10
+
11
+ Installation is done in the usual manner for Radiant extensions.
12
+
13
+ This extension requires Radiant 0.9 or higher as well as the following
14
+ gems:
15
+
16
+ * fabulator
17
+
18
+ You may also want to add some fabulator extensions.
19
+ See http://github.com/jgsmith/
20
+
21
+ [Radiant CMS]: http://www.radiantcms.org/
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,36 @@
1
+ class FabulatorContext < ActiveRecord::Base
2
+ #serialize :context
3
+ belongs_to :page
4
+ belongs_to :user
5
+
6
+ def self.find_by_page(p)
7
+ if p.request.session[:user_id].blank?
8
+ c = self.first(:conditions => [
9
+ 'page_id = ? AND session = ? AND (user_id IS NULL OR user_id=0)',
10
+ p.id, p.request.session[:session_id]
11
+ ] )
12
+ else
13
+ c = self.first(:conditions => [
14
+ 'page_id = ? AND session = ? AND user_id = ?',
15
+ p.id, p.request.session[:session_id], p.request.session[:user_id]
16
+ ] )
17
+ end
18
+ if c.nil? && !p.request.session[:user_id].blank?
19
+ c = self.first(:conditions => [
20
+ 'page_id = ? AND session = ?',
21
+ p.id, p.request.session[:session_id]
22
+ ] )
23
+ if !c.nil? && c.user.nil?
24
+ c.update_attribute(:user_id, p.request.session[:user_id])
25
+ end
26
+ end
27
+ p.fabulator_context = c.context unless c.nil?
28
+ return c unless c.nil?
29
+ self.new(
30
+ :context => YAML::dump(p.fabulator_context),
31
+ :page_id => p.id,
32
+ :user_id => p.request.session[:user_id],
33
+ :session => p.request.session[:session_id]
34
+ )
35
+ end
36
+ end
@@ -0,0 +1,459 @@
1
+ class FabulatorPage < Page
2
+ # precompile xslt so we don't do this for *every* request
3
+
4
+ @@fabulator_xslt_file = RAILS_ROOT + '/vendor/extensions/fabulator/xslt/form.xsl'
5
+ @@fabulator_xslt = REXML::Document.new File.open(@@fabulator_xslt_file)
6
+
7
+ attr_accessor :inner_content
8
+
9
+ description %{
10
+ A Fabulator page allows you to create a simple, interactive
11
+ web application that manages data in RDF models defined in the
12
+ Fabulator > RDF Models tab of the administrative area.
13
+ }
14
+ # need a reasonable name for the XML part
15
+ XML_PART_NAME = 'extended'
16
+
17
+ after_save :set_defaults
18
+ attr_accessor :resource_ln, :c_state_machine
19
+
20
+ # create tags to access filtered data in page display
21
+ # might also create tags for form fields, etc., so it's easy to
22
+ # create a form and fill in data
23
+
24
+ def cache?
25
+ false
26
+ end
27
+
28
+ def find_by_url(url, live = true, clean = false)
29
+ #Rails.logger.info("find_by_url(#{url}, #{live}, #{clean})")
30
+ #Rails.logger.info("invoking super")
31
+ p = super
32
+ #Rails.logger.info("returning from super")
33
+ #Rails.logger.info("Found #{p}")
34
+ return p if !p.nil? && !p.is_a?(FileNotFoundPage)
35
+ #Rails.logger.info("Seeing if we have a resource")
36
+
37
+ url = clean_url(url) if clean
38
+ #Rails.logger.info("Our url: #{self.url}")
39
+ #Rails.logger.info("Target url: #{url}")
40
+ if url =~ %r{^#{ self.url }([-_0-9a-zA-Z]+)/?$}
41
+ #Rails.logger.info("resource: #{$1}")
42
+ self.resource_ln = $1
43
+ return self
44
+ else
45
+ return p
46
+ end
47
+ end
48
+
49
+ def url
50
+ #Rails.logger.info("Getting url")
51
+ u = super
52
+ if !self.resource_ln.nil?
53
+ u = u + '/' + self.resource_ln
54
+ end
55
+ #Rails.logger.info("Returning '#{u}' as url")
56
+ u
57
+ end
58
+
59
+ def state_machine
60
+ if self.compiled_xml.nil? || self.compiled_xml == ''
61
+ self.c_state_machine = nil
62
+ else
63
+ self.c_state_machine = (YAML::load(self.compiled_xml) rescue nil) unless self.c_state_machine
64
+ end
65
+ self.c_state_machine
66
+ end
67
+
68
+ def fabulator_context
69
+ if @roots.nil?
70
+ @roots = { }
71
+ end
72
+
73
+ if @roots['data'].nil?
74
+ @roots['data'] = Fabulator::Expr::Node.new('data', @roots, nil, [])
75
+ ctx = Fabulator::Expr::Context.new
76
+ ctx.root = @roots['data']
77
+ ctx.traverse_path(['resource'], true).first.value = self.resource_ln if self.resource_ln
78
+ self.state_machine.init_context(ctx)
79
+ end
80
+ @roots['data']
81
+ end
82
+
83
+ def fabulator_context=(c)
84
+ fc = self.fabulator_context
85
+ @roots = { } if @roots.nil?
86
+ @roots['data'] = c
87
+ end
88
+
89
+ def headers
90
+ if @resetting_context
91
+ {
92
+ :location => self.url,
93
+ }
94
+ elsif @redirecting
95
+ {
96
+ :location => @redirecting,
97
+ }
98
+ else
99
+ { }
100
+ end
101
+ end
102
+
103
+ def response_code
104
+ @resetting_context ? 302 : ( @redirecting ? 304 : 200 )
105
+ end
106
+
107
+ def render_snippet(p)
108
+ if p.name != XML_PART_NAME
109
+ super
110
+ else
111
+ # check if page part was updated since page -- might need to recompile
112
+
113
+ sm = self.state_machine
114
+ return '' if sm.nil?
115
+
116
+ # run state machine if POST
117
+ context = FabulatorContext.find_by_page(self)
118
+ @resetting_context = false
119
+
120
+ if request.method == :get &&
121
+ params[:reset_context]
122
+ if !context.new_record?
123
+ context.destroy
124
+ end
125
+ # redirect without the reset_context param?
126
+ @response.redirect(url,302)
127
+ @resetting_context = true
128
+ return
129
+ end
130
+
131
+ begin
132
+ sm.context = YAML::load(context.context)
133
+ if sm.context.empty?
134
+ sm.init_context(self.fabulator_context)
135
+ end
136
+ #sm.context.merge!(self.resource_ln, ['resource'] ) if self.resource_ln
137
+ if request.method == :post
138
+ sm.run(params)
139
+ # save context
140
+ @sm_missing_args = sm.missing_params
141
+ @sm_errors = sm.errors
142
+ context.context = YAML::dump(sm.context)
143
+ context.save
144
+ end
145
+ # save statemachine state
146
+ # display resulting view
147
+ rescue Fabulator::FabulatorRequireAuth => e
148
+ @redirecting = e.to_s
149
+ rescue => e
150
+ return "<p>#{e.to_s}</p><pre>" + e.backtrace.join("\n") + "</pre>"
151
+ end
152
+ return '' if @redirecting
153
+ if sm.state != XML_PART_NAME
154
+ return self.render_part(sm.state)
155
+ else
156
+ return 'Error: Fabulator application is not in a displayable state.'
157
+ end
158
+ end
159
+ end
160
+
161
+ def missing_args
162
+ @sm_missing_args
163
+ end
164
+
165
+ tag 'fabulator' do |tag|
166
+ tag.locals.fabulator_context = tag.locals.page.fabulator_context
167
+ tag.expand
168
+ end
169
+
170
+ desc %{
171
+ Formats the enclosed logical form markup, adds default values,
172
+ existing values, and marks errors or warnings and required fields.
173
+ }
174
+ tag 'form' do |tag|
175
+ # get xml markup of form and transform it via xslt while adding
176
+ # default values and such
177
+ # wrap the whole thing in a form tag to post back to this page
178
+ xml = tag.expand
179
+ return '' if xml.blank?
180
+
181
+ text_parser = Fabulator::Template::Parser.new
182
+
183
+ c = get_fabulator_context(tag)
184
+ root = nil
185
+
186
+ missing_args = tag.locals.page.missing_args
187
+
188
+ form_base = tag.attr['base']
189
+ if form_base.nil? || form_base == ''
190
+ root = c
191
+ form_base = c.root.path.gsub(/^.*::/, '').gsub('/', '.').gsub(/^\.+/, '')
192
+ else
193
+ root = c.nil? ? nil : c.with_root(c.eval_expression('/' + form_base.gsub('.', '/')).first)
194
+ root = c if !c.nil? && root.root.nil?
195
+ end
196
+ root = c
197
+
198
+ xml = %{<view><form>} + xml + %{</form></view>}
199
+ doc = text_parser.parse(c, xml)
200
+
201
+ # add default values
202
+ doc.add_default_values(root)
203
+
204
+ doc.to_html
205
+ end
206
+
207
+ # borrowed heavily from http://cpansearch.perl.org/src/JSMITH/Gestinanna-0.02/lib/Gestinanna/ContentProvider/XSM.pm
208
+ def add_default_values(doc, ctx)
209
+ REXML::XPath.each(doc.root, %{
210
+ //text
211
+ | //textline
212
+ | //textbox
213
+ | //editbox
214
+ | //file
215
+ | //password
216
+ | //selection
217
+ | //grid
218
+ }) do |el|
219
+ own_id = el.attribute('id')
220
+ next if own_id.nil? || own_id.to_s == ''
221
+
222
+ default = 0
223
+ is_grid = false
224
+ if el.local_name == 'grid'
225
+ default = REXML::XPath.match(el, './default | ./row/default | ./column/default')
226
+ is_grid = true
227
+ else
228
+ default = REXML::XPath.match(el, './default')
229
+ end
230
+
231
+ #missing = el.attribute('missing')
232
+
233
+ ancestors = REXML::XPath.match(el, %{
234
+ ancestor::option[@id != '']
235
+ | ancestor::group[@id != '']
236
+ | ancestor::form[@id != '']
237
+ | ancestor::container[@id != '']
238
+ })
239
+ ids = ancestors.collect{|a| a.attribute('id')}.select{|a| !a.nil? }
240
+ ids << own_id
241
+ id = ids.collect{|i| i.to_s}.join('.')
242
+ ids = id.split('.')
243
+ if !ctx.nil? && (default.is_a?(Array) && default.empty? || !default)
244
+ # create a new node 'default'
245
+ l = ctx.traverse_path(ids)
246
+ if !l.nil? && !l.empty?
247
+ if is_grid
248
+ count = (el.attribute('count').to_s rescue '')
249
+ how_many = 'multiple'
250
+ direction = 'both'
251
+ if count =~ %r{^(multiple|single)(-by-(row|column))?$}
252
+ how_many = $1
253
+ direction = $3 || 'both'
254
+ end
255
+ if direction == 'both'
256
+ l.collect{|ll| ll.value }.each do |v|
257
+ default = el.add_element('default')
258
+ default.add_text(v)
259
+ end
260
+ elsif direction == 'row' || direction == 'column'
261
+ REXML::XPath.each(el, "./#{direction}").each do |div|
262
+ id = (div.attribute('id').to_s rescue '')
263
+ next if id == ''
264
+ l.collect{|c| c.traverse_path(id)}.flatten.collect{|c| c.value }. each do |v|
265
+ default = div.add_element('default')
266
+ default.add_text(v)
267
+ end
268
+ end
269
+ end
270
+ else
271
+ l.collect{|ll| ll.value }.each do |v|
272
+ default = el.add_element('default')
273
+ default.add_text(v)
274
+ end
275
+ end
276
+ end
277
+ end
278
+ # now handle missing info for el
279
+
280
+ if !missing_args.nil? && missing_args.include?(id)
281
+ el.add_attribute('missing', '1')
282
+ end
283
+ end
284
+
285
+ end
286
+
287
+ desc %{
288
+ Defines XML namespace prefix to URI mappings.
289
+ }
290
+ tag 'xmlns' do |tag|
291
+ tag.expand
292
+ end
293
+
294
+ desc %{
295
+ Iterates through a set of data nodes.
296
+
297
+ *Usage:*
298
+
299
+ <pre><code><r:for-each select="./foo">...</r:for-each></code></pre>
300
+ }
301
+ tag 'for-each' do |tag|
302
+ selection = tag.attr['select']
303
+ c = get_fabulator_context(tag)
304
+ #Rails.logger.info("context: #{YAML::dump(c)}")
305
+ #Rails.logger.info("for-each: #{selection} from #{c}")
306
+ ns = get_fabulator_ns(tag)
307
+ items = c.nil? ? [] : c.eval_expression(selection)
308
+ sort_by = tag.attr['sort']
309
+ sort_dir = tag.attr['order'] || 'asc'
310
+
311
+ if !sort_by.nil? && sort_by != ''
312
+ parser = Fabulator::Expr::Parser.new
313
+ sort_by_f = parser.parse(sort_by, c)
314
+ items = items.sort_by { |i| c.with_root(i).eval_expression(sort_by_f).first.value }
315
+ if sort_dir == 'desc'
316
+ items.reverse!
317
+ end
318
+ end
319
+ res = ''
320
+ #Rails.logger.info("Found #{items.size} items for for-each")
321
+ items.each do |i|
322
+ next if i.empty?
323
+ tag.locals.fabulator_context = c.with_root(i)
324
+ res = res + tag.expand
325
+ end
326
+ res
327
+ end
328
+
329
+ desc %{
330
+ Selects the value and returns it in HTML.
331
+ TODO: allow escaping of HTML special characters
332
+
333
+ *Usage:*
334
+
335
+ <pre><code><r:value select="./foo" /></code></pre>
336
+ }
337
+ tag 'value' do |tag|
338
+ selection = tag.attr['select']
339
+ c = get_fabulator_context(tag)
340
+ items = c.nil? ? [] : c.eval_expression(selection)
341
+ items.collect{|i| i.to([Fabulator::FAB_NS, 'html']).value }.join('')
342
+ end
343
+
344
+ desc %{
345
+ Chooses the first test which returns content. Otherwise,
346
+ uses the 'otherwise' tag.
347
+ }
348
+ tag 'choose' do |tag|
349
+ @chosen ||= [ ]
350
+ @chosen.unshift false
351
+ ret = tag.expand
352
+ @chosen.shift
353
+ ret
354
+ end
355
+
356
+ desc %{
357
+ Renders the enclosed content if the test passes.
358
+ }
359
+ tag 'choose:when' do |tag|
360
+ return '' if @chosen.first
361
+ selection = tag.attr['test']
362
+ c = get_fabulator_context(tag)
363
+ items = c.nil? ? [] : c.eval_expression(selection)
364
+ if items.is_a?(Array)
365
+ if items.empty?
366
+ return ''
367
+ else
368
+ @chosen[0] = true
369
+ return tag.expand
370
+ end
371
+ elsif items
372
+ @chosen[0] = true
373
+ return tag.expand
374
+ end
375
+ return ''
376
+ end
377
+
378
+ desc %{
379
+ Renders the enclosed content.
380
+ }
381
+ tag 'choose:otherwise' do |tag|
382
+ return '' if @chosen.first
383
+ tag.expand
384
+ end
385
+
386
+ desc %{
387
+ Renders the inherited view.
388
+ }
389
+ tag 'inner' do |tag|
390
+ @inner_content.nil? ? '' : @inner_content
391
+ end
392
+
393
+ desc %{
394
+ Renders the parent view providing the child view as an augmentation.
395
+ }
396
+ tag 'augment' do |tag|
397
+ parent_page = self.state_machine.isa
398
+ inner = tag.expand
399
+ return inner if parent_page.nil?
400
+ parent_page.inner_content = inner
401
+ parent_page.render_part(self.state_machine.state)
402
+ end
403
+
404
+ private
405
+
406
+ def get_fabulator_ns(tag)
407
+ c = tag.locals.page
408
+ if c.nil?
409
+ c = tag.globals.page
410
+ end
411
+ #Rails.logger.info("page: #{c}")
412
+ #Rails.logger.info("state machine: #{c.state_machine}")
413
+ #Rails.logger.info("namespaces: #{c.state_machine.namespaces}")
414
+ ret = (c.state_machine.namespaces rescue { })
415
+ #Rails.logger.info("get_fabulator_ns: [#{ret}]")
416
+ ret
417
+ end
418
+
419
+ def get_fabulator_context(tag)
420
+ c = tag.locals.fabulator_context
421
+ if c.nil?
422
+ c = tag.locals.page.state_machine.fabulator_context
423
+ if c.nil?
424
+ c = tag.globals.page.state_machine.fabulator_context
425
+ end
426
+ end
427
+ # TODO: move serialization back into the model
428
+ if c.is_a?(String)
429
+ c = YAML::load(c)
430
+ end
431
+ if c.is_a?(Hash)
432
+ c = c[:data]
433
+ end
434
+ return c
435
+ end
436
+
437
+
438
+ def set_defaults
439
+ # create a part for each state in the document
440
+ # 'body' is a description/special
441
+ # 'sidebar' is reserved
442
+
443
+ # compile statemachine into a set of Ruby objects and save
444
+ # not the most efficient, but we don't usually have hundreds of states
445
+ self[:compiled_xml] = nil
446
+ @compiled_xml = nil
447
+ sm = self.state_machine
448
+ Rails.logger.info("SM: #{YAML::dump(sm)}")
449
+ return if sm.nil?
450
+ #Rails.logger.info("Ensuring the right parts are present")
451
+
452
+ sm.state_names.sort.each do |part_name|
453
+ parts.create(:name => part_name, :content => %{
454
+ <h1>View for State #{part_name}</h1>
455
+ }) unless parts.any?{ |p| p.name == part_name }
456
+ end
457
+ end
458
+
459
+ end
@@ -0,0 +1,9 @@
1
+ class AddFabulatorFields < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :pages, :compiled_xml, :text
4
+ end
5
+
6
+ def self.down
7
+ remove_column :pages, :compiled_xml
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ class CreateFabulatorContextsTable < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :fabulator_contexts do |t|
4
+ t.string :session, :null => false
5
+ t.references :page, :null => false
6
+ t.references :user
7
+ t.text :context
8
+ t.integer :lock_version, :default => 0
9
+ end
10
+
11
+ add_index :fabulator_contexts, [ :session, :page_id, :user_id ], :unique => true
12
+ end
13
+
14
+ def self.down
15
+ drop_table :fabulator_contexts
16
+ end
17
+ end
@@ -0,0 +1,61 @@
1
+ $: << File.expand_path(File.dirname(__FILE__))+'/lib'
2
+
3
+ require 'fabulator/radiant'
4
+
5
+ require_dependency "#{File.expand_path(File.dirname(__FILE__))}/app/models/fabulator_page"
6
+
7
+ class FabulatorExtension < Radiant::Extension
8
+ version "1.0"
9
+ description "Applications as documents"
10
+ url "http://github.com/jgsmith/radiant-fabulator"
11
+
12
+ XML_PART_NAME = 'extended'
13
+
14
+ extension_config do |config|
15
+ config.gem 'fabulator'
16
+ config.after_initialize do
17
+ #run_something
18
+ end
19
+ end
20
+
21
+
22
+ def activate
23
+ FabulatorPage
24
+
25
+ tab 'Fabulator' do
26
+ end
27
+
28
+ PagePart.class_eval do
29
+ before_save :compile_xml
30
+
31
+ def compile_xml
32
+ if self.page.class_name == 'FabulatorPage' &&
33
+ self.name == FabulatorExtension::XML_PART_NAME
34
+ old_compiled_xml = self.page.compiled_xml
35
+ if self.content.nil? || self.content == ''
36
+ self.page.compiled_xml = nil
37
+ else
38
+ # compile
39
+ #isa = Fabulator::ActionLib.get_local_attr(doc.root, Fabulator::FAB_NS, 'is-a')
40
+ isa = nil
41
+ sm = nil
42
+ if isa.nil?
43
+ sm = Fabulator::Core::StateMachine.new.compile_xml(self.content)
44
+ else
45
+ supersm_page = self.page.find_by_url(isa)
46
+ if supersm_page.nil? || supersm_page.is_a?(FileNotFoundPage) || !supersm_page.is_a?(FabulatorPage) || supersm_page.state_machine.nil?
47
+ raise "File Not Found: unable to find #{isa}"
48
+ end
49
+ sm = supersm_page.state_machine.clone
50
+ sm.compile_xml(self.content)
51
+ end
52
+ self.page.compiled_xml = YAML::dump(sm)
53
+ end
54
+ if old_compiled_xml != self.page.compiled_xml
55
+ self.page.save
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1 @@
1
+ require 'fabulator/radiant/actions'
@@ -0,0 +1,89 @@
1
+ require 'fabulator/action_lib'
2
+ require 'fabulator/radiant/actions/require_auth'
3
+
4
+ module Fabulator
5
+ RADIANT_NS="http://dh.tamu.edu/ns/fabulator/radiant/1.0#"
6
+ class FabulatorRequireAuth < StandardError
7
+ def initialize(message = "") super; end
8
+ end
9
+
10
+ module Radiant
11
+ module Actions
12
+ class Lib
13
+ include Fabulator::ActionLib
14
+
15
+ register_namespace RADIANT_NS
16
+
17
+ #action 'require-auth', Fabulator::Radiant::Actions::RequireAuth
18
+
19
+ #register_type 'user', {
20
+ #}
21
+
22
+ register_type 'page', {
23
+ :ops => {
24
+ :children => Proc.new { |p| p.value.children.collect { |c| Lib.page_to_node(c, p) } },
25
+ },
26
+ }
27
+
28
+ # page parts are attributes of a page
29
+ # as are @name, @breadcrumb, @description, @keywords
30
+ # @layout, @page-type, @status
31
+ # slug is the node name
32
+ # page parts have attributes @filter
33
+ register_type 'page-part', {
34
+ :to => [
35
+ { :type => [ FAB_NS, 'string' ],
36
+ :weight => 1.0,
37
+ :convert => Proc.new { |p| p.anon_node(p.value, [ FAB_NS, 'string' ]) }
38
+ }
39
+ ],
40
+ }
41
+
42
+ # 'radiant' axis
43
+ axis 'radiant' do |ctx|
44
+ # returns the root 'Home' page for the site
45
+ # children are addressable by their slug
46
+ Lib.page_to_node(Page.find_by_parent_id(nil), ctx)
47
+ end
48
+
49
+ function 'find', [ RADIANT_NS, 'page' ] do |ctx, args|
50
+ args[0].collect { |a|
51
+ Lib.page_to_node(Page.find_by_parent_id(nil).find_by_url(a.to_s), ctx)
52
+ }
53
+ end
54
+
55
+ function 'current-user' do |ctx, args|
56
+ u = UserActionObserver.current_user
57
+ if !u.nil?
58
+ n = ctx.root.anon_node(u.id) #, [ RADIANT_NS, 'user' ])
59
+ n.set_attribute('admin', u.admin?)
60
+ Rails.logger.info("Returning: #{YAML::dump(n)}")
61
+ return [ n ]
62
+ else
63
+ return [ ]
64
+ end
65
+ end
66
+
67
+ def self.page_to_node(p, ctx)
68
+ return nil if p.nil?
69
+ p_node = ctx.root.anon_node(p, [ RADIANT_NS, 'page' ])
70
+ p_node.name = p.slug
71
+ p.parts.each do |pp|
72
+ pp_node = ctx.root.anon_node(pp.content, [ RADIANT_NS, 'page-part' ])
73
+ pp_node.name = pp.name
74
+ #pp_node.set_attribute('filter', pp.filter)
75
+ p_node.set_attribute(pp.name, pp_node)
76
+ end
77
+ p_node.set_attribute('title', p.title)
78
+ p_node.set_attribute('breadcrumb', p.breadcrumb)
79
+ p_node.set_attribute('description', p.description)
80
+ p_node.set_attribute('keywords', p.keywords)
81
+ #p_node.set_attribute('layout', p.layout)
82
+ #p_node.set_attribute('page-type', p.page_type)
83
+ #p_node.set_attribute('status', p.status)
84
+ p_node
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: radiant-fabulator-extension
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - James Smith
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-10 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: fabulator
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 27
30
+ segments:
31
+ - 0
32
+ - 0
33
+ - 2
34
+ version: 0.0.2
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: Creates a Fabulator page type allowing applications to be built using the fabulator engine.
38
+ email: jgsmith@tamu.edu
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - README.rdoc
45
+ files:
46
+ - COPYING.markdown
47
+ - README.rdoc
48
+ - VERSION
49
+ - app/models/fabulator_context.rb
50
+ - app/models/fabulator_page.rb
51
+ - db/migrate/001_add_fabulator_fields.rb
52
+ - db/migrate/002_create_fabulator_contexts_table.rb
53
+ - fabulator_extension.rb
54
+ - lib/fabulator/radiant.rb
55
+ - lib/fabulator/radiant/actions.rb
56
+ has_rdoc: true
57
+ homepage: http://github.com/jgsmith/radiant-fabulator
58
+ licenses: []
59
+
60
+ post_install_message:
61
+ rdoc_options:
62
+ - --charset=UTF-8
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ requirements: []
84
+
85
+ rubyforge_project:
86
+ rubygems_version: 1.3.7
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: Fabulator Extension for Radiant CMS
90
+ test_files: []
91
+