arctic-ui 0.1.0

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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +36 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +4 -0
  7. data/Gemfile.lock +98 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +28 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/core-api.gemspec +41 -0
  14. data/documentation/.editorconfig +15 -0
  15. data/documentation/.gitignore +24 -0
  16. data/documentation/.travis.yml +10 -0
  17. data/documentation/CHANGELOG.md +137 -0
  18. data/documentation/CODE_OF_CONDUCT.md +46 -0
  19. data/documentation/Gemfile +11 -0
  20. data/documentation/Gemfile.lock +129 -0
  21. data/documentation/LICENSE +13 -0
  22. data/documentation/Procfile +1 -0
  23. data/documentation/README.md +118 -0
  24. data/documentation/config.rb +57 -0
  25. data/documentation/deploy.sh +215 -0
  26. data/documentation/font-selection.json +148 -0
  27. data/documentation/lib/multilang.rb +16 -0
  28. data/documentation/lib/nesting_unique_head.rb +22 -0
  29. data/documentation/lib/toc_data.rb +30 -0
  30. data/documentation/lib/unique_head.rb +24 -0
  31. data/documentation/source/fonts/slate.eot +0 -0
  32. data/documentation/source/fonts/slate.svg +14 -0
  33. data/documentation/source/fonts/slate.ttf +0 -0
  34. data/documentation/source/fonts/slate.woff +0 -0
  35. data/documentation/source/fonts/slate.woff2 +0 -0
  36. data/documentation/source/images/logo.png +0 -0
  37. data/documentation/source/images/navbar.png +0 -0
  38. data/documentation/source/includes/_errors.md +17 -0
  39. data/documentation/source/index.html.md +179 -0
  40. data/documentation/source/javascripts/all.js +2 -0
  41. data/documentation/source/javascripts/all_nosearch.js +16 -0
  42. data/documentation/source/javascripts/app/_lang.js +164 -0
  43. data/documentation/source/javascripts/app/_search.js +98 -0
  44. data/documentation/source/javascripts/app/_toc.js +114 -0
  45. data/documentation/source/javascripts/lib/_energize.js +169 -0
  46. data/documentation/source/javascripts/lib/_imagesloaded.min.js +7 -0
  47. data/documentation/source/javascripts/lib/_jquery.highlight.js +108 -0
  48. data/documentation/source/javascripts/lib/_jquery.js +9831 -0
  49. data/documentation/source/javascripts/lib/_lunr.js +1910 -0
  50. data/documentation/source/layouts/layout.erb +116 -0
  51. data/documentation/source/stylesheets/_icon-font.scss +38 -0
  52. data/documentation/source/stylesheets/_normalize.scss +427 -0
  53. data/documentation/source/stylesheets/_rtl.scss +140 -0
  54. data/documentation/source/stylesheets/_variables.scss +103 -0
  55. data/documentation/source/stylesheets/_variables2.scss +147 -0
  56. data/documentation/source/stylesheets/print.css.scss +148 -0
  57. data/documentation/source/stylesheets/screen.css.scss +707 -0
  58. data/lib/arctic/ui.rb +21 -0
  59. data/lib/arctic/ui/api.rb +69 -0
  60. data/lib/arctic/ui/configuration.rb +26 -0
  61. data/lib/arctic/ui/version.rb +5 -0
  62. metadata +288 -0
@@ -0,0 +1,2 @@
1
+ //= require ./all_nosearch
2
+ //= require ./app/_search
@@ -0,0 +1,16 @@
1
+ //= require ./lib/_energize
2
+ //= require ./app/_toc
3
+ //= require ./app/_lang
4
+
5
+ $(function() {
6
+ loadToc($('#toc'), '.toc-link', '.toc-list-h2', 10);
7
+ setupLanguages($('body').data('languages'));
8
+ $('.content').imagesLoaded( function() {
9
+ window.recacheHeights();
10
+ window.refreshToc();
11
+ });
12
+ });
13
+
14
+ window.onpopstate = function() {
15
+ activateLanguage(getLanguageFromQueryString());
16
+ };
@@ -0,0 +1,164 @@
1
+ //= require ../lib/_jquery
2
+
3
+ /*
4
+ Copyright 2008-2013 Concur Technologies, Inc.
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License"); you may
7
+ not use this file except in compliance with the License. You may obtain
8
+ a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ License for the specific language governing permissions and limitations
16
+ under the License.
17
+ */
18
+ ;(function () {
19
+ 'use strict';
20
+
21
+ var languages = [];
22
+
23
+ window.setupLanguages = setupLanguages;
24
+ window.activateLanguage = activateLanguage;
25
+ window.getLanguageFromQueryString = getLanguageFromQueryString;
26
+
27
+ function activateLanguage(language) {
28
+ if (!language) return;
29
+ if (language === "") return;
30
+
31
+ $(".lang-selector a").removeClass('active');
32
+ $(".lang-selector a[data-language-name='" + language + "']").addClass('active');
33
+ for (var i=0; i < languages.length; i++) {
34
+ $(".highlight.tab-" + languages[i]).hide();
35
+ $(".lang-specific." + languages[i]).hide();
36
+ }
37
+ $(".highlight.tab-" + language).show();
38
+ $(".lang-specific." + language).show();
39
+
40
+ window.recacheHeights();
41
+
42
+ // scroll to the new location of the position
43
+ if ($(window.location.hash).get(0)) {
44
+ $(window.location.hash).get(0).scrollIntoView(true);
45
+ }
46
+ }
47
+
48
+ // parseURL and stringifyURL are from https://github.com/sindresorhus/query-string
49
+ // MIT licensed
50
+ // https://github.com/sindresorhus/query-string/blob/7bee64c16f2da1a326579e96977b9227bf6da9e6/license
51
+ function parseURL(str) {
52
+ if (typeof str !== 'string') {
53
+ return {};
54
+ }
55
+
56
+ str = str.trim().replace(/^(\?|#|&)/, '');
57
+
58
+ if (!str) {
59
+ return {};
60
+ }
61
+
62
+ return str.split('&').reduce(function (ret, param) {
63
+ var parts = param.replace(/\+/g, ' ').split('=');
64
+ var key = parts[0];
65
+ var val = parts[1];
66
+
67
+ key = decodeURIComponent(key);
68
+ // missing `=` should be `null`:
69
+ // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
70
+ val = val === undefined ? null : decodeURIComponent(val);
71
+
72
+ if (!ret.hasOwnProperty(key)) {
73
+ ret[key] = val;
74
+ } else if (Array.isArray(ret[key])) {
75
+ ret[key].push(val);
76
+ } else {
77
+ ret[key] = [ret[key], val];
78
+ }
79
+
80
+ return ret;
81
+ }, {});
82
+ };
83
+
84
+ function stringifyURL(obj) {
85
+ return obj ? Object.keys(obj).sort().map(function (key) {
86
+ var val = obj[key];
87
+
88
+ if (Array.isArray(val)) {
89
+ return val.sort().map(function (val2) {
90
+ return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
91
+ }).join('&');
92
+ }
93
+
94
+ return encodeURIComponent(key) + '=' + encodeURIComponent(val);
95
+ }).join('&') : '';
96
+ };
97
+
98
+ // gets the language set in the query string
99
+ function getLanguageFromQueryString() {
100
+ if (location.search.length >= 1) {
101
+ var language = parseURL(location.search).language;
102
+ if (language) {
103
+ return language;
104
+ } else if (jQuery.inArray(location.search.substr(1), languages) != -1) {
105
+ return location.search.substr(1);
106
+ }
107
+ }
108
+
109
+ return false;
110
+ }
111
+
112
+ // returns a new query string with the new language in it
113
+ function generateNewQueryString(language) {
114
+ var url = parseURL(location.search);
115
+ if (url.language) {
116
+ url.language = language;
117
+ return stringifyURL(url);
118
+ }
119
+ return language;
120
+ }
121
+
122
+ // if a button is clicked, add the state to the history
123
+ function pushURL(language) {
124
+ if (!history) { return; }
125
+ var hash = window.location.hash;
126
+ if (hash) {
127
+ hash = hash.replace(/^#+/, '');
128
+ }
129
+ history.pushState({}, '', '?' + generateNewQueryString(language) + '#' + hash);
130
+
131
+ // save language as next default
132
+ localStorage.setItem("language", language);
133
+ }
134
+
135
+ function setupLanguages(l) {
136
+ var defaultLanguage = localStorage.getItem("language");
137
+
138
+ languages = l;
139
+
140
+ var presetLanguage = getLanguageFromQueryString();
141
+ if (presetLanguage) {
142
+ // the language is in the URL, so use that language!
143
+ activateLanguage(presetLanguage);
144
+
145
+ localStorage.setItem("language", presetLanguage);
146
+ } else if ((defaultLanguage !== null) && (jQuery.inArray(defaultLanguage, languages) != -1)) {
147
+ // the language was the last selected one saved in localstorage, so use that language!
148
+ activateLanguage(defaultLanguage);
149
+ } else {
150
+ // no language selected, so use the default
151
+ activateLanguage(languages[0]);
152
+ }
153
+ }
154
+
155
+ // if we click on a language tab, activate that language
156
+ $(function() {
157
+ $(".lang-selector a").on("click", function() {
158
+ var language = $(this).data("language-name");
159
+ pushURL(language);
160
+ activateLanguage(language);
161
+ return false;
162
+ });
163
+ });
164
+ })();
@@ -0,0 +1,98 @@
1
+ //= require ../lib/_lunr
2
+ //= require ../lib/_jquery
3
+ //= require ../lib/_jquery.highlight
4
+ ;(function () {
5
+ 'use strict';
6
+
7
+ var content, searchResults;
8
+ var highlightOpts = { element: 'span', className: 'search-highlight' };
9
+ var searchDelay = 0;
10
+ var timeoutHandle = 0;
11
+
12
+ var index = new lunr.Index();
13
+
14
+ index.ref('id');
15
+ index.field('title', { boost: 10 });
16
+ index.field('body');
17
+ index.pipeline.add(lunr.trimmer, lunr.stopWordFilter);
18
+
19
+ $(populate);
20
+ $(bind);
21
+
22
+ function populate() {
23
+ $('h1, h2').each(function() {
24
+ var title = $(this);
25
+ var body = title.nextUntil('h1, h2');
26
+ index.add({
27
+ id: title.prop('id'),
28
+ title: title.text(),
29
+ body: body.text()
30
+ });
31
+ });
32
+
33
+ determineSearchDelay();
34
+ }
35
+ function determineSearchDelay() {
36
+ if(index.tokenStore.length>5000) {
37
+ searchDelay = 300;
38
+ }
39
+ }
40
+
41
+ function bind() {
42
+ content = $('.content');
43
+ searchResults = $('.search-results');
44
+
45
+ $('#input-search').on('keyup',function(e) {
46
+ var wait = function() {
47
+ return function(executingFunction, waitTime){
48
+ clearTimeout(timeoutHandle);
49
+ timeoutHandle = setTimeout(executingFunction, waitTime);
50
+ };
51
+ }();
52
+ wait(function(){
53
+ search(e);
54
+ }, searchDelay );
55
+ });
56
+ }
57
+
58
+ function search(event) {
59
+
60
+ var searchInput = $('#input-search')[0];
61
+
62
+ unhighlight();
63
+ searchResults.addClass('visible');
64
+
65
+ // ESC clears the field
66
+ if (event.keyCode === 27) searchInput.value = '';
67
+
68
+ if (searchInput.value) {
69
+ var results = index.search(searchInput.value).filter(function(r) {
70
+ return r.score > 0.0001;
71
+ });
72
+
73
+ if (results.length) {
74
+ searchResults.empty();
75
+ $.each(results, function (index, result) {
76
+ var elem = document.getElementById(result.ref);
77
+ searchResults.append("<li><a href='#" + result.ref + "'>" + $(elem).text() + "</a></li>");
78
+ });
79
+ highlight.call(searchInput);
80
+ } else {
81
+ searchResults.html('<li></li>');
82
+ $('.search-results li').text('No Results Found for "' + searchInput.value + '"');
83
+ }
84
+ } else {
85
+ unhighlight();
86
+ searchResults.removeClass('visible');
87
+ }
88
+ }
89
+
90
+ function highlight() {
91
+ if (this.value) content.highlight(this.value, highlightOpts);
92
+ }
93
+
94
+ function unhighlight() {
95
+ content.unhighlight(highlightOpts);
96
+ }
97
+ })();
98
+
@@ -0,0 +1,114 @@
1
+ //= require ../lib/_jquery
2
+ //= require ../lib/_imagesloaded.min
3
+ ;(function () {
4
+ 'use strict';
5
+
6
+ var loaded = false;
7
+
8
+ var debounce = function(func, waitTime) {
9
+ var timeout = false;
10
+ return function() {
11
+ if (timeout === false) {
12
+ setTimeout(function() {
13
+ func();
14
+ timeout = false;
15
+ }, waitTime);
16
+ timeout = true;
17
+ }
18
+ };
19
+ };
20
+
21
+ var closeToc = function() {
22
+ $(".toc-wrapper").removeClass('open');
23
+ $("#nav-button").removeClass('open');
24
+ };
25
+
26
+ function loadToc($toc, tocLinkSelector, tocListSelector, scrollOffset) {
27
+ var headerHeights = {};
28
+ var pageHeight = 0;
29
+ var windowHeight = 0;
30
+ var originalTitle = document.title;
31
+
32
+ var recacheHeights = function() {
33
+ headerHeights = {};
34
+ pageHeight = $(document).height();
35
+ windowHeight = $(window).height();
36
+
37
+ $toc.find(tocLinkSelector).each(function() {
38
+ var targetId = $(this).attr('href');
39
+ if (targetId[0] === "#") {
40
+ headerHeights[targetId] = $(targetId).offset().top;
41
+ }
42
+ });
43
+ };
44
+
45
+ var refreshToc = function() {
46
+ var currentTop = $(document).scrollTop() + scrollOffset;
47
+
48
+ if (currentTop + windowHeight >= pageHeight) {
49
+ // at bottom of page, so just select last header by making currentTop very large
50
+ // this fixes the problem where the last header won't ever show as active if its content
51
+ // is shorter than the window height
52
+ currentTop = pageHeight + 1000;
53
+ }
54
+
55
+ var best = null;
56
+ for (var name in headerHeights) {
57
+ if ((headerHeights[name] < currentTop && headerHeights[name] > headerHeights[best]) || best === null) {
58
+ best = name;
59
+ }
60
+ }
61
+
62
+ // Catch the initial load case
63
+ if (currentTop == scrollOffset && !loaded) {
64
+ best = window.location.hash;
65
+ loaded = true;
66
+ }
67
+
68
+ var $best = $toc.find("[href='" + best + "']").first();
69
+ if (!$best.hasClass("active")) {
70
+ // .active is applied to the ToC link we're currently on, and its parent <ul>s selected by tocListSelector
71
+ // .active-expanded is applied to the ToC links that are parents of this one
72
+ $toc.find(".active").removeClass("active");
73
+ $toc.find(".active-parent").removeClass("active-parent");
74
+ $best.addClass("active");
75
+ $best.parents(tocListSelector).addClass("active").siblings(tocLinkSelector).addClass('active-parent');
76
+ $best.siblings(tocListSelector).addClass("active");
77
+ $toc.find(tocListSelector).filter(":not(.active)").slideUp(150);
78
+ $toc.find(tocListSelector).filter(".active").slideDown(150);
79
+ // TODO remove classnames
80
+ document.title = $best.data("title") + " – " + originalTitle;
81
+ }
82
+ };
83
+
84
+ var makeToc = function() {
85
+ recacheHeights();
86
+ refreshToc();
87
+
88
+ $("#nav-button").click(function() {
89
+ $(".toc-wrapper").toggleClass('open');
90
+ $("#nav-button").toggleClass('open');
91
+ return false;
92
+ });
93
+ $(".page-wrapper").click(closeToc);
94
+ $(".toc-link").click(closeToc);
95
+
96
+ // reload immediately after scrolling on toc click
97
+ $toc.find(tocLinkSelector).click(function() {
98
+ setTimeout(function() {
99
+ refreshToc();
100
+ }, 0);
101
+ });
102
+
103
+ $(window).scroll(debounce(refreshToc, 200));
104
+ $(window).resize(debounce(recacheHeights, 200));
105
+ };
106
+
107
+ makeToc();
108
+
109
+ window.recacheHeights = recacheHeights;
110
+ window.refreshToc = refreshToc;
111
+ }
112
+
113
+ window.loadToc = loadToc;
114
+ })();
@@ -0,0 +1,169 @@
1
+ /**
2
+ * energize.js v0.1.0
3
+ *
4
+ * Speeds up click events on mobile devices.
5
+ * https://github.com/davidcalhoun/energize.js
6
+ */
7
+
8
+ (function() { // Sandbox
9
+ /**
10
+ * Don't add to non-touch devices, which don't need to be sped up
11
+ */
12
+ if(!('ontouchstart' in window)) return;
13
+
14
+ var lastClick = {},
15
+ isThresholdReached, touchstart, touchmove, touchend,
16
+ click, closest;
17
+
18
+ /**
19
+ * isThresholdReached
20
+ *
21
+ * Compare touchstart with touchend xy coordinates,
22
+ * and only fire simulated click event if the coordinates
23
+ * are nearby. (don't want clicking to be confused with a swipe)
24
+ */
25
+ isThresholdReached = function(startXY, xy) {
26
+ return Math.abs(startXY[0] - xy[0]) > 5 || Math.abs(startXY[1] - xy[1]) > 5;
27
+ };
28
+
29
+ /**
30
+ * touchstart
31
+ *
32
+ * Save xy coordinates when the user starts touching the screen
33
+ */
34
+ touchstart = function(e) {
35
+ this.startXY = [e.touches[0].clientX, e.touches[0].clientY];
36
+ this.threshold = false;
37
+ };
38
+
39
+ /**
40
+ * touchmove
41
+ *
42
+ * Check if the user is scrolling past the threshold.
43
+ * Have to check here because touchend will not always fire
44
+ * on some tested devices (Kindle Fire?)
45
+ */
46
+ touchmove = function(e) {
47
+ // NOOP if the threshold has already been reached
48
+ if(this.threshold) return false;
49
+
50
+ this.threshold = isThresholdReached(this.startXY, [e.touches[0].clientX, e.touches[0].clientY]);
51
+ };
52
+
53
+ /**
54
+ * touchend
55
+ *
56
+ * If the user didn't scroll past the threshold between
57
+ * touchstart and touchend, fire a simulated click.
58
+ *
59
+ * (This will fire before a native click)
60
+ */
61
+ touchend = function(e) {
62
+ // Don't fire a click if the user scrolled past the threshold
63
+ if(this.threshold || isThresholdReached(this.startXY, [e.changedTouches[0].clientX, e.changedTouches[0].clientY])) {
64
+ return;
65
+ }
66
+
67
+ /**
68
+ * Create and fire a click event on the target element
69
+ * https://developer.mozilla.org/en/DOM/event.initMouseEvent
70
+ */
71
+ var touch = e.changedTouches[0],
72
+ evt = document.createEvent('MouseEvents');
73
+ evt.initMouseEvent('click', true, true, window, 0, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
74
+ evt.simulated = true; // distinguish from a normal (nonsimulated) click
75
+ e.target.dispatchEvent(evt);
76
+ };
77
+
78
+ /**
79
+ * click
80
+ *
81
+ * Because we've already fired a click event in touchend,
82
+ * we need to listed for all native click events here
83
+ * and suppress them as necessary.
84
+ */
85
+ click = function(e) {
86
+ /**
87
+ * Prevent ghost clicks by only allowing clicks we created
88
+ * in the click event we fired (look for e.simulated)
89
+ */
90
+ var time = Date.now(),
91
+ timeDiff = time - lastClick.time,
92
+ x = e.clientX,
93
+ y = e.clientY,
94
+ xyDiff = [Math.abs(lastClick.x - x), Math.abs(lastClick.y - y)],
95
+ target = closest(e.target, 'A') || e.target, // needed for standalone apps
96
+ nodeName = target.nodeName,
97
+ isLink = nodeName === 'A',
98
+ standAlone = window.navigator.standalone && isLink && e.target.getAttribute("href");
99
+
100
+ lastClick.time = time;
101
+ lastClick.x = x;
102
+ lastClick.y = y;
103
+
104
+ /**
105
+ * Unfortunately Android sometimes fires click events without touch events (seen on Kindle Fire),
106
+ * so we have to add more logic to determine the time of the last click. Not perfect...
107
+ *
108
+ * Older, simpler check: if((!e.simulated) || standAlone)
109
+ */
110
+ if((!e.simulated && (timeDiff < 500 || (timeDiff < 1500 && xyDiff[0] < 50 && xyDiff[1] < 50))) || standAlone) {
111
+ e.preventDefault();
112
+ e.stopPropagation();
113
+ if(!standAlone) return false;
114
+ }
115
+
116
+ /**
117
+ * Special logic for standalone web apps
118
+ * See http://stackoverflow.com/questions/2898740/iphone-safari-web-app-opens-links-in-new-window
119
+ */
120
+ if(standAlone) {
121
+ window.location = target.getAttribute("href");
122
+ }
123
+
124
+ /**
125
+ * Add an energize-focus class to the targeted link (mimics :focus behavior)
126
+ * TODO: test and/or remove? Does this work?
127
+ */
128
+ if(!target || !target.classList) return;
129
+ target.classList.add("energize-focus");
130
+ window.setTimeout(function(){
131
+ target.classList.remove("energize-focus");
132
+ }, 150);
133
+ };
134
+
135
+ /**
136
+ * closest
137
+ * @param {HTMLElement} node current node to start searching from.
138
+ * @param {string} tagName the (uppercase) name of the tag you're looking for.
139
+ *
140
+ * Find the closest ancestor tag of a given node.
141
+ *
142
+ * Starts at node and goes up the DOM tree looking for a
143
+ * matching nodeName, continuing until hitting document.body
144
+ */
145
+ closest = function(node, tagName){
146
+ var curNode = node;
147
+
148
+ while(curNode !== document.body) { // go up the dom until we find the tag we're after
149
+ if(!curNode || curNode.nodeName === tagName) { return curNode; } // found
150
+ curNode = curNode.parentNode; // not found, so keep going up
151
+ }
152
+
153
+ return null; // not found
154
+ };
155
+
156
+ /**
157
+ * Add all delegated event listeners
158
+ *
159
+ * All the events we care about bubble up to document,
160
+ * so we can take advantage of event delegation.
161
+ *
162
+ * Note: no need to wait for DOMContentLoaded here
163
+ */
164
+ document.addEventListener('touchstart', touchstart, false);
165
+ document.addEventListener('touchmove', touchmove, false);
166
+ document.addEventListener('touchend', touchend, false);
167
+ document.addEventListener('click', click, true); // TODO: why does this use capture?
168
+
169
+ })();