metaruby 1.0.0.rc1

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 (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/History.txt +1 -0
  4. data/Manifest.txt +40 -0
  5. data/README.md +318 -0
  6. data/Rakefile +39 -0
  7. data/lib/metaruby/class.rb +120 -0
  8. data/lib/metaruby/dsls/doc.rb +78 -0
  9. data/lib/metaruby/dsls/find_through_method_missing.rb +76 -0
  10. data/lib/metaruby/dsls.rb +2 -0
  11. data/lib/metaruby/gui/exception_view.rb +124 -0
  12. data/lib/metaruby/gui/html/button.rb +65 -0
  13. data/lib/metaruby/gui/html/collection.rb +103 -0
  14. data/lib/metaruby/gui/html/exception_view.css +8 -0
  15. data/lib/metaruby/gui/html/jquery.min.js +154 -0
  16. data/lib/metaruby/gui/html/jquery.selectfilter.js +65 -0
  17. data/lib/metaruby/gui/html/jquery.tagcloud.min.js +8 -0
  18. data/lib/metaruby/gui/html/jquery.tinysort.min.js +8 -0
  19. data/lib/metaruby/gui/html/list.rhtml +24 -0
  20. data/lib/metaruby/gui/html/page.css +55 -0
  21. data/lib/metaruby/gui/html/page.rb +283 -0
  22. data/lib/metaruby/gui/html/page.rhtml +13 -0
  23. data/lib/metaruby/gui/html/page_body.rhtml +17 -0
  24. data/lib/metaruby/gui/html/rock-website.css +694 -0
  25. data/lib/metaruby/gui/html.rb +16 -0
  26. data/lib/metaruby/gui/model_browser.rb +262 -0
  27. data/lib/metaruby/gui/model_selector.rb +266 -0
  28. data/lib/metaruby/gui/rendering_manager.rb +112 -0
  29. data/lib/metaruby/gui/ruby_constants_item_model.rb +253 -0
  30. data/lib/metaruby/gui.rb +9 -0
  31. data/lib/metaruby/inherited_attribute.rb +482 -0
  32. data/lib/metaruby/module.rb +158 -0
  33. data/lib/metaruby/registration.rb +157 -0
  34. data/lib/metaruby/test.rb +79 -0
  35. data/lib/metaruby.rb +17 -0
  36. data/manifest.xml +12 -0
  37. data/test/suite.rb +15 -0
  38. data/test/test_attributes.rb +323 -0
  39. data/test/test_class.rb +68 -0
  40. data/test/test_dsls.rb +49 -0
  41. data/test/test_module.rb +105 -0
  42. data/test/test_registration.rb +182 -0
  43. metadata +160 -0
@@ -0,0 +1,65 @@
1
+ /*
2
+ *
3
+ * Plugin created by Andras Zoltan-Gyarfas - azolee [at] gmail [dot] com
4
+ * License: GNU License - http://www.gnu.org/licenses/gpl.html
5
+ * Demo & latest release: http://realizare-site-web.ro/works/codes/jquery/HTML-Select-List-Filter/index.html
6
+ * Last modification date: 04/20/2011
7
+ *
8
+ */
9
+
10
+ ;(function($) {
11
+ $.fn.selectFilter = function() {
12
+ var name = $(this).attr("name").replace(/\]/g, '').replace(/\[/g, '');
13
+ $(this).addClass(name+"_select");
14
+ var iname = name;
15
+ $(this).before("<input class='"+iname+"' style='display: block;' type='text' />");
16
+ $(this).css("display", "block");
17
+ $("input."+name).live("keyup", function(){
18
+ var txt = $(this).val().toLowerCase();
19
+
20
+ var fields=txt.split(' ');
21
+ var text = new Array();
22
+ var tags = new Array();
23
+ var tag_matcher = new RegExp("^tag:");
24
+ for (var i = 0; i < fields.length; ++i) {
25
+ var el = fields[i];
26
+ if (tag_matcher.test(el)) {
27
+ el = el.split(':');
28
+ tags.push(new RegExp(el[1]));
29
+ }
30
+ else if (el.length != 0) {
31
+ text.push(new RegExp(el));
32
+ }
33
+ }
34
+
35
+ if (text.length == 0 && tags.length == 0) {
36
+ $("."+name+"_select").children('div').show();
37
+ }
38
+ else {
39
+ $("."+name+"_select").children('div').hide();
40
+ $("."+name+"_select").children('div').each(function(i, selected){
41
+ var value = $(this).text().toLowerCase();
42
+ var show = true;
43
+ for (var i = 0; show && i < text.length; ++i) {
44
+ if (!text[i].test(value)) {
45
+ show = false;
46
+ }
47
+ }
48
+ var value = $(this).attr('tags');
49
+ if (value) {
50
+ value = value.toLowerCase();
51
+ for (var i = 0; show && i < tags.length; ++i) {
52
+ if (!tags[i].test(value)) {
53
+ show = false;
54
+ }
55
+ }
56
+ }
57
+ if (show) {
58
+ $(selected).show();
59
+ }
60
+ });
61
+ }
62
+ });
63
+ return this;
64
+ };
65
+ })(jQuery);
@@ -0,0 +1,8 @@
1
+ /*
2
+ * jQuery TagCloud 0.5.0
3
+ * Copyright (c) 2008 Ron Valstar
4
+ * Dual licensed under the MIT and GPL licenses:
5
+ * http://www.opensource.org/licenses/mit-license.php
6
+ * http://www.gnu.org/licenses/gpl.html
7
+ */
8
+ (function(F){var C;var A={};var G={};var L=2.399963;F.tagcloud={id:"TagCloud",version:"0.5.0",defaults:{height:null,type:"cloud",sizemax:20,sizemin:10,colormax:"00F",colormin:"B4D2FF",seed:null,power:0.5}};F.fn.extend({tagcloud:function(M){C=F.extend({},F.tagcloud.defaults,M);if(C.seed===null){C.seed=Math.ceil(Math.random()*45309714203)}switch(C.type){case"sphere":case"cloud":A={position:"relative"};G={position:"absolute",display:"block"};break;case"list":A={height:"auto"};G={position:"static",display:"inline"};break}B.setSeed(C.seed+123456);return this.each(function(f,a){var q=F(a);var R=q.find(">li");var S=R.length;var Z=q.width();var l=C.height===null?(0.004*Z*S):C.height;q.css({width:Z,height:l,listStyle:"none",margin:0,padding:0});q.css(A);var e=-2147483647;var r=2147483648;var T=-1;for(var d=0;d<S;d++){var p=F(R[d]);var n=p.attr("value")==-1?T++:p.attr("value");if(n>e){e=n}if(n<r){r=n}T=n}var b=e-r;var X=new Array();for(var d=0;d<S;d++){X[d]=d}for(var d,V,c=X.length;c;d=parseInt(B.rand(0,1000)/1000*c),V=X[--c],X[c]=X[d],X[d]=V){}T=-1;for(var d=0;d<S;d++){var p=F(R[d]);var n=p.attr("value")==-1?T++:p.attr("value");T=n;var g=((S-d-1)/(S-1));var g=(n-r)/b;var m=C.sizemin+g*(C.sizemax-C.sizemin);var N=D(C.colormin,C.colormax,g);p.css({fontSize:m,position:"absolute",color:"#"+N,margin:0,padding:0}).children().css({color:"#"+N});var Y=p.width();var h=p.height();var Q={};if(C.type!="list"){if(C.type=="cloud"){var s=B.rand(0,Z-Y);var W=X[d]*(l/S)-h/2}else{var P=Math.pow(d/S,C.power);var U=(d+Math.PI/2)*L;var s=Z/2-Y/2+0.5*Z*P*Math.sin(U);var W=l/2-h/2+0.5*l*P*Math.cos(U)}Q.left=s;Q.top=W}for(var O in G){Q[O]=G[O]}p.css(Q)}})}});var B=new function(){this.seed=23145678901;this.A=48271;this.M=2147483647;this.Q=this.M/this.A;this.R=this.M%this.A;this.oneOverM=1/this.M};B.setSeed=function(M){this.seed=M};B.next=function(){var M=this.seed/this.Q;var N=this.seed%this.Q;var O=this.A*N-this.R*M;this.seed=O+(O>0?0:this.M);return(this.seed*this.oneOverM)};B.rand=function(N,M){return Math.floor((M-N+1)*this.next()+N)};function I(M){return M.toString(16)}function K(M){return parseInt(M,16)}function H(Q){var M=Q.length==3;var O=[];for(var N=0;N<3;N++){var P=Q.substring(N*(M?1:2),(N+1)*(M?1:2));O.push(K(M?P+P:P))}return O}function J(M){var O="";for(var N=0;N<3;N++){var P=I(M[N]);if(P.length==1){P="0"+P}O+=P}return O}function D(R,S,P){var Q=H(R);var M=H(S);var O=[];for(var N=0;N<3;N++){O.push(Q[N]+Math.floor(P*(M[N]-Q[N])))}return J(O)}function E(M){if(window.console&&window.console.log){if(typeof (M)=="string"){window.console.log(M)}else{for(var N in M){window.console.log(N+": "+M[N])}}}}F.fn.TagCloud=F.fn.Tagcloud=F.fn.tagcloud})(jQuery);
@@ -0,0 +1,8 @@
1
+ /*
2
+ * jQuery TinySort 1.0.1
3
+ * Copyright (c) 2008 Ron Valstar
4
+ * Dual licensed under the MIT and GPL licenses:
5
+ * http://www.opensource.org/licenses/mit-license.php
6
+ * http://www.gnu.org/licenses/gpl.html
7
+ */
8
+ (function(C){C.tinysort={id:"TinySort",version:"1.0.1",defaults:{order:"asc",attr:"",place:"start",returns:false}};C.fn.extend({tinysort:function(I,J){if(I&&typeof (I)!="string"){J=I;I=null}var F=C.extend({},C.tinysort.defaults,J);var P={};this.each(function(T){var V=(!I||I=="")?C(this):C(this).find(I);var U=F.order=="rand"?""+Math.random():(F.attr==""?V.text():V.attr(F.attr));var S=C(this).parent();if(!P[S]){P[S]={s:[],n:[]}}if(V.length>0){P[S].s.push({s:U,e:C(this),n:T})}else{P[S].n.push({e:C(this),n:T})}});for(var H in P){var E=P[H];E.s.sort(function K(U,T){var S=U.s.toLowerCase?U.s.toLowerCase():U.s;var V=T.s.toLowerCase?T.s.toLowerCase():T.s;if(D(U.s)&&D(T.s)){S=parseFloat(U.s);V=parseFloat(T.s)}return(F.order=="asc"?1:-1)*(S<V?-1:(S>V?1:0))})}var M=[];for(var H in P){var E=P[H];var N=[];var G=C(this).length;switch(F.place){case"first":C.each(E.s,function(S,T){G=Math.min(G,T.n)});break;case"org":C.each(E.s,function(S,T){N.push(T.n)});break;case"end":G=E.n.length;break;default:G=0}var Q=[0,0];for(var L=0;L<C(this).length;L++){var O=L>=G&&L<G+E.s.length;if(A(N,L)){O=true}var R=(O?E.s:E.n)[Q[O?0:1]].e;R.parent().append(R);if(O||!F.returns){M.push(R.get(0))}Q[O?0:1]++}}return this.setArray(M)}});function D(E){return(parseFloat(E)+"")==E}function A(F,G){var E=false;C.each(F,function(I,H){if(!E){E=H==G}});return E}function B(E){if(window.console&&window.console.log){if(typeof (E)=="string"){window.console.log(E)}else{for(var F in E){window.console.log(F+": "+E[F])}}}}C.fn.TinySort=C.fn.Tinysort=C.fn.tsort=C.fn.tinysort})(jQuery);
@@ -0,0 +1,24 @@
1
+ <% if options[:filter] %>
2
+ <script type="text/javascript">
3
+ jQuery(document).ready(function(){
4
+ jQuery("div#<%= push_options[:id] %>-list").selectFilter();
5
+ });
6
+ </script>
7
+ <% end %>
8
+
9
+ <div name="index_filter" id="<%= push_options[:id] %>-list">
10
+ <%
11
+ items.each_with_index do |(data, attributes), index|
12
+ if attributes
13
+ div_attributes = attributes.map { |k, v| " \#{k}=\"\#{v}\"" }.join("")
14
+ end
15
+ %>
16
+ <div class="short_doc<%= " list_alt" if index % 2 == 0 %>"<%= div_attributes %>>
17
+ <% if data.respond_to?(:to_ary) %>
18
+ <% data = data.join("\n") %>
19
+ <% end %>
20
+ <%= data %>
21
+ </div>
22
+ <% end %>
23
+ </div>
24
+
@@ -0,0 +1,55 @@
1
+ body {font-family: arial, sans-serif; }
2
+ h1 {margin: 40px 0px 10px 0px; padding: 0px 0px 2px 0px; color: rgb(88,144,168); font-weight: bold; -size: 200%;}
3
+ h2 {width: 500px; margin: 40px 0px 10px 0px; padding: 0px 0px 2px 0px; border-bottom: solid 3px rgb(88,144,168); color: rgb(88,144,168); font-weight: bold; font-size: 160%;}
4
+ table {clear: left; margin: 0.5em 0px 0.2em 30px; border: solid 1px rgb(150,150,150); empty-cells: show; border-collapse: collapse; background-color: rgb(233,232,244);}
5
+ table tr {margin: 0px; padding: 0px;}
6
+ table td {padding: 2px 7px 2px 7px; border: solid 1px rgb(150,150,150); text-align: left; }
7
+ table th {margin: 0px; padding: 2px 7px 2px 7px; border: solid 1px rgb(150,150,150); empty-cells: show; text-align: left; }
8
+ table-caption {margin: 0.5em 0px 1.0em 30px; padding: 0px; clear: both; text-align: left; }
9
+
10
+ .button_bar {margin: 0px; padding: 0px; font-family: verdana, arial, sans serif; font-size: 1.0em;}
11
+ .button_bar span {margin-left: .1em; padding: 2px 5px 2px 5px; background-color: rgb(255,255,255); font-weight: normal; font-size: .9em; }
12
+ .button_bar span em {font-weight: bold; font-style: normal;}
13
+ .button_bar a {color: rgb(115,162,182); text-decoration: none; font-size: .9em; font-weight: normal;}
14
+ .button_bar a:hover {color: rgb(50,50,50); text-decoration: none;}
15
+
16
+ .body-header-list {margin: 0em 2em 1em 0em; padding: 0 0 0 0; background-color: rgb(238,237,249); font-size: 1.0em;}
17
+ .body-header-list ul {margin: 5px 0px 0px 0px; padding: 0px; border-bottom: solid 1px rgb(216,206,159); background-color: rgb(219,230,241);}
18
+ .body-header-list li {list-style: none; margin: 0px; padding: 0px;display: block; min-height: 1.7em; height: auto !important; height: 1.7em; line-height: 1.7em; margin: 0px; padding: 0px 7px 0px 10px; border-top: solid 1px rgb(200,200,200); border-left: solid 7px rgb(219,230,241); color: rgb(75,75,75); font-weight: normal; font-size: 100%; text-decoration: none;}
19
+ .body-header-list li.title {margin: 0px 0px 0px 0px; padding: 3px 5px 2px 15px; background-color: rgb(156,186,214); color: rgb(255,255,255); text-transform: uppercase; font-weight: bold;}
20
+
21
+ .body-header-list li table {clear: left; margin: 0em 0px 0em 25px; empty-cells: show; border-collapse: collapse; }
22
+ .body-header-list li table tr {margin: 0px; padding: 0px;}
23
+ .body-header-list li table td {margin: 0px; padding: 0px 7px 0px 7px; border: none; text-align: left;}
24
+ .body-header-list li table th {margin: 0px; padding: 0px; border: none; empty-cells: show; text-align: left; }
25
+
26
+ code {
27
+ padding:5px;
28
+ background:#e4e4ff;
29
+ color:#222;
30
+ border:2px solid #ddd;
31
+ margin-top: 1em;
32
+ margin-bottom: 1em;
33
+ margin-left: 0em;
34
+ margin-right: 0em;
35
+ font-family: monospace;
36
+ white-space: pre;
37
+ display: block;
38
+ }
39
+ /* Style for the main documentation block for a page */
40
+ .doc-main { font-size: 130% }
41
+ .doc-above { margin-bottom: -.3em; padding-bottom: 0em; font-style: italic; }
42
+ .doc-above p { margin-top: .1em; margin-bottom: .1em; }
43
+
44
+ div.short_doc {
45
+ margin-top: .2em;
46
+ background-color: rgb(238,237,249);
47
+ padding: .2em;
48
+ width: 100%;
49
+ }
50
+ div.short_doc td.short_doc {
51
+ font-style: italic;
52
+ }
53
+ div.list_alt {
54
+ background-color: rgb(230,228,249);
55
+ }
@@ -0,0 +1,283 @@
1
+ module MetaRuby::GUI
2
+ module HTML
3
+ RESSOURCES_DIR = File.expand_path(File.dirname(__FILE__))
4
+
5
+ # A class that can be used as the webpage container for the Page class
6
+ class HTMLPage
7
+ attr_accessor :html
8
+
9
+ def main_frame; self end
10
+ end
11
+
12
+ # A helper class that gives us easy-to-use page elements on a
13
+ # Qt::WebView
14
+ class Page < Qt::Object
15
+ attr_reader :fragments
16
+ attr_reader :view
17
+ attr_accessor :object_uris
18
+
19
+ class Fragment
20
+ attr_accessor :title
21
+ attr_accessor :html
22
+ attr_accessor :id
23
+ attr_reader :buttons
24
+
25
+ def initialize(title, html, view_options = Hash.new)
26
+ view_options = Kernel.validate_options view_options,
27
+ :id => nil, :buttons => []
28
+ @title = title
29
+ @html = html
30
+ @id = view_options[:id]
31
+ @buttons = view_options[:buttons]
32
+ end
33
+ end
34
+
35
+ def link_to(object, text = nil)
36
+ text = HTML.escape_html(text || object.name)
37
+ if uri = uri_for(object)
38
+ if uri[0, 1] != '/'
39
+ uri = "/#{uri}"
40
+ end
41
+ "<a href=\"link://metaruby#{uri}\">#{text}</a>"
42
+ else text
43
+ end
44
+ end
45
+
46
+ # Converts the given text from markdown to HTML and generates the
47
+ # necessary <div> context.
48
+ #
49
+ # @return [String] the HTML snippet that should be used to render
50
+ # the given text as main documentation
51
+ def self.main_doc(text)
52
+ "<div class=\"doc-main\">#{Kramdown::Document.new(text).to_html}</div>"
53
+ end
54
+
55
+ def main_doc(text)
56
+ self.class.main_doc(text)
57
+ end
58
+
59
+ PAGE_TEMPLATE = File.join(RESSOURCES_DIR, "page.rhtml")
60
+ PAGE_BODY_TEMPLATE = File.join(RESSOURCES_DIR, "page_body.rhtml")
61
+ LIST_TEMPLATE = File.join(RESSOURCES_DIR, "list.rhtml")
62
+ ASSETS = %w{page.css jquery.min.js jquery.selectfilter.js}
63
+
64
+ def self.copy_assets_to(target_dir, assets = ASSETS)
65
+ FileUtils.mkdir_p target_dir
66
+ assets.each do |file|
67
+ FileUtils.cp File.join(RESSOURCES_DIR, file), target_dir
68
+ end
69
+ end
70
+
71
+ def load_template(*path)
72
+ path = File.join(*path)
73
+ @templates[path] ||= ERB.new(File.read(path))
74
+ @templates[path].filename = path
75
+ @templates[path]
76
+ end
77
+
78
+ attr_reader :page
79
+
80
+ attr_accessor :page_name
81
+ attr_accessor :title
82
+
83
+ def initialize(page)
84
+ super()
85
+ @page = page
86
+ @fragments = []
87
+ @templates = Hash.new
88
+ @auto_id = 0
89
+
90
+ if page.kind_of?(Qt::WebPage)
91
+ page.link_delegation_policy = Qt::WebPage::DelegateAllLinks
92
+ Qt::Object.connect(page, SIGNAL('linkClicked(const QUrl&)'), self, SLOT('pageLinkClicked(const QUrl&)'))
93
+ end
94
+ @object_uris = Hash.new
95
+ end
96
+
97
+ def uri_for(object)
98
+ object_uris[object]
99
+ end
100
+
101
+ # Removes all existing displays
102
+ def clear
103
+ page.main_frame.html = ""
104
+ fragments.clear
105
+ end
106
+
107
+ def scale_attribute(node, name, scale)
108
+ node.attributes[name] = node.attributes[name].gsub /[\d\.]+/ do |n|
109
+ (Float(n) * scale).to_s
110
+ end
111
+ end
112
+
113
+ def update_html
114
+ page.main_frame.html = html
115
+ end
116
+
117
+ def html(options = Hash.new)
118
+ options = Kernel.validate_options options, :ressource_dir => RESSOURCES_DIR
119
+ ressource_dir = options[:ressource_dir]
120
+ load_template(PAGE_TEMPLATE).result(binding)
121
+ end
122
+
123
+ def html_body(options = Hash.new)
124
+ options = Kernel.validate_options options, :ressource_dir => RESSOURCES_DIR
125
+ ressource_dir = options[:ressource_dir]
126
+ load_template(PAGE_BODY_TEMPLATE).result(binding)
127
+ end
128
+
129
+ def find_button_by_url(url)
130
+ id = url.path
131
+ fragments.each do |fragment|
132
+ if result = fragment.buttons.find { |b| b.id == id }
133
+ return result
134
+ end
135
+ end
136
+ nil
137
+ end
138
+
139
+ def find_first_element(selector)
140
+ page.main_frame.find_first_element(selector)
141
+ end
142
+
143
+ def pageLinkClicked(url)
144
+ return if url.host != 'metaruby'
145
+
146
+ if url.scheme == 'btn'
147
+ if btn = find_button_by_url(url)
148
+ new_state = if url.fragment == 'on' then true
149
+ else false
150
+ end
151
+
152
+ btn.state = new_state
153
+ new_text = btn.text
154
+ element = find_first_element("a##{btn.html_id}")
155
+ element.replace(btn.render)
156
+
157
+ emit buttonClicked(btn.id, new_state)
158
+ else
159
+ MetaRuby.warn "invalid button URI #{url}: could not find corresponding handler"
160
+ end
161
+ elsif url.scheme == 'link'
162
+ emit linkClicked(url)
163
+ end
164
+ end
165
+ slots 'pageLinkClicked(const QUrl&)'
166
+ signals 'linkClicked(const QUrl&)', 'buttonClicked(const QString&,bool)'
167
+
168
+ # Save the current state of the page, so that it can be restored by
169
+ # calling {restore}
170
+ def save
171
+ @saved_state = fragments.map(&:dup)
172
+ end
173
+
174
+ # Restore the page at the state it was at the last call to {save}
175
+ def restore
176
+ return if !@saved_state
177
+
178
+ fragments_by_id = Hash.new
179
+ @saved_state.each do |fragment|
180
+ fragments_by_id[fragment.id] = fragment
181
+ end
182
+
183
+ # Delete all fragments that are not in the saved state
184
+ fragments.delete_if do |fragment|
185
+ element = find_first_element("div##{fragment.id}")
186
+ if old_fragment = fragments_by_id[fragment.id]
187
+ if old_fragment.html != fragment.html
188
+ element.replace(old_fragment.html)
189
+ end
190
+ else
191
+ element.replace("")
192
+ true
193
+ end
194
+ end
195
+ end
196
+
197
+ # Adds a fragment to this page, with the given title and HTML
198
+ # content
199
+ #
200
+ # The added fragment is enclosed in a div block to allow for dynamic
201
+ # replacement
202
+ #
203
+ # @option view_options [String] id the ID of the fragment. If given,
204
+ # and if an existing fragment with the same ID exists, the new
205
+ # fragment replaces the existing one, and the view is updated
206
+ # accordingly.
207
+ #
208
+ def push(title, html, view_options = Hash.new)
209
+ if id = view_options[:id]
210
+ # Check whether we should replace the existing content or
211
+ # push it new
212
+ fragment = fragments.find do |fragment|
213
+ fragment.id == id
214
+ end
215
+ if fragment
216
+ fragment.html = html
217
+ element = find_first_element("div##{fragment.id}")
218
+ element.replace("<div id=\"#{id}\">#{html}</div>")
219
+ return
220
+ end
221
+ end
222
+
223
+ fragments << Fragment.new(title, html, Hash[:id => auto_id].merge(view_options))
224
+ update_html
225
+ end
226
+
227
+ def auto_id
228
+ "metaruby-html-page-fragment-#{@auto_id += 1}"
229
+ end
230
+
231
+ # Create an item for the rendering in tables
232
+ def render_item(name, value = nil)
233
+ if value
234
+ "<li><b>#{name}</b>: #{value}</li>"
235
+ else
236
+ "<li>#{name}</li>"
237
+ end
238
+ end
239
+
240
+ # Render a list of objects into HTML and push it to this page
241
+ #
242
+ # @param [String,nil] title the section's title. If nil, no new
243
+ # section is created
244
+ # @param [Array<Object>,Array<(Object,Hash)>] items the list
245
+ # items, one item per line. If a hash is provided, it is used as
246
+ # HTML attributes for the lines
247
+ # @param [Hash] options
248
+ # @option options [Boolean] filter (false) if true, a filter is
249
+ # added at the top of the page. You must provide a :id option for
250
+ # the list for this to work
251
+ # @option (see #push)
252
+ def render_list(title, items, options = Hash.new)
253
+ options, push_options = Kernel.filter_options options, :filter => false, :id => nil
254
+ if options[:filter] && !options[:id]
255
+ raise ArgumentError, ":filter is true, but no :id has been given"
256
+ end
257
+ html = load_template(LIST_TEMPLATE).result(binding)
258
+ push(title, html, push_options.merge(:id => options[:id]))
259
+ end
260
+
261
+ signals 'updated()'
262
+
263
+ def self.to_html_page(object, renderer, options = Hash.new)
264
+ webpage = HTMLPage.new
265
+ page = new(webpage)
266
+ renderer.new(page).render(object, options)
267
+ page
268
+ end
269
+
270
+ # Renders an object to HTML using a given rendering class
271
+ def self.to_html(object, renderer, options = Hash.new)
272
+ html_options, options = Kernel.filter_options options, :ressource_dir => RESSOURCES_DIR
273
+ to_html_page(object, renderer, options).html(html_options)
274
+ end
275
+
276
+ def self.to_html_body(object, renderer, options = Hash.new)
277
+ html_options, options = Kernel.filter_options options, :ressource_dir => RESSOURCES_DIR
278
+ to_html_page(object, renderer, options).html_body(html_options)
279
+ end
280
+ end
281
+ end
282
+ end
283
+
@@ -0,0 +1,13 @@
1
+ <% prefix = if ressource_dir[0, 1] == "/" then "file://"
2
+ end
3
+ %>
4
+ <html>
5
+ <link rel="stylesheet" href="<%= prefix %><%= File.join(ressource_dir, 'page.css') %>" type="text/css" />
6
+ <script type="text/javascript" src="<%= prefix %><%= File.join(ressource_dir, 'jquery.min.js') %>"></script>
7
+ <script type="text/javascript" src="<%= prefix %><%= File.join(ressource_dir, 'jquery.selectfilter.js') %>"></script>
8
+ <title><%= page_name %></title>
9
+ </html>
10
+ <body>
11
+ <%= html_body(:ressource_dir => ressource_dir) %>
12
+ </body>
13
+
@@ -0,0 +1,17 @@
1
+ <% if title %>
2
+ <h1><%= title %></h1>
3
+ <% end %>
4
+ <% fragments.each do |fragment| %>
5
+ <% if fragment.title %>
6
+ <h2><%= fragment.title %></h2>
7
+ <% end %>
8
+ <%= HTML.render_button_bar(fragment.buttons) %>
9
+ <% if fragment.id %>
10
+ <div id="<%= fragment.id %>">
11
+ <% end %>
12
+ <%= fragment.html %>
13
+ <% if fragment.id %>
14
+ </div>
15
+ <% end %>
16
+ <% end %>
17
+