alula 0.2.3 → 0.4.0b

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 (182) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +7 -0
  3. data/Guardfile +9 -0
  4. data/Rakefile +12 -1
  5. data/VERSION +1 -1
  6. data/alula.gemspec +20 -4
  7. data/lib/alula/attachment_processor.rb +77 -0
  8. data/lib/alula/cdn.rb +30 -0
  9. data/lib/alula/cdns/edgecast.rb +16 -0
  10. data/lib/alula/cdns/hosts.rb +14 -0
  11. data/lib/alula/cli.rb +90 -39
  12. data/lib/alula/compressors.rb +22 -10
  13. data/lib/alula/config.rb +141 -0
  14. data/lib/alula/content.rb +113 -0
  15. data/lib/alula/contents/attachment.rb +8 -0
  16. data/lib/alula/contents/item.rb +409 -0
  17. data/lib/alula/contents/metadata.rb +73 -0
  18. data/lib/alula/contents/page.rb +9 -0
  19. data/lib/alula/contents/post.rb +32 -0
  20. data/lib/alula/context.rb +72 -0
  21. data/lib/alula/core_ext.rb +5 -0
  22. data/lib/alula/core_ext/environment.rb +20 -0
  23. data/lib/alula/core_ext/filter.rb +20 -0
  24. data/lib/alula/core_ext/filters/smilies.rb +36 -0
  25. data/lib/alula/core_ext/manifest.rb +30 -0
  26. data/lib/alula/core_ext/tag.rb +100 -0
  27. data/lib/alula/core_ext/tags/attachment.rb +28 -0
  28. data/lib/alula/core_ext/tags/blockquote.rb +21 -0
  29. data/lib/alula/core_ext/tags/image.rb +48 -0
  30. data/lib/alula/core_ext/tags/locale.rb +17 -0
  31. data/lib/alula/core_ext/tags/video.rb +103 -0
  32. data/lib/alula/generator.rb +31 -0
  33. data/lib/alula/generators/feedbuilder.rb +44 -0
  34. data/lib/alula/generators/paginate.rb +88 -0
  35. data/lib/alula/generators/sitemap.rb +26 -0
  36. data/lib/alula/helpers.rb +2 -0
  37. data/lib/alula/helpers/addons.rb +12 -0
  38. data/lib/alula/helpers/assets.rb +56 -0
  39. data/lib/alula/helpers/url_helpers.rb +16 -0
  40. data/lib/alula/plugin.rb +32 -0
  41. data/lib/alula/processor.rb +86 -0
  42. data/lib/alula/processors/dummy.rb +24 -0
  43. data/lib/alula/processors/image.rb +52 -0
  44. data/lib/alula/processors/magick.rb +83 -0
  45. data/lib/alula/processors/video.rb +97 -0
  46. data/lib/alula/processors/zencoder.rb +199 -0
  47. data/lib/alula/progress.rb +95 -0
  48. data/lib/alula/progressbar.rb +66 -0
  49. data/lib/alula/site.rb +331 -262
  50. data/lib/alula/storage.rb +46 -0
  51. data/lib/alula/storages/file_item.rb +43 -0
  52. data/lib/alula/storages/filestorage.rb +96 -0
  53. data/lib/alula/storages/item.rb +12 -0
  54. data/lib/alula/support/commonlogger.rb +30 -0
  55. data/lib/alula/theme.rb +70 -13
  56. data/lib/alula/theme/layout.rb +56 -0
  57. data/lib/alula/theme/view.rb +43 -0
  58. data/lib/alula/version.rb +1 -1
  59. data/locales/en.yml +9 -0
  60. data/locales/fi.yml +10 -0
  61. data/locales/l10n/ar.yml +199 -0
  62. data/locales/l10n/az.yml +199 -0
  63. data/locales/l10n/bg.yml +199 -0
  64. data/locales/l10n/bn-IN.yml +182 -0
  65. data/locales/l10n/bs.yml +242 -0
  66. data/locales/l10n/ca.yml +199 -0
  67. data/locales/l10n/cs.yml +198 -0
  68. data/locales/l10n/csb.yml +210 -0
  69. data/locales/l10n/cy.yml +199 -0
  70. data/locales/l10n/da.yml +199 -0
  71. data/locales/l10n/de-AT.yml +203 -0
  72. data/locales/l10n/de-CH.yml +203 -0
  73. data/locales/l10n/de.yml +203 -0
  74. data/locales/l10n/dsb.yml +215 -0
  75. data/locales/l10n/el.yml +199 -0
  76. data/locales/l10n/en-AU.yml +205 -0
  77. data/locales/l10n/en-CA.yml +214 -0
  78. data/locales/l10n/en-GB.yml +205 -0
  79. data/locales/l10n/en-IN.yml +205 -0
  80. data/locales/l10n/en-US.yml +205 -0
  81. data/locales/l10n/en.yml +205 -0
  82. data/locales/l10n/eo.yml +201 -0
  83. data/locales/l10n/es-AR.yml +205 -0
  84. data/locales/l10n/es-CL.yml +199 -0
  85. data/locales/l10n/es-CO.yml +205 -0
  86. data/locales/l10n/es-MX.yml +205 -0
  87. data/locales/l10n/es-PE.yml +181 -0
  88. data/locales/l10n/es-VE.yml +205 -0
  89. data/locales/l10n/es.yml +199 -0
  90. data/locales/l10n/et.yml +199 -0
  91. data/locales/l10n/eu.yml +199 -0
  92. data/locales/l10n/fa.yml +199 -0
  93. data/locales/l10n/fi.yml +199 -0
  94. data/locales/l10n/fr-CA.yml +207 -0
  95. data/locales/l10n/fr-CH.yml +207 -0
  96. data/locales/l10n/fr.yml +222 -0
  97. data/locales/l10n/fur.yml +199 -0
  98. data/locales/l10n/gl-ES.yml +178 -0
  99. data/locales/l10n/gsw-CH.yml +199 -0
  100. data/locales/l10n/he.yml +201 -0
  101. data/locales/l10n/hi-IN.yml +199 -0
  102. data/locales/l10n/hi.yml +199 -0
  103. data/locales/l10n/hr.yml +237 -0
  104. data/locales/l10n/hsb.yml +214 -0
  105. data/locales/l10n/hu.yml +199 -0
  106. data/locales/l10n/id.yml +200 -0
  107. data/locales/l10n/is.yml +213 -0
  108. data/locales/l10n/it.yml +205 -0
  109. data/locales/l10n/ja.yml +197 -0
  110. data/locales/l10n/kn.yml +199 -0
  111. data/locales/l10n/ko.yml +197 -0
  112. data/locales/l10n/lo.yml +186 -0
  113. data/locales/l10n/lt.yml +182 -0
  114. data/locales/l10n/lv.yml +215 -0
  115. data/locales/l10n/mk.yml +170 -0
  116. data/locales/l10n/mn.yml +205 -0
  117. data/locales/l10n/nb.yml +207 -0
  118. data/locales/l10n/nl.yml +199 -0
  119. data/locales/l10n/nn.yml +160 -0
  120. data/locales/l10n/pl.yml +221 -0
  121. data/locales/l10n/pt-BR.yml +207 -0
  122. data/locales/l10n/pt-PT.yml +207 -0
  123. data/locales/l10n/quotes.yml +24 -0
  124. data/locales/l10n/rm.yml +182 -0
  125. data/locales/l10n/ro.yml +199 -0
  126. data/locales/l10n/ru.yml +257 -0
  127. data/locales/l10n/sk.yml +213 -0
  128. data/locales/l10n/sl.yml +210 -0
  129. data/locales/l10n/sr-Latn.yml +170 -0
  130. data/locales/l10n/sr.yml +170 -0
  131. data/locales/l10n/sv-SE.yml +199 -0
  132. data/locales/l10n/sw.yml +197 -0
  133. data/locales/l10n/th.yml +173 -0
  134. data/locales/l10n/tl.yml +229 -0
  135. data/locales/l10n/tr.yml +199 -0
  136. data/locales/l10n/uk.yml +257 -0
  137. data/locales/l10n/vi.yml +201 -0
  138. data/locales/l10n/wo.yml +205 -0
  139. data/locales/l10n/zh-CN.yml +199 -0
  140. data/locales/l10n/zh-TW.yml +199 -0
  141. data/template/Gemfile.erb +14 -4
  142. data/template/README +16 -0
  143. data/template/config.yml.erb +42 -38
  144. data/test/fixtures/config_001_simple.yml +2 -0
  145. data/test/fixtures/config_002_l10n.yml +5 -0
  146. data/test/fixtures/pages/invalid-page.markdown +1 -0
  147. data/test/fixtures/pages/multilingual-page.markdown +20 -0
  148. data/test/fixtures/pages/section/subpage.markdown +5 -0
  149. data/test/fixtures/pages/simple-page.markdown +7 -0
  150. data/test/fixtures/posts/2012-07-02-invalid-post.markdown +1 -0
  151. data/test/fixtures/posts/2012-07-02-simple.markdown +7 -0
  152. data/test/fixtures/posts/2012-07-03-full-metadata.markdown +8 -0
  153. data/test/fixtures/posts/2012-07-03-multilingual-full-metadata.markdown +20 -0
  154. data/test/fixtures/theme/test/layouts/default.html.erb +1 -0
  155. data/test/fixtures/theme/test/views/page.html.erb +1 -0
  156. data/test/fixtures/theme/test/views/post.html.erb +1 -0
  157. data/test/minitest_helper.rb +14 -0
  158. data/test/test_config.rb +33 -0
  159. data/test/test_content.rb +30 -0
  160. data/test/test_metadata.rb +83 -0
  161. data/test/test_page.rb +81 -0
  162. data/test/test_post.rb +123 -0
  163. data/test/test_storage.rb +23 -0
  164. data/test/test_storage_file.rb +32 -0
  165. data/test/test_theme.rb +45 -0
  166. data/vendor/assets/images/favicon.png +0 -0
  167. data/vendor/assets/images/grey.gif +0 -0
  168. data/vendor/assets/javascripts/jquery.alula.js.coffee +16 -0
  169. data/vendor/{javascripts → assets/javascripts}/jquery.js +0 -0
  170. data/vendor/assets/javascripts/jquery.lazyload.js +210 -0
  171. data/vendor/assets/javascripts/lazyload.js.coffee +15 -0
  172. data/vendor/layouts/feed.xml.builder +19 -0
  173. data/vendor/layouts/sitemap.xml.builder +10 -0
  174. data/vendor/views/feed_post.html.haml +1 -0
  175. metadata +529 -50
  176. data/lib/alula.rb +0 -5
  177. data/lib/alula/assethelper.rb +0 -75
  178. data/lib/alula/plugins.rb +0 -23
  179. data/lib/alula/plugins/assets.rb +0 -82
  180. data/lib/alula/plugins/pagination.rb +0 -121
  181. data/lib/alula/rake_tasks.rb +0 -42
  182. data/lib/alula/tasks.rb +0 -2
@@ -0,0 +1,123 @@
1
+ require "minitest_helper"
2
+ require 'alula/contents/post'
3
+ require 'alula/config'
4
+ require 'alula/storage'
5
+
6
+ describe Alula::Content::Post do
7
+ before do
8
+ @site = MiniTest::Mock.new
9
+ @site.expect :context, {}
10
+ @site.expect :config, OpenStruct.new({
11
+ permalinks: "/:year/:month/:title/",
12
+ pagelinks: "/:locale/:slug/",
13
+ locale: "en", hides_base_locale: true,
14
+ })
15
+ end
16
+
17
+ def mock_item(name)
18
+ item = MiniTest::Mock.new
19
+ item.expect :nil?, false
20
+ item.expect :exists?, File.exists?("test/fixtures/posts/#{name}")
21
+ item.expect :name, name
22
+ if File.exists?("test/fixtures/posts/#{name}")
23
+ item.expect :has_payload?, File.read("test/fixtures/posts/#{name}", 3) == "---"
24
+ item.expect :read, File.read("test/fixtures/posts/#{name}")
25
+ end
26
+
27
+ item
28
+ end
29
+
30
+ let :missing_post do
31
+ mock_item("invalid.file")
32
+ end
33
+
34
+ let :simple_post do
35
+ mock_item("2012-07-02-simple.markdown")
36
+ end
37
+
38
+ let :metadata_post do
39
+ mock_item("2012-07-03-full-metadata.markdown")
40
+ end
41
+
42
+ let :invalid_post do
43
+ mock_item("2012-07-02-invalid-post.markdown")
44
+ end
45
+
46
+ let :complex_post do
47
+ mock_item("2012-07-03-multilingual-full-metadata.markdown")
48
+ end
49
+
50
+ it "fails with non-existing file" do
51
+ post = Alula::Content::Post.load(item: missing_post, site: @site)
52
+ post.must_be_nil
53
+ end
54
+
55
+ it "skips invalid post" do
56
+ post = Alula::Content::Post.load(item: invalid_post, site: @site)
57
+ end
58
+
59
+ it "parses simple post" do
60
+ post = Alula::Content::Post.load(item: simple_post, site: @site)
61
+ post.metadata.title.must_equal "Simple Post"
62
+ post.metadata.languages.must_be_nil
63
+
64
+ # Parse and render
65
+ post.send(:parse_liquid).must_equal "# Header\n\nThis is a simple post.\n"
66
+ post.send(:parse_markdown).must_equal "<h1>Header</h1>\n\n<p>This is a simple post.</p>\n"
67
+
68
+ # Path and URI must be correct
69
+ post.path.must_equal "/2012/07/simple-post/index.html"
70
+ post.url.must_equal "/2012/07/simple-post/"
71
+ end
72
+
73
+ it "parses full metadata post" do
74
+ post = Alula::Content::Post.load(item: metadata_post, site: @site)
75
+ post.url.must_equal "/blog/path/to/long/nonce/to/get/nonce/"
76
+ post.path.must_equal "/blog/path/to/long/nonce/to/get/nonce/index.html"
77
+ end
78
+
79
+ it "parses complex post" do
80
+ @site.config.permalinks = "/:locale/:year/:month/:title/"
81
+ @site.config.locale = "en"
82
+ @site.config.hides_base_locale = true
83
+
84
+ post = Alula::Content::Post.load(item: complex_post, site: @site)
85
+ post.metadata.title.must_equal "Multilingual Post"
86
+ post.metadata.languages.must_equal ["en", "fi"]
87
+ post.metadata.title("fi").must_equal "Monikielinen kirjoitelma"
88
+
89
+ post.url.must_equal "/2012/07/multilingual-post/"
90
+ post.url("fi").must_equal "/fi/2012/07/monikielinen-kirjoitelma/"
91
+
92
+ @site.config.hides_base_locale = false
93
+ post = Alula::Content::Post.load(item: complex_post, site: @site)
94
+ post.url.must_equal "/en/2012/07/multilingual-post/"
95
+
96
+ @site.config.permalinks = "/:locale/:year/:slug"
97
+ post = Alula::Content::Post.load(item: complex_post, site: @site)
98
+ post.url("fi").must_equal "/fi/2012/monikielinen-blogi-kirjoitelma.html"
99
+ post.path("fi").must_equal "/fi/2012/monikielinen-blogi-kirjoitelma.html"
100
+ end
101
+
102
+ it "renders content on simple post" do
103
+ # Create mockup layout
104
+ view = MiniTest::Mock.new
105
+ view.expect :render, "<h1>Header</h1>", [{}]
106
+
107
+ layout = MiniTest::Mock.new
108
+
109
+ theme = MiniTest::Mock.new
110
+ theme.expect :view, view, ["post"]
111
+
112
+ site = MiniTest::Mock.new
113
+ site.expect :context, {}
114
+ site.expect :config, OpenStruct.new({locale: "en"})
115
+ site.expect :theme, theme
116
+ post = Alula::Content::Post.load(item: simple_post, site: site)
117
+
118
+ # Render page using current layout, for all languages
119
+ post.render
120
+ post.content.must_equal "<h1>Header</h1>"
121
+
122
+ end
123
+ end
@@ -0,0 +1,23 @@
1
+ require "minitest_helper"
2
+ require 'alula/storage'
3
+ require 'ostruct'
4
+
5
+ describe "Storage" do
6
+ before do
7
+ @site = MiniTest::Mock.new
8
+ @site.expect :config, OpenStruct.new({})
9
+ end
10
+
11
+ it "loads proper provider" do
12
+ puts ":: #{@site.config.storage.inspect}"
13
+ @site.config.storage = {"none" => {}}
14
+ storage = Alula::Storage.load(site: @site)
15
+ storage.must_be_nil
16
+
17
+ @site.config.storage = {"file" => { "content_path" => 'test/fixtures', "pages_path" => 'test/fixtures/pages',
18
+ "posts_path" => 'test/fixtures/posts', "attachments_path" => 'test/fixtures/attachments', "public_path" => 'public' }}
19
+ storage = Alula::Storage.load(site: @site)
20
+ storage.wont_be_nil
21
+
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ require "minitest_helper"
2
+ require 'alula/storages/file'
3
+ require 'ostruct'
4
+
5
+ describe "File Storage" do
6
+ before do
7
+ @site = MiniTest::Mock.new
8
+ @config = {
9
+ "content_path" => 'test/fixtures',
10
+ "pages_path" => 'test/fixtures/pages',
11
+ "posts_path" => 'test/fixtures/posts',
12
+ "attachments_path" => 'test/fixtures/attachments',
13
+ "public_path" => 'public',
14
+ }
15
+ end
16
+
17
+ it "accept simple configuration" do
18
+ storage = Alula::Storage::File.new(@config, site: @site)
19
+ end
20
+
21
+ it "lists all posts" do
22
+ storage = Alula::Storage::File.new(@config, site: @site)
23
+ storage.posts.count.must_equal 4
24
+ storage.post("2012-07-02-simple.markdown").wont_be_nil
25
+ end
26
+
27
+ it "list all pages" do
28
+ storage = Alula::Storage::File.new(@config, site: @site)
29
+ storage.pages.count.must_equal 4
30
+ storage.page("simple-page.markdown").wont_be_nil
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ require "minitest_helper"
2
+ require 'alula/theme'
3
+ require 'ostruct'
4
+
5
+ describe "Themes" do
6
+ before do
7
+ context = Object.new
8
+ context.class.class_eval do
9
+ def initialize; @vars = {}; end
10
+ def [](key); @vars[key]; end
11
+ def []=(key, val); @vars[key] = val; end
12
+ def method_missing(meth, *args, &blk); return @vars[meth] if @vars; super; end
13
+ end
14
+
15
+ @site = MiniTest::Mock.new
16
+ @site.expect :config, OpenStruct.new({theme: 'test'})
17
+ @site.expect :context, context
18
+
19
+ # Register our theme
20
+ Alula::Theme.register(:test, "test/fixtures/theme")
21
+ end
22
+
23
+ it "doesn't load nonexisting theme" do
24
+ @site.config.theme = "unknown"
25
+ theme = Alula::Theme.load(site: @site)
26
+ theme.must_be_nil
27
+ end
28
+
29
+ it "has working theme" do
30
+ @site.config.theme = "test"
31
+ theme = Alula::Theme.load(site: @site)
32
+ theme.wont_be_nil
33
+
34
+ # Find layout
35
+ layout = theme.layout("default")
36
+ layout.wont_be_nil
37
+
38
+ # Find view
39
+ view = theme.view("post")
40
+ view.wont_be_nil
41
+
42
+ # Test rendering
43
+ view.render(content: "Theme Test").must_equal "<html><body><p>Theme Test</p></body></html>"
44
+ end
45
+ end
@@ -0,0 +1,16 @@
1
+ #=require jquery
2
+ #
3
+ # Copyright Owl Forstry
4
+ # Alula JavaScript additions
5
+
6
+ # Make sure we have devicePixelRatio always available
7
+ jQuery.getDevicePixelRatio = ->
8
+ if window.devicePixelRatio is undefined
9
+ return 1
10
+ else
11
+ return window.devicePixelRatio
12
+
13
+ # Hide mobile Safari address bar
14
+ jQuery ->
15
+ delay = (ms, func) -> setTimeout func, ms
16
+ delay 0, -> window.scrollTo(0, 1)
@@ -0,0 +1,210 @@
1
+ /*
2
+ * Lazy Load - jQuery plugin for lazy loading images
3
+ *
4
+ * Copyright (c) 2007-2012 Mika Tuupola
5
+ *
6
+ * Licensed under the MIT license:
7
+ * http://www.opensource.org/licenses/mit-license.php
8
+ *
9
+ * Project home:
10
+ * http://www.appelsiini.net/projects/lazyload
11
+ *
12
+ * Version: 1.7.2
13
+ *
14
+ */
15
+ (function($, window) {
16
+
17
+ $window = $(window);
18
+
19
+ $.fn.lazyload = function(options) {
20
+ var elements = this;
21
+ var settings = {
22
+ threshold : 0,
23
+ failure_limit : 0,
24
+ event : "scroll",
25
+ effect : "show",
26
+ container : window,
27
+ data_attribute : "original",
28
+ skip_invisible : true,
29
+ appear : null,
30
+ load : null
31
+ };
32
+
33
+ function update() {
34
+ var counter = 0;
35
+
36
+ elements.each(function() {
37
+ var $this = $(this);
38
+ if (settings.skip_invisible && !$this.is(":visible")) {
39
+ return;
40
+ }
41
+ if ($.abovethetop(this, settings) ||
42
+ $.leftofbegin(this, settings)) {
43
+ /* Nothing. */
44
+ } else if (!$.belowthefold(this, settings) &&
45
+ !$.rightoffold(this, settings)) {
46
+ $this.trigger("appear");
47
+ } else {
48
+ if (++counter > settings.failure_limit) {
49
+ return false;
50
+ }
51
+ }
52
+ });
53
+
54
+ }
55
+
56
+ if(options) {
57
+ /* Maintain BC for a couple of versions. */
58
+ if (undefined !== options.failurelimit) {
59
+ options.failure_limit = options.failurelimit;
60
+ delete options.failurelimit;
61
+ }
62
+ if (undefined !== options.effectspeed) {
63
+ options.effect_speed = options.effectspeed;
64
+ delete options.effectspeed;
65
+ }
66
+
67
+ $.extend(settings, options);
68
+ }
69
+
70
+ /* Cache container as jQuery as object. */
71
+ $container = (settings.container === undefined ||
72
+ settings.container === window) ? $window : $(settings.container);
73
+
74
+ /* Fire one scroll event per scroll. Not one scroll event per image. */
75
+ if (0 === settings.event.indexOf("scroll")) {
76
+ $container.bind(settings.event, function(event) {
77
+ return update();
78
+ });
79
+ }
80
+
81
+ this.each(function() {
82
+ var self = this;
83
+ var $self = $(self);
84
+
85
+ self.loaded = false;
86
+
87
+ /* When appear is triggered load original image. */
88
+ $self.one("appear", function() {
89
+ if (!this.loaded) {
90
+ if (settings.appear) {
91
+ var elements_left = elements.length;
92
+ settings.appear.call(self, elements_left, settings);
93
+ }
94
+ $("<img />")
95
+ .bind("load", function() {
96
+ $self
97
+ .hide()
98
+ .attr("src", $self.data(settings.data_attribute))
99
+ [settings.effect](settings.effect_speed);
100
+ self.loaded = true;
101
+
102
+ /* Remove image from array so it is not looped next time. */
103
+ var temp = $.grep(elements, function(element) {
104
+ return !element.loaded;
105
+ });
106
+ elements = $(temp);
107
+
108
+ if (settings.load) {
109
+ var elements_left = elements.length;
110
+ settings.load.call(self, elements_left, settings);
111
+ }
112
+ })
113
+ .attr("src", $self.data(settings.data_attribute));
114
+ }
115
+ });
116
+
117
+ /* When wanted event is triggered load original image */
118
+ /* by triggering appear. */
119
+ if (0 !== settings.event.indexOf("scroll")) {
120
+ $self.bind(settings.event, function(event) {
121
+ if (!self.loaded) {
122
+ $self.trigger("appear");
123
+ }
124
+ });
125
+ }
126
+ });
127
+
128
+ /* Check if something appears when window is resized. */
129
+ $window.bind("resize", function(event) {
130
+ update();
131
+ });
132
+
133
+ /* Force initial check if images should appear. */
134
+ update();
135
+
136
+ return this;
137
+ };
138
+
139
+ /* Convenience methods in jQuery namespace. */
140
+ /* Use as $.belowthefold(element, {threshold : 100, container : window}) */
141
+
142
+ $.belowthefold = function(element, settings) {
143
+ var fold;
144
+
145
+ if (settings.container === undefined || settings.container === window) {
146
+ fold = $window.height() + $window.scrollTop();
147
+ } else {
148
+ fold = $container.offset().top + $container.height();
149
+ }
150
+
151
+ return fold <= $(element).offset().top - settings.threshold;
152
+ };
153
+
154
+ $.rightoffold = function(element, settings) {
155
+ var fold;
156
+
157
+ if (settings.container === undefined || settings.container === window) {
158
+ fold = $window.width() + $window.scrollLeft();
159
+ } else {
160
+ fold = $container.offset().left + $container.width();
161
+ }
162
+
163
+ return fold <= $(element).offset().left - settings.threshold;
164
+ };
165
+
166
+ $.abovethetop = function(element, settings) {
167
+ var fold;
168
+
169
+ if (settings.container === undefined || settings.container === window) {
170
+ fold = $window.scrollTop();
171
+ } else {
172
+ fold = $container.offset().top;
173
+ }
174
+
175
+ return fold >= $(element).offset().top + settings.threshold + $(element).height();
176
+ };
177
+
178
+ $.leftofbegin = function(element, settings) {
179
+ var fold;
180
+
181
+ if (settings.container === undefined || settings.container === window) {
182
+ fold = $window.scrollLeft();
183
+ } else {
184
+ fold = $container.offset().left;
185
+ }
186
+
187
+ return fold >= $(element).offset().left + settings.threshold + $(element).width();
188
+ };
189
+
190
+ $.inviewport = function(element, settings) {
191
+ return !$.rightofscreen(element, settings) && !$.leftofscreen(element, settings) &&
192
+ !$.belowthefold(element, settings) && !$.abovethetop(element, settings);
193
+ };
194
+
195
+ /* Custom selectors for your convenience. */
196
+ /* Use as $("img:below-the-fold").something() */
197
+
198
+ $.extend($.expr[':'], {
199
+ "below-the-fold" : function(a) { return $.belowthefold(a, {threshold : 0, container: window}); },
200
+ "above-the-top" : function(a) { return !$.belowthefold(a, {threshold : 0, container: window}); },
201
+ "right-of-screen": function(a) { return $.rightoffold(a, {threshold : 0, container: window}); },
202
+ "left-of-screen" : function(a) { return !$.rightoffold(a, {threshold : 0, container: window}); },
203
+ "in-viewport" : function(a) { return !$.inviewport(a, {threshold : 0, container: window}); },
204
+ /* Maintain BC for couple of versions. */
205
+ "above-the-fold" : function(a) { return !$.belowthefold(a, {threshold : 0, container: window}); },
206
+ "right-of-fold" : function(a) { return $.rightoffold(a, {threshold : 0, container: window}); },
207
+ "left-of-fold" : function(a) { return !$.rightoffold(a, {threshold : 0, container: window}); }
208
+ });
209
+
210
+ })(jQuery, window);