documentation 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/documentation/link.svg +28 -0
  3. data/app/assets/images/documentation/logo-black.svg +23 -0
  4. data/app/assets/images/documentation/logo-white.svg +23 -0
  5. data/app/assets/images/documentation/page.svg +16 -0
  6. data/app/assets/images/documentation/pin.svg +15 -0
  7. data/app/assets/images/documentation/recommendation.svg +11 -0
  8. data/app/assets/images/documentation/search.svg +10 -0
  9. data/app/assets/images/documentation/unhappy.svg +15 -0
  10. data/app/assets/images/documentation/warning.svg +16 -0
  11. data/app/assets/javascripts/documentation/application.coffee +14 -0
  12. data/app/assets/javascripts/documentation/jquery-ui.js +4146 -0
  13. data/app/assets/javascripts/documentation/jquery.autosize.js +263 -0
  14. data/app/assets/stylesheets/documentation/application.scss +320 -0
  15. data/app/assets/stylesheets/documentation/markdown.scss +168 -0
  16. data/app/assets/stylesheets/documentation/page_form.scss +38 -0
  17. data/app/assets/stylesheets/documentation/reset.scss +101 -0
  18. data/app/controllers/documentation/application_controller.rb +21 -0
  19. data/app/controllers/documentation/pages_controller.rb +74 -0
  20. data/app/helpers/documentation/application_helper.rb +13 -0
  21. data/app/models/documentation/page.rb +213 -0
  22. data/app/views/documentation/pages/_admin_buttons.html.haml +18 -0
  23. data/app/views/documentation/pages/form.html.haml +12 -0
  24. data/app/views/documentation/pages/index.html.haml +13 -0
  25. data/app/views/documentation/pages/positioning.html.haml +22 -0
  26. data/app/views/documentation/pages/search.html.haml +26 -0
  27. data/app/views/documentation/pages/show.html.haml +14 -0
  28. data/app/views/documentation/shared/access_denied.html.haml +10 -0
  29. data/app/views/documentation/shared/not_found.html.haml +10 -0
  30. data/app/views/layouts/documentation/_header.html.haml +3 -0
  31. data/app/views/layouts/documentation/_search.html.haml +5 -0
  32. data/app/views/layouts/documentation/application.html.haml +18 -0
  33. data/config/locales/en.yml +56 -0
  34. data/config/routes.rb +10 -0
  35. data/db/migrate/20140711185212_create_documentation_pages.rb +10 -0
  36. data/db/seeds.rb +15 -0
  37. data/lib/documentation.rb +16 -0
  38. data/lib/documentation/authorizer.rb +52 -0
  39. data/lib/documentation/config.rb +31 -0
  40. data/lib/documentation/engine.rb +29 -0
  41. data/lib/documentation/errors.rb +7 -0
  42. data/lib/documentation/generators/setup_generator.rb +13 -0
  43. data/lib/documentation/markdown_renderer.rb +62 -0
  44. data/lib/documentation/search_result.rb +84 -0
  45. data/lib/documentation/searchers/abstract.rb +47 -0
  46. data/lib/documentation/searchers/simple.rb +40 -0
  47. data/lib/documentation/version.rb +1 -1
  48. data/lib/documentation/view_helpers.rb +113 -0
  49. data/lib/tasks/documentation.rake +6 -0
  50. metadata +219 -3
@@ -0,0 +1,168 @@
1
+ div.documentationMarkdown {
2
+ a { color:#35A4D4; text-decoration:none; border-bottom:1px solid #35A4D4; font-weight:600;}
3
+
4
+ h1, h2 { font-size:1.6em; font-weight:300; margin:20px 0; border-bottom:1px solid #aecdda; padding-bottom:2px; color:#35A4D4;}
5
+ h3 { font-size:1.3em; font-weight:500; margin:20px 0; }
6
+ h4 { font-size:1.1em; font-weight:500; margin:20px 0;}
7
+ h5 { font-size:1.1em; font-weight:500; margin:20px 0;}
8
+
9
+ p { margin:20px 0; line-height:1.8;}
10
+
11
+ ul, ol { line-height:1.8em; margin:20px 0; margin-left:40px; }
12
+ ul li { background:image-url('documentation/pin.svg') no-repeat 0 5px; background-size:13px; padding-left:25px;}
13
+ ol { margin-left:65px;}
14
+ ol li { margin-bottom:20px;padding-left:15px;}
15
+ ol li:last-child { margin-bottom:0; }
16
+ ul.pages {
17
+ overflow:hidden;
18
+ li { background:image-url('documentation/page.svg') no-repeat 0 5px; background-size:13px; padding-left:25px; width:45%; float:left; margin-bottom:5px;}
19
+ }
20
+
21
+ h2, h3, h4, h5 {
22
+ &:hover a.anchor { display:inline-block;}
23
+ }
24
+
25
+ a.anchor { display:none; float:right; border:0; color:#999; width:16px; height:16px; background:image-url('documentation/link.svg'); opacity:0.6; background-size:16px; text-indent:-40000px;}
26
+
27
+ p.recommendation {
28
+ background:image-url('documentation/recommendation.svg') #F5F7FB no-repeat 20px 16px;
29
+ background-size:20px;
30
+ border:1px solid #E4E7ED;
31
+ padding:15px;
32
+ margin-left:0;
33
+ margin-right:0;
34
+ padding-left:55px;
35
+ }
36
+
37
+ p.warning {
38
+ background:image-url('documentation/warning.svg') #fffbec no-repeat 20px 18px;
39
+ background-size:20px;
40
+ border:1px solid #edda8c;
41
+ padding:15px;
42
+ color:#97894f;
43
+ margin-left:0;
44
+ margin-right:0;
45
+ padding-left:55px;
46
+ }
47
+
48
+ p.codeTitle {
49
+ background:#f7f7f7;
50
+ margin-bottom:0;
51
+ line-height:1;
52
+ border-top-left-radius:6px;
53
+ border-top-right-radius:6px;
54
+ padding:15px 20px;
55
+ font-size:0.9em;
56
+ font-weight:500;
57
+ color:#666;
58
+ border:1px solid #ddd;
59
+ border-bottom:0;
60
+ }
61
+
62
+ p.codeTitle + div.highlight pre {
63
+ margin-top:0 !important;
64
+ border-top-left-radius:0;
65
+ border-top-right-radius:0;
66
+ }
67
+
68
+ pre {
69
+ margin:25px 0;
70
+ line-height:1.4;
71
+ padding:20px;
72
+ border-radius:6px;
73
+ overflow-x:auto;
74
+ word-wrap: normal;
75
+ white-space: pre;
76
+ }
77
+
78
+ code { background:#F8F8F8; border:1px solid #ddd; border-radius:4px; padding:0px 5px; margin:0 2px; font-size:0.85em; white-space:pre; word-wrap:none;}
79
+
80
+ .imgcontainer.center {
81
+ display:block;
82
+ margin:0 35px;
83
+ text-align:center;
84
+ img {
85
+ max-width:90%;
86
+ }
87
+ }
88
+
89
+ table {
90
+ margin:25px 0;
91
+ min-width:100%;
92
+ td, th { border:1px solid #E4E7ED; padding:10px;}
93
+ th { background:#F5F7FB; color:#8E9BB4; font-weight:300; text-align:left;}
94
+ }
95
+
96
+ .highlight {
97
+ pre {
98
+ font-family:Consolas, "Liberation Mono", Courier, monospace;
99
+ font-size:15px;
100
+ background: #1d1f21; color: #c5c8c6;
101
+ .hll { background-color: #373b41 }
102
+ .c { color: #969896 } /* Comment */
103
+ .err { color: #cc6666 } /* Error */
104
+ .k { color: #b294bb } /* Keyword */
105
+ .l { color: #de935f } /* Literal */
106
+ .n { color: #c5c8c6 } /* Name */
107
+ .o { color: #8abeb7 } /* Operator */
108
+ .p { color: #c5c8c6 } /* Punctuation */
109
+ .cm { color: #969896 } /* Comment.Multiline */
110
+ .cp { color: #969896 } /* Comment.Preproc */
111
+ .c1 { color: #969896 } /* Comment.Single */
112
+ .cs { color: #969896 } /* Comment.Special */
113
+ .gd { color: #cc6666 } /* Generic.Deleted */
114
+ .ge { font-style: italic } /* Generic.Emph */
115
+ .gh { color: #c5c8c6; font-weight: bold } /* Generic.Heading */
116
+ .gi { color: #b5bd68 } /* Generic.Inserted */
117
+ .gp { color: #969896; font-weight: bold } /* Generic.Prompt */
118
+ .gs { font-weight: bold } /* Generic.Strong */
119
+ .gu { color: #8abeb7; font-weight: bold } /* Generic.Subheading */
120
+ .kc { color: #b294bb } /* Keyword.Constant */
121
+ .kd { color: #b294bb } /* Keyword.Declaration */
122
+ .kn { color: #8abeb7 } /* Keyword.Namespace */
123
+ .kp { color: #b294bb } /* Keyword.Pseudo */
124
+ .kr { color: #b294bb } /* Keyword.Reserved */
125
+ .kt { color: #f0c674 } /* Keyword.Type */
126
+ .ld { color: #b5bd68 } /* Literal.Date */
127
+ .m { color: #de935f } /* Literal.Number */
128
+ .s { color: #b5bd68 } /* Literal.String */
129
+ .na { color: #81a2be } /* Name.Attribute */
130
+ .nb { color: #c5c8c6 } /* Name.Builtin */
131
+ .nc { color: #f0c674 } /* Name.Class */
132
+ .no { color: #cc6666 } /* Name.Constant */
133
+ .nd { color: #8abeb7 } /* Name.Decorator */
134
+ .ni { color: #c5c8c6 } /* Name.Entity */
135
+ .ne { color: #cc6666 } /* Name.Exception */
136
+ .nf { color: #81a2be } /* Name.Function */
137
+ .nl { color: #c5c8c6 } /* Name.Label */
138
+ .nn { color: #f0c674 } /* Name.Namespace */
139
+ .nx { color: #81a2be } /* Name.Other */
140
+ .py { color: #c5c8c6 } /* Name.Property */
141
+ .nt { color: #8abeb7 } /* Name.Tag */
142
+ .nv { color: #cc6666 } /* Name.Variable */
143
+ .ow { color: #8abeb7 } /* Operator.Word */
144
+ .w { color: #c5c8c6 } /* Text.Whitespace */
145
+ .mf { color: #de935f } /* Literal.Number.Float */
146
+ .mh { color: #de935f } /* Literal.Number.Hex */
147
+ .mi { color: #de935f } /* Literal.Number.Integer */
148
+ .mo { color: #de935f } /* Literal.Number.Oct */
149
+ .sb { color: #b5bd68 } /* Literal.String.Backtick */
150
+ .sc { color: #c5c8c6 } /* Literal.String.Char */
151
+ .sd { color: #969896 } /* Literal.String.Doc */
152
+ .s2 { color: #b5bd68 } /* Literal.String.Double */
153
+ .se { color: #de935f } /* Literal.String.Escape */
154
+ .sh { color: #b5bd68 } /* Literal.String.Heredoc */
155
+ .si { color: #de935f } /* Literal.String.Interpol */
156
+ .sx { color: #b5bd68 } /* Literal.String.Other */
157
+ .sr { color: #b5bd68 } /* Literal.String.Regex */
158
+ .s1 { color: #b5bd68 } /* Literal.String.Single */
159
+ .ss { color: #b5bd68 } /* Literal.String.Symbol */
160
+ .bp { color: #c5c8c6 } /* Name.Builtin.Pseudo */
161
+ .vc { color: #cc6666 } /* Name.Variable.Class */
162
+ .vg { color: #cc6666 } /* Name.Variable.Global */
163
+ .vi { color: #cc6666 } /* Name.Variable.Instance */
164
+ .il { color: #de935f } /* Literal.Number.Integer.Long */
165
+ }
166
+ }
167
+
168
+ }
@@ -0,0 +1,38 @@
1
+ form.pageForm {
2
+ padding:15px 35px 25px 35px;
3
+ margin-top:10px;
4
+ input[type=text], textarea {
5
+ width:100%;
6
+ border:1px solid #c7cfde;
7
+ padding:6px;
8
+ background:#F5F7FB;
9
+ }
10
+
11
+ p.title {
12
+ margin-bottom:15px;
13
+ input { font-size:1.3em; font-weight:normal; padding:10px;}
14
+ }
15
+
16
+ p.content {
17
+ textarea {
18
+ width:100%;
19
+ min-height:300px;
20
+ font-size:0.9em;
21
+ line-height:1.4;
22
+ padding:10px;
23
+ font-family:'Consolas', Monaco, 'Courier New', Courier, fixed;
24
+ resize:none;
25
+ }
26
+ }
27
+
28
+ dl {
29
+ margin:15px 0;
30
+ dt { width:120px; float:left; color:#999;padding-top:6px;}
31
+ dd { margin-left:160px; }
32
+ dd input { width:100%; font-size:1.1em;}
33
+ }
34
+
35
+ p.submit {
36
+ text-align:right;
37
+ }
38
+ }
@@ -0,0 +1,101 @@
1
+ html, body, body div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, figure, footer, header, hgroup, menu, nav, section, time, mark, audio, video {
2
+ margin: 0;
3
+ padding: 0;
4
+ border: 0;
5
+ outline: 0;
6
+ font-size: 100%;
7
+ letter-spacing:0;
8
+ vertical-align: baseline;
9
+ background: transparent;
10
+ font-weight:normal;
11
+ }
12
+
13
+ article, aside, figure, footer, header, hgroup, nav, section {display: block;}
14
+
15
+ img,object,embed {max-width: 100%;}
16
+ ul {list-style: none;}
17
+ blockquote, q {quotes: none;}
18
+ b,strong { font-weight: bold;}
19
+ blockquote:before, blockquote:after, q:before, q:after {content: ''; content: none;}
20
+
21
+ a {margin: 0; padding: 0; font-size: 100%; vertical-align: baseline; background: transparent;}
22
+
23
+ del {text-decoration: line-through;}
24
+
25
+ abbr[title], dfn[title] {border-bottom: 1px dotted #000; cursor: help;}
26
+
27
+ /* tables still need cellspacing="0" in the markup */
28
+ table {border-collapse: collapse; border-spacing: 0;}
29
+ th {font-weight: bold; vertical-align: bottom;}
30
+ td {font-weight: normal; vertical-align: top;}
31
+
32
+ hr {display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0;}
33
+
34
+ input, select {vertical-align: middle;}
35
+
36
+ pre {
37
+ white-space: pre; /* CSS2 */
38
+ white-space: pre-wrap; /* CSS 2.1 */
39
+ white-space: pre-line; /* CSS 3 (and 2.1 as well, actually) */
40
+ word-wrap: break-word; /* IE */
41
+ }
42
+
43
+ input[type="radio"] {vertical-align: text-bottom;}
44
+ input[type="checkbox"] {vertical-align: bottom; *vertical-align: baseline;}
45
+ .ie6 input {vertical-align: text-bottom;}
46
+
47
+ select, input, textarea {font: 99% sans-serif;}
48
+
49
+ table {font-size: inherit; font: 100%;}
50
+
51
+ /* Accessible focus treatment
52
+ people.opera.com/patrickl/experiments/keyboard/test */
53
+ a:hover, a:active {outline: none;}
54
+
55
+ small {font-size: 85%;}
56
+
57
+ strong, th {font-weight: bold;}
58
+
59
+ td, td img {vertical-align: top;}
60
+
61
+ /* Make sure sup and sub don't screw with your line-heights
62
+ gist.github.com/413930 */
63
+ sub, sup {font-size: 75%; line-height: 0; position: relative;}
64
+ sup {top: -0.5em;}
65
+ sub {bottom: -0.25em;}
66
+
67
+ /* standardize any monospaced elements */
68
+ pre, code, kbd, samp {font-family: monospace, sans-serif;}
69
+
70
+ /* hand cursor on clickable elements */
71
+ .clickable,
72
+ label,
73
+ input[type=button],
74
+ input[type=submit],
75
+ button {cursor: pointer;}
76
+
77
+ /* Webkit browsers add a 2px margin outside the chrome of form elements */
78
+ button, input, select, textarea {margin: 0;}
79
+
80
+ /* make buttons play nice in IE */
81
+ button {width: auto; overflow: visible;}
82
+
83
+ /* scale images in IE7 more attractively */
84
+ .ie7 img {-ms-interpolation-mode: bicubic;}
85
+
86
+ /* prevent BG image flicker upon hover */
87
+ .ie6 html {filter: expression(document.execCommand("BackgroundImageCache", false, true));}
88
+
89
+ /* let's clear some floats */
90
+ .clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; }
91
+ .clearfix:after { clear: both; }
92
+ .clearfix { zoom: 1; }
93
+
94
+ select, input, textarea, a { outline: none;}
95
+
96
+
97
+ input, textarea {
98
+ -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
99
+ -moz-box-sizing: border-box; /* Firefox, other Gecko */
100
+ box-sizing: border-box; /* Opera/IE 8+ */
101
+ }
@@ -0,0 +1,21 @@
1
+ module Documentation
2
+ class ApplicationController < ActionController::Base
3
+
4
+ rescue_from Documentation::AccessDeniedError do |e|
5
+ render :template => 'documentation/shared/access_denied', :layout => false
6
+ end
7
+
8
+ rescue_from ActiveRecord::RecordNotFound do |e|
9
+ render :template => 'documentation/shared/not_found', :layout => false
10
+ end
11
+
12
+ private
13
+
14
+ def authorizer
15
+ @authorizer ||= Documentation.config.authorizer.new(self)
16
+ end
17
+
18
+ helper_method :authorizer
19
+
20
+ end
21
+ end
@@ -0,0 +1,74 @@
1
+ module Documentation
2
+ class PagesController < Documentation::ApplicationController
3
+
4
+ before_filter :find_page, :only => [:show, :edit, :new, :destroy, :positioning]
5
+
6
+ def show
7
+ authorizer.check! :view_page, @page
8
+ end
9
+
10
+ def edit
11
+ authorizer.check! :edit_page, @page
12
+
13
+ if request.patch?
14
+ if @page.update_attributes(safe_params)
15
+ redirect_to page_path(@page.full_permalink), :notice => "Page has been saved successfully."
16
+ return
17
+ end
18
+ end
19
+ render :action => "form"
20
+ end
21
+
22
+ def new
23
+ authorizer.check! :add_page, @page
24
+
25
+ parent = @page
26
+ @page = Page.new(:title => "Untitled Page")
27
+ if @page.parent = parent
28
+ @page.parents = parent.breadcrumb
29
+ end
30
+
31
+ if request.post?
32
+ @page.attributes = safe_params
33
+ if @page.save
34
+ redirect_to page_path(@page.full_permalink), :notice => "Page created successfully"
35
+ return
36
+ end
37
+ end
38
+ render :action => "form"
39
+ end
40
+
41
+ def destroy
42
+ authorizer.check! :delete_page, @page
43
+ @page.destroy
44
+ redirect_to @page.parent ? page_path(@page.parent.full_permalink) : root_path, :notice => "Page has been removed successfully."
45
+ end
46
+
47
+ def positioning
48
+ authorizer.check! :reposition_page, @page
49
+ @pages = @page ? @page.children : Page.roots
50
+ if request.post?
51
+ Page.reorder(@page, params[:order])
52
+ render :json => {:status => 'ok'}
53
+ end
54
+ end
55
+
56
+ def search
57
+ authorizer.check! :search
58
+ @result = Documentation::Page.search(params[:query], :page => params[:page].blank? ? 1 : params[:page].to_i)
59
+ end
60
+
61
+ private
62
+
63
+ def find_page
64
+ if params[:path]
65
+ @page = Page.find_from_path(params[:path])
66
+ end
67
+ end
68
+
69
+ def safe_params
70
+ params.require(:page).permit(:title, :permalink, :content, :favourite)
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,13 @@
1
+ module Documentation
2
+ module ApplicationHelper
3
+
4
+ include Documentation::ViewHelpers
5
+
6
+ def flash_messages
7
+ flashes = flash.collect do |key,msg|
8
+ content_tag :div, content_tag(:p, h(msg)), :id => "flash-#{key}"
9
+ end.join.html_safe
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,213 @@
1
+ module Documentation
2
+ class Page < ActiveRecord::Base
3
+
4
+ validates :title, :presence => true
5
+ validates :position, :presence => true
6
+ validates :permalink, :presence => true, :uniqueness => {:scope => :parent_id}
7
+
8
+ default_scope -> { order(:position) }
9
+ scope :roots, -> { where(:parent_id => nil) }
10
+
11
+ belongs_to :parent, :class_name => 'Documentation::Page', :foreign_key => 'parent_id'
12
+
13
+ before_validation do
14
+ if self.position.blank?
15
+ last_position = self.class.unscoped.where(:parent_id => self.parent_id).order(:position => :desc).first
16
+ self.position = last_position ? last_position.position + 1 : 1
17
+ end
18
+ end
19
+
20
+ before_validation :set_permalink
21
+ before_save :compile_content
22
+
23
+ #
24
+ # Ensure the page is updated in the index after saving/destruction
25
+ #
26
+ after_commit :index, :on => [:create, :update]
27
+ after_commit :delete_from_index, :on => :destroy
28
+
29
+ #
30
+ # Store all the parents of this object. THis is automatically populated when it is loaded
31
+ # from a path
32
+ #
33
+ attr_accessor :parents
34
+
35
+ #
36
+ # Set the permalink for this page
37
+ #
38
+ def set_permalink
39
+ proposed_permalink = self.title.parameterize
40
+ index = 1
41
+ while self.permalink.blank?
42
+ if self.class.where(:permalink => proposed_permalink, :parent_id => self.parent_id).exists?
43
+ index += 1
44
+ proposed_permalink = self.title.parameterize + "-#{index}"
45
+ else
46
+ self.permalink = proposed_permalink
47
+ end
48
+ end
49
+ end
50
+
51
+ #
52
+ # Return a default empty array for parents
53
+ #
54
+ def parents
55
+ @parents ||= self.parent ? [self.parent.parents, self.parent].flatten : []
56
+ end
57
+
58
+ #
59
+ # Return a full breadcrumb to this page (as it has been loaded)
60
+ #
61
+ def breadcrumb
62
+ @breadcrumb ||= [parents, new_record? ? nil : self].flatten.compact
63
+ end
64
+
65
+ #
66
+ # Return the path where this page can be viewed in the site
67
+ #
68
+ def preview_path
69
+ if path = Documentation.config.preview_path_prefix
70
+ "#{path}#{full_permalink}"
71
+ else
72
+ nil
73
+ end
74
+ end
75
+
76
+ #
77
+ # Return a full permalink tot his page
78
+ #
79
+ def full_permalink
80
+ @full_permalink ||= begin
81
+ if parents.empty?
82
+ self.permalink
83
+ else
84
+ previous = breadcrumb.compact.map(&:permalink).compact
85
+ previous.empty? ? self.permalink : previous.join('/')
86
+ end
87
+ end
88
+ end
89
+
90
+ #
91
+ # Return all child pages
92
+ #
93
+ def children
94
+ @children ||= begin
95
+ if self.new_record?
96
+ []
97
+ else
98
+ children = self.class.where(:parent_id => self.id)
99
+ children.each { |c| c.parents = [parents, self].flatten }
100
+ children
101
+ end
102
+ end
103
+ end
104
+
105
+ #
106
+ # Does this page have children?
107
+ #
108
+ def has_children?
109
+ !children.empty?
110
+ end
111
+
112
+ #
113
+ # Return pages which should be included in the navigation
114
+ #
115
+ def navigation
116
+ if has_children?
117
+ root_parent = parents[-1]
118
+ if root_parent.nil?
119
+ pages = self.class.roots
120
+ else
121
+ pages = (root_parent || self).children
122
+ end
123
+ else
124
+ root_parent = parents[-2] || parents[-1]
125
+ if root_parent.nil? || (root_parent.parent.nil? && parents.size <= 1)
126
+ pages = self.class.roots
127
+ else
128
+ pages = (root_parent || self).children
129
+ end
130
+ end
131
+
132
+
133
+ pages.map do |c|
134
+ child_pages = []
135
+ child_pages = c.children if breadcrumb.include?(c)
136
+ [c, child_pages]
137
+ end
138
+ end
139
+
140
+ #
141
+ # Create the compiled content
142
+ #
143
+ def compile_content
144
+ mr = Documentation::MarkdownRenderer.new
145
+ mr.page = self
146
+ rc = Redcarpet::Markdown.new(mr, :space_after_headers => true, :fenced_code_blocks => true, :no_intra_emphasis => true, :highlight => true)
147
+ self.compiled_content = rc.render(self.content.to_s).html_safe
148
+ end
149
+
150
+ #
151
+ # Index this page
152
+ #
153
+ def index
154
+ if searcher = Documentation.config.searcher
155
+ searcher.index(self)
156
+ end
157
+ end
158
+
159
+ #
160
+ # Delete this page from the index
161
+ #
162
+ def delete_from_index
163
+ if searcher = Documentation.config.searcher
164
+ searcher.delete(self)
165
+ end
166
+ end
167
+
168
+ #
169
+ # Find a page using the searcher if one exists otherwise just fall back to AR
170
+ # searching. Returns a Documentation::SearchResult object.
171
+ #
172
+ def self.search(query, options = {})
173
+ if searcher = Documentation.config.searcher
174
+ searcher.search(query, options)
175
+ end
176
+ end
177
+
178
+ #
179
+ # Find a page by passing a path to the page from the root of the
180
+ # site
181
+ #
182
+ def self.find_from_path(path_string)
183
+ raise ActiveRecord::RecordNotFound, "Couldn't find page without a path" if path_string.blank?
184
+ path_parts = path_string.split('/')
185
+ path = []
186
+ path_parts.each_with_index do |p, i|
187
+ page = self.where(:parent_id => (path.last ? path.last.id : nil)).find_by_permalink(p)
188
+ if page
189
+ page.parents = path.dup
190
+ page.parent = path.last
191
+ path << page
192
+ else
193
+ raise ActiveRecord::RecordNotFound, "Couldn't find page at #{path_string}"
194
+ end
195
+ end
196
+ path.last
197
+ end
198
+
199
+ #
200
+ # Reorder pgaes
201
+ #
202
+ def self.reorder(parent, order = [])
203
+ order = order.map(&:to_i)
204
+ order = self.where(:parent_id => parent.id).map(&:id) if order.empty?
205
+ order.each_with_index do |id, index|
206
+ command = self.find_by_id!(id)
207
+ command.position = index + 1
208
+ command.save
209
+ end
210
+ end
211
+
212
+ end
213
+ end