diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b54990 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +\#* +*~ +.#* +.DS_Store +.idea +.project +tmp +nbproject +*.swp +spec/dummy diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..53607ea --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--colour diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..1122a8b --- /dev/null +++ b/Gemfile @@ -0,0 +1,9 @@ +source 'http://rubygems.org' + +if RUBY_VERSION < '1.9' + gem 'ruby-debug' +else + gem 'ruby-debug19' +end + +gemspec diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b96241c --- /dev/null +++ b/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2012 [name of plugin creator] +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name Spree nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3b60870 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +SpreeProductZoom +================ + +Introduction goes here. + + +Example +======= + +Example goes here. + +Testing +------- + +Be sure to bundle your dependencies and then create a dummy test app for the specs to run against. + + $ bundle + $ bundle exec rake test_app + $ bundle exec rspec spec + +Copyright (c) 2012 [name of extension creator], released under the New BSD License diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..c8e808f --- /dev/null +++ b/Rakefile @@ -0,0 +1,29 @@ +require 'rake' +require 'rake/testtask' +require 'rake/packagetask' +require 'rubygems/package_task' +require 'rspec/core/rake_task' +require 'spree/core/testing_support/common_rake' + +RSpec::Core::RakeTask.new + +task :default => [:spec] + +spec = eval(File.read('spree_product_zoom.gemspec')) + +Gem::PackageTask.new(spec) do |p| + p.gem_spec = spec +end + +desc 'Release to gemcutter' +task :release => :package do + require 'rake/gemcutter' + Rake::Gemcutter::Tasks.new(spec).define + Rake::Task['gem:push'].invoke +end + +desc 'Generates a dummy app for testing' +task :test_app do + ENV['LIB_NAME'] = 'spree_product_zoom' + Rake::Task['common:test_app'].invoke +end diff --git a/Versionfile b/Versionfile new file mode 100644 index 0000000..5db83aa --- /dev/null +++ b/Versionfile @@ -0,0 +1,11 @@ +# This file is used to designate compatibilty with different versions of Spree +# Please see http://spreecommerce.com/documentation/extensions.html#versionfile for details + +# Examples +# +# '1.2.x' => { :branch => 'master' } +# '1.1.x' => { :branch => '1-1-stable' } +# '1.0.x' => { :branch => '1-0-stable' } +# '0.70.x' => { :branch => '0-70-stable' } +# '0.40.x' => { :tag => 'v1.0.0', :version => '1.0.0' } + diff --git a/app/assets/javascripts/admin/spree_product_zoom.js b/app/assets/javascripts/admin/spree_product_zoom.js new file mode 100644 index 0000000..a3b2c53 --- /dev/null +++ b/app/assets/javascripts/admin/spree_product_zoom.js @@ -0,0 +1 @@ +//= require admin/spree_core diff --git a/app/assets/javascripts/store/spree_product_zoom.js b/app/assets/javascripts/store/spree_product_zoom.js new file mode 100644 index 0000000..2dd78f2 --- /dev/null +++ b/app/assets/javascripts/store/spree_product_zoom.js @@ -0,0 +1,2 @@ +//= require store/spree_core +//= require fancybox diff --git a/app/assets/stylesheets/admin/spree_product_zoom.css b/app/assets/stylesheets/admin/spree_product_zoom.css new file mode 100644 index 0000000..21ef02a --- /dev/null +++ b/app/assets/stylesheets/admin/spree_product_zoom.css @@ -0,0 +1,3 @@ +/* + *= require admin/spree_core +*/ diff --git a/app/assets/stylesheets/store/spree_product_zoom.css b/app/assets/stylesheets/store/spree_product_zoom.css new file mode 100644 index 0000000..2e0fb7b --- /dev/null +++ b/app/assets/stylesheets/store/spree_product_zoom.css @@ -0,0 +1,4 @@ +/* + *= require store/spree_core + *= require fancybox +*/ diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..179c14c --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,5 @@ +# Sample localization file for English. Add more files in this directory for other locales. +# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. + +en: + hello: "Hello world" diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..53e2eeb --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,3 @@ +Spree::Core::Engine.routes.draw do + # Add your extension routes here +end diff --git a/lib/generators/spree_product_zoom/install/install_generator.rb b/lib/generators/spree_product_zoom/install/install_generator.rb new file mode 100644 index 0000000..a7590f4 --- /dev/null +++ b/lib/generators/spree_product_zoom/install/install_generator.rb @@ -0,0 +1,14 @@ +module SpreeProductZoom + module Generators + class InstallGenerator < Rails::Generators::Base + + def add_javascripts + append_file 'app/assets/javascripts/store/all.js', "//= require store/spree_product_zoom\n" + end + + def add_stylesheets + inject_into_file 'app/assets/stylesheets/store/all.css', " *= require store/spree_product_zoom\n", :before => /\*\//, :verbose => true + end + end + end +end diff --git a/lib/spree_product_zoom.rb b/lib/spree_product_zoom.rb new file mode 100644 index 0000000..1f1da9a --- /dev/null +++ b/lib/spree_product_zoom.rb @@ -0,0 +1,2 @@ +require 'spree_core' +require 'spree_product_zoom/engine' diff --git a/lib/spree_product_zoom/engine.rb b/lib/spree_product_zoom/engine.rb new file mode 100644 index 0000000..7df431b --- /dev/null +++ b/lib/spree_product_zoom/engine.rb @@ -0,0 +1,22 @@ +module SpreeProductZoom + class Engine < Rails::Engine + require 'spree/core' + isolate_namespace Spree + engine_name 'spree_product_zoom' + + config.autoload_paths += %W(#{config.root}/lib) + + # use rspec for tests + config.generators do |g| + g.test_framework :rspec + end + + def self.activate + Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c| + Rails.configuration.cache_classes ? require(c) : load(c) + end + end + + config.to_prepare &method(:activate).to_proc + end +end diff --git a/script/rails b/script/rails new file mode 100644 index 0000000..cd9185c --- /dev/null +++ b/script/rails @@ -0,0 +1,7 @@ +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +ENGINE_ROOT = File.expand_path('../..', __FILE__) +ENGINE_PATH = File.expand_path('../../lib/spree_product_zoom/engine', __FILE__) + +require 'rails/all' +require 'rails/engine/commands' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..8d6355d --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,44 @@ +# Configure Rails Environment +ENV['RAILS_ENV'] = 'test' + +require File.expand_path('../dummy/config/environment.rb', __FILE__) + +require 'rspec/rails' +require 'ffaker' + +# Requires supporting ruby files with custom matchers and macros, etc, +# in spec/support/ and its subdirectories. +Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require f } + +# Requires factories defined in spree_core +require 'spree/core/testing_support/factories' +require 'spree/core/url_helpers' + +RSpec.configure do |config| + config.include FactoryGirl::Syntax::Methods + + # == URL Helpers + # + # Allows access to Spree's routes in specs: + # + # visit spree.admin_path + # current_path.should eql(spree.products_path) + config.include Spree::Core::UrlHelpers + + # == Mock Framework + # + # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: + # + # config.mock_with :mocha + # config.mock_with :flexmock + # config.mock_with :rr + config.mock_with :rspec + + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true +end diff --git a/spree_product_zoom.gemspec b/spree_product_zoom.gemspec new file mode 100644 index 0000000..3abb43d --- /dev/null +++ b/spree_product_zoom.gemspec @@ -0,0 +1,26 @@ +# encoding: UTF-8 +Gem::Specification.new do |s| + s.platform = Gem::Platform::RUBY + s.name = 'spree_product_zoom' + s.version = '1.1.2' + s.summary = 'TODO: Add gem summary here' + s.description = 'TODO: Add (optional) gem description here' + s.required_ruby_version = '>= 1.8.7' + + # s.author = 'You' + # s.email = 'you@example.com' + # s.homepage = 'http://www.spreecommerce.com' + + #s.files = `git ls-files`.split("\n") + #s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + s.require_path = 'lib' + s.requirements << 'none' + + s.add_dependency 'spree_core', '~> 1.1.2' + + s.add_development_dependency 'capybara', '1.0.1' + s.add_development_dependency 'factory_girl', '~> 2.6.4' + s.add_development_dependency 'ffaker' + s.add_development_dependency 'rspec-rails', '~> 2.9' + s.add_development_dependency 'sqlite3' +end diff --git a/vendor/assets/images/blank.gif b/vendor/assets/images/blank.gif new file mode 100755 index 0000000..35d42e8 Binary files /dev/null and b/vendor/assets/images/blank.gif differ diff --git a/vendor/assets/images/fancybox_buttons.png b/vendor/assets/images/fancybox_buttons.png new file mode 100755 index 0000000..e0e1ea8 Binary files /dev/null and b/vendor/assets/images/fancybox_buttons.png differ diff --git a/vendor/assets/images/fancybox_loading.gif b/vendor/assets/images/fancybox_loading.gif new file mode 100755 index 0000000..0158617 Binary files /dev/null and b/vendor/assets/images/fancybox_loading.gif differ diff --git a/vendor/assets/images/fancybox_sprite.png b/vendor/assets/images/fancybox_sprite.png new file mode 100755 index 0000000..a1aae1a Binary files /dev/null and b/vendor/assets/images/fancybox_sprite.png differ diff --git a/vendor/assets/javascripts/fancybox.js b/vendor/assets/javascripts/fancybox.js new file mode 100644 index 0000000..228dc6f --- /dev/null +++ b/vendor/assets/javascripts/fancybox.js @@ -0,0 +1,4 @@ +//= require jquery.fancybox +//= require jquery.fancybox-buttons +//= require jquery.fancybox-thumbs +//= require jquery.fancybox-media diff --git a/vendor/assets/javascripts/jquery.fancybox-buttons.js b/vendor/assets/javascripts/jquery.fancybox-buttons.js new file mode 100755 index 0000000..e116e38 --- /dev/null +++ b/vendor/assets/javascripts/jquery.fancybox-buttons.js @@ -0,0 +1,115 @@ + /*! + * Buttons helper for fancyBox + * version: 1.0.2 + * @requires fancyBox v2.0 or later + * + * Usage: + * $(".fancybox").fancybox({ + * buttons: { + * position : 'top' + * } + * }); + * + * Options: + * tpl - HTML template + * position - 'top' or 'bottom' + * + */ +(function ($) { + //Shortcut for fancyBox object + var F = $.fancybox; + + //Add helper object + F.helpers.buttons = { + tpl: '
', + list: null, + buttons: {}, + + update: function () { + var toggle = this.buttons.toggle.removeClass('btnDisabled btnToggleOn'); + + //Size toggle button + if (F.current.canShrink) { + toggle.addClass('btnToggleOn'); + + } else if (!F.current.canExpand) { + toggle.addClass('btnDisabled'); + } + }, + + beforeLoad: function (opts) { + //Remove self if gallery do not have at least two items + if (F.group.length < 2) { + F.coming.helpers.buttons = false; + F.coming.closeBtn = true; + + return; + } + + //Increase top margin to give space for buttons + F.coming.margin[ opts.position === 'bottom' ? 2 : 0 ] += 30; + }, + + onPlayStart: function () { + if (this.list) { + this.buttons.play.attr('title', 'Pause slideshow').addClass('btnPlayOn'); + } + }, + + onPlayEnd: function () { + if (this.list) { + this.buttons.play.attr('title', 'Start slideshow').removeClass('btnPlayOn'); + } + }, + + afterShow: function (opts) { + var buttons; + + if (!this.list) { + this.list = $(opts.tpl || this.tpl).addClass(opts.position || 'top').appendTo('body'); + + this.buttons = { + prev : this.list.find('.btnPrev').click( F.prev ), + next : this.list.find('.btnNext').click( F.next ), + play : this.list.find('.btnPlay').click( F.play ), + toggle : this.list.find('.btnToggle').click( F.toggle ) + } + } + + buttons = this.buttons; + + //Prev + if (F.current.index > 0 || F.current.loop) { + buttons.prev.removeClass('btnDisabled'); + } else { + buttons.prev.addClass('btnDisabled'); + } + + //Next / Play + if (F.current.loop || F.current.index < F.group.length - 1) { + buttons.next.removeClass('btnDisabled'); + buttons.play.removeClass('btnDisabled'); + + } else { + buttons.next.addClass('btnDisabled'); + buttons.play.addClass('btnDisabled'); + } + + this.update(); + }, + + onUpdate: function () { + this.update(); + }, + + beforeClose: function () { + if (this.list) { + this.list.remove(); + } + + this.list = null; + this.buttons = {}; + } + }; + +}(jQuery)); \ No newline at end of file diff --git a/vendor/assets/javascripts/jquery.fancybox-media.js b/vendor/assets/javascripts/jquery.fancybox-media.js new file mode 100755 index 0000000..be5f586 --- /dev/null +++ b/vendor/assets/javascripts/jquery.fancybox-media.js @@ -0,0 +1,85 @@ + /*! + * Media helper for fancyBox + * version: 1.0.0 + * @requires fancyBox v2.0 or later + * + * Usage: + * $(".fancybox").fancybox({ + * media: {} + * }); + * + * Supports: + * Youtube + * http://www.youtube.com/watch?v=opj24KnzrWo + * http://youtu.be/opj24KnzrWo + * Vimeo + * http://vimeo.com/25634903 + * Metacafe + * http://www.metacafe.com/watch/7635964/dr_seuss_the_lorax_movie_trailer/ + * http://www.metacafe.com/watch/7635964/ + * Dailymotion + * http://www.dailymotion.com/video/xoytqh_dr-seuss-the-lorax-premiere_people + * Twitvid + * http://twitvid.com/QY7MD + * Twitpic + * http://twitpic.com/7p93st + * Instagram + * http://instagr.am/p/IejkuUGxQn/ + * http://instagram.com/p/IejkuUGxQn/ + * Google maps + * http://maps.google.com/maps?q=Eiffel+Tower,+Avenue+Gustave+Eiffel,+Paris,+France&t=h&z=17 + * http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16 + * http://maps.google.com/?ll=48.859463,2.292626&spn=0.000965,0.002642&t=m&z=19&layer=c&cbll=48.859524,2.292532&panoid=YJ0lq28OOy3VT2IqIuVY0g&cbp=12,151.58,,0,-15.56 + */ +(function ($) { + //Shortcut for fancyBox object + var F = $.fancybox; + + //Add helper object + F.helpers.media = { + beforeLoad : function(opts, obj) { + var href = obj.href || '', + type = false, + rez; + + if ((rez = href.match(/(youtube\.com|youtu\.be)\/(v\/|u\/|embed\/|watch\?v=)?([^#\&\?]*).*/i))) { + href = '//www.youtube.com/embed/' + rez[3] + '?autoplay=1&autohide=1&fs=1&rel=0&enablejsapi=1'; + type = 'iframe'; + + } else if ((rez = href.match(/vimeo.com\/(\d+)\/?(.*)/))) { + href = '//player.vimeo.com/video/' + rez[1] + '?hd=1&autoplay=1&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1'; + type = 'iframe'; + + } else if ((rez = href.match(/metacafe.com\/watch\/(\d+)\/?(.*)/))) { + href = '//www.metacafe.com/fplayer/' + rez[1] + '/.swf?playerVars=autoPlay=yes'; + type = 'swf'; + + } else if ((rez = href.match(/dailymotion.com\/video\/(.*)\/?(.*)/))) { + href = '//www.dailymotion.com/swf/video/' + rez[1] + '?additionalInfos=0&autoStart=1'; + type = 'swf'; + + } else if ((rez = href.match(/twitvid\.com\/([a-zA-Z0-9_\-\?\=]+)/i))) { + href = '//www.twitvid.com/embed.php?autoplay=0&guid=' + rez[1]; + type = 'iframe'; + + } else if ((rez = href.match(/twitpic\.com\/(?!(?:place|photos|events)\/)([a-zA-Z0-9\?\=\-]+)/i))) { + href = '//twitpic.com/show/full/' + rez[1]; + type = 'image'; + + } else if ((rez = href.match(/(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i))) { + href = '//' + rez[1] + '/p/' + rez[2] + '/media/?size=l'; + type = 'image'; + + } else if ((rez = href.match(/maps\.google\.com\/(\?ll=|maps\/?\?q=)(.*)/i))) { + href = '//maps.google.com/' + rez[1] + '' + rez[2] + '&output=' + (rez[2].indexOf('layer=c') ? 'svembed' : 'embed'); + type = 'iframe'; + } + + if (type) { + obj.href = href; + obj.type = type; + } + } + } + +}(jQuery)); \ No newline at end of file diff --git a/vendor/assets/javascripts/jquery.fancybox-thumbs.js b/vendor/assets/javascripts/jquery.fancybox-thumbs.js new file mode 100755 index 0000000..a1b2bb7 --- /dev/null +++ b/vendor/assets/javascripts/jquery.fancybox-thumbs.js @@ -0,0 +1,157 @@ + /*! + * Thumbnail helper for fancyBox + * version: 1.0.4 + * @requires fancyBox v2.0 or later + * + * Usage: + * $(".fancybox").fancybox({ + * thumbs: { + * width : 50, + * height : 50 + * } + * }); + * + * Options: + * width - thumbnail width + * height - thumbnail height + * source - function to obtain the URL of the thumbnail image + * position - 'top' or 'bottom' + * + */ +(function ($) { + //Shortcut for fancyBox object + var F = $.fancybox; + + //Add helper object + F.helpers.thumbs = { + wrap: null, + list: null, + width: 0, + + //Default function to obtain the URL of the thumbnail image + source: function (el) { + var img; + + if ($.type(el) === 'string') { + return el; + } + + img = $(el).find('img'); + + return img.length ? img.attr('src') : el.href; + }, + + init: function (opts) { + var that = this, + list, + thumbWidth = opts.width || 50, + thumbHeight = opts.height || 50, + thumbSource = opts.source || this.source; + + //Build list structure + list = ''; + + for (var n = 0; n < F.group.length; n++) { + list += '
  • '; + } + + this.wrap = $('
    ').addClass(opts.position || 'bottom').appendTo('body'); + this.list = $('').appendTo(this.wrap); + + //Load each thumbnail + $.each(F.group, function (i) { + $("").load(function () { + var width = this.width, + height = this.height, + widthRatio, heightRatio, parent; + + if (!that.list || !width || !height) { + return; + } + + //Calculate thumbnail width/height and center it + widthRatio = width / thumbWidth; + heightRatio = height / thumbHeight; + parent = that.list.children().eq(i).find('a'); + + if (widthRatio >= 1 && heightRatio >= 1) { + if (widthRatio > heightRatio) { + width = Math.floor(width / heightRatio); + height = thumbHeight; + + } else { + width = thumbWidth; + height = Math.floor(height / widthRatio); + } + } + + $(this).css({ + width: width, + height: height, + top: Math.floor(thumbHeight / 2 - height / 2), + left: Math.floor(thumbWidth / 2 - width / 2) + }); + + parent.width(thumbWidth).height(thumbHeight); + + $(this).hide().appendTo(parent).fadeIn(300); + + }).attr('src', thumbSource( F.group[ i ] )); + }); + + //Set initial width + this.width = this.list.children().eq(0).outerWidth(true); + + this.list.width(this.width * (F.group.length + 1)).css('left', Math.floor($(window).width() * 0.5 - (F.current.index * this.width + this.width * 0.5))); + }, + + //Center list + update: function (opts) { + if (this.list) { + this.list.stop(true).animate({ + 'left': Math.floor($(window).width() * 0.5 - (F.current.index * this.width + this.width * 0.5)) + }, 150); + } + }, + + beforeLoad: function (opts) { + //Remove self if gallery do not have at least two items + if (F.group.length < 2) { + F.coming.helpers.thumbs = false; + + return; + } + + //Increase bottom margin to give space for thumbs + F.coming.margin[ opts.position === 'top' ? 0 : 2 ] = opts.height + 30; + }, + + afterShow: function (opts) { + //Check if exists and create or update list + if (this.list) { + this.update(opts); + + } else { + this.init(opts); + } + + //Set active element + this.list.children().removeClass('active').eq(F.current.index).addClass('active'); + }, + + onUpdate: function () { + this.update(); + }, + + beforeClose: function () { + if (this.wrap) { + this.wrap.remove(); + } + + this.wrap = null; + this.list = null; + this.width = 0; + } + } + +}(jQuery)); \ No newline at end of file diff --git a/vendor/assets/javascripts/jquery.fancybox.js b/vendor/assets/javascripts/jquery.fancybox.js new file mode 100755 index 0000000..704d95c --- /dev/null +++ b/vendor/assets/javascripts/jquery.fancybox.js @@ -0,0 +1,1463 @@ +/*! + * fancyBox - jQuery Plugin + * version: 2.0.6 (16/04/2012) + * @requires jQuery v1.6 or later + * + * Examples at http://fancyapps.com/fancybox/ + * License: www.fancyapps.com/fancybox/#license + * + * Copyright 2012 Janis Skarnelis - janis@fancyapps.com + * + */ + +(function (window, document, $, undefined) { + "use strict"; + + var W = $(window), + D = $(document), + F = $.fancybox = function () { + F.open.apply( this, arguments ); + }, + didResize = false, + resizeTimer = null, + isTouch = document.createTouch !== undefined, + isString = function(str) { + return $.type(str) === "string"; + }, + isPercentage = function(str) { + return isString(str) && str.indexOf('%') > 0; + }, + getValue = function(value, dim) { + if (dim && isPercentage(value)) { + value = F.getViewport()[ dim ] / 100 * parseInt(value, 10); + } + + return Math.round(value) + 'px'; + }; + + $.extend(F, { + // The current version of fancyBox + version: '2.0.5', + + defaults: { + padding: 15, + margin: 20, + + width: 800, + height: 600, + minWidth: 100, + minHeight: 100, + maxWidth: 9999, + maxHeight: 9999, + + autoSize: true, + autoResize: !isTouch, + autoCenter : !isTouch, + fitToView: true, + aspectRatio: false, + topRatio: 0.5, + + fixed: false, + scrolling: 'auto', // 'auto', 'yes' or 'no' + wrapCSS: '', + + arrows: true, + closeBtn: true, + closeClick: false, + nextClick : false, + mouseWheel: true, + autoPlay: false, + playSpeed: 3000, + preload : 3, + + modal: false, + loop: true, + ajax: { dataType: 'html', headers: { 'X-fancyBox': true } }, + keys: { + next: [13, 32, 34, 39, 40], // enter, space, page down, right arrow, down arrow + prev: [8, 33, 37, 38], // backspace, page up, left arrow, up arrow + close: [27] // escape key + }, + + // Override some properties + index: 0, + type: null, + href: null, + content: null, + title: null, + + // HTML templates + tpl: { + wrap: '
    ', + image: '', + iframe: '', + swf: '', + error: '

    The requested content cannot be loaded.
    Please try again later.

    ', + closeBtn: '
    ', + next: '', + prev: '' + }, + + // Properties for each animation type + // Opening fancyBox + openEffect: 'fade', // 'elastic', 'fade' or 'none' + openSpeed: 300, + openEasing: 'swing', + openOpacity: true, + openMethod: 'zoomIn', + + // Closing fancyBox + closeEffect: 'fade', // 'elastic', 'fade' or 'none' + closeSpeed: 300, + closeEasing: 'swing', + closeOpacity: true, + closeMethod: 'zoomOut', + + // Changing next gallery item + nextEffect: 'elastic', // 'elastic', 'fade' or 'none' + nextSpeed: 300, + nextEasing: 'swing', + nextMethod: 'changeIn', + + // Changing previous gallery item + prevEffect: 'elastic', // 'elastic', 'fade' or 'none' + prevSpeed: 300, + prevEasing: 'swing', + prevMethod: 'changeOut', + + // Enabled helpers + helpers: { + overlay: { + speedIn: 0, + speedOut: 300, + opacity: 0.8, + css: { + cursor: 'pointer' + }, + closeClick: true + }, + title: { + type: 'float' // 'float', 'inside', 'outside' or 'over' + } + }, + + // Callbacks + onCancel: $.noop, // If canceling + beforeLoad: $.noop, // Before loading + afterLoad: $.noop, // After loading + beforeShow: $.noop, // Before changing in current item + afterShow: $.noop, // After opening + beforeClose: $.noop, // Before closing + afterClose: $.noop // After closing + }, + + //Current state + group: {}, // Selected group + opts: {}, // Group options + coming: null, // Element being loaded + current: null, // Currently loaded element + isOpen: false, // Is currently open + isOpened: false, // Have been fully opened at least once + wrap: null, + skin: null, + outer: null, + inner: null, + + player: { + timer: null, + isActive: false + }, + + // Loaders + ajaxLoad: null, + imgPreload: null, + + // Some collections + transitions: {}, + helpers: {}, + + /* + * Static methods + */ + + open: function (group, opts) { + //Kill existing instances + F.close(true); + + //Normalize group + if (group && !$.isArray(group)) { + group = group instanceof $ ? $(group).get() : [group]; + } + + F.isActive = true; + + //Extend the defaults + F.opts = $.extend(true, {}, F.defaults, opts); + + //All options are merged recursive except keys + if ($.isPlainObject(opts) && opts.keys !== undefined) { + F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false; + } + + F.group = group; + + F._start(F.opts.index || 0); + }, + + cancel: function () { + if (F.coming && false === F.trigger('onCancel')) { + return; + } + + F.coming = null; + + F.hideLoading(); + + if (F.ajaxLoad) { + F.ajaxLoad.abort(); + } + + F.ajaxLoad = null; + + if (F.imgPreload) { + F.imgPreload.onload = F.imgPreload.onabort = F.imgPreload.onerror = null; + } + }, + + close: function (a) { + F.cancel(); + + if (!F.current || false === F.trigger('beforeClose')) { + return; + } + + F.unbindEvents(); + + //If forced or is still opening then remove immediately + if (!F.isOpen || (a && a[0] === true)) { + $('.fancybox-wrap').stop().trigger('onReset').remove(); + + F._afterZoomOut(); + + } else { + F.isOpen = F.isOpened = false; + + $('.fancybox-item, .fancybox-nav').remove(); + + F.wrap.stop(true).removeClass('fancybox-opened'); + F.inner.css('overflow', 'hidden'); + + F.transitions[F.current.closeMethod](); + } + }, + + // Start/stop slideshow + play: function (a) { + var clear = function () { + clearTimeout(F.player.timer); + }, + set = function () { + clear(); + + if (F.current && F.player.isActive) { + F.player.timer = setTimeout(F.next, F.current.playSpeed); + } + }, + stop = function () { + clear(); + + $('body').unbind('.player'); + + F.player.isActive = false; + + F.trigger('onPlayEnd'); + }, + start = function () { + if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) { + F.player.isActive = true; + + $('body').bind({ + 'afterShow.player onUpdate.player': set, + 'onCancel.player beforeClose.player': stop, + 'beforeLoad.player': clear + }); + + set(); + + F.trigger('onPlayStart'); + } + }; + + if (F.player.isActive || (a && a[0] === false)) { + stop(); + } else { + start(); + } + }, + + next: function () { + if (F.current) { + F.jumpto(F.current.index + 1); + } + }, + + prev: function () { + if (F.current) { + F.jumpto(F.current.index - 1); + } + }, + + jumpto: function (index) { + if (!F.current) { + return; + } + + index = parseInt(index, 10); + + if (F.group.length > 1 && F.current.loop) { + if (index >= F.group.length) { + index = 0; + + } else if (index < 0) { + index = F.group.length - 1; + } + } + + if (F.group[index] !== undefined) { + F.cancel(); + + F._start(index); + } + }, + + reposition: function (e, onlyAbsolute) { + var pos; + + if (F.isOpen) { + pos = F._getPosition(onlyAbsolute); + + if (e && e.type === 'scroll') { + delete pos.position; + + F.wrap.stop(true, true).animate(pos, 200); + + } else { + F.wrap.css(pos); + } + } + }, + + update: function (e) { + if (!F.isOpen) { + return; + } + + // Run this code after a delay for better performance + if (!didResize) { + resizeTimer = setTimeout(function () { + var current = F.current, anyway = !e || (e && e.type === 'orientationchange'); + + if (didResize) { + didResize = false; + + if (!current) { + return; + } + + if ((!e || e.type !== 'scroll') || anyway) { + if (current.autoSize && current.type !== 'iframe') { + F.inner.height('auto'); + current.height = F.inner.height(); + } + + if (current.autoResize || anyway) { + F._setDimension(); + } + + if (current.canGrow && current.type !== 'iframe') { + F.inner.height('auto'); + } + } + + if (current.autoCenter || anyway) { + F.reposition(e); + } + + F.trigger('onUpdate'); + } + }, 200); + } + + didResize = true; + }, + + toggle: function () { + if (F.isOpen) { + F.current.fitToView = !F.current.fitToView; + + F.update(); + } + }, + + hideLoading: function () { + D.unbind('keypress.fb'); + + $('#fancybox-loading').remove(); + }, + + showLoading: function () { + F.hideLoading(); + + //If user will press the escape-button, the request will be canceled + D.bind('keypress.fb', function(e) { + if (e.keyCode === 27) { + e.preventDefault(); + F.cancel(); + } + }); + + $('
    ').click(F.cancel).appendTo('body'); + }, + + getViewport: function () { + // See http://bugs.jquery.com/ticket/6724 + return { + x: W.scrollLeft(), + y: W.scrollTop(), + w: isTouch && window.innerWidth ? window.innerWidth : W.width(), + h: isTouch && window.innerHeight ? window.innerHeight : W.height() + }; + }, + + // Unbind the keyboard / clicking actions + unbindEvents: function () { + if (F.wrap) { + F.wrap.unbind('.fb'); + } + + D.unbind('.fb'); + W.unbind('.fb'); + }, + + bindEvents: function () { + var current = F.current, + keys = current.keys; + + if (!current) { + return; + } + + W.bind('resize.fb orientationchange.fb' + (current.autoCenter && !current.fixed ? ' scroll.fb' : ''), F.update); + + if (keys) { + D.bind('keydown.fb', function (e) { + var code, target = e.target || e.srcElement; + + // Ignore key combinations and key events within form elements + if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) { + code = e.keyCode; + + if ($.inArray(code, keys.close) > -1) { + F.close(); + e.preventDefault(); + + } else if ($.inArray(code, keys.next) > -1) { + F.next(); + e.preventDefault(); + + } else if ($.inArray(code, keys.prev) > -1) { + F.prev(); + e.preventDefault(); + } + } + }); + } + + if ($.fn.mousewheel && current.mouseWheel && F.group.length > 1) { + F.wrap.bind('mousewheel.fb', function (e, delta) { + var target = e.target || null; + + if (delta !== 0 && (!target || target.clientHeight === 0 || (target.scrollHeight === target.clientHeight && target.scrollWidth === target.clientWidth))) { + e.preventDefault(); + + F[delta > 0 ? 'prev' : 'next'](); + } + }); + } + }, + + trigger: function (event, o) { + var ret, obj = o || F[ $.inArray(event, ['onCancel', 'beforeLoad', 'afterLoad']) > -1 ? 'coming' : 'current' ]; + + if (!obj) { + return; + } + + if ($.isFunction( obj[event] )) { + ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1)); + } + + if (ret === false) { + return false; + } + + if (obj.helpers) { + $.each(obj.helpers, function (helper, opts) { + if (opts && $.isPlainObject(F.helpers[helper]) && $.isFunction(F.helpers[helper][event])) { + F.helpers[helper][event](opts, obj); + } + }); + } + + $.event.trigger(event + '.fb'); + }, + + isImage: function (str) { + return isString(str) && str.match(/\.(jpe?g|gif|png|bmp)((\?|#).*)?$/i); + }, + + isSWF: function (str) { + return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i); + }, + + _start: function (index) { + var coming = {}, + element = F.group[index] || null, + isDom, + href, + type, + rez, + hrefParts; + + if (element && (element.nodeType || element instanceof $)) { + isDom = true; + + if ($.metadata) { + coming = $(element).metadata(); + } + } + + coming = $.extend(true, {}, F.opts, {index : index, element : element}, ($.isPlainObject(element) ? element : coming)); + + // Re-check overridable options + $.each(['href', 'title', 'content', 'type'], function(i,v) { + coming[v] = F.opts[ v ] || (isDom && $(element).attr( v )) || coming[ v ] || null; + }); + + // Convert margin property to array - top, right, bottom, left + if (typeof coming.margin === 'number') { + coming.margin = [coming.margin, coming.margin, coming.margin, coming.margin]; + } + + // 'modal' propery is just a shortcut + if (coming.modal) { + $.extend(true, coming, { + closeBtn : false, + closeClick: false, + nextClick : false, + arrows : false, + mouseWheel : false, + keys : null, + helpers: { + overlay : { + css: { + cursor : 'auto' + }, + closeClick : false + } + } + }); + } + + //Give a chance for callback or helpers to update coming item (type, title, etc) + F.coming = coming; + + if (false === F.trigger('beforeLoad')) { + F.coming = null; + return; + } + + type = coming.type; + href = coming.href || element; + + ///Check if content type is set, if not, try to get + if (!type) { + if (isDom) { + type = $(element).data('fancybox-type'); + + if (!type) { + rez = element.className.match(/fancybox\.(\w+)/); + type = rez ? rez[1] : null; + } + } + + if (!type && isString(href)) { + if (F.isImage(href)) { + type = 'image'; + + } else if (F.isSWF(href)) { + type = 'swf'; + + } else if (href.match(/^#/)) { + type = 'inline'; + } + } + + // ...if not - display element itself + if (!type) { + type = isDom ? 'inline' : 'html'; + } + + coming.type = type; + } + + // Check before try to load; 'inline' and 'html' types need content, others - href + if (type === 'inline' || type === 'html') { + if (!coming.content) { + if (type === 'inline') { + coming.content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7 + + } else { + coming.content = element; + } + } + + if (!coming.content || !coming.content.length) { + type = null; + } + + } else if (!href) { + type = null; + } + + /* + * Add reference to the group, so it`s possible to access from callbacks, example: + * afterLoad : function() { + * this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : ''); + * } + */ + + if (type === 'ajax' && isString(href)) { + hrefParts = href.split(/\s+/, 2); + + href = hrefParts.shift(); + coming.selector = hrefParts.shift(); + } + + coming.href = href; + coming.group = F.group; + coming.isDom = isDom; + + switch (type) { + case 'image': + F._loadImage(); + break; + + case 'ajax': + F._loadAjax(); + break; + + case 'inline': + case 'iframe': + case 'swf': + case 'html': + F._afterLoad(); + break; + + default: + F._error( 'type' ); + } + }, + + _error: function ( type ) { + F.hideLoading(); + + $.extend(F.coming, { + type : 'html', + autoSize : true, + minWidth : 0, + minHeight : 0, + padding : 15, + hasError : type, + content : F.coming.tpl.error + }); + + F._afterLoad(); + }, + + _loadImage: function () { + // Reset preload image so it is later possible to check "complete" property + var img = F.imgPreload = new Image(); + + img.onload = function () { + this.onload = this.onerror = null; + + F.coming.width = this.width; + F.coming.height = this.height; + + F._afterLoad(); + }; + + img.onerror = function () { + this.onload = this.onerror = null; + + F._error( 'image' ); + }; + + img.src = F.coming.href; + + if (img.complete === undefined || !img.complete) { + F.showLoading(); + } + }, + + _loadAjax: function () { + F.showLoading(); + + F.ajaxLoad = $.ajax($.extend({}, F.coming.ajax, { + url: F.coming.href, + error: function (jqXHR, textStatus) { + if (F.coming && textStatus !== 'abort') { + F._error( 'ajax', jqXHR ); + + } else { + F.hideLoading(); + } + }, + success: function (data, textStatus) { + if (textStatus === 'success') { + F.coming.content = data; + + F._afterLoad(); + } + } + })); + }, + + _preloadImages: function() { + var group = F.group, + current = F.current, + len = group.length, + item, + href, + i, + cnt = Math.min(current.preload, len - 1); + + if (!current.preload || group.length < 2) { + return; + } + + for (i = 1; i <= cnt; i += 1) { + item = group[ (current.index + i ) % len ]; + href = item.href || $( item ).attr('href') || item; + + if (item.type === 'image' || F.isImage(href)) { + new Image().src = href; + } + } + }, + + _afterLoad: function () { + F.hideLoading(); + + if (!F.coming || false === F.trigger('afterLoad', F.current)) { + F.coming = false; + + return; + } + + if (F.isOpened) { + $('.fancybox-item, .fancybox-nav').remove(); + + F.wrap.stop(true).removeClass('fancybox-opened'); + F.inner.css('overflow', 'hidden'); + + F.transitions[F.current.prevMethod](); + + } else { + $('.fancybox-wrap').stop().trigger('onReset').remove(); + + F.trigger('afterClose'); + } + + F.unbindEvents(); + + F.isOpen = false; + F.current = F.coming; + + //Build the neccessary markup + F.wrap = $(F.current.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + F.current.type + ' fancybox-tmp ' + F.current.wrapCSS).appendTo('body'); + F.skin = $('.fancybox-skin', F.wrap).css('padding', getValue(F.current.padding)); + F.outer = $('.fancybox-outer', F.wrap); + F.inner = $('.fancybox-inner', F.wrap); + + F._setContent(); + }, + + _setContent: function () { + var current = F.current, + content = current.content, + type = current.type, + minWidth = current.minWidth, + minHeight = current.minHeight, + maxWidth = current.maxWidth, + maxHeight = current.maxHeight, + loadingBay; + + switch (type) { + case 'inline': + case 'ajax': + case 'html': + if (current.selector) { + content = $('
    ').html(content).find(current.selector); + + } else if (content instanceof $) { + if (content.parent().hasClass('fancybox-inner')) { + content.parents('.fancybox-wrap').unbind('onReset'); + } + + content = content.show().detach(); + + $(F.wrap).bind('onReset', function () { + content.appendTo('body').hide(); + }); + } + + if (current.autoSize) { + loadingBay = $('
    ') + .appendTo('body') + .css({ + minWidth : getValue(minWidth, 'w'), + minHeight : getValue(minHeight, 'h'), + maxWidth : getValue(maxWidth, 'w'), + maxHeight : getValue(maxHeight, 'h') + }) + .append(content); + + current.width = loadingBay.width(); + current.height = loadingBay.height(); + + // Re-check to fix 1px bug in some browsers + loadingBay.width( F.current.width ); + + if (loadingBay.height() > current.height) { + loadingBay.width(current.width + 1); + + current.width = loadingBay.width(); + current.height = loadingBay.height(); + } + + content = loadingBay.contents().detach(); + + loadingBay.remove(); + } + + break; + + case 'image': + content = current.tpl.image.replace('{href}', current.href); + + current.aspectRatio = true; + break; + + case 'swf': + content = current.tpl.swf.replace(/\{width\}/g, current.width).replace(/\{height\}/g, current.height).replace(/\{href\}/g, current.href); + break; + + case 'iframe': + content = $(current.tpl.iframe.replace('{rnd}', new Date().getTime()) ) + .attr('scrolling', current.scrolling) + .attr('src', current.href); + + current.scrolling = isTouch ? 'scroll' : 'auto'; + + break; + } + + if (type === 'image' || type === 'swf') { + current.autoSize = false; + current.scrolling = 'visible'; + } + + if (type === 'iframe' && current.autoSize) { + F.showLoading(); + + F._setDimension(); + + F.inner.css('overflow', current.scrolling); + + content.bind({ + onCancel : function() { + $(this).unbind(); + + F._afterZoomOut(); + }, + load : function() { + F.hideLoading(); + + try { + if (this.contentWindow.document.location) { + F.current.height = $(this).contents().find('body').height(); + } + } catch (e) { + F.current.autoSize = false; + } + + F[ F.isOpen ? '_afterZoomIn' : '_beforeShow'](); + } + }).appendTo(F.inner); + + } else { + F.inner.append(content); + + F._beforeShow(); + } + }, + + _beforeShow : function() { + F.coming = null; + + //Give a chance for helpers or callbacks to update elements + F.trigger('beforeShow'); + + //Set initial dimensions and hide + F._setDimension(); + F.wrap.hide().removeClass('fancybox-tmp'); + + F.bindEvents(); + + F._preloadImages(); + + F.transitions[ F.isOpened ? F.current.nextMethod : F.current.openMethod ](); + }, + + _setDimension: function () { + var wrap = F.wrap, + inner = F.inner, + current = F.current, + viewport = F.getViewport(), + margin = current.margin, + padding2 = current.padding * 2, + width = current.width, + height = current.height, + maxWidth = current.maxWidth + padding2, + maxHeight = current.maxHeight + padding2, + minWidth = current.minWidth + padding2, + minHeight = current.minHeight + padding2, + ratio, + height_; + + viewport.w -= (margin[1] + margin[3]); + viewport.h -= (margin[0] + margin[2]); + + if (isPercentage(width)) { + width = (((viewport.w - padding2) * parseFloat(width)) / 100); + } + + if (isPercentage(height)) { + height = (((viewport.h - padding2) * parseFloat(height)) / 100); + } + + ratio = width / height; + width += padding2; + height += padding2; + + if (current.fitToView) { + maxWidth = Math.min(viewport.w, maxWidth); + maxHeight = Math.min(viewport.h, maxHeight); + } + + if (current.aspectRatio) { + if (width > maxWidth) { + width = maxWidth; + height = ((width - padding2) / ratio) + padding2; + } + + if (height > maxHeight) { + height = maxHeight; + width = ((height - padding2) * ratio) + padding2; + } + + if (width < minWidth) { + width = minWidth; + height = ((width - padding2) / ratio) + padding2; + } + + if (height < minHeight) { + height = minHeight; + width = ((height - padding2) * ratio) + padding2; + } + + } else { + width = Math.max(minWidth, Math.min(width, maxWidth)); + height = Math.max(minHeight, Math.min(height, maxHeight)); + } + + width = Math.round(width); + height = Math.round(height); + + //Reset dimensions + $(wrap.add(inner)).width('auto').height('auto'); + + inner.width(width - padding2).height(height - padding2); + wrap.width(width); + + height_ = wrap.height(); // Real wrap height + + //Fit wrapper inside + if (width > maxWidth || height_ > maxHeight) { + while ((width > maxWidth || height_ > maxHeight) && width > minWidth && height_ > minHeight) { + height = height - 10; + + if (current.aspectRatio) { + width = Math.round(((height - padding2) * ratio) + padding2); + + if (width < minWidth) { + width = minWidth; + height = ((width - padding2) / ratio) + padding2; + } + + } else { + width = width - 10; + } + + inner.width(width - padding2).height(height - padding2); + wrap.width(width); + + height_ = wrap.height(); + } + } + + current.dim = { + width : getValue(width), + height : getValue(height_) + }; + + current.canGrow = current.autoSize && height > minHeight && height < maxHeight; + current.canShrink = false; + current.canExpand = false; + + if ((width - padding2) < current.width || (height - padding2) < current.height) { + current.canExpand = true; + + } else if ((width > viewport.w || height_ > viewport.h) && width > minWidth && height > minHeight) { + current.canShrink = true; + } + + F.innerSpace = height_ - padding2 - inner.height(); + }, + + _getPosition: function (onlyAbsolute) { + var current = F.current, + viewport = F.getViewport(), + margin = current.margin, + width = F.wrap.width() + margin[1] + margin[3], + height = F.wrap.height() + margin[0] + margin[2], + rez = { + position: 'absolute', + top : margin[0] + viewport.y, + left : margin[3] + viewport.x + }; + + if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) { + rez = { + position: 'fixed', + top : margin[0], + left : margin[3] + }; + } + + rez.top = getValue(Math.max(rez.top, rez.top + ((viewport.h - height) * current.topRatio))); + rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width) * 0.5))); + + return rez; + }, + + _afterZoomIn: function () { + var current = F.current, scrolling = current ? current.scrolling : 'no'; + + if (!current) { + return; + } + + F.isOpen = F.isOpened = true; + + F.wrap.addClass('fancybox-opened'); + + F.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling)); + + F.trigger('afterShow'); + + F.update(); + + //Assign a click event + if (current.closeClick || current.nextClick) { + F.inner.css('cursor', 'pointer').bind('click.fb', function(e) { + if (!$(e.target).is('a') && !$(e.target).parent().is('a')) { + F[ current.closeClick ? 'close' : 'next' ](); + } + }); + } + + //Create a close button + if (current.closeBtn) { + $(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', F.close); + } + + //Create navigation arrows + if (current.arrows && F.group.length > 1) { + if (current.loop || current.index > 0) { + $(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev); + } + + if (current.loop || current.index < F.group.length - 1) { + $(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next); + } + } + + if (F.opts.autoPlay && !F.player.isActive) { + F.opts.autoPlay = false; + + F.play(); + } + }, + + _afterZoomOut: function () { + var current = F.current; + + F.wrap.trigger('onReset').remove(); + + $.extend(F, { + group: {}, + opts: {}, + current: null, + isActive: false, + isOpened: false, + isOpen: false, + wrap: null, + skin: null, + outer: null, + inner: null + }); + + F.trigger('afterClose', current); + } + }); + + /* + * Default transitions + */ + + F.transitions = { + getOrigPosition: function () { + var current = F.current, + element = current.element, + padding = current.padding, + orig = $(current.orig), + pos = {}, + width = 50, + height = 50, + viewport; + + if (!orig.length && current.isDom && $(element).is(':visible')) { + orig = $(element).find('img:first'); + + if (!orig.length) { + orig = $(element); + } + } + + if (orig.length) { + pos = orig.offset(); + + if (orig.is('img')) { + width = orig.outerWidth(); + height = orig.outerHeight(); + } + + } else { + viewport = F.getViewport(); + + pos.top = viewport.y + (viewport.h - height) * 0.5; + pos.left = viewport.x + (viewport.w - width) * 0.5; + } + + pos = { + top : getValue(pos.top - padding), + left : getValue(pos.left - padding), + width : getValue(width + padding * 2), + height : getValue(height + padding * 2) + }; + + return pos; + }, + + step: function (now, fx) { + var prop = fx.prop, value, ratio; + + if (prop === 'width' || prop === 'height') { + value = Math.ceil(now - (F.current.padding * 2)); + + if (prop === 'height') { + ratio = (now - fx.start) / (fx.end - fx.start); + + if (fx.start > fx.end) { + ratio = 1 - ratio; + } + + value -= F.innerSpace * ratio; + } + + F.inner[prop](value); + } + }, + + zoomIn: function () { + var wrap = F.wrap, + current = F.current, + effect = current.openEffect, + elastic = effect === 'elastic', + dim = current.dim, + startPos = $.extend({}, dim, F._getPosition( elastic )), + endPos = $.extend({opacity : 1}, startPos); + + //Remove "position" property that breaks older IE + delete endPos.position; + + if (elastic) { + startPos = this.getOrigPosition(); + + if (current.openOpacity) { + startPos.opacity = 0; + } + + F.outer.add(F.inner).width('auto').height('auto'); + + } else if (effect === 'fade') { + startPos.opacity = 0; + } + + wrap.css(startPos) + .show() + .animate(endPos, { + duration : effect === 'none' ? 0 : current.openSpeed, + easing : current.openEasing, + step : elastic ? this.step : null, + complete : F._afterZoomIn + }); + }, + + zoomOut: function () { + var wrap = F.wrap, + current = F.current, + effect = current.openEffect, + elastic = effect === 'elastic', + endPos = {opacity : 0}; + + if (elastic) { + if (wrap.css('position') === 'fixed') { + wrap.css(F._getPosition(true)); + } + + endPos = this.getOrigPosition(); + + if (current.closeOpacity) { + endPos.opacity = 0; + } + } + + wrap.animate(endPos, { + duration : effect === 'none' ? 0 : current.closeSpeed, + easing : current.closeEasing, + step : elastic ? this.step : null, + complete : F._afterZoomOut + }); + }, + + changeIn: function () { + var wrap = F.wrap, + current = F.current, + effect = current.nextEffect, + elastic = effect === 'elastic', + startPos = F._getPosition( elastic ), + endPos = { opacity : 1 }; + + startPos.opacity = 0; + + if (elastic) { + startPos.top = getValue(parseInt(startPos.top, 10) - 200); + endPos.top = '+=200px'; + } + + wrap.css(startPos) + .show() + .animate(endPos, { + duration : effect === 'none' ? 0 : current.nextSpeed, + easing : current.nextEasing, + complete : F._afterZoomIn + }); + }, + + changeOut: function () { + var wrap = F.wrap, + current = F.current, + effect = current.prevEffect, + endPos = { opacity : 0 }, + cleanUp = function () { + $(this).trigger('onReset').remove(); + }; + + wrap.removeClass('fancybox-opened'); + + if (effect === 'elastic') { + endPos.top = '+=200px'; + } + + wrap.animate(endPos, { + duration : effect === 'none' ? 0 : current.prevSpeed, + easing : current.prevEasing, + complete : cleanUp + }); + } + }; + + /* + * Overlay helper + */ + + F.helpers.overlay = { + overlay: null, + + update: function () { + var width, scrollWidth, offsetWidth; + + //Reset width/height so it will not mess + this.overlay.width('100%').height('100%'); + + if ($.browser.msie || isTouch) { + scrollWidth = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth); + offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth); + + width = scrollWidth < offsetWidth ? W.width() : scrollWidth; + + } else { + width = D.width(); + } + + this.overlay.width(width).height(D.height()); + }, + + beforeShow: function (opts) { + if (this.overlay) { + return; + } + + opts = $.extend(true, {}, F.defaults.helpers.overlay, opts); + + this.overlay = $('
    ').css(opts.css).appendTo('body'); + + if (opts.closeClick) { + this.overlay.bind('click.fb', F.close); + } + + if (F.current.fixed && !isTouch) { + this.overlay.addClass('overlay-fixed'); + + } else { + this.update(); + + this.onUpdate = function () { + this.update(); + }; + } + + this.overlay.fadeTo(opts.speedIn, opts.opacity); + }, + + afterClose: function (opts) { + if (this.overlay) { + this.overlay.fadeOut(opts.speedOut || 0, function () { + $(this).remove(); + }); + } + + this.overlay = null; + } + }; + + /* + * Title helper + */ + + F.helpers.title = { + beforeShow: function (opts) { + var title, text = F.current.title; + + if (text) { + title = $('
    ' + text + '
    ').appendTo('body'); + + if (opts.type === 'float') { + //This helps for some browsers + title.width(title.width()); + + title.wrapInner(''); + + //Increase bottom margin so this title will also fit into viewport + F.current.margin[2] += Math.abs(parseInt(title.css('margin-bottom'), 10)); + } + + title.appendTo(opts.type === 'over' ? F.inner : (opts.type === 'outside' ? F.wrap : F.skin)); + } + } + }; + + // jQuery plugin initialization + $.fn.fancybox = function (options) { + var that = $(this), + selector = this.selector || '', + index, + run = function(e) { + var what = this, idx = index, relType, relVal; + + if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !$(what).is('.fancybox-wrap')) { + e.preventDefault(); + + relType = options.groupAttr || 'data-fancybox-group'; + relVal = $(what).attr(relType); + + if (!relVal) { + relType = 'rel'; + relVal = what[ relType ]; + } + + if (relVal && relVal !== '' && relVal !== 'nofollow') { + what = selector.length ? $(selector) : that; + what = what.filter('[' + relType + '="' + relVal + '"]'); + idx = what.index(this); + } + + options.index = idx; + + F.open(what, options); + } + }; + + options = options || {}; + index = options.index || 0; + + if (selector) { + D.undelegate(selector, 'click.fb-start').delegate(selector, 'click.fb-start', run); + + } else { + that.unbind('click.fb-start').bind('click.fb-start', run); + } + + return this; + }; + + // Test for fixedPosition needs a body at doc ready + $(document).ready(function() { + F.defaults.fixed = $.support.fixedPosition || (!($.browser.msie && $.browser.version <= 6) && !isTouch); + }); + +}(window, document, jQuery)); \ No newline at end of file diff --git a/vendor/assets/stylesheets/fancybox.css b/vendor/assets/stylesheets/fancybox.css new file mode 100644 index 0000000..96517db --- /dev/null +++ b/vendor/assets/stylesheets/fancybox.css @@ -0,0 +1,5 @@ +/* + *= require jquery.fancybox + *= require jquery.fancybox-buttons + *= require jquery.fancybox-thumbs +*/ diff --git a/vendor/assets/stylesheets/jquery.fancybox-buttons.css b/vendor/assets/stylesheets/jquery.fancybox-buttons.css new file mode 100755 index 0000000..0cff8a3 --- /dev/null +++ b/vendor/assets/stylesheets/jquery.fancybox-buttons.css @@ -0,0 +1,85 @@ +#fancybox-buttons { + position: fixed; + left: 0; + width: 100%; + z-index: 8050; +} + +#fancybox-buttons.top { + top: 10px; +} + +#fancybox-buttons.bottom { + bottom: 10px; +} + +#fancybox-buttons ul { + display: block; + width: 170px; + height: 30px; + margin: 0 auto; + padding: 0; + list-style: none; + background: #111; + -webkit-box-shadow: 0 1px 3px #000,0 0 0 1px rgba(0,0,0,.7),inset 0 0 0 1px rgba(255,255,255,.05); + -moz-box-shadow: 0 1px 3px #000,0 0 0 1px rgba(0,0,0,.7),inset 0 0 0 1px rgba(255,255,255,.05); + background: #111 -webkit-gradient(linear,0% 0%,0% 100%,from(rgba(255,255,255,.2)),color-stop(.5,rgba(255,255,255,.15)),color-stop(.5,rgba(255,255,255,.1)),to(rgba(255,255,255,.15))); + background: #111 -moz-linear-gradient(top,rgba(255,255,255,.2) 0%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.1) 50%,rgba(255,255,255,.15) 100%); + border-radius: 3px; +} + +#fancybox-buttons ul li { + float: left; + margin: 0; + padding: 0; +} + +#fancybox-buttons a { + display: block; + width: 30px; + height: 30px; + text-indent: -9999px; + background-image: url('fancybox_buttons.png'); + background-repeat: no-repeat; + outline: none; +} + +#fancybox-buttons a.btnPrev { + width: 32px; + background-position: 6px 0; +} + +#fancybox-buttons a.btnNext { + background-position: -33px 0; + border-right: 1px solid #3e3e3e; +} + +#fancybox-buttons a.btnPlay { + background-position: 0 -30px; +} + +#fancybox-buttons a.btnPlayOn { + background-position: -30px -30px; +} + +#fancybox-buttons a.btnToggle { + background-position: 3px -60px; + border-left: 1px solid #111; + border-right: 1px solid #3e3e3e; + width: 35px +} + +#fancybox-buttons a.btnToggleOn { + background-position: -27px -60px; +} + +#fancybox-buttons a.btnClose { + border-left: 1px solid #111; + width: 38px; + background-position: -57px 0px; +} + +#fancybox-buttons a.btnDisabled { + opacity : 0.5; + cursor: default; +} \ No newline at end of file diff --git a/vendor/assets/stylesheets/jquery.fancybox-thumbs.css b/vendor/assets/stylesheets/jquery.fancybox-thumbs.css new file mode 100755 index 0000000..e40ae82 --- /dev/null +++ b/vendor/assets/stylesheets/jquery.fancybox-thumbs.css @@ -0,0 +1,54 @@ +#fancybox-thumbs { + position: fixed; + left: 0; + width: 100%; + overflow: hidden; + z-index: 8050; +} + +#fancybox-thumbs.bottom { + bottom: 2px; +} + +#fancybox-thumbs.top { + top: 2px; +} + +#fancybox-thumbs ul { + position: relative; + list-style: none; + margin: 0; + padding: 0; +} + +#fancybox-thumbs ul li { + float: left; + padding: 1px; + opacity: 0.5; +} + +#fancybox-thumbs ul li.active { + opacity: 0.75; + padding: 0; + border: 1px solid #fff; +} + +#fancybox-thumbs ul li:hover { + opacity: 1; +} + +#fancybox-thumbs ul li a { + display: block; + position: relative; + overflow: hidden; + border: 1px solid #222; + background: #111; + outline: none; +} + +#fancybox-thumbs ul li img { + display: block; + position: relative; + border: 0; + padding: 0; +} \ No newline at end of file diff --git a/vendor/assets/stylesheets/jquery.fancybox.css b/vendor/assets/stylesheets/jquery.fancybox.css new file mode 100755 index 0000000..783d02f --- /dev/null +++ b/vendor/assets/stylesheets/jquery.fancybox.css @@ -0,0 +1,234 @@ +/*! fancyBox v2.0.6 fancyapps.com | fancyapps.com/fancybox/#license */ +.fancybox-tmp iframe, .fancybox-tmp object { + vertical-align: top; + padding: 0; + margin: 0; +} + +.fancybox-wrap { + position: absolute; + top: 0; + left: 0; + z-index: 8020; +} + +.fancybox-skin { + position: relative; + padding: 0; + margin: 0; + background: #f9f9f9; + color: #444; + text-shadow: none; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.fancybox-opened { + z-index: 8030; +} + +.fancybox-opened .fancybox-skin { + -webkit-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); +} + +.fancybox-outer, .fancybox-inner { + padding: 0; + margin: 0; + position: relative; + outline: none; +} + +.fancybox-inner { + overflow: hidden; +} + +.fancybox-type-iframe .fancybox-inner { + -webkit-overflow-scrolling: touch; +} + +.fancybox-error { + color: #444; + font: 14px/20px "Helvetica Neue",Helvetica,Arial,sans-serif; + margin: 0; + padding: 10px; +} + +.fancybox-image, .fancybox-iframe { + display: block; + width: 100%; + height: 100%; + border: 0; + padding: 0; + margin: 0; + vertical-align: top; +} + +.fancybox-image { + max-width: 100%; + max-height: 100%; +} + +#fancybox-loading, .fancybox-close, .fancybox-prev span, .fancybox-next span { + background-image: url('fancybox_sprite.png'); +} + +#fancybox-loading { + position: fixed; + top: 50%; + left: 50%; + margin-top: -22px; + margin-left: -22px; + background-position: 0 -108px; + opacity: 0.8; + cursor: pointer; + z-index: 8020; +} + +#fancybox-loading div { + width: 44px; + height: 44px; + background: url('fancybox_loading.gif') center center no-repeat; +} + +.fancybox-close { + position: absolute; + top: -18px; + right: -18px; + width: 36px; + height: 36px; + cursor: pointer; + z-index: 8040; +} + +.fancybox-nav { + position: absolute; + top: 0; + width: 40%; + height: 100%; + cursor: pointer; + background: transparent url('blank.gif'); /* helps IE */ + -webkit-tap-highlight-color: rgba(0,0,0,0); + z-index: 8040; +} + +.fancybox-prev { + left: 0; +} + +.fancybox-next { + right: 0; +} + +.fancybox-nav span { + position: absolute; + top: 50%; + width: 36px; + height: 34px; + margin-top: -18px; + cursor: pointer; + z-index: 8040; + visibility: hidden; +} + +.fancybox-prev span { + left: 20px; + background-position: 0 -36px; +} + +.fancybox-next span { + right: 20px; + background-position: 0 -72px; +} + +.fancybox-nav:hover span { + visibility: visible; +} + +.fancybox-tmp { + position: absolute; + top: -9999px; + left: -9999px; + padding: 0; + overflow: visible; + visibility: hidden; +} + +/* Overlay helper */ + +#fancybox-overlay { + position: absolute; + top: 0; + left: 0; + overflow: hidden; + display: none; + z-index: 8010; + background: #000; +} + +#fancybox-overlay.overlay-fixed { + position: fixed; + bottom: 0; + right: 0; +} + +/* Title helper */ + +.fancybox-title { + visibility: hidden; + font: normal 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif; + position: relative; + text-shadow: none; + z-index: 8050; +} + +.fancybox-opened .fancybox-title { + visibility: visible; +} + +.fancybox-title-float-wrap { + position: absolute; + bottom: 0; + right: 50%; + margin-bottom: -35px; + z-index: 8030; + text-align: center; +} + +.fancybox-title-float-wrap .child { + display: inline-block; + margin-right: -100%; + padding: 2px 20px; + background: transparent; /* Fallback for web browsers that doesn't support RGBa */ + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; + text-shadow: 0 1px 2px #222; + color: #FFF; + font-weight: bold; + line-height: 24px; + white-space: nowrap; +} + +.fancybox-title-outside-wrap { + position: relative; + margin-top: 10px; + color: #fff; +} + +.fancybox-title-inside-wrap { + margin-top: 10px; +} + +.fancybox-title-over-wrap { + position: absolute; + bottom: 0; + left: 0; + color: #fff; + padding: 10px; + background: #000; + background: rgba(0, 0, 0, .8); +} \ No newline at end of file