bookends 2.8.0 → 3.0.0.beta1
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.
- checksums.yaml +4 -4
- data/Rakefile +0 -8
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-book.eot +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-book.svg +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-book.ttf +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-book.woff +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-medium.eot +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-medium.svg +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-medium.ttf +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-medium.woff +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-regular.eot +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-regular.svg +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-regular.ttf +0 -0
- data/{fixtures/dummy-rails/app → app}/assets/fonts/bentonsans-regular.woff +0 -0
- data/app/assets/fonts/glyphicons-halflings-regular.eot +0 -0
- data/app/assets/fonts/glyphicons-halflings-regular.svg +288 -0
- data/app/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/app/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/app/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/app/assets/fonts/hk-icon.eot +0 -0
- data/app/assets/fonts/hk-icon.svg +268 -0
- data/app/assets/fonts/hk-icon.ttf +0 -0
- data/app/assets/fonts/hk-icon.woff +0 -0
- data/app/assets/fonts/inconsolata-bold.eot +0 -0
- data/app/assets/fonts/inconsolata-bold.svg +239 -0
- data/app/assets/fonts/inconsolata-bold.ttf +0 -0
- data/app/assets/fonts/inconsolata-bold.woff +0 -0
- data/app/assets/fonts/inconsolata-regular.eot +0 -0
- data/app/assets/fonts/inconsolata-regular.svg +239 -0
- data/app/assets/fonts/inconsolata-regular.ttf +0 -0
- data/app/assets/fonts/inconsolata-regular.woff +0 -0
- data/{lib/bookends/templates/footer_images → app/assets/images/bookends/footer}/footer_sprite.png +0 -0
- data/app/assets/images/bookends/footer/footer_sprite@2x.png +0 -0
- data/{lib/bookends/templates/footer_images → app/assets/images/bookends/footer}/salesforce.png +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/dashboard.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/databases.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/dataclips.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/docs.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/elements.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/heroku-logo.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/navigator-purple.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/navigator.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/settings.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/signout.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/support.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/icons/addons.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/icons/buildpacks.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/icons/buttons.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/icons/connect.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/icons/elements-information.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/icons/enterprise.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/icons/platform.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/icons/postgres.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/icons/redis.svg +0 -0
- data/{lib/bookends/templates → app/assets/images/bookends}/icons/teams.svg +0 -0
- data/app/assets/images/logo.svg +14 -0
- data/app/assets/images/nav-dropdown-caret.svg +16 -0
- data/app/assets/javascripts/blog-fetcher.js +131 -0
- data/{fixtures/dummy-rails/app/assets/javascripts/application.js → app/assets/javascripts/bookends.js} +1 -2
- data/{lib/bookends/templates/js → app/assets/javascripts}/header.js +0 -0
- data/app/assets/javascripts/heroku-namespace.js +1 -0
- data/app/assets/javascripts/lscache.js +359 -0
- data/{lib/bookends/templates/js → app/assets/javascripts}/md5.js +0 -0
- data/app/assets/javascripts/moment.js +3195 -0
- data/{lib/bookends/templates/js → app/assets/javascripts}/newsletter-init.js +1 -1
- data/{lib/bookends/templates/js → app/assets/javascripts}/newsletter.js +0 -0
- data/app/assets/stylesheets/bookends/_base.scss +21 -0
- data/app/assets/stylesheets/bookends/_colors.scss +62 -0
- data/app/assets/stylesheets/bookends/_fonts.scss +12 -0
- data/{lib/bookends/templates/scss/footer.scss → app/assets/stylesheets/bookends/_footer.scss} +17 -14
- data/{lib/bookends/templates/scss/glostick.scss → app/assets/stylesheets/bookends/_glostick.scss} +0 -0
- data/app/assets/stylesheets/bookends/_grid-settings.scss +18 -0
- data/app/assets/stylesheets/bookends/_header.scss +745 -0
- data/app/assets/stylesheets/bookends/_mixins.scss +72 -0
- data/app/assets/stylesheets/bookends/_responsive.scss +129 -0
- data/app/assets/stylesheets/bookends/_variables.scss +82 -0
- data/app/assets/stylesheets/bookends/bookends.scss +13 -0
- data/app/controllers/bookends/application_controller.rb +5 -0
- data/app/helpers/bookends/application_helper.rb +93 -0
- data/{lib/bookends/templates/footer.html → app/views/bookends/_footer.html.erb} +4 -6
- data/{lib/bookends/templates/rails_header.html.erb → app/views/bookends/_header.html.erb} +1 -2
- data/config/routes.rb +2 -0
- data/lib/bookends.rb +2 -2
- data/lib/bookends/config.rb +24 -0
- data/lib/bookends/engine.rb +15 -2
- data/lib/bookends/version.rb +1 -1
- data/lib/tasks/bookends_tasks.rake +4 -0
- metadata +221 -152
- data/.gitignore +0 -17
- data/.rspec +0 -2
- data/.ruby-version +0 -1
- data/.travis.yml +0 -8
- data/Gemfile +0 -4
- data/bin/bookends +0 -5
- data/bin/setup +0 -7
- data/bookends.gemspec +0 -31
- data/fixtures/dummy-jekyll/.gitkeep +0 -0
- data/fixtures/dummy-rails/README.md +0 -9
- data/fixtures/dummy-rails/Rakefile +0 -6
- data/fixtures/dummy-rails/app/assets/images/.keep +0 -0
- data/fixtures/dummy-rails/app/assets/images/bookends/footer/footer_sprite.png +0 -0
- data/fixtures/dummy-rails/app/assets/images/bookends/footer/footer_sprite@2x.png +0 -0
- data/fixtures/dummy-rails/app/assets/images/bookends/footer/salesforce_heroku_gray.png +0 -0
- data/fixtures/dummy-rails/app/assets/stylesheets/application.css.scss +0 -11
- data/fixtures/dummy-rails/app/controllers/application_controller.rb +0 -5
- data/fixtures/dummy-rails/app/controllers/concerns/.keep +0 -0
- data/fixtures/dummy-rails/app/controllers/pages_controller.rb +0 -5
- data/fixtures/dummy-rails/app/helpers/application_helper.rb +0 -2
- data/fixtures/dummy-rails/app/mailers/.keep +0 -0
- data/fixtures/dummy-rails/app/models/.keep +0 -0
- data/fixtures/dummy-rails/app/models/concerns/.keep +0 -0
- data/fixtures/dummy-rails/app/views/layouts/application.html.erb +0 -16
- data/fixtures/dummy-rails/app/views/pages/home.html.erb +0 -1
- data/fixtures/dummy-rails/bin/bundle +0 -3
- data/fixtures/dummy-rails/bin/rails +0 -4
- data/fixtures/dummy-rails/bin/rake +0 -4
- data/fixtures/dummy-rails/bin/setup +0 -29
- data/fixtures/dummy-rails/config.ru +0 -4
- data/fixtures/dummy-rails/config/application.rb +0 -34
- data/fixtures/dummy-rails/config/boot.rb +0 -5
- data/fixtures/dummy-rails/config/database.yml +0 -25
- data/fixtures/dummy-rails/config/environment.rb +0 -5
- data/fixtures/dummy-rails/config/environments/development.rb +0 -41
- data/fixtures/dummy-rails/config/environments/production.rb +0 -79
- data/fixtures/dummy-rails/config/environments/test.rb +0 -42
- data/fixtures/dummy-rails/config/initializers/assets.rb +0 -11
- data/fixtures/dummy-rails/config/initializers/backtrace_silencers.rb +0 -7
- data/fixtures/dummy-rails/config/initializers/cookies_serializer.rb +0 -3
- data/fixtures/dummy-rails/config/initializers/filter_parameter_logging.rb +0 -4
- data/fixtures/dummy-rails/config/initializers/inflections.rb +0 -16
- data/fixtures/dummy-rails/config/initializers/mime_types.rb +0 -4
- data/fixtures/dummy-rails/config/initializers/session_store.rb +0 -3
- data/fixtures/dummy-rails/config/initializers/wrap_parameters.rb +0 -14
- data/fixtures/dummy-rails/config/locales/en.yml +0 -23
- data/fixtures/dummy-rails/config/routes.rb +0 -6
- data/fixtures/dummy-rails/config/secrets.yml +0 -22
- data/fixtures/dummy-rails/db/development.sqlite3 +0 -0
- data/fixtures/dummy-rails/lib/assets/.keep +0 -0
- data/fixtures/dummy-rails/public/404.html +0 -67
- data/fixtures/dummy-rails/public/422.html +0 -67
- data/fixtures/dummy-rails/public/500.html +0 -66
- data/fixtures/dummy-rails/public/favicon.ico +0 -0
- data/lib/bookends/cli.rb +0 -95
- data/lib/bookends/config/framework.rb +0 -24
- data/lib/bookends/config/turbolinks.rb +0 -18
- data/lib/bookends/file_actions.rb +0 -13
- data/lib/bookends/flag_handler.rb +0 -17
- data/lib/bookends/jekyll_handler.rb +0 -25
- data/lib/bookends/rails_handler.rb +0 -41
- data/lib/bookends/templates/bookends_helper.rb +0 -63
- data/lib/bookends/templates/bookends_helper_spec.rb +0 -57
- data/lib/bookends/templates/footer_images/footer_sprite@2x.png +0 -0
- data/lib/bookends/templates/icons/kafka.svg +0 -37
- data/lib/bookends/templates/icons/spaces.svg +0 -1
- data/lib/bookends/templates/jekyll_header.html +0 -102
- data/lib/bookends/templates/js/header-turbolinks.js +0 -18
- data/lib/bookends/templates/js/newsletter-init-turbolinks.js +0 -6
- data/lib/bookends/templates/scss/bookends.scss +0 -21
|
Binary file
|
|
Binary file
|
data/{lib/bookends/templates/footer_images → app/assets/images/bookends/footer}/footer_sprite.png
RENAMED
|
File without changes
|
|
Binary file
|
data/{lib/bookends/templates/footer_images → app/assets/images/bookends/footer}/salesforce.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/{lib/bookends/templates → app/assets/images/bookends}/glostick_icons/navigator-purple.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<svg width="143px" height="40px" viewBox="0 0 143 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
|
3
|
+
<!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch -->
|
|
4
|
+
<title>logo</title>
|
|
5
|
+
<desc>Created with Sketch.</desc>
|
|
6
|
+
<defs></defs>
|
|
7
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
|
8
|
+
<g id="main" sketch:type="MSArtboardGroup" transform="translate(-25.000000, -23.000000)" fill="#FFFFFF">
|
|
9
|
+
<g id="nav" sketch:type="MSLayerGroup" transform="translate(25.000000, 23.000000)">
|
|
10
|
+
<path d="M32.274167,0 L3.58601855,0 C1.60573942,0 0,1.612 0,3.6 L0,36.4 C0,38.388 1.60573942,40 3.58601855,40 L32.274167,40 C34.2544461,40 35.8601855,38.388 35.8601855,36.4 L35.8601855,3.6 C35.8601855,1.612 34.2544461,0 32.274167,0 Z M33.867953,36.4 C33.867953,37.2825 33.1532396,38 32.274167,38 L3.58601855,38 C2.70744401,38 1.99223253,37.2825 1.99223253,36.4 L1.99223253,3.6 C1.99223253,2.7175 2.70744401,2 3.58601855,2 L32.274167,2 C33.1532396,2 33.867953,2.7175 33.867953,3.6 L33.867953,36.4 Z M8.96504638,34 L13.4475696,30 L8.96504638,26 L8.96504638,34 Z M25.1604027,17.7875 C24.357533,16.972 22.8832809,16 20.4203834,16 C17.7194142,16 14.9387556,16.7055 12.9495114,17.3555 L12.9495114,6 L8.96504638,6 L8.96504638,23.346 L11.7795729,22.066 C11.8248962,22.0455 16.3691786,20 20.4203834,20 C22.4429975,20 22.8912498,21.1215 22.9106741,22.055 L22.9106741,34 L26.8951392,34 L26.8951392,22 C26.8976294,21.744 26.8737227,19.5275 25.1604027,17.7875 Z M19.9223253,12.5 L23.9067904,12.5 C25.7087647,10.45 26.6261878,8.272 26.8951392,6 L22.9106741,6 C22.4713868,8.267 21.4882201,10.4375 19.9223253,12.5 Z M130.435895,21.9021404 L130.435895,13.0509941 L134.436196,13.0509941 L134.436196,21.8825993 C134.436196,23.9193901 135.096308,24.838326 136.69693,24.838326 C138.296549,24.838326 138.936597,23.9193901 138.936597,21.8825993 L138.936597,13.0509941 L142.857143,13.0509941 L142.857143,21.9021404 C142.857143,25.8188917 140.977127,28.0556037 136.656802,28.0556037 C132.335975,28.0556037 130.435895,25.8188917 130.435895,21.9021404 Z M113.581962,13.0509941 L117.581762,13.0509941 L117.581762,18.4062758 L121.662821,13.0509941 L126.30317,13.0509941 L121.322231,18.8852849 L126.742576,27.8361414 L122.222111,27.8361414 L118.722412,21.9216816 L117.581762,23.2404598 L117.581762,27.8361414 L113.581962,27.8361414 L113.581962,13.0509941 Z M94.5876806,20.4430667 C94.5876806,15.0296624 98.2875201,12.770904 101.867978,12.770904 C105.428371,12.770904 109.128712,15.0296624 109.128712,20.4430667 C109.128712,25.857473 105.428371,28.1152293 101.867978,28.1152293 C98.2875201,28.1152293 94.5876806,25.857473 94.5876806,20.4430667 Z M105.127909,20.4430667 C105.127909,17.7258424 103.948134,16.0678496 101.867978,16.0678496 C99.7677568,16.0678496 98.5879815,17.7258424 98.5879815,20.4430667 C98.5879815,23.1612931 99.7677568,24.9189959 101.867978,24.9189959 C103.948134,24.9189959 105.127909,23.1612931 105.127909,20.4430667 Z M78.5132424,13.0509941 L84.29374,13.0509941 C88.0939005,13.0509941 90.4143258,14.3101467 90.4143258,17.8661379 C90.4143258,20.1835199 89.4336878,21.5228414 87.4939807,22.1812284 L90.6340289,27.8361414 L86.3939607,27.8361414 L83.5333066,22.7018251 L82.4332865,22.7018251 L82.4332865,27.8361414 L78.5132424,27.8361414 L78.5132424,13.0509941 Z M84.1532905,19.6639253 C85.7935393,19.6639253 86.5133427,19.2044573 86.5133427,17.965848 C86.5133427,16.7277397 85.7935393,16.2873119 84.1532905,16.2873119 L82.4332865,16.2873119 L82.4332865,19.6639253 L84.1532905,19.6639253 Z M63.2182986,13.0509941 L73.7790931,13.0509941 L73.7790931,16.3679818 L67.2185995,16.3679818 L67.2185995,18.7655327 L71.899077,18.7655327 L71.899077,21.8825993 L67.2185995,21.8825993 L67.2185995,24.6193647 L74.119683,24.6193647 L74.119683,27.8361414 L63.2182986,27.8361414 L63.2182986,13.0509941 Z M45.1444623,13.0509941 L49.1447632,13.0509941 L49.1447632,18.5450682 L54.065008,18.5450682 L54.065008,13.0509941 L58.0658106,13.0509941 L58.0658106,27.8361414 L54.065008,27.8361414 L54.065008,21.862056 L49.1447632,21.862056 L49.1447632,27.8361414 L45.1444623,27.8361414 L45.1444623,13.0509941 Z" id="logo" sketch:type="MSShapeGroup"></path>
|
|
11
|
+
</g>
|
|
12
|
+
</g>
|
|
13
|
+
</g>
|
|
14
|
+
</svg>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<svg width="9px" height="6px" viewBox="0 0 9 6" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
|
3
|
+
<!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch -->
|
|
4
|
+
<title>nav-dropdown-caret</title>
|
|
5
|
+
<desc>Created with Sketch.</desc>
|
|
6
|
+
<defs></defs>
|
|
7
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
|
8
|
+
<g id="main" sketch:type="MSArtboardGroup" transform="translate(-267.000000, -42.000000)" stroke="#F2EFFF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
9
|
+
<g id="nav" sketch:type="MSLayerGroup" transform="translate(25.000000, 23.000000)">
|
|
10
|
+
<g id="main" transform="translate(174.000000, 15.000000)" sketch:type="MSShapeGroup">
|
|
11
|
+
<path d="M75.6666667,5 L72.3333333,9 L69,5" id="nav-dropdown-caret"></path>
|
|
12
|
+
</g>
|
|
13
|
+
</g>
|
|
14
|
+
</g>
|
|
15
|
+
</g>
|
|
16
|
+
</svg>
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
//= require lscache
|
|
2
|
+
//= require moment
|
|
3
|
+
|
|
4
|
+
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
|
5
|
+
|
|
6
|
+
Heroku.BlogFetcher = (function() {
|
|
7
|
+
function BlogFetcher(container) {
|
|
8
|
+
this.handleError = bind(this.handleError, this);
|
|
9
|
+
this.appendData = bind(this.appendData, this);
|
|
10
|
+
this.$container = $(container);
|
|
11
|
+
this.init();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
BlogFetcher.prototype.init = function() {
|
|
15
|
+
this.$container
|
|
16
|
+
.on('dataLoaded', this.appendData)
|
|
17
|
+
.on('dataError', this.handleError);
|
|
18
|
+
return this.getPosts();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
BlogFetcher.prototype.getPosts = function() {
|
|
22
|
+
$.support.cors = true;
|
|
23
|
+
if (lscache.get('blogEntry')) {
|
|
24
|
+
return this.$container.trigger('dataLoaded');
|
|
25
|
+
} else {
|
|
26
|
+
var self = this;
|
|
27
|
+
return $.ajax({
|
|
28
|
+
url: 'https://blog.heroku.com/rss_feedburner',
|
|
29
|
+
type: 'GET',
|
|
30
|
+
dataType: 'xml',
|
|
31
|
+
crossDomain: true
|
|
32
|
+
})
|
|
33
|
+
.done(function(result) {
|
|
34
|
+
var obj = self.xmlToJson($(result).find('item')[0]);
|
|
35
|
+
var textBlock = obj.description['#text'];
|
|
36
|
+
var content = typeof textBlock === 'object' ? textBlock[0] : textBlock; // FF treats the textBlock as an object for some reason
|
|
37
|
+
var blog = {
|
|
38
|
+
'title': obj.title['#text'],
|
|
39
|
+
'contentSnippet': self.trimToLength(content, 200),
|
|
40
|
+
'link': obj.link['#text'],
|
|
41
|
+
'publishedDate': obj.pubDate['#text'],
|
|
42
|
+
'author': obj.author['#text']
|
|
43
|
+
};
|
|
44
|
+
lscache.set('blogEntry', blog, 60);
|
|
45
|
+
return self.$container.trigger('dataLoaded');
|
|
46
|
+
})
|
|
47
|
+
.fail(function(e) {
|
|
48
|
+
return self.$container.trigger('dataError');
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
BlogFetcher.prototype.appendData = function() {
|
|
54
|
+
var blogContent = this.$container.find('.js-blog-content');
|
|
55
|
+
this.storedEntry = lscache.get('blogEntry');
|
|
56
|
+
this.$container.find('.js-blog-link').text(this.storedEntry.title);
|
|
57
|
+
this.$container.find('.js-blog-link').attr('href', this.storedEntry.link);
|
|
58
|
+
this.$container.find('.js-blog-date').html(this.buildDateAndAuthor());
|
|
59
|
+
blogContent.html(this.storedEntry.contentSnippet);
|
|
60
|
+
blogContent.find('p').append(' <a href="' + this.storedEntry.link + '">Read More</a>');
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
BlogFetcher.prototype.handleError = function() {
|
|
64
|
+
if (this.storedEntry) {
|
|
65
|
+
return this.$container.trigger('dataloaded');
|
|
66
|
+
} else {
|
|
67
|
+
this.$container.find('.js-blog-link').text('Visit the Heroku Blog');
|
|
68
|
+
this.$container.find('.js-blog-date').empty();
|
|
69
|
+
this.$container.find('.js-blog-content').text('Find news and updates from Heroku in the blog.');
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
BlogFetcher.prototype.buildDateAndAuthor = function() {
|
|
74
|
+
var ago = moment.utc(this.storedEntry.publishedDate, 'ddd, D MMM YYYY hh:mm:ss ZZ').fromNow();
|
|
75
|
+
return ago + " by " + this.storedEntry.author;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
//http://davidwalsh.name/convert-xml-json
|
|
79
|
+
BlogFetcher.prototype.xmlToJson = function(xml) {
|
|
80
|
+
// Create the return object
|
|
81
|
+
var obj = {};
|
|
82
|
+
|
|
83
|
+
if (xml.nodeType == 1) { // element
|
|
84
|
+
// do attributes
|
|
85
|
+
if (xml.attributes.length > 0) {
|
|
86
|
+
obj["@attributes"] = {};
|
|
87
|
+
for (var j = 0; j < xml.attributes.length; j++) {
|
|
88
|
+
var attribute = xml.attributes.item(j);
|
|
89
|
+
obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} else if (xml.nodeType == 3) { // text
|
|
93
|
+
obj = xml.nodeValue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// do children
|
|
97
|
+
if (xml.hasChildNodes()) {
|
|
98
|
+
for(var i = 0; i < xml.childNodes.length; i++) {
|
|
99
|
+
var item = xml.childNodes.item(i);
|
|
100
|
+
var nodeName = item.nodeName;
|
|
101
|
+
if (typeof(obj[nodeName]) == "undefined") {
|
|
102
|
+
obj[nodeName] = this.xmlToJson(item);
|
|
103
|
+
} else {
|
|
104
|
+
if (typeof(obj[nodeName].push) == "undefined") {
|
|
105
|
+
var old = obj[nodeName];
|
|
106
|
+
obj[nodeName] = [];
|
|
107
|
+
obj[nodeName].push(old);
|
|
108
|
+
}
|
|
109
|
+
obj[nodeName].push(this.xmlToJson(item));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return obj;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
BlogFetcher.prototype.trimToLength = function(str, max) {
|
|
117
|
+
if (str.length > max) {
|
|
118
|
+
return jQuery.trim(str).substring(0, max).split(' ').slice(0, -1).join(' ') + '...';
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
return str;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
return BlogFetcher;
|
|
126
|
+
|
|
127
|
+
})();
|
|
128
|
+
|
|
129
|
+
$(function() {
|
|
130
|
+
return window.Heroku.latestBlog = new Heroku.BlogFetcher('#more-blog');
|
|
131
|
+
});
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var Heroku = Heroku || {};
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lscache library
|
|
3
|
+
* Copyright (c) 2011, Pamela Fox
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/* jshint undef:true, browser:true, node:true */
|
|
19
|
+
/* global define */
|
|
20
|
+
|
|
21
|
+
(function (root, factory) {
|
|
22
|
+
if (typeof define === 'function' && define.amd) {
|
|
23
|
+
// AMD. Register as an anonymous module.
|
|
24
|
+
define([], factory);
|
|
25
|
+
} else if (typeof module !== "undefined" && module.exports) {
|
|
26
|
+
// CommonJS/Node module
|
|
27
|
+
module.exports = factory();
|
|
28
|
+
} else {
|
|
29
|
+
// Browser globals
|
|
30
|
+
root.lscache = factory();
|
|
31
|
+
}
|
|
32
|
+
}(this, function () {
|
|
33
|
+
|
|
34
|
+
// Prefix for all lscache keys
|
|
35
|
+
var CACHE_PREFIX = 'lscache-';
|
|
36
|
+
|
|
37
|
+
// Suffix for the key name on the expiration items in localStorage
|
|
38
|
+
var CACHE_SUFFIX = '-cacheexpiration';
|
|
39
|
+
|
|
40
|
+
// expiration date radix (set to Base-36 for most space savings)
|
|
41
|
+
var EXPIRY_RADIX = 10;
|
|
42
|
+
|
|
43
|
+
// time resolution in minutes
|
|
44
|
+
var EXPIRY_UNITS = 60 * 1000;
|
|
45
|
+
|
|
46
|
+
// ECMAScript max Date (epoch + 1e8 days)
|
|
47
|
+
var MAX_DATE = Math.floor(8.64e15/EXPIRY_UNITS);
|
|
48
|
+
|
|
49
|
+
var cachedStorage;
|
|
50
|
+
var cachedJSON;
|
|
51
|
+
var cacheBucket = '';
|
|
52
|
+
var warnings = false;
|
|
53
|
+
|
|
54
|
+
// Determines if localStorage is supported in the browser;
|
|
55
|
+
// result is cached for better performance instead of being run each time.
|
|
56
|
+
// Feature detection is based on how Modernizr does it;
|
|
57
|
+
// it's not straightforward due to FF4 issues.
|
|
58
|
+
// It's not run at parse-time as it takes 200ms in Android.
|
|
59
|
+
function supportsStorage() {
|
|
60
|
+
var key = '__lscachetest__';
|
|
61
|
+
var value = key;
|
|
62
|
+
|
|
63
|
+
if (cachedStorage !== undefined) {
|
|
64
|
+
return cachedStorage;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
setItem(key, value);
|
|
69
|
+
removeItem(key);
|
|
70
|
+
cachedStorage = true;
|
|
71
|
+
} catch (e) {
|
|
72
|
+
if (isOutOfSpace(e)) { // If we hit the limit, then it means we have support,
|
|
73
|
+
cachedStorage = true; // just maxed it out and even the set test failed.
|
|
74
|
+
} else {
|
|
75
|
+
cachedStorage = false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return cachedStorage;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check to set if the error is us dealing with being out of space
|
|
82
|
+
function isOutOfSpace(e) {
|
|
83
|
+
if (e && e.name === 'QUOTA_EXCEEDED_ERR' ||
|
|
84
|
+
e.name === 'NS_ERROR_DOM_QUOTA_REACHED' ||
|
|
85
|
+
e.name === 'QuotaExceededError') {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Determines if native JSON (de-)serialization is supported in the browser.
|
|
92
|
+
function supportsJSON() {
|
|
93
|
+
/*jshint eqnull:true */
|
|
94
|
+
if (cachedJSON === undefined) {
|
|
95
|
+
cachedJSON = (window.JSON != null);
|
|
96
|
+
}
|
|
97
|
+
return cachedJSON;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Returns a string where all RegExp special characters are escaped with a \.
|
|
102
|
+
* @param {String} text
|
|
103
|
+
* @return {string}
|
|
104
|
+
*/
|
|
105
|
+
function escapeRegExpSpecialCharacters(text) {
|
|
106
|
+
return text.replace(/[[\]{}()*+?.\\^$|]/g, '\\$&');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Returns the full string for the localStorage expiration item.
|
|
111
|
+
* @param {String} key
|
|
112
|
+
* @return {string}
|
|
113
|
+
*/
|
|
114
|
+
function expirationKey(key) {
|
|
115
|
+
return key + CACHE_SUFFIX;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Returns the number of minutes since the epoch.
|
|
120
|
+
* @return {number}
|
|
121
|
+
*/
|
|
122
|
+
function currentTime() {
|
|
123
|
+
return Math.floor((new Date().getTime())/EXPIRY_UNITS);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Wrapper functions for localStorage methods
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
function getItem(key) {
|
|
131
|
+
return localStorage.getItem(CACHE_PREFIX + cacheBucket + key);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function setItem(key, value) {
|
|
135
|
+
// Fix for iPad issue - sometimes throws QUOTA_EXCEEDED_ERR on setItem.
|
|
136
|
+
localStorage.removeItem(CACHE_PREFIX + cacheBucket + key);
|
|
137
|
+
localStorage.setItem(CACHE_PREFIX + cacheBucket + key, value);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function removeItem(key) {
|
|
141
|
+
localStorage.removeItem(CACHE_PREFIX + cacheBucket + key);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function eachKey(fn) {
|
|
145
|
+
var prefixRegExp = new RegExp('^' + CACHE_PREFIX + escapeRegExpSpecialCharacters(cacheBucket) + '(.*)');
|
|
146
|
+
// Loop in reverse as removing items will change indices of tail
|
|
147
|
+
for (var i = localStorage.length-1; i >= 0 ; --i) {
|
|
148
|
+
var key = localStorage.key(i);
|
|
149
|
+
key = key && key.match(prefixRegExp);
|
|
150
|
+
key = key && key[1];
|
|
151
|
+
if (key && key.indexOf(CACHE_SUFFIX) < 0) {
|
|
152
|
+
fn(key, expirationKey(key));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function flushItem(key) {
|
|
158
|
+
var exprKey = expirationKey(key);
|
|
159
|
+
|
|
160
|
+
removeItem(key);
|
|
161
|
+
removeItem(exprKey);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function flushExpiredItem(key) {
|
|
165
|
+
var exprKey = expirationKey(key);
|
|
166
|
+
var expr = getItem(exprKey);
|
|
167
|
+
|
|
168
|
+
if (expr) {
|
|
169
|
+
var expirationTime = parseInt(expr, EXPIRY_RADIX);
|
|
170
|
+
|
|
171
|
+
// Check if we should actually kick item out of storage
|
|
172
|
+
if (currentTime() >= expirationTime) {
|
|
173
|
+
removeItem(key);
|
|
174
|
+
removeItem(exprKey);
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function warn(message, err) {
|
|
181
|
+
if (!warnings) return;
|
|
182
|
+
if (!('console' in window) || typeof window.console.warn !== 'function') return;
|
|
183
|
+
window.console.warn("lscache - " + message);
|
|
184
|
+
if (err) window.console.warn("lscache - The error was: " + err.message);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
var lscache = {
|
|
188
|
+
/**
|
|
189
|
+
* Stores the value in localStorage. Expires after specified number of minutes.
|
|
190
|
+
* @param {string} key
|
|
191
|
+
* @param {Object|string} value
|
|
192
|
+
* @param {number} time
|
|
193
|
+
*/
|
|
194
|
+
set: function(key, value, time) {
|
|
195
|
+
if (!supportsStorage()) return;
|
|
196
|
+
|
|
197
|
+
// If we don't get a string value, try to stringify
|
|
198
|
+
// In future, localStorage may properly support storing non-strings
|
|
199
|
+
// and this can be removed.
|
|
200
|
+
if (typeof value !== 'string') {
|
|
201
|
+
if (!supportsJSON()) return;
|
|
202
|
+
try {
|
|
203
|
+
value = JSON.stringify(value);
|
|
204
|
+
} catch (e) {
|
|
205
|
+
// Sometimes we can't stringify due to circular refs
|
|
206
|
+
// in complex objects, so we won't bother storing then.
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
setItem(key, value);
|
|
213
|
+
} catch (e) {
|
|
214
|
+
if (isOutOfSpace(e)) {
|
|
215
|
+
// If we exceeded the quota, then we will sort
|
|
216
|
+
// by the expire time, and then remove the N oldest
|
|
217
|
+
var storedKeys = [];
|
|
218
|
+
var storedKey;
|
|
219
|
+
eachKey(function(key, exprKey) {
|
|
220
|
+
var expiration = getItem(exprKey);
|
|
221
|
+
if (expiration) {
|
|
222
|
+
expiration = parseInt(expiration, EXPIRY_RADIX);
|
|
223
|
+
} else {
|
|
224
|
+
// TODO: Store date added for non-expiring items for smarter removal
|
|
225
|
+
expiration = MAX_DATE;
|
|
226
|
+
}
|
|
227
|
+
storedKeys.push({
|
|
228
|
+
key: key,
|
|
229
|
+
size: (getItem(key) || '').length,
|
|
230
|
+
expiration: expiration
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
// Sorts the keys with oldest expiration time last
|
|
234
|
+
storedKeys.sort(function(a, b) { return (b.expiration-a.expiration); });
|
|
235
|
+
|
|
236
|
+
var targetSize = (value||'').length;
|
|
237
|
+
while (storedKeys.length && targetSize > 0) {
|
|
238
|
+
storedKey = storedKeys.pop();
|
|
239
|
+
warn("Cache is full, removing item with key '" + key + "'");
|
|
240
|
+
flushItem(storedKey.key);
|
|
241
|
+
targetSize -= storedKey.size;
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
setItem(key, value);
|
|
245
|
+
} catch (e) {
|
|
246
|
+
// value may be larger than total quota
|
|
247
|
+
warn("Could not add item with key '" + key + "', perhaps it's too big?", e);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
// If it was some other error, just give up.
|
|
252
|
+
warn("Could not add item with key '" + key + "'", e);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// If a time is specified, store expiration info in localStorage
|
|
258
|
+
if (time) {
|
|
259
|
+
setItem(expirationKey(key), (currentTime() + time).toString(EXPIRY_RADIX));
|
|
260
|
+
} else {
|
|
261
|
+
// In case they previously set a time, remove that info from localStorage.
|
|
262
|
+
removeItem(expirationKey(key));
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Retrieves specified value from localStorage, if not expired.
|
|
268
|
+
* @param {string} key
|
|
269
|
+
* @return {string|Object}
|
|
270
|
+
*/
|
|
271
|
+
get: function(key) {
|
|
272
|
+
if (!supportsStorage()) return null;
|
|
273
|
+
|
|
274
|
+
// Return the de-serialized item if not expired
|
|
275
|
+
if (flushExpiredItem(key)) { return null; }
|
|
276
|
+
|
|
277
|
+
// Tries to de-serialize stored value if its an object, and returns the normal value otherwise.
|
|
278
|
+
var value = getItem(key);
|
|
279
|
+
if (!value || !supportsJSON()) {
|
|
280
|
+
return value;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
// We can't tell if its JSON or a string, so we try to parse
|
|
285
|
+
return JSON.parse(value);
|
|
286
|
+
} catch (e) {
|
|
287
|
+
// If we can't parse, it's probably because it isn't an object
|
|
288
|
+
return value;
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Removes a value from localStorage.
|
|
294
|
+
* Equivalent to 'delete' in memcache, but that's a keyword in JS.
|
|
295
|
+
* @param {string} key
|
|
296
|
+
*/
|
|
297
|
+
remove: function(key) {
|
|
298
|
+
if (!supportsStorage()) return;
|
|
299
|
+
|
|
300
|
+
flushItem(key);
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Returns whether local storage is supported.
|
|
305
|
+
* Currently exposed for testing purposes.
|
|
306
|
+
* @return {boolean}
|
|
307
|
+
*/
|
|
308
|
+
supported: function() {
|
|
309
|
+
return supportsStorage();
|
|
310
|
+
},
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Flushes all lscache items and expiry markers without affecting rest of localStorage
|
|
314
|
+
*/
|
|
315
|
+
flush: function() {
|
|
316
|
+
if (!supportsStorage()) return;
|
|
317
|
+
|
|
318
|
+
eachKey(function(key) {
|
|
319
|
+
flushItem(key);
|
|
320
|
+
});
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Flushes expired lscache items and expiry markers without affecting rest of localStorage
|
|
325
|
+
*/
|
|
326
|
+
flushExpired: function() {
|
|
327
|
+
if (!supportsStorage()) return;
|
|
328
|
+
|
|
329
|
+
eachKey(function(key) {
|
|
330
|
+
flushExpiredItem(key);
|
|
331
|
+
});
|
|
332
|
+
},
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Appends CACHE_PREFIX so lscache will partition data in to different buckets.
|
|
336
|
+
* @param {string} bucket
|
|
337
|
+
*/
|
|
338
|
+
setBucket: function(bucket) {
|
|
339
|
+
cacheBucket = bucket;
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Resets the string being appended to CACHE_PREFIX so lscache will use the default storage behavior.
|
|
344
|
+
*/
|
|
345
|
+
resetBucket: function() {
|
|
346
|
+
cacheBucket = '';
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Sets whether to display warnings when an item is removed from the cache or not.
|
|
351
|
+
*/
|
|
352
|
+
enableWarnings: function(enabled) {
|
|
353
|
+
warnings = enabled;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
// Return the module
|
|
358
|
+
return lscache;
|
|
359
|
+
}));
|