almanac 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +76 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/images/almanac/background.jpg +0 -0
  5. data/app/assets/images/almanac/icons/compose.png +0 -0
  6. data/app/assets/images/almanac/icons/feed.png +0 -0
  7. data/app/assets/images/almanac/icons/gear.png +0 -0
  8. data/app/assets/images/almanac/icons/glyphicons-halflings-white.png +0 -0
  9. data/app/assets/images/almanac/icons/glyphicons-halflings.png +0 -0
  10. data/app/assets/images/almanac/icons/upload.png +0 -0
  11. data/app/assets/images/almanac/logo.jpg +0 -0
  12. data/app/assets/javascripts/almanac/2-jquery.backstretch.js +357 -0
  13. data/app/assets/javascripts/almanac/3-pixastic.js +637 -0
  14. data/app/assets/javascripts/almanac/4-bootstrap-datepicker.js +454 -0
  15. data/app/assets/javascripts/almanac/5-main.coffee.erb +46 -0
  16. data/app/assets/javascripts/almanac/application.js +16 -0
  17. data/app/assets/stylesheets/almanac/1-datepicker.css +7 -0
  18. data/app/assets/stylesheets/almanac/2-main.css.scss +279 -0
  19. data/app/assets/stylesheets/almanac/application.css +15 -0
  20. data/app/controllers/almanac/application_controller.rb +24 -0
  21. data/app/controllers/almanac/blogs_controller.rb +64 -0
  22. data/app/controllers/almanac/comments_controller.rb +41 -0
  23. data/app/controllers/almanac/images_controller.rb +29 -0
  24. data/app/controllers/almanac/posts_controller.rb +109 -0
  25. data/app/helpers/almanac/application_helper.rb +4 -0
  26. data/app/models/almanac/blog.rb +32 -0
  27. data/app/models/almanac/comment.rb +20 -0
  28. data/app/models/almanac/image.rb +10 -0
  29. data/app/models/almanac/post.rb +55 -0
  30. data/app/views/almanac/blogs/_form.html.haml +76 -0
  31. data/app/views/almanac/blogs/_topbar.html.haml +5 -0
  32. data/app/views/almanac/blogs/edit.html.haml +4 -0
  33. data/app/views/almanac/blogs/new.html.haml +3 -0
  34. data/app/views/almanac/blogs/spam.html.haml +15 -0
  35. data/app/views/almanac/posts/_form.html.haml +52 -0
  36. data/app/views/almanac/posts/_post.html.haml +59 -0
  37. data/app/views/almanac/posts/edit.html.haml +1 -0
  38. data/app/views/almanac/posts/index.html.haml +30 -0
  39. data/app/views/almanac/posts/index.rss.builder +18 -0
  40. data/app/views/almanac/posts/new.html.haml +1 -0
  41. data/app/views/almanac/posts/show.html.haml +4 -0
  42. data/app/views/almanac/posts/tag.html.haml +22 -0
  43. data/app/views/layouts/almanac/_ga.html.haml +10 -0
  44. data/app/views/layouts/almanac/_twitter_follow.html.haml +2 -0
  45. data/app/views/layouts/almanac/application.html.haml +52 -0
  46. data/config/routes.rb +22 -0
  47. data/db/migrate/20121009222451_create_almanac_posts.rb +17 -0
  48. data/db/migrate/20121010033555_create_almanac_blogs.rb +14 -0
  49. data/db/migrate/20121017032059_add_excerpt_to_almanac_posts.rb +11 -0
  50. data/db/migrate/20121017210007_create_almanac_files.rb +15 -0
  51. data/db/migrate/20121017221819_rename_file_to_image.rb +9 -0
  52. data/db/migrate/20121025223403_add_image_fields_to_almanac_blogs.rb +13 -0
  53. data/db/migrate/20121029211221_add_new_fields_to_blogs.rb +15 -0
  54. data/db/migrate/20121029221815_acts_as_taggable_on_migration.rb +30 -0
  55. data/db/migrate/20121101030836_create_almanac_comments.rb +16 -0
  56. data/db/migrate/20121102181941_add_rakismet_fields_to_blogs.rb +13 -0
  57. data/db/migrate/20121102185130_add_spam_to_comments.rb +11 -0
  58. data/db/migrate/20121110000024_add_written_at_to_posts.rb +11 -0
  59. data/db/migrate/20121112205256_add_background_fields_to_blogs.rb +13 -0
  60. data/db/migrate/20121113010557_add_footer_to_almanac_blogs.rb +11 -0
  61. data/db/migrate/20121114043648_change_default_value_for_background_tiles_in_almanac_blogs.rb +9 -0
  62. data/lib/almanac.rb +16 -0
  63. data/lib/almanac/MarkdownParser.rb +18 -0
  64. data/lib/almanac/engine.rb +9 -0
  65. data/lib/almanac/version.rb +3 -0
  66. data/lib/tasks/almanac_tasks.rake +4 -0
  67. data/spec/controllers/blogs_controller_spec.rb +80 -0
  68. data/spec/controllers/comments_controller_spec.rb +51 -0
  69. data/spec/controllers/posts_controller_spec.rb +120 -0
  70. data/spec/dummy/README.rdoc +261 -0
  71. data/spec/dummy/Rakefile +7 -0
  72. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  73. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  74. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  75. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  76. data/spec/dummy/app/models/ability.rb +13 -0
  77. data/spec/dummy/app/models/user.rb +11 -0
  78. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  79. data/spec/dummy/config.ru +4 -0
  80. data/spec/dummy/config/application.rb +59 -0
  81. data/spec/dummy/config/boot.rb +10 -0
  82. data/spec/dummy/config/database.yml +25 -0
  83. data/spec/dummy/config/environment.rb +5 -0
  84. data/spec/dummy/config/environments/development.rb +37 -0
  85. data/spec/dummy/config/environments/production.rb +67 -0
  86. data/spec/dummy/config/environments/test.rb +37 -0
  87. data/spec/dummy/config/initializers/almanac.rb +1 -0
  88. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  89. data/spec/dummy/config/initializers/devise.rb +233 -0
  90. data/spec/dummy/config/initializers/dragonfly.rb +7 -0
  91. data/spec/dummy/config/initializers/inflections.rb +15 -0
  92. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  93. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  94. data/spec/dummy/config/initializers/session_store.rb +8 -0
  95. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  96. data/spec/dummy/config/locales/en.yml +5 -0
  97. data/spec/dummy/config/routes.rb +14 -0
  98. data/spec/dummy/db/migrate/20121009230705_create_almanac_posts.rb +18 -0
  99. data/spec/dummy/db/migrate/20121010033827_create_almanac_blogs.rb +15 -0
  100. data/spec/dummy/db/migrate/20121102224650_add_excerpt_to_almanac_posts.rb +12 -0
  101. data/spec/dummy/db/migrate/20121102224651_create_almanac_files..rb +16 -0
  102. data/spec/dummy/db/migrate/20121102224652_rename_file_to_image.rb +10 -0
  103. data/spec/dummy/db/migrate/20121102224653_add_image_fields_to_almanac_blogs.rb +14 -0
  104. data/spec/dummy/db/migrate/20121102224654_add_new_fields_to_almanac_blogs.rb +16 -0
  105. data/spec/dummy/db/migrate/20121102224655_acts_as_taggable_on_migration.rb +31 -0
  106. data/spec/dummy/db/migrate/20121102224656_create_almanac_comments.rb +17 -0
  107. data/spec/dummy/db/migrate/20121102224657_add_rakismet_fields_to_almanac_blogs.rb +14 -0
  108. data/spec/dummy/db/migrate/20121102224658_add_spam_to_almanac_comments.rb +12 -0
  109. data/spec/dummy/db/migrate/20121106220325_devise_create_users.rb +46 -0
  110. data/spec/dummy/db/migrate/20121114032144_add_written_at_to_almanac_posts.rb +12 -0
  111. data/spec/dummy/db/migrate/20121114032145_add_background_fields_to_almanac_blogs.rb +14 -0
  112. data/spec/dummy/db/migrate/20121114032146_add_footer_to_almanac_blogs.rb +12 -0
  113. data/spec/dummy/db/schema.rb +98 -0
  114. data/spec/dummy/db/test.sqlite3 +0 -0
  115. data/spec/dummy/log/production.log +1 -0
  116. data/spec/dummy/log/test.log +2930 -0
  117. data/spec/dummy/public/404.html +26 -0
  118. data/spec/dummy/public/422.html +26 -0
  119. data/spec/dummy/public/500.html +25 -0
  120. data/spec/dummy/public/favicon.ico +0 -0
  121. data/spec/dummy/script/rails +6 -0
  122. data/spec/factories.rb +72 -0
  123. data/spec/models/blog_spec.rb +16 -0
  124. data/spec/models/comment_spec.rb +35 -0
  125. data/spec/models/post_spec.rb +79 -0
  126. data/spec/spec_helper.rb +37 -0
  127. metadata +485 -0
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,76 @@
1
+ # Almanac
2
+ Almanac is the most elegant mountable blog engine that can be easily hooked up in the existing Rails application.
3
+
4
+ ## Main Features
5
+ - Slick default design that can be easily customized.
6
+ - Markdown for everything.
7
+ - Drafts that make sense.
8
+ - Easy Google Analytics support.
9
+ - Akismet support for spam filtering in comments.
10
+ - Built-in social sharing with Facebook and Twitter.
11
+ - RSS support.
12
+ - Tags for posts.
13
+ - Photo uploading.
14
+ - Complete integration with Devise and CanCan.
15
+ - Tested with RSpec and FactoryGirl
16
+ - Uses haml, scss, CoffeeScript and Bootstrap for views.
17
+
18
+ ## Installation
19
+ ### 1. Add the gem to your `Gemfile`
20
+ ```ruby
21
+ gem "almanac"
22
+ ```
23
+ And run `bundle install`.
24
+
25
+ ### 2. Setup Routes
26
+ To hook up Almanac routes to your current Rails app simply put this code in your `config/routes.rd` file
27
+
28
+ ```ruby
29
+ mount Almanac::Engine, :at => '/blog'
30
+ ```
31
+
32
+ You can obviously setup any route you want. E.g. `/posts` or `/almanac`.
33
+
34
+ ### 3. Run Almanac Migrations
35
+ First off, install Almanac migrations:
36
+
37
+ ```ruby
38
+ bundle exec rake almanac:install:migrations
39
+ ```
40
+
41
+ Then migrate your database:
42
+
43
+ ```ruby
44
+ bundle exec rake db:migrate
45
+ ```
46
+
47
+ ### 4. Devise and CanCan Setup
48
+ Almanac relies on Devise and CanCan properly configured in your app. In short, the `current_user` variable and CanCan `ability.rb` file has to exist. You can setup permissions for the following Almanac models:
49
+
50
+ ```ruby
51
+ can :manage, Almanac::Post
52
+ can :manage, Almanac::Blog
53
+ can :manage, Almanac::Comment
54
+ can :manage, Almanac::Image
55
+ ```
56
+
57
+ These particular rules will allow the specified user to do anything with any Almanac record in the database.
58
+
59
+ ### 5. Specify User Class Name
60
+ Lastly, you'll have to specify the name of your user model. Create a `config/initializers/almanac.rb` file and add the following line there:
61
+
62
+ ```ruby
63
+ Almanac.user_class = "User" # other possibilities: "Author", "Writer", etc.
64
+ ```
65
+
66
+ ## Testing
67
+ Almanac's models and controllers are tested with RSpec and FactoryGirl. Rails engines, such as Almanac, are normally tested with a dummy app that is located inside the 'spec' folder. Migrate your test database from the `spec/dummy` directory:
68
+
69
+ ```ruby
70
+ rake db:migrate RAILS_ENV=test
71
+ ```
72
+
73
+ Go back to the `almanac` directory and run `rspec spec`.
74
+
75
+ ## Contribute
76
+ Fork the repo, do work, test it, pull request.
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Almanac'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
24
+ load 'rails/tasks/engine.rake'
25
+
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
30
+ require 'rake/testtask'
31
+
32
+ Rake::TestTask.new(:test) do |t|
33
+ t.libs << 'lib'
34
+ t.libs << 'test'
35
+ t.pattern = 'test/**/*_test.rb'
36
+ t.verbose = false
37
+ end
38
+
39
+
40
+ task :default => :test
@@ -0,0 +1,357 @@
1
+ /*! Backstretch - v2.0.1 - 2012-10-01
2
+ * http://srobbin.com/jquery-plugins/backstretch/
3
+ * Copyright (c) 2012 Scott Robbin; Licensed MIT */
4
+
5
+ ;(function ($, window, undefined) {
6
+ 'use strict';
7
+
8
+ /* PLUGIN DEFINITION
9
+ * ========================= */
10
+
11
+ $.fn.backstretch = function (images, options) {
12
+ // We need at least one image
13
+ if (images === undefined || images.length === 0) {
14
+ $.error("No images were supplied for Backstretch");
15
+ }
16
+
17
+ /*
18
+ * Scroll the page one pixel to get the right window height on iOS
19
+ * Pretty harmless for everyone else
20
+ */
21
+ if ($(window).scrollTop() === 0 ) {
22
+ window.scrollTo(0, 0);
23
+ }
24
+
25
+ return this.each(function () {
26
+ var $this = $(this)
27
+ , obj = $this.data('backstretch');
28
+
29
+ // If we've already attached Backstretch to this element, remove the old instance.
30
+ if (obj) {
31
+ // Merge the old options with the new
32
+ options = $.extend(obj.options, options);
33
+
34
+ // Remove the old instance
35
+ obj.destroy(true);
36
+ }
37
+
38
+ obj = new Backstretch(this, images, options);
39
+ $this.data('backstretch', obj);
40
+ });
41
+ };
42
+
43
+ // If no element is supplied, we'll attach to body
44
+ $.backstretch = function (images, options) {
45
+ // Return the instance
46
+ return $('body')
47
+ .backstretch(images, options)
48
+ .data('backstretch');
49
+ };
50
+
51
+ // Custom selector
52
+ $.expr[':'].backstretch = function(elem) {
53
+ return $(elem).data('backstretch') !== undefined;
54
+ };
55
+
56
+ /* DEFAULTS
57
+ * ========================= */
58
+
59
+ $.fn.backstretch.defaults = {
60
+ centeredX: true // Should we center the image on the X axis?
61
+ , centeredY: true // Should we center the image on the Y axis?
62
+ , duration: 5000 // Amount of time in between slides (if slideshow)
63
+ , fade: 0 // Speed of fade transition between slides
64
+ };
65
+
66
+ /* STYLES
67
+ *
68
+ * Baked-in styles that we'll apply to our elements.
69
+ * In an effort to keep the plugin simple, these are not exposed as options.
70
+ * That said, anyone can override these in their own stylesheet.
71
+ * ========================= */
72
+ var styles = {
73
+ wrap: {
74
+ left: 0
75
+ , top: 0
76
+ , overflow: 'hidden'
77
+ , margin: 0
78
+ , padding: 0
79
+ , height: '100%'
80
+ , width: '100%'
81
+ , zIndex: -999999
82
+ }
83
+ , img: {
84
+ position: 'absolute'
85
+ , display: 'none'
86
+ , margin: 0
87
+ , padding: 0
88
+ , border: 'none'
89
+ , width: 'auto'
90
+ , height: 'auto'
91
+ , maxWidth: 'none'
92
+ , zIndex: -999999
93
+ }
94
+ };
95
+
96
+ /* CLASS DEFINITION
97
+ * ========================= */
98
+ var Backstretch = function (container, images, options) {
99
+ this.options = $.extend({}, $.fn.backstretch.defaults, options || {});
100
+
101
+ /* In its simplest form, we allow Backstretch to be called on an image path.
102
+ * e.g. $.backstretch('/path/to/image.jpg')
103
+ * So, we need to turn this back into an array.
104
+ */
105
+ this.images = $.isArray(images) ? images : [images];
106
+
107
+ // Preload images
108
+ $.each(this.images, function () {
109
+ $('<img />')[0].src = this;
110
+ });
111
+
112
+ // Convenience reference to know if the container is body.
113
+ this.isBody = container === document.body;
114
+
115
+ /* We're keeping track of a few different elements
116
+ *
117
+ * Container: the element that Backstretch was called on.
118
+ * Wrap: a DIV that we place the image into, so we can hide the overflow.
119
+ * Root: Convenience reference to help calculate the correct height.
120
+ */
121
+ this.$container = $(container);
122
+ this.$wrap = $('<div class="backstretch"></div>').css(styles.wrap).appendTo(this.$container);
123
+ this.$root = this.isBody ? supportsFixedPosition ? $(window) : $(document) : this.$container;
124
+
125
+ // Non-body elements need some style adjustments
126
+ if (!this.isBody) {
127
+ // If the container is statically positioned, we need to make it relative,
128
+ // and if no zIndex is defined, we should set it to zero.
129
+ var position = this.$container.css('position')
130
+ , zIndex = this.$container.css('zIndex');
131
+
132
+ this.$container.css({
133
+ position: position === 'static' ? 'relative' : position
134
+ , zIndex: zIndex === 'auto' ? 0 : zIndex
135
+ , background: 'none'
136
+ });
137
+
138
+ // Needs a higher z-index
139
+ this.$wrap.css({zIndex: -999998});
140
+ }
141
+
142
+ // Fixed or absolute positioning?
143
+ this.$wrap.css({
144
+ position: this.isBody && supportsFixedPosition ? 'fixed' : 'absolute'
145
+ });
146
+
147
+ // Set the first image
148
+ this.index = 0;
149
+ this.show(this.index);
150
+
151
+ // Listen for resize
152
+ $(window).on('resize.backstretch', $.proxy(this.resize, this))
153
+ .on('orientationchange.backstretch', $.proxy(function () {
154
+ // Need to do this in order to get the right window height
155
+ if (this.isBody && window.pageYOffset === 0) {
156
+ window.scrollTo(0, 1);
157
+ this.resize();
158
+ }
159
+ }, this));
160
+ };
161
+
162
+ /* PUBLIC METHODS
163
+ * ========================= */
164
+ Backstretch.prototype = {
165
+ resize: function () {
166
+ try {
167
+ var bgCSS = {left: 0, top: 0}
168
+ , rootWidth = this.isBody ? this.$root.width() : this.$root.innerWidth()
169
+ , bgWidth = rootWidth
170
+ , rootHeight = this.isBody ? ( window.innerHeight ? window.innerHeight : this.$root.height() ) : this.$root.innerHeight()
171
+ , bgHeight = bgWidth / this.$img.data('ratio')
172
+ , bgOffset;
173
+
174
+ // Make adjustments based on image ratio
175
+ if (bgHeight >= rootHeight) {
176
+ bgOffset = (bgHeight - rootHeight) / 2;
177
+ if(this.options.centeredY) {
178
+ bgCSS.top = '-' + bgOffset + 'px';
179
+ }
180
+ } else {
181
+ bgHeight = rootHeight;
182
+ bgWidth = bgHeight * this.$img.data('ratio');
183
+ bgOffset = (bgWidth - rootWidth) / 2;
184
+ if(this.options.centeredX) {
185
+ bgCSS.left = '-' + bgOffset + 'px';
186
+ }
187
+ }
188
+
189
+ this.$wrap.css({width: rootWidth, height: rootHeight})
190
+ .find('img:not(.deleteable)').css({width: bgWidth, height: bgHeight}).css(bgCSS);
191
+ } catch(err) {
192
+ // IE7 seems to trigger resize before the image is loaded.
193
+ // This try/catch block is a hack to let it fail gracefully.
194
+ }
195
+
196
+ return this;
197
+ }
198
+
199
+ // Show the slide at a certain position
200
+ , show: function (index) {
201
+ // Validate index
202
+ if (Math.abs(index) > this.images.length - 1) {
203
+ return;
204
+ } else {
205
+ this.index = index;
206
+ }
207
+
208
+ // Vars
209
+ var self = this
210
+ , oldImage = self.$wrap.find('img').addClass('deleteable')
211
+ , evt = $.Event('backstretch.show', {
212
+ relatedTarget: self.$container[0]
213
+ });
214
+
215
+ // Pause the slideshow
216
+ clearInterval(self.interval);
217
+
218
+ // New image
219
+ self.$img = $('<img />')
220
+ .css(styles.img)
221
+ .bind('load', function (e) {
222
+ var imgWidth = this.width || $(e.target).width()
223
+ , imgHeight = this.height || $(e.target).height();
224
+
225
+ // Save the ratio
226
+ $(this).data('ratio', imgWidth / imgHeight);
227
+
228
+ // Resize
229
+ self.resize();
230
+
231
+ // Show the image, then delete the old one
232
+ // "speed" option has been deprecated, but we want backwards compatibilty
233
+ $(this).fadeIn(self.options.speed || self.options.fade, function () {
234
+ oldImage.remove();
235
+
236
+ // Resume the slideshow
237
+ if (!self.paused) {
238
+ self.cycle();
239
+ }
240
+
241
+ // Trigger the event
242
+ self.$container.trigger(evt);
243
+ });
244
+ })
245
+ .appendTo(self.$wrap);
246
+
247
+ // Hack for IE img onload event
248
+ self.$img.attr('src', self.images[index]);
249
+ return self;
250
+ }
251
+
252
+ , next: function () {
253
+ // Next slide
254
+ return this.show(this.index < this.images.length - 1 ? this.index + 1 : 0);
255
+ }
256
+
257
+ , prev: function () {
258
+ // Previous slide
259
+ return this.show(this.index === 0 ? this.images.length - 1 : this.index - 1);
260
+ }
261
+
262
+ , pause: function () {
263
+ // Pause the slideshow
264
+ this.paused = true;
265
+ return this;
266
+ }
267
+
268
+ , resume: function () {
269
+ // Resume the slideshow
270
+ this.paused = false;
271
+ this.next();
272
+ return this;
273
+ }
274
+
275
+ , cycle: function () {
276
+ // Start/resume the slideshow
277
+ if(this.images.length > 1) {
278
+ // Clear the interval, just in case
279
+ clearInterval(this.interval);
280
+
281
+ this.interval = setInterval($.proxy(function () {
282
+ // Check for paused slideshow
283
+ if (!this.paused) {
284
+ this.next();
285
+ }
286
+ }, this), this.options.duration);
287
+ }
288
+ return this;
289
+ }
290
+
291
+ , destroy: function (preserveBackground) {
292
+ // Stop the resize events
293
+ $(window).off('resize.backstretch orientationchange.backstretch');
294
+
295
+ // Clear the interval
296
+ clearInterval(this.interval);
297
+
298
+ // Remove Backstretch
299
+ if(!preserveBackground) {
300
+ this.$wrap.remove();
301
+ }
302
+ this.$container.removeData('backstretch');
303
+ }
304
+ };
305
+
306
+ /* SUPPORTS FIXED POSITION?
307
+ *
308
+ * Based on code from jQuery Mobile 1.1.0
309
+ * http://jquerymobile.com/
310
+ *
311
+ * In a nutshell, we need to figure out if fixed positioning is supported.
312
+ * Unfortunately, this is very difficult to do on iOS, and usually involves
313
+ * injecting content, scrolling the page, etc.. It's ugly.
314
+ * jQuery Mobile uses this workaround. It's not ideal, but works.
315
+ *
316
+ * Modified to detect IE6
317
+ * ========================= */
318
+
319
+ var supportsFixedPosition = (function () {
320
+ var ua = navigator.userAgent
321
+ , platform = navigator.platform
322
+ // Rendering engine is Webkit, and capture major version
323
+ , wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ )
324
+ , wkversion = !!wkmatch && wkmatch[ 1 ]
325
+ , ffmatch = ua.match( /Fennec\/([0-9]+)/ )
326
+ , ffversion = !!ffmatch && ffmatch[ 1 ]
327
+ , operammobilematch = ua.match( /Opera Mobi\/([0-9]+)/ )
328
+ , omversion = !!operammobilematch && operammobilematch[ 1 ]
329
+ , iematch = ua.match( /MSIE ([0-9]+)/ )
330
+ , ieversion = !!iematch && iematch[ 1 ];
331
+
332
+ return !(
333
+ // iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5)
334
+ ((platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1 || platform.indexOf( "iPod" ) > -1 ) && wkversion && wkversion < 534) ||
335
+
336
+ // Opera Mini
337
+ (window.operamini && ({}).toString.call( window.operamini ) === "[object OperaMini]") ||
338
+ (operammobilematch && omversion < 7458) ||
339
+
340
+ //Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2)
341
+ (ua.indexOf( "Android" ) > -1 && wkversion && wkversion < 533) ||
342
+
343
+ // Firefox Mobile before 6.0 -
344
+ (ffversion && ffversion < 6) ||
345
+
346
+ // WebOS less than 3
347
+ ("palmGetResource" in window && wkversion && wkversion < 534) ||
348
+
349
+ // MeeGo
350
+ (ua.indexOf( "MeeGo" ) > -1 && ua.indexOf( "NokiaBrowser/8.5.0" ) > -1) ||
351
+
352
+ // IE6
353
+ (ieversion && ieversion <= 6)
354
+ );
355
+ }());
356
+
357
+ }(jQuery, window));