trusty-snippets-extension 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.
Files changed (41) hide show
  1. data/README.md +7 -0
  2. data/Rakefile +109 -0
  3. data/app/controllers/admin/snippets_controller.rb +8 -0
  4. data/app/helpers/admin/snippets_helper.rb +3 -0
  5. data/app/models/snippet.rb +23 -0
  6. data/app/models/snippet_finder.rb +24 -0
  7. data/app/models/snippet_tags.rb +80 -0
  8. data/app/views/admin/snippets/_form.html.haml +29 -0
  9. data/app/views/admin/snippets/_popups.html.haml +4 -0
  10. data/app/views/admin/snippets/edit.html.haml +11 -0
  11. data/app/views/admin/snippets/index.html.haml +33 -0
  12. data/app/views/admin/snippets/new.html.haml +9 -0
  13. data/app/views/admin/snippets/remove.html.haml +17 -0
  14. data/config/initializers/radiant_config.rb +3 -0
  15. data/config/locales/en.yml +16 -0
  16. data/config/routes.rb +8 -0
  17. data/cucumber.yml +1 -0
  18. data/features/admin/configuration.feature +9 -0
  19. data/features/admin/pagination.feature +27 -0
  20. data/features/admin/snippets_management.feature +82 -0
  21. data/features/step_definitions/admin/snippet_steps.rb +25 -0
  22. data/features/support/env.rb +11 -0
  23. data/features/support/paths.rb +22 -0
  24. data/lib/snippets/engine.rb +5 -0
  25. data/lib/tasks/snippets_extension_tasks.rake +47 -0
  26. data/lib/trusty-snippets-extension.rb +8 -0
  27. data/snippets_extension.rb +69 -0
  28. data/spec/ci/before_script +22 -0
  29. data/spec/ci/script +2 -0
  30. data/spec/controllers/admin/snippets_controller_spec.rb +110 -0
  31. data/spec/datasets/snippets_dataset.rb +44 -0
  32. data/spec/fixtures/snippet_template.radius +1 -0
  33. data/spec/lib/radiant/admin_ui_spec.rb +33 -0
  34. data/spec/models/page_spec.rb +81 -0
  35. data/spec/models/snippet_finder_spec.rb +20 -0
  36. data/spec/models/snippet_spec.rb +59 -0
  37. data/spec/models/user_action_observer_spec.rb +25 -0
  38. data/spec/snippets_spec_helper.rb +36 -0
  39. data/spec/spec.opts +6 -0
  40. data/trusty-snippets-extension.gemspec +26 -0
  41. metadata +120 -0
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # Snippets
2
+
3
+ Use Snippets as reusable bits of content.
4
+
5
+ This extension was pulled from the original core.
6
+
7
+ Created by Radiant CMS Development Team.
data/Rakefile ADDED
@@ -0,0 +1,109 @@
1
+ # Determine where the RSpec plugin is by loading the boot
2
+ unless defined? RADIANT_ROOT
3
+ ENV["RAILS_ENV"] = "test"
4
+ case
5
+ when ENV["RADIANT_ENV_FILE"]
6
+ require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
7
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
8
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
9
+ else
10
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
11
+ end
12
+ end
13
+
14
+ require 'rake'
15
+ require 'rdoc/task'
16
+ require 'rake/testtask'
17
+
18
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
19
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
20
+ require 'spec/rake/spectask'
21
+ require 'cucumber'
22
+ require 'cucumber/rake/task'
23
+
24
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
25
+ Object.send(:remove_const, :RADIANT_ROOT)
26
+
27
+ extension_root = File.expand_path(File.dirname(__FILE__))
28
+
29
+ task :default => [:spec, :features]
30
+ task :stats => "spec:statsetup"
31
+
32
+ desc "Run all specs in spec directory"
33
+ Spec::Rake::SpecTask.new(:spec) do |t|
34
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
35
+ t.spec_files = FileList['spec/**/*_spec.rb']
36
+ end
37
+
38
+ task :features => 'spec:integration'
39
+
40
+ namespace :spec do
41
+ desc "Run all specs in spec directory with RCov"
42
+ Spec::Rake::SpecTask.new(:rcov) do |t|
43
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
44
+ t.spec_files = FileList['spec/**/*_spec.rb']
45
+ t.rcov = true
46
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
47
+ end
48
+
49
+ desc "Print Specdoc for all specs"
50
+ Spec::Rake::SpecTask.new(:doc) do |t|
51
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
52
+ t.spec_files = FileList['spec/**/*_spec.rb']
53
+ end
54
+
55
+ [:models, :controllers, :views, :helpers].each do |sub|
56
+ desc "Run the specs under spec/#{sub}"
57
+ Spec::Rake::SpecTask.new(sub) do |t|
58
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
59
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
60
+ end
61
+ end
62
+
63
+ desc "Run the Cucumber features"
64
+ Cucumber::Rake::Task.new(:integration) do |t|
65
+ t.fork = true
66
+ t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'pretty')]
67
+ # t.feature_pattern = "#{extension_root}/features/**/*.feature"
68
+ t.profile = "default"
69
+ end
70
+
71
+ # Setup specs for stats
72
+ task :statsetup do
73
+ require 'code_statistics'
74
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
75
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
76
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
77
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
78
+ ::CodeStatistics::TEST_TYPES << "Model specs"
79
+ ::CodeStatistics::TEST_TYPES << "View specs"
80
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
81
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
82
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
83
+ end
84
+
85
+ namespace :db do
86
+ namespace :fixtures do
87
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
88
+ task :load => :environment do
89
+ require 'active_record/fixtures'
90
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
91
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
92
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ desc 'Generate documentation for the snippets extension.'
100
+ RDoc::Task.new(:rdoc) do |rdoc|
101
+ rdoc.rdoc_dir = 'rdoc'
102
+ rdoc.title = 'SnippetsExtension'
103
+ rdoc.options << '--line-numbers' << '--inline-source'
104
+ rdoc.rdoc_files.include('README')
105
+ rdoc.rdoc_files.include('lib/**/*.rb')
106
+ end
107
+
108
+ # Load any custom rakefiles for extension
109
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
@@ -0,0 +1,8 @@
1
+ class Admin::SnippetsController < Admin::ResourceController
2
+ paginate_models
3
+ only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy,
4
+ :when => [:designer, :admin],
5
+ :denied_url => { :controller => 'admin/pages', :action => 'index' },
6
+ :denied_message => 'You must have designer privileges to perform this action.'
7
+
8
+ end
@@ -0,0 +1,3 @@
1
+ module Admin::SnippetsHelper
2
+
3
+ end
@@ -0,0 +1,23 @@
1
+ class Snippet < ActiveRecord::Base
2
+
3
+ # Default Order
4
+ default_scope :order => 'name'
5
+
6
+ # Associations
7
+ belongs_to :created_by, :class_name => 'User'
8
+ belongs_to :updated_by, :class_name => 'User'
9
+
10
+ # Validations
11
+ validates_presence_of :name
12
+ validates_length_of :name, :maximum => 100
13
+ validates_length_of :filter_id, :maximum => 25, :allow_nil => true
14
+ validates_format_of :name, :with => %r{^\S*$}
15
+ validates_uniqueness_of :name
16
+
17
+ object_id_attr :filter, TextFilter
18
+
19
+ def after_initialize
20
+ self.filter_id ||= TrustyCms::Config['defaults.snippet.filter'] if new_record?
21
+ end
22
+
23
+ end
@@ -0,0 +1,24 @@
1
+ class SnippetFinder
2
+ class << self
3
+ def find(id)
4
+ find_map('find',id)
5
+ end
6
+
7
+ def find_by_name(name)
8
+ find_map('find_by_name', name)
9
+ end
10
+
11
+ def finder_types
12
+ [SnippetFile, Snippet]
13
+ end
14
+
15
+ private
16
+
17
+ def find_map(meth, *args)
18
+ finder_types.find{|type|
19
+ found = type.send(meth, *args)
20
+ return found if found
21
+ }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,80 @@
1
+ module SnippetTags
2
+ include TrustyCms::Taggable
3
+
4
+ class TagError < StandardError; end
5
+
6
+ desc %{
7
+ Renders the snippet specified in the @name@ attribute within the context of a page.
8
+
9
+ *Usage:*
10
+
11
+ <pre><code><r:snippet name="snippet_name" /></code></pre>
12
+
13
+ When used as a double tag, the part in between both tags may be used within the
14
+ snippet itself, being substituted in place of @<r:yield/>@.
15
+
16
+ *Usage:*
17
+
18
+ <pre><code><r:snippet name="snippet_name">Lorem ipsum dolor...</r:snippet></code></pre>
19
+ }
20
+ tag 'snippet' do |tag|
21
+ required_attr(tag, 'name')
22
+ name = tag['name']
23
+
24
+ snippet = snippet_cache(name.strip)
25
+
26
+ if snippet
27
+ tag.locals.yield = tag.expand if tag.double?
28
+ tag.globals.page.render_snippet(snippet)
29
+ else
30
+ raise TagError.new("snippet '#{name}' not found")
31
+ end
32
+ end
33
+
34
+ def snippet_cache(name)
35
+ @snippet_cache ||= {}
36
+
37
+ snippet = @snippet_cache[name]
38
+ unless snippet
39
+ snippet = SnippetFinder.find_by_name(name)
40
+ @snippet_cache[name] = snippet
41
+ end
42
+ snippet
43
+ end
44
+ private :snippet_cache
45
+
46
+ desc %{
47
+ Used within a snippet as a placeholder for substitution of child content, when
48
+ the snippet is called as a double tag.
49
+
50
+ *Usage (within a snippet):*
51
+
52
+ <pre><code>
53
+ <div id="outer">
54
+ <p>before</p>
55
+ <r:yield/>
56
+ <p>after</p>
57
+ </div>
58
+ </code></pre>
59
+
60
+ If the above snippet was named "yielding", you could call it from any Page,
61
+ Layout or Snippet as follows:
62
+
63
+ <pre><code><r:snippet name="yielding">Content within</r:snippet></code></pre>
64
+
65
+ Which would output the following:
66
+
67
+ <pre><code>
68
+ <div id="outer">
69
+ <p>before</p>
70
+ Content within
71
+ <p>after</p>
72
+ </div>
73
+ </code></pre>
74
+
75
+ When called in the context of a Page or a Layout, @<r:yield/>@ outputs nothing.
76
+ }
77
+ tag 'yield' do |tag|
78
+ tag.locals.yield
79
+ end
80
+ end
@@ -0,0 +1,29 @@
1
+ = form_for [:admin, @snippet], :html => {'data-onsubmit_status' => onsubmit_status(@snippet)} do |f|
2
+ = f.hidden_field :lock_version
3
+ = render_region :form_top, :locals => {:f => f}
4
+ .form_area
5
+ - render_region :form, :locals => {:f => f} do |form|
6
+ - form.edit_title do
7
+ %p.title
8
+ = f.label :name, t('name')
9
+ = f.text_field :name, :class => 'textbox activate', :maxlength => 100
10
+ - form.edit_content do
11
+ %p.content
12
+ = f.label :content, t('body')
13
+ ~ f.text_area :content, :class => "textarea large", :style => "width: 100%"
14
+ - form.edit_filter do
15
+ .set
16
+ %p
17
+ %span.reference_links
18
+ == #{t('reference')}:
19
+ %span{:id => "tag_reference_link"}
20
+ = link_to t('available_tags'), admin_reference_url(:tags), id: 'tag_reference'
21
+ - render_region :form_bottom, :locals => {:f => f} do |form_bottom|
22
+ - form_bottom.edit_buttons do
23
+ .buttons{:style=>"clear: left"}
24
+ = save_model_button(@snippet)
25
+ = save_model_and_continue_editing_button(@snippet)
26
+ = t('or')
27
+ = link_to t('cancel'), admin_snippets_url
28
+ - form_bottom.edit_timestamp do
29
+ = updated_stamp @snippet
@@ -0,0 +1,4 @@
1
+ - content_for :popups do
2
+ #popup_window
3
+ .outer
4
+ .content
@@ -0,0 +1,11 @@
1
+ - @page_title = @snippet.name + ' ' + t('snippet') + ' - ' + default_page_title
2
+
3
+ - render_region :main do |main|
4
+ - main.edit_header do
5
+ %h1= t('edit_snippet')
6
+ - main.edit_form do
7
+ = render :partial => 'form'
8
+ - main.edit_popups do
9
+ = render :partial => "popups"
10
+
11
+ - content_for 'page_scripts'
@@ -0,0 +1,33 @@
1
+ - @page_title = t('snippets') + ' - ' + default_page_title
2
+
3
+ .outset
4
+ = render_region :top
5
+ %table.index#snippets
6
+ %thead
7
+ %tr
8
+ - render_region :thead do |thead|
9
+ - thead.title_header do
10
+ %th.name= t('snippet')
11
+ - thead.actions_header do
12
+ %th.actions{:style=>"width:9em"}= t('modify')
13
+ %tbody
14
+ - if @snippets.any?
15
+ - @snippets.each do |snippet|
16
+ %tr[snippet]
17
+ - render_region :tbody, :locals => {:snippet => snippet} do |tbody|
18
+ - tbody.title_cell do
19
+ %td.name
20
+ = link_to image('snippet', :alt => '') + ' ' + snippet.name, edit_admin_snippet_url(snippet)
21
+ - tbody.actions_cell do
22
+ %td.actions
23
+ = link_to image('minus') + ' ' + t('remove'), remove_admin_snippet_url(snippet), :class => "action"
24
+ - else
25
+ %tr
26
+ %td.empty{:colspan => admin.snippet.index.tbody.length}= t('no_snippets')
27
+
28
+ - render_region :bottom do |bottom|
29
+ - bottom.new_button do
30
+ #actions
31
+ = pagination_for(@snippets)
32
+ %ul
33
+ %li= link_to image('plus') + " " + t('new_snippet'), new_admin_snippet_url, :class => 'action_button'
@@ -0,0 +1,9 @@
1
+ - render_region :main do |main|
2
+ - main.edit_header do
3
+ %h1= t('new_snippet')
4
+ - main.edit_form do
5
+ = render :partial => 'form'
6
+ - main.edit_popups do
7
+ = render :partial => "popups"
8
+
9
+ - content_for 'page_scripts'
@@ -0,0 +1,17 @@
1
+ %h1= t('remove_snippet')
2
+
3
+ %p
4
+ = t('text.snippets.remove_warning')
5
+
6
+ %table.index#snippets
7
+ %tbody
8
+ %tr.node.level_1
9
+ %td.snippet
10
+ = image('snippet', :alt => "")
11
+ %span.title= @snippet.name
12
+
13
+ = form_for [:admin, @snippet], :html => {:method => :delete, 'data-onsubmit_status'=>"Removing snippet&#8230;"} do
14
+ .buttons
15
+ %input.button{:type=>"submit", :value => t('delete_snippet')}/
16
+ = t('or')
17
+ = link_to t('cancel'), admin_snippets_url
@@ -0,0 +1,3 @@
1
+ if TrustyCms.config_definitions['defaults.snippet.filter'].nil?
2
+ TrustyCms.config.define 'defaults.snippet.filter', :select_from => lambda { TextFilter.descendants.map { |s| s.filter_name }.sort }, :allow_blank => true
3
+ end
@@ -0,0 +1,16 @@
1
+ ---
2
+ en:
3
+ snippet: 'Snippet'
4
+ snippets: 'Snippets'
5
+ config:
6
+ defaults:
7
+ snippet:
8
+ filter: "snippet filter"
9
+ delete_snippet: 'Delete Snippet'
10
+ edit_snippet: 'Edit Snippet'
11
+ new_snippet: 'New Snippet'
12
+ no_snippets: 'No Snippets'
13
+ remove_snippet: 'Remove Snippet'
14
+ text:
15
+ snippets:
16
+ remove_warning: 'Are you sure you want to <strong class="warning">permanently remove</strong> the following snippet?'
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+ TrustyCms::Application.routes.draw do
2
+ namespace :admin do
3
+
4
+ resources :snippets do
5
+ get :remove, on: :member
6
+ end
7
+ end
8
+ end
data/cucumber.yml ADDED
@@ -0,0 +1 @@
1
+ default: --format progress features --tags ~@proposed,~@in_progress
@@ -0,0 +1,9 @@
1
+ Feature: Rich configuration
2
+ In order to control site delivery
3
+ an administrator
4
+ wants to change the configuration of the site
5
+
6
+ Scenario: Reviewing configuration
7
+ Given I am logged in as "admin"
8
+ And I go to the "configuration" admin page
9
+ Then I should see "Snippet Filter"
@@ -0,0 +1,27 @@
1
+ Feature: Paginating admin views
2
+ In order to reduce load time and page bulk
3
+ a content editor
4
+ wants longer resource lists to be paginated
5
+
6
+ Background:
7
+ Given There are many snippets
8
+ And I am logged in as "designer"
9
+ And I go to the "snippets" admin page
10
+
11
+ Scenario: More snippets than we want to show on one page
12
+ Then I should see "first"
13
+ And I should not see "snippet_50"
14
+ And I should see page 1 of the results
15
+ And I should see pagination controls
16
+ And I should see a depagination link
17
+
18
+ When I follow "2" within "div.pagination"
19
+ Then I should see page 2 of the results
20
+ And I should see "snippet_50"
21
+
22
+ When I follow "show all"
23
+ # Then I should mention the request parameters
24
+ Then I should see all the snippets
25
+ And I should not see pagination controls
26
+ And I should not see a depagination link
27
+