radiant-taginator-extension 2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZmNiN2ZmYzBiMjMxYTAzNDUyYTU2MzMzMjFlOWU3ODRkMDA5YzQ1NA==
5
+ data.tar.gz: !binary |-
6
+ YzkxYTk0Mzk1M2JlOWYyMTcyZTVkZDg4OTQ2YzE3NzIzYTAyODk2Nw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NTQ3OTI0NmJiZWVlMmM3ZDZlODY0NTIxNWI2YzM0OTI4NjkwZWNhZmNhMmZl
10
+ ZjlkZjhmMTNiNDRkNjhjOTVkNWQ5ODM0ZWZkN2E4NDY2MjhlOTVkZDNkOGU1
11
+ NTdlZmI2M2FlNDYwZmQyOGY2OGVhYzVmYTA0NmFmMjc1NzI0ZTU=
12
+ data.tar.gz: !binary |-
13
+ NjM1YjkzZDkyNWI2ZWQ4ODFmNGRiMjFmZmE0NmMzYzQ3MmE2ZTkyODA1YWQy
14
+ MmM1NjkzYTBjODRmNzRiOWYyOTI4NGUzNTQ4NmY1OGY3YmEzM2NlZjljZWYz
15
+ NTVjODIyZDIwYTA4NWMzNWNhYTc2Y2I1Y2E2NDE1ZGQ5Mzg2ZTk=
@@ -0,0 +1 @@
1
+ radiant-*-extension-*.gem
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/plugins/acts-as-taggable-on"]
2
+ path = vendor/plugins/acts-as-taggable-on
3
+ url = https://github.com/mikz/acts-as-taggable-on.git
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake', '~> 0.9'
@@ -0,0 +1,79 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ radiant-taginator-extension (2.0.beta1)
5
+ acts-as-taggable-on
6
+ radiant
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ RedCloth (4.2.9)
12
+ actionmailer (2.3.18)
13
+ actionpack (= 2.3.18)
14
+ actionpack (2.3.18)
15
+ activesupport (= 2.3.18)
16
+ rack (~> 1.1.0)
17
+ activerecord (2.3.18)
18
+ activesupport (= 2.3.18)
19
+ activeresource (2.3.18)
20
+ activesupport (= 2.3.18)
21
+ activesupport (2.3.18)
22
+ acts-as-taggable-on (2.1.1)
23
+ rails
24
+ acts_as_tree (0.1.1)
25
+ chunky_png (1.2.8)
26
+ compass (0.12.2)
27
+ chunky_png (~> 1.2)
28
+ fssm (>= 0.2.7)
29
+ sass (~> 3.1)
30
+ compass-rails (1.0.3)
31
+ compass (>= 0.12.2, < 0.14)
32
+ delocalize (0.2.6)
33
+ fssm (0.2.10)
34
+ haml (3.1.8)
35
+ highline (1.6.19)
36
+ json (1.8.0)
37
+ rack (1.1.6)
38
+ rack-cache (1.2)
39
+ rack (>= 0.4)
40
+ radiant (1.1.4)
41
+ RedCloth (~> 4.2.0)
42
+ acts_as_tree (~> 0.1.1)
43
+ bundler (>= 1.0.0)
44
+ compass (~> 0.12.2)
45
+ compass-rails (~> 1.0.3)
46
+ delocalize (~> 0.2.3)
47
+ haml (~> 3.1.1)
48
+ highline (~> 1.6.10)
49
+ rack (~> 1.1.6)
50
+ rack-cache (~> 1.2)
51
+ radius (~> 0.7.3)
52
+ rails (~> 2.3.18)
53
+ rake (>= 0.8.7)
54
+ rdoc (>= 3.9.2)
55
+ stringex (~> 1.3.0)
56
+ tzinfo (~> 0.3.31)
57
+ will_paginate (~> 2.3.11)
58
+ radius (0.7.4)
59
+ rails (2.3.18)
60
+ actionmailer (= 2.3.18)
61
+ actionpack (= 2.3.18)
62
+ activerecord (= 2.3.18)
63
+ activeresource (= 2.3.18)
64
+ activesupport (= 2.3.18)
65
+ rake (>= 0.8.3)
66
+ rake (0.9.6)
67
+ rdoc (4.0.1)
68
+ json (~> 1.4)
69
+ sass (3.2.11)
70
+ stringex (1.3.3)
71
+ tzinfo (0.3.37)
72
+ will_paginate (2.3.16)
73
+
74
+ PLATFORMS
75
+ ruby
76
+
77
+ DEPENDENCIES
78
+ radiant-taginator-extension!
79
+ rake (~> 0.9)
data/HELP.md ADDED
@@ -0,0 +1,50 @@
1
+ The Tags extension provides a way for you to easily categorize your pages.
2
+
3
+ == Results page
4
+
5
+ <r:search:empty>
6
+ <h2>I couldn't find anything tagged with "<r:search:query/>".</h2>
7
+ </r:search:empty>
8
+
9
+ <r:search:results>
10
+ <h2>Found the following pages that are tagged with "<em><r:search:query/></em>".</h2>
11
+
12
+ <ul>
13
+ <r:search:results:each>
14
+ <li><r:link/> - <r:author/> - <r:date/></li>
15
+ </r:search:results:each>
16
+ </ul>
17
+ </r:search:results>
18
+
19
+
20
+ == Tag cloud
21
+
22
+ Use `<r:tag_cloud />` anywhere you like.
23
+ I made a stab at building the 'perfect' tag cloud markup, as inspired by a post on 24ways.org; http://24ways.org/2006/marking-up-a-tag-cloud
24
+
25
+ == Tag list
26
+
27
+ Use `<r:tag_list />` to get a list of tags for the current page.
28
+ Also works through children:each.
29
+
30
+ == All tags
31
+
32
+ Use `<r:all_tags />` to get a list of all tags. You may iterate through them with
33
+ `<r:all_tags:each>` and access their associated pages with `<r:all_tags:each:pages:each>`
34
+
35
+ == Collections
36
+
37
+ You can grab a collection of pages with a certain tag like so;
38
+
39
+ <r:tagged with="sometag" [scope="/some/page"] [with_any="true"]>
40
+ <r:link />
41
+ </r:tagged>
42
+
43
+ Which would iterate over all the resulting pages, like you do with children:each.
44
+ When you define scope, only this page and any of it's (grand)children will be used.
45
+ Using scope="current_page" will use the page that is currently being rendered as scope.
46
+ You can also set limit, offset etc like with children:each.
47
+
48
+ Using r:tagged in it's default setting searches for pages that have all of the given tags.
49
+ Using r:tagged with the attribute 'with_any' set to 'true' will find pages that have any of
50
+ the given tags.
@@ -0,0 +1,30 @@
1
+ The Tags extension allows you to configure the style of tagging between 2 options:
2
+ simple or complex strings.
3
+
4
+ == Simple Tagging
5
+
6
+ By default you may add tags to a page in a string such as "this that other". That string
7
+ will be parsed and turned into 3 separate tags.
8
+
9
+ == Complex Tagging
10
+
11
+ You may set `Radiant::Config['tags.complex_strings'] = true` to allow you to enter more
12
+ complex tags for your pages.
13
+
14
+ When this setting is `true` the tags are delimited by a semi-colon, allowing you to enter
15
+ a string of tags such as "My Summer Vacation (2008); Entertainment/Nonsense; Miscellaneous 2.0".
16
+ The result of that string will return 3 tags: `My Summer Vacation (2008)`,
17
+ `Entertainment/Nonsense` and 'Miscellaneous 2.0'
18
+
19
+ == Making the choice
20
+
21
+ You'll need to restart the application server after changing this setting. Please keep in
22
+ mind that any changes to this setting may affect any tags you currently have in the database.
23
+ It is recommended that you choose either Simple or Complex, but that you do not switch
24
+ after creating your tags.
25
+
26
+ == Tag Clouds
27
+
28
+ Some styles are provided in tags.css for the <r:tag_cloud>. To use it, add this to your layout:
29
+
30
+ <link rel="stylesheet" type="text/css" href="/stylesheets/tags.css" />
data/README ADDED
@@ -0,0 +1,38 @@
1
+ = Tags extension
2
+
3
+ Created by: Keith Bingman - keithbingman.com
4
+ Revived by: Benny Degezelle - gorilla-webdesign.be
5
+ New features by: Jim Gay - saturnflyer.com
6
+ Rewrite by: Michal Cichra - blog.o2h.cz
7
+
8
+ Version: 2.0.beta
9
+
10
+ This extension enhances the page model with tagging capabilities, tagging as in "2.0" and tagclouds.
11
+
12
+ == Requirements
13
+
14
+ This extension depends on the acts-as-taggable-on plugin (included in vendor/plugins)
15
+
16
+ == Installation
17
+
18
+ 1. Copy the extension to your vendor/extensions directory as you would any other extension.
19
+ 2. Run 'rake radiant:extensions:tags:install'
20
+ 3. Make a page to sit in '/t', and give it the "Tag Search" pagetype.
21
+ If you want to change this location, it's in Radiant::Config['tags.results_page_url'].
22
+
23
+ Done!
24
+ Here's a sample results page to get you started;
25
+
26
+ <r:search:empty>
27
+ <h2>I couldn't find anything tagged with "<r:search:query/>".</h2>
28
+ </r:search:empty>
29
+
30
+ <r:search:results>
31
+ <h2>Found the following pages that are tagged with "<em><r:search:query/></em>".</h2>
32
+
33
+ <ul>
34
+ <r:search:results:each>
35
+ <li><r:link/> - <r:author/> - <r:date/></li>
36
+ </r:search:results:each>
37
+ </ul>
38
+ </r:search:results>
@@ -0,0 +1,27 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require "bundler/gem_tasks"
5
+
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :test
9
+
10
+ desc 'Test the tags extension.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc 'Generate documentation for the tags extension.'
18
+ Rake::RDocTask.new(:rdoc) do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'TagsExtension'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
25
+
26
+ # Load any custom rakefiles for extension
27
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
@@ -0,0 +1,88 @@
1
+ class TagSearchPage < Page
2
+
3
+ attr_accessor :requested_tag
4
+ #### Tags ####
5
+ desc %{ The namespace for all search tags.}
6
+ tag 'search' do |tag|
7
+ tag.expand
8
+ end
9
+
10
+ desc %{ Renders the passed query.}
11
+ tag 'search:query' do |tag|
12
+ requested_tag
13
+ end
14
+
15
+ desc %{ Renders the contained block if no results were returned.}
16
+ tag 'search:empty' do |tag|
17
+ if found_tags.blank?
18
+ tag.expand
19
+ end
20
+ end
21
+
22
+ desc %{ Renders the contained block if results were returned.}
23
+ tag 'search:results' do |tag|
24
+ unless found_tags.blank?
25
+ tag.expand
26
+ end
27
+ end
28
+
29
+ desc %{ <r:search:results:each [sort_by="id"] [order="asc"]/>
30
+ Renders the contained block for each result page. The context
31
+ inside the tag refers to the found page.
32
+
33
+ Optionaly can pass <em>conditions</em>, <em>order</em> and such attributes.
34
+ }
35
+ tag 'search:results:each' do |tag|
36
+ # Ordering in Ruby because we already fetched our resultset before
37
+ tags = found_tags tag.attr.symbolize_keys
38
+
39
+ returning String.new do |content|
40
+ tags.each do |page|
41
+ tag.locals.page = page
42
+ content << tag.expand
43
+ end
44
+ end
45
+ end
46
+
47
+ desc %{ <r:truncate_and_strip [length="100"] />
48
+ Truncates and strips all HTML tags from the content of the contained block.
49
+ Useful for displaying a snippet of a found page. The optional `length' attribute
50
+ specifies how many characters to truncate to.}
51
+ tag 'truncate_and_strip' do |tag|
52
+ tag.attr['length'] ||= 100
53
+ length = tag.attr['length'].to_i
54
+ helper = ActionView::Base.new
55
+ helper.truncate(helper.strip_tags(tag.expand).gsub(/\s+/," "), length)
56
+ end
57
+
58
+ #### "Behavior" methods ####
59
+ def cache?
60
+ true
61
+ end
62
+
63
+ def found_tags(options = {:order => 'published_at DESC'})
64
+ return @found_tags if @found_tags
65
+ return [] if requested_tag.blank?
66
+
67
+ options.reverse_merge! :state => 'published'
68
+ @found_tags = Page.tagged_with(requested_tag, options)
69
+ end
70
+
71
+ def render
72
+ self.requested_tag = @request.parameters[:tag] unless requested_tag
73
+ self.title = "Tagged with #{requested_tag}" if requested_tag
74
+
75
+ super
76
+ end
77
+
78
+ def find_by_url(url, live = true, clean = false)
79
+ url = clean_url(url).chop # chop off trailing slash added by clean_url
80
+ if url =~ /^#{self.url}(.*?)\/?$/
81
+ self.requested_tag = $1.gsub(/\b\+\b/, " ")
82
+ self
83
+ else
84
+ super
85
+ end
86
+ end
87
+
88
+ end
@@ -0,0 +1,4 @@
1
+ %h4 Tags
2
+ %p Tags that you list on your pages are ad-hoc categories and tags that you apply to your pages are as flexible as you want them to be. Rather than selecting a category for your page from a pre-defined list of categories, you can create whatever you need.
3
+ %p Tags are delimited (separated) by a space, so if you want to tag a page with Totally Awesome as one tag, be sure to put it in quotes such as 'Totally Awesome', otherwise you'll create two tags: one called Totally and one called Awesome.
4
+ %p These tags may be used by the site developers to provide a list of links (for example) to a group of pages with the same tag.
@@ -0,0 +1,8 @@
1
+ %tr
2
+ %th.label
3
+ %label{:for => "page_categories_list"}
4
+ Tags
5
+ %td.field
6
+ = f.text_field :category_list, :class => 'textbox'
7
+ - unless model.errors.on_base.nil?
8
+ %span.error= model.errors.on_base
@@ -0,0 +1,22 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ # FIME: it doesn't work with namespace admin and without :name_prefix and path_prefix (only on production). :(
3
+ #map.namespace(:admin) do |admin|
4
+ map.resources :galleries,
5
+ :name_prefix =>'admin_',
6
+ :path_prefix => 'admin',
7
+ :member => {
8
+ :clear_thumbs => :get,
9
+ :reorder => :get,
10
+ :update_order => :post
11
+ },
12
+ :collection => {
13
+ :children => :get,
14
+ :reorder => :get,
15
+ :update_order => :post
16
+ } do |galleries|
17
+ galleries.resources :children, :controller => 'galleries', :path_prefix => '/admin/galleries/:parent_id'
18
+ galleries.resources :items, :controller => 'gallery_items', :member => { :move => :put }
19
+ galleries.resources :importings, :controller => 'gallery_importings', :member => { :import => :put }
20
+ galleries.resources :keywords, :controller => 'gallery_keywords', :only => [ :edit, :update, :destroy ]
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ class ActsAsTaggableOnMigration < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :tags do |t|
4
+ t.column :name, :string
5
+ end
6
+
7
+ create_table :taggings do |t|
8
+ t.column :tag_id, :integer
9
+ t.column :taggable_id, :integer
10
+ t.column :tagger_id, :integer
11
+ t.column :tagger_type, :string
12
+
13
+ # You should make sure that the column created is
14
+ # long enough to store the required class names.
15
+ t.column :taggable_type, :string
16
+ t.column :context, :string
17
+
18
+ t.column :created_at, :datetime
19
+ end
20
+
21
+ add_index :taggings, :tag_id
22
+ add_index :taggings, [:taggable_id, :taggable_type, :context]
23
+ end
24
+
25
+ def self.down
26
+ drop_table :taggings
27
+ drop_table :tags
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ class ActsAsTaggableOnPrivateTags < ActiveRecord::Migration
2
+ def self.up
3
+ change_table :tags do |t|
4
+ t.boolean :private, :null => false, :default => false
5
+ end
6
+
7
+ add_index :tags, :private
8
+ end
9
+
10
+ def self.down
11
+ remove_column :tags, :private
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ module Taginator
2
+ autoload :VERSION, 'taginator/version'
3
+ autoload :Tags, 'taginator/tags'
4
+ end
@@ -0,0 +1,324 @@
1
+ module Taginator::Tags
2
+ include Radiant::Taggable
3
+ include ActionView::Helpers::TextHelper
4
+
5
+ class TagError < StandardError; end
6
+
7
+ desc %{
8
+ Expands if a <pre><r:tagged with="" /></pre> call would return items. Takes the same options as the 'tagged' tag.
9
+ The <pre><r:unless_tagged with="" /></pre> is also available.
10
+ }
11
+ tag 'if_tagged' do |tag|
12
+ if tag.attr[:with]
13
+ tag.locals.tagged_results = find_with_tag_options(tag)
14
+ tag.expand unless tag.locals.tagged_results.empty?
15
+ else
16
+ tag.expand unless tag.locals.page.tag_list.empty?
17
+ end
18
+ end
19
+
20
+ tag 'unless_tagged' do |tag|
21
+ if tag.attr[:with]
22
+ tag.expand if find_with_tag_options(tag).empty?
23
+ else
24
+ tag.expand if tag.locals.page.tag_list.empty?
25
+ end
26
+ end
27
+
28
+ desc %{
29
+ Find all pages with certain tags, within in an optional scope. Additionally, you may set with_any to true to select pages that have any of the listed tags (opposed to all listed tags which is the provided default).
30
+
31
+ *Usage:*
32
+ <pre><code><r:tagged with="shoes diesel" [scope="/fashion/cult-update"] [with_any="true"] [offset="number"] [limit="number"] [by="attribute"] [order="asc|desc"]>...</r:tagged></code></pre>
33
+ }
34
+ tag 'tagged' do |tag|
35
+ tag.attr[:exclude_id] ||= tag.locals.page.id
36
+ tag.locals.tagged_results ||= find_with_tag_options(tag)
37
+
38
+ tag.locals.tagged_results.map do |page|
39
+ tag.locals.page = page
40
+ tag.expand
41
+ end
42
+ end
43
+
44
+ desc %{
45
+ Find all pages related to the current page, based on all or any of the current page's tags. A scope attribute may be given to limit results to a certain site area.
46
+
47
+ *Usage:*
48
+ <pre><code><r:related_by_tags [scope="/fashion/cult-update"] [offset="number"] [limit="number"] [by="attribute"] [order="asc|desc"]>...</r:related_by_tags></code></pre>
49
+ }
50
+ tag "related_by_tags" do |tag|
51
+ options = tag.attr.slice(:offset, :limit, :order).symbolize_keys
52
+ results = tag.locals.page.find_related_on_categories(options).to_a
53
+ return if results.size < 1
54
+
55
+ if scope = tag.attr[:scope].presence
56
+ results.reject! {|page| not page.url.starts_with?(scope) }
57
+ end
58
+
59
+ results.map do |page|
60
+ tag.locals.page = page
61
+ tag.locals.first = results.first == page
62
+ tag.expand
63
+ end
64
+ end
65
+
66
+ tag "if_has_related_by_tags" do |tag|
67
+ options = tag.attr.slice(:offset, :limit, :order).symbolize_keys
68
+ results = tag.locals.page.find_related_on_categories(options)
69
+ tag.expand if results.size > 0
70
+ end
71
+
72
+ tag "related_by_tags:if_first" do |tag|
73
+ tag.expand if tag.locals.first
74
+ end
75
+
76
+ desc %{
77
+ Render a Tag cloud
78
+ The results_page attribute will default to #{Radiant::Config['tags.results_page_url']}
79
+ * :start_at - Restrict the tags to those created after a certain time
80
+ * :end_at - Restrict the tags to those created before a certain time
81
+ * :conditions - A piece of SQL conditions to add to the query
82
+ * :limit - The maximum number of tags to return
83
+ * :order - A piece of SQL to order by. Eg 'tags.count desc' or 'taggings.created_at desc'
84
+ * :at_least - Exclude tags with a frequency less than the given value
85
+ * :at_most - Exclude tags with a frequency greater than the given value
86
+ *Usage:*
87
+ <pre><code><r:tag_cloud_list [limit="number"] [results_page="/some/url"] [scope="/some/url"]/></code></pre>
88
+ }
89
+ tag "tag_cloud" do |tag|
90
+ options = tag.attr.except(:scope, :results_page).symbolize_keys
91
+ tags = tag.locals.page.class.tag_counts_on(:categories, options)
92
+
93
+ tags = filter_tags_to_url_scope(tags, tag.attr['scope']) unless tag.attr['scope'].nil?
94
+
95
+ content_tag :ol, :class => :tag_cloud do
96
+ if tags.length > 0
97
+ build_tag_cloud(tags, %w(size1 size2 size3 size4 size5 size6 size7 size8 size9)) do |t, cloud_class, amount|
98
+ puts t, cloud_class, amount
99
+ content_tag :li, :class => cloud_class do
100
+ content_tag(:span, pluralize(amount, 'page is', 'pages are') << ' tagged with ') +
101
+ link_to(t, results_page(tag) << t, :class => :tag)
102
+ end
103
+ end
104
+ else
105
+ return "<p>No tags found.</p>"
106
+ end
107
+ end
108
+ end
109
+
110
+ desc %{
111
+ Render a Tag list, more for 'categories'-ish usage, i.e.: Cats (2) Logs (1) ...
112
+ The results_page attribute will default to #{Radiant::Config['tags.results_page_url']}
113
+
114
+ *Usage:*
115
+ <pre><code><r:tag_cloud_list [results_page="/some/url"] [scope="/some/url"]/></code></pre>
116
+ }
117
+ tag "tag_cloud_list" do |tag|
118
+ options = {}
119
+ tags = tag.locals.page.class.all_tag_counts(options).order('count desc')
120
+ tags = filter_tags_to_url_scope(tags, tag.attr[:scope]) unless tag.attr[:scope].nil?
121
+
122
+ results_page = tag.attr[:results_page] || Radiant::Config['tags.results_page_url']
123
+
124
+ content_tag :ul, :class => :tag_list do
125
+ if tags.length > 0
126
+ build_tag_cloud(tags, %w(size1 size2 size3 size4 size5 size6 size7 size8 size9)) do |t, cloud_class, amount|
127
+ content_tag :li, :class => cloud_class do
128
+ link_to("#{t} (#{amount})", results_page(tag) << t, :class => :tag)
129
+ end
130
+ end
131
+ else
132
+ return "<p>No tags found.</p>"
133
+ end
134
+ end
135
+ end
136
+
137
+ desc "List the current page's tags"
138
+ tag "tag_list" do |tag|
139
+ tag.locals.page.tag_list.map{|t| link_to(t, results_page(tag) << t, :class => :tag)}.join(", ")
140
+ end
141
+
142
+ desc "List the current page's tagsi as technorati tags. this should be included in the body of a post or in your rss feed"
143
+ tag "tag_list_technorati" do |tag|
144
+ tag.locals.page.tag_list.map{|t| link_to(t, 'http://technorati.com/tag/' << t, :rel => :tag)}.join(", ")
145
+ end
146
+
147
+ tag "tags" do |tag|
148
+ tag.expand
149
+ end
150
+
151
+ #desc "Iterates over the tags of the current page"
152
+ tag "tags:each" do |tag|
153
+ tag.locals.page.categories.map do |category|
154
+ tag.locals.category = category
155
+ tag.expand
156
+ end
157
+ end
158
+
159
+ tag "tags:each:name" do |tag|
160
+ tag.locals.category.name
161
+ end
162
+
163
+ tag "tags:each:link" do |tag|
164
+ name = tag.locals.category.name
165
+ link_to name, results_page(tag) << name, :class => 'tag'
166
+ end
167
+
168
+ #desc "Set the scope for all tags in the database"
169
+ tag "all_tags" do |tag|
170
+ tag.expand
171
+ end
172
+
173
+ desc %{
174
+ Iterates through each tag and allows you to specify the order: by popularity or by name.
175
+ The default is by name. You may also limit the search; the default is 5 results.
176
+
177
+ Usage: <pre><code><r:all_tags:each order="popularity" limit="5">...</r:all_tags:each></code></pre>
178
+ }
179
+ tag "all_tags:each" do |tag|
180
+ options = tag.attr.slice(:order, :limit).symbolize_keys
181
+
182
+ if names = tag.attr[:names]
183
+ names = names.split(",").map{|t| t.strip }
184
+ options[:conditions] = ["name IN (?)", names] if names.length > 0
185
+ end
186
+
187
+ Page.all_tag_counts(options).map do |t|
188
+ tag.locals.tag = t
189
+ tag.expand
190
+ end
191
+ end
192
+
193
+ desc "Renders the tag's name"
194
+ tag "all_tags:each:name" do |tag|
195
+ tag.locals.tag.name
196
+ end
197
+
198
+ tag "all_tags:each:link" do |tag|
199
+ name = tag.locals.tag.name
200
+ link_to tag.expand.presence || name,
201
+ results_page(tag) << name,
202
+ tag.attr.reverse_merge(:class => 'tag')
203
+ end
204
+
205
+ desc "Set the scope for the tag's pages"
206
+ tag "all_tags:each:pages" do |tag|
207
+ tag.expand
208
+ end
209
+
210
+ desc "Iterates through each page"
211
+ tag "all_tags:each:pages:each" do |tag|
212
+ Page.tagged_with(tag.locals.tag.name, tag.attr.symbolize_keys).map do |page|
213
+ tag.locals.page = page
214
+ tag.expand
215
+ end
216
+ end
217
+
218
+ private
219
+
220
+ def build_tag_cloud(tag_cloud, style_list)
221
+ max, min = 0, 0
222
+ counts = tag_cloud.map(&:count)
223
+ min, max = counts.min, counts.max
224
+
225
+ divisor = ((max - min) / style_list.size) + 1
226
+
227
+ tag_cloud.map do |tag|
228
+ yield tag.name, style_list[(tag.count - min) / divisor], tag.count
229
+ end
230
+ end
231
+
232
+ def tag_item_url(name)
233
+ "#{Radiant::Config['tags.results_page_url']}/#{name}"
234
+ end
235
+
236
+ def find_with_tag_options(tag)
237
+ options = tagged_with_options(tag)
238
+ with_any = tag.attr[:with_any] || false
239
+ scope_attr = tag.attr[:scope] || '/'
240
+
241
+ raise TagError, "`tagged' tag must contain a `with' attribute." unless (tag.attr['with'] || tag.locals.page.class_name = TagSearchPage)
242
+ ttag = tag.attr['with'] || @request.parameters[:tag]
243
+
244
+ scope = scope_attr == 'current_page' ? Page.find_by_url(@request.request_uri) : Page.find_by_url(scope_attr)
245
+ return "The scope attribute must be a valid url to an existing page." if scope.nil? || scope.class_name.eql?('FileNotFoundPage')
246
+
247
+
248
+ page_ids = Page.tagged_with(ttag, options.merge(:any => with_any)).map do |page|
249
+ page.id if page.ancestors.include?(scope) || page == scope
250
+ end.compact
251
+
252
+ Page.find_all_by_id page_ids, options
253
+ end
254
+
255
+ def tagged_with_options(tag)
256
+
257
+ options = {}
258
+
259
+ [:limit, :offset].each do |symbol|
260
+ if number = tag.attr[symbol]
261
+ if number =~ /^\d{1,4}$/
262
+ options[symbol] = number.to_i
263
+ else
264
+ raise TagError.new("`#{symbol}' attribute of `each' tag must be a positive number between 1 and 4 digits")
265
+ end
266
+ end
267
+ end
268
+
269
+ by = (tag.attr[:by] || 'published_at').strip
270
+ order = (tag.attr[:order] || 'desc').strip
271
+ order_string = ''
272
+
273
+ if self.attributes.keys.include?(by)
274
+ order_string << by
275
+ else
276
+ raise TagError.new("`by' attribute of `each' tag must be set to a valid field name")
277
+ end
278
+
279
+ if order =~ /^(asc|desc)$/i
280
+ order_string << " #{$1.upcase}"
281
+ else
282
+ raise TagError.new(%{`order' attribute of `each' tag must be set to either "asc" or "desc"})
283
+ end
284
+
285
+ options[:order] = order_string
286
+
287
+ status = (tag.attr[:status] || 'published').downcase
288
+ exclude = tag.attr[:exclude_id] ? "AND pages.id != #{tag.attr[:exclude_id]}" : ""
289
+
290
+ unless status == 'all'
291
+ stat = Status[status]
292
+ unless stat.nil?
293
+ options[:conditions] = ["(virtual = ?) and (status_id = ?) #{exclude} and (published_at <= ?)", false, stat.id, Time.current]
294
+ else
295
+ raise TagError.new(%{`status' attribute of `each' tag must be set to a valid status})
296
+ end
297
+ else
298
+ options[:conditions] = ["virtual = ? #{exclude}", false]
299
+ end
300
+
301
+ options
302
+ end
303
+
304
+ def filter_tags_to_url_scope(tags, scope)
305
+ tags.select{ |tag|
306
+ tag.taggings.any?{ |tagging|
307
+ tagging.taggable.url.starts_with? scope
308
+ }
309
+ }
310
+ end
311
+
312
+ delegate :template, :to => :response
313
+ # delegate :link_to, :to => :template, :allow_nil => true
314
+ delegate :content_tag, :to => :template
315
+
316
+ def link_to *args
317
+ args.second.gsub!(' ', '+') if args.second.respond_to?(:gsub)
318
+ template.send(:link_to, *args)
319
+ end
320
+
321
+ def results_page(tag)
322
+ (tag.attr['results_page'] || Radiant::Config['tags.results_page_url']).dup << "/"
323
+ end
324
+ end
@@ -0,0 +1,3 @@
1
+ module Taginator
2
+ VERSION = "2.0.beta1"
3
+ end
@@ -0,0 +1,32 @@
1
+ namespace :radiant do
2
+ namespace :extensions do
3
+ namespace :tags do
4
+
5
+ desc "Runs the migration and update tasks of the Tags extension"
6
+ task :install => [:environment, :migrate, :update]
7
+
8
+ desc "Runs the migration of the Tags extension"
9
+ task :migrate => :environment do
10
+ require 'radiant/extension_migrator'
11
+ if ENV["VERSION"]
12
+ TagsExtension.migrator.migrate(ENV["VERSION"].to_i)
13
+ else
14
+ TagsExtension.migrator.migrate
15
+ end
16
+ end
17
+
18
+ desc "Copy needed files to public dir"
19
+ task :update => :environment do
20
+ is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
21
+ Dir[TagsExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
22
+ path = file.sub(TagsExtension.root, '')
23
+ directory = File.dirname(path)
24
+ puts "Copying #{path}..."
25
+ mkdir_p RAILS_ROOT + directory
26
+ cp file, RAILS_ROOT + path
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,11 @@
1
+ ol.tag_cloud { list-style: none; }
2
+ .tag_cloud li { display: inline; }
3
+ /* hide the extra context from CSS-enabled browsers, but not screenreaders */
4
+ .tag_cloud span { position: absolute; left: 0px; top: -500px; width: 1px; height: 1px; overflow: hidden; }
5
+
6
+ .tag_cloud .size1 { font-size: 1em; }
7
+ .tag_cloud .size2 { font-size: 1.3em; }
8
+ .tag_cloud .size3 { font-size: 1.6em; }
9
+ .tag_cloud .size4 { font-size: 1.9em; }
10
+ .tag_cloud .size5 { font-size: 2.2em; }
11
+ .tag_cloud .size6 { font-size: 2.5em; }
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'taginator'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'radiant-taginator-extension'
7
+ s.version = Taginator::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["mikz"]
10
+ s.email = ["mikz@o2h.cz"]
11
+ s.homepage = 'http://github.com/mikz/radiant-taginator-extension'
12
+ s.summary = "This extension enhances the page model with tagging capabilities, tagging as in \"2.0\" and tagclouds."
13
+ s.description = %q{Original extension - https://github.com/jomz/radiant-tags-extension}
14
+ s.require_paths = ['lib']
15
+
16
+ #s.rubyforge_project = "radiant_tools"
17
+ #s.add_dependency 'rack-rewrite', '~> 1.1.0'
18
+ #s.add_dependency 'radiant', '~> 0.9.0'
19
+ s.add_dependency 'acts-as-taggable-on'
20
+ s.add_dependency 'radiant'
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+ end
@@ -0,0 +1,43 @@
1
+ require_dependency 'application_controller'
2
+
3
+ class TaginatorExtension < Radiant::Extension
4
+ version Taginator::VERSION
5
+ description "This extension enhances the page model with tagging capabilities, tagging as in \"2.0\" and tagclouds."
6
+ url "http://github.com/mikz/radiant-taginator-extension"
7
+
8
+ DEFAULT_RESULTS_URL = '/t'
9
+
10
+ def activate
11
+ config = Radiant::Config
12
+ if config.table_exists?
13
+ config['tags.results_page_url'] = config['tags.results_page_url'].presence || DEFAULT_RESULTS_URL
14
+ config['tags.complex_strings'] = config['tags.complex_strings'].presence || false
15
+ end
16
+
17
+ Page.class_eval do
18
+ acts_as_taggable_on :categories
19
+
20
+ def category_names
21
+ categories.map &:name
22
+ end
23
+
24
+ alias :tag_list :category_list
25
+ alias :tag_list= :category_list=
26
+
27
+ end
28
+
29
+ TagSearchPage
30
+ Page.send :include, Taginator::Tags
31
+ admin.page.edit.add :extended_metadata, 'tag_field'
32
+
33
+
34
+
35
+ # HELP
36
+ if admin.respond_to?(:help)
37
+ admin.help.index.add :page_details, 'using_tags', :after => 'breadcrumbs'
38
+ end
39
+ end
40
+
41
+ def deactivate
42
+ end
43
+ end
@@ -0,0 +1,12 @@
1
+ lorem:
2
+ id: 1
3
+ name: lorem
4
+ ipsum:
5
+ id: 2
6
+ name: ipsum
7
+ dolor:
8
+ id: 3
9
+ name: dolor
10
+ sit:
11
+ id: 4
12
+ name: sit
@@ -0,0 +1,17 @@
1
+ display_tags_part:
2
+ id: 1
3
+ page_id: 5
4
+ name: body
5
+ content:
6
+ <h1>Results for <r:search:query /></h1>
7
+ <r:search:empty>
8
+ <h2>No pages tagged with "<r:search:query/>".</h2>
9
+ </r:search:empty>
10
+ <r:search:results>
11
+ <h2>These pages are tagged with "<r:search:query/>".</h2>
12
+ <ul>
13
+ <r:search:results:each order="desc" by="published_at">
14
+ <li><r:link/> door <r:author/> op <r:date/></li>
15
+ </r:search:results:each>
16
+ </ul>
17
+ </r:search:results>
@@ -0,0 +1,43 @@
1
+ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
+ homepage:
3
+ id: 1
4
+ title: Ruby Home Page
5
+ breadcrumb: Home
6
+ slug: /
7
+ status_id: 100
8
+ parent_id:
9
+ published_at: 2006-01-30 08:41:07
10
+ documentation:
11
+ id: 2
12
+ title: Documentation
13
+ breadcrumb: Documentation
14
+ slug: documentation
15
+ status_id: 100
16
+ parent_id: 1
17
+ published_at: 2006-01-31 08:41:07
18
+ books:
19
+ id: 3
20
+ title: Books
21
+ breadcrumb: Books
22
+ slug: books
23
+ status_id: 100
24
+ parent_id: 2
25
+ published_at: 2006-01-30 08:41:07
26
+ textile:
27
+ id: 4
28
+ title: Textile
29
+ breadcrumb: Textile
30
+ slug: textile
31
+ status_id: 100
32
+ parent_id: 1
33
+ published_at: 2006-01-30 08:41:07
34
+
35
+ tags_page:
36
+ id: 5
37
+ title: Tags Page
38
+ breadcrumb: tags
39
+ slug: tags
40
+ status_id: 100
41
+ parent_id: 1
42
+ class_name: TagSearchPage
43
+ published_at: 2006-01-30 08:41:07
@@ -0,0 +1,20 @@
1
+ 1:
2
+ meta_tag_id: 1
3
+ taggable_id: 1
4
+ taggable_type: Page
5
+ 2:
6
+ meta_tag_id: 2
7
+ taggable_id: 1
8
+ taggable_type: Page
9
+ 3:
10
+ meta_tag_id: 3
11
+ taggable_id: 1
12
+ taggable_type: Page
13
+ 4:
14
+ meta_tag_id: 1
15
+ taggable_id: 2
16
+ taggable_type: Page
17
+ 5:
18
+ meta_tag_id: 2
19
+ taggable_id: 2
20
+ taggable_type: Page
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class TagSearchPageTest < ActiveSupport::TestCase
4
+
5
+ fixtures :pages, :meta_tags, :taggings, :page_parts
6
+
7
+ def setup
8
+ @page = pages(:tags_page)
9
+ @page.request = ActionController::TestRequest.new
10
+ @page.response = ActionController::TestResponse.new
11
+ end
12
+
13
+ def test_title_gets_set_ok
14
+ @page.request.request_parameters = {:tag => "foo"}
15
+ @page.render
16
+ assert_equal "Tagged with foo", @page.title
17
+ end
18
+
19
+ def test_no_title_means_no_title_change
20
+ @page.render
21
+ assert_equal "Tags Page", @page.title
22
+ end
23
+
24
+ def test_page_should_show_posts_tagged_with_tag
25
+ @page.request.request_parameters = {:tag => "lorem"}
26
+ output = @page.render
27
+ assert_match /These pages are tagged with "lorem"/, output
28
+ assert_match /Ruby Home Page/, output
29
+ assert_match /Documentation/, output
30
+ end
31
+
32
+ def test_resulting_pages_should_be_sorted
33
+ @page.request.request_parameters = {:tag => "lorem"}
34
+ output = @page.render
35
+ assert_match /Documentation.*Ruby Home Page/, output
36
+ end
37
+
38
+ def test_unknown_tag_should_say_so
39
+ @page.request.request_parameters = {:tag => "foobarbar"}
40
+ output = @page.render
41
+ assert_match /No pages tagged with "foobarbar"/, output
42
+ end
43
+
44
+ end
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class TagsExtensionTest < ActiveSupport::TestCase
4
+
5
+ fixtures :pages, :meta_tags, :taggings
6
+ test_helper :render
7
+
8
+ def setup
9
+ @page = pages(:documentation)
10
+ end
11
+
12
+ def test_cloud_tag
13
+ assert_renders "<ol class=\"tag_cloud\"><li class=\"size2\"><span>1 page is tagged with </span><a href=\"?q=dolor\" class=\"tag\">dolor</a></li><li class=\"size3\"><span>2 pages are tagged with </span><a href=\"?q=ipsum\" class=\"tag\">ipsum</a></li><li class=\"size3\"><span>2 pages are tagged with </span><a href=\"?q=lorem\" class=\"tag\">lorem</a></li></ol>", "<r:tag_cloud />"
14
+ end
15
+
16
+ def test_tag_list
17
+ assert_renders "<a href=\"?q=ipsum\" class=\"tag\">ipsum</a>, <a href=\"?q=lorem\" class=\"tag\">lorem</a>", "<r:tag_list />"
18
+ end
19
+ end
@@ -0,0 +1,60 @@
1
+ module RenderTestHelper
2
+
3
+ def assert_renders(expected, input, url = nil, host = nil)
4
+ output = get_render_output(input, url, host)
5
+ message = "<#{expected.inspect}> expected but was <#{output.inspect}>"
6
+ assert_block(message) { expected == output }
7
+ end
8
+
9
+ def assert_render_match(regexp, input, url = nil)
10
+ regexp = Regexp.new(regexp) if regexp.kind_of? String
11
+ output = get_render_output(input, url)
12
+ message = "<#{output.inspect}> expected to be =~ <#{regexp.inspect}>"
13
+ assert_block(message) { output =~ regexp }
14
+ end
15
+
16
+ def assert_render_error(expected_error_message, input, url = nil)
17
+ output = get_render_output(input, url)
18
+ message = "expected error message <#{expected_error_message.inspect}> expected but none was thrown"
19
+ assert_block(message) { false }
20
+ rescue => e
21
+ message = "expected error message <#{expected_error_message.inspect}> but was <#{e.message.inspect}>"
22
+ assert_block(message) { expected_error_message === e.message }
23
+ end
24
+
25
+ def assert_headers(expected_headers, url = nil)
26
+ setup_page(url)
27
+ headers = @page.headers
28
+ message = "<#{expected_headers.inspect}> expected but was <#{headers.inspect}>"
29
+ assert_block(message) { expected_headers == headers }
30
+ end
31
+
32
+ def assert_page_renders(page_name, expected, message = nil)
33
+ page = pages(page_name)
34
+ output = page.render
35
+ message = "<#{expected.inspect}> expected, but was <#{output.inspect}>"
36
+ assert_block(message) { expected == output }
37
+ end
38
+
39
+ def assert_snippet_renders(snippet_name, expected, message = nil)
40
+ snippet = snippets(snippet_name)
41
+ output = @page.render_snippet(snippet)
42
+ message = "<#{expected.inspect}> expected, but was <#{output.inspect}>"
43
+ assert_block(message) { expected == output }
44
+ end
45
+
46
+ private
47
+
48
+ def get_render_output(input, url, host = nil)
49
+ setup_page(url, host)
50
+ @page.send(:parse, input)
51
+ end
52
+
53
+ def setup_page(url = nil, host = nil)
54
+ @page.request = ActionController::TestRequest.new
55
+ @page.request.request_uri = (url || @page.url)
56
+ @page.request.host = host || "testhost.tld"
57
+ @page.response = ActionController::TestResponse.new
58
+ end
59
+
60
+ end
@@ -0,0 +1,20 @@
1
+ require 'test/unit'
2
+ # Load the the environment
3
+ unless defined? RADIANT_ROOT
4
+ ENV["RAILS_ENV"] = "test"
5
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
6
+ end
7
+ require "#{RADIANT_ROOT}/test/test_helper"
8
+
9
+ class ActiveSupport::TestCase
10
+
11
+ # Include a helper to make testing Radius tags easier
12
+ test_helper :render
13
+
14
+ # Add the fixture directory to the fixture path
15
+ self.fixture_path << File.dirname(__FILE__) + "/fixtures"
16
+
17
+ fixtures :users, :pages
18
+ # Add more helper methods to be used by all extension tests here...
19
+
20
+ end
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class PageTaggabilityTest < ActiveSupport::TestCase
4
+ def setup
5
+ @page = Page.find 1
6
+ end
7
+
8
+ def test_page_should_be_taggable
9
+ assert true, @page.respond_to?("tag_with")
10
+ assert_difference MetaTag, :count, 2 do
11
+ @page.tag_with 'lorem ipsum'
12
+ end
13
+ end
14
+
15
+ def assert_difference(object, method = nil, difference = 1)
16
+ initial_value = object.send(method)
17
+ yield
18
+ assert_equal initial_value + difference, object.send(method), "#{object}##{method}"
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: radiant-taginator-extension
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.beta1
5
+ platform: ruby
6
+ authors:
7
+ - mikz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: acts-as-taggable-on
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: radiant
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Original extension - https://github.com/jomz/radiant-tags-extension
42
+ email:
43
+ - mikz@o2h.cz
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .gitmodules
50
+ - Gemfile
51
+ - Gemfile.lock
52
+ - HELP.md
53
+ - HELP_admin.md
54
+ - README
55
+ - Rakefile
56
+ - app/models/tag_search_page.rb
57
+ - app/views/admin/help/_using_tags.html.haml
58
+ - app/views/admin/pages/_tag_field.html.haml
59
+ - config/routes.rb
60
+ - db/migrate/001_acts_as_taggable_on_migration.rb
61
+ - db/migrate/002_acts_as_taggable_on_private_tags.rb
62
+ - lib/taginator.rb
63
+ - lib/taginator/tags.rb
64
+ - lib/taginator/version.rb
65
+ - lib/tasks/tags_extension_tasks.rake
66
+ - public/stylesheets/tags.css
67
+ - radiant-taginator-extension.gemspec
68
+ - taginator_extension.rb
69
+ - test/fixtures/meta_tags.yml
70
+ - test/fixtures/page_parts.yml
71
+ - test/fixtures/pages.yml
72
+ - test/fixtures/taggings.yml
73
+ - test/functional/tag_search_page_test.rb
74
+ - test/functional/tags_extension_test.rb
75
+ - test/helpers/render_test_helper.rb
76
+ - test/test_helper.rb
77
+ - test/unit/page_taggability_test.rb
78
+ homepage: http://github.com/mikz/radiant-taginator-extension
79
+ licenses: []
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ! '>'
93
+ - !ruby/object:Gem::Version
94
+ version: 1.3.1
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.0.6
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: This extension enhances the page model with tagging capabilities, tagging
101
+ as in "2.0" and tagclouds.
102
+ test_files:
103
+ - test/fixtures/meta_tags.yml
104
+ - test/fixtures/page_parts.yml
105
+ - test/fixtures/pages.yml
106
+ - test/fixtures/taggings.yml
107
+ - test/functional/tag_search_page_test.rb
108
+ - test/functional/tags_extension_test.rb
109
+ - test/helpers/render_test_helper.rb
110
+ - test/test_helper.rb
111
+ - test/unit/page_taggability_test.rb