merbiful-release 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +44 -0
- data/lib/merbiful-release/admin.rb +281 -0
- data/lib/merbiful-release/admin.rb~ +12 -0
- data/lib/merbiful-release/body.rb +36 -0
- data/lib/merbiful-release/body.rb~ +15 -0
- data/lib/merbiful-release/controller.rb +55 -0
- data/lib/merbiful-release/controller.rb~ +12 -0
- data/lib/merbiful-release/css.rb +70 -0
- data/lib/merbiful-release/css.rb~ +62 -0
- data/lib/merbiful-release/erubis.rb +13 -0
- data/lib/merbiful-release/erubis.rb~ +11 -0
- data/lib/merbiful-release/eruby.rb~ +11 -0
- data/lib/merbiful-release/filters.rb +22 -0
- data/lib/merbiful-release/haml.rb +23 -0
- data/lib/merbiful-release/haml.rb~ +11 -0
- data/lib/merbiful-release/images.rb +28 -0
- data/lib/merbiful-release/js.rb +69 -0
- data/lib/merbiful-release/js.rb~ +62 -0
- data/lib/merbiful-release/layout.rb +49 -0
- data/lib/merbiful-release/layout.rb~ +21 -0
- data/lib/merbiful-release/merbiful.rb~ +8 -0
- data/lib/merbiful-release/page.rb +98 -0
- data/lib/merbiful-release/page.rb~ +57 -0
- data/lib/merbiful-release/relative_time.rb +116 -0
- data/lib/merbiful-release/relative_time.rb~ +78 -0
- data/lib/merbiful-release/routes.rb +42 -0
- data/lib/merbiful-release/routes.rb~ +4 -0
- data/lib/merbiful-release/version.rb~ +45 -0
- data/lib/merbiful-release.rb +29 -0
- data/lib/merbiful-release.rb~ +2 -0
- data/templates/admin.css +17 -0
- data/templates/admin.css~ +3 -0
- data/templates/admin_layout.html.haml +11 -0
- data/templates/admin_layout.html.haml~ +9 -0
- data/templates/admin_layout.html.rhtml~ +10 -0
- data/templates/css.html.haml +29 -0
- data/templates/css.html.haml.orig +28 -0
- data/templates/css.html.haml~ +29 -0
- data/templates/images.html.haml +17 -0
- data/templates/index.html.haml +2 -0
- data/templates/index.html.haml~ +2 -0
- data/templates/js.html.haml +26 -0
- data/templates/js.html.haml~ +29 -0
- data/templates/layouts.html.haml +23 -0
- data/templates/layouts.html.haml~ +0 -0
- data/templates/page_form.html.haml +41 -0
- data/templates/page_form.html.haml~ +1 -0
- data/templates/pages.html.haml~ +3 -0
- metadata +120 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
module Merbiful
|
3
|
+
|
4
|
+
module Images
|
5
|
+
|
6
|
+
IMAGE_REGEXP = /\.(gif|jpg|jpeg|png|bmp)$/i
|
7
|
+
|
8
|
+
def self.images
|
9
|
+
rval = []
|
10
|
+
Dir.glob(File.join(Merb.root, "public", "images", "*")).each do |file|
|
11
|
+
if file.match(IMAGE_REGEXP)
|
12
|
+
rval << Pathname.new("/").join(Pathname.new(file).relative_path_from(Pathname.new(File.join(Merb.root, "public"))))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
rval
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.delete_possible?(image)
|
19
|
+
Pathname.new(File.join(Merb.root, "public", image)).writable?
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.upload_possible?
|
23
|
+
Pathname.new(File.join(Merb.root, "public", "images")).writable?
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
module Merbiful
|
3
|
+
|
4
|
+
class Js
|
5
|
+
|
6
|
+
include DataMapper::Resource
|
7
|
+
include DataMapper::Validate
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
property :id, Serial
|
11
|
+
|
12
|
+
property :name, DataMapper::Types::Text, :nullable => false
|
13
|
+
property :cached, Boolean, :default => true, :nullable => false
|
14
|
+
|
15
|
+
property :created_at, DateTime
|
16
|
+
property :updated_at, DateTime
|
17
|
+
|
18
|
+
has n, :js_nesses, :class_name => "Merbiful::Js::Ness"
|
19
|
+
has n, :page_versions, :through => :js_nesses, :class_name => "Merbiful::Page::Version"
|
20
|
+
has n, :js_versions, :class_name => "Merbiful::Js::Version"
|
21
|
+
|
22
|
+
def latest
|
23
|
+
js_versions.first(:js_id => self.id, :order => [:id.desc])
|
24
|
+
end
|
25
|
+
|
26
|
+
def_delegators :latest, :render, :body, :filter
|
27
|
+
|
28
|
+
def path
|
29
|
+
"/javascripts/#{latest.id}"
|
30
|
+
end
|
31
|
+
|
32
|
+
class Ness
|
33
|
+
include DataMapper::Resource
|
34
|
+
include DataMapper::Validate
|
35
|
+
|
36
|
+
property :id, Serial
|
37
|
+
|
38
|
+
belongs_to :js, :class_name => "Merbiful::Js"
|
39
|
+
belongs_to :page_version, :class_name => "Merbiful::Page::Version"
|
40
|
+
end
|
41
|
+
|
42
|
+
class Version
|
43
|
+
|
44
|
+
include DataMapper::Resource
|
45
|
+
include DataMapper::Validate
|
46
|
+
include Merbiful::Body
|
47
|
+
|
48
|
+
property :id, Serial
|
49
|
+
|
50
|
+
property :js_id, Integer, :index => true, :nullable => false
|
51
|
+
|
52
|
+
property :body, DataMapper::Types::Text
|
53
|
+
property :filter, DataMapper::Types::Text
|
54
|
+
|
55
|
+
property :created_at, DateTime
|
56
|
+
property :updated_at, DateTime
|
57
|
+
|
58
|
+
belongs_to :js, :class_name => "Merbiful::Js"
|
59
|
+
|
60
|
+
before :save do
|
61
|
+
clear_cache(js.path) if js.latest
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
module Merbiful
|
3
|
+
|
4
|
+
class Css
|
5
|
+
|
6
|
+
include DataMapper::Resource
|
7
|
+
include DataMapper::Validate
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
property :id, Serial
|
11
|
+
|
12
|
+
property :name, DataMapper::Types::Text, :nullable => false
|
13
|
+
property :media, DataMapper::Types::Text
|
14
|
+
property :cached, Boolean, :default => true, :nullable => false
|
15
|
+
|
16
|
+
property :created_at, DateTime
|
17
|
+
property :updated_at, DateTime
|
18
|
+
|
19
|
+
has n, :css_nesses, :class_name => "Merbiful::Css::Ness"
|
20
|
+
has n, :page_versions, :through => :css_nesses, :class_name => "Merbiful::Page::Version"
|
21
|
+
has n, :css_versions, :class_name => "Merbiful::Css::Version"
|
22
|
+
|
23
|
+
def latest
|
24
|
+
css_versions.first(:order => [:id.desc])
|
25
|
+
end
|
26
|
+
|
27
|
+
def_delegators :latest, :render
|
28
|
+
|
29
|
+
class Ness
|
30
|
+
include DataMapper::Resource
|
31
|
+
include DataMapper::Validate
|
32
|
+
|
33
|
+
property :id, Serial
|
34
|
+
|
35
|
+
belongs_to :css, :class_name => "Merbiful::Css"
|
36
|
+
belongs_to :page_version, :class_name => "Merbiful::Page::Version"
|
37
|
+
end
|
38
|
+
|
39
|
+
class Version
|
40
|
+
|
41
|
+
include DataMapper::Resource
|
42
|
+
include DataMapper::Validate
|
43
|
+
include Merbiful::Body
|
44
|
+
|
45
|
+
property :id, Serial
|
46
|
+
|
47
|
+
property :css_id, Integer, :index => true, :nullable => false
|
48
|
+
|
49
|
+
property :body, DataMapper::Types::Text
|
50
|
+
property :filter, DataMapper::Types::Text
|
51
|
+
|
52
|
+
property :created_at, DateTime
|
53
|
+
property :updated_at, DateTime
|
54
|
+
|
55
|
+
belongs_to :css, :class_name => "Merbiful::Css"
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
module Merbiful
|
3
|
+
|
4
|
+
class Layout
|
5
|
+
|
6
|
+
include DataMapper::Resource
|
7
|
+
include DataMapper::Validate
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
property :id, Serial
|
11
|
+
|
12
|
+
property :name, DataMapper::Types::Text, :nullable => false
|
13
|
+
|
14
|
+
property :created_at, DateTime
|
15
|
+
property :updated_at, DateTime
|
16
|
+
|
17
|
+
has n, :layout_versions, :class_name => "Merbiful::Layout::Version"
|
18
|
+
has n, :page_versions, :class_name => "Merbiful::Page::Version"
|
19
|
+
|
20
|
+
def latest
|
21
|
+
layout_versions.first(:layout_id => self.id, :order => [:id.desc])
|
22
|
+
end
|
23
|
+
|
24
|
+
def_delegators :latest, :render, :body, :filter
|
25
|
+
|
26
|
+
class Version
|
27
|
+
|
28
|
+
include DataMapper::Resource
|
29
|
+
include DataMapper::Validate
|
30
|
+
include Merbiful::Body
|
31
|
+
|
32
|
+
property :id, Serial
|
33
|
+
|
34
|
+
property :layout_id, Integer, :index => true, :nullable => false
|
35
|
+
|
36
|
+
property :body, DataMapper::Types::Text
|
37
|
+
property :filter, DataMapper::Types::Text
|
38
|
+
|
39
|
+
property :created_at, DateTime
|
40
|
+
property :updated_at, DateTime
|
41
|
+
|
42
|
+
belongs_to :layout, :class_name => "Merbiful::Layout"
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
class Page
|
3
|
+
|
4
|
+
include DataMapper::Resource
|
5
|
+
include DataMapper::Validate
|
6
|
+
|
7
|
+
property :id, Integer, :key => true, :serial => true
|
8
|
+
property :version, Integer, :key => true
|
9
|
+
property :body, DataMapper::Types::Text
|
10
|
+
property :filter, DataMapper::Types::Text
|
11
|
+
property :parent_id, Integer
|
12
|
+
property :path, DataMapper::Types::Text, :key => true
|
13
|
+
property :created_at, DateTime
|
14
|
+
property :updated_at, DateTime
|
15
|
+
property :position, Integer
|
16
|
+
property :author, DataMapper::Types::Text
|
17
|
+
property :layout, Integer
|
18
|
+
property :title, DataMapper::Types::Text
|
19
|
+
property :keywords, DataMapper::Types::Text
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
module Merbiful
|
3
|
+
|
4
|
+
class Page
|
5
|
+
|
6
|
+
class NoSuchFilterError < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
include DataMapper::Resource
|
10
|
+
include DataMapper::Validate
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
property :id, Serial
|
14
|
+
property :parent_id, Integer, :index => true
|
15
|
+
|
16
|
+
property :path, DataMapper::Types::Text, :unique_index => true, :nullable => false
|
17
|
+
property :position, Integer
|
18
|
+
property :cached, Boolean, :default => true, :nullable => false
|
19
|
+
|
20
|
+
property :created_at, DateTime
|
21
|
+
property :updated_at, DateTime
|
22
|
+
|
23
|
+
belongs_to :parent, :class_name => "Merbiful::Page", :child_key => [:parent_id]
|
24
|
+
has n, :children, :class_name => "Merbiful::Page", :child_key => [:parent_id]
|
25
|
+
has n, :versions, :class_name => "Merbiful::Page::Version"
|
26
|
+
|
27
|
+
validates_is_unique :path
|
28
|
+
|
29
|
+
before :save do
|
30
|
+
if self.position.nil?
|
31
|
+
last_position = self.class.first(:parent_id => self.parent_id, :id.not => self.id)
|
32
|
+
if last_position.nil?
|
33
|
+
self.position = 0
|
34
|
+
else
|
35
|
+
self.position = last_position.position + 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def latest
|
41
|
+
versions.first(:page_id => self.id, :order => [:id.desc])
|
42
|
+
end
|
43
|
+
|
44
|
+
def_delegators :latest, :render, :layout, :csses, :add_css, :remove_css, :jses, :add_js, :remove_js, :body, :filter, :title, :keywords
|
45
|
+
|
46
|
+
class Version
|
47
|
+
|
48
|
+
include DataMapper::Resource
|
49
|
+
include DataMapper::Validate
|
50
|
+
include Merbiful::Body
|
51
|
+
|
52
|
+
property :id, Serial
|
53
|
+
|
54
|
+
property :page_id, Integer, :nullable => false, :index => true
|
55
|
+
property :layout_id, Integer, :index => true
|
56
|
+
|
57
|
+
property :body, DataMapper::Types::Text
|
58
|
+
property :filter, DataMapper::Types::Text
|
59
|
+
property :title, DataMapper::Types::Text
|
60
|
+
property :keywords, DataMapper::Types::Text
|
61
|
+
|
62
|
+
property :created_at, DateTime
|
63
|
+
property :updated_at, DateTime
|
64
|
+
|
65
|
+
belongs_to :page, :class_name => "Merbiful::Page"
|
66
|
+
belongs_to :layout, :class_name => "Merbiful::Layout"
|
67
|
+
|
68
|
+
has n, :css_nesses, :class_name => "Merbiful::Css::Ness"
|
69
|
+
has n, :csses, :through => :css_nesses, :class_name => "Merbiful::Css", :remote_name => :css
|
70
|
+
|
71
|
+
has n, :js_nesses, :class_name => "Merbiful::Js::Ness"
|
72
|
+
has n, :jses, :through => :js_nesses, :class_name => "Merbiful::Js", :remote_name => :js
|
73
|
+
|
74
|
+
before :save do
|
75
|
+
clear_cache(page.path) if page.latest
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_css(css)
|
79
|
+
Merbiful::Css::Ness.new(:css => css, :page_version => self).save
|
80
|
+
end
|
81
|
+
|
82
|
+
def remove_css(css)
|
83
|
+
css_nesses.first(:css_id => css.id).destroy
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_js(js)
|
87
|
+
Merbiful::Js::Ness.new(:js => js, :page_version => self).save
|
88
|
+
end
|
89
|
+
|
90
|
+
def remove_js(js)
|
91
|
+
js_nesses.first(:js_id => js.id).destroy
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
module Merbiful
|
3
|
+
|
4
|
+
class Page
|
5
|
+
|
6
|
+
class NoSuchFilterError < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
include DataMapper::Resource
|
10
|
+
include DataMapper::Validate
|
11
|
+
include Merbiful::Body
|
12
|
+
|
13
|
+
validates_is_unique :version, :scope => [:path]
|
14
|
+
|
15
|
+
property :id, Serial
|
16
|
+
property :version, Integer, :index => true
|
17
|
+
property :body, DataMapper::Types::Text
|
18
|
+
property :filter, DataMapper::Types::Text
|
19
|
+
property :path, DataMapper::Types::Text, :index => true
|
20
|
+
property :position, Integer
|
21
|
+
property :created_at, DateTime
|
22
|
+
property :updated_at, DateTime
|
23
|
+
property :title, DataMapper::Types::Text
|
24
|
+
property :keywords, DataMapper::Types::Text
|
25
|
+
property :parent_path, DataMapper::Types::Text
|
26
|
+
property :layout_id, Integer
|
27
|
+
|
28
|
+
belongs_to :layout, :class_name => "Merbiful::Layout"
|
29
|
+
|
30
|
+
before :save do
|
31
|
+
last_version = self.class.first(:path => self.path, :order => [:version.desc])
|
32
|
+
if last_version.nil?
|
33
|
+
self.version = 0
|
34
|
+
else
|
35
|
+
self.version = last_version.version + 1
|
36
|
+
end
|
37
|
+
if self.position.nil?
|
38
|
+
last_position = self.class.first(:parent_path => self.parent_path, :path.not => self.path)
|
39
|
+
if last_position.nil?
|
40
|
+
self.position = 0
|
41
|
+
else
|
42
|
+
self.position = last_position.position + 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
if self.path.nil?
|
46
|
+
self.path = "/"
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def children
|
52
|
+
Page.find_by_sql(["SELECT id FROM merbiful_pages WHERE parent_path = ? GROUP BY path ORDER BY version DESC", self.path])
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
|
2
|
+
module Merbiful
|
3
|
+
|
4
|
+
module RelativeTimeHelpers
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :time_class
|
8
|
+
attr_accessor :time_output
|
9
|
+
end
|
10
|
+
|
11
|
+
self.time_class = Time
|
12
|
+
self.time_output = {
|
13
|
+
:today => 'today',
|
14
|
+
:yesterday => 'yesterday',
|
15
|
+
:tomorrow => 'tomorrow',
|
16
|
+
:initial_format => '%b %d',
|
17
|
+
:year_format => ', %Y'
|
18
|
+
}
|
19
|
+
|
20
|
+
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
|
21
|
+
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
22
|
+
to_time = to_time.to_time if to_time.respond_to?(:to_time)
|
23
|
+
distance_in_minutes = (((to_time - from_time).abs)/60).round
|
24
|
+
distance_in_seconds = ((to_time - from_time).abs).round
|
25
|
+
|
26
|
+
case distance_in_minutes
|
27
|
+
when 0..1
|
28
|
+
return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
|
29
|
+
case distance_in_seconds
|
30
|
+
when 0..4 then 'less than 5 seconds'
|
31
|
+
when 5..9 then 'less than 10 seconds'
|
32
|
+
when 10..19 then 'less than 20 seconds'
|
33
|
+
when 20..39 then 'half a minute'
|
34
|
+
when 40..59 then 'less than a minute'
|
35
|
+
else '1 minute'
|
36
|
+
end
|
37
|
+
|
38
|
+
when 2..44 then "#{distance_in_minutes} minutes"
|
39
|
+
when 45..89 then 'about 1 hour'
|
40
|
+
when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
|
41
|
+
when 1440..2879 then '1 day'
|
42
|
+
when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
|
43
|
+
when 43200..86399 then 'about 1 month'
|
44
|
+
when 86400..525599 then "#{(distance_in_minutes / 43200).round} months"
|
45
|
+
when 525600..1051199 then 'about 1 year'
|
46
|
+
else "over #{(distance_in_minutes / 525600).round} years"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def time_ago_in_words(from_time, include_seconds = false)
|
51
|
+
distance_of_time_in_words(from_time, Time.now, include_seconds)
|
52
|
+
end
|
53
|
+
|
54
|
+
def relative_date(time)
|
55
|
+
date = time.to_date
|
56
|
+
today = time_class.now.to_date
|
57
|
+
if date == today
|
58
|
+
time_output[:today]
|
59
|
+
elsif date == (today - 1)
|
60
|
+
time_output[:yesterday]
|
61
|
+
elsif date == (today + 1)
|
62
|
+
time_output[:tomorrow]
|
63
|
+
else
|
64
|
+
fmt = time_output[:initial_format].dup
|
65
|
+
fmt << time_output[:year_format] unless date.year == today.year
|
66
|
+
time.strftime_ordinalized(fmt)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def relative_date_span(times)
|
71
|
+
times = [times.first, times.last].collect!(&:to_date)
|
72
|
+
times.sort!
|
73
|
+
if times.first == times.last
|
74
|
+
relative_date(times.first)
|
75
|
+
else
|
76
|
+
first = times.first; last = times.last; now = time_class.now
|
77
|
+
[first.strftime_ordinalized('%b %d')].tap do |arr|
|
78
|
+
arr << ", #{first.year}" unless first.year == last.year
|
79
|
+
arr << ' - '
|
80
|
+
arr << last.strftime('%b') << ' ' unless first.year == last.year && first.month == last.month
|
81
|
+
arr << last.day.ordinalize
|
82
|
+
arr << ", #{last.year}" unless first.year == last.year && last.year == now.year
|
83
|
+
end.to_s
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def relative_time_span(times)
|
88
|
+
times = [times.first, times.last].collect!(&:to_time)
|
89
|
+
times.sort!
|
90
|
+
if times.first == times.last
|
91
|
+
"#{prettier_time(times.first)} #{relative_date(times.first)}"
|
92
|
+
elsif times.first.to_date == times.last.to_date
|
93
|
+
same_half = (times.first.hour/12 == times.last.hour/12)
|
94
|
+
"#{prettier_time(times.first, !same_half)} - #{prettier_time(times.last)} #{relative_date(times.first)}"
|
95
|
+
|
96
|
+
else
|
97
|
+
first = times.first; last = times.last; now = time_class.now
|
98
|
+
[prettier_time(first)].tap do |arr|
|
99
|
+
arr << ' '
|
100
|
+
arr << first.strftime_ordinalized('%b %d')
|
101
|
+
arr << ", #{first.year}" unless first.year == last.year
|
102
|
+
arr << ' - '
|
103
|
+
arr << prettier_time(last)
|
104
|
+
arr << ' '
|
105
|
+
arr << last.strftime('%b') << ' ' unless first.year == last.year && first.month == last.month
|
106
|
+
arr << last.day.ordinalize
|
107
|
+
arr << ", #{last.year}" unless first.year == last.year && last.year == now.year
|
108
|
+
end.to_s
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def prettier_time(time, ampm=true)
|
113
|
+
time.strftime("%I:%M#{" %p" if ampm}").sub(/^0/, '')
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Merbiful
|
2
|
+
|
3
|
+
module RelativeTimeHelpers
|
4
|
+
mattr_accessor :time_class
|
5
|
+
mattr_accessor :time_output
|
6
|
+
|
7
|
+
self.time_class = Time
|
8
|
+
self.time_output = {
|
9
|
+
:today => 'today',
|
10
|
+
:yesterday => 'yesterday',
|
11
|
+
:tomorrow => 'tomorrow',
|
12
|
+
:initial_format => '%b %d',
|
13
|
+
:year_format => ', %Y'
|
14
|
+
}
|
15
|
+
|
16
|
+
def relative_date(time)
|
17
|
+
date = time.to_date
|
18
|
+
today = time_class.now.to_date
|
19
|
+
if date == today
|
20
|
+
time_output[:today]
|
21
|
+
elsif date == (today - 1)
|
22
|
+
time_output[:yesterday]
|
23
|
+
elsif date == (today + 1)
|
24
|
+
time_output[:tomorrow]
|
25
|
+
else
|
26
|
+
fmt = time_output[:initial_format].dup
|
27
|
+
fmt << time_output[:year_format] unless date.year == today.year
|
28
|
+
time.strftime_ordinalized(fmt)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def relative_date_span(times)
|
33
|
+
times = [times.first, times.last].collect!(&:to_date)
|
34
|
+
times.sort!
|
35
|
+
if times.first == times.last
|
36
|
+
relative_date(times.first)
|
37
|
+
else
|
38
|
+
first = times.first; last = times.last; now = time_class.now
|
39
|
+
[first.strftime_ordinalized('%b %d')].tap do |arr|
|
40
|
+
arr << ", #{first.year}" unless first.year == last.year
|
41
|
+
arr << ' - '
|
42
|
+
arr << last.strftime('%b') << ' ' unless first.year == last.year && first.month == last.month
|
43
|
+
arr << last.day.ordinalize
|
44
|
+
arr << ", #{last.year}" unless first.year == last.year && last.year == now.year
|
45
|
+
end.to_s
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def relative_time_span(times)
|
50
|
+
times = [times.first, times.last].collect!(&:to_time)
|
51
|
+
times.sort!
|
52
|
+
if times.first == times.last
|
53
|
+
"#{prettier_time(times.first)} #{relative_date(times.first)}"
|
54
|
+
elsif times.first.to_date == times.last.to_date
|
55
|
+
same_half = (times.first.hour/12 == times.last.hour/12)
|
56
|
+
"#{prettier_time(times.first, !same_half)} - #{prettier_time(times.last)} #{relative_date(times.first)}"
|
57
|
+
|
58
|
+
else
|
59
|
+
first = times.first; last = times.last; now = time_class.now
|
60
|
+
[prettier_time(first)].tap do |arr|
|
61
|
+
arr << ' '
|
62
|
+
arr << first.strftime_ordinalized('%b %d')
|
63
|
+
arr << ", #{first.year}" unless first.year == last.year
|
64
|
+
arr << ' - '
|
65
|
+
arr << prettier_time(last)
|
66
|
+
arr << ' '
|
67
|
+
arr << last.strftime('%b') << ' ' unless first.year == last.year && first.month == last.month
|
68
|
+
arr << last.day.ordinalize
|
69
|
+
arr << ", #{last.year}" unless first.year == last.year && last.year == now.year
|
70
|
+
end.to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def prettier_time(time, ampm=true)
|
75
|
+
time.strftime("%I:%M#{" %p" if ampm}").sub(/^0/, '')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
Merb.logger.info("Compiling merbiful routes...")
|
3
|
+
Merb::Router.append do |r|
|
4
|
+
r.match("/merbiful_admin").to(:controller => "admin", :namespace => "merbiful", :action => "index").name(:merbiful_admin_index)
|
5
|
+
r.match("/merbiful_admin/:action").to(:controller => "admin", :namespace => "merbiful").name(:merbiful_admin)
|
6
|
+
r.match("/stylesheets/admin").to(:controller => "admin", :namespace => "merbiful", :action => "render_css").name(:merbiful_admin_css)
|
7
|
+
r.match("/stylesheets/:id").to(:controller => "controller", :namespace => "merbiful", :action => "css")
|
8
|
+
r.match("/javascripts/:id").to(:controller => "controller", :namespace => "merbiful", :action => "js")
|
9
|
+
r.match(/(.*)/).to(:controller => "controller", :namespace => "merbiful", :action => "display", :what => "[1]")
|
10
|
+
end
|
11
|
+
|
12
|
+
module Merbiful
|
13
|
+
|
14
|
+
PREPEND_ROUTES = Merb::Router.routes[0..4]
|
15
|
+
APPEND_ROUTES = Merb::Router.routes[5..-1]
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
module Merb
|
20
|
+
|
21
|
+
class Router
|
22
|
+
|
23
|
+
class << self
|
24
|
+
|
25
|
+
alias :merbiful_old_prepare :prepare
|
26
|
+
|
27
|
+
def prepare(first = [], last = [], &block)
|
28
|
+
merbiful_old_prepare(first + ::Merbiful::PREPEND_ROUTES, last + ::Merbiful::APPEND_ROUTES, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
alias :merbiful_old_compile :compile
|
32
|
+
|
33
|
+
def compile
|
34
|
+
merbiful_old_compile unless compiled_statement.blank?
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
module Merbiful
|
3
|
+
|
4
|
+
class Page
|
5
|
+
|
6
|
+
class NoSuchFilterError < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
include DataMapper::Resource
|
10
|
+
include DataMapper::Validate
|
11
|
+
include Merbiful::Body
|
12
|
+
|
13
|
+
validates_is_unique :version, :scope => [:path]
|
14
|
+
|
15
|
+
property :id, Serial
|
16
|
+
property :version, Integer, :index => true
|
17
|
+
property :body, DataMapper::Types::Text
|
18
|
+
property :filter, DataMapper::Types::Text
|
19
|
+
property :path, DataMapper::Types::Text, :index => true
|
20
|
+
property :position, Integer
|
21
|
+
property :created_at, DateTime
|
22
|
+
property :updated_at, DateTime
|
23
|
+
property :title, DataMapper::Types::Text
|
24
|
+
property :keywords, DataMapper::Types::Text
|
25
|
+
property :parent_path, DataMapper::Types::Text
|
26
|
+
property :layout_id, Integer
|
27
|
+
|
28
|
+
before :save do
|
29
|
+
if self.position.nil?
|
30
|
+
last_position = self.class.first(:parent_path => self.parent_path, :path.not => self.path)
|
31
|
+
if last_position.nil?
|
32
|
+
self.position = 0
|
33
|
+
else
|
34
|
+
self.position = last_position.position + 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
if self.path.nil?
|
38
|
+
self.path = "/"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|