alula 0.2.3 → 0.4.0b

Sign up to get free protection for your applications and to get access to all the features.
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);