local_documentation 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/app/assets/images/documentation/link.svg +28 -0
  4. data/app/assets/images/documentation/logo-black.svg +23 -0
  5. data/app/assets/images/documentation/logo-white.svg +23 -0
  6. data/app/assets/images/documentation/page.svg +16 -0
  7. data/app/assets/images/documentation/pin.svg +15 -0
  8. data/app/assets/images/documentation/recommendation.svg +11 -0
  9. data/app/assets/images/documentation/search.svg +10 -0
  10. data/app/assets/images/documentation/unhappy.svg +15 -0
  11. data/app/assets/images/documentation/warning.svg +16 -0
  12. data/app/assets/javascripts/documentation/application.coffee +78 -0
  13. data/app/assets/javascripts/documentation/jquery-ui.js +4146 -0
  14. data/app/assets/javascripts/documentation/jquery.autosize.js +263 -0
  15. data/app/assets/stylesheets/documentation/application.scss +322 -0
  16. data/app/assets/stylesheets/documentation/markdown.scss +168 -0
  17. data/app/assets/stylesheets/documentation/page_form.scss +39 -0
  18. data/app/assets/stylesheets/documentation/reset.scss +101 -0
  19. data/app/controllers/documentation/application_controller.rb +27 -0
  20. data/app/controllers/documentation/pages_controller.rb +93 -0
  21. data/app/helpers/documentation/application_helper.rb +13 -0
  22. data/app/models/documentation/page.rb +214 -0
  23. data/app/models/documentation/screenshot.rb +15 -0
  24. data/app/views/documentation/pages/_admin_buttons.html.haml +18 -0
  25. data/app/views/documentation/pages/form.html.haml +16 -0
  26. data/app/views/documentation/pages/index.html.haml +13 -0
  27. data/app/views/documentation/pages/positioning.html.haml +22 -0
  28. data/app/views/documentation/pages/screenshot.html.haml +15 -0
  29. data/app/views/documentation/pages/search.html.haml +12 -0
  30. data/app/views/documentation/pages/show.html.haml +14 -0
  31. data/app/views/documentation/shared/access_denied.html.haml +10 -0
  32. data/app/views/documentation/shared/not_found.html.haml +10 -0
  33. data/app/views/layouts/documentation/_footer.html.haml +0 -0
  34. data/app/views/layouts/documentation/_head.html.haml +0 -0
  35. data/app/views/layouts/documentation/_header.html.haml +3 -0
  36. data/app/views/layouts/documentation/_search.html.haml +5 -0
  37. data/app/views/layouts/documentation/application.html.haml +22 -0
  38. data/config/locales/en.yml +62 -0
  39. data/config/routes.rb +11 -0
  40. data/db/migrate/20140711185212_create_documentation_pages.rb +10 -0
  41. data/db/migrate/20140724111844_create_nifty_attachments_table.rb +16 -0
  42. data/db/migrate/20140724114255_create_documentation_screenshots.rb +7 -0
  43. data/db/seeds.rb +15 -0
  44. data/doc/developers-guide/authorization.md +37 -0
  45. data/doc/developers-guide/building-views/accessing-pages.md +38 -0
  46. data/doc/developers-guide/building-views/helpers.md +105 -0
  47. data/doc/developers-guide/building-views/overview.md +3 -0
  48. data/doc/developers-guide/customization.md +9 -0
  49. data/doc/developers-guide/overview.md +20 -0
  50. data/doc/developers-guide/search-backends.md +17 -0
  51. data/doc/markdown/overview.md +37 -0
  52. data/lib/documentation.rb +20 -0
  53. data/lib/documentation/authorizer.rb +60 -0
  54. data/lib/documentation/config.rb +31 -0
  55. data/lib/documentation/engine.rb +29 -0
  56. data/lib/documentation/errors.rb +7 -0
  57. data/lib/documentation/generators/setup_generator.rb +17 -0
  58. data/lib/documentation/markdown_renderer.rb +62 -0
  59. data/lib/documentation/search_result.rb +84 -0
  60. data/lib/documentation/searchers/abstract.rb +47 -0
  61. data/lib/documentation/searchers/simple.rb +40 -0
  62. data/lib/documentation/version.rb +3 -0
  63. data/lib/documentation/view_helpers.rb +159 -0
  64. data/lib/tasks/documentation.rake +44 -0
  65. metadata +307 -0
@@ -0,0 +1,263 @@
1
+ /*!
2
+ Autosize v1.18.4 - 2014-01-11
3
+ Automatically adjust textarea height based on user input.
4
+ (c) 2014 Jack Moore - http://www.jacklmoore.com/autosize
5
+ license: http://www.opensource.org/licenses/mit-license.php
6
+ */
7
+ (function ($) {
8
+ var
9
+ defaults = {
10
+ className: 'autosizejs',
11
+ append: '',
12
+ callback: false,
13
+ resizeDelay: 10,
14
+ placeholder: true
15
+ },
16
+
17
+ // border:0 is unnecessary, but avoids a bug in Firefox on OSX
18
+ copy = '<textarea tabindex="-1" style="position:absolute; top:-999px; left:0; right:auto; bottom:auto; border:0; padding: 0; -moz-box-sizing:content-box; -webkit-box-sizing:content-box; box-sizing:content-box; word-wrap:break-word; height:0 !important; min-height:0 !important; overflow:hidden; transition:none; -webkit-transition:none; -moz-transition:none;"/>',
19
+
20
+ // line-height is conditionally included because IE7/IE8/old Opera do not return the correct value.
21
+ typographyStyles = [
22
+ 'fontFamily',
23
+ 'fontSize',
24
+ 'fontWeight',
25
+ 'fontStyle',
26
+ 'letterSpacing',
27
+ 'textTransform',
28
+ 'wordSpacing',
29
+ 'textIndent'
30
+ ],
31
+
32
+ // to keep track which textarea is being mirrored when adjust() is called.
33
+ mirrored,
34
+
35
+ // the mirror element, which is used to calculate what size the mirrored element should be.
36
+ mirror = $(copy).data('autosize', true)[0];
37
+
38
+ // test that line-height can be accurately copied.
39
+ mirror.style.lineHeight = '99px';
40
+ if ($(mirror).css('lineHeight') === '99px') {
41
+ typographyStyles.push('lineHeight');
42
+ }
43
+ mirror.style.lineHeight = '';
44
+
45
+ $.fn.autosize = function (options) {
46
+ if (!this.length) {
47
+ return this;
48
+ }
49
+
50
+ options = $.extend({}, defaults, options || {});
51
+
52
+ if (mirror.parentNode !== document.body) {
53
+ $(document.body).append(mirror);
54
+ }
55
+
56
+ return this.each(function () {
57
+ var
58
+ ta = this,
59
+ $ta = $(ta),
60
+ maxHeight,
61
+ minHeight,
62
+ boxOffset = 0,
63
+ callback = $.isFunction(options.callback),
64
+ originalStyles = {
65
+ height: ta.style.height,
66
+ overflow: ta.style.overflow,
67
+ overflowY: ta.style.overflowY,
68
+ wordWrap: ta.style.wordWrap,
69
+ resize: ta.style.resize
70
+ },
71
+ timeout,
72
+ width = $ta.width();
73
+
74
+ if ($ta.data('autosize')) {
75
+ // exit if autosize has already been applied, or if the textarea is the mirror element.
76
+ return;
77
+ }
78
+ $ta.data('autosize', true);
79
+
80
+ if ($ta.css('box-sizing') === 'border-box' || $ta.css('-moz-box-sizing') === 'border-box' || $ta.css('-webkit-box-sizing') === 'border-box'){
81
+ boxOffset = $ta.outerHeight() - $ta.height();
82
+ }
83
+
84
+ // IE8 and lower return 'auto', which parses to NaN, if no min-height is set.
85
+ minHeight = Math.max(parseInt($ta.css('minHeight'), 10) - boxOffset || 0, $ta.height());
86
+
87
+ $ta.css({
88
+ overflow: 'hidden',
89
+ overflowY: 'hidden',
90
+ wordWrap: 'break-word', // horizontal overflow is hidden, so break-word is necessary for handling words longer than the textarea width
91
+ resize: ($ta.css('resize') === 'none' || $ta.css('resize') === 'vertical') ? 'none' : 'horizontal'
92
+ });
93
+
94
+ // The mirror width must exactly match the textarea width, so using getBoundingClientRect because it doesn't round the sub-pixel value.
95
+ // window.getComputedStyle, getBoundingClientRect returning a width are unsupported, but also unneeded in IE8 and lower.
96
+ function setWidth() {
97
+ var width;
98
+ var style = window.getComputedStyle ? window.getComputedStyle(ta, null) : false;
99
+
100
+ if (style) {
101
+
102
+ width = ta.getBoundingClientRect().width;
103
+
104
+ if (width === 0) {
105
+ width = parseInt(style.width,10);
106
+ }
107
+
108
+ $.each(['paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth'], function(i,val){
109
+ width -= parseInt(style[val],10);
110
+ });
111
+ } else {
112
+ width = Math.max($ta.width(), 0);
113
+ }
114
+
115
+ mirror.style.width = width + 'px';
116
+ }
117
+
118
+ function initMirror() {
119
+ var styles = {};
120
+
121
+ mirrored = ta;
122
+ mirror.className = options.className;
123
+ maxHeight = parseInt($ta.css('maxHeight'), 10);
124
+
125
+ // mirror is a duplicate textarea located off-screen that
126
+ // is automatically updated to contain the same text as the
127
+ // original textarea. mirror always has a height of 0.
128
+ // This gives a cross-browser supported way getting the actual
129
+ // height of the text, through the scrollTop property.
130
+ $.each(typographyStyles, function(i,val){
131
+ styles[val] = $ta.css(val);
132
+ });
133
+ $(mirror).css(styles);
134
+
135
+ setWidth();
136
+
137
+ // Chrome-specific fix:
138
+ // When the textarea y-overflow is hidden, Chrome doesn't reflow the text to account for the space
139
+ // made available by removing the scrollbar. This workaround triggers the reflow for Chrome.
140
+ if (window.chrome) {
141
+ var width = ta.style.width;
142
+ ta.style.width = '0px';
143
+ var ignore = ta.offsetWidth;
144
+ ta.style.width = width;
145
+ }
146
+ }
147
+
148
+ // Using mainly bare JS in this function because it is going
149
+ // to fire very often while typing, and needs to very efficient.
150
+ function adjust() {
151
+ var height, original;
152
+
153
+ if (mirrored !== ta) {
154
+ initMirror();
155
+ } else {
156
+ setWidth();
157
+ }
158
+
159
+ if (!ta.value && options.placeholder) {
160
+ // If the textarea is empty, copy the placeholder text into
161
+ // the mirror control and use that for sizing so that we
162
+ // don't end up with placeholder getting trimmed.
163
+ mirror.value = ($(ta).attr("placeholder") || '') + options.append;
164
+ } else {
165
+ mirror.value = ta.value + options.append;
166
+ }
167
+
168
+ mirror.style.overflowY = ta.style.overflowY;
169
+ original = parseInt(ta.style.height,10);
170
+
171
+ // Setting scrollTop to zero is needed in IE8 and lower for the next step to be accurately applied
172
+ mirror.scrollTop = 0;
173
+
174
+ mirror.scrollTop = 9e4;
175
+
176
+ // Using scrollTop rather than scrollHeight because scrollHeight is non-standard and includes padding.
177
+ height = mirror.scrollTop;
178
+
179
+ if (maxHeight && height > maxHeight) {
180
+ ta.style.overflowY = 'scroll';
181
+ height = maxHeight;
182
+ } else {
183
+ ta.style.overflowY = 'hidden';
184
+ if (height < minHeight) {
185
+ height = minHeight;
186
+ }
187
+ }
188
+
189
+ height += boxOffset;
190
+
191
+ if (original !== height) {
192
+ ta.style.height = height + 'px';
193
+ if (callback) {
194
+ options.callback.call(ta,ta);
195
+ }
196
+ }
197
+ }
198
+
199
+ function resize () {
200
+ clearTimeout(timeout);
201
+ timeout = setTimeout(function(){
202
+ var newWidth = $ta.width();
203
+
204
+ if (newWidth !== width) {
205
+ width = newWidth;
206
+ adjust();
207
+ }
208
+ }, parseInt(options.resizeDelay,10));
209
+ }
210
+
211
+ if ('onpropertychange' in ta) {
212
+ if ('oninput' in ta) {
213
+ // Detects IE9. IE9 does not fire onpropertychange or oninput for deletions,
214
+ // so binding to onkeyup to catch most of those occasions. There is no way that I
215
+ // know of to detect something like 'cut' in IE9.
216
+ $ta.on('input.autosize keyup.autosize', adjust);
217
+ } else {
218
+ // IE7 / IE8
219
+ $ta.on('propertychange.autosize', function(){
220
+ if(event.propertyName === 'value'){
221
+ adjust();
222
+ }
223
+ });
224
+ }
225
+ } else {
226
+ // Modern Browsers
227
+ $ta.on('input.autosize', adjust);
228
+ }
229
+
230
+ // Set options.resizeDelay to false if using fixed-width textarea elements.
231
+ // Uses a timeout and width check to reduce the amount of times adjust needs to be called after window resize.
232
+
233
+ if (options.resizeDelay !== false) {
234
+ $(window).on('resize.autosize', resize);
235
+ }
236
+
237
+ // Event for manual triggering if needed.
238
+ // Should only be needed when the value of the textarea is changed through JavaScript rather than user input.
239
+ $ta.on('autosize.resize', adjust);
240
+
241
+ // Event for manual triggering that also forces the styles to update as well.
242
+ // Should only be needed if one of typography styles of the textarea change, and the textarea is already the target of the adjust method.
243
+ $ta.on('autosize.resizeIncludeStyle', function() {
244
+ mirrored = null;
245
+ adjust();
246
+ });
247
+
248
+ $ta.on('autosize.destroy', function(){
249
+ mirrored = null;
250
+ clearTimeout(timeout);
251
+ $(window).off('resize', resize);
252
+ $ta
253
+ .off('autosize')
254
+ .off('.autosize')
255
+ .css(originalStyles)
256
+ .removeData('autosize');
257
+ });
258
+
259
+ // Call adjust in case the textarea already contains text.
260
+ adjust();
261
+ });
262
+ };
263
+ }(window.jQuery || window.$)); // jQuery or jQuery-like library, such as Zepto
@@ -0,0 +1,322 @@
1
+ /*
2
+ *= require documentation/reset
3
+ *= require nifty/dialog
4
+ *= require_self
5
+ *= require documentation/markdown
6
+ *= require documentation/page_form
7
+ */
8
+
9
+ $font: 'Helvetica Neue', Helvetica, Arial, sans-serif;
10
+ input, textarea { font-family:$font;}
11
+
12
+ body {
13
+ font-family: $font;
14
+ font-size:14px;
15
+ }
16
+
17
+ //
18
+ // Main page header
19
+ //
20
+ header {
21
+ background:#354050;
22
+ height:45px;
23
+ position:fixed;
24
+ top:0;
25
+ width:100%;
26
+ h1 {
27
+ margin:10px 0 0 15px;
28
+ float:left;
29
+ a {
30
+ display:block;
31
+ background:image-url('documentation/logo-white.svg') no-repeat;
32
+ background-size:20px;
33
+ width:20px;
34
+ height:20px;
35
+ text-indent:-40000px;
36
+ }
37
+ }
38
+ p.back {
39
+ float:right;
40
+ margin:14px 15px 0 0;
41
+ a { color:#97a4b7; text-decoration:none; }
42
+ a:hover { color:#fff;}
43
+ }
44
+ }
45
+
46
+ //
47
+ // Search Form
48
+ //
49
+ .searchForm {
50
+ padding:0 15px;
51
+ margin-bottom:15px;
52
+ input {
53
+ width:100%;
54
+ background:image-url('documentation/search.svg') white no-repeat 5px 6px;
55
+ font-family:$font;
56
+ background-size:14px;
57
+ border:2px solid #bbc5da;
58
+ border-radius:4px;
59
+ padding:6px 6px 6px 25px;
60
+ }
61
+ }
62
+
63
+ //
64
+ // Left-side navigation
65
+ //
66
+ nav.pages {
67
+ position:fixed;
68
+ top:45px;
69
+ bottom:0;
70
+ width:249px;
71
+ border-right:1px solid #E2E7F1;
72
+ background:#F5F7FB;
73
+ font-size:0.9em;
74
+ div.inner {
75
+ padding:15px 0;
76
+ ul {
77
+ li {
78
+ a {
79
+ text-decoration:none;
80
+ color:#333;
81
+ padding:5px 15px;
82
+ display:block;
83
+ &:hover {
84
+ background:#e2e7f1;
85
+ }
86
+ &.active {
87
+ background:#35A4D4;
88
+ color:#fff;
89
+ }
90
+ }
91
+ ul li a { padding-left:35px;}
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ //
98
+ // Main content area
99
+ //
100
+ section.content {
101
+ position:fixed;
102
+ top:45px;
103
+ left:250px;
104
+ bottom:0;
105
+ right:0;
106
+ background:#fff;
107
+ overflow-y:scroll;
108
+ }
109
+
110
+ //
111
+ // The breadcrumb
112
+ //
113
+ nav.breadcrumb {
114
+ font-size:0.85em;
115
+ background:#E2E7F1;
116
+ margin-bottom:10px;
117
+ padding:10px 35px;
118
+ ul {
119
+ overflow:hidden;
120
+ li {
121
+ float:left; margin-right:7px;
122
+ &:after { content:"\21D2"; padding-left:7px; color:#abb6cd;}
123
+ &:last-child:after { color:#E2E7F1; padding-left:0;}
124
+ a {color:#8e9bb4;}
125
+ a:hover { color:#748098;}
126
+ &:last-child a { text-decoration:none;}
127
+ &:last-child a:hover {color:#8e9bb4;}
128
+ }
129
+ }
130
+ }
131
+
132
+ //
133
+ // A page
134
+ //
135
+ section.page {
136
+ margin:25px 35px 35px 35px;
137
+ h1 {
138
+ font-size:2.2em;
139
+ font-weight:300 ;
140
+ margin-bottom:4px;
141
+ }
142
+
143
+ p.updated {
144
+ color:#999;
145
+ font-size:0.85em;
146
+ margin-bottom:10px;
147
+ }
148
+
149
+ p.previewLink {
150
+ float:right;
151
+ margin-top:4px;
152
+ }
153
+
154
+ p.adminButtons {
155
+ border-top:1px dashed #ddd;
156
+ padding:15px 0;
157
+ margin-top:30px;
158
+ text-align:right;
159
+ }
160
+
161
+ form.reordering {
162
+ padding:0 0 0 0;
163
+ }
164
+ form.reordering ul {
165
+ padding:25px 0 0 0;
166
+ }
167
+ form.reordering ul li {
168
+ background:#F5F7FB;
169
+ font-size:1.1em;
170
+ margin-bottom:7px;
171
+ padding:10px;
172
+ cursor:pointer;
173
+ border:1px dashed #748098;
174
+ background:image-url('documentation/page.svg') #F5F7FB no-repeat 16px 10px;
175
+ background-size:14px;
176
+ padding-left:40px;
177
+ }
178
+
179
+ }
180
+
181
+ //
182
+ // Generic button style
183
+ //
184
+ a.button, input.button {
185
+ display:inline-block;
186
+ border:2px solid lighten(#9357B0, 20%);
187
+ text-decoration:none;
188
+ background:#fff;
189
+ color:#9357B0;
190
+ font-weight:500;
191
+ padding:3px 10px;
192
+ font-size:12px;
193
+ background:#fff;
194
+ border-radius:5px;
195
+ margin-left:5px;
196
+ appearance:none;
197
+ vertical-align:middle;
198
+ &.delete {
199
+ color:#F6744F;
200
+ border-color:lighten(#F6744F, 20%);
201
+ }
202
+ &.new {
203
+ color:#65BA65;
204
+ border-color:lighten(#65BA65, 20%);
205
+ }
206
+ &.preview {
207
+ color:#999;
208
+ border-color:#ccc;
209
+ }
210
+ }
211
+
212
+ //
213
+ // Flash message - for notices
214
+ //
215
+ #flash-notice {
216
+ background:#65BA65;
217
+ padding:15px 35px;
218
+ color:#fff;
219
+ font-size:1.2em;
220
+ font-weight:600;
221
+ }
222
+
223
+ //
224
+ // Flash message - for alerts
225
+ //
226
+ #flash-alert {
227
+ background:#F6744F;
228
+ padding:15px 35px;
229
+ color:#fff;
230
+ font-size:1.2em;
231
+ font-weight:600;
232
+ }
233
+
234
+ //
235
+ // Welcome message on homepage
236
+ //
237
+ section.welcome {
238
+ text-align:center;
239
+ margin:60px 0;
240
+ background:image-url('documentation/logo-black.svg') no-repeat top center;
241
+ background-size:100px;
242
+ padding-top:150px;
243
+ h1 { font-size:3.6em; font-weight:300;}
244
+ h2 { color:#aaa; margin-top:2px; font-size:1.5em; font-weight:300;}
245
+ .override {
246
+ background:#fdffe0;
247
+ width:80%;
248
+ margin:50px auto;
249
+ font-size:1.1em;
250
+ line-height:1.7;
251
+ padding:25px;
252
+ border:1px solid #ced0ad;
253
+ color:#727457;
254
+ code { font-weight:bold; }
255
+ }
256
+ }
257
+
258
+ //
259
+ // Access denied
260
+ //
261
+ html.errorPage {
262
+ background:lighten(#354050, 70%);
263
+ }
264
+
265
+ section.errorMessage {
266
+ width:450px;
267
+ margin:100px auto;
268
+ box-shadow: 0 0 35px lighten(#354050, 60%);
269
+ background:white;
270
+ text-align:center;
271
+ h2 {
272
+ background:#354050;
273
+ color:#fff;
274
+ padding:15px;
275
+ font-size:1.5em;
276
+ font-weight:300;
277
+ }
278
+ p {
279
+ padding:25px 15px;
280
+ line-height:1.5;
281
+ font-size:0.9em;
282
+ color:lighten(#354050, 30%);
283
+ }
284
+ }
285
+
286
+ //
287
+ // Search results
288
+ //
289
+ ul.searchResults {
290
+ margin:25px 0;
291
+ a { color:inherit; text-decoration:none;}
292
+ a:hover { text-decoration:underline;}
293
+ li {
294
+ margin-bottom:25px;
295
+ h4 { font-weight:600; color:#35A4D4; }
296
+ p.in { font-size:0.85em; color:#92BBC9; margin-top:4px;}
297
+ p.excerpt { margin-top:5px; line-height:1.5;}
298
+ p.excerpt mark { background:#fffdca; border-bottom:1px solid #d9d33b; }
299
+ }
300
+ }
301
+
302
+ //
303
+ // Search summary
304
+ //
305
+ p.searchSummary {
306
+ color:#999; margin-top:5px;
307
+ }
308
+
309
+ //
310
+ // No search results
311
+ //
312
+ p.noSearchResults {
313
+ text-align:center;
314
+ margin:100px 0;
315
+ color:#999;
316
+ font-style:italic;
317
+ font-size:1.5em;
318
+ font-weight:300;
319
+ background:image-url('documentation/unhappy.svg') no-repeat center top;
320
+ background-size:170px;
321
+ padding-top:200px;
322
+ }