twigg-app 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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