aura 0.0.1.pre10

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 (249) hide show
  1. data/.gitignore +6 -0
  2. data/.travis.yml +3 -0
  3. data/Gemfile +2 -0
  4. data/HISTORY.md +95 -0
  5. data/README.md +53 -0
  6. data/Rakefile +27 -0
  7. data/Scribefile +8 -0
  8. data/app/css/_utilities.scss +88 -0
  9. data/app/css/admin.scss +21 -0
  10. data/app/css/admin/_settings.scss +136 -0
  11. data/app/css/admin/chrome.scss +208 -0
  12. data/app/css/admin/common.scss +78 -0
  13. data/app/css/admin/forms.scss +342 -0
  14. data/app/css/admin/jquery_wysiwyg.scss +96 -0
  15. data/app/css/admin/loading.scss +18 -0
  16. data/app/css/admin/meta.scss +42 -0
  17. data/app/css/admin/reset.scss +46 -0
  18. data/app/css/admin/sections.scss +79 -0
  19. data/app/css/admin/setup.scss +22 -0
  20. data/app/css/admin/sidebar.scss +136 -0
  21. data/app/css/admin/slug.scss +78 -0
  22. data/app/css/admin/uiscreen.scss +22 -0
  23. data/app/css/admin/wysiwyg_field.scss +11 -0
  24. data/app/css/admin_watermark.scss +23 -0
  25. data/app/css/default_home_page.scss +13 -0
  26. data/app/css/login.scss +47 -0
  27. data/app/helpers/admin_helpers.rb +59 -0
  28. data/app/helpers/flash_helpers.rb +86 -0
  29. data/app/helpers/form_builder_helpers.rb +9 -0
  30. data/app/helpers/html_helpers.rb +27 -0
  31. data/app/helpers/jquery_helpers.rb +26 -0
  32. data/app/helpers/main_helpers.rb +67 -0
  33. data/app/helpers/page_helpers.rb +92 -0
  34. data/app/helpers/template_helpers.rb +94 -0
  35. data/app/helpers/user_helpers.rb +45 -0
  36. data/app/init/admin.rb +34 -0
  37. data/app/init/extensions.rb +18 -0
  38. data/app/init/pistol.rb +11 -0
  39. data/app/init/sequel.rb +11 -0
  40. data/app/main.rb +106 -0
  41. data/app/migrations/page.rb +29 -0
  42. data/app/migrations/settings.rb +11 -0
  43. data/app/migrations/user.rb +13 -0
  44. data/app/models/page.rb +116 -0
  45. data/app/models/page_seed.rb +47 -0
  46. data/app/models/settings.rb +59 -0
  47. data/app/models/user.rb +60 -0
  48. data/app/routes/admin.rb +44 -0
  49. data/app/routes/css_js.rb +53 -0
  50. data/app/routes/design_tests.rb +15 -0
  51. data/app/routes/editor.rb +152 -0
  52. data/app/routes/site.rb +33 -0
  53. data/app/routes/user.rb +48 -0
  54. data/app/views/admin/_back_to_dashboard.haml +3 -0
  55. data/app/views/admin/dashboard.haml +46 -0
  56. data/app/views/admin/layout.haml +73 -0
  57. data/app/views/admin/settings.haml +40 -0
  58. data/app/views/admin/settings/database.haml +42 -0
  59. data/app/views/base/crumbs.haml +50 -0
  60. data/app/views/base/delete.haml +19 -0
  61. data/app/views/base/edit.haml +61 -0
  62. data/app/views/base/errors.haml +10 -0
  63. data/app/views/base/form.haml +11 -0
  64. data/app/views/base/list.haml +14 -0
  65. data/app/views/base/list_actions.haml +4 -0
  66. data/app/views/base/list_item.haml +7 -0
  67. data/app/views/base/nav.haml +36 -0
  68. data/app/views/base/new.haml +36 -0
  69. data/app/views/base/preview.haml +28 -0
  70. data/app/views/base/tabs.haml +12 -0
  71. data/app/views/default_home_page.haml +15 -0
  72. data/app/views/design_tests/admin_styles.haml +58 -0
  73. data/app/views/form_builder/builder.haml +29 -0
  74. data/app/views/page/edit.haml +29 -0
  75. data/app/views/page/form.haml +22 -0
  76. data/app/views/page/meta_form.haml +22 -0
  77. data/app/views/page/new.haml +26 -0
  78. data/app/views/user/edit.haml +52 -0
  79. data/app/views/user/form.haml +43 -0
  80. data/app/views/user/list.haml +11 -0
  81. data/app/views/user/login.haml +33 -0
  82. data/app/views/user/new.haml +25 -0
  83. data/app/views/user/welcome.haml +29 -0
  84. data/app/views/watermark/watermark.haml +16 -0
  85. data/aura.gemspec +36 -0
  86. data/bin/aura +8 -0
  87. data/config/database.rb +12 -0
  88. data/config/extensions.rb +5 -0
  89. data/config/scss.rb +14 -0
  90. data/config/user.rb +10 -0
  91. data/default/.gitignore +6 -0
  92. data/default/Gemfile +11 -0
  93. data/default/README.md +24 -0
  94. data/default/Rakefile +8 -0
  95. data/default/app/README +3 -0
  96. data/default/app/css/.gitignore +0 -0
  97. data/default/app/helpers/helpers.rb.example +9 -0
  98. data/default/app/js/.gitignore +0 -0
  99. data/default/app/migrations/model.rb.example +20 -0
  100. data/default/app/models/model.rb.example +11 -0
  101. data/default/app/models/page-ext.rb.example +17 -0
  102. data/default/app/routes/site.rb.example +5 -0
  103. data/default/app/views/hello.haml.example +1 -0
  104. data/default/config.ru +3 -0
  105. data/default/config/.gitignore +0 -0
  106. data/default/config/database.rb.example +30 -0
  107. data/default/config/extensions.rb +5 -0
  108. data/default/config/user.rb.example +10 -0
  109. data/default/db/.gitignore +0 -0
  110. data/default/init.rb +15 -0
  111. data/default/public/.gitignore +0 -0
  112. data/extensions/contact_form/migrations/contact_form.rb +13 -0
  113. data/extensions/contact_form/models/contact_form.rb +13 -0
  114. data/extensions/contact_form/routes/contact_form.rb +11 -0
  115. data/extensions/contact_form/views/contact_form/edit.haml +8 -0
  116. data/extensions/contact_form/views/contact_form/form.haml +3 -0
  117. data/extensions/contact_form/views/contact_form/nav.haml +42 -0
  118. data/extensions/contact_form/views/contact_form/responses.haml +20 -0
  119. data/extensions/contact_form/views/contact_form/tabs.haml +8 -0
  120. data/extensions/default_theme/css/theme/_settings.scss +3 -0
  121. data/extensions/default_theme/css/theme/chrome.scss +66 -0
  122. data/extensions/default_theme/css/theme/reset.scss +34 -0
  123. data/extensions/default_theme/css/theme/style.scss +3 -0
  124. data/extensions/default_theme/info.yml +2 -0
  125. data/extensions/default_theme/public/browse.png +0 -0
  126. data/extensions/default_theme/views/base/id_portfolio.haml +32 -0
  127. data/extensions/default_theme/views/base/show.haml +31 -0
  128. data/extensions/default_theme/views/errors/error.haml +9 -0
  129. data/extensions/default_theme/views/errors/not_found.haml +11 -0
  130. data/extensions/default_theme/views/layout.haml +33 -0
  131. data/lib/aura.rb +315 -0
  132. data/lib/aura/admin.rb +41 -0
  133. data/lib/aura/app.rb +4 -0
  134. data/lib/aura/cli.rb +19 -0
  135. data/lib/aura/cli/base.rb +89 -0
  136. data/lib/aura/cli/helpers.rb +32 -0
  137. data/lib/aura/editor.rb +30 -0
  138. data/lib/aura/extension.rb +189 -0
  139. data/lib/aura/files.rb +38 -0
  140. data/lib/aura/menu.rb +142 -0
  141. data/lib/aura/models.rb +80 -0
  142. data/lib/aura/public.rb +68 -0
  143. data/lib/aura/rendering.rb +134 -0
  144. data/lib/aura/seeder.rb +38 -0
  145. data/lib/aura/slugs.rb +87 -0
  146. data/lib/aura/subtype.rb +48 -0
  147. data/lib/aura/tasks.rb +24 -0
  148. data/lib/aura/tasks/common.rb +17 -0
  149. data/lib/aura/tasks/db.rake +54 -0
  150. data/lib/aura/utils.rb +81 -0
  151. data/lib/aura/version.rb +25 -0
  152. data/lib/core/hasharray.rb +65 -0
  153. data/lib/core/object_ext.rb +9 -0
  154. data/lib/sequel/plugins/aura_custom.rb +16 -0
  155. data/lib/sequel/plugins/aura_editable.rb +39 -0
  156. data/lib/sequel/plugins/aura_hierarchy.rb +82 -0
  157. data/lib/sequel/plugins/aura_model.rb +271 -0
  158. data/lib/sequel/plugins/aura_renderable.rb +42 -0
  159. data/lib/sequel/plugins/aura_sluggable.rb +103 -0
  160. data/lib/sequel/plugins/aura_subtyped.rb +83 -0
  161. data/lib/terra.rb +185 -0
  162. data/lib/terra/ext.rb +16 -0
  163. data/lib/terra/field.rb +98 -0
  164. data/lib/terra/fields.rb +122 -0
  165. data/lib/terra/fieldset.rb +93 -0
  166. data/lib/terra/form.rb +111 -0
  167. data/manual/configuration.md +42 -0
  168. data/manual/extensions.md +45 -0
  169. data/manual/files.md +70 -0
  170. data/manual/helpers.md +39 -0
  171. data/manual/index.md +65 -0
  172. data/manual/models.md +58 -0
  173. data/manual/recipes.md +38 -0
  174. data/manual/recipes/bundling_sample_data.md +30 -0
  175. data/manual/recipes/creating_themes.md +10 -0
  176. data/manual/recipes/using_markdown_or_textile.md +24 -0
  177. data/manual/routes.md +39 -0
  178. data/manual/theming.md +55 -0
  179. data/manual/views.md +128 -0
  180. data/public/hi.html +0 -0
  181. data/public/images/admin/back.png +0 -0
  182. data/public/images/admin/browse.png +0 -0
  183. data/public/images/admin/mock-bg.png +0 -0
  184. data/public/images/admin/top-loader.gif +0 -0
  185. data/public/images/admin/uiscreen-loader.gif +0 -0
  186. data/public/images/admin_icons/add.png +0 -0
  187. data/public/images/admin_icons/contact.png +0 -0
  188. data/public/images/admin_icons/dashboard.png +0 -0
  189. data/public/images/admin_icons/generic.png +0 -0
  190. data/public/images/admin_icons/home-12.png +0 -0
  191. data/public/images/admin_icons/page.png +0 -0
  192. data/public/images/admin_icons/settings.png +0 -0
  193. data/public/images/jquery.wysiwyg.gif +0 -0
  194. data/public/js/admin.form_builder.js +15 -0
  195. data/public/js/admin.js +62 -0
  196. data/public/js/admin.layout.js +53 -0
  197. data/public/js/admin.nav.js +241 -0
  198. data/public/js/admin.slug.js +46 -0
  199. data/public/js/admin.subpage.js +15 -0
  200. data/public/js/jquery.hashlisten.js +85 -0
  201. data/public/js/jquery.js +166 -0
  202. data/public/js/jquery.livenavigate.js +58 -0
  203. data/public/js/jquery.livequery.js +226 -0
  204. data/public/js/jquery.quickvalidate.js +164 -0
  205. data/public/js/jquery.tmpl.js +486 -0
  206. data/public/js/jquery.uiscreen.js +150 -0
  207. data/public/js/jquery.wysiwyg.js +2339 -0
  208. data/public/js/jqueryui.js +766 -0
  209. data/public/js/lib.dirty.js +11 -0
  210. data/public/js/lib.loading.js +23 -0
  211. data/public/js/lib.wysiwyg.js +155 -0
  212. data/public/js/underscore-1.1.7.js +27 -0
  213. data/test/app/app/css/test_raw.css +1 -0
  214. data/test/app/app/css/test_sass.sass +3 -0
  215. data/test/app/app/damogram.txt +1 -0
  216. data/test/app/app/js/test_coffee.coffee +4 -0
  217. data/test/app/app/js/test_javascript.js +4 -0
  218. data/test/app/init.rb +5 -0
  219. data/test/stories/admin_css_story.rb +18 -0
  220. data/test/stories/css_js_story.rb +29 -0
  221. data/test/stories/first_login_story.rb +29 -0
  222. data/test/stories/visit_story.rb +39 -0
  223. data/test/stories_helper.rb +58 -0
  224. data/test/test_cli_helper.rb +31 -0
  225. data/test/test_helper.rb +111 -0
  226. data/test/test_temp_helper.rb +9 -0
  227. data/test/unit/cli_test.rb +38 -0
  228. data/test/unit/dump_test.rb +14 -0
  229. data/test/unit/extensions_test.rb +18 -0
  230. data/test/unit/files_test.rb +14 -0
  231. data/test/unit/flash_helper_test.rb +36 -0
  232. data/test/unit/html_helper_test.rb +29 -0
  233. data/test/unit/jquery_helper_test.rb +18 -0
  234. data/test/unit/model_test.rb +34 -0
  235. data/test/unit/page_helpers_test.rb +36 -0
  236. data/test/unit/seeder_test.rb +15 -0
  237. data/test/unit/settings_test.rb +29 -0
  238. data/test/unit/slug_test.rb +39 -0
  239. data/test/unit/ss_migration_test.rb +14 -0
  240. data/test/unit/terra_test.rb +125 -0
  241. data/test/unit/utils_test.rb +11 -0
  242. data/vendor/sinatra-sequel/.gitignore +3 -0
  243. data/vendor/sinatra-sequel/COPYING +18 -0
  244. data/vendor/sinatra-sequel/README.md +84 -0
  245. data/vendor/sinatra-sequel/Rakefile +67 -0
  246. data/vendor/sinatra-sequel/lib/sinatra/sequel.rb +73 -0
  247. data/vendor/sinatra-sequel/sinatra-sequel.gemspec +39 -0
  248. data/vendor/sinatra-sequel/spec/spec_sinatra_sequel.rb +70 -0
  249. metadata +536 -0
@@ -0,0 +1,82 @@
1
+ # Sequel plugin: AuraHierarchy
2
+ # Used on models that have children and parents.
3
+ #
4
+ # ## Description
5
+ # This automatically gives models parent/child support.
6
+ #
7
+ # #### How to use
8
+ # Use `plugin :aura_hierarchy` in your model.
9
+ #
10
+ # class Book < Sequel::Model
11
+ # plugin :aura_hierarchy
12
+ # end
13
+ #
14
+ # #### Database setup
15
+ # Add `:parent_id` to your schema.
16
+ #
17
+ # database.create_table :books do
18
+ # foreign_key :parent_id
19
+ # # ...
20
+ # end
21
+ #
22
+ # #### Example
23
+ # Our `Book` class can now have parents and children.
24
+ #
25
+ # book = Book[2]
26
+ #
27
+ # # Traversion
28
+ # book.parent
29
+ # book.children
30
+ # book.siblings
31
+ #
32
+ module Sequel::Plugins::AuraHierarchy
33
+ def self.configure(model, options={})
34
+ model.many_to_one :parent, :class => model
35
+ model.one_to_many :children, :key => :parent_id, :class => model
36
+ end
37
+
38
+ module InstanceMethods
39
+ def parentable?
40
+ true
41
+ end
42
+
43
+ def siblings
44
+ if parent.nil?
45
+ self.class.filter(:parent_id => nil)
46
+ else
47
+ parent.children
48
+ end
49
+ end
50
+
51
+ def prev_sibling
52
+ siblings.each_cons(2) { |(other, item)| return item if other.id == self.id }
53
+ end
54
+
55
+ def next_sibling
56
+ siblings.each_cons(2) { |(item, other)| return item if other.id == self.id }
57
+ end
58
+
59
+ def nearest
60
+ children.any? ? children : siblings
61
+ end
62
+
63
+ def nearest_parent
64
+ children.any? ? self : parent
65
+ end
66
+
67
+ def crumbs
68
+ return [self] if parent.nil?
69
+ parent.crumbs + [self]
70
+ end
71
+ end
72
+
73
+ module ClassMethods
74
+ def parentable?
75
+ true
76
+ end
77
+
78
+ def roots
79
+ filter(:parent_id => nil)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,271 @@
1
+ # Sequel plugin: AuraModel
2
+ # The base plugin for a model.
3
+ #
4
+ # ## Description
5
+ # All models use this plugin, and all methods it provides are available
6
+ # to all Aura/Sequel models.
7
+ #
8
+ module Sequel::Plugins::AuraModel
9
+ def self.configure(model)
10
+ model.plugin :validation_helpers
11
+ end
12
+
13
+ module InstanceMethods
14
+ # Method: parent (AuraModel)
15
+ # Returns the parent.
16
+ #
17
+ def parent
18
+ nil
19
+ end
20
+
21
+ def to_s
22
+ begin
23
+ title
24
+ rescue NoMethodError
25
+ @values[:title] || self.class.to_s.split('::').last
26
+ end
27
+ end
28
+
29
+ def validate!
30
+ raise Sequel::ValidationFailed(errors) unless valid?
31
+ end
32
+
33
+ # Method: shown_in_menu? (AuraModel)
34
+ # Determines if the record should be shown to visitors in the site menus.
35
+ #
36
+ # ## Description
37
+ # This only affects the front-facing site, and has to influence as
38
+ # to whether it will be shown in the admin area.
39
+ #
40
+ # Override this.
41
+ #
42
+ def shown_in_menu?
43
+ false
44
+ end
45
+
46
+ def <=>(other)
47
+ self.sort_index <=> other.sort_index
48
+ end
49
+
50
+ # Method: sort_index (AuraModel)
51
+ # This is what they'll be sorted by.
52
+ #
53
+ # To enable sorting, implement a `position` field.
54
+ #
55
+ # You can reimplement this. Make sure it returns a tuple of an int and an int.
56
+ #
57
+ def sort_index
58
+ pos = nil
59
+ pos ||= self.position if self.respond_to?(:position)
60
+ [pos || 9999, self.id]
61
+ end
62
+
63
+ # Method: set_fields (AuraModel)
64
+ # Sets the fields to the values in the hash.
65
+ #
66
+ # Overriding `set_fields` to make the 2nd param optional.
67
+ #
68
+ def set_fields(hash, keys=hash.keys)
69
+ super hash, keys
70
+ end
71
+
72
+ def templates_for(template)
73
+ self.class.templates_for template
74
+ end
75
+
76
+ # Method: menu_title (AuraModel)
77
+ # Returns the name of the record as it should appear on the menu.
78
+ #
79
+ # This defaults to whatever the title of the record is (`#to_s`).
80
+ # Have your model override this if you need to.
81
+ #
82
+ def menu_title
83
+ to_s
84
+ end
85
+
86
+ # Method: path (AuraModel)
87
+ # Returns the URL path for the record.
88
+ #
89
+ # ## Example
90
+ #
91
+ # Page[1].path #=> '/products/cx-300'
92
+ # User[1].path #=> '/user/1' (because user is not sluggable.)
93
+ #
94
+ # Page[1].path(:edit) # => '/products/cx-300/edit'
95
+ #
96
+ def path(*a)
97
+ ret = "/#{self.class.class_name}/#{self.id}"
98
+ ret += "/#{a.shift.to_s}" if a.first.is_a?(String) || a.first.is_a?(Symbol)
99
+ ret += "?" + Aura::Utils.query_string(a.shift) if a.first.is_a?(Hash)
100
+ ret
101
+ end
102
+
103
+ # Method: parentable? (AuraModel)
104
+ # Determines if the record can have children.
105
+ #
106
+ # This is reimplemented by {AuraHierarchy}.
107
+ #
108
+ def parentable?
109
+ false
110
+ end
111
+
112
+ # Method: parent? (AuraModel)
113
+ # Determines if the record has a parent.
114
+ #
115
+ def parent?
116
+ ! parent.nil?
117
+ end
118
+
119
+ # Method: children (AuraModel)
120
+ # Returns the children of the record.
121
+ def children
122
+ Array.new
123
+ end
124
+
125
+ # Method: submenu (AuraModel)
126
+ # Returns a list of items for the submenu.
127
+ #
128
+ # ## Example
129
+ #
130
+ # <% item.submenu.each do %>
131
+ # <li><% item.to_s %></li>
132
+ # <% end %>
133
+ #
134
+ def submenu
135
+ children.select { |item| item.shown_in_menu? }.sort
136
+ end
137
+
138
+ # Method: crumbs (AuraModel)
139
+ # Returns an array of records of breadcrumb path of the record, starting from the root.
140
+ #
141
+ def crumbs
142
+ [self]
143
+ end
144
+
145
+ # Determines how far removed the record is from the root.
146
+ #
147
+ # ## Example
148
+ #
149
+ # p = Page[1]
150
+ # p.parent? #=> false
151
+ # p.depth #=> 1
152
+ #
153
+ def depth
154
+ crumbs.size
155
+ end
156
+
157
+ def is_parent_of?(target)
158
+ target.crumbs.include?(self)
159
+ end
160
+ end
161
+
162
+ module ClassMethods
163
+ # Class method: content? (AuraModel)
164
+ # Returns if the model data is considered to be site content.
165
+ #
166
+ # ## Description
167
+ # The site is considered empty if all models that are content?
168
+ # are empty.
169
+ #
170
+ def content?
171
+ false
172
+ end
173
+
174
+ # Class method: roots (AuraModel)
175
+ # Returns a set of results of all records that don't have parents.
176
+ #
177
+ # Returns a Sequel dataset.
178
+ def roots
179
+ select
180
+ end
181
+
182
+ # Class method: seed (AuraModel)
183
+ # Ensures that the model has some bare essentials in it.
184
+ #
185
+ # This is called every time the application initializes.
186
+ # Override this if you need certain records to exist, like as
187
+ # how there is always one user.
188
+ #
189
+ # As this is called every application load, if you override this,
190
+ # it is your responsibility to check if the model is #empty? before
191
+ # writing anything.
192
+ #
193
+ # A parameter `type` may be given. If this is set to `:sample`, then
194
+ # load up some sample data.
195
+ #
196
+ def seed(type=nil, &b)
197
+ end
198
+
199
+ # Class method: seed! (AuraModel)
200
+ # Like `seed`, but empties the table first.
201
+ #
202
+ def seed!(type=nil, &b)
203
+ delete
204
+ seed type, &b
205
+ end
206
+
207
+ # Class method: parentable (AuraModel)
208
+ # Determines if the model can have children.
209
+ #
210
+ # Reimplemented by aura_hierarchy.
211
+ #
212
+ def parentable?
213
+ false
214
+ end
215
+
216
+ def templates_for(template)
217
+ [ :"#{class_name}/#{template}",
218
+ :"base/#{template}"
219
+ ]
220
+ end
221
+
222
+ # Class method: class_name (AuraModel)
223
+ # Returns a string of the model's name for use in URLs.
224
+ #
225
+ # ## Example
226
+ #
227
+ # BlogPost.class_name #=> "blog_post"
228
+ #
229
+ def class_name
230
+ self.to_s.demodulize.underscore
231
+ end
232
+
233
+ # Class method: title (AuraModel)
234
+ # Returns a string of the model's name to appear on pages.
235
+ #
236
+ # ## Example
237
+ #
238
+ # BlogPost.title #=> "Blog post"
239
+ #
240
+ def title
241
+ self.class_name.humanize
242
+ end
243
+
244
+ # Class method: title_plural (AuraModel)
245
+ # Returns a string of the model's name, pluralized, to appear on pages.
246
+ #
247
+ # ## Example
248
+ #
249
+ # BlogPost.title_plural #=> "Blog posts"
250
+ #
251
+ def title_plural
252
+ self.title.pluralize
253
+ end
254
+
255
+ # Class method: path (AuraModel)
256
+ # Returns a URL path for an action for the model.
257
+ #
258
+ # ## Example
259
+ #
260
+ # BlogPost.path #=> /blog_post
261
+ # BlogPost.path(:list) #=> /blog_post/list
262
+ # BlogPost.path(:list, :all) #=> /blog_post/list/all
263
+ #
264
+ def path(*a)
265
+ ret = "/#{class_name}"
266
+ ret += "/#{a.shift}" if a.first.is_a?(String) || a.first.is_a?(Symbol)
267
+ ret += "?" + Aura::Utils.query_string(a.shift) if a.first.is_a?(Hash)
268
+ ret
269
+ end
270
+ end
271
+ end
@@ -0,0 +1,42 @@
1
+ # Models that can be viewed by a URL.
2
+ # Supports templating and stuff.
3
+ #
4
+ # Assumptions:
5
+ #
6
+ # - Your data table must have `String :template`. (optional;
7
+ # Aura guesses the template name if it's not available.)
8
+ #
9
+ module Sequel
10
+ module Plugins
11
+ module AuraRenderable
12
+ module InstanceMethods
13
+ # Returns the templates to be tried for the item, listed
14
+ # in order of priority.
15
+ #
16
+ # Example:
17
+ #
18
+ # [ "product/mofo", "base/mofo", "product/default", "base/default" ]
19
+ #
20
+ def page_templates
21
+ klass = self.class.class_name # blog_post
22
+
23
+ [ :"#{klass}/#{template}",
24
+ :"base/#{template}",
25
+ :"#{klass}/show",
26
+ :"base/show"
27
+ ].map { |s| s.to_sym }.uniq
28
+ end
29
+
30
+ # Returns the template to be used when it's displayed.
31
+ # Overridden by AuraSubtyped.
32
+ def template
33
+ 'show'
34
+ end
35
+
36
+ def renderable?
37
+ true
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,103 @@
1
+ # Sequel plugin: AuraSluggable
2
+ # Implemented for models that are to be accessible via a slug URL.
3
+ #
4
+ # ## Description
5
+ # This automatically gives models the ability to be accessed via a
6
+ # slug URL (like `/products/boots`).
7
+ #
8
+ # #### How to use
9
+ # Use `plugin :aura_sluggable`.
10
+ #
11
+ # class Book < Sequel::Model
12
+ # plugin :aura_sluggable
13
+ #
14
+ # # ...
15
+ # end
16
+ #
17
+ # #### Database setup
18
+ # Add `String :slug` to your schema.
19
+ #
20
+ # database.create_table :books do
21
+ # String :slug
22
+ # # ...
23
+ # end
24
+ #
25
+ module Sequel
26
+ module Plugins
27
+ module AuraSluggable
28
+ def self.configure(model, opts={})
29
+ Aura.slugs.register(model)
30
+ end
31
+
32
+ module InstanceMethods
33
+ def sluggable?
34
+ true
35
+ end
36
+
37
+ # Method: path (AuraSluggable)
38
+ # Returns the URL path.
39
+ #
40
+ def path(*a)
41
+ return super if slug.nil?
42
+ ret = '/' + (slug.to_s)
43
+ ret = "#{parent.path}#{ret}" if respond_to?(:parent) && parent.respond_to?(:path)
44
+ ret += "/#{a.shift.to_s}" if a.first.is_a?(String) || a.first.is_a?(Symbol)
45
+ ret += "?" + Aura::Utils.query_string(a.shift) if a.first.is_a?(Hash)
46
+ ret
47
+ end
48
+
49
+ # Method: slugify (AuraSluggable)
50
+ # Returns a unique slug for the item.
51
+ #
52
+ # ## Example
53
+ # b = Book.new
54
+ # b.title = 'Darkly Dreaming Dexter'
55
+ #
56
+ # b.slugify #=> "darkly-dreaming-dexter"
57
+ # b.slugify("Dexter by Design") #=> "dexter-by-design"
58
+ #
59
+ def slugify(str=title)
60
+ str = str.to_s
61
+ str = str.scan(/[A-Za-z0-9]+/).join('-').downcase
62
+ i = 1
63
+
64
+ loop do
65
+ slug = str
66
+ slug = "#{str}-#{i}" if i>1
67
+
68
+ item = self.class.find(:slug => slug)
69
+ return slug if item.nil? || item == self
70
+ i += 1
71
+ end
72
+ end
73
+
74
+ def validate
75
+ self.slug = self.slugify if self.slug.nil? or self.slug.empty?
76
+ super
77
+ end
78
+ end
79
+
80
+ module ClassMethods
81
+ def sluggable?
82
+ true
83
+ end
84
+
85
+ # Class method: get_by_slug (AuraSluggable)
86
+ # Finds an item by a given slug.
87
+ #
88
+ # ## Example
89
+ # b = Book.get_by_slug('darkly-dreaming-dexter')
90
+ #
91
+ def get_by_slug(slug, parent=nil)
92
+ pid = parent.nil? ? nil : parent.id
93
+
94
+ if columns.include?(:parent_id)
95
+ find(:slug => slug, :parent_id => pid)
96
+ else
97
+ find(:slug => slug)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end