Permalink
Browse files

first commit

  • Loading branch information...
0 parents commit cd347d6d36e6eeaf1bbbcc59068f92be62b7e1e3 Sven Fuchs committed Mar 30, 2009
Showing with 288 additions and 0 deletions.
  1. +66 −0 README
  2. +20 −0 init.rb
  3. +22 −0 lib/app/controllers/tag_cloud_controller.rb
  4. +28 −0 lib/app/views/tag_cloud/distribution.html.erb
  5. +20 −0 lib/drops.rb
  6. +20 −0 lib/liquid/tag_cloud.rb
  7. +23 −0 lib/models.rb
  8. +12 −0 lib/plugin.rb
  9. +68 −0 lib/tag_cloud.rb
  10. +9 −0 lib/url_filters.rb
66 README
@@ -0,0 +1,66 @@
+Tag Cloud Plugin For Mephisto
+=============================
+
+This plugin allows you to display a tag cloud in your Mephisto templates. It is, as of writing, the most complete, sophisticated, standard-conform and allover-awesome implementation of a tag cloud plugin for Mephisto. You guessed it, I'm biased ;)
+
+The architecture of this plugin (i.e. the implementation as a custom Liquid tag) is based on the Boldr tag cloud plugin by Nicolas Mérouze which can be found at: http://svn.boldr.net/mephisto/plugins/trunk/mephisto_tag_cloud/.
+
+Usage
+=====
+
+Install the plugin:
+
+ ruby script/plugin install http://svn.artweb-design.de/stuff/mephisto/mephisto_tag_cloud
+
+Thereafter you can use a dedicated liquid tag, 'tagcloud', in your templates like this:
+
+ <ul class="tagcloud">
+ {% tagcloud as tag %}
+ <li>{{ tag | link_to_tag }}</li>
+ {% endtagcloud %}
+ </ul>
+
+We use CSS to define the formatting. Just define classes like these in your stylesheets:
+
+ .tagcloud .weight-1 { font-size: 10px; }
+ .tagcloud .weight-2 { font-size: 11px; }
+ .tagcloud .weight-3 { font-size: 12px; }
+ .tagcloud .weight-4 { font-size: 13px; }
+
+Options
+=======
+
+You can configure the number of sizes/weights that are generated through the option:
+
+ TagCloud.weights = 6 # default: 10
+
+This get's you a distribution over 6 sizes.
+
+You can configure whether the tags are ordered alphabetically or by the weight of the tag by using:
+
+ TagCloud.order = :alpha # default
+ TagCloud.order = :weight
+
+You can specify the distribution method that is used to distribute the tags over the weights by using:
+
+ TagCloud.method = :log # logarithmic distribution
+ TagCloud.method = :linear # linear (weights share same range of counts)
+ TagCloud.method = lambda {|number| ... } # custom: specify your own
+
+Tag cloud distribution graph
+============================
+
+To visualize the distribution of your tags/weights and play around with the options, you can add this to your routes:
+
+# config/routes.rb
+map.connect 'tagcloud/distribution', :controller => 'tag_cloud', :action => 'distribution'
+
+Afterwards you can access a simple distribution graph at (e.g.) http://localhost:3000/tagcloud/distribution
+
+
+Licence and support
+===================
+
+(C) 2007 Sven Fuchs, under an MIT licence. http://www.opensource.org/licenses/mit-license.php
+
+Please leave any bugs or feedback at http://www.artweb-design.de
20 init.rb
@@ -0,0 +1,20 @@
+controller_path = File.join(directory, 'lib', 'app', 'controllers')
+$LOAD_PATH << controller_path
+Dependencies.load_paths << controller_path
+config.controller_paths << controller_path
+
+require File.join(lib_path, 'drops')
+require File.join(lib_path, 'url_filters')
+require File.join(lib_path, 'plugin')
+
+config.to_prepare do
+ require_dependency 'tag_cloud'
+ require_dependency File.join(lib_path, 'models')
+ require_dependency File.join(lib_path, 'liquid', 'tag_cloud')
+ Liquid::Template.register_tag('tagcloud', Liquid::TagCloud)
+ # TagCloud.limit = 10
+ # TagCloud.weights = 4
+ # TagCloud.order = :alpha
+ # TagCloud.method = :linear
+ # TagCloud.method = lambda { |number| Math.log10 number + 2 }
+end
@@ -0,0 +1,22 @@
+class TagCloudController < ApplicationController
+
+ self.view_paths = File.join(File.dirname(__FILE__), '..', 'views')
+ layout nil
+ session :off
+ before_filter :set_site
+
+ def distribution
+ # TagCloud.method = :linear
+ # TagCloud.method = :log
+ # TagCloud.method = :power
+ # TagCloud.order = :weight
+ # TagCloud.weights = 8
+ @cloud = TagCloud.new(@site)
+ end
+
+ private
+
+ def set_site
+ @site ||= Site.find_by_host(host) || Site.find(:first, :order => 'id')
+ end
+end
@@ -0,0 +1,28 @@
+<style>
+ .graph {
+ width: 910px;
+ height: 175px;
+ position: relative;
+ font-family: "Lucida Grande", Verdana, Arial;
+ }
+ .graph li {
+ position: absolute;
+ width: 3px;
+ height: 103px;
+ bottom: 10px;
+ padding: 0 !important;
+ margin: 0 !important;
+ list-style-type: none;
+ background-color: red;
+ }
+ <% @cloud.tags.each_with_index do |tag, index| -%>
+ #graph-1 .<%= tag.name.downcase %> { left: <%= 10 + (5 * index) %>px; }
+ <% end -%>
+</style>
+
+<ul class="graph" id="graph-1">
+ <% @cloud.tags.each_with_index do |tag, index|
+ scaled_value = ((tag.weight.to_f / @cloud.max.to_f) * 100).round * 5 %>
+ <li class="<%= tag.name.downcase %>" style="height: <%= scaled_value %>;" title="<%= tag.name.humanize %> (<%= tag.count %> => <%= tag.weight %>)"></li>
+ <% end %>
+</ul>
@@ -0,0 +1,20 @@
+class TagDrop < BaseDrop
+ # liquid_attributes.push *[:name]
+ def name
+ source.name
+ end
+ def weight
+ source.weight if source.respond_to? :weight
+ end
+ def count
+ source.count if source.respond_to? :count
+ end
+ def to_s
+ source.name
+ end
+ private
+ def gsub
+ 'kekse'
+ end
+end
+
@@ -0,0 +1,20 @@
+class Liquid::TagCloud < Liquid::Block
+
+ Syntax = /as\s(#{Liquid::VariableSignature}+)/ unless const_defined?('Syntax') # stupid plugin reloading issue
+
+ def initialize(tag_name, markup, tokens)
+ super
+ markup =~ Syntax
+ @param = $1
+ raise "Syntax Error in tag 'tagcloud' - Valid syntax: {tagcloud as tag} ... {endtagcloud}" unless @param
+ end
+
+ def render(context)
+ i = -1
+ TagCloud.new(context['site'].source).tags.collect do |tag|
+ context[@param] = tag
+ context['index'] = (i += 1)
+ render_all(@nodelist, context)
+ end
+ end
+end
@@ -0,0 +1,23 @@
+Site.class_eval do
+ def tags_with_count(options = {})
+ options.merge! :conditions => ['contents.type = ? AND contents.site_id = ?', 'Article', id]
+ Tag.find_all_with_count options
+ end
+end
+
+Tag.class_eval do
+ attr_accessor :weight
+
+ class << self
+ def find_all_with_count(options = {})
+ options.merge! :select => "tags.*, COUNT(*) as count", :group => "tags.id",
+ :joins => %( LEFT JOIN taggings ON taggings.tag_id = tags.id
+ LEFT JOIN contents ON contents.id = taggings.taggable_id AND contents.published_at IS NOT NULL )
+ Tag.find :all, options
+ end
+ end
+
+ def to_liquid
+ TagDrop.new self
+ end
+end
@@ -0,0 +1,12 @@
+module Mephisto
+ module Plugins
+ class TagCloud < Mephisto::Plugin
+ author 'Sven Fuchs'
+ version '0.1'
+ homepage 'http://www.artweb-design.de/projects/mephisto_tag_cloud'
+ notes "Liquid Plugin to display a tag cloud in your Mephisto templates. See homepage for credits!"
+ # option :limit, 0 # TODO this is not used, yet
+ add_route 'tagcloud/distribution', :controller => 'tag_cloud', :action => 'distribution'
+ end
+ end
+end
@@ -0,0 +1,68 @@
+require_dependency 'models/site'
+require_dependency 'models/tag'
+
+class TagCloud
+ cattr_accessor :weights, :method, :order, :limit
+ @@weights = 10
+ @@method = :log
+ @@order = :alpha
+ @@limit = nil
+
+ def initialize(site)
+ @site = site
+ end
+
+ def tags
+ @tags ||= raw_tags.each do |tag|
+ thresholds.each_with_index do |threshold, i|
+ tag.weight = i + 1 if (compute(tag.count.to_i) <= threshold) && tag.weight.nil?
+ end
+ end
+ end
+
+ def to_array
+ tags.collect {|tag| [tag.name, tag.count.to_i]}
+ end
+
+ def min
+ @min ||= counts.min
+ end
+
+ def max
+ max ||= counts.max
+ end
+
+ def thresholds
+ @thresholds ||= (1..weights).inject([]) do |res, x|
+ res << min + x * (max - min) / weights.to_f; res
+ end
+ end
+
+ private
+
+ def raw_tags
+ @raw_tags ||= @site.tags_with_count :order => order_sql, :limit => limit
+ end
+
+ def counts
+ @counts ||= raw_tags.inject([]) { |res, tag| res << tag.count.to_i; res }.uniq
+ end
+
+ def compute(value)
+ case method
+ when :linear
+ value
+ when :log
+ Math.log(value) * max / Math.log(max)
+ when :power
+ (value * value / max).round.to_f
+ else
+ method.call(value) # TODO needs to be a lambda
+ end
+ end
+
+ def order_sql
+ raise "Invalid value for TagCloud.order (#{order.inspect}). Valid values are: :weight, :alpha." unless [:weight, :alpha].include?(order)
+ order == :weight ? "count DESC" : "tags.name"
+ end
+end
@@ -0,0 +1,9 @@
+UrlFilters.module_eval do
+ def link_to_tag(tag)
+ content_tag :a, h(tag), :href => tag_url(tag), :rel => 'tag',
+ :class => (tag.weight.nil? ? nil : "weight-#{tag.weight}"),
+ :title => (tag.count.nil? ? nil : "#{h(tag)} (#{tag.count})")
+ end
+end
+
+

0 comments on commit cd347d6

Please sign in to comment.