bowtie 0.1

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.
data/README ADDED
@@ -0,0 +1,20 @@
1
+ Bowtie for Sinatra.
2
+
3
+ Seems to work but need to do a lot of testing yet.
4
+
5
+ To try out, download and put in /lib in your app. Then in your config.ru do something like:
6
+
7
+ require 'app'
8
+ require 'bowtie'
9
+
10
+ app = Rack::Builder.new {
11
+ map "/admin" do
12
+ run Bowtie::Admin
13
+ end
14
+
15
+ map '/' do
16
+ run MyApp
17
+ end
18
+ }
19
+
20
+ run app
data/bowtie.gemspec ADDED
@@ -0,0 +1,41 @@
1
+
2
+ Gem::Specification.new do |s|
3
+ s.name = %q{bowtie}
4
+ s.version = "0.1"
5
+
6
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
7
+ s.authors = ["Tomás Pollak"]
8
+ s.date = %q{2010-02-14}
9
+ s.description = %q{Sinatra scaffold for DataMapper models.}
10
+ s.email = %q{tomas@usefork.com}
11
+ s.extra_rdoc_files = ["lib/bowtie.rb", "lib/bowtie/admin.rb", "lib/bowtie/core_extensions.rb", "lib/bowtie/helpers.rb"]
12
+ s.files = ["README", "bowtie.gemspec", "lib/bowtie.rb", "lib/bowtie/admin.rb", "lib/bowtie/core_extensions.rb", "lib/bowtie/helpers.rb", "lib/bowtie/views/errors.erb", "lib/bowtie/views/field.erb", "lib/bowtie/views/flash.erb", "lib/bowtie/views/form.erb", "lib/bowtie/views/index.erb", "lib/bowtie/views/layout.erb", "lib/bowtie/views/new.erb", "lib/bowtie/views/search.erb", "lib/bowtie/views/search.erb", "lib/bowtie/views/show.erb", "lib/bowtie/views/subtypes.erb", "lib/bowtie/views/table.erb", "lib/bowtie/views/row.erb", "lib/bowtie/public/css/bowtie.css", "lib/bowtie/public/js/bowtie.js", "lib/bowtie/public/js/jquery.tablesorter.pack.js", "lib/bowtie/public/js/jquery.jeditable.pack.js"]
13
+ s.homepage = %q{http://github.com/tomas/bowtie}
14
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Bowtie", "--main", "README"]
15
+ s.require_paths = ["lib"]
16
+ s.rubyforge_project = %q{bowtie}
17
+ s.rubygems_version = %q{1.3.5}
18
+ s.summary = %q{Bowtie Admin}
19
+
20
+ if s.respond_to? :specification_version then
21
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
22
+ s.specification_version = 3
23
+
24
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
25
+ s.add_runtime_dependency(%q<sinatra>, [">= 0.9.4"])
26
+ s.add_runtime_dependency(%q<dm-core>, [">= 0.10.2"])
27
+ s.add_runtime_dependency(%q<dm-aggregates>, [">= 0.10.2"])
28
+ s.add_runtime_dependency(%q<dm-pager>, [">= 1.0.1"])
29
+ else
30
+ s.add_dependency(%q<sinatra>, [">= 0.9.4"])
31
+ s.add_dependency(%q<dm-core>, [">= 0.10.2"])
32
+ s.add_dependency(%q<dm-aggregates>, [">= 0.10.2"])
33
+ s.add_dependency(%q<dm-pager>, [">= 1.0.1"])
34
+ end
35
+ else
36
+ s.add_dependency(%q<sinatra>, [">= 0.9.4"])
37
+ s.add_dependency(%q<dm-core>, [">= 0.10.2"])
38
+ s.add_dependency(%q<dm-aggregates>, [">= 0.10.2"])
39
+ s.add_dependency(%q<dm-pager>, [">= 1.0.1"])
40
+ end
41
+ end
data/lib/bowtie.rb ADDED
@@ -0,0 +1,10 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ %w(sinatra dm-core dm-aggregates dm-pager bowtie/helpers bowtie/core_extensions bowtie/admin).each {|lib| require lib}
5
+
6
+ begin
7
+ repository(:default).adapter
8
+ rescue DataMapper::RepositoryNotSetupError
9
+ puts ' ** You need to set up your DataMapper adapter for Bowtie to work. **'
10
+ end
@@ -0,0 +1,113 @@
1
+ module Bowtie
2
+
3
+ class Admin < Sinatra::Base
4
+
5
+ PER_PAGE = 25
6
+
7
+ # TODO: make this easily modifiable
8
+ use Rack::Auth::Basic do |username, password|
9
+ username == 'admin' && password == 'bowtie'
10
+ end
11
+
12
+ use Rack::MethodOverride
13
+
14
+ set :views, File.dirname(__FILE__) + '/views'
15
+
16
+ helpers do
17
+ include Helpers
18
+ end
19
+
20
+ before do
21
+ @app_name = ENV['APP_NAME'] ? [self.class.name, ENV['APP_NAME']].join(' > ') : self.class.name
22
+ @models = DataMapper::Model.descendants.to_a
23
+ end
24
+
25
+ get '/*.js|css|png|jpg' do
26
+ deliver_file or status 404
27
+ end
28
+
29
+ get '/' do
30
+ redirect ''
31
+ end
32
+
33
+ get '' do
34
+ redirect '/' + @models.first.pluralize
35
+ end
36
+
37
+ get '/search*' do
38
+ redirect('/' + params[:model] ||= '') if params[:q].blank?
39
+ query1, query2 = [], []
40
+ clean_params.each do |key, val|
41
+ query1 << "#{model}.all(:#{key} => '#{val}')"
42
+ end
43
+ model.searchable_fields.each do |field|
44
+ query2 << "#{model}.all(:#{field}.like => '%#{params[:q]}%')"
45
+ end
46
+ query = query1.any? ? [query1.join(' & '), query2.join(' + ')].join(' & ') : query2.join(' + ')
47
+ @resources = eval(query).page(params[:page], :per_page => PER_PAGE)
48
+ @subtypes = model.subtypes
49
+ erb :index
50
+ end
51
+
52
+ get "/:model" do
53
+ @resources = model.all(clean_params).page(params[:page], :per_page => PER_PAGE)
54
+ @subtypes = model.subtypes
55
+ erb :index
56
+ end
57
+
58
+ get "/:model/new" do
59
+ @resource = model.new
60
+ erb :new
61
+ end
62
+
63
+ post "/:model" do
64
+ @resource = model.create(params[:resource].normalize)
65
+ if @resource.valid? and @resource.save
66
+ redirect "/#{model.pluralize}?notice=created"
67
+ else
68
+ erb :new
69
+ end
70
+ end
71
+
72
+ get "/:model/:id" do
73
+ @resource = resource
74
+ erb :show
75
+ end
76
+
77
+ get "/:model/:id/:association" do
78
+ @title = "#{params[:association].titleize} for #{model.to_s.titleize} ##{params[:id]}"
79
+ res = model.get(params[:id]).send(params[:association])
80
+ if res.respond_to?(:page)
81
+ @resources = res.page(params[:page], :per_page => PER_PAGE)
82
+ erb :index
83
+ else
84
+ redirect('/' + model.to_s + '?error=doesnt+exist') unless res
85
+ @resource = res
86
+ erb :show
87
+ end
88
+ end
89
+
90
+ put "/:model/:id" do
91
+ puts params[:resource].inspect
92
+ if resource.update(params[:resource].normalize)
93
+ request.xhr? ? resource.to_json : redirect("/#{model.pluralize}/#{params[:id]}?notice=saved")
94
+ else
95
+ if request.xhr?
96
+ false
97
+ else
98
+ @resource = resource
99
+ erb :show
100
+ end
101
+ end
102
+ end
103
+
104
+ delete "/:model/:id" do
105
+ if resource.destroy
106
+ redirect "/#{model.pluralize}?notice=destroyed"
107
+ else
108
+ redirect "/#{model.pluralize}/#{params[:id]}?error=not+destroyed"
109
+ end
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,50 @@
1
+ class String
2
+
3
+ def titleize
4
+ self.capitalize.gsub('_',' ')
5
+ end
6
+
7
+ def singularize
8
+ self.gsub(/ies/,'y').gsub(/s$/, '')
9
+ end
10
+
11
+ def pluralize
12
+ self.gsub(/y$/,'ie') + "s"
13
+ end
14
+
15
+ end
16
+
17
+ class Class
18
+
19
+ def pluralize
20
+ self.to_s.pluralize
21
+ end
22
+
23
+ def searchable_fields
24
+ self.properties.map{|a| a.name if a.type == String}.compact
25
+ end
26
+
27
+ def subtypes
28
+ self.validators.first.last.map{|a,b| b = {a.field_name => a.options[:set]} if a.class == DataMapper::Validate::WithinValidator}.compact
29
+ end
30
+
31
+ def options_for_subtype(field)
32
+ self.validators.first.last.map{|a| a.options[:set] if a.class == DataMapper::Validate::WithinValidator && a.field_name == field}.compact.reduce
33
+ end
34
+
35
+ def relation_keys_include?(property)
36
+ self.relationships.map {|rel| true if property.to_sym == rel[1].child_key.first.name}.reduce
37
+ end
38
+
39
+ end
40
+
41
+ class Hash
42
+
43
+ # this is for checkboxes which give us a param of 'on' on the params hash
44
+ def normalize
45
+ normalized = {}
46
+ self.each_pair {|k,v| normalized[k] = v == 'on' ? true : v }
47
+ normalized
48
+ end
49
+
50
+ end
@@ -0,0 +1,60 @@
1
+ module Bowtie
2
+
3
+ module Helpers
4
+
5
+ def deliver_file
6
+ file = File.expand_path(File.dirname(__FILE__)) + "/public/#{@env['PATH_INFO']}"
7
+ return false unless File.exist?(file)
8
+ content_type(Rack::Mime::MIME_TYPES[File.extname(file)], :charset => 'utf-8')
9
+ File.read(file)
10
+ end
11
+
12
+ def base_path
13
+ env['SCRIPT_NAME']
14
+ end
15
+
16
+ # Sinatra's redirect is not adding path prefix. Seems like a bug to me.
17
+ def redirect(uri, *args)
18
+ super base_path + uri.downcase, *args
19
+ end
20
+
21
+ def partial(name, *args)
22
+ erb(name, :layout => false, *args)
23
+ end
24
+
25
+ def get_model_class
26
+ begin
27
+ Kernel.const_get(params[:model].singularize.capitalize)
28
+ rescue NameError
29
+ halt 404, "Model not found!"
30
+ end
31
+ end
32
+
33
+ def clean_params
34
+ @env['rack.request.query_hash'].delete_if{|a,b| %w(model page notice error q).include?(a) }
35
+ end
36
+
37
+ def model
38
+ @model ||= get_model_class
39
+ end
40
+
41
+ def resource
42
+ @resource ||= model.get(params[:id]) or halt(404, 'Resource not found!')
43
+ end
44
+
45
+ def current_model
46
+ model
47
+ end
48
+
49
+ def model_path(m = current_model)
50
+ string = m.name ||= m
51
+ base_path + '/' + string.to_s.pluralize.downcase
52
+ end
53
+
54
+ def url_for(object)
55
+ model_path(object.class) + '/' + object.id.to_s
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -0,0 +1,277 @@
1
+ /*
2
+ CSS for Bowtie
3
+ By Tomas Pollak - Fork Limited
4
+ http://usefork.com
5
+ ----------------------------------------- */
6
+
7
+ *{
8
+ margin: 0;
9
+ padding: 0;
10
+ }
11
+
12
+ body{
13
+ font-size: 14px;
14
+ font-family: Corbel, Calibri, Helvetica, Arial, sans-serif;
15
+ background: #efefef;
16
+ }
17
+
18
+
19
+ a { color:#111; }
20
+ .pager a{ color: #528e00; }
21
+
22
+ p{
23
+ font-size: 1.2em;
24
+ margin: 1em 0;
25
+ }
26
+
27
+ hr { border:0; border-top:5px solid #efefef; margin:15px 0;}
28
+
29
+ /* flash
30
+ -------------------------------------------------------------*/
31
+
32
+ #flash{
33
+ text-align: center;
34
+ margin: 0;
35
+ padding: 5px;
36
+ color: white;
37
+ }
38
+
39
+ #flash.notice{
40
+ background: #ff9900;
41
+ }
42
+
43
+ #flash.error{
44
+ background: #a00;
45
+ }
46
+
47
+ /* headings
48
+ -------------------------------------------------------------*/
49
+
50
+ span.hl { background:#efefef; padding:2px;}
51
+ h1 { margin:10px 0; font-size:190%; font-weight:bold; color:#528e00;}
52
+ h2 { margin:10px 0; font-size:130%;}
53
+
54
+ /* header, navigation
55
+ -------------------------------------------------------------*/
56
+
57
+ #header { background:#000; padding: 8px 5% 0 5%; border-bottom:1px solid #444;border-bottom:5px solid #528e00;}
58
+ #header h1 { color:#333; font-size: 3em; font-weight:bold; margin: 10px 0;}
59
+ #header h1 a{ color: #fff; text-decoration: none}
60
+ #header ul li { display:inline;}
61
+ #header ul li a { color:#fff; text-decoration:none; margin-right:10px; display:inline-block; padding:8px; -webkit-border-top-right-radius:6px; -webkit-border-top-left-radius:6px; }
62
+ #header ul li a:hover { background:#333;}
63
+ #header ul li.current a { background: #528e00; font-weight:bold; color:#fff;}
64
+
65
+ .subnav { padding: 2px 50px 7px 50px; background:#528e00; font-size:90%; margin: -20px -50px 20px; }
66
+ .subnav li { display:inline;}
67
+ .subnav li a { color:#fff; text-decoration:none; margin-right:10px; display:inline-block; background:#89bf41; padding:5px; -webkit-border-radius:3px; -moz-border-radius:3px;}
68
+ .subnav li.current a { background:#fff; font-weight:bold; color:#528e00;}
69
+ .subnav li a:active { background:#8def08;}
70
+
71
+ /* container
72
+ -------------------------------------------------------------*/
73
+
74
+ #container h1{
75
+ margin-bottom: 30px;
76
+ }
77
+
78
+ #container{
79
+ font-size: 1.3em;
80
+ background: #fff;
81
+ padding: 20px 50px 50px;
82
+ position: relative;
83
+ }
84
+
85
+ #search{
86
+ float: right;
87
+ margin-top: 10px;
88
+ }
89
+ #search input{
90
+ width: 250px;
91
+ padding: 4px;
92
+ font-size: 1em;
93
+ color: #666;
94
+ -moz-border-radius: 7px;
95
+ -webkit-border-radius: 7px;
96
+ }
97
+
98
+ .edit-button{
99
+ float: right;
100
+ margin: 15px 15px 0 0;
101
+ }
102
+ .edit-button.active{
103
+ color: green;
104
+ }
105
+
106
+
107
+ /* tablas
108
+ -------------------------------------------------------------*/
109
+
110
+ table{
111
+ width: 100%;
112
+ margin: 0 auto;
113
+ border-collapse:collapse;
114
+ text-align: left;
115
+ }
116
+
117
+ table tr:hover{
118
+ background: #efefef;
119
+ }
120
+
121
+ table tr td, table tr th {
122
+ border:1px solid #ccc;
123
+ padding:6px;
124
+ }
125
+
126
+ table th{
127
+ padding: 4px 5px;
128
+ font-size: 1.1em;
129
+ color: #888;
130
+ text-align: left;
131
+ background:#efefef;
132
+ font-size:80%;
133
+ font-weight:bold;
134
+ }
135
+
136
+ table td{
137
+ padding: 0px; margin:0px;
138
+ border-bottom: 1px solid #ddd;
139
+ padding: 6px 5px;
140
+ color: #666;
141
+
142
+ }
143
+
144
+ table tr td.no-data { text-align:center; padding:40px 0; color:#999; font-style:italic; font-size:130%;}
145
+
146
+
147
+ table .center{
148
+ text-align: center;
149
+ }
150
+ table .last{
151
+ text-align: right;
152
+ }
153
+
154
+ table .check-column{
155
+ text-align: center;
156
+ }
157
+
158
+ table .good{
159
+ color: green;
160
+ }
161
+
162
+ table .bad, table .error{
163
+ color: #a00;
164
+ }
165
+
166
+ table td.rel, th.rel {
167
+ background: #fafafa;
168
+ }
169
+
170
+ table .icon{
171
+ position: relative;
172
+ top: 3px;
173
+ margin-right: 2px;
174
+ margin-top: -3px;
175
+ }
176
+
177
+ /* forms
178
+ -------------------------------------------------------------*/
179
+
180
+ input:focus{
181
+ color: #333;
182
+ }
183
+
184
+ form.destroy button{
185
+ font-size: 1em;
186
+ color: #666;
187
+ padding: 2px 5px;
188
+ margin-bottom: 20px;
189
+ color: #a00;
190
+ }
191
+
192
+ form.resource small{
193
+ color: #ccc;
194
+ }
195
+ form.resource input,
196
+ form.resource select{
197
+ font-size: .9em;
198
+ color: #666;
199
+ padding: 2px 5px;
200
+ }
201
+
202
+ form.resource input[type=text]{
203
+ -moz-border-radius: 3px;
204
+ -webkit-border-radius: 3px;
205
+ border: 1px solid #999;
206
+ width: 300px;
207
+ }
208
+
209
+ form.resource input:focus[type=text]{
210
+ border-color: #333;
211
+ }
212
+
213
+ form .left-col{
214
+ width: 30%;
215
+ }
216
+
217
+ form .submit input{
218
+ /* color: green;*/
219
+ }
220
+
221
+ /* errors
222
+ --------------------------------------------------------------*/
223
+
224
+ .errorlist {
225
+ color: #a00;
226
+ margin: 0 0 20px 20px;
227
+ }
228
+
229
+
230
+ /* pagination
231
+ --------------------------------------------------------------*/
232
+
233
+ .pager{
234
+ margin: 30px 0;
235
+ text-align: center;
236
+ }
237
+ .pager li{
238
+ display: inline;
239
+ }
240
+ .pager .disabled{
241
+ display: none;
242
+ }
243
+ .pager .current{
244
+ color: #666;
245
+ margin: 0 3px;
246
+ }
247
+ .pager a{
248
+ border: 1px solid;
249
+ padding: 3px 5px;
250
+ margin: 0 1px;
251
+ border-radius: 2px;
252
+ -moz-border-radius: 2px;
253
+ -webkit-border-radius: 2px;
254
+ -khtml-border-radius: 2px;
255
+ }
256
+ .pager a:hover{
257
+ color: #000;
258
+ }
259
+
260
+
261
+ /* footer
262
+ -------------------------------------------------------------*/
263
+
264
+ #footer {
265
+ text-align: center;
266
+ padding:10px 5%;
267
+ background:#efefef;
268
+ color:#999;
269
+ font-size:85%;
270
+ line-height:1.5;
271
+ border-top:5px
272
+ solid #ccc;
273
+ padding-top:10px;
274
+ }
275
+ #footer p a {
276
+ color:#999;
277
+ }
@@ -0,0 +1,64 @@
1
+ var Bowtie = {
2
+
3
+ ///////////////////////////////////////////////////
4
+ // custom stuff for in-place editing
5
+ ///////////////////////////////////////////////////
6
+
7
+ toggleEditableMode: function(a){
8
+
9
+ if ($(a).hasClass('active')){
10
+ $('table td.editable').data('disabled.editable', true);
11
+ html = 'Edit Mode OFF';
12
+ } else {
13
+ if ($('table td.editable').data('disabled.editable')){
14
+ $('table td.editable').data('disabled.editable', false);
15
+ } else {
16
+ this.activateEditables();
17
+ }
18
+ html = 'Edit Mode ON';
19
+ }
20
+
21
+ $(a).toggleClass('active').html(html);
22
+
23
+ },
24
+
25
+ activateEditables: function(){
26
+
27
+ var current_path = location.href.split('#')[0];
28
+
29
+ $('table td.editable').editable(function(value, settings){
30
+
31
+ var self = this;
32
+ var original = $(this).html();
33
+ var id = $(this).siblings('.id-col').children('a').html();
34
+ var field = "resource[" + $(this).attr('class').split('-')[0] + "]";
35
+ var submitdata = { '_method' : 'put' };
36
+ submitdata[field] = value;
37
+
38
+ $.post(current_path + '/' + id, submitdata, function(response){
39
+ if(response) {
40
+ $(self).removeClass('error').html(value);
41
+ } else {
42
+ $(self).addClass('error').html(self.revert)
43
+ }
44
+ // callback.apply(self, [self.innerHTML, settings]);
45
+ self.editing = false;
46
+ });
47
+ return false;
48
+ }, {
49
+ event : "dblclick",
50
+ indicator : 'Saving...',
51
+ placeholder : "<em>(edit)</em>",
52
+ });
53
+
54
+ }
55
+
56
+ }
57
+
58
+ $(document).ready(function() {
59
+
60
+ $("table.sortable").tablesorter({
61
+ headers: { 0: { sorter: false } }
62
+ });
63
+
64
+ });
@@ -0,0 +1,38 @@
1
+
2
+ (function($){$.fn.editable=function(target,options){if('disable'==target){$(this).data('disabled.editable',true);return;}
3
+ if('enable'==target){$(this).data('disabled.editable',false);return;}
4
+ if('destroy'==target){$(this).unbind($(this).data('event.editable')).removeData('disabled.editable').removeData('event.editable');return;}
5
+ var settings=$.extend({},$.fn.editable.defaults,{target:target},options);var plugin=$.editable.types[settings.type].plugin||function(){};var submit=$.editable.types[settings.type].submit||function(){};var buttons=$.editable.types[settings.type].buttons||$.editable.types['defaults'].buttons;var content=$.editable.types[settings.type].content||$.editable.types['defaults'].content;var element=$.editable.types[settings.type].element||$.editable.types['defaults'].element;var reset=$.editable.types[settings.type].reset||$.editable.types['defaults'].reset;var callback=settings.callback||function(){};var onedit=settings.onedit||function(){};var onsubmit=settings.onsubmit||function(){};var onreset=settings.onreset||function(){};var onerror=settings.onerror||reset;if(settings.tooltip){$(this).attr('title',settings.tooltip);}
6
+ settings.autowidth='auto'==settings.width;settings.autoheight='auto'==settings.height;return this.each(function(){var self=this;var savedwidth=$(self).width();var savedheight=$(self).height();$(this).data('event.editable',settings.event);if(!$.trim($(this).html())){$(this).html(settings.placeholder);}
7
+ $(this).bind(settings.event,function(e){if(true===$(this).data('disabled.editable')){return;}
8
+ if(self.editing){return;}
9
+ if(false===onedit.apply(this,[settings,self])){return;}
10
+ e.preventDefault();e.stopPropagation();if(settings.tooltip){$(self).removeAttr('title');}
11
+ if(0==$(self).width()){settings.width=savedwidth;settings.height=savedheight;}else{if(settings.width!='none'){settings.width=settings.autowidth?$(self).width():settings.width;}
12
+ if(settings.height!='none'){settings.height=settings.autoheight?$(self).height():settings.height;}}
13
+ if($(this).html().toLowerCase().replace(/(;|")/g,'')==settings.placeholder.toLowerCase().replace(/(;|")/g,'')){$(this).html('');}
14
+ self.editing=true;self.revert=$(self).html();$(self).html('');var form=$('<form />');if(settings.cssclass){if('inherit'==settings.cssclass){form.attr('class',$(self).attr('class'));}else{form.attr('class',settings.cssclass);}}
15
+ if(settings.style){if('inherit'==settings.style){form.attr('style',$(self).attr('style'));form.css('display',$(self).css('display'));}else{form.attr('style',settings.style);}}
16
+ var input=element.apply(form,[settings,self]);var input_content;if(settings.loadurl){var t=setTimeout(function(){input.disabled=true;content.apply(form,[settings.loadtext,settings,self]);},100);var loaddata={};loaddata[settings.id]=self.id;if($.isFunction(settings.loaddata)){$.extend(loaddata,settings.loaddata.apply(self,[self.revert,settings]));}else{$.extend(loaddata,settings.loaddata);}
17
+ $.ajax({type:settings.loadtype,url:settings.loadurl,data:loaddata,async:false,success:function(result){window.clearTimeout(t);input_content=result;input.disabled=false;}});}else if(settings.data){input_content=settings.data;if($.isFunction(settings.data)){input_content=settings.data.apply(self,[self.revert,settings]);}}else{input_content=self.revert;}
18
+ content.apply(form,[input_content,settings,self]);input.attr('name',settings.name);buttons.apply(form,[settings,self]);$(self).append(form);plugin.apply(form,[settings,self]);$(':input:visible:enabled:first',form).focus();if(settings.select){input.select();}
19
+ input.keydown(function(e){if(e.keyCode==27){e.preventDefault();reset.apply(form,[settings,self]);}});var t;if('cancel'==settings.onblur){input.blur(function(e){t=setTimeout(function(){reset.apply(form,[settings,self]);},500);});}else if('submit'==settings.onblur){input.blur(function(e){t=setTimeout(function(){form.submit();},200);});}else if($.isFunction(settings.onblur)){input.blur(function(e){settings.onblur.apply(self,[input.val(),settings]);});}else{input.blur(function(e){});}
20
+ form.submit(function(e){if(t){clearTimeout(t);}
21
+ e.preventDefault();if(false!==onsubmit.apply(form,[settings,self])){if(false!==submit.apply(form,[settings,self])){if($.isFunction(settings.target)){var str=settings.target.apply(self,[input.val(),settings]);$(self).html(str);self.editing=false;callback.apply(self,[self.innerHTML,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}}else{var submitdata={};submitdata[settings.name]=input.val();submitdata[settings.id]=self.id;if($.isFunction(settings.submitdata)){$.extend(submitdata,settings.submitdata.apply(self,[self.revert,settings]));}else{$.extend(submitdata,settings.submitdata);}
22
+ if('PUT'==settings.method){submitdata['_method']='put';}
23
+ $(self).html(settings.indicator);var ajaxoptions={type:'POST',data:submitdata,dataType:'html',url:settings.target,success:function(result,status){if(ajaxoptions.dataType=='html'){$(self).html(result);}
24
+ self.editing=false;callback.apply(self,[result,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}},error:function(xhr,status,error){onerror.apply(form,[settings,self,xhr]);}};$.extend(ajaxoptions,settings.ajaxoptions);$.ajax(ajaxoptions);}}}
25
+ $(self).attr('title',settings.tooltip);return false;});});this.reset=function(form){if(this.editing){if(false!==onreset.apply(form,[settings,self])){$(self).html(self.revert);self.editing=false;if(!$.trim($(self).html())){$(self).html(settings.placeholder);}
26
+ if(settings.tooltip){$(self).attr('title',settings.tooltip);}}}};});};$.editable={types:{defaults:{element:function(settings,original){var input=$('<input type="hidden"></input>');$(this).append(input);return(input);},content:function(string,settings,original){$(':input:first',this).val(string);},reset:function(settings,original){original.reset(this);},buttons:function(settings,original){var form=this;if(settings.submit){if(settings.submit.match(/>$/)){var submit=$(settings.submit).click(function(){if(submit.attr("type")!="submit"){form.submit();}});}else{var submit=$('<button type="submit" />');submit.html(settings.submit);}
27
+ $(this).append(submit);}
28
+ if(settings.cancel){if(settings.cancel.match(/>$/)){var cancel=$(settings.cancel);}else{var cancel=$('<button type="cancel" />');cancel.html(settings.cancel);}
29
+ $(this).append(cancel);$(cancel).click(function(event){if($.isFunction($.editable.types[settings.type].reset)){var reset=$.editable.types[settings.type].reset;}else{var reset=$.editable.types['defaults'].reset;}
30
+ reset.apply(form,[settings,original]);return false;});}}},text:{element:function(settings,original){var input=$('<input />');if(settings.width!='none'){input.width(settings.width);}
31
+ if(settings.height!='none'){input.height(settings.height);}
32
+ input.attr('autocomplete','off');$(this).append(input);return(input);}},textarea:{element:function(settings,original){var textarea=$('<textarea />');if(settings.rows){textarea.attr('rows',settings.rows);}else if(settings.height!="none"){textarea.height(settings.height);}
33
+ if(settings.cols){textarea.attr('cols',settings.cols);}else if(settings.width!="none"){textarea.width(settings.width);}
34
+ $(this).append(textarea);return(textarea);}},select:{element:function(settings,original){var select=$('<select />');$(this).append(select);return(select);},content:function(data,settings,original){if(String==data.constructor){eval('var json = '+data);}else{var json=data;}
35
+ for(var key in json){if(!json.hasOwnProperty(key)){continue;}
36
+ if('selected'==key){continue;}
37
+ var option=$('<option />').val(key).append(json[key]);$('select',this).append(option);}
38
+ $('select',this).children().each(function(){if($(this).val()==json['selected']||$(this).text()==$.trim(original.revert)){$(this).attr('selected','selected');}});}}},addInputType:function(name,input){$.editable.types[name]=input;}};$.fn.editable.defaults={name:'value',id:'id',type:'text',width:'auto',height:'auto',event:'click.editable',onblur:'cancel',loadtype:'GET',loadtext:'Loading...',placeholder:'Click to edit',loaddata:{},submitdata:{},ajaxoptions:{}};})(jQuery);
@@ -0,0 +1,2 @@
1
+
2
+ (function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,cells[i]);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,node){var l=parsers.length;for(var i=1;i<l;i++){if(parsers[i].is($.trim(getElementText(table.config,node)),table,node)){return parsers[i];}}return parsers[0];}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=table.tBodies[0].rows[i],cols=[];cache.row.push($(c));for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));}cols.push(i);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){if(!node)return"";var t="";if(config.textExtraction=="simple"){if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){t=node.childNodes[0].innerHTML;}else{t=node.innerHTML;}}else{if(typeof(config.textExtraction)=="function"){t=config.textExtraction(node);}else{t=$(node).text();}}return t;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){rows.push(r[n[i][checkCell]]);if(!table.config.appender){var o=r[n[i][checkCell]];var l=o.length;for(var j=0;j<l;j++){tableBody[0].appendChild(o[j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false,tableHeadersRows=[];for(var i=0;i<table.tHead.rows.length;i++){tableHeadersRows[i]=0;};$tableHeaders=$("thead th",table);$tableHeaders.each(function(index){this.count=0;this.column=index;this.order=formatSortingOrder(table.config.sortInitialOrder);if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(!this.sortDisabled){$(this).addClass(table.config.cssHeader);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){i=(v.toLowerCase()=="desc")?1:0;}else{i=(v==(0||1))?v:0;}return i;}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(getCachedSortType(table.config.parsers,c)=="text")?((order==0)?"sortText":"sortTextDesc"):((order==0)?"sortNumeric":"sortNumericDesc");var e="e"+i;dynamicExp+="var "+e+" = "+s+"(a["+c+"],b["+c+"]); ";dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function sortText(a,b){return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){var DECIMAL='\\'+config.decimal;var exp='/(^[+]?0('+DECIMAL+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)'+DECIMAL+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*'+DECIMAL+'0+$)/';return RegExp(exp).test($.trim(s));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}$("tr:visible",table.tBodies[0]).filter(':even').removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0]).end().filter(':odd').removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
@@ -0,0 +1,13 @@
1
+ <% if @resource and @resource.errors.any? %>
2
+
3
+ <div class="errorlist">
4
+
5
+ <ul>
6
+ <% @resource.errors.each do |message| %>
7
+ <li><%= message %></li>
8
+ <% end %>
9
+ </ul>
10
+
11
+ </div>
12
+
13
+ <% end %>
@@ -0,0 +1,23 @@
1
+ <%=
2
+
3
+ html =''
4
+ name = @p.name.to_s
5
+ value = @resource.send(@p.name).to_s
6
+
7
+ case @p.type.to_s
8
+ when "Array", /Class/ # weird how datamapper names enum classes
9
+ html += '<select class="array" name="resource['+name+']">'
10
+ @resource.model.options_for_subtype(name.to_sym).each do |option|
11
+ selected = value.to_s == option.to_s ? 'selected="selected"' : ''
12
+ html += '<option value="'+option.to_s+'" '+selected+'>'+option.to_s.titleize+'</option>'
13
+ end
14
+ html += '</select>'
15
+ when "TrueClass", "FalseClass", /Boolean/
16
+ checked = (value == 'n' || value.blank?) ? '' : 'checked="checked"'
17
+ html += '<input name="resource['+name+']" type="checkbox" '+checked+' />'
18
+ else
19
+ html += '<input class="string" type="text" name="resource['+name+']" value="'+value+'" />'
20
+ end
21
+ html
22
+
23
+ %>
@@ -0,0 +1,11 @@
1
+ <% if params[:notice] %>
2
+
3
+ <p id="flash" class="notice">Resource <%= params[:notice] %>.</p>
4
+
5
+ <% end %>
6
+
7
+ <% if params[:error] %>
8
+
9
+ <p id="flash" class="error">Resource <%= params[:error] %>.</p>
10
+
11
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <form class="resource" method="post" action="<%= model_path(@resource.model) %><%= '/' + @resource.id.to_s if @resource.id %>">
2
+ <%= '<input type="hidden" name="_method" value="put">' if @resource.id %>
3
+
4
+ <%= partial(:errors) %>
5
+
6
+ <table>
7
+ <% @resource.model.properties.each do |p| %>
8
+ <% unless [:created_at, :id].include?(p.name) %>
9
+ <% @p = p %>
10
+ <tr>
11
+ <td class="left-col"><%= p.name.to_s.titleize %> <small>(<%= p.type.to_s %>)</small></td>
12
+ <td class="right-col"><%= partial(:field) %></td>
13
+ </tr>
14
+ <% end %>
15
+ <% end %>
16
+ </table>
17
+
18
+ <p class="submit">
19
+ <input type="submit" value="Submit" />
20
+ </p>
21
+
22
+ </form>
@@ -0,0 +1,20 @@
1
+ <%= partial(:subtypes) if !params[:association] and @subtypes.any? %>
2
+
3
+ <%= partial(:search) %>
4
+ <a class="edit-button" href="#" title="Enables in-place editing of editable fields" onclick="Bowtie.toggleEditableMode(this); return false;">Edit Mode OFF</a>
5
+
6
+ <h1><%= @resources.pager.total %> <%= @title || @model.name.pluralize %> <a href="<%= model_path %>/new">(new)</a></h1>
7
+
8
+ <% if @resources.any? %>
9
+
10
+ <%= @resources.pager.to_html(@env['REQUEST_URI'].gsub(/\?.*/,'')) if @resources.respond_to?(:pager) %>
11
+
12
+ <%= partial(:table) %>
13
+
14
+ <%= @resources.pager.to_html(@env['REQUEST_URI'].gsub(/\?.*/,'')) if @resources.respond_to?(:pager) %>
15
+
16
+ <% else %>
17
+
18
+ <h2>No records found.</h2>
19
+
20
+ <% end %>
@@ -0,0 +1,42 @@
1
+ <!DOCTYPE html>
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+ <head profile="http://gmpg.org/xfn/11">
4
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
5
+ <title><%= @app_name %></title>
6
+ <link rel="stylesheet" href="<%= base_path %>/css/bowtie.css" type="text/css" media="screen" charset="utf-8" />
7
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
8
+ <script type="text/javascript" src="<%= base_path %>/js/jquery.jeditable.pack.js"></script>
9
+ <script type="text/javascript" src="<%= base_path %>/js/jquery.tablesorter.pack.js"></script>
10
+ <script type="text/javascript" src="<%= base_path %>/js/bowtie.js">
11
+
12
+ </script>
13
+ </head>
14
+
15
+ <body>
16
+
17
+ <%= partial(:flash) %>
18
+
19
+ <div id="header">
20
+
21
+ <h1>
22
+ <a href="<%= base_path %>"><%= @app_name %></a>
23
+ </h1>
24
+
25
+ <ul class="nav">
26
+ <% @models.each do |m| %>
27
+ <li class="<%= 'current' if @model && @model == m %>"><a href="<%= model_path(m) %>"><%= m.pluralize %></a></li>
28
+ <% end %>
29
+ </ul>
30
+
31
+ </div><!-- /header -->
32
+
33
+ <div id="container">
34
+ <%= yield %>
35
+ </div><!-- /container -->
36
+
37
+ <div id="footer">
38
+ <p>(c) <a href="http://usefork.com">Fork Limited</a></p>
39
+ </div><!-- /footer -->
40
+
41
+ </body>
42
+ </html>
@@ -0,0 +1,3 @@
1
+ <h1>New <%= @model.name.downcase %></h1>
2
+
3
+ <%= partial(:form) %>
@@ -0,0 +1,25 @@
1
+ <tr id="resource-<%= @r.key.first.to_s %>" class="<%= @r.ok? ? 'good' : 'bad' if @r.respond_to? 'ok?' %>">
2
+ <td class="<%= @model.key.first.name.to_s %>-col"><a href="<%= url_for(@r) %>"><%= @r.key.first.to_s %></a></td>
3
+ <% @r.attributes.each do |a| %>
4
+ <% next if a[0] == @model.key.first.name %>
5
+ <td class="<%= a[0] %>-col editable"><%= a[1] || 'nil' %></td>
6
+ <% end %>
7
+ <% unless params[:association] %>
8
+ <% @model.relationships.each do |rel| %>
9
+ <% unless rel[1].class.name =~ /ManyTo/ %>
10
+ <td class="rel <%= rel[0].to_s %>-col">
11
+ <a href="<%= model_path %>/<%= @r.id %>/<%= rel[0].to_s %>">
12
+ <%= rel[1].class.name =~ /OneToOne/ ? "View" : @r.send(rel[0]).count %>
13
+ </a>
14
+ </td>
15
+ <% end %>
16
+ <% end %>
17
+ <% end %>
18
+ <td><a href="<%= url_for(@r) %>">Show/Edit</a></td>
19
+ <td>
20
+ <form method="post" action="<%= model_path(@r.model) %>/<%= @r.id %>" onsubmit="return confirm('Are you sure?');">
21
+ <input type="hidden" name="_method" value="delete" />
22
+ <button type="submit">Destroy</button>
23
+ </form>
24
+ </td>
25
+ </tr>
@@ -0,0 +1,8 @@
1
+ <% model = params[:model] %>
2
+ <form id="search" action="<%= base_path %>/search" method="get">
3
+ <% params.each do |k, v| %>
4
+ <% next if ['splat', 'q'].include?(k) or v.blank? %>
5
+ <input type="hidden" name="<%= k %>" value="<%= v %>" />
6
+ <% end %>
7
+ <input type="text" name="q" value="Find <%= model %>:" onfocus="if(this.value=='Find <%= model %>:')this.value='';" onblur="if(this.value=='')this.value='Find <%= model %>:';"/>
8
+ </form>
@@ -0,0 +1,8 @@
1
+ <h1><%= @title || @model.name + ':' + @resource.id.to_s %></h1>
2
+
3
+ <form class="destroy" method="post" action="<%= model_path(@resource.model) %>/<%= @resource.id %>" onsubmit="return confirm('Are you sure?');">
4
+ <input type="hidden" name="_method" value="delete" />
5
+ <button type="submit">Destroy</button>
6
+ </form>
7
+
8
+ <%= partial(:form) %>
@@ -0,0 +1,9 @@
1
+ <ul class="subnav">
2
+ <% @subtypes.each do |subtype| %>
3
+ <% subtype.each do |k, vals| %>
4
+ <% vals.each do |v| %>
5
+ <li class="<%= 'current' if params[k] and params[k] == v.to_s %>"><a href="<%= model_path %>?<%= k %>=<%= v %>"><%= k %>::<%= v %></a></li>
6
+ <% end %>
7
+ <% end %>
8
+ <% end %>
9
+ </ul>
@@ -0,0 +1,25 @@
1
+ <table class="sortable">
2
+ <thead>
3
+ <tr>
4
+ <th title="<%= @model.key.first.type.to_s %>" class="<%= @model.key.first.name.to_s %>-col"><%= @model.key.first.name.to_s.upcase %></th>
5
+ <% @resources.first.attributes.each do |p| %>
6
+ <% next if p[0] == @model.key.first.name %>
7
+ <th title="<%= p[1].class.to_s %>" class="<%= p[0].to_s %>-col"><%= p[0].to_s.titleize %></th>
8
+ <% end %>
9
+ <% unless params[:association] %>
10
+ <% @resources.first.class.relationships.each do |rel| %>
11
+ <% unless rel[1].class.name =~ /ManyTo/ %>
12
+ <th title="<%= rel[1].class.name.to_s.gsub('DataMapper::Associations::','') %>" class="rel <%= rel[0].to_s %>-col"><%= rel[0].to_s.titleize %></th>
13
+ <% end %>
14
+ <% end %>
15
+ <% end %>
16
+ <th class="actions" colspan="3">&nbsp;</th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <% @resources.each do |r| %>
21
+ <% @r = r %>
22
+ <%= partial(:row) %>
23
+ <% end %>
24
+ </tbody>
25
+ </table>
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bowtie
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - "Tom\xC3\xA1s Pollak"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-14 00:00:00 -03:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sinatra
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.4
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: dm-core
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.10.2
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: dm-aggregates
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.10.2
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: dm-pager
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.0.1
54
+ version:
55
+ description: Sinatra scaffold for DataMapper models.
56
+ email: tomas@usefork.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - lib/bowtie.rb
63
+ - lib/bowtie/admin.rb
64
+ - lib/bowtie/core_extensions.rb
65
+ - lib/bowtie/helpers.rb
66
+ files:
67
+ - README
68
+ - bowtie.gemspec
69
+ - lib/bowtie.rb
70
+ - lib/bowtie/admin.rb
71
+ - lib/bowtie/core_extensions.rb
72
+ - lib/bowtie/helpers.rb
73
+ - lib/bowtie/views/errors.erb
74
+ - lib/bowtie/views/field.erb
75
+ - lib/bowtie/views/flash.erb
76
+ - lib/bowtie/views/form.erb
77
+ - lib/bowtie/views/index.erb
78
+ - lib/bowtie/views/layout.erb
79
+ - lib/bowtie/views/new.erb
80
+ - lib/bowtie/views/search.erb
81
+ - lib/bowtie/views/show.erb
82
+ - lib/bowtie/views/subtypes.erb
83
+ - lib/bowtie/views/table.erb
84
+ - lib/bowtie/views/row.erb
85
+ - lib/bowtie/public/css/bowtie.css
86
+ - lib/bowtie/public/js/bowtie.js
87
+ - lib/bowtie/public/js/jquery.tablesorter.pack.js
88
+ - lib/bowtie/public/js/jquery.jeditable.pack.js
89
+ has_rdoc: true
90
+ homepage: http://github.com/tomas/bowtie
91
+ licenses: []
92
+
93
+ post_install_message:
94
+ rdoc_options:
95
+ - --line-numbers
96
+ - --inline-source
97
+ - --title
98
+ - Bowtie
99
+ - --main
100
+ - README
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: "0"
108
+ version:
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: "1.2"
114
+ version:
115
+ requirements: []
116
+
117
+ rubyforge_project: bowtie
118
+ rubygems_version: 1.3.5
119
+ signing_key:
120
+ specification_version: 3
121
+ summary: Bowtie Admin
122
+ test_files: []
123
+