twigg-app 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. checksums.yaml +7 -0
  2. data/data/quips.yml +45 -0
  3. data/lib/twigg-app/app/quips.rb +13 -0
  4. data/lib/twigg-app/app/routes.rb +43 -0
  5. data/lib/twigg-app/app/server.rb +146 -0
  6. data/lib/twigg-app/app/version.rb +5 -0
  7. data/lib/twigg-app/app.rb +14 -0
  8. data/lib/twigg-app.rb +5 -0
  9. data/public/application.js +106 -0
  10. data/public/favicon.ico +0 -0
  11. data/public/favicon.png +0 -0
  12. data/public/vendor/bootstrap/CNAME +1 -0
  13. data/public/vendor/bootstrap/CONTRIBUTING.md +66 -0
  14. data/public/vendor/bootstrap/Gruntfile.js +195 -0
  15. data/public/vendor/bootstrap/LICENSE +176 -0
  16. data/public/vendor/bootstrap/README.md +139 -0
  17. data/public/vendor/bootstrap/_config.yml +28 -0
  18. data/public/vendor/bootstrap/_includes/ads.html +1 -0
  19. data/public/vendor/bootstrap/_includes/footer.html +33 -0
  20. data/public/vendor/bootstrap/_includes/header.html +43 -0
  21. data/public/vendor/bootstrap/_includes/nav-components.html +135 -0
  22. data/public/vendor/bootstrap/_includes/nav-css.html +77 -0
  23. data/public/vendor/bootstrap/_includes/nav-customize.html +40 -0
  24. data/public/vendor/bootstrap/_includes/nav-getting-started.html +28 -0
  25. data/public/vendor/bootstrap/_includes/nav-javascript.html +88 -0
  26. data/public/vendor/bootstrap/_includes/nav-main.html +32 -0
  27. data/public/vendor/bootstrap/_includes/old-bs-docs.html +8 -0
  28. data/public/vendor/bootstrap/_includes/social-buttons.html +16 -0
  29. data/public/vendor/bootstrap/_layouts/customize.html +52 -0
  30. data/public/vendor/bootstrap/_layouts/default.html +72 -0
  31. data/public/vendor/bootstrap/_layouts/home.html +43 -0
  32. data/public/vendor/bootstrap/assets/css/docs.css +896 -0
  33. data/public/vendor/bootstrap/assets/css/pygments-manni.css +66 -0
  34. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-114-precomposed.png +0 -0
  35. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-144-precomposed.png +0 -0
  36. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-57-precomposed.png +0 -0
  37. data/public/vendor/bootstrap/assets/ico/apple-touch-icon-72-precomposed.png +0 -0
  38. data/public/vendor/bootstrap/assets/ico/favicon.png +0 -0
  39. data/public/vendor/bootstrap/assets/js/application.js +82 -0
  40. data/public/vendor/bootstrap/assets/js/customizer.js +175 -0
  41. data/public/vendor/bootstrap/assets/js/holder.js +419 -0
  42. data/public/vendor/bootstrap/assets/js/html5shiv.js +8 -0
  43. data/public/vendor/bootstrap/assets/js/jquery.bbq.min.js +1287 -0
  44. data/public/vendor/bootstrap/assets/js/jquery.js +5 -0
  45. data/public/vendor/bootstrap/assets/js/jszip.js +1425 -0
  46. data/public/vendor/bootstrap/assets/js/less.js +9 -0
  47. data/public/vendor/bootstrap/assets/js/respond.min.js +6 -0
  48. data/public/vendor/bootstrap/assets/js/uglify.js +14 -0
  49. data/public/vendor/bootstrap/bower.json +11 -0
  50. data/public/vendor/bootstrap/browserstack.json +37 -0
  51. data/public/vendor/bootstrap/components.html +2555 -0
  52. data/public/vendor/bootstrap/composer.json +20 -0
  53. data/public/vendor/bootstrap/css.html +2276 -0
  54. data/public/vendor/bootstrap/customize.html +1480 -0
  55. data/public/vendor/bootstrap/dist/css/bootstrap.css +5579 -0
  56. data/public/vendor/bootstrap/dist/css/bootstrap.min.css +9 -0
  57. data/public/vendor/bootstrap/dist/js/bootstrap.js +1993 -0
  58. data/public/vendor/bootstrap/dist/js/bootstrap.min.js +6 -0
  59. data/public/vendor/bootstrap/getting-started.html +375 -0
  60. data/public/vendor/bootstrap/index.html +16 -0
  61. data/public/vendor/bootstrap/javascript.html +1904 -0
  62. data/public/vendor/bootstrap/js/affix.js +126 -0
  63. data/public/vendor/bootstrap/js/alert.js +98 -0
  64. data/public/vendor/bootstrap/js/button.js +109 -0
  65. data/public/vendor/bootstrap/js/carousel.js +217 -0
  66. data/public/vendor/bootstrap/js/collapse.js +179 -0
  67. data/public/vendor/bootstrap/js/dropdown.js +154 -0
  68. data/public/vendor/bootstrap/js/modal.js +244 -0
  69. data/public/vendor/bootstrap/js/popover.js +117 -0
  70. data/public/vendor/bootstrap/js/scrollspy.js +158 -0
  71. data/public/vendor/bootstrap/js/tab.js +135 -0
  72. data/public/vendor/bootstrap/js/tests/index.html +52 -0
  73. data/public/vendor/bootstrap/js/tests/phantom.js +63 -0
  74. data/public/vendor/bootstrap/js/tests/server.js +14 -0
  75. data/public/vendor/bootstrap/js/tests/unit/affix.js +25 -0
  76. data/public/vendor/bootstrap/js/tests/unit/alert.js +62 -0
  77. data/public/vendor/bootstrap/js/tests/unit/button.js +116 -0
  78. data/public/vendor/bootstrap/js/tests/unit/carousel.js +87 -0
  79. data/public/vendor/bootstrap/js/tests/unit/collapse.js +164 -0
  80. data/public/vendor/bootstrap/js/tests/unit/dropdown.js +219 -0
  81. data/public/vendor/bootstrap/js/tests/unit/modal.js +177 -0
  82. data/public/vendor/bootstrap/js/tests/unit/phantom.js +69 -0
  83. data/public/vendor/bootstrap/js/tests/unit/popover.js +133 -0
  84. data/public/vendor/bootstrap/js/tests/unit/scrollspy.js +37 -0
  85. data/public/vendor/bootstrap/js/tests/unit/tab.js +86 -0
  86. data/public/vendor/bootstrap/js/tests/unit/tooltip.js +437 -0
  87. data/public/vendor/bootstrap/js/tests/unit/transition.js +13 -0
  88. data/public/vendor/bootstrap/js/tests/vendor/jquery.js +5 -0
  89. data/public/vendor/bootstrap/js/tests/vendor/qunit.css +232 -0
  90. data/public/vendor/bootstrap/js/tests/vendor/qunit.js +1510 -0
  91. data/public/vendor/bootstrap/js/tooltip.js +382 -0
  92. data/public/vendor/bootstrap/js/transition.js +56 -0
  93. data/public/vendor/bootstrap/less/alerts.less +71 -0
  94. data/public/vendor/bootstrap/less/badges.less +51 -0
  95. data/public/vendor/bootstrap/less/bootstrap.less +63 -0
  96. data/public/vendor/bootstrap/less/breadcrumbs.less +23 -0
  97. data/public/vendor/bootstrap/less/button-groups.less +244 -0
  98. data/public/vendor/bootstrap/less/buttons.less +159 -0
  99. data/public/vendor/bootstrap/less/carousel.less +204 -0
  100. data/public/vendor/bootstrap/less/close.less +33 -0
  101. data/public/vendor/bootstrap/less/code.less +56 -0
  102. data/public/vendor/bootstrap/less/component-animations.less +29 -0
  103. data/public/vendor/bootstrap/less/dropdowns.less +176 -0
  104. data/public/vendor/bootstrap/less/forms.less +332 -0
  105. data/public/vendor/bootstrap/less/grid.less +340 -0
  106. data/public/vendor/bootstrap/less/input-groups.less +127 -0
  107. data/public/vendor/bootstrap/less/jumbotron.less +29 -0
  108. data/public/vendor/bootstrap/less/labels.less +54 -0
  109. data/public/vendor/bootstrap/less/list-group.less +88 -0
  110. data/public/vendor/bootstrap/less/media.less +56 -0
  111. data/public/vendor/bootstrap/less/mixins.less +693 -0
  112. data/public/vendor/bootstrap/less/modals.less +133 -0
  113. data/public/vendor/bootstrap/less/navbar.less +559 -0
  114. data/public/vendor/bootstrap/less/navs.less +228 -0
  115. data/public/vendor/bootstrap/less/normalize.less +396 -0
  116. data/public/vendor/bootstrap/less/pager.less +55 -0
  117. data/public/vendor/bootstrap/less/pagination.less +72 -0
  118. data/public/vendor/bootstrap/less/panels.less +128 -0
  119. data/public/vendor/bootstrap/less/popovers.less +133 -0
  120. data/public/vendor/bootstrap/less/print.less +100 -0
  121. data/public/vendor/bootstrap/less/progress-bars.less +99 -0
  122. data/public/vendor/bootstrap/less/responsive-utilities.less +149 -0
  123. data/public/vendor/bootstrap/less/scaffolding.less +111 -0
  124. data/public/vendor/bootstrap/less/tables.less +211 -0
  125. data/public/vendor/bootstrap/less/thumbnails.less +42 -0
  126. data/public/vendor/bootstrap/less/tooltip.less +95 -0
  127. data/public/vendor/bootstrap/less/type.less +238 -0
  128. data/public/vendor/bootstrap/less/utilities.less +42 -0
  129. data/public/vendor/bootstrap/less/variables.less +607 -0
  130. data/public/vendor/bootstrap/less/wells.less +29 -0
  131. data/public/vendor/bootstrap/package.json +33 -0
  132. data/public/vendor/bootstrap-glyphicons/CHANGELOG.md +3 -0
  133. data/public/vendor/bootstrap-glyphicons/CNAME +1 -0
  134. data/public/vendor/bootstrap-glyphicons/CONTRIBUTING.md +54 -0
  135. data/public/vendor/bootstrap-glyphicons/LICENSE +19 -0
  136. data/public/vendor/bootstrap-glyphicons/README.md +61 -0
  137. data/public/vendor/bootstrap-glyphicons/_config.yml +12 -0
  138. data/public/vendor/bootstrap-glyphicons/composer.json +9 -0
  139. data/public/vendor/bootstrap-glyphicons/css/bootstrap-glyphicons.css +2 -0
  140. data/public/vendor/bootstrap-glyphicons/css/bootstrap.css +9 -0
  141. data/public/vendor/bootstrap-glyphicons/css/docs.css +160 -0
  142. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.eot +0 -0
  143. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.otf +0 -0
  144. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.svg +175 -0
  145. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.ttf +0 -0
  146. data/public/vendor/bootstrap-glyphicons/fonts/glyphiconshalflings-regular.woff +0 -0
  147. data/public/vendor/bootstrap-glyphicons/index.html +255 -0
  148. data/public/vendor/bootstrap-glyphicons/less/bootstrap-glyphicons.less +201 -0
  149. data/public/vendor/bootstrap-glyphicons/package.json +18 -0
  150. data/public/vendor/d3/LICENSE +26 -0
  151. data/public/vendor/d3/README.md +7 -0
  152. data/public/vendor/d3/bower.json +25 -0
  153. data/public/vendor/d3/d3.js +8810 -0
  154. data/public/vendor/d3/d3.min.js +5 -0
  155. data/public/vendor/jquery/README.md +11 -0
  156. data/public/vendor/jquery/bower.json +11 -0
  157. data/public/vendor/jquery/component.json +15 -0
  158. data/public/vendor/jquery/composer.json +35 -0
  159. data/public/vendor/jquery/jquery-migrate.js +511 -0
  160. data/public/vendor/jquery/jquery-migrate.min.js +3 -0
  161. data/public/vendor/jquery/jquery.js +8829 -0
  162. data/public/vendor/jquery/jquery.min.js +6 -0
  163. data/public/vendor/jquery/jquery.min.map +1 -0
  164. data/public/vendor/jquery/package.json +7 -0
  165. data/public/vendor/replacejs/CHANGELOG.md +3 -0
  166. data/public/vendor/replacejs/MIT-LICENSE.txt +20 -0
  167. data/public/vendor/replacejs/README.md +123 -0
  168. data/public/vendor/replacejs/bower.json +24 -0
  169. data/public/vendor/replacejs/primer.js +17 -0
  170. data/public/vendor/replacejs/primer.min.js +1 -0
  171. data/public/vendor/replacejs/replace.js +182 -0
  172. data/public/vendor/stupidtable.js +158 -0
  173. data/views/dashboard.haml +17 -0
  174. data/views/layout.haml +60 -0
  175. metadata +330 -0
@@ -0,0 +1,123 @@
1
+ # Replace.js
2
+
3
+ Tool for adding simple AJAX functionality to a site. See the [demo] for example
4
+ use cases.
5
+
6
+ [demo]: http://causes.github.io/replacejs/demo/
7
+
8
+ ## Background
9
+
10
+ After doing web development for a while, we noticed that most interactions we
11
+ added to the site involved catching a click event, performing an AJAX request,
12
+ and updating part of the page based on the result. This typically required a
13
+ lot of boilerplate JavaScript to set up click handlers. All that JavaScript
14
+ slowed down the initial page load, and until the page finished loading, things
15
+ didn't work right. It also required duplicating business and rendering logic on
16
+ the server and the client. The site was slow and our JS code was brittle and
17
+ difficult to test. We realized that one small library could implement this
18
+ pattern and replace most of our JS code base.
19
+
20
+ We weren't the first to reach a similar conclusion -- see Makinde Adeagbo's
21
+ excellent presentation on [Primer].
22
+
23
+ [Primer]: http://blip.tv/jsconf/makinde-adeagbo-primer-facebook-s-2k-of-javascript-to-power-almost-all-interactions-3858673
24
+
25
+ ## Requirements
26
+
27
+ Any server-side language should do, though we use Rails. jQuery must be
28
+ present.
29
+
30
+ ## Installation
31
+
32
+ Put the contents of `primer.min.js` in a <script> tag in the document
33
+ header. Link to `replace.js` at the bottom of the document body, below jQuery.
34
+
35
+ ```html
36
+ <script src="/path/to/replace.js"></script>
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ You AJAX-ify a link by giving it a `data-replace` attribute containing a jQuery
42
+ selector. When the link is clicked, its closest ancestor matching the selector
43
+ will be replaced by the result of an AJAX request to the link's `href`.
44
+
45
+ ```html
46
+ <div class="container">
47
+ <a href="/foo" data-replace=".container">Foo</a>
48
+ </div>
49
+ ```
50
+
51
+ The link can replace itself. A convenient selector for doing so is '*'.
52
+
53
+ ```html
54
+ <a href="/foo" data-replace="*">Foo</a>
55
+ ```
56
+
57
+ It is up to you to ensure that the server returns an appropriate partial in
58
+ response to that AJAX request. If the URL also represents a full page that
59
+ might be visited normally (e.g. linked externally), add the `data-pushstate`
60
+ attribute to have the window's location updated using the `history.pushState()`
61
+ API. The server can check the `X-Requested-With` header to determine whether
62
+ to return a partial or a full page.
63
+
64
+ ```html
65
+ <a href="/foo" data-replace="*" data-pushstate>Foo</a>
66
+ ```
67
+
68
+ The `data-replace` attribute also works on forms, catching the `submit` event.
69
+
70
+ ```html
71
+ <form action="/foo" data-replace="*">
72
+ <input type="submit">
73
+ </form>
74
+ ```
75
+
76
+ ## Styling
77
+
78
+ While the AJAX operation is in progress, the matched container will have the
79
+ CSS class `.replace-active`. Clicks/submits within that container will be
80
+ ignored until the current operation completes, so you don't have to worry
81
+ about forms being submitted twice when a user double-clicks the button.
82
+
83
+ The `.replace-active` class can be useful for styling the container in order
84
+ to give the user feedback about when the operation begins and ends. For
85
+ instance, the following CSS style will cause elements to be faded when they
86
+ are in the process of being replaced:
87
+
88
+ ```css
89
+ .replace-active {
90
+ opacity: 0.5;
91
+ }
92
+ ```
93
+
94
+ ## Events
95
+
96
+ When a replace operation occurs, a `replace:done` event is triggered on each
97
+ top-level element of the inserted partial. For example, given the following
98
+ listener:
99
+
100
+ ```javascript
101
+ $(document).on('replace:done', 'p', function() {
102
+ console.log(this.innerHTML);
103
+ });
104
+ ```
105
+
106
+ If the server returns the following partial:
107
+
108
+ ```html
109
+ <p>First.</p>
110
+ <p><em>Second.</em></p>
111
+ <div><p>Third.</p></div>
112
+ ```
113
+
114
+ The console will print:
115
+
116
+ ```
117
+ First.
118
+ <em>Second.</em>
119
+ ```
120
+
121
+ ## License
122
+
123
+ This project is released under the MIT license.
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "replacejs",
3
+ "version": "0.0.1",
4
+ "main": [
5
+ "replace.js",
6
+ "primer.js",
7
+ "primer.min.js"
8
+ ],
9
+ "ignore": [
10
+ "**/.*",
11
+ "demo",
12
+ "index.html",
13
+ "node_modules",
14
+ "bower_components",
15
+ "test",
16
+ "tests"
17
+ ],
18
+ "dependencies": {
19
+ "jquery": ">=1.10"
20
+ },
21
+ "devDependencies": {
22
+ "jquery-waypoints": "~2.0.2"
23
+ }
24
+ }
@@ -0,0 +1,17 @@
1
+ releaseClicks = (function(document) {
2
+ if (document.addEventListener) {
3
+ var events = [];
4
+ function handler(event) {
5
+ var data = event.target.dataset;
6
+ if (data && data.replace) {
7
+ events.push(event);
8
+ event.preventDefault();
9
+ }
10
+ }
11
+ document.addEventListener('click', handler);
12
+ return function() {
13
+ document.removeEventListener('click', handler);
14
+ return events;
15
+ }
16
+ }
17
+ })(document);
@@ -0,0 +1 @@
1
+ releaseClicks=function(e){if(e.addEventListener){var t=[];function n(e){var n=e.target.dataset;if(n&&n.replace){t.push(e);e.preventDefault()}}e.addEventListener("click",n);return function(){e.removeEventListener("click",n);return t}}}(document)
@@ -0,0 +1,182 @@
1
+ // Allow links to replace part of the page, rather than the entire thing.
2
+ //
3
+ // <div class="container">
4
+ // <a href="/foo" data-replace=".container">Foo</a>
5
+ // </div>
6
+ //
7
+ // When you click the link "Foo", it will:
8
+ // - Find an ancestor element matching the selector ".container".
9
+ // - Perform a GET request to /foo.
10
+ // - If the request is successful, replace the ancestor with the response body.
11
+ //
12
+ // It also works for forms:
13
+ //
14
+ // <div class="container">
15
+ // <form action="/bar" method="POST" data-replace=".container">
16
+ // <input type="submit">
17
+ // </form>
18
+ // </div>
19
+ //
20
+ // Notes:
21
+ // - It is possible to replace the same element that was clicked/submitted. A
22
+ // convenient selector for doing so is "*".
23
+ // - If a link has the attribute "data-pushstate" and the browser supports it,
24
+ // the address bar will be updated on success using history.pushState.
25
+ // - The container will have the class ".replace-active" while a replace
26
+ // operation is in progress. This can be useful for styling purposes.
27
+ // - Clicks inside a container with a replace operation in progress are ignored.
28
+ // This obviates the need to prevent double submissions of forms.
29
+
30
+ (function($, undefined) {
31
+ // Apply callback to every descendent matching selector that exists at page
32
+ // load or that is added later. This frees you as the developer from having to
33
+ // find every place in the codebase where a given widget might be added to the
34
+ // page and attaching its initialization logic there.
35
+ //
36
+ // Example:
37
+ // $(document).initializeEach('[data-background-url]', function() {
38
+ // $(this).waypoint(function() {
39
+ // $(this).css('backgroundUrl', $(this).data('backgroundUrl'));
40
+ // }, { offset: '100%', triggerOnce: true });
41
+ // });
42
+ //
43
+ // It is also possible to nest these calls.
44
+ //
45
+ // $(document).initializeEach('.discussion-board', function() {
46
+ // $(this).initializeEach('.discussion-post', function() {
47
+ // // ...
48
+ // });
49
+ // });
50
+ //
51
+ $.fn.initializeEach = function(selector, callback) {
52
+ this
53
+ .on('replace:done', function(event) {
54
+ $(event.target).find(selector).addBack(selector).each(callback);
55
+ })
56
+ .find(selector).each(callback);
57
+ };
58
+
59
+ // Replace an element with the result of an AJAX request.
60
+ function ajaxReplace($elem, url, options) {
61
+ if ($elem.closest('.replace-active').length) {
62
+ return;
63
+ }
64
+ options = options || {};
65
+ var $container = $elem.closest(options.selector || '*');
66
+ $container.addClass('replace-active').trigger('replace:start');
67
+
68
+ $.ajax(url, { type: options.method, data: options.data })
69
+ .always(function() {
70
+ $container.removeClass('replace-active');
71
+ })
72
+ .done(function(data) {
73
+ if (options.success) {
74
+ options.success($container, data);
75
+ }
76
+ $(data).replaceAll($container).trigger('replace:done');
77
+ })
78
+ .fail(function() {
79
+ $container.trigger('replace:fail');
80
+ });
81
+ }
82
+
83
+ $(window).on('popstate', function(event) {
84
+ var state = event.originalEvent.state;
85
+ if (state && state.selector) {
86
+ $(state.data).replaceAll(state.selector)
87
+ .trigger('replace:done');
88
+ }
89
+ });
90
+
91
+ $(document).on('click', 'a[data-replace]', function(event) {
92
+ var $link = $(this);
93
+
94
+ if ($link.data('pushstate')) {
95
+ if (!window.history || !history.pushState) {
96
+ // If a link would like to use pushState but that is not supported by
97
+ // the browser, we'll let it do a full page load. Affects IE 8/9 users.
98
+ return;
99
+ }
100
+ if (event.shiftKey || event.metaKey) {
101
+ // User is trying to open link in a new tab or window. Allow default.
102
+ return;
103
+ }
104
+ }
105
+
106
+ event.preventDefault();
107
+
108
+ ajaxReplace($link, $link.attr('href'), {
109
+ selector: $link.data('replace'),
110
+ success: function($container, data) {
111
+ if ($link.data('pushstate')) {
112
+ history.replaceState({
113
+ selector: $link.data('replace'),
114
+ data: $container[0].outerHTML
115
+ }, null);
116
+ history.pushState({
117
+ selector: $link.data('replace'),
118
+ data: data
119
+ }, null, $link.attr('href'));
120
+ }
121
+ }
122
+ });
123
+ });
124
+
125
+ $(document).on('submit', 'form[data-replace]', function(event) {
126
+ event.preventDefault();
127
+ var $form = $(this);
128
+
129
+ ajaxReplace($form, $form.attr('action'), {
130
+ selector: $form.data('replace'),
131
+ method: $form.attr('method'),
132
+ data: $form.serialize()
133
+ });
134
+ });
135
+
136
+ // When you submit a form using the built-in click handler for buttons, the
137
+ // clicked button's name/value will be added to the query string. This can be
138
+ // useful for knowing which button was clicked in a form with several of
139
+ // them. When we submit the form programatically, the clicked button is no
140
+ // longer active and we have no way of knowing which one it was. This click
141
+ // handler emulates the built-in functionality.
142
+ $(document).on('click', 'form[data-replace] button', function(event) {
143
+ var $button = $(this);
144
+ $('<input type="hidden">')
145
+ .prop('name', $button.prop('name'))
146
+ .val($button.val())
147
+ .appendTo($button.closest('form'));
148
+ });
149
+
150
+ if (window.releaseClicks) {
151
+ $.each(releaseClicks(), function(_, event) {
152
+ $(event.target).trigger(event.type);
153
+ });
154
+ }
155
+
156
+ // Allows sections of the page to be lazily loaded just before they come into
157
+ // view. Implementation is simple: just add a 'lazy-url' data attribute like so
158
+ //
159
+ // <div data-lazy-url="http://causes.com/expensive/content"></div>
160
+ //
161
+ // The rest will be handled by this code, in conjunction with the jQuery
162
+ // waypoints plug-in (http://imakewebthings.com/jquery-waypoints/); if the
163
+ // plug-in is not available, we degrade gracefully and revert to eager
164
+ // loading.
165
+ //
166
+ // Note that we support adding yet-more lazy content onto the page after page
167
+ // initialization, but only when using Replace.js.
168
+ $(document).initializeEach('[data-lazy-url]', function() {
169
+ var $this = $(this);
170
+ if (typeof $.fn.waypoint === 'function') {
171
+ $this.waypoint({
172
+ offset: '120%',
173
+ triggerOnce: true,
174
+ handler: function() {
175
+ ajaxReplace($this, $this.data('lazy-url'));
176
+ }
177
+ });
178
+ } else {
179
+ ajaxReplace($this, $this.data('lazy-url'));
180
+ }
181
+ });
182
+ })(jQuery);
@@ -0,0 +1,158 @@
1
+ // Stupid jQuery table plugin.
2
+
3
+ // Call on a table
4
+ // sortFns: Sort functions for your datatypes.
5
+ (function($) {
6
+
7
+ $.fn.stupidtable = function(sortFns) {
8
+ return this.each(function() {
9
+ var $table = $(this);
10
+ sortFns = sortFns || {};
11
+
12
+ // ==================================================== //
13
+ // Utility functions //
14
+ // ==================================================== //
15
+
16
+ // Merge sort functions with some default sort functions.
17
+ sortFns = $.extend({}, $.fn.stupidtable.default_sort_fns, sortFns);
18
+
19
+ // Return the resulting indexes of a sort so we can apply
20
+ // this result elsewhere. This returns an array of index numbers.
21
+ // return[0] = x means "arr's 0th element is now at x"
22
+ var sort_map = function(arr, sort_function, reverse_column) {
23
+ var map = [];
24
+ var index = 0;
25
+ if (reverse_column) {
26
+ for (var i = arr.length-1; i >= 0; i--) {
27
+ map.push(i);
28
+ }
29
+ }
30
+ else {
31
+ var sorted = arr.slice(0).sort(sort_function);
32
+ for (var i=0; i<arr.length; i++) {
33
+ index = $.inArray(arr[i], sorted);
34
+
35
+ // If this index is already in the map, look for the next index.
36
+ // This handles the case of duplicate entries.
37
+ while ($.inArray(index, map) != -1) {
38
+ index++;
39
+ }
40
+ map.push(index);
41
+ }
42
+ }
43
+ return map;
44
+ };
45
+
46
+ // Apply a sort map to the array.
47
+ var apply_sort_map = function(arr, map) {
48
+ var clone = arr.slice(0),
49
+ newIndex = 0;
50
+ for (var i=0; i<map.length; i++) {
51
+ newIndex = map[i];
52
+ clone[newIndex] = arr[i];
53
+ }
54
+ return clone;
55
+ };
56
+
57
+ // ==================================================== //
58
+ // Begin execution! //
59
+ // ==================================================== //
60
+
61
+ // Do sorting when THs are clicked
62
+ $table.on("click", "th", function() {
63
+ var trs = $table.children("tbody").children("tr");
64
+ var $this = $(this);
65
+ var th_index = 0;
66
+ var dir = $.fn.stupidtable.dir;
67
+
68
+ $this.closest('tr').find("th").slice(0, $this.index()).each(function() {
69
+ var cols = $(this).attr("colspan") || 1;
70
+ th_index += parseInt(cols,10);
71
+ });
72
+
73
+ // Determine (and/or reverse) sorting direction, default `asc`
74
+ var sort_dir = $this.data("sort-dir") === dir.ASC ? dir.DESC : dir.ASC;
75
+
76
+ // Choose appropriate sorting function. If we're sorting descending, check
77
+ // for a `data-sort-desc` attribute.
78
+ if ( sort_dir == dir.DESC )
79
+ var type = $this.data("sort-desc") || $this.data("sort") || null;
80
+ else
81
+ var type = $this.data("sort") || null;
82
+
83
+ // Prevent sorting if no type defined
84
+ if (type === null) {
85
+ return;
86
+ }
87
+
88
+ // Trigger `beforetablesort` event that calling scripts can hook into;
89
+ // pass parameters for sorted column index and sorting direction
90
+ $table.trigger("beforetablesort", {column: th_index, direction: sort_dir});
91
+ // More reliable method of forcing a redraw
92
+ $table.css("display");
93
+
94
+ // Run sorting asynchronously on a timout to force browser redraw after
95
+ // `beforetablesort` callback. Also avoids locking up the browser too much.
96
+ setTimeout(function() {
97
+ // Gather the elements for this column
98
+ var column = [];
99
+ var sortMethod = sortFns[type];
100
+
101
+ // Push either the value of the `data-order-by` attribute if specified
102
+ // or just the text() value in this column to column[] for comparison.
103
+ trs.each(function(index,tr) {
104
+ var $e = $(tr).children().eq(th_index);
105
+ var sort_val = $e.data("sort-value");
106
+ var order_by = typeof(sort_val) !== "undefined" ? sort_val : $e.text();
107
+ column.push(order_by);
108
+ });
109
+
110
+ // Create the sort map. This column having a sort-dir implies it was
111
+ // the last column sorted. As long as no data-sort-desc is specified,
112
+ // we're free to just reverse the column.
113
+ var reverse_column = !!$this.data("sort-dir") && !$this.data("sort-desc");
114
+ var theMap = sort_map(column, sortMethod, reverse_column);
115
+
116
+ // Reset siblings
117
+ $table.find("th").data("sort-dir", null).removeClass("sorting-desc sorting-asc");
118
+ $this.data("sort-dir", sort_dir).addClass("sorting-"+sort_dir);
119
+
120
+ // Replace the content of tbody with the sortedTRs. Strangely (and
121
+ // conveniently!) enough, .append accomplishes this for us.
122
+ var sortedTRs = $(apply_sort_map(trs, theMap));
123
+ $table.children("tbody").append(sortedTRs);
124
+
125
+ // Trigger `aftertablesort` event. Similar to `beforetablesort`
126
+ $table.trigger("aftertablesort", {column: th_index, direction: sort_dir});
127
+ // More reliable method of forcing a redraw
128
+ $table.css("display");
129
+ }, 10);
130
+ });
131
+ });
132
+ };
133
+
134
+ // Enum containing sorting directions
135
+ $.fn.stupidtable.dir = {ASC: "asc", DESC: "desc"};
136
+
137
+ $.fn.stupidtable.default_sort_fns = {
138
+ "int": function(a, b) {
139
+ return parseInt(a, 10) - parseInt(b, 10);
140
+ },
141
+ "float": function(a, b) {
142
+ return parseFloat(a) - parseFloat(b);
143
+ },
144
+ "string": function(a, b) {
145
+ if (a < b) return -1;
146
+ if (a > b) return +1;
147
+ return 0;
148
+ },
149
+ "string-ins": function(a, b) {
150
+ a = a.toLowerCase();
151
+ b = b.toLowerCase();
152
+ if (a < b) return -1;
153
+ if (a > b) return +1;
154
+ return 0;
155
+ }
156
+ };
157
+
158
+ })(jQuery);
@@ -0,0 +1,17 @@
1
+ - content_for :title do
2
+ Twigg
3
+ %small
4
+ %span{day_links}
5
+
6
+ %h2 Teams
7
+ .teams.well{ 'data-lazy-url' => teams_path(days: @days) }
8
+
9
+ %h2 Pairs
10
+ .pairs.well{ 'data-lazy-url' => pairs_path(days: @days) }
11
+
12
+ - if Twigg::Config.app.gerrit.enabled
13
+ %h2 Gerrit
14
+ .gerrit.well{ 'data-lazy-url' => gerrit_path }
15
+
16
+ %h2 Authors
17
+ .authors.well{ 'data-lazy-url' => authors_path(days: @days) }
data/views/layout.haml ADDED
@@ -0,0 +1,60 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title
5
+ = strip_tags(yield_content :title)
6
+ - if Twigg::Config.organization
7
+ &mdash;
8
+ &= Twigg::Config.organization
9
+ %meta(name='viewport' content='width=device-width, initial-scale=1.0')
10
+ %link(rel='stylesheet' href='/vendor/bootstrap/dist/css/bootstrap.min.css' media='screen')
11
+ %link(rel='stylesheet' href='/vendor/bootstrap-glyphicons/css/bootstrap-glyphicons.css' media='screen')
12
+ %link(rel='stylesheet' href='/stylesheets/application.css' media='screen')
13
+ %link(rel='shortcut icon' href='/favicon.png')
14
+ %body
15
+ .wrap
16
+ .navbar.navbar-inverse
17
+ .container
18
+ .navbar-header
19
+ %button{ type: 'button', class: 'navbar-toggle', data: { toggle: 'collapse', target: '.navbar-responsive-collapse' }}
20
+ %span.icon-bar
21
+ %span.icon-bar
22
+ %span.icon-bar
23
+ %a.navbar-brand(href='/') Twigg
24
+ .navbar-collapse.collapse.navbar-responsive-collapse
25
+ %ul.nav.navbar-nav
26
+ %li{ class: active?(teams_path) }
27
+ %a{ href: teams_path } Teams
28
+ %li{ class: active?(authors_path) }
29
+ %a{ href: authors_path } Authors
30
+ %li{ class: active?(pairs_path) }
31
+ %a{ href: pairs_path } Pairs
32
+ - if Twigg::Config.app.gerrit.enabled
33
+ %li.dropdown{ class: active?(gerrit_changes_path, gerrit_authors_path) }
34
+ %a{ href: '#', data: { toggle: 'dropdown' } }
35
+ Gerrit
36
+ %b.caret
37
+ %ul.dropdown-menu
38
+ %li
39
+ %a{ href: gerrit_changes_path } Changes
40
+ %li
41
+ %a{ href: gerrit_authors_path } Authors
42
+ %li{ class: active?(russian_novels_path) }
43
+ %a{ href: russian_novels_path } я
44
+ .container
45
+ .page-header
46
+ %h1= yield_content :title
47
+ = yield
48
+ .push
49
+ .footer.navbar
50
+ - quip = random_quip
51
+ %p.navbar-text.text-center{ title: quip }
52
+ Twigg &mdash;
53
+ %em= quip
54
+ %script(src='/vendor/jquery/jquery.min.js')
55
+ %script(src='/vendor/bootstrap/dist/js/bootstrap.min.js')
56
+ %script(src='/vendor/replacejs/replace.js')
57
+ %script(src='/vendor/d3/d3.min.js')
58
+ %script(src='/vendor/stupidtable.js')
59
+ %script(src='/application.js')
60
+ = yield_content :footer