parlement 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGES +26 -0
  2. data/README +2 -1
  3. data/app/controllers/account_controller.rb +27 -18
  4. data/app/controllers/application.rb +1 -3
  5. data/app/controllers/elt_controller.rb +92 -42
  6. data/app/helpers/elt_helper.rb +7 -18
  7. data/app/models/elt.rb +76 -22
  8. data/app/models/mail.rb +13 -10
  9. data/app/models/mail_notify.rb +11 -27
  10. data/app/models/person.rb +1 -1
  11. data/app/views/account/_login.rhtml +14 -9
  12. data/app/views/account/_show.rhtml +23 -9
  13. data/app/views/elt/_choice.rhtml +32 -0
  14. data/app/views/elt/_elt.rhtml +90 -78
  15. data/app/views/elt/_list.rhtml +83 -50
  16. data/app/views/elt/_listByDate.rhtml +60 -0
  17. data/app/views/elt/_listByVote.rhtml +71 -0
  18. data/app/views/elt/choices.rhtml +29 -0
  19. data/app/views/elt/new.rhtml +11 -26
  20. data/app/views/elt/rss.rxml +14 -12
  21. data/app/views/elt/show.rhtml +23 -29
  22. data/app/views/elt/vote_rss.rxml +40 -0
  23. data/app/views/layouts/top.rhtml +5 -13
  24. data/config/environment.rb +3 -1
  25. data/config/routes.rb +4 -0
  26. data/db/development_structure.sql +5 -2
  27. data/db/migrate/002_nested_set.rb +22 -0
  28. data/db/migrate/003_elt_children_count.rb +12 -0
  29. data/public/images/ParlementLogo.png +0 -0
  30. data/public/images/indicator.gif +0 -0
  31. data/public/javascripts/behaviour.js +254 -0
  32. data/public/javascripts/mybehaviour.js +96 -0
  33. data/public/javascripts/slider.js +188 -163
  34. data/test/fixtures/elts.yml +19 -0
  35. data/test/fixtures/mail/mail_ruby +4 -0
  36. data/test/fixtures/mail/mail_rubyChild +1 -1
  37. data/test/fixtures/mail/mail_rubyChild2 +1 -1
  38. data/test/functional/account_controller_test.rb +24 -0
  39. data/test/functional/elt_controller_test.rb +64 -4
  40. data/test/unit/elt_test.rb +28 -4
  41. data/test/unit/mail_notify_test.rb +7 -5
  42. data/test/unit/mail_test.rb +1 -1
  43. data/vendor/plugins/google_analytics/README +19 -0
  44. data/vendor/plugins/google_analytics/Rakefile +22 -0
  45. data/vendor/plugins/google_analytics/init.rb +3 -0
  46. data/vendor/plugins/google_analytics/lib/rubaidh/google_analytics.rb +70 -0
  47. data/vendor/plugins/google_analytics/test/google_analytics_test.rb +8 -0
  48. data/vendor/plugins/output_compression/README +4 -0
  49. data/vendor/plugins/output_compression/Rakefile +22 -0
  50. data/vendor/plugins/output_compression/init.rb +2 -0
  51. data/vendor/plugins/output_compression/lib/output_compression.rb +66 -0
  52. data/vendor/plugins/output_compression/tasks/output_compression_tasks.rake +4 -0
  53. data/vendor/plugins/output_compression/test/output_compression_test.rb +8 -0
  54. metadata +32 -4
  55. data/public/images/smile.svg +0 -257
  56. data/public/javascripts/borders.js +0 -687
@@ -4,24 +4,15 @@
4
4
 
5
5
  <%= error_messages_for 'elt' %>
6
6
 
7
- <!--
8
- <span id="author_<%= @elt.parent_id %>">
9
- <%= render :partial => 'account/show',
10
- :locals => { :divId => 'author_'+@elt.parent_id } %>
11
- </span>
12
- -->
13
-
14
7
  <%= form_remote_tag(
15
8
  :update => 'eltSubs_'+@elt.parent_id,
16
- :url => { :action => 'create' },
9
+ :url => { :action => 'create', :id => @elt.parent },
17
10
  :position => 'bottom',
18
- :loading => visual_effect(:BlindUp, 'eltNew_'+@elt.parent.id.to_s),
19
- :complete => "Element.show('eltSubs_#{@elt.parent_id.to_s}');
20
- Element.show('eltSubsClose_#{@elt.parent_id.to_s}');",
21
- :loaded => visual_effect(:BlindDown, 'elt_'+@elt.id.to_s)) %>
11
+ :before => visual_effect(:BlindUp, 'eltNew_'+@elt.parent_id),
12
+ :loading => "Element.show('eltSubs_#{@elt.parent_id}');
13
+ Element.show('eltSubsClose_#{@elt.parent_id}')") %>
22
14
 
23
- <!--[form:elt]-->
24
- <%= hidden_field 'elt', 'parent_id' %></p>
15
+ <%= hidden_field 'elt', 'parent_id' %>
25
16
 
26
17
  <h2>
27
18
  <%= text_field 'elt', 'subject' %>
@@ -35,18 +26,14 @@
35
26
  ' } %>
36
27
  </h2>
37
28
 
38
- <div style="display:none">
39
- <label for="elt_position">Position:</label>
40
- <%= text_field 'elt', 'position', 'size' => 1, 'align' => 'right' %>
41
- </div>
42
-
43
29
  <%= text_area 'elt', 'body' %>
44
30
 
45
31
  <div class="eltNewButtons">
46
32
  <%= submit_to_remote('Preview', 'Preview',
47
- :update => 'eltNewPreview_'+@elt.parent_id,
48
- :url => { :action => 'create', :submit => :preview },
49
- :loaded => visual_effect(:BlindDown, 'eltNewPreview_'+@elt.parent_id)) %>
33
+ :update => "eltNewPreview_"+@elt.parent_id,
34
+ :url => { :action => "create", :id => @elt.parent, :submit => "preview" },
35
+ :loading => visual_effect(:BlindDown, 'eltNewPreview_'+@elt.parent_id)) %>
36
+
50
37
  <%= submit_tag 'Propose!' %>
51
38
 
52
39
  <%= render :partial => '/help',
@@ -94,9 +81,7 @@
94
81
  <a href="http://hobix.com/textile/quick.html">Textile Reference</a>
95
82
  ' } %>
96
83
  </div>
97
-
98
- <span class="eltNew" id="eltNewPreview_<%= @elt.parent_id %>"/>
99
-
100
- <!--[eoform:elt]-->
101
84
  <%= end_form_tag %>
102
85
 
86
+ <span class="elt" id="eltNewPreview_<%= @elt.parent_id %>"/>
87
+
@@ -1,16 +1,17 @@
1
1
  xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
2
2
  xml.channel do
3
- xml.title(@elt.subject)
4
- xml.link(url_for(:only_path => false, :action => nil, :id => @elt.id))
5
- xml.description @elt.subject+" (parlement)"
6
- xml.language "en"
7
- xml.language "fr"
3
+ xml.title @elt.subject
4
+ xml.link url_for(:only_path => false, :action => 'show', :id => @elt)
5
+ xml.description @elt.subject
8
6
 
9
- for item in @elt.children.reverse
7
+ Elt.find(:all,
8
+ :conditions => "lft > #{@elt.lft} AND rgt < #{@elt.rgt}",
9
+ :order => 'created_on DESC',
10
+ :limit => PAGE_ELT_LENGTH).each do |item|
10
11
  xml.item do
11
- xml.title(item.subject)
12
+ xml.title item.subject
12
13
  #xml.category(@elt.subject)
13
- xml.pubDate(item.created_on)
14
+ xml.pubDate item.created_on
14
15
 
15
16
  if url_for(:only_path => false).match(/http:\/\/echarp.dyndns.org/) and @elt.id == 'blog'
16
17
  xml.link(url_for(:only_path => false, :controller => 'perso',
@@ -18,14 +19,15 @@ xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
18
19
  xml.comments(url_for(:only_path => false, :controller => 'perso',
19
20
  :action => 'blog', :id => item.id+'.html'))
20
21
  else
21
- xml.link(url_for(:only_path => false, :action => 'show', :id => item.id))
22
- xml.comments(url_for(:only_path => false, :action => 'show', :id => item.id))
22
+ xml.link(url_for(:only_path => false, :action => 'show', :id => item))
23
+ xml.comments(url_for(:only_path => false, :action => 'show', :id => item))
23
24
  end
24
25
 
25
- xml.tag!("dc:creator", item.person.name) if item.person != nil
26
+ xml.tag!("dc:creator", item.person.name) if item.person
26
27
 
27
- xml.description("<p>"+format(item.body)+"</p>")
28
+ xml.description "<p>"+format(item.body)+"</p>"
28
29
  end
29
30
  end
30
31
  end
31
32
  end
33
+
@@ -2,7 +2,7 @@
2
2
  <h3 class="boxTitle">Electoral list</h3>
3
3
  <div class="box">
4
4
  All voters:
5
- <span class="result" style="float: none">
5
+ <span class="result selected" style="float: none">
6
6
  <%= Choice.count :select => 'person_id', :distinct => true %>
7
7
  </span>
8
8
  </div>
@@ -10,36 +10,27 @@
10
10
  <h3 class="boxTitle">Identity</h3>
11
11
  <div class="box">
12
12
  <div id="author_<%= @elt.id %>">
13
- <%= render :partial => 'account/show',
14
- :locals => { :divId => 'author_'+@elt.id } %>
13
+ <%= render :partial => 'account/show', :locals => { :divId => 'author_'+@elt.id } %>
15
14
  </div>
16
15
  </div>
17
16
 
18
- <% if @elt.children.count > 0 %>
19
- <h3 class="boxTitle">Titres</h3>
20
- <% end %>
21
-
22
- <div class="box">
23
- <ul>
24
- <% for elt in @elt.children.reverse[0...PAGE_ELT_LENGTH] %>
25
- <li class="boxLine" title="<%= elt.created_on.strftime('%d/%m') %>">
26
- <span class="result"><%= sprintf("%+d", elt.result) %></span>
27
- <%= link_to elt.subject, :id => elt %>
28
- </li>
29
- <% end %>
30
- </ul>
17
+ <% if @elt.elts_count > 0 %><h3 class="boxTitle">Highest posts</h3><% end %>
18
+ <div class="box listByVote">
19
+ <%= render :partial => '/elt/listByVote' %>
20
+ </div>
31
21
 
32
- <%= link_to image_tag("/images/webfeed.gif"),
33
- :action => 'rss', :id => @elt %>
22
+ <% if @elt.elts_count > 0 %><h3 class="boxTitle">Latest posts</h3><% end %>
23
+ <div class="box listByDate">
24
+ <%= render :partial => '/elt/listByDate' %>
34
25
  </div>
35
26
 
36
27
  <h3 class="boxTitle">Subscribe</h3>
37
28
  <div class="box">
38
29
  <div id="subscription">
39
30
  <%= link_to_remote(((@session[:person] and @elt.subscribers.include?(@session[:person])) ? 'Unsubscribe!' : 'Subscribe!'),
40
- :update => 'subscription',
41
- :url => { :controller => 'subscriber', :action => 'subscribe', :id => @elt },
42
- :loaded => visual_effect(:BlindDown, 'subscription')) %>
31
+ :update => 'subscription',
32
+ :url => { :controller => 'subscriber', :action => 'subscribe', :id => @elt },
33
+ :loaded => visual_effect(:BlindDown, 'subscription')) %>
43
34
  </div>
44
35
 
45
36
  <div class="boxLine">
@@ -47,7 +38,12 @@
47
38
  <%= link_to(i.name, :controller => 'person', :action => 'show', :id => i) %>
48
39
  <% end %>
49
40
  </div>
50
- <div class="boxLineR"><%= @elt.subscribers.size %> subscriber(s)</div>
41
+
42
+ <div class="boxLineR">
43
+ <% @elt.parent.all_recipients.each do |i| %>
44
+ <%= link_to(i.name, :controller => 'person', :action => 'show', :id => i) %>
45
+ <% end %>
46
+ </div>
51
47
  </div>
52
48
  </div>
53
49
 
@@ -55,14 +51,12 @@
55
51
  <div class="<%= key %>"><%= value %></div>
56
52
  <% end %>
57
53
 
58
- <% if @elt.parent and @elt.parent.subject != '' %>
59
- <h3 class="parent">
60
- <%= link_to(textilize_without_paragraph(@elt.parent.subject),
61
- :id => @elt.parent) %>
62
- </h3>
63
- <% end %>
54
+ <h3 class="parent">
55
+ <%= link_to textilize_without_paragraph(@elt.parent.subject), :id => @elt.parent \
56
+ if @elt.parent %>
57
+ </h3>
64
58
 
65
- <ul>
59
+ <ul class="top">
66
60
  <%= render :partial => 'elt', :layout => 'top',
67
61
  :locals => { :elt => @elt, :eltTop => true } %>
68
62
  </ul>
@@ -0,0 +1,40 @@
1
+ xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
2
+ xml.channel do
3
+ xml.title @elt.subject
4
+ xml.link url_for(:only_path => false, :action => 'show', :id => @elt)
5
+ xml.description @elt.subject
6
+
7
+ Elt.find(:all,
8
+ :select => 'SUM(value), elts.id, parent_id, elts.created_on, parent_id,' \
9
+ +'elts_count, position, elts.person_id, subject, body, lft, rgt',
10
+ :conditions => "lft > #{@elt.lft} AND rgt < #{@elt.rgt}",
11
+ :order => 'SUM(value) IS NULL, SUM(value) DESC, created_on DESC',
12
+ :group => 'elts.id, parent_id, elts.created_on, parent_id, elts_count,' \
13
+ +'position, elts.person_id, subject, body, lft, rgt',
14
+ :limit => PAGE_ELT_LENGTH,
15
+ :joins => "LEFT JOIN choices ON elt_id = elts.id").each do |item|
16
+
17
+ xml.item do
18
+ xml.title item.subject
19
+ #xml.category(@elt.subject)
20
+ xml.vote item.result
21
+ xml.pubDate item.created_on
22
+
23
+ if url_for(:only_path => false).match(/http:\/\/echarp.dyndns.org/) and @elt.id == 'blog'
24
+ xml.link(url_for(:only_path => false, :controller => 'perso',
25
+ :action => 'blog', :id => item.id+'.html'))
26
+ xml.comments(url_for(:only_path => false, :controller => 'perso',
27
+ :action => 'blog', :id => item.id+'.html'))
28
+ else
29
+ xml.link(url_for(:only_path => false, :action => 'show', :id => item))
30
+ xml.comments(url_for(:only_path => false, :action => 'show', :id => item))
31
+ end
32
+
33
+ xml.tag!("dc:creator", item.person.name) if item.person
34
+
35
+ xml.description "<p>"+format(item.body)+"</p>"
36
+ end
37
+ end
38
+ end
39
+ end
40
+
@@ -7,9 +7,9 @@
7
7
  <%= stylesheet_link_tag 'default.css' %>
8
8
  <%= javascript_include_tag "/javascripts/prototype" %>
9
9
  <%= javascript_include_tag "/javascripts/scriptaculous" %>
10
- <!--
11
- <%= javascript_include_tag "/javascripts/borders" %>
12
- -->
10
+
11
+ <%= javascript_include_tag "/javascripts/behaviour" %>
12
+ <%= javascript_include_tag "/javascripts/mybehaviour" %>
13
13
 
14
14
  <!-- compliance patch for microsoft browsers -->
15
15
  <!--[if lt IE 7]>
@@ -17,7 +17,6 @@
17
17
  <%= javascript_include_tag "/javascripts/ie7.js" %>
18
18
  <![endif]-->
19
19
 
20
-
21
20
  <link rel="shortcut icon" href="/images/world.png" type="image/png"/>
22
21
 
23
22
  <meta name="ROBOTS" content="ALL"/>
@@ -34,10 +33,10 @@
34
33
  <body>
35
34
  <div class="links">
36
35
  <a class="title" href="http://leparlement.org">Parlement</a>
37
- <div class="signets">
36
+ <span class="signets">
38
37
  <a href="http://rubyforge.org/projects/parlement">forge</a>
39
38
  <a href="http://www.gnu.org/licenses/gpl.html">GPL</a>
40
- </div>
39
+ </span>
41
40
  </div>
42
41
 
43
42
  <%= @content_for_layout %>
@@ -52,13 +51,6 @@
52
51
  <img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0 Strict"/>
53
52
  </a>
54
53
  </p>
55
-
56
- <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
57
- </script>
58
- <script type="text/javascript">
59
- _uacct = "UA-317241-1";
60
- urchinTracker();
61
- </script>
62
54
  </body>
63
55
  </html>
64
56
 
@@ -64,7 +64,7 @@ require 'rails_file_column'
64
64
  require 'jcode'
65
65
  $KCODE = 'u'
66
66
 
67
- PARLEMENT_VERSION='0.5'
67
+ PARLEMENT_VERSION='0.6'
68
68
 
69
69
  # How many elements are displayed at once
70
70
  PAGE_ELT_LENGTH = 10
@@ -101,3 +101,5 @@ module LoginEngine
101
101
  end
102
102
  Engines.start :login
103
103
 
104
+ Rubaidh::GoogleAnalytics.tracker_id = 'UA-317241-1'
105
+
data/config/routes.rb CHANGED
@@ -12,16 +12,20 @@ ActionController::Routing::Routes.draw do |map|
12
12
 
13
13
  map.connect '', :controller => 'elt', :action => 'show', :id => 'parlement'
14
14
  map.connect 'index.rss', :controller => 'elt', :action => 'rss', :id => 'parlement'
15
+ map.connect 'vote.rss', :controller => 'elt', :action => 'vote_rss', :id => 'parlement'
15
16
 
16
17
  map.connect ':id', :controller => 'elt', :action => 'rss', :requirements => { :id => /.*\.rss/ }
17
18
  map.connect ':id', :controller => 'elt', :action => 'show'
18
19
  map.connect ':id/index.rss', :controller => 'elt', :action => 'rss'
20
+ map.connect ':id/vote.rss', :controller => 'elt', :action => 'vote_rss'
19
21
  map.connect ':id//index.rss', :controller => 'elt', :action => 'rss'
22
+ map.connect ':id//vote.rss', :controller => 'elt', :action => 'vote_rss'
20
23
 
21
24
  map.connect 'perso/:id', :controller => 'elt', :action => 'show'
22
25
  map.connect 'perso/:id/index.rss', :controller => 'elt', :action => 'rss'
23
26
  map.connect 'perso/blog/:id', :controller => 'elt'
24
27
  map.connect 'perso/blog/:id/index.rss', :controller => 'elt', :action => 'rss'
28
+ map.connect 'perso/blog/:id/vote.rss', :controller => 'elt', :action => 'vote_rss'
25
29
 
26
30
  # Allow downloading Web Service WSDL as a file with an extension
27
31
  # instead of a file named 'wsdl'
@@ -70,7 +70,10 @@ CREATE TABLE elts (
70
70
  created_on timestamp with time zone DEFAULT now() NOT NULL,
71
71
  person_id text,
72
72
  subject text,
73
- body text
73
+ body text,
74
+ lft integer,
75
+ rgt integer,
76
+ elts_count integer DEFAULT 0
74
77
  );
75
78
 
76
79
 
@@ -357,4 +360,4 @@ ALTER TABLE ONLY usersold
357
360
  -- PostgreSQL database dump complete
358
361
  --
359
362
 
360
- INSERT INTO schema_info (version) VALUES (1)
363
+ INSERT INTO schema_info (version) VALUES (3)
@@ -0,0 +1,22 @@
1
+ class NestedSet < ActiveRecord::Migration
2
+
3
+ def NestedSet.nested_set_construction(e)
4
+ e.children.each { |c|
5
+ e.add_child c
6
+ nested_set_construction c
7
+ }
8
+ end
9
+
10
+ def self.up
11
+ add_column :elts, :lft, :integer
12
+ add_column :elts, :rgt, :integer
13
+
14
+ e = Elt.find 'ROOT'
15
+ NestedSet.nested_set_construction e
16
+ end
17
+
18
+ def self.down
19
+ remove_column :elts, :lft
20
+ remove_column :elts, :rgt
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ class EltChildrenCount < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :elts, :elts_count, :integer, :default => 0
4
+ execute 'UPDATE elts SET elts_count = (SELECT COUNT(*) FROM elts e2 WHERE e2.parent_id = elts.id)'
5
+ add_index "elts", ["lft"], :name => "elts_lft_key", :unique => true
6
+ add_index "elts", ["parent_id"], :name => "elts_parent_key"
7
+ end
8
+
9
+ def self.down
10
+ remove_column :elts, :elts_count
11
+ end
12
+ end
Binary file
Binary file
@@ -0,0 +1,254 @@
1
+ /*
2
+ Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work
3
+ of Simon Willison (see comments by Simon below).
4
+
5
+ Description:
6
+
7
+ Uses css selectors to apply javascript behaviours to enable
8
+ unobtrusive javascript in html documents.
9
+
10
+ Usage:
11
+
12
+ var myrules = {
13
+ 'b.someclass' : function(element){
14
+ element.onclick = function(){
15
+ alert(this.innerHTML);
16
+ }
17
+ },
18
+ '#someid u' : function(element){
19
+ element.onmouseover = function(){
20
+ this.innerHTML = "BLAH!";
21
+ }
22
+ }
23
+ };
24
+
25
+ Behaviour.register(myrules);
26
+
27
+ // Call Behaviour.apply() to re-apply the rules (if you
28
+ // update the dom, etc).
29
+
30
+ License:
31
+
32
+ This file is entirely BSD licensed.
33
+
34
+ More information:
35
+
36
+ http:/ipcord.co.nz/behaviour/
37
+
38
+ */
39
+
40
+ var Behaviour = {
41
+ list : new Array,
42
+
43
+ register : function(sheet){
44
+ Behaviour.list.push(sheet);
45
+ },
46
+
47
+ start : function(){
48
+ Behaviour.addLoadEvent(function(){
49
+ Behaviour.apply();
50
+ });
51
+ },
52
+
53
+ apply : function(){
54
+ for (h=0;sheet=Behaviour.list[h];h++){
55
+ for (selector in sheet){
56
+ list = document.getElementsBySelector(selector);
57
+
58
+ if (!list){
59
+ continue;
60
+ }
61
+
62
+ for (i=0;element=list[i];i++){
63
+ sheet[selector](element);
64
+ }
65
+ }
66
+ }
67
+ },
68
+
69
+ addLoadEvent : function(func){
70
+ var oldonload = window.onload;
71
+
72
+ if (typeof window.onload != 'function') {
73
+ window.onload = func;
74
+ } else {
75
+ window.onload = function() {
76
+ oldonload();
77
+ func();
78
+ }
79
+ }
80
+ }
81
+ }
82
+
83
+ Behaviour.start();
84
+
85
+ /*
86
+ The following code is Copyright (C) Simon Willison 2004.
87
+
88
+ document.getElementsBySelector(selector)
89
+ - returns an array of element objects from the current document
90
+ matching the CSS selector. Selectors can contain element names,
91
+ class names and ids and can be nested. For example:
92
+
93
+ elements = document.getElementsBySelect('div#main p a.external')
94
+
95
+ Will return an array of all 'a' elements with 'external' in their
96
+ class attribute that are contained inside 'p' elements that are
97
+ contained inside the 'div' element which has id="main"
98
+
99
+ New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
100
+ See http://www.w3.org/TR/css3-selectors/#attribute-selectors
101
+
102
+ Version 0.4 - Simon Willison, March 25th 2003
103
+ -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
104
+ -- Opera 7 fails
105
+ */
106
+
107
+ function getAllChildren(e) {
108
+ // Returns all children of element. Workaround required for IE5/Windows. Ugh.
109
+ return e.all ? e.all : e.getElementsByTagName('*');
110
+ }
111
+
112
+ document.getElementsBySelector = function(selector) {
113
+ // Attempt to fail gracefully in lesser browsers
114
+ if (!document.getElementsByTagName) {
115
+ return new Array();
116
+ }
117
+ // Split selector in to tokens
118
+ var tokens = selector.split(' ');
119
+ var currentContext = new Array(document);
120
+ for (var i = 0; i < tokens.length; i++) {
121
+ token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
122
+ if (token.indexOf('#') > -1) {
123
+ // Token is an ID selector
124
+ var bits = token.split('#');
125
+ var tagName = bits[0];
126
+ var id = bits[1];
127
+ var element = document.getElementById(id);
128
+ if (tagName && element.nodeName.toLowerCase() != tagName) {
129
+ // tag with that ID not found, return false
130
+ return new Array();
131
+ }
132
+ // Set currentContext to contain just this element
133
+ currentContext = new Array(element);
134
+ continue; // Skip to next token
135
+ }
136
+ if (token.indexOf('.') > -1) {
137
+ // Token contains a class selector
138
+ var bits = token.split('.');
139
+ var tagName = bits[0];
140
+ var className = bits[1];
141
+ if (!tagName) {
142
+ tagName = '*';
143
+ }
144
+ // Get elements matching tag, filter them for class selector
145
+ var found = new Array;
146
+ var foundCount = 0;
147
+ for (var h = 0; h < currentContext.length; h++) {
148
+ var elements;
149
+ if (tagName == '*') {
150
+ elements = getAllChildren(currentContext[h]);
151
+ } else {
152
+ elements = currentContext[h].getElementsByTagName(tagName);
153
+ }
154
+ for (var j = 0; j < elements.length; j++) {
155
+ found[foundCount++] = elements[j];
156
+ }
157
+ }
158
+ currentContext = new Array;
159
+ var currentContextIndex = 0;
160
+ for (var k = 0; k < found.length; k++) {
161
+ if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
162
+ currentContext[currentContextIndex++] = found[k];
163
+ }
164
+ }
165
+ continue; // Skip to next token
166
+ }
167
+ // Code to deal with attribute selectors
168
+ if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
169
+ var tagName = RegExp.$1;
170
+ var attrName = RegExp.$2;
171
+ var attrOperator = RegExp.$3;
172
+ var attrValue = RegExp.$4;
173
+ if (!tagName) {
174
+ tagName = '*';
175
+ }
176
+ // Grab all of the tagName elements within current context
177
+ var found = new Array;
178
+ var foundCount = 0;
179
+ for (var h = 0; h < currentContext.length; h++) {
180
+ var elements;
181
+ if (tagName == '*') {
182
+ elements = getAllChildren(currentContext[h]);
183
+ } else {
184
+ elements = currentContext[h].getElementsByTagName(tagName);
185
+ }
186
+ for (var j = 0; j < elements.length; j++) {
187
+ found[foundCount++] = elements[j];
188
+ }
189
+ }
190
+ currentContext = new Array;
191
+ var currentContextIndex = 0;
192
+ var checkFunction; // This function will be used to filter the elements
193
+ switch (attrOperator) {
194
+ case '=': // Equality
195
+ checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
196
+ break;
197
+ case '~': // Match one of space seperated words
198
+ checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
199
+ break;
200
+ case '|': // Match start with value followed by optional hyphen
201
+ checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
202
+ break;
203
+ case '^': // Match starts with value
204
+ checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
205
+ break;
206
+ case '$': // Match ends with value - fails with "Warning" in Opera 7
207
+ checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
208
+ break;
209
+ case '*': // Match ends with value
210
+ checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
211
+ break;
212
+ default :
213
+ // Just test for existence of attribute
214
+ checkFunction = function(e) { return e.getAttribute(attrName); };
215
+ }
216
+ currentContext = new Array;
217
+ var currentContextIndex = 0;
218
+ for (var k = 0; k < found.length; k++) {
219
+ if (checkFunction(found[k])) {
220
+ currentContext[currentContextIndex++] = found[k];
221
+ }
222
+ }
223
+ // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
224
+ continue; // Skip to next token
225
+ }
226
+
227
+ if (!currentContext[0]){
228
+ return;
229
+ }
230
+
231
+ // If we get here, token is JUST an element (not a class or ID selector)
232
+ tagName = token;
233
+ var found = new Array;
234
+ var foundCount = 0;
235
+ for (var h = 0; h < currentContext.length; h++) {
236
+ var elements = currentContext[h].getElementsByTagName(tagName);
237
+ for (var j = 0; j < elements.length; j++) {
238
+ found[foundCount++] = elements[j];
239
+ }
240
+ }
241
+ currentContext = found;
242
+ }
243
+ return currentContext;
244
+ }
245
+
246
+ /* That revolting regular expression explained
247
+ /^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
248
+ \---/ \---/\-------------/ \-------/
249
+ | | | |
250
+ | | | The value
251
+ | | ~,|,^,$,* or =
252
+ | Attribute
253
+ Tag
254
+ */