├── Procfile ├── config.ru ├── views ├── calling.haml ├── browser-phone │ ├── dial_client.xml │ ├── dial_number.php │ ├── LICENSE │ └── browser-phone.php ├── sms.haml ├── index.haml ├── layout.haml ├── javascripts │ ├── jquery.foundation.alerts.js │ ├── jquery.foundation.mediaQueryToggle.js │ ├── jquery.foundation.accordion.js │ ├── app.js │ ├── jquery.foundation.navigation.js │ ├── jquery.foundation.tabs.js │ ├── jquery.foundation.buttons.js │ ├── jquery.foundation.magellan.js │ ├── jquery.placeholder.js │ ├── jquery.foundation.topbar.js │ ├── modernizr.foundation.js │ ├── jquery.foundation.tooltips.js │ ├── jquery.foundation.clearing.js │ ├── jquery.foundation.forms.js │ ├── jquery.foundation.joyride.js │ ├── jquery.foundation.reveal.js │ └── jquery.foundation.orbit.js ├── dd.haml └── dex.erb ├── public ├── images │ └── foundation │ │ └── orbit │ │ ├── bullets.jpg │ │ ├── loading.gif │ │ ├── left-arrow.png │ │ ├── mask-black.png │ │ ├── pause-black.png │ │ ├── right-arrow.png │ │ ├── timer-black.png │ │ ├── rotator-black.png │ │ ├── left-arrow-small.png │ │ └── right-arrow-small.png └── stylesheets │ └── app.css ├── Gemfile ├── README.md ├── t.rb ├── yelp.rb ├── Gemfile.lock └── prank.rb /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec ruby prank.rb -p $PORT 2 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require './prank.rb' 2 | run Sinatra::Application 3 | -------------------------------------------------------------------------------- /views/calling.haml: -------------------------------------------------------------------------------- 1 | %body 2 | %h1 MAKING CALL TO #{number1} AND #{number2} 3 | -------------------------------------------------------------------------------- /public/images/foundation/orbit/bullets.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i/rubyprank/master/public/images/foundation/orbit/bullets.jpg -------------------------------------------------------------------------------- /public/images/foundation/orbit/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i/rubyprank/master/public/images/foundation/orbit/loading.gif -------------------------------------------------------------------------------- /public/images/foundation/orbit/left-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i/rubyprank/master/public/images/foundation/orbit/left-arrow.png -------------------------------------------------------------------------------- /public/images/foundation/orbit/mask-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i/rubyprank/master/public/images/foundation/orbit/mask-black.png -------------------------------------------------------------------------------- /public/images/foundation/orbit/pause-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i/rubyprank/master/public/images/foundation/orbit/pause-black.png -------------------------------------------------------------------------------- /public/images/foundation/orbit/right-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i/rubyprank/master/public/images/foundation/orbit/right-arrow.png -------------------------------------------------------------------------------- /public/images/foundation/orbit/timer-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i/rubyprank/master/public/images/foundation/orbit/timer-black.png -------------------------------------------------------------------------------- /public/images/foundation/orbit/rotator-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i/rubyprank/master/public/images/foundation/orbit/rotator-black.png -------------------------------------------------------------------------------- /views/browser-phone/dial_client.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | alice 4 | -------------------------------------------------------------------------------- /public/images/foundation/orbit/left-arrow-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i/rubyprank/master/public/images/foundation/orbit/left-arrow-small.png -------------------------------------------------------------------------------- /public/images/foundation/orbit/right-arrow-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i/rubyprank/master/public/images/foundation/orbit/right-arrow-small.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org', '~>3.1.4' 2 | gem 'sinatra' 3 | gem 'uuid' 4 | gem 'erubis' 5 | gem 'builder' 6 | gem 'oauth' 7 | gem 'twilio-ruby' 8 | gem 'haml' 9 | -------------------------------------------------------------------------------- /views/browser-phone/dial_number.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rubyprank 2 | ========= 3 | Deprecated version of Prank Roulette. [Prank Roulette](https://github.com/sagnew/Prank-Roulette "Prank Roulette"). 4 | Check out the live version here: http://prankroulette.com 5 | -------------------------------------------------------------------------------- /views/sms.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | 3 | %html 4 | %head 5 | %title PrankRoulette - Screw over everyone! 6 | %body 7 | %form(action='/sms' method='POST') 8 | %input(type='text' name='number') 9 | %input(type='text' name='message') 10 | %input(type='submit') 11 | -------------------------------------------------------------------------------- /views/index.haml: -------------------------------------------------------------------------------- 1 | .row 2 | .two.columns 3 | Enter two phone numbers and listen to the phone call they have. 4 | .ten.columns.centered 5 | %form(action='/call' method='POST') 6 | %input(type='text' placeholder='Enter 1st #' size='10' name='number1') 7 | %input(type='text' placeholder='Enter 2nd #' size='10' name='number2') 8 | %input(type='text' placeholder='Enter your #' size='10' name='number3') 9 | %input(type='submit' value='Call') 10 | -------------------------------------------------------------------------------- /views/layout.haml: -------------------------------------------------------------------------------- 1 | !!! 5 2 | %html 3 | %head 4 | %title PrankRoulette - Play Operator 5 | %meta{charset: 'utf-8'}/ 6 | %meta{name: 'viewpoint', content: 'width=device-width, initial-scale=1, maximum-scale=1'}/ 7 | 8 | %link{rel: 'stylesheet', href: '/stylesheets/app.css'}/ 9 | %link{rel: 'stylesheet', href: '/stylesheets/foundation.css'}/ 10 | %link{rel: 'stylesheet', href: '/stylesheets/foundation.min.css'}/ 11 | 12 | %body 13 | .row 14 | %h1 PrankRoulette 15 | %hr 16 | =yield 17 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.alerts.js: -------------------------------------------------------------------------------- 1 | ;(function ($, window, undefined) { 2 | 'use strict'; 3 | 4 | $.fn.foundationAlerts = function (options) { 5 | var settings = $.extend({ 6 | callback: $.noop 7 | }, options); 8 | 9 | $(document).on("click", ".alert-box a.close", function (e) { 10 | e.preventDefault(); 11 | $(this).closest(".alert-box").fadeOut(function () { 12 | $(this).remove(); 13 | // Do something else after the alert closes 14 | settings.callback(); 15 | }); 16 | }); 17 | 18 | }; 19 | 20 | })(jQuery, this); 21 | -------------------------------------------------------------------------------- /t.rb: -------------------------------------------------------------------------------- 1 | require 'oauth' 2 | require 'json' 3 | 4 | consumer_key = 'Sorq2fWtuL-FF7AYS0dq-w' 5 | consumer_secret = 'HTWRIJmFgHStxEqz0ItWqaPGIHE' 6 | token = '_PDNffZN54vOmnzYtzp7ig98gyX3zg0L' 7 | token_secret = 'RgEjVR7ECQS5mxmD1l4lTC2ifIA' 8 | 9 | api_host = 'api.yelp.com' 10 | 11 | consumer = OAuth::Consumer.new(consumer_key, consumer_secret, {:site => "http://#{api_host}"}) 12 | access_token = OAuth::AccessToken.new(consumer, token, token_secret) 13 | 14 | path = "/v2/search?term=restaurants&location=new%20brunswick" 15 | 16 | #p access_token.get(path).body.class 17 | 18 | json = JSON.parse access_token.get(path).body 19 | puts (json) 20 | 21 | -------------------------------------------------------------------------------- /yelp.rb: -------------------------------------------------------------------------------- 1 | require 'oauth' 2 | require 'json' 3 | 4 | consumer_key = 'Sorq2fWtuL-FF7AYS0dq-w' 5 | consumer_secret = 'HTWRIJmFgHStxEqz0ItWqaPGIHE' 6 | token = '_PDNffZN54vOmnzYtzp7ig98gyX3zg0L' 7 | token_secret = 'RgEjVR7ECQS5mxmD1l4lTC2ifIA' 8 | 9 | api_host = 'api.yelp.com' 10 | 11 | consumer = OAuth::Consumer.new(consumer_key, consumer_secret, {:site => "http://#{api_host}"}) 12 | access_token = OAuth::AccessToken.new(consumer, token, token_secret) 13 | 14 | path = "/v2/search?term=restaurants&location=new%20brunswick" 15 | 16 | #p access_token.get(path).body.class 17 | 18 | json = JSON.parse access_token.get(path).body 19 | puts (json) 20 | 21 | -------------------------------------------------------------------------------- /public/stylesheets/app.css: -------------------------------------------------------------------------------- 1 | /* Artfully masterminded by ZURB */ 2 | 3 | /* -------------------------------------------------- 4 | Table of Contents 5 | ----------------------------------------------------- 6 | :: Shared Styles 7 | :: Page Name 1 8 | :: Page Name 2 9 | */ 10 | 11 | 12 | /* ----------------------------------------- 13 | Shared Styles 14 | ----------------------------------------- */ 15 | 16 | 17 | 18 | /* ----------------------------------------- 19 | Page Name 1 20 | ----------------------------------------- */ 21 | 22 | 23 | 24 | 25 | /* ----------------------------------------- 26 | Page Name 2 27 | ----------------------------------------- */ 28 | 29 | 30 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | builder (3.0.4) 5 | erubis (2.7.0) 6 | haml (4.0.0) 7 | tilt 8 | jwt (0.1.5) 9 | multi_json (>= 1.0) 10 | macaddr (1.6.1) 11 | systemu (~> 2.5.0) 12 | multi_json (1.6.1) 13 | oauth (0.4.7) 14 | rack (1.4.5) 15 | rack-protection (1.3.2) 16 | rack 17 | sinatra (1.3.4) 18 | rack (~> 1.4) 19 | rack-protection (~> 1.3) 20 | tilt (~> 1.3, >= 1.3.3) 21 | systemu (2.5.2) 22 | tilt (1.3.3) 23 | twilio-ruby (3.9.0) 24 | builder (>= 2.1.2) 25 | jwt (>= 0.1.2) 26 | multi_json (>= 1.3.0) 27 | uuid (2.3.7) 28 | macaddr (~> 1.0) 29 | 30 | PLATFORMS 31 | ruby 32 | 33 | DEPENDENCIES 34 | builder 35 | erubis 36 | haml 37 | oauth 38 | sinatra 39 | twilio-ruby 40 | uuid 41 | -------------------------------------------------------------------------------- /views/browser-phone/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Twilio, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /views/dd.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %head 4 | %title Hello Monkey 1 5 | %script(type='text/javascript' src='//static.twilio.com/libs/twiliojs/1.1/twilio.min.js') 6 | %script(type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery1.7.2/jquery.min.js') 7 | %link(href='//static0.twilio.com/packages/quickstart/client.css') 8 | %script(type='text/javascript') 9 | :javascript 10 | /* Create the Client with a Capability Token */ 11 | Twilio.Device.setup("<%= token %>", {debug: true}); 12 | 13 | /* Let us know when the client is ready. */ 14 | Twilio.Device.ready(function (device) { 15 | $("#log").text("Ready"); 16 | }); 17 | 18 | /* Report any errors on the screen */ 19 | Twilio.Device.error(function (error) { 20 | $("#log").text("Error: " + error.message); 21 | }); 22 | 23 | Twilio.Device.connect(function (conn) { 24 | $("#log").text("Successfully established call"); 25 | }); 26 | 27 | /* Connect to Twilio when we call this function. */ 28 | function call() { 29 | Twilio.Device.connect(); 30 | } 31 | 32 | %body 33 | %button(class='call' onclick='call();') Call 34 | .log Loading pigeons 35 | -------------------------------------------------------------------------------- /views/dex.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello Client Monkey 1 5 | 7 | 10 | 12 | 36 | 37 | 38 | 39 | 42 | 43 |
Loading pigeons...
44 | 45 | 46 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.mediaQueryToggle.js: -------------------------------------------------------------------------------- 1 | ;(function ($, window, undefined) { 2 | 'use strict'; 3 | 4 | $.fn.foundationMediaQueryViewer = function (options) { 5 | var settings = $.extend(options,{toggleKey:77}), // Press 'M' 6 | $doc = $(document); 7 | 8 | $doc.on("keyup.mediaQueryViewer", ":input", function (e){ 9 | if (e.which === settings.toggleKey) { 10 | e.stopPropagation(); 11 | } 12 | }); 13 | $doc.on("keyup.mediaQueryViewer", function (e) { 14 | var $mqViewer = $('#fqv'); 15 | 16 | if (e.which === settings.toggleKey) { 17 | if ($mqViewer.length > 0) { 18 | $mqViewer.remove(); 19 | } else { 20 | $('body').prepend('

Media: Extra LargeLargeMediumSmallLandscapePortraitTouch

'); 21 | } 22 | } 23 | }); 24 | 25 | }; 26 | 27 | })(jQuery, this); 28 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.accordion.js: -------------------------------------------------------------------------------- 1 | ;(function ($, window, undefined){ 2 | 'use strict'; 3 | 4 | $.fn.foundationAccordion = function (options) { 5 | 6 | // DRY up the logic used to determine if the event logic should execute. 7 | var hasHover = function(accordion) { 8 | return accordion.hasClass('hover') && !Modernizr.touch 9 | }; 10 | 11 | $(document).on('mouseenter', '.accordion li', function () { 12 | var p = $(this).parent(); 13 | 14 | if (hasHover(p)) { 15 | var flyout = $(this).children('.content').first(); 16 | 17 | $('.content', p).not(flyout).hide().parent('li').removeClass('active'); 18 | flyout.show(0, function () { 19 | flyout.parent('li').addClass('active'); 20 | }); 21 | } 22 | } 23 | ); 24 | 25 | $(document).on('click.fndtn', '.accordion li .title', function () { 26 | var li = $(this).closest('li'), 27 | p = li.parent(); 28 | 29 | if(!hasHover(p)) { 30 | var flyout = li.children('.content').first(); 31 | 32 | if (li.hasClass('active')) { 33 | p.find('li').removeClass('active').end().find('.content').hide(); 34 | } else { 35 | $('.content', p).not(flyout).hide().parent('li').removeClass('active'); 36 | flyout.show(0, function () { 37 | flyout.parent('li').addClass('active'); 38 | }); 39 | } 40 | } 41 | } 42 | ); 43 | 44 | }; 45 | 46 | })( jQuery, this ); 47 | 48 | -------------------------------------------------------------------------------- /prank.rb: -------------------------------------------------------------------------------- 1 | require 'erubis' 2 | require 'sinatra' 3 | require 'haml' 4 | require 'oauth' 5 | require 'twilio-ruby' 6 | require 'uuid' 7 | 8 | $client = Twilio::REST::Client.new twiliosid, twilioauth 9 | $capability = Twilio::Util::Capability.new twiliosid, twilioauth 10 | $capability.allow_client_outgoing appsid 11 | 12 | $token = $capability.generate 13 | 14 | get '/phone' do 15 | haml :calling, :locals => {:token => $token} 16 | end 17 | 18 | get '/' do 19 | haml :index 20 | end 21 | 22 | get '/sms' do 23 | haml :sms 24 | end 25 | 26 | post '/sms' do 27 | number = params['number'] 28 | message = $client.account.sms.messages.create "Jenny please?! I love you <4", params['number'], "4159686840" 29 | end 30 | 31 | post '/call' do 32 | uuid = UUID.generate 33 | haml :calling, :locals => {:number1 => params['number1'], :number2 => params['number2']} 34 | call1 = $client.account.calls.make "+14159686840", params['number1'], "http://twimlets.com/conference?Name=#{uuid}&Message=%20" 35 | call2 = $client.account.calls.make "+14159686840", params['number2'], "http://twimlets.com/conference?Name=#{uuid}&Message=%20" 36 | call3 = $client.account.calls.make "+14159686840", params['number3'], "http://twimlets.com/conference?Name=#{uuid}&Message=%20" 37 | end 38 | 39 | 40 | get '/fad' do 41 | @client.class.to_s 42 | end 43 | 44 | get '/monkey' do 45 | # Find these values at twilio.com/user/account 46 | # This application sid will play a Welcome Message. 47 | demo_app_sid = 'APabe7650f654fc34655fc81ae71caa3ff' 48 | capability = Twilio::Util::Capability.new twiliosid, twilioauth 49 | capability.allow_client_outgoing demo_app_sid 50 | token = capability.generate 51 | erb :dex, :locals => {:token => token} 52 | end 53 | 54 | -------------------------------------------------------------------------------- /views/javascripts/app.js: -------------------------------------------------------------------------------- 1 | ;(function ($, window, undefined) { 2 | 'use strict'; 3 | 4 | var $doc = $(document), 5 | Modernizr = window.Modernizr; 6 | 7 | $(document).ready(function() { 8 | $.fn.foundationAlerts ? $doc.foundationAlerts() : null; 9 | $.fn.foundationButtons ? $doc.foundationButtons() : null; 10 | $.fn.foundationAccordion ? $doc.foundationAccordion() : null; 11 | $.fn.foundationNavigation ? $doc.foundationNavigation() : null; 12 | $.fn.foundationTopBar ? $doc.foundationTopBar() : null; 13 | $.fn.foundationCustomForms ? $doc.foundationCustomForms() : null; 14 | $.fn.foundationMediaQueryViewer ? $doc.foundationMediaQueryViewer() : null; 15 | $.fn.foundationTabs ? $doc.foundationTabs({callback : $.foundation.customForms.appendCustomMarkup}) : null; 16 | $.fn.foundationTooltips ? $doc.foundationTooltips() : null; 17 | $.fn.foundationMagellan ? $doc.foundationMagellan() : null; 18 | $.fn.foundationClearing ? $doc.foundationClearing() : null; 19 | 20 | $.fn.placeholder ? $('input, textarea').placeholder() : null; 21 | }); 22 | 23 | // UNCOMMENT THE LINE YOU WANT BELOW IF YOU WANT IE8 SUPPORT AND ARE USING .block-grids 24 | // $('.block-grid.two-up>li:nth-child(2n+1)').css({clear: 'both'}); 25 | // $('.block-grid.three-up>li:nth-child(3n+1)').css({clear: 'both'}); 26 | // $('.block-grid.four-up>li:nth-child(4n+1)').css({clear: 'both'}); 27 | // $('.block-grid.five-up>li:nth-child(5n+1)').css({clear: 'both'}); 28 | 29 | // Hide address bar on mobile devices (except if #hash present, so we don't mess up deep linking). 30 | if (Modernizr.touch && !window.location.hash) { 31 | $(window).load(function () { 32 | setTimeout(function () { 33 | window.scrollTo(0, 1); 34 | }, 0); 35 | }); 36 | } 37 | 38 | })(jQuery, this); 39 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.navigation.js: -------------------------------------------------------------------------------- 1 | ;(function ($, window, undefined) { 2 | 'use strict'; 3 | 4 | $.fn.foundationNavigation = function (options) { 5 | 6 | var lockNavBar = false; 7 | // Windows Phone, sadly, does not register touch events :( 8 | if (Modernizr.touch || navigator.userAgent.match(/Windows Phone/i)) { 9 | $(document).on('click.fndtn touchstart.fndtn', '.nav-bar a.flyout-toggle', function (e) { 10 | e.preventDefault(); 11 | var flyout = $(this).siblings('.flyout').first(); 12 | if (lockNavBar === false) { 13 | $('.nav-bar .flyout').not(flyout).slideUp(500); 14 | flyout.slideToggle(500, function () { 15 | lockNavBar = false; 16 | }); 17 | } 18 | lockNavBar = true; 19 | }); 20 | $('.nav-bar>li.has-flyout', this).addClass('is-touch'); 21 | } else { 22 | $('.nav-bar>li.has-flyout', this).on('mouseenter mouseleave', function (e) { 23 | if (e.type == 'mouseenter') { 24 | $('.nav-bar').find('.flyout').hide(); 25 | $(this).children('.flyout').show(); 26 | } 27 | 28 | if (e.type == 'mouseleave') { 29 | var flyout = $(this).children('.flyout'), 30 | inputs = flyout.find('input'), 31 | hasFocus = function (inputs) { 32 | var focus; 33 | if (inputs.length > 0) { 34 | inputs.each(function () { 35 | if ($(this).is(":focus")) { 36 | focus = true; 37 | } 38 | }); 39 | return focus; 40 | } 41 | 42 | return false; 43 | }; 44 | 45 | if (!hasFocus(inputs)) { 46 | $(this).children('.flyout').hide(); 47 | } 48 | } 49 | 50 | }); 51 | } 52 | 53 | }; 54 | 55 | })( jQuery, this ); 56 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.tabs.js: -------------------------------------------------------------------------------- 1 | ;(function ($, window, document, undefined) { 2 | 'use strict'; 3 | 4 | var settings = { 5 | callback: $.noop, 6 | deep_linking: true, 7 | init: false 8 | }, 9 | 10 | methods = { 11 | init : function (options) { 12 | settings = $.extend({}, settings, options); 13 | 14 | return this.each(function () { 15 | if (!settings.init) methods.events(); 16 | 17 | if (settings.deep_linking) methods.from_hash(); 18 | }); 19 | }, 20 | 21 | events : function () { 22 | $(document).on('click.fndtn', '.tabs a', function (e) { 23 | methods.set_tab($(this).parent('dd, li'), e); 24 | }); 25 | 26 | settings.init = true; 27 | }, 28 | 29 | set_tab : function ($tab, e) { 30 | var $activeTab = $tab.closest('dl, ul').find('.active'), 31 | target = $tab.children('a').attr("href"), 32 | hasHash = /^#/.test(target), 33 | $content = $(target + 'Tab'); 34 | 35 | if (hasHash && $content.length > 0) { 36 | // Show tab content 37 | if (e && !settings.deep_linking) e.preventDefault(); 38 | $content.closest('.tabs-content').children('li').removeClass('active').hide(); 39 | $content.css('display', 'block').addClass('active'); 40 | } 41 | 42 | // Make active tab 43 | $activeTab.removeClass('active'); 44 | $tab.addClass('active'); 45 | 46 | settings.callback(); 47 | }, 48 | 49 | from_hash : function () { 50 | var hash = window.location.hash, 51 | $tab = $('a[href="' + hash + '"]'); 52 | 53 | $tab.trigger('click.fndtn'); 54 | } 55 | } 56 | 57 | $.fn.foundationTabs = function (method) { 58 | if (methods[method]) { 59 | return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 60 | } else if (typeof method === 'object' || !method) { 61 | return methods.init.apply(this, arguments); 62 | } else { 63 | $.error('Method ' + method + ' does not exist on jQuery.foundationTabs'); 64 | } 65 | }; 66 | }(jQuery, this, this.document)); 67 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.buttons.js: -------------------------------------------------------------------------------- 1 | ;(function ($, window, undefined) { 2 | 'use strict'; 3 | 4 | $.fn.foundationButtons = function (options) { 5 | var $doc = $(document), 6 | config = $.extend({ 7 | dropdownAsToggle:false, 8 | activeClass:'active' 9 | }, options), 10 | 11 | // close all dropdowns except for the dropdown passed 12 | closeDropdowns = function (dropdown) { 13 | // alert(dropdown.html()); 14 | $('.button.dropdown').find('ul').not(dropdown).removeClass('show-dropdown'); 15 | }, 16 | // reset all toggle states except for the button passed 17 | resetToggles = function (button) { 18 | // alert(button.html()); 19 | var buttons = $('.button.dropdown').not(button); 20 | buttons.add($('> span.' + config.activeClass, buttons)).removeClass(config.activeClass); 21 | }; 22 | 23 | // Prevent event propagation on disabled buttons 24 | $doc.on('click.fndtn', '.button.disabled', function (e) { 25 | e.preventDefault(); 26 | }); 27 | 28 | $('.button.dropdown > ul', this).addClass('no-hover'); 29 | 30 | // reset other active states 31 | $doc.on('click.fndtn', '.button.dropdown:not(.split), .button.dropdown.split span', function (e) { 32 | var $el = $(this), 33 | button = $el.closest('.button.dropdown'), 34 | dropdown = $('> ul', button); 35 | 36 | // If the click is registered on an actual link or on button element then do not preventDefault which stops the browser from following the link 37 | if ($.inArray(e.target.nodeName, ['A', 'BUTTON'])){ 38 | e.preventDefault(); 39 | } 40 | 41 | // close other dropdowns 42 | setTimeout(function () { 43 | closeDropdowns(config.dropdownAsToggle ? '' : dropdown); 44 | dropdown.toggleClass('show-dropdown'); 45 | 46 | if (config.dropdownAsToggle) { 47 | resetToggles(button); 48 | $el.toggleClass(config.activeClass); 49 | } 50 | }, 0); 51 | }); 52 | 53 | // close all dropdowns and deactivate all buttons 54 | $doc.on('click.fndtn', 'body, html', function (e) { 55 | if (undefined == e.originalEvent) { return; } 56 | // check original target instead of stopping event propagation to play nice with other events 57 | if (!$(e.originalEvent.target).is('.button.dropdown:not(.split), .button.dropdown.split span')) { 58 | closeDropdowns(); 59 | if (config.dropdownAsToggle) { 60 | resetToggles(); 61 | } 62 | } 63 | }); 64 | 65 | // Positioning the Flyout List 66 | var normalButtonHeight = $('.button.dropdown:not(.large):not(.small):not(.tiny):visible', this).outerHeight() - 1, 67 | largeButtonHeight = $('.button.large.dropdown:visible', this).outerHeight() - 1, 68 | smallButtonHeight = $('.button.small.dropdown:visible', this).outerHeight() - 1, 69 | tinyButtonHeight = $('.button.tiny.dropdown:visible', this).outerHeight() - 1; 70 | 71 | $('.button.dropdown:not(.large):not(.small):not(.tiny) > ul', this).css('top', normalButtonHeight); 72 | $('.button.dropdown.large > ul', this).css('top', largeButtonHeight); 73 | $('.button.dropdown.small > ul', this).css('top', smallButtonHeight); 74 | $('.button.dropdown.tiny > ul', this).css('top', tinyButtonHeight); 75 | 76 | $('.button.dropdown.up:not(.large):not(.small):not(.tiny) > ul', this).css('top', 'auto').css('bottom', normalButtonHeight - 2); 77 | $('.button.dropdown.up.large > ul', this).css('top', 'auto').css('bottom', largeButtonHeight - 2); 78 | $('.button.dropdown.up.small > ul', this).css('top', 'auto').css('bottom', smallButtonHeight - 2); 79 | $('.button.dropdown.up.tiny > ul', this).css('top', 'auto').css('bottom', tinyButtonHeight - 2); 80 | 81 | }; 82 | 83 | })( jQuery, this ); 84 | -------------------------------------------------------------------------------- /views/browser-phone/browser-phone.php: -------------------------------------------------------------------------------- 1 | allowClientOutgoing('APxxxxxxxxxxxxxxx'); 10 | $token->allowClientIncoming("alice"); 11 | // @end snippet 12 | ?> 13 | 14 | 15 | 16 | 17 | 18 | Twilio Client Click to Call 19 | 20 | 21 | 22 | 23 | 90 | 91 | 92 | 93 |
94 | 95 | Number to call: 96 | 97 | 98 |
99 | Offline 100 |
101 | 125 | 126 |
127 | 128 | 129 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.magellan.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Foundation Magellan 0.1.0 3 | * http://foundation.zurb.com 4 | * Copyright 2012, ZURB 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | */ 8 | 9 | /*jslint unparam: true, browser: true, indent: 2 */ 10 | 11 | ;(function ($, window, undefined) { 12 | 'use strict'; 13 | 14 | $.fn.foundationMagellan = function(options) { 15 | var $window = $(window), 16 | $document = $(document), 17 | $fixedMagellan = $('[data-magellan-expedition=fixed]'), 18 | defaults = { 19 | threshold: ($fixedMagellan.length) ? $fixedMagellan.outerHeight(true) : 0, 20 | activeClass: 'active' 21 | }, 22 | options = $.extend({}, defaults, options); 23 | 24 | // Indicate we have arrived at a destination 25 | $document.on('magellan.arrival', '[data-magellan-arrival]', function(e) { 26 | var $destination = $(this), 27 | $expedition = $destination.closest('[data-magellan-expedition]'), 28 | activeClass = $expedition.attr('data-magellan-active-class') || options.activeClass; 29 | $destination 30 | .closest('[data-magellan-expedition]') 31 | .find('[data-magellan-arrival]') 32 | .not(this) 33 | .removeClass(activeClass); 34 | $destination.addClass(activeClass); 35 | }); 36 | 37 | // Set starting point as the current destination 38 | var $expedition = $('[data-magellan-expedition]'); 39 | $expedition.find('[data-magellan-arrival]:first') 40 | .addClass($expedition.attr('data-magellan-active-class') || options.activeClass); 41 | 42 | // Update fixed position 43 | $fixedMagellan.on('magellan.update-position', function(){ 44 | var $el = $(this); 45 | $el.data("magellan-fixed-position",""); 46 | $el.data("magellan-top-offset", ""); 47 | }) 48 | .trigger('magellan.update-position'); 49 | 50 | $window.on('resize.magellan', function() { 51 | $fixedMagellan.trigger('magellan.update-position'); 52 | }); 53 | 54 | $window.on('scroll.magellan', function() { 55 | var windowScrollTop = $window.scrollTop(); 56 | $fixedMagellan.each(function() { 57 | var $expedition = $(this); 58 | if ($expedition.data("magellan-top-offset") === "") { 59 | $expedition.data("magellan-top-offset", $expedition.offset().top); 60 | } 61 | var fixed_position = (windowScrollTop + options.threshold) > $expedition.data("magellan-top-offset"); 62 | if ($expedition.data("magellan-fixed-position") != fixed_position) { 63 | $expedition.data("magellan-fixed-position", fixed_position); 64 | if (fixed_position) { 65 | $expedition.css({position:"fixed", top:0}); 66 | } else { 67 | $expedition.css({position:"", top:""}); 68 | } 69 | } 70 | }); 71 | }); 72 | 73 | // Determine when a destination has been reached, ah0y! 74 | var $lastDestination = $('[data-magellan-destination]:last'); 75 | // Determine if a destination has been set 76 | if ($lastDestination.length > 0) { 77 | $window.on('scroll.magellan', function (e) { 78 | var windowScrollTop = $window.scrollTop(), 79 | scrolltopPlusHeight = windowScrollTop + $window.outerHeight(true), 80 | lastDestinationTop = Math.ceil($lastDestination.offset().top); 81 | $('[data-magellan-destination]').each(function () { 82 | var $destination = $(this), 83 | destination_name = $destination.attr('data-magellan-destination'), 84 | topOffset = $destination.offset().top - windowScrollTop; 85 | if (topOffset <= options.threshold) { 86 | $('[data-magellan-arrival=' + destination_name + ']').trigger('magellan.arrival'); 87 | } 88 | // In large screens we may hit the bottom of the page and dont reach the top of the last magellan-destination, so lets force it 89 | if (scrolltopPlusHeight >= $document.outerHeight(true) && lastDestinationTop > windowScrollTop && lastDestinationTop < scrolltopPlusHeight) { 90 | $('[data-magellan-arrival]:last').trigger('magellan.arrival'); 91 | } 92 | }); 93 | }); 94 | } 95 | }; 96 | }(jQuery, this)); 97 | -------------------------------------------------------------------------------- /views/javascripts/jquery.placeholder.js: -------------------------------------------------------------------------------- 1 | /*! http://mths.be/placeholder v2.0.7 by @mathias */ 2 | ;(function(window, document, $) { 3 | 4 | var isInputSupported = 'placeholder' in document.createElement('input'), 5 | isTextareaSupported = 'placeholder' in document.createElement('textarea'), 6 | prototype = $.fn, 7 | valHooks = $.valHooks, 8 | hooks, 9 | placeholder; 10 | 11 | if (isInputSupported && isTextareaSupported) { 12 | 13 | placeholder = prototype.placeholder = function() { 14 | return this; 15 | }; 16 | 17 | placeholder.input = placeholder.textarea = true; 18 | 19 | } else { 20 | 21 | placeholder = prototype.placeholder = function() { 22 | var $this = this; 23 | $this 24 | .filter((isInputSupported ? 'textarea' : ':input') + '[placeholder]') 25 | .not('.placeholder') 26 | .bind({ 27 | 'focus.placeholder': clearPlaceholder, 28 | 'blur.placeholder': setPlaceholder 29 | }) 30 | .data('placeholder-enabled', true) 31 | .trigger('blur.placeholder'); 32 | return $this; 33 | }; 34 | 35 | placeholder.input = isInputSupported; 36 | placeholder.textarea = isTextareaSupported; 37 | 38 | hooks = { 39 | 'get': function(element) { 40 | var $element = $(element); 41 | return $element.data('placeholder-enabled') && $element.hasClass('placeholder') ? '' : element.value; 42 | }, 43 | 'set': function(element, value) { 44 | var $element = $(element); 45 | if (!$element.data('placeholder-enabled')) { 46 | return element.value = value; 47 | } 48 | if (value == '') { 49 | element.value = value; 50 | // Issue #56: Setting the placeholder causes problems if the element continues to have focus. 51 | if (element != document.activeElement) { 52 | // We can't use `triggerHandler` here because of dummy text/password inputs :( 53 | setPlaceholder.call(element); 54 | } 55 | } else if ($element.hasClass('placeholder')) { 56 | clearPlaceholder.call(element, true, value) || (element.value = value); 57 | } else { 58 | element.value = value; 59 | } 60 | // `set` can not return `undefined`; see http://jsapi.info/jquery/1.7.1/val#L2363 61 | return $element; 62 | } 63 | }; 64 | 65 | isInputSupported || (valHooks.input = hooks); 66 | isTextareaSupported || (valHooks.textarea = hooks); 67 | 68 | $(function() { 69 | // Look for forms 70 | $(document).delegate('form', 'submit.placeholder', function() { 71 | // Clear the placeholder values so they don't get submitted 72 | var $inputs = $('.placeholder', this).each(clearPlaceholder); 73 | setTimeout(function() { 74 | $inputs.each(setPlaceholder); 75 | }, 10); 76 | }); 77 | }); 78 | 79 | // Clear placeholder values upon page reload 80 | $(window).bind('beforeunload.placeholder', function() { 81 | $('.placeholder').each(function() { 82 | this.value = ''; 83 | }); 84 | }); 85 | 86 | } 87 | 88 | function args(elem) { 89 | // Return an object of element attributes 90 | var newAttrs = {}, 91 | rinlinejQuery = /^jQuery\d+$/; 92 | $.each(elem.attributes, function(i, attr) { 93 | if (attr.specified && !rinlinejQuery.test(attr.name)) { 94 | newAttrs[attr.name] = attr.value; 95 | } 96 | }); 97 | return newAttrs; 98 | } 99 | 100 | function clearPlaceholder(event, value) { 101 | var input = this, 102 | $input = $(input); 103 | if (input.value == $input.attr('placeholder') && $input.hasClass('placeholder')) { 104 | if ($input.data('placeholder-password')) { 105 | $input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id')); 106 | // If `clearPlaceholder` was called from `$.valHooks.input.set` 107 | if (event === true) { 108 | return $input[0].value = value; 109 | } 110 | $input.focus(); 111 | } else { 112 | input.value = ''; 113 | $input.removeClass('placeholder'); 114 | input == document.activeElement && input.select(); 115 | } 116 | } 117 | } 118 | 119 | function setPlaceholder() { 120 | var $replacement, 121 | input = this, 122 | $input = $(input), 123 | $origInput = $input, 124 | id = this.id; 125 | if (input.value == '') { 126 | if (input.type == 'password') { 127 | if (!$input.data('placeholder-textinput')) { 128 | try { 129 | $replacement = $input.clone().attr({ 'type': 'text' }); 130 | } catch(e) { 131 | $replacement = $('').attr($.extend(args(this), { 'type': 'text' })); 132 | } 133 | $replacement 134 | .removeAttr('name') 135 | .data({ 136 | 'placeholder-password': true, 137 | 'placeholder-id': id 138 | }) 139 | .bind('focus.placeholder', clearPlaceholder); 140 | $input 141 | .data({ 142 | 'placeholder-textinput': $replacement, 143 | 'placeholder-id': id 144 | }) 145 | .before($replacement); 146 | } 147 | $input = $input.removeAttr('id').hide().prev().attr('id', id).show(); 148 | // Note: `$input[0] != input` now! 149 | } 150 | $input.addClass('placeholder'); 151 | $input[0].value = $input.attr('placeholder'); 152 | } else { 153 | $input.removeClass('placeholder'); 154 | } 155 | } 156 | 157 | }(this, document, jQuery)); 158 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.topbar.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Foundation Top Bar 2.0.4 3 | * http://foundation.zurb.com 4 | * Copyright 2012, ZURB 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | */ 8 | 9 | /*jslint unparam: true, browser: true, indent: 2 */ 10 | 11 | ;(function ($, window, undefined) { 12 | 'use strict'; 13 | 14 | var settings = { 15 | index : 0, 16 | initialized : false 17 | }, 18 | 19 | methods = { 20 | init : function (options) { 21 | return this.each(function () { 22 | settings = $.extend(settings, options); 23 | settings.$w = $(window), 24 | settings.$topbar = $('nav.top-bar'), 25 | settings.$section = settings.$topbar.find('section'), 26 | settings.$titlebar = settings.$topbar.children('ul:first'); 27 | 28 | var breakpoint = $("
").appendTo("body"); 29 | settings.breakPoint = breakpoint.width(); 30 | breakpoint.remove(); 31 | 32 | if (!settings.initialized) { 33 | methods.assemble(); 34 | settings.initialized = true; 35 | } 36 | 37 | if (!settings.height) { 38 | methods.largestUL(); 39 | } 40 | 41 | if (settings.$topbar.parent().hasClass('fixed')) { 42 | $('body').css('padding-top',settings.$topbar.outerHeight()) 43 | } 44 | 45 | $('.top-bar .toggle-topbar').off('click.fndtn').on('click.fndtn', function (e) { 46 | e.preventDefault(); 47 | 48 | if (methods.breakpoint()) { 49 | settings.$topbar.toggleClass('expanded'); 50 | settings.$topbar.css('min-height', ''); 51 | } 52 | 53 | if (!settings.$topbar.hasClass('expanded')) { 54 | settings.$section.css({left: '0%'}); 55 | settings.$section.find('>.name').css({left: '100%'}); 56 | settings.$section.find('li.moved').removeClass('moved'); 57 | settings.index = 0; 58 | } 59 | }); 60 | 61 | // Show the Dropdown Levels on Click 62 | $('.top-bar .has-dropdown>a').off('click.fndtn').on('click.fndtn', function (e) { 63 | if (Modernizr.touch || methods.breakpoint()) 64 | e.preventDefault(); 65 | 66 | if (methods.breakpoint()) { 67 | var $this = $(this), 68 | $selectedLi = $this.closest('li'); 69 | 70 | settings.index += 1; 71 | $selectedLi.addClass('moved'); 72 | settings.$section.css({left: -(100 * settings.index) + '%'}); 73 | settings.$section.find('>.name').css({left: 100 * settings.index + '%'}); 74 | 75 | $this.siblings('ul').height(settings.height + settings.$titlebar.outerHeight(true)); 76 | settings.$topbar.css('min-height', settings.height + settings.$titlebar.outerHeight(true) * 2) 77 | } 78 | }); 79 | 80 | $(window).on('resize.fndtn.topbar',function() { 81 | if (!methods.breakpoint()) { 82 | settings.$topbar.css('min-height', ''); 83 | } 84 | }); 85 | 86 | // Go up a level on Click 87 | $('.top-bar .has-dropdown .back').off('click.fndtn').on('click.fndtn', function (e) { 88 | e.preventDefault(); 89 | 90 | var $this = $(this), 91 | $movedLi = $this.closest('li.moved'), 92 | $previousLevelUl = $movedLi.parent(); 93 | 94 | settings.index -= 1; 95 | settings.$section.css({left: -(100 * settings.index) + '%'}); 96 | settings.$section.find('>.name').css({'left': 100 * settings.index + '%'}); 97 | 98 | if (settings.index === 0) { 99 | settings.$topbar.css('min-height', 0); 100 | } 101 | 102 | setTimeout(function () { 103 | $movedLi.removeClass('moved'); 104 | }, 300); 105 | }); 106 | }); 107 | }, 108 | 109 | breakpoint : function () { 110 | return settings.$w.width() < settings.breakPoint; 111 | }, 112 | 113 | assemble : function () { 114 | // Pull element out of the DOM for manipulation 115 | settings.$section.detach(); 116 | 117 | settings.$section.find('.has-dropdown>a').each(function () { 118 | var $link = $(this), 119 | $dropdown = $link.siblings('.dropdown'), 120 | $titleLi = $('
  • '); 121 | 122 | // Copy link to subnav 123 | $titleLi.find('h5>a').html($link.html()); 124 | $dropdown.prepend($titleLi); 125 | }); 126 | 127 | // Put element back in the DOM 128 | settings.$section.appendTo(settings.$topbar); 129 | }, 130 | 131 | largestUL : function () { 132 | var uls = settings.$topbar.find('section ul ul'), 133 | largest = uls.first(), 134 | total = 0; 135 | 136 | uls.each(function () { 137 | if ($(this).children('li').length > largest.children('li').length) { 138 | largest = $(this); 139 | } 140 | }); 141 | 142 | largest.children('li').each(function () { total += $(this).outerHeight(true); }); 143 | 144 | settings.height = total; 145 | } 146 | }; 147 | 148 | $.fn.foundationTopBar = function (method) { 149 | if (methods[method]) { 150 | return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 151 | } else if (typeof method === 'object' || !method) { 152 | return methods.init.apply(this, arguments); 153 | } else { 154 | $.error('Method ' + method + ' does not exist on jQuery.foundationTopBar'); 155 | } 156 | }; 157 | 158 | // Monitor scroll position for sticky 159 | if ($('.sticky').length > 0) { 160 | var distance = $('.sticky').length ? $('.sticky').offset().top: 0, 161 | $window = $(window); 162 | 163 | $window.scroll(function() { 164 | if ( $window.scrollTop() >= distance ) { 165 | $(".sticky").addClass("fixed"); 166 | } 167 | 168 | else if ( $window.scrollTop() < distance ) { 169 | $(".sticky").removeClass("fixed"); 170 | } 171 | }); 172 | } 173 | 174 | }(jQuery, this)); 175 | -------------------------------------------------------------------------------- /views/javascripts/modernizr.foundation.js: -------------------------------------------------------------------------------- 1 | /* Modernizr 2.6.2 (Custom Build) | MIT & BSD 2 | * Build: http://modernizr.com/download/#-inlinesvg-svg-svgclippaths-touch-shiv-mq-cssclasses-teststyles-prefixes-ie8compat-load 3 | */ 4 | ;window.Modernizr=function(a,b,c){function y(a){j.cssText=a}function z(a,b){return y(m.join(a+";")+(b||""))}function A(a,b){return typeof a===b}function B(a,b){return!!~(""+a).indexOf(b)}function C(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:A(f,"function")?f.bind(d||b):f}return!1}var d="2.6.2",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n={svg:"http://www.w3.org/2000/svg"},o={},p={},q={},r=[],s=r.slice,t,u=function(a,c,d,e){var f,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=["­",'"].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},v=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return u("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},w={}.hasOwnProperty,x;!A(w,"undefined")&&!A(w.call,"undefined")?x=function(a,b){return w.call(a,b)}:x=function(a,b){return b in a&&A(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=s.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(s.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(s.call(arguments)))};return e}),o.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:u(["@media (",m.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},o.svg=function(){return!!b.createElementNS&&!!b.createElementNS(n.svg,"svg").createSVGRect},o.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==n.svg},o.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(l.call(b.createElementNS(n.svg,"clipPath")))};for(var D in o)x(o,D)&&(t=D.toLowerCase(),e[t]=o[D](),r.push((e[t]?"":"no-")+t));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)x(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},y(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=m,e.mq=v,e.testStyles=u,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+r.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f' + content + ''; 21 | } 22 | }, 23 | methods = { 24 | init : function (options) { 25 | settings = $.extend(settings, options); 26 | 27 | // alias the old targetClass option 28 | settings.selector = settings.targetClass ? settings.targetClass : settings.selector; 29 | 30 | return this.each(function () { 31 | var $body = $('body'); 32 | 33 | if (Modernizr.touch) { 34 | $body.on('click.tooltip touchstart.tooltip touchend.tooltip', settings.selector, function (e) { 35 | e.preventDefault(); 36 | $(settings.tooltipClass).hide(); 37 | methods.showOrCreateTip($(this)); 38 | }); 39 | $body.on('click.tooltip touchstart.tooltip touchend.tooltip', settings.tooltipClass, function (e) { 40 | e.preventDefault(); 41 | $(this).fadeOut(150); 42 | }); 43 | } else { 44 | $body.on('mouseenter.tooltip mouseleave.tooltip', settings.selector, function (e) { 45 | var $this = $(this); 46 | 47 | if (e.type === 'mouseenter') { 48 | methods.showOrCreateTip($this); 49 | } else if (e.type === 'mouseleave') { 50 | methods.hide($this); 51 | } 52 | }); 53 | } 54 | 55 | $(this).data('tooltips', true); 56 | 57 | }); 58 | }, 59 | showOrCreateTip : function ($target, content) { 60 | var $tip = methods.getTip($target); 61 | 62 | if ($tip && $tip.length > 0) { 63 | methods.show($target); 64 | } else { 65 | methods.create($target, content); 66 | } 67 | }, 68 | getTip : function ($target) { 69 | var selector = methods.selector($target), 70 | tip = null; 71 | 72 | if (selector) { 73 | tip = $('span[data-selector=' + selector + ']' + settings.tooltipClass); 74 | } 75 | return (tip.length > 0) ? tip : false; 76 | }, 77 | selector : function ($target) { 78 | var id = $target.attr('id'), 79 | dataSelector = $target.data('selector'); 80 | 81 | if (id === undefined && dataSelector === undefined) { 82 | dataSelector = 'tooltip' + Math.random().toString(36).substring(7); 83 | $target.attr('data-selector', dataSelector); 84 | } 85 | return (id) ? id : dataSelector; 86 | }, 87 | create : function ($target, content) { 88 | var $tip = $(settings.tipTemplate(methods.selector($target), 89 | $('
    ').html(content ? content : $target.attr('title')).html())), 90 | classes = methods.inheritable_classes($target); 91 | 92 | $tip.addClass(classes).appendTo('body'); 93 | if (Modernizr.touch) { 94 | $tip.append('tap to close '); 95 | } 96 | $target.removeAttr('title'); 97 | methods.show($target); 98 | }, 99 | reposition : function (target, tip, classes) { 100 | var width, nub, nubHeight, nubWidth, column, objPos; 101 | 102 | tip.css('visibility', 'hidden').show(); 103 | 104 | width = target.data('width'); 105 | nub = tip.children('.nub'); 106 | nubHeight = nub.outerHeight(); 107 | nubWidth = nub.outerWidth(); 108 | 109 | objPos = function (obj, top, right, bottom, left, width) { 110 | return obj.css({ 111 | 'top' : top, 112 | 'bottom' : bottom, 113 | 'left' : left, 114 | 'right' : right, 115 | 'max-width' : (width) ? width : 'auto' 116 | }).end(); 117 | }; 118 | 119 | objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', target.offset().left, width); 120 | objPos(nub, -nubHeight, 'auto', 'auto', 10); 121 | 122 | if ($(window).width() < 767) { 123 | if (target.data('mobile-width')) { 124 | tip.width(target.data('mobile-width')).css('left', 15).addClass('tip-override'); 125 | } else { 126 | column = target.closest('.columns'); 127 | if (column.length < 0) { 128 | // if not using Foundation 129 | column = $('body'); 130 | } 131 | if (column.outerWidth()) { 132 | tip.width(column.outerWidth() - 25).css('left', 15).addClass('tip-override'); 133 | } else { 134 | var tmp_width = Math.ceil($(window).width() * 0.9); 135 | tip.width(tmp_width).css('left', 15).addClass('tip-override'); 136 | } 137 | } 138 | objPos(nub, -nubHeight, 'auto', 'auto', target.offset().left); 139 | } else { 140 | if (classes && classes.indexOf('tip-top') > -1) { 141 | objPos(tip, (target.offset().top - tip.outerHeight() - nubHeight), 'auto', 'auto', target.offset().left, width) 142 | .removeClass('tip-override'); 143 | objPos(nub, 'auto', 'auto', -nubHeight, 'auto'); 144 | } else if (classes && classes.indexOf('tip-left') > -1) { 145 | objPos(tip, (target.offset().top + (target.outerHeight() / 2) - nubHeight), 'auto', 'auto', (target.offset().left - tip.outerWidth() - 10), width) 146 | .removeClass('tip-override'); 147 | objPos(nub, (tip.outerHeight() / 2) - (nubHeight / 2), -nubHeight, 'auto', 'auto'); 148 | } else if (classes && classes.indexOf('tip-right') > -1) { 149 | objPos(tip, (target.offset().top + (target.outerHeight() / 2) - nubHeight), 'auto', 'auto', (target.offset().left + target.outerWidth() + 10), width) 150 | .removeClass('tip-override'); 151 | objPos(nub, (tip.outerHeight() / 2) - (nubHeight / 2), 'auto', 'auto', -nubHeight); 152 | } else if (classes && classes.indexOf('tip-centered-top') > -1) { 153 | objPos(tip, (target.offset().top - tip.outerHeight() - nubHeight), 'auto', 'auto', (target.offset().left + ((target.outerWidth() - tip.outerWidth()) / 2) ), width) 154 | .removeClass('tip-override'); 155 | objPos(nub, 'auto', ((tip.outerWidth() / 2) -(nubHeight / 2)), -nubHeight, 'auto'); 156 | } else if (classes && classes.indexOf('tip-centered-bottom') > -1) { 157 | objPos(tip, (target.offset().top + target.outerHeight() + 10), 'auto', 'auto', (target.offset().left + ((target.outerWidth() - tip.outerWidth()) / 2) ), width) 158 | .removeClass('tip-override'); 159 | objPos(nub, -nubHeight, ((tip.outerWidth() / 2) -(nubHeight / 2)), 'auto', 'auto'); 160 | } 161 | } 162 | tip.css('visibility', 'visible').hide(); 163 | }, 164 | inheritable_classes : function (target) { 165 | var inheritables = ['tip-top', 'tip-left', 'tip-bottom', 'tip-right', 'tip-centered-top', 'tip-centered-bottom', 'noradius'].concat(settings.additionalInheritableClasses), 166 | classes = target.attr('class'), 167 | filtered = classes ? $.map(classes.split(' '), function (el, i) { 168 | if ($.inArray(el, inheritables) !== -1) { 169 | return el; 170 | } 171 | }).join(' ') : ''; 172 | 173 | return $.trim(filtered); 174 | }, 175 | show : function ($target) { 176 | var $tip = methods.getTip($target); 177 | 178 | methods.reposition($target, $tip, $target.attr('class')); 179 | $tip.fadeIn(150); 180 | }, 181 | hide : function ($target) { 182 | var $tip = methods.getTip($target); 183 | 184 | $tip.fadeOut(150); 185 | }, 186 | reload : function () { 187 | var $self = $(this); 188 | 189 | return ($self.data('tooltips')) ? $self.foundationTooltips('destroy').foundationTooltips('init') : $self.foundationTooltips('init'); 190 | }, 191 | destroy : function () { 192 | return this.each(function () { 193 | $(window).off('.tooltip'); 194 | $(settings.selector).off('.tooltip'); 195 | $(settings.tooltipClass).each(function (i) { 196 | $($(settings.selector).get(i)).attr('title', $(this).text()); 197 | }).remove(); 198 | }); 199 | } 200 | }; 201 | 202 | $.fn.foundationTooltips = function (method) { 203 | if (methods[method]) { 204 | return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 205 | } else if (typeof method === 'object' || !method) { 206 | return methods.init.apply(this, arguments); 207 | } else { 208 | $.error('Method ' + method + ' does not exist on jQuery.foundationTooltips'); 209 | } 210 | }; 211 | }(jQuery, this)); 212 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.clearing.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Foundation Clearing 1.2.1 3 | * http://foundation.zurb.com 4 | * Copyright 2012, ZURB 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | */ 8 | 9 | /*jslint unparam: true, browser: true, indent: 2 */ 10 | 11 | ;(function ($, window, document, undefined) { 12 | 'use strict'; 13 | 14 | var defaults = { 15 | templates : { 16 | viewing : '×' + 17 | '' 20 | }, 21 | 22 | // comma delimited list of selectors that, on click, will close clearing, 23 | // add 'div.clearing-blackout, div.visible-img' to close on background click 24 | close_selectors : 'a.clearing-close', 25 | 26 | // event initializers and locks 27 | initialized : false, 28 | locked : false 29 | }, 30 | 31 | cl = { 32 | init : function (options, extendMethods) { 33 | return this.find('ul[data-clearing]').each(function () { 34 | var doc = $(document), 35 | $el = $(this), 36 | options = options || {}, 37 | extendMethods = extendMethods || {}, 38 | settings = $el.data('fndtn.clearing.settings'); 39 | 40 | if (!settings) { 41 | options.$parent = $el.parent(); 42 | 43 | $el.data('fndtn.clearing.settings', $.extend({}, defaults, options)); 44 | 45 | cl.assemble($el.find('li')); 46 | 47 | if (!defaults.initialized) { 48 | cl.events($el); 49 | if (Modernizr.touch) cl.swipe_events(); 50 | } 51 | 52 | } 53 | }); 54 | }, 55 | 56 | events : function (el) { 57 | var settings = el.data('fndtn.clearing.settings'); 58 | 59 | $(document) 60 | .on('click.fndtn.clearing', 'ul[data-clearing] li', function (e, current, target) { 61 | var current = current || $(this), 62 | target = target || current, 63 | settings = current.parent().data('fndtn.clearing.settings'); 64 | 65 | e.preventDefault(); 66 | 67 | if (!settings) { 68 | current.parent().foundationClearing(); 69 | } 70 | 71 | // set current and target to the clicked li if not otherwise defined. 72 | cl.open($(e.target), current, target); 73 | cl.update_paddles(target); 74 | }) 75 | 76 | .on('click.fndtn.clearing', '.clearing-main-right', function (e) { cl.nav(e, 'next') }) 77 | .on('click.fndtn.clearing', '.clearing-main-left', function (e) { cl.nav(e, 'prev') }) 78 | .on('click.fndtn.clearing', settings.close_selectors, this.close) 79 | .on('keydown.fndtn.clearing', this.keydown); 80 | 81 | $(window).on('resize.fndtn.clearing', this.resize); 82 | 83 | defaults.initialized = true; 84 | }, 85 | 86 | swipe_events : function () { 87 | $(document) 88 | .bind('swipeleft', 'ul[data-clearing]', function (e) { cl.nav(e, 'next') }) 89 | .bind('swiperight', 'ul[data-clearing]', function (e) { cl.nav(e, 'prev') }) 90 | .bind('movestart', 'ul[data-clearing]', function (e) { 91 | if ((e.distX > e.distY && e.distX < -e.distY) || 92 | (e.distX < e.distY && e.distX > -e.distY)) { 93 | e.preventDefault(); 94 | } 95 | }); 96 | }, 97 | 98 | assemble : function ($li) { 99 | var $el = $li.parent(), 100 | settings = $el.data('fndtn.clearing.settings'), 101 | grid = $el.detach(), 102 | data = { 103 | grid: '', 104 | viewing: settings.templates.viewing 105 | }, 106 | wrapper = '
    ' + data.viewing + data.grid + '
    '; 107 | 108 | return settings.$parent.append(wrapper); 109 | }, 110 | 111 | open : function ($image, current, target) { 112 | var root = target.closest('.clearing-assembled'), 113 | container = root.find('div:first'), 114 | visible_image = container.find('.visible-img'), 115 | image = visible_image.find('img').not($image); 116 | 117 | if (!cl.locked()) { 118 | 119 | // set the image to the selected thumbnail 120 | image.attr('src', this.load($image)); 121 | 122 | image.loaded(function () { 123 | // toggle the gallery if not visible 124 | root.addClass('clearing-blackout'); 125 | container.addClass('clearing-container'); 126 | this.caption(visible_image.find('.clearing-caption'), $image); 127 | visible_image.show(); 128 | this.fix_height(target); 129 | this.center(image); 130 | 131 | // shift the thumbnails if necessary 132 | this.shift(current, target, function () { 133 | target.siblings().removeClass('visible'); 134 | target.addClass('visible'); 135 | }); 136 | }.bind(this)); 137 | } 138 | }, 139 | 140 | close : function (e) { 141 | e.preventDefault(); 142 | 143 | var root = (function (target) { 144 | if (/blackout/.test(target.selector)) { 145 | return target; 146 | } else { 147 | return target.closest('.clearing-blackout'); 148 | } 149 | }($(this))), container, visible_image; 150 | 151 | if (this === e.target && root) { 152 | container = root.find('div:first'), 153 | visible_image = container.find('.visible-img'); 154 | 155 | defaults.prev_index = 0; 156 | 157 | root.find('ul[data-clearing]').attr('style', '') 158 | root.removeClass('clearing-blackout'); 159 | container.removeClass('clearing-container'); 160 | visible_image.hide(); 161 | } 162 | 163 | return false; 164 | }, 165 | 166 | keydown : function (e) { 167 | var clearing = $('.clearing-blackout').find('ul[data-clearing]'); 168 | 169 | if (e.which === 39) cl.go(clearing, 'next'); 170 | if (e.which === 37) cl.go(clearing, 'prev'); 171 | if (e.which === 27) $('a.clearing-close').trigger('click'); 172 | }, 173 | 174 | nav : function (e, direction) { 175 | var clearing = $('.clearing-blackout').find('ul[data-clearing]'); 176 | 177 | e.preventDefault(); 178 | this.go(clearing, direction); 179 | }, 180 | 181 | resize : function () { 182 | var image = $('.clearing-blackout .visible-img').find('img'); 183 | 184 | if (image.length > 0) { 185 | cl.center(image); 186 | } 187 | }, 188 | 189 | fix_height : function (target) { 190 | var lis = target.siblings(); 191 | 192 | lis.each(function () { 193 | var li = $(this), 194 | image = li.find('img'); 195 | 196 | if (li.height() > image.outerHeight()) { 197 | li.addClass('fix-height'); 198 | } 199 | }) 200 | .closest('ul').width(lis.length * 100 + '%'); 201 | }, 202 | 203 | update_paddles : function (target) { 204 | var visible_image = target.closest('.carousel').siblings('.visible-img'); 205 | 206 | if (target.next().length > 0) { 207 | visible_image.find('.clearing-main-right').removeClass('disabled'); 208 | } else { 209 | visible_image.find('.clearing-main-right').addClass('disabled'); 210 | } 211 | 212 | if (target.prev().length > 0) { 213 | visible_image.find('.clearing-main-left').removeClass('disabled'); 214 | } else { 215 | visible_image.find('.clearing-main-left').addClass('disabled'); 216 | } 217 | }, 218 | 219 | load : function ($image) { 220 | var href = $image.parent().attr('href'); 221 | 222 | this.preload($image); 223 | 224 | if (href) return href; 225 | return $image.attr('src'); 226 | }, 227 | 228 | preload : function ($image) { 229 | this.img($image.closest('li').next()); 230 | this.img($image.closest('li').prev()); 231 | }, 232 | 233 | img : function (img) { 234 | if (img.length > 0) { 235 | var new_img = new Image(), 236 | new_a = img.find('a'); 237 | 238 | if (new_a.length > 0) { 239 | new_img.src = new_a.attr('href'); 240 | } else { 241 | new_img.src = img.find('img').attr('src'); 242 | } 243 | } 244 | }, 245 | 246 | caption : function (container, $image) { 247 | var caption = $image.data('caption'); 248 | 249 | if (caption) { 250 | container.text(caption).show(); 251 | } else { 252 | container.text('').hide(); 253 | } 254 | }, 255 | 256 | go : function ($ul, direction) { 257 | var current = $ul.find('.visible'), 258 | target = current[direction](); 259 | 260 | if (target.length > 0) { 261 | target.find('img').trigger('click', [current, target]); 262 | } 263 | }, 264 | 265 | shift : function (current, target, callback) { 266 | var clearing = target.parent(), 267 | old_index = defaults.prev_index, 268 | direction = this.direction(clearing, current, target), 269 | left = parseInt(clearing.css('left'), 10), 270 | width = target.outerWidth(), 271 | skip_shift; 272 | 273 | // we use jQuery animate instead of CSS transitions because we 274 | // need a callback to unlock the next animation 275 | if (target.index() !== old_index && !/skip/.test(direction)){ 276 | if (/left/.test(direction)) { 277 | this.lock(); 278 | clearing.animate({left : left + width}, 300, this.unlock); 279 | } else if (/right/.test(direction)) { 280 | this.lock(); 281 | clearing.animate({left : left - width}, 300, this.unlock); 282 | } 283 | } else if (/skip/.test(direction)) { 284 | 285 | // the target image is not adjacent to the current image, so 286 | // do we scroll right or not 287 | skip_shift = target.index() - defaults.up_count; 288 | this.lock(); 289 | 290 | if (skip_shift > 0) { 291 | clearing.animate({left : -(skip_shift * width)}, 300, this.unlock); 292 | } else { 293 | clearing.animate({left : 0}, 300, this.unlock); 294 | } 295 | } 296 | 297 | callback(); 298 | }, 299 | 300 | lock : function () { 301 | defaults.locked = true; 302 | }, 303 | 304 | unlock : function () { 305 | defaults.locked = false; 306 | }, 307 | 308 | locked : function () { 309 | return defaults.locked; 310 | }, 311 | 312 | direction : function ($el, current, target) { 313 | var lis = $el.find('li'), 314 | li_width = lis.outerWidth() + (lis.outerWidth() / 4), 315 | up_count = Math.floor($('.clearing-container').outerWidth() / li_width) - 1, 316 | target_index = lis.index(target), 317 | response; 318 | 319 | defaults.up_count = up_count; 320 | 321 | if (this.adjacent(defaults.prev_index, target_index)) { 322 | if ((target_index > up_count) && target_index > defaults.prev_index) { 323 | response = 'right'; 324 | } else if ((target_index > up_count - 1) && target_index <= defaults.prev_index) { 325 | response = 'left'; 326 | } else { 327 | response = false; 328 | } 329 | } else { 330 | response = 'skip'; 331 | } 332 | 333 | defaults.prev_index = target_index; 334 | 335 | return response; 336 | }, 337 | 338 | adjacent : function (current_index, target_index) { 339 | for (var i = target_index + 1; i >= target_index - 1; i--) { 340 | if (i === current_index) return true; 341 | } 342 | return false; 343 | }, 344 | 345 | center : function (target) { 346 | target.css({ 347 | marginLeft : -(target.outerWidth() / 2), 348 | marginTop : -(target.outerHeight() / 2) 349 | }); 350 | }, 351 | 352 | outerHTML : function (el) { 353 | // support FireFox < 11 354 | return el.outerHTML || new XMLSerializer().serializeToString(el); 355 | } 356 | 357 | }; 358 | 359 | $.fn.foundationClearing = function (method) { 360 | if (cl[method]) { 361 | return cl[method].apply(this, Array.prototype.slice.call(arguments, 1)); 362 | } else if (typeof method === 'object' || !method) { 363 | return cl.init.apply(this, arguments); 364 | } else { 365 | $.error('Method ' + method + ' does not exist on jQuery.foundationClearing'); 366 | } 367 | }; 368 | 369 | // jquery.imageready.js 370 | // @weblinc, @jsantell, (c) 2012 371 | 372 | (function( $ ) { 373 | $.fn.loaded = function ( callback, userSettings ) { 374 | var 375 | options = $.extend( {}, $.fn.loaded.defaults, userSettings ), 376 | $images = this.find( 'img' ).add( this.filter( 'img' ) ), 377 | unloadedImages = $images.length; 378 | 379 | function loaded () { 380 | unloadedImages -= 1; 381 | !unloadedImages && callback(); 382 | } 383 | 384 | function bindLoad () { 385 | this.one( 'load', loaded ); 386 | if ( $.browser.msie ) { 387 | var 388 | src = this.attr( 'src' ), 389 | param = src.match( /\?/ ) ? '&' : '?'; 390 | param += options.cachePrefix + '=' + ( new Date() ).getTime(); 391 | this.attr( 'src', src + param ); 392 | } 393 | } 394 | 395 | return $images.each(function () { 396 | var $this = $( this ); 397 | if ( !$this.attr( 'src' ) ) { 398 | loaded(); 399 | return; 400 | } 401 | this.complete || this.readyState === 4 ? 402 | loaded() : 403 | bindLoad.call( $this ); 404 | }); 405 | }; 406 | 407 | $.fn.loaded.defaults = { 408 | cachePrefix: 'random' 409 | }; 410 | 411 | }(jQuery)); 412 | 413 | }(jQuery, this, this.document)); 414 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.forms.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Custom Forms Plugin 1.0 3 | * www.ZURB.com 4 | * Copyright 2010, ZURB 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | */ 8 | 9 | (function( $ ){ 10 | 11 | /** 12 | * Helper object used to quickly adjust all hidden parent element's, display and visibility properties. 13 | * This is currently used for the custom drop downs. When the dropdowns are contained within a reveal modal 14 | * we cannot accurately determine the list-item elements width property, since the modal's display property is set 15 | * to 'none'. 16 | * 17 | * This object will help us work around that problem. 18 | * 19 | * NOTE: This could also be plugin. 20 | * 21 | * @function hiddenFix 22 | */ 23 | var hiddenFix = function() { 24 | 25 | return { 26 | /** 27 | * Sets all hidden parent elements and self to visibile. 28 | * 29 | * @method adjust 30 | * @param {jQuery Object} $child 31 | */ 32 | 33 | // We'll use this to temporarily store style properties. 34 | tmp : [], 35 | 36 | // We'll use this to set hidden parent elements. 37 | hidden : null, 38 | 39 | adjust : function( $child ) { 40 | // Internal reference. 41 | var _self = this; 42 | 43 | // Set all hidden parent elements, including this element. 44 | _self.hidden = $child.parents().andSelf().filter( ":hidden" ); 45 | 46 | // Loop through all hidden elements. 47 | _self.hidden.each( function() { 48 | 49 | // Cache the element. 50 | var $elem = $( this ); 51 | 52 | // Store the style attribute. 53 | // Undefined if element doesn't have a style attribute. 54 | _self.tmp.push( $elem.attr( 'style' ) ); 55 | 56 | // Set the element's display property to block, 57 | // but ensure it's visibility is hidden. 58 | $elem.css( { 'visibility' : 'hidden', 'display' : 'block' } ); 59 | }); 60 | 61 | }, // end adjust 62 | 63 | /** 64 | * Resets the elements previous state. 65 | * 66 | * @method reset 67 | */ 68 | reset : function() { 69 | // Internal reference. 70 | var _self = this; 71 | // Loop through our hidden element collection. 72 | _self.hidden.each( function( i ) { 73 | // Cache this element. 74 | var $elem = $( this ), 75 | _tmp = _self.tmp[ i ]; // Get the stored 'style' value for this element. 76 | 77 | // If the stored value is undefined. 78 | if( _tmp === undefined ) 79 | // Remove the style attribute. 80 | $elem.removeAttr( 'style' ); 81 | else 82 | // Otherwise, reset the element style attribute. 83 | $elem.attr( 'style', _tmp ); 84 | 85 | }); 86 | // Reset the tmp array. 87 | _self.tmp = []; 88 | // Reset the hidden elements variable. 89 | _self.hidden = null; 90 | 91 | } // end reset 92 | 93 | }; // end return 94 | 95 | }; 96 | 97 | jQuery.foundation = jQuery.foundation || {}; 98 | jQuery.foundation.customForms = jQuery.foundation.customForms || {}; 99 | 100 | $.foundation.customForms.appendCustomMarkup = function ( options ) { 101 | 102 | var defaults = { 103 | disable_class: "no-custom" 104 | }; 105 | 106 | options = $.extend( defaults, options ); 107 | 108 | function appendCustomMarkup(idx, sel) { 109 | var $this = $(sel).hide(), 110 | type = $this.attr('type'), 111 | $span = $this.next('span.custom.' + type); 112 | 113 | if ($span.length === 0) { 114 | $span = $('').insertAfter($this); 115 | } 116 | 117 | $span.toggleClass('checked', $this.is(':checked')); 118 | $span.toggleClass('disabled', $this.is(':disabled')); 119 | } 120 | 121 | function appendCustomSelect(idx, sel) { 122 | var hiddenFixObj = hiddenFix(); 123 | // 124 | // jQueryify the element. 145 | // 146 | $options = $this.find( 'option' ), 147 | // 148 | // Filter down the selected options 149 | // 150 | $selectedOption = $options.filter( ':selected' ), 151 | // 152 | // Initial max width. 153 | // 154 | maxWidth = 0, 155 | // 156 | // We'll use this variable to create the
  • elements for our custom select. 157 | // 158 | liHtml = '', 159 | // 160 | // We'll use this to cache the created
  • elements within our custom select. 161 | // 162 | $listItems 163 | ; 164 | var $currentSelect = false; 165 | // 166 | // Should we not create a custom list? 167 | // 168 | if ( $this.hasClass( options.disable_class ) ) return; 169 | 170 | // 171 | // Did we not create a custom select element yet? 172 | // 173 | if ( $customSelect.length === 0 ) { 174 | // 175 | // Let's create our custom select element! 176 | // 177 | 178 | // 179 | // Determine what select size to use. 180 | // 181 | var customSelectSize = $this.hasClass( 'small' ) ? 'small' : 182 | $this.hasClass( 'medium' ) ? 'medium' : 183 | $this.hasClass( 'large' ) ? 'large' : 184 | $this.hasClass( 'expand' ) ? 'expand' : '' 185 | ; 186 | // 187 | // Build our custom list. 188 | // 189 | $customSelect = $('
      '); 190 | // 191 | // Grab the selector element 192 | // 193 | $selector = $customSelect.find( ".selector" ); 194 | // 195 | // Grab the unordered list element from the custom list. 196 | // 197 | $customList = $customSelect.find( "ul" ); 198 | // 199 | // Build our
    • elements. 200 | // 201 | liHtml = $options.map( function() { return "
    • " + $( this ).html() + "
    • "; } ).get().join( '' ); 202 | // 203 | // Append our
    • elements to the custom list (
        ). 204 | // 205 | $customList.append( liHtml ); 206 | // 207 | // Insert the the currently selected list item before all other elements. 208 | // Then, find the element and assign it to $currentSelect. 209 | // 210 | 211 | $currentSelect = $customSelect.prepend( '' + $selectedOption.html() + '' ).find( ".current" ); 212 | // 213 | // Add the custom select element after the element. 218 | // 219 | .hide(); 220 | 221 | } else { 222 | // 223 | // Create our list item
      • elements. 224 | // 225 | liHtml = $options.map( function() { return "
      • " + $( this ).html() + "
      • "; } ).get().join( '' ); 226 | // 227 | // Refresh the ul with options from the select in case the supplied markup doesn't match. 228 | // Clear what's currently in the
          element. 229 | // 230 | $customList.html( '' ) 231 | // 232 | // Populate the list item
        • elements. 233 | // 234 | .append( liHtml ); 235 | 236 | } // endif $customSelect.length === 0 237 | 238 | // 239 | // Determine whether or not the custom select element should be disabled. 240 | // 241 | $customSelect.toggleClass( 'disabled', $this.is( ':disabled' ) ); 242 | // 243 | // Cache our List item elements. 244 | // 245 | $listItems = $customList.find( 'li' ); 246 | 247 | // 248 | // Determine which elements to select in our custom list. 249 | // 250 | $options.each( function ( index ) { 251 | 252 | if ( this.selected ) { 253 | // 254 | // Add the selected class to the current li element 255 | // 256 | $listItems.eq( index ).addClass( 'selected' ); 257 | // 258 | // Update the current element with the option value. 259 | // 260 | if ($currentSelect) { 261 | $currentSelect.html( $( this ).html() ); 262 | } 263 | 264 | } 265 | 266 | }); 267 | 268 | // 269 | // Update the custom
            list width property. 270 | // 271 | $customList.css( 'width', 'auto' ); 272 | // 273 | // Set the custom select width property. 274 | // 275 | $customSelect.css( 'width', 'auto' ); 276 | 277 | // 278 | // If we're not specifying a predetermined form size. 279 | // 280 | if ( !$customSelect.is( '.small, .medium, .large, .expand' ) ) { 281 | 282 | // ------------------------------------------------------------------------------------ 283 | // This is a work-around for when elements are contained within hidden parents. 284 | // For example, when custom-form elements are inside of a hidden reveal modal. 285 | // 286 | // We need to display the current custom list element as well as hidden parent elements 287 | // in order to properly calculate the list item element's width property. 288 | // ------------------------------------------------------------------------------------- 289 | 290 | // 291 | // Show the drop down. 292 | // This should ensure that the list item's width values are properly calculated. 293 | // 294 | $customSelect.addClass( 'open' ); 295 | // 296 | // Quickly, display all parent elements. 297 | // This should help us calcualate the width of the list item's within the drop down. 298 | // 299 | hiddenFixObj.adjust( $customList ); 300 | // 301 | // Grab the largest list item width. 302 | // 303 | maxWidth = ( $listItems.outerWidth() > maxWidth ) ? $listItems.outerWidth() : maxWidth; 304 | // 305 | // Okay, now reset the parent elements. 306 | // This will hide them again. 307 | // 308 | hiddenFixObj.reset(); 309 | // 310 | // Finally, hide the drop down. 311 | // 312 | $customSelect.removeClass( 'open' ); 313 | // 314 | // Set the custom list width. 315 | // 316 | $customSelect.width( maxWidth + 18); 317 | // 318 | // Set the custom list element (
              ) width. 319 | // 320 | $customList.width( maxWidth + 16 ); 321 | 322 | } // endif 323 | 324 | } 325 | 326 | $('form.custom input:radio[data-customforms!=disabled]').each(appendCustomMarkup); 327 | $('form.custom input:checkbox[data-customforms!=disabled]').each(appendCustomMarkup); 328 | $('form.custom select[data-customforms!=disabled]').each(appendCustomSelect); 329 | }; 330 | 331 | var refreshCustomSelect = function($select) { 332 | var maxWidth = 0, 333 | $customSelect = $select.next(); 334 | $options = $select.find('option'); 335 | $customSelect.find('ul').html(''); 336 | 337 | $options.each(function () { 338 | $li = $('
            • ' + $(this).html() + '
            • '); 339 | $customSelect.find('ul').append($li); 340 | }); 341 | 342 | // re-populate 343 | $options.each(function (index) { 344 | if (this.selected) { 345 | $customSelect.find('li').eq(index).addClass('selected'); 346 | $customSelect.find('.current').html($(this).html()); 347 | } 348 | }); 349 | 350 | // fix width 351 | $customSelect.removeAttr('style') 352 | .find('ul').removeAttr('style'); 353 | $customSelect.find('li').each(function () { 354 | $customSelect.addClass('open'); 355 | if ($(this).outerWidth() > maxWidth) { 356 | maxWidth = $(this).outerWidth(); 357 | } 358 | $customSelect.removeClass('open'); 359 | }); 360 | $customSelect.css('width', maxWidth + 18 + 'px'); 361 | $customSelect.find('ul').css('width', maxWidth + 16 + 'px'); 362 | 363 | }; 364 | 365 | var toggleCheckbox = function($element) { 366 | var $input = $element.prev(), 367 | input = $input[0]; 368 | 369 | if (false === $input.is(':disabled')) { 370 | input.checked = ((input.checked) ? false : true); 371 | $element.toggleClass('checked'); 372 | 373 | $input.trigger('change'); 374 | } 375 | }; 376 | 377 | var toggleRadio = function($element) { 378 | var $input = $element.prev(), 379 | $form = $input.closest('form.custom'), 380 | input = $input[0]; 381 | 382 | if (false === $input.is(':disabled')) { 383 | $form.find('input:radio[name="' + $input.attr('name') + '"]').next().not($element).removeClass('checked'); 384 | if ( !$element.hasClass('checked') ) { 385 | $element.toggleClass('checked'); 386 | } 387 | input.checked = $element.hasClass('checked'); 388 | 389 | $input.trigger('change'); 390 | } 391 | }; 392 | 393 | $(document).on('click', 'form.custom span.custom.checkbox', function (event) { 394 | event.preventDefault(); 395 | event.stopPropagation(); 396 | 397 | toggleCheckbox($(this)); 398 | }); 399 | 400 | $(document).on('click', 'form.custom span.custom.radio', function (event) { 401 | event.preventDefault(); 402 | event.stopPropagation(); 403 | 404 | toggleRadio($(this)); 405 | }); 406 | 407 | $(document).on('change', 'form.custom select[data-customforms!=disabled]', function (event) { 408 | refreshCustomSelect($(this)); 409 | }); 410 | 411 | $(document).on('click', 'form.custom label', function (event) { 412 | var $associatedElement = $('#' + $(this).attr('for') + '[data-customforms!=disabled]'), 413 | $customCheckbox, 414 | $customRadio; 415 | if ($associatedElement.length !== 0) { 416 | if ($associatedElement.attr('type') === 'checkbox') { 417 | event.preventDefault(); 418 | $customCheckbox = $(this).find('span.custom.checkbox'); 419 | //the checkbox might be outside after the label 420 | if ($customCheckbox.length == 0) { 421 | $customCheckbox = $(this).next('span.custom.checkbox'); 422 | } 423 | //the checkbox might be outside before the label 424 | if ($customCheckbox.length == 0) { 425 | $customCheckbox = $(this).prev('span.custom.checkbox'); 426 | } 427 | toggleCheckbox($customCheckbox); 428 | } else if ($associatedElement.attr('type') === 'radio') { 429 | event.preventDefault(); 430 | $customRadio = $(this).find('span.custom.radio'); 431 | //the radio might be outside after the label 432 | if ($customRadio.length == 0) { 433 | $customRadio = $(this).next('span.custom.radio'); 434 | } 435 | //the radio might be outside before the label 436 | if ($customRadio.length == 0) { 437 | $customRadio = $(this).prev('span.custom.radio'); 438 | } 439 | toggleRadio($customRadio); 440 | } 441 | } 442 | }); 443 | 444 | $(document).on('click', 'form.custom div.custom.dropdown a.current, form.custom div.custom.dropdown a.selector', function (event) { 445 | var $this = $(this), 446 | $dropdown = $this.closest('div.custom.dropdown'), 447 | $select = $dropdown.prev(); 448 | 449 | event.preventDefault(); 450 | $('div.dropdown').removeClass('open'); 451 | 452 | if (false === $select.is(':disabled')) { 453 | $dropdown.toggleClass('open'); 454 | 455 | if ($dropdown.hasClass('open')) { 456 | $(document).bind('click.customdropdown', function (event) { 457 | $dropdown.removeClass('open'); 458 | $(document).unbind('.customdropdown'); 459 | }); 460 | } else { 461 | $(document).unbind('.customdropdown'); 462 | } 463 | return false; 464 | } 465 | }); 466 | 467 | $(document).on('click', 'form.custom div.custom.dropdown li', function (event) { 468 | var $this = $(this), 469 | $customDropdown = $this.closest('div.custom.dropdown'), 470 | $select = $customDropdown.prev(), 471 | selectedIndex = 0; 472 | 473 | event.preventDefault(); 474 | event.stopPropagation(); 475 | $('div.dropdown').removeClass('open'); 476 | 477 | $this 478 | .closest('ul') 479 | .find('li') 480 | .removeClass('selected'); 481 | $this.addClass('selected'); 482 | 483 | $customDropdown 484 | .removeClass('open') 485 | .find('a.current') 486 | .html($this.html()); 487 | 488 | $this.closest('ul').find('li').each(function (index) { 489 | if ($this[0] == this) { 490 | selectedIndex = index; 491 | } 492 | 493 | }); 494 | $select[0].selectedIndex = selectedIndex; 495 | 496 | $select.trigger('change'); 497 | }); 498 | 499 | 500 | $.fn.foundationCustomForms = $.foundation.customForms.appendCustomMarkup; 501 | 502 | })( jQuery ); 503 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.joyride.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Foundation Joyride Plugin 2.0.3 3 | * http://foundation.zurb.com 4 | * Copyright 2012, ZURB 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | */ 8 | 9 | /*jslint unparam: true, browser: true, indent: 2 */ 10 | 11 | ;(function ($, window, undefined) { 12 | 'use strict'; 13 | 14 | var defaults = { 15 | 'version' : '2.0.3', 16 | 'tipLocation' : 'bottom', // 'top' or 'bottom' in relation to parent 17 | 'nubPosition' : 'auto', // override on a per tooltip bases 18 | 'scrollSpeed' : 300, // Page scrolling speed in milliseconds 19 | 'timer' : 0, // 0 = no timer , all other numbers = timer in milliseconds 20 | 'startTimerOnClick' : true, // true or false - true requires clicking the first button start the timer 21 | 'startOffset' : 0, // the index of the tooltip you want to start on (index of the li) 22 | 'nextButton' : true, // true or false to control whether a next button is used 23 | 'tipAnimation' : 'fade', // 'pop' or 'fade' in each tip 24 | 'pauseAfter' : [], // array of indexes where to pause the tour after 25 | 'tipAnimationFadeSpeed': 300, // when tipAnimation = 'fade' this is speed in milliseconds for the transition 26 | 'cookieMonster' : false, // true or false to control whether cookies are used 27 | 'cookieName' : 'joyride', // Name the cookie you'll use 28 | 'cookieDomain' : false, // Will this cookie be attached to a domain, ie. '.notableapp.com' 29 | 'tipContainer' : 'body', // Where will the tip be attached 30 | 'postRideCallback' : $.noop, // A method to call once the tour closes (canceled or complete) 31 | 'postStepCallback' : $.noop, // A method to call after each step 32 | 'template' : { // HTML segments for tip layout 33 | 'link' : 'X', 34 | 'timer' : '
              ', 35 | 'tip' : '
              ', 36 | 'wrapper' : '
              ', 37 | 'button' : '' 38 | } 39 | }, 40 | 41 | Modernizr = Modernizr || false, 42 | 43 | settings = {}, 44 | 45 | methods = { 46 | 47 | init : function (opts) { 48 | return this.each(function () { 49 | 50 | if ($.isEmptyObject(settings)) { 51 | settings = $.extend(true, defaults, opts); 52 | 53 | // non configurable settings 54 | settings.document = window.document; 55 | settings.$document = $(settings.document); 56 | settings.$window = $(window); 57 | settings.$content_el = $(this); 58 | settings.body_offset = $(settings.tipContainer).position(); 59 | settings.$tip_content = $('> li', settings.$content_el); 60 | settings.paused = false; 61 | settings.attempts = 0; 62 | 63 | settings.tipLocationPatterns = { 64 | top: ['bottom'], 65 | bottom: [], // bottom should not need to be repositioned 66 | left: ['right', 'top', 'bottom'], 67 | right: ['left', 'top', 'bottom'] 68 | }; 69 | 70 | // are we using jQuery 1.7+ 71 | methods.jquery_check(); 72 | 73 | // can we create cookies? 74 | if (!$.isFunction($.cookie)) { 75 | settings.cookieMonster = false; 76 | } 77 | 78 | // generate the tips and insert into dom. 79 | if (!settings.cookieMonster || !$.cookie(settings.cookieName)) { 80 | 81 | settings.$tip_content.each(function (index) { 82 | methods.create({$li : $(this), index : index}); 83 | }); 84 | 85 | // show first tip 86 | if (!settings.startTimerOnClick && settings.timer > 0) { 87 | methods.show('init'); 88 | methods.startTimer(); 89 | } else { 90 | methods.show('init'); 91 | } 92 | 93 | } 94 | 95 | settings.$document.on('click.joyride', '.joyride-next-tip, .joyride-modal-bg', function (e) { 96 | e.preventDefault(); 97 | 98 | if (settings.$li.next().length < 1) { 99 | methods.end(); 100 | } else if (settings.timer > 0) { 101 | clearTimeout(settings.automate); 102 | methods.hide(); 103 | methods.show(); 104 | methods.startTimer(); 105 | } else { 106 | methods.hide(); 107 | methods.show(); 108 | } 109 | 110 | }); 111 | 112 | settings.$document.on('click.joyride', '.joyride-close-tip', function (e) { 113 | e.preventDefault(); 114 | methods.end(); 115 | }); 116 | 117 | settings.$window.bind('resize.joyride', function (e) { 118 | if (methods.is_phone()) { 119 | methods.pos_phone(); 120 | } else { 121 | methods.pos_default(); 122 | } 123 | }); 124 | } else { 125 | methods.restart(); 126 | } 127 | 128 | }); 129 | }, 130 | 131 | // call this method when you want to resume the tour 132 | resume : function () { 133 | methods.set_li(); 134 | methods.show(); 135 | }, 136 | 137 | tip_template : function (opts) { 138 | var $blank, content; 139 | 140 | opts.tip_class = opts.tip_class || ''; 141 | 142 | $blank = $(settings.template.tip).addClass(opts.tip_class); 143 | content = $.trim($(opts.li).html()) + 144 | methods.button_text(opts.button_text) + 145 | settings.template.link + 146 | methods.timer_instance(opts.index); 147 | 148 | $blank.append($(settings.template.wrapper)); 149 | $blank.first().attr('data-index', opts.index); 150 | $('.joyride-content-wrapper', $blank).append(content); 151 | 152 | return $blank[0]; 153 | }, 154 | 155 | timer_instance : function (index) { 156 | var txt; 157 | 158 | if ((index === 0 && settings.startTimerOnClick && settings.timer > 0) || settings.timer === 0) { 159 | txt = ''; 160 | } else { 161 | txt = methods.outerHTML($(settings.template.timer)[0]); 162 | } 163 | return txt; 164 | }, 165 | 166 | button_text : function (txt) { 167 | if (settings.nextButton) { 168 | txt = $.trim(txt) || 'Next'; 169 | txt = methods.outerHTML($(settings.template.button).append(txt)[0]); 170 | } else { 171 | txt = ''; 172 | } 173 | return txt; 174 | }, 175 | 176 | create : function (opts) { 177 | // backwards compatibility with data-text attribute 178 | var buttonText = opts.$li.attr('data-button') || opts.$li.attr('data-text'), 179 | tipClass = opts.$li.attr('class'), 180 | $tip_content = $(methods.tip_template({ 181 | tip_class : tipClass, 182 | index : opts.index, 183 | button_text : buttonText, 184 | li : opts.$li 185 | })); 186 | 187 | $(settings.tipContainer).append($tip_content); 188 | }, 189 | 190 | show : function (init) { 191 | var opts = {}, ii, opts_arr = [], opts_len = 0, p, 192 | $timer = null; 193 | 194 | // are we paused? 195 | if (settings.$li === undefined || ($.inArray(settings.$li.index(), settings.pauseAfter) === -1)) { 196 | 197 | // don't go to the next li if the tour was paused 198 | if (settings.paused) { 199 | settings.paused = false; 200 | } else { 201 | methods.set_li(init); 202 | } 203 | 204 | settings.attempts = 0; 205 | 206 | if (settings.$li.length && settings.$target.length > 0) { 207 | opts_arr = (settings.$li.data('options') || ':').split(';'); 208 | opts_len = opts_arr.length; 209 | 210 | // parse options 211 | for (ii = opts_len - 1; ii >= 0; ii--) { 212 | p = opts_arr[ii].split(':'); 213 | 214 | if (p.length === 2) { 215 | opts[$.trim(p[0])] = $.trim(p[1]); 216 | } 217 | } 218 | 219 | settings.tipSettings = $.extend({}, settings, opts); 220 | 221 | settings.tipSettings.tipLocationPattern = settings.tipLocationPatterns[settings.tipSettings.tipLocation]; 222 | 223 | // scroll if not modal 224 | if (!/body/i.test(settings.$target.selector)) { 225 | methods.scroll_to(); 226 | } 227 | 228 | if (methods.is_phone()) { 229 | methods.pos_phone(true); 230 | } else { 231 | methods.pos_default(true); 232 | } 233 | 234 | $timer = $('.joyride-timer-indicator', settings.$next_tip); 235 | 236 | if (/pop/i.test(settings.tipAnimation)) { 237 | 238 | $timer.outerWidth(0); 239 | 240 | if (settings.timer > 0) { 241 | 242 | settings.$next_tip.show(); 243 | $timer.animate({ 244 | width: $('.joyride-timer-indicator-wrap', settings.$next_tip).outerWidth() 245 | }, settings.timer); 246 | 247 | } else { 248 | 249 | settings.$next_tip.show(); 250 | 251 | } 252 | 253 | 254 | } else if (/fade/i.test(settings.tipAnimation)) { 255 | 256 | $timer.outerWidth(0); 257 | 258 | if (settings.timer > 0) { 259 | 260 | settings.$next_tip.fadeIn(settings.tipAnimationFadeSpeed); 261 | 262 | settings.$next_tip.show(); 263 | $timer.animate({ 264 | width: $('.joyride-timer-indicator-wrap', settings.$next_tip).outerWidth() 265 | }, settings.timer); 266 | 267 | } else { 268 | 269 | settings.$next_tip.fadeIn(settings.tipAnimationFadeSpeed); 270 | 271 | } 272 | } 273 | 274 | settings.$current_tip = settings.$next_tip; 275 | 276 | // skip non-existent targets 277 | } else if (settings.$li && settings.$target.length < 1) { 278 | 279 | methods.show(); 280 | 281 | } else { 282 | 283 | methods.end(); 284 | 285 | } 286 | } else { 287 | 288 | settings.paused = true; 289 | 290 | } 291 | 292 | }, 293 | 294 | // detect phones with media queries if supported. 295 | is_phone : function () { 296 | if (Modernizr) { 297 | return Modernizr.mq('only screen and (max-width: 767px)'); 298 | } 299 | 300 | return (settings.$window.width() < 767) ? true : false; 301 | }, 302 | 303 | hide : function () { 304 | settings.postStepCallback(settings.$li.index(), settings.$current_tip); 305 | $('.joyride-modal-bg').hide(); 306 | settings.$current_tip.hide(); 307 | }, 308 | 309 | set_li : function (init) { 310 | if (init) { 311 | settings.$li = settings.$tip_content.eq(settings.startOffset); 312 | methods.set_next_tip(); 313 | settings.$current_tip = settings.$next_tip; 314 | } else { 315 | settings.$li = settings.$li.next(); 316 | methods.set_next_tip(); 317 | } 318 | 319 | methods.set_target(); 320 | }, 321 | 322 | set_next_tip : function () { 323 | settings.$next_tip = $('.joyride-tip-guide[data-index=' + settings.$li.index() + ']'); 324 | }, 325 | 326 | set_target : function () { 327 | var cl = settings.$li.attr('data-class'), 328 | id = settings.$li.attr('data-id'), 329 | $sel = function () { 330 | if (id) { 331 | return $(settings.document.getElementById(id)); 332 | } else if (cl) { 333 | return $('.' + cl).first(); 334 | } else { 335 | return $('body'); 336 | } 337 | }; 338 | 339 | settings.$target = $sel(); 340 | }, 341 | 342 | scroll_to : function () { 343 | var window_half, tipOffset; 344 | 345 | window_half = settings.$window.height() / 2; 346 | tipOffset = Math.ceil(settings.$target.offset().top - window_half + settings.$next_tip.outerHeight()); 347 | 348 | $("html, body").stop().animate({ 349 | scrollTop: tipOffset 350 | }, settings.scrollSpeed); 351 | }, 352 | 353 | paused : function () { 354 | if (($.inArray((settings.$li.index() + 1), settings.pauseAfter) === -1)) { 355 | return true; 356 | } 357 | 358 | return false; 359 | }, 360 | 361 | destroy : function () { 362 | settings.$document.off('.joyride'); 363 | $(window).off('.joyride'); 364 | $('.joyride-close-tip, .joyride-next-tip, .joyride-modal-bg').off('.joyride'); 365 | $('.joyride-tip-guide, .joyride-modal-bg').remove(); 366 | clearTimeout(settings.automate); 367 | settings = {}; 368 | }, 369 | 370 | restart : function () { 371 | methods.hide(); 372 | settings.$li = undefined; 373 | methods.show('init'); 374 | }, 375 | 376 | pos_default : function (init) { 377 | var half_fold = Math.ceil(settings.$window.height() / 2), 378 | tip_position = settings.$next_tip.offset(), 379 | $nub = $('.joyride-nub', settings.$next_tip), 380 | nub_height = Math.ceil($nub.outerHeight() / 2), 381 | toggle = init || false; 382 | 383 | // tip must not be "display: none" to calculate position 384 | if (toggle) { 385 | settings.$next_tip.css('visibility', 'hidden'); 386 | settings.$next_tip.show(); 387 | } 388 | 389 | if (!/body/i.test(settings.$target.selector)) { 390 | 391 | if (methods.bottom()) { 392 | settings.$next_tip.css({ 393 | top: (settings.$target.offset().top + nub_height + settings.$target.outerHeight()), 394 | left: settings.$target.offset().left}); 395 | 396 | methods.nub_position($nub, settings.tipSettings.nubPosition, 'top'); 397 | 398 | } else if (methods.top()) { 399 | 400 | settings.$next_tip.css({ 401 | top: (settings.$target.offset().top - settings.$next_tip.outerHeight() - nub_height), 402 | left: settings.$target.offset().left}); 403 | 404 | methods.nub_position($nub, settings.tipSettings.nubPosition, 'bottom'); 405 | 406 | } else if (methods.right()) { 407 | 408 | settings.$next_tip.css({ 409 | top: settings.$target.offset().top, 410 | left: (settings.$target.outerWidth() + settings.$target.offset().left)}); 411 | 412 | methods.nub_position($nub, settings.tipSettings.nubPosition, 'left'); 413 | 414 | } else if (methods.left()) { 415 | 416 | settings.$next_tip.css({ 417 | top: settings.$target.offset().top, 418 | left: (settings.$target.offset().left - settings.$next_tip.outerWidth() - nub_height)}); 419 | 420 | methods.nub_position($nub, settings.tipSettings.nubPosition, 'right'); 421 | 422 | } 423 | 424 | if (!methods.visible(methods.corners(settings.$next_tip)) && settings.attempts < settings.tipSettings.tipLocationPattern.length) { 425 | 426 | $nub.removeClass('bottom') 427 | .removeClass('top') 428 | .removeClass('right') 429 | .removeClass('left'); 430 | 431 | settings.tipSettings.tipLocation = settings.tipSettings.tipLocationPattern[settings.attempts]; 432 | 433 | settings.attempts++; 434 | 435 | methods.pos_default(true); 436 | 437 | } 438 | 439 | } else if (settings.$li.length) { 440 | 441 | methods.pos_modal($nub); 442 | 443 | } 444 | 445 | if (toggle) { 446 | settings.$next_tip.hide(); 447 | settings.$next_tip.css('visibility', 'visible'); 448 | } 449 | 450 | }, 451 | 452 | pos_phone : function (init) { 453 | var tip_height = settings.$next_tip.outerHeight(), 454 | tip_offset = settings.$next_tip.offset(), 455 | target_height = settings.$target.outerHeight(), 456 | $nub = $('.joyride-nub', settings.$next_tip), 457 | nub_height = Math.ceil($nub.outerHeight() / 2), 458 | toggle = init || false; 459 | 460 | $nub.removeClass('bottom') 461 | .removeClass('top') 462 | .removeClass('right') 463 | .removeClass('left'); 464 | 465 | if (toggle) { 466 | settings.$next_tip.css('visibility', 'hidden'); 467 | settings.$next_tip.show(); 468 | } 469 | 470 | if (!/body/i.test(settings.$target.selector)) { 471 | 472 | if (methods.top()) { 473 | 474 | settings.$next_tip.offset({top: settings.$target.offset().top - tip_height - nub_height}); 475 | $nub.addClass('bottom'); 476 | 477 | } else { 478 | 479 | settings.$next_tip.offset({top: settings.$target.offset().top + target_height + nub_height}); 480 | $nub.addClass('top'); 481 | 482 | } 483 | 484 | } else if (settings.$li.length) { 485 | 486 | methods.pos_modal($nub); 487 | 488 | } 489 | 490 | if (toggle) { 491 | settings.$next_tip.hide(); 492 | settings.$next_tip.css('visibility', 'visible'); 493 | } 494 | }, 495 | 496 | pos_modal : function ($nub) { 497 | methods.center(); 498 | $nub.hide(); 499 | 500 | if ($('.joyride-modal-bg').length < 1) { 501 | $('body').append('
              ').show(); 502 | } 503 | 504 | if (/pop/i.test(settings.tipAnimation)) { 505 | $('.joyride-modal-bg').show(); 506 | } else { 507 | $('.joyride-modal-bg').fadeIn(settings.tipAnimationFadeSpeed); 508 | } 509 | }, 510 | 511 | center : function () { 512 | var $w = settings.$window; 513 | 514 | settings.$next_tip.css({ 515 | top : ((($w.height() - settings.$next_tip.outerHeight()) / 2) + $w.scrollTop()), 516 | left : ((($w.width() - settings.$next_tip.outerWidth()) / 2) + $w.scrollLeft()) 517 | }); 518 | 519 | return true; 520 | }, 521 | 522 | bottom : function () { 523 | return /bottom/i.test(settings.tipSettings.tipLocation); 524 | }, 525 | 526 | top : function () { 527 | return /top/i.test(settings.tipSettings.tipLocation); 528 | }, 529 | 530 | right : function () { 531 | return /right/i.test(settings.tipSettings.tipLocation); 532 | }, 533 | 534 | left : function () { 535 | return /left/i.test(settings.tipSettings.tipLocation); 536 | }, 537 | 538 | corners : function (el) { 539 | var w = settings.$window, 540 | right = w.width() + w.scrollLeft(), 541 | bottom = w.width() + w.scrollTop(); 542 | 543 | return [ 544 | el.offset().top <= w.scrollTop(), 545 | right <= el.offset().left + el.outerWidth(), 546 | bottom <= el.offset().top + el.outerHeight(), 547 | w.scrollLeft() >= el.offset().left 548 | ]; 549 | }, 550 | 551 | visible : function (hidden_corners) { 552 | var i = hidden_corners.length; 553 | 554 | while (i--) { 555 | if (hidden_corners[i]) return false; 556 | } 557 | 558 | return true; 559 | }, 560 | 561 | nub_position : function (nub, pos, def) { 562 | if (pos === 'auto') { 563 | nub.addClass(def); 564 | } else { 565 | nub.addClass(pos); 566 | } 567 | }, 568 | 569 | startTimer : function () { 570 | if (settings.$li.length) { 571 | settings.automate = setTimeout(function () { 572 | methods.hide(); 573 | methods.show(); 574 | methods.startTimer(); 575 | }, settings.timer); 576 | } else { 577 | clearTimeout(settings.automate); 578 | } 579 | }, 580 | 581 | end : function () { 582 | if (settings.cookieMonster) { 583 | $.cookie(settings.cookieName, 'ridden', { expires: 365, domain: settings.cookieDomain }); 584 | } 585 | 586 | if (settings.timer > 0) { 587 | clearTimeout(settings.automate); 588 | } 589 | 590 | $('.joyride-modal-bg').hide(); 591 | settings.$current_tip.hide(); 592 | settings.postStepCallback(settings.$li.index(), settings.$current_tip); 593 | settings.postRideCallback(settings.$li.index(), settings.$current_tip); 594 | }, 595 | 596 | jquery_check : function () { 597 | // define on() and off() for older jQuery 598 | if (!$.isFunction($.fn.on)) { 599 | 600 | $.fn.on = function (types, sel, fn) { 601 | 602 | return this.delegate(sel, types, fn); 603 | 604 | }; 605 | 606 | $.fn.off = function (types, sel, fn) { 607 | 608 | return this.undelegate(sel, types, fn); 609 | 610 | }; 611 | 612 | return false; 613 | } 614 | 615 | return true; 616 | }, 617 | 618 | outerHTML : function (el) { 619 | // support FireFox < 11 620 | return el.outerHTML || new XMLSerializer().serializeToString(el); 621 | }, 622 | 623 | version : function () { 624 | return settings.version; 625 | } 626 | 627 | }; 628 | 629 | $.fn.joyride = function (method) { 630 | if (methods[method]) { 631 | return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 632 | } else if (typeof method === 'object' || !method) { 633 | return methods.init.apply(this, arguments); 634 | } else { 635 | $.error('Method ' + method + ' does not exist on jQuery.joyride'); 636 | } 637 | }; 638 | 639 | }(jQuery, this)); 640 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.reveal.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Reveal Plugin 1.1 3 | * www.ZURB.com 4 | * Copyright 2010, ZURB 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | */ 8 | /*globals jQuery */ 9 | 10 | (function ($) { 11 | 'use strict'; 12 | // 13 | // Global variable. 14 | // Helps us determine if the current modal is being queued for display. 15 | // 16 | var modalQueued = false; 17 | 18 | // 19 | // Bind the live 'click' event to all anchor elemnets with the data-reveal-id attribute. 20 | // 21 | $(document).on('click', 'a[data-reveal-id]', function ( event ) { 22 | // 23 | // Prevent default action of the event. 24 | // 25 | event.preventDefault(); 26 | // 27 | // Get the clicked anchor data-reveal-id attribute value. 28 | // 29 | var modalLocation = $( this ).attr( 'data-reveal-id' ); 30 | // 31 | // Find the element with that modalLocation id and call the reveal plugin. 32 | // 33 | $( '#' + modalLocation ).reveal( $( this ).data() ); 34 | 35 | }); 36 | 37 | /** 38 | * @module reveal 39 | * @property {Object} [options] Reveal options 40 | */ 41 | $.fn.reveal = function ( options ) { 42 | /* 43 | * Cache the document object. 44 | */ 45 | var $doc = $( document ), 46 | /* 47 | * Default property values. 48 | */ 49 | defaults = { 50 | /** 51 | * Possible options: fade, fadeAndPop, none 52 | * 53 | * @property animation 54 | * @type {String} 55 | * @default fadeAndPop 56 | */ 57 | animation: 'fadeAndPop', 58 | /** 59 | * Speed at which the reveal should show. How fast animtions are. 60 | * 61 | * @property animationSpeed 62 | * @type {Integer} 63 | * @default 300 64 | */ 65 | animationSpeed: 300, 66 | /** 67 | * Should the modal close when the background is clicked? 68 | * 69 | * @property closeOnBackgroundClick 70 | * @type {Boolean} 71 | * @default true 72 | */ 73 | closeOnBackgroundClick: true, 74 | /** 75 | * Specify a class name for the 'close modal' element. 76 | * This element will close an open modal. 77 | * 78 | @example 79 | Close Me 80 | * 81 | * @property dismissModalClass 82 | * @type {String} 83 | * @default close-reveal-modal 84 | */ 85 | dismissModalClass: 'close-reveal-modal', 86 | /** 87 | * Specify a callback function that triggers 'before' the modal opens. 88 | * 89 | * @property open 90 | * @type {Function} 91 | * @default function(){} 92 | */ 93 | open: $.noop, 94 | /** 95 | * Specify a callback function that triggers 'after' the modal is opened. 96 | * 97 | * @property opened 98 | * @type {Function} 99 | * @default function(){} 100 | */ 101 | opened: $.noop, 102 | /** 103 | * Specify a callback function that triggers 'before' the modal prepares to close. 104 | * 105 | * @property close 106 | * @type {Function} 107 | * @default function(){} 108 | */ 109 | close: $.noop, 110 | /** 111 | * Specify a callback function that triggers 'after' the modal is closed. 112 | * 113 | * @property closed 114 | * @type {Function} 115 | * @default function(){} 116 | */ 117 | closed: $.noop 118 | } 119 | ; 120 | // 121 | // Extend the default options. 122 | // This replaces the passed in option (options) values with default values. 123 | // 124 | options = $.extend( {}, defaults, options ); 125 | 126 | // 127 | // Apply the plugin functionality to each element in the jQuery collection. 128 | // 129 | return this.not('.reveal-modal.open').each( function () { 130 | // 131 | // Cache the modal element 132 | // 133 | var modal = $( this ), 134 | // 135 | // Get the current css 'top' property value in decimal format. 136 | // 137 | topMeasure = parseInt( modal.css( 'top' ), 10 ), 138 | // 139 | // Calculate the top offset. 140 | // 141 | topOffset = modal.height() + topMeasure, 142 | // 143 | // Helps determine if the modal is locked. 144 | // This way we keep the modal from triggering while it's in the middle of animating. 145 | // 146 | locked = false, 147 | // 148 | // Get the modal background element. 149 | // 150 | modalBg = $( '.reveal-modal-bg' ), 151 | // 152 | // Show modal properties 153 | // 154 | cssOpts = { 155 | // 156 | // Used, when we show the modal. 157 | // 158 | open : { 159 | // 160 | // Set the 'top' property to the document scroll minus the calculated top offset. 161 | // 162 | 'top': 0, 163 | // 164 | // Opacity gets set to 0. 165 | // 166 | 'opacity': 0, 167 | // 168 | // Show the modal 169 | // 170 | 'visibility': 'visible', 171 | // 172 | // Ensure it's displayed as a block element. 173 | // 174 | 'display': 'block' 175 | }, 176 | // 177 | // Used, when we hide the modal. 178 | // 179 | close : { 180 | // 181 | // Set the default 'top' property value. 182 | // 183 | 'top': topMeasure, 184 | // 185 | // Has full opacity. 186 | // 187 | 'opacity': 1, 188 | // 189 | // Hide the modal 190 | // 191 | 'visibility': 'hidden', 192 | // 193 | // Ensure the elment is hidden. 194 | // 195 | 'display': 'none' 196 | } 197 | 198 | }, 199 | // 200 | // Initial closeButton variable. 201 | // 202 | $closeButton 203 | ; 204 | 205 | // 206 | // Do we have a modal background element? 207 | // 208 | if ( modalBg.length === 0 ) { 209 | // 210 | // No we don't. So, let's create one. 211 | // 212 | modalBg = $( '
              ', { 'class' : 'reveal-modal-bg' } ) 213 | // 214 | // Then insert it after the modal element. 215 | // 216 | .insertAfter( modal ); 217 | // 218 | // Now, fade it out a bit. 219 | // 220 | modalBg.fadeTo( 'fast', 0.8 ); 221 | } 222 | 223 | // 224 | // Helper Methods 225 | // 226 | 227 | /** 228 | * Unlock the modal for animation. 229 | * 230 | * @method unlockModal 231 | */ 232 | function unlockModal() { 233 | locked = false; 234 | } 235 | 236 | /** 237 | * Lock the modal to prevent further animation. 238 | * 239 | * @method lockModal 240 | */ 241 | function lockModal() { 242 | locked = true; 243 | } 244 | 245 | /** 246 | * Closes all open modals. 247 | * 248 | * @method closeOpenModal 249 | */ 250 | function closeOpenModals() { 251 | // 252 | // Get all reveal-modal elements with the .open class. 253 | // 254 | var $openModals = $( ".reveal-modal.open" ); 255 | // 256 | // Do we have modals to close? 257 | // 258 | if ( $openModals.length === 1 ) { 259 | // 260 | // Set the modals for animation queuing. 261 | // 262 | modalQueued = true; 263 | // 264 | // Trigger the modal close event. 265 | // 266 | $openModals.trigger( "reveal:close" ); 267 | } 268 | 269 | } 270 | /** 271 | * Animates the modal opening. 272 | * Handles the modal 'open' event. 273 | * 274 | * @method openAnimation 275 | */ 276 | function openAnimation() { 277 | // 278 | // First, determine if we're in the middle of animation. 279 | // 280 | if ( !locked ) { 281 | // 282 | // We're not animating, let's lock the modal for animation. 283 | // 284 | lockModal(); 285 | // 286 | // Close any opened modals. 287 | // 288 | closeOpenModals(); 289 | // 290 | // Now, add the open class to this modal. 291 | // 292 | modal.addClass( "open" ); 293 | 294 | // 295 | // Are we executing the 'fadeAndPop' animation? 296 | // 297 | if ( options.animation === "fadeAndPop" ) { 298 | // 299 | // Yes, we're doing the 'fadeAndPop' animation. 300 | // Okay, set the modal css properties. 301 | // 302 | // 303 | // Set the 'top' property to the document scroll minus the calculated top offset. 304 | // 305 | cssOpts.open.top = $doc.scrollTop() - topOffset; 306 | // 307 | // Flip the opacity to 0. 308 | // 309 | cssOpts.open.opacity = 0; 310 | // 311 | // Set the css options. 312 | // 313 | modal.css( cssOpts.open ); 314 | // 315 | // Fade in the background element, at half the speed of the modal element. 316 | // So, faster than the modal element. 317 | // 318 | modalBg.fadeIn( options.animationSpeed / 2 ); 319 | 320 | // 321 | // Let's delay the next animation queue. 322 | // We'll wait until the background element is faded in. 323 | // 324 | modal.delay( options.animationSpeed / 2 ) 325 | // 326 | // Animate the following css properties. 327 | // 328 | .animate( { 329 | // 330 | // Set the 'top' property to the document scroll plus the calculated top measure. 331 | // 332 | "top": $doc.scrollTop() + topMeasure + 'px', 333 | // 334 | // Set it to full opacity. 335 | // 336 | "opacity": 1 337 | 338 | }, 339 | /* 340 | * Fade speed. 341 | */ 342 | options.animationSpeed, 343 | /* 344 | * End of animation callback. 345 | */ 346 | function () { 347 | // 348 | // Trigger the modal reveal:opened event. 349 | // This should trigger the functions set in the options.opened property. 350 | // 351 | modal.trigger( 'reveal:opened' ); 352 | 353 | }); // end of animate. 354 | 355 | } // end if 'fadeAndPop' 356 | 357 | // 358 | // Are executing the 'fade' animation? 359 | // 360 | if ( options.animation === "fade" ) { 361 | // 362 | // Yes, were executing 'fade'. 363 | // Okay, let's set the modal properties. 364 | // 365 | cssOpts.open.top = $doc.scrollTop() + topMeasure; 366 | // 367 | // Flip the opacity to 0. 368 | // 369 | cssOpts.open.opacity = 0; 370 | // 371 | // Set the css options. 372 | // 373 | modal.css( cssOpts.open ); 374 | // 375 | // Fade in the modal background at half the speed of the modal. 376 | // So, faster than modal. 377 | // 378 | modalBg.fadeIn( options.animationSpeed / 2 ); 379 | 380 | // 381 | // Delay the modal animation. 382 | // Wait till the modal background is done animating. 383 | // 384 | modal.delay( options.animationSpeed / 2 ) 385 | // 386 | // Now animate the modal. 387 | // 388 | .animate( { 389 | // 390 | // Set to full opacity. 391 | // 392 | "opacity": 1 393 | }, 394 | 395 | /* 396 | * Animation speed. 397 | */ 398 | options.animationSpeed, 399 | 400 | /* 401 | * End of animation callback. 402 | */ 403 | function () { 404 | // 405 | // Trigger the modal reveal:opened event. 406 | // This should trigger the functions set in the options.opened property. 407 | // 408 | modal.trigger( 'reveal:opened' ); 409 | 410 | }); 411 | 412 | } // end if 'fade' 413 | 414 | // 415 | // Are we not animating? 416 | // 417 | if ( options.animation === "none" ) { 418 | // 419 | // We're not animating. 420 | // Okay, let's set the modal css properties. 421 | // 422 | // 423 | // Set the top property. 424 | // 425 | cssOpts.open.top = $doc.scrollTop() + topMeasure; 426 | // 427 | // Set the opacity property to full opacity, since we're not fading (animating). 428 | // 429 | cssOpts.open.opacity = 1; 430 | // 431 | // Set the css property. 432 | // 433 | modal.css( cssOpts.open ); 434 | // 435 | // Show the modal Background. 436 | // 437 | modalBg.css( { "display": "block" } ); 438 | // 439 | // Trigger the modal opened event. 440 | // 441 | modal.trigger( 'reveal:opened' ); 442 | 443 | } // end if animating 'none' 444 | 445 | }// end if !locked 446 | 447 | }// end openAnimation 448 | 449 | 450 | function openVideos() { 451 | var video = modal.find('.flex-video'), 452 | iframe = video.find('iframe'); 453 | if (iframe.length > 0) { 454 | iframe.attr("src", iframe.data("src")); 455 | video.fadeIn(100); 456 | } 457 | } 458 | 459 | // 460 | // Bind the reveal 'open' event. 461 | // When the event is triggered, openAnimation is called 462 | // along with any function set in the options.open property. 463 | // 464 | modal.bind( 'reveal:open.reveal', openAnimation ); 465 | modal.bind( 'reveal:open.reveal', openVideos); 466 | 467 | /** 468 | * Closes the modal element(s) 469 | * Handles the modal 'close' event. 470 | * 471 | * @method closeAnimation 472 | */ 473 | function closeAnimation() { 474 | // 475 | // First, determine if we're in the middle of animation. 476 | // 477 | if ( !locked ) { 478 | // 479 | // We're not animating, let's lock the modal for animation. 480 | // 481 | lockModal(); 482 | // 483 | // Clear the modal of the open class. 484 | // 485 | modal.removeClass( "open" ); 486 | 487 | // 488 | // Are we using the 'fadeAndPop' animation? 489 | // 490 | if ( options.animation === "fadeAndPop" ) { 491 | // 492 | // Yes, okay, let's set the animation properties. 493 | // 494 | modal.animate( { 495 | // 496 | // Set the top property to the document scrollTop minus calculated topOffset. 497 | // 498 | "top": $doc.scrollTop() - topOffset + 'px', 499 | // 500 | // Fade the modal out, by using the opacity property. 501 | // 502 | "opacity": 0 503 | 504 | }, 505 | /* 506 | * Fade speed. 507 | */ 508 | options.animationSpeed / 2, 509 | /* 510 | * End of animation callback. 511 | */ 512 | function () { 513 | // 514 | // Set the css hidden options. 515 | // 516 | modal.css( cssOpts.close ); 517 | 518 | }); 519 | // 520 | // Is the modal animation queued? 521 | // 522 | if ( !modalQueued ) { 523 | // 524 | // Oh, the modal(s) are mid animating. 525 | // Let's delay the animation queue. 526 | // 527 | modalBg.delay( options.animationSpeed ) 528 | // 529 | // Fade out the modal background. 530 | // 531 | .fadeOut( 532 | /* 533 | * Animation speed. 534 | */ 535 | options.animationSpeed, 536 | /* 537 | * End of animation callback. 538 | */ 539 | function () { 540 | // 541 | // Trigger the modal 'closed' event. 542 | // This should trigger any method set in the options.closed property. 543 | // 544 | modal.trigger( 'reveal:closed' ); 545 | 546 | }); 547 | 548 | } else { 549 | // 550 | // We're not mid queue. 551 | // Trigger the modal 'closed' event. 552 | // This should trigger any method set in the options.closed propety. 553 | // 554 | modal.trigger( 'reveal:closed' ); 555 | 556 | } // end if !modalQueued 557 | 558 | } // end if animation 'fadeAndPop' 559 | 560 | // 561 | // Are we using the 'fade' animation. 562 | // 563 | if ( options.animation === "fade" ) { 564 | // 565 | // Yes, we're using the 'fade' animation. 566 | // 567 | modal.animate( { "opacity" : 0 }, 568 | /* 569 | * Animation speed. 570 | */ 571 | options.animationSpeed, 572 | /* 573 | * End of animation callback. 574 | */ 575 | function () { 576 | // 577 | // Set the css close options. 578 | // 579 | modal.css( cssOpts.close ); 580 | 581 | }); // end animate 582 | 583 | // 584 | // Are we mid animating the modal(s)? 585 | // 586 | if ( !modalQueued ) { 587 | // 588 | // Oh, the modal(s) are mid animating. 589 | // Let's delay the animation queue. 590 | // 591 | modalBg.delay( options.animationSpeed ) 592 | // 593 | // Let's fade out the modal background element. 594 | // 595 | .fadeOut( 596 | /* 597 | * Animation speed. 598 | */ 599 | options.animationSpeed, 600 | /* 601 | * End of animation callback. 602 | */ 603 | function () { 604 | // 605 | // Trigger the modal 'closed' event. 606 | // This should trigger any method set in the options.closed propety. 607 | // 608 | modal.trigger( 'reveal:closed' ); 609 | 610 | }); // end fadeOut 611 | 612 | } else { 613 | // 614 | // We're not mid queue. 615 | // Trigger the modal 'closed' event. 616 | // This should trigger any method set in the options.closed propety. 617 | // 618 | modal.trigger( 'reveal:closed' ); 619 | 620 | } // end if !modalQueued 621 | 622 | } // end if animation 'fade' 623 | 624 | // 625 | // Are we not animating? 626 | // 627 | if ( options.animation === "none" ) { 628 | // 629 | // We're not animating. 630 | // Set the modal close css options. 631 | // 632 | modal.css( cssOpts.close ); 633 | // 634 | // Is the modal in the middle of an animation queue? 635 | // 636 | if ( !modalQueued ) { 637 | // 638 | // It's not mid queueu. Just hide it. 639 | // 640 | modalBg.css( { 'display': 'none' } ); 641 | } 642 | // 643 | // Trigger the modal 'closed' event. 644 | // This should trigger any method set in the options.closed propety. 645 | // 646 | modal.trigger( 'reveal:closed' ); 647 | 648 | } // end if not animating 649 | // 650 | // Reset the modalQueued variable. 651 | // 652 | modalQueued = false; 653 | } // end if !locked 654 | 655 | } // end closeAnimation 656 | 657 | /** 658 | * Destroys the modal and it's events. 659 | * 660 | * @method destroy 661 | */ 662 | function destroy() { 663 | // 664 | // Unbind all .reveal events from the modal. 665 | // 666 | modal.unbind( '.reveal' ); 667 | // 668 | // Unbind all .reveal events from the modal background. 669 | // 670 | modalBg.unbind( '.reveal' ); 671 | // 672 | // Unbind all .reveal events from the modal 'close' button. 673 | // 674 | $closeButton.unbind( '.reveal' ); 675 | // 676 | // Unbind all .reveal events from the body. 677 | // 678 | $( 'body' ).unbind( '.reveal' ); 679 | 680 | } 681 | 682 | function closeVideos() { 683 | var video = modal.find('.flex-video'), 684 | iframe = video.find('iframe'); 685 | if (iframe.length > 0) { 686 | iframe.data("src", iframe.attr("src")); 687 | iframe.attr("src", ""); 688 | video.fadeOut(100); 689 | } 690 | } 691 | 692 | // 693 | // Bind the modal 'close' event 694 | // 695 | modal.bind( 'reveal:close.reveal', closeAnimation ); 696 | modal.bind( 'reveal:closed.reveal', closeVideos ); 697 | // 698 | // Bind the modal 'opened' + 'closed' event 699 | // Calls the unlockModal method. 700 | // 701 | modal.bind( 'reveal:opened.reveal reveal:closed.reveal', unlockModal ); 702 | // 703 | // Bind the modal 'closed' event. 704 | // Calls the destroy method. 705 | // 706 | modal.bind( 'reveal:closed.reveal', destroy ); 707 | // 708 | // Bind the modal 'open' event 709 | // Handled by the options.open property function. 710 | // 711 | modal.bind( 'reveal:open.reveal', options.open ); 712 | // 713 | // Bind the modal 'opened' event. 714 | // Handled by the options.opened property function. 715 | // 716 | modal.bind( 'reveal:opened.reveal', options.opened ); 717 | // 718 | // Bind the modal 'close' event. 719 | // Handled by the options.close property function. 720 | // 721 | modal.bind( 'reveal:close.reveal', options.close ); 722 | // 723 | // Bind the modal 'closed' event. 724 | // Handled by the options.closed property function. 725 | // 726 | modal.bind( 'reveal:closed.reveal', options.closed ); 727 | 728 | // 729 | // We're running this for the first time. 730 | // Trigger the modal 'open' event. 731 | // 732 | modal.trigger( 'reveal:open' ); 733 | 734 | // 735 | // Get the closeButton variable element(s). 736 | // 737 | $closeButton = $( '.' + options.dismissModalClass ) 738 | // 739 | // Bind the element 'click' event and handler. 740 | // 741 | .bind( 'click.reveal', function () { 742 | // 743 | // Trigger the modal 'close' event. 744 | // 745 | modal.trigger( 'reveal:close' ); 746 | 747 | }); 748 | 749 | // 750 | // Should we close the modal background on click? 751 | // 752 | if ( options.closeOnBackgroundClick ) { 753 | // 754 | // Yes, close the modal background on 'click' 755 | // Set the modal background css 'cursor' propety to pointer. 756 | // Adds a pointer symbol when you mouse over the modal background. 757 | // 758 | modalBg.css( { "cursor": "pointer" } ); 759 | // 760 | // Bind a 'click' event handler to the modal background. 761 | // 762 | modalBg.bind( 'click.reveal', function () { 763 | // 764 | // Trigger the modal 'close' event. 765 | // 766 | modal.trigger( 'reveal:close' ); 767 | 768 | }); 769 | 770 | } 771 | 772 | // 773 | // Bind keyup functions on the body element. 774 | // We'll want to close the modal when the 'escape' key is hit. 775 | // 776 | $( 'body' ).bind( 'keyup.reveal', function ( event ) { 777 | // 778 | // Did the escape key get triggered? 779 | // 780 | if ( event.which === 27 ) { // 27 is the keycode for the Escape key 781 | // 782 | // Escape key was triggered. 783 | // Trigger the modal 'close' event. 784 | // 785 | modal.trigger( 'reveal:close' ); 786 | } 787 | 788 | }); // end $(body) 789 | 790 | }); // end this.each 791 | 792 | }; // end $.fn 793 | 794 | } ( jQuery ) ); 795 | -------------------------------------------------------------------------------- /views/javascripts/jquery.foundation.orbit.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Orbit Plugin 1.4.0 3 | * www.ZURB.com/playground 4 | * Copyright 2010, ZURB 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | */ 8 | 9 | 10 | (function ($) { 11 | 'use strict'; 12 | 13 | $.fn.findFirstImage = function () { 14 | return this.first() 15 | .find('img') 16 | .andSelf().filter('img') 17 | .first(); 18 | }; 19 | 20 | var ORBIT = { 21 | 22 | defaults: { 23 | animation: 'horizontal-push', // fade, horizontal-slide, vertical-slide, horizontal-push, vertical-push 24 | animationSpeed: 600, // how fast animations are 25 | timer: true, // display timer? 26 | advanceSpeed: 4000, // if timer is enabled, time between transitions 27 | pauseOnHover: false, // if you hover pauses the slider 28 | startClockOnMouseOut: false, // if clock should start on MouseOut 29 | startClockOnMouseOutAfter: 1000, // how long after MouseOut should the timer start again 30 | directionalNav: true, // manual advancing directional navs 31 | directionalNavRightText: 'Right', // text of right directional element for accessibility 32 | directionalNavLeftText: 'Left', // text of left directional element for accessibility 33 | captions: true, // do you want captions? 34 | captionAnimation: 'fade', // fade, slideOpen, none 35 | captionAnimationSpeed: 600, // if so how quickly should they animate in 36 | resetTimerOnClick: false, // true resets the timer instead of pausing slideshow progress on manual navigation 37 | bullets: false, // true or false to activate the bullet navigation 38 | bulletThumbs: false, // thumbnails for the bullets 39 | bulletThumbLocation: '', // relative path to thumbnails from this file 40 | bulletThumbsHideOnSmall: true, // hide thumbs on small devices 41 | afterSlideChange: $.noop, // callback to execute after slide changes 42 | afterLoadComplete: $.noop, // callback to execute after everything has been loaded 43 | fluid: true, 44 | centerBullets: true, // center bullet nav with js, turn this off if you want to position the bullet nav manually 45 | singleCycle: false, // cycles through orbit slides only once 46 | slideNumber: false, // display slide numbers? 47 | stackOnSmall: false // stack slides on small devices (i.e. phones) 48 | }, 49 | 50 | activeSlide: 0, 51 | numberSlides: 0, 52 | orbitWidth: null, 53 | orbitHeight: null, 54 | locked: null, 55 | timerRunning: null, 56 | degrees: 0, 57 | wrapperHTML: '
              ', 58 | timerHTML: '
              ', 59 | captionHTML: '
              ', 60 | directionalNavHTML: '
              ', 61 | bulletHTML: '
                ', 62 | slideNumberHTML: '', 63 | 64 | init: function (element, options) { 65 | var $imageSlides, 66 | imagesLoadedCount = 0, 67 | self = this; 68 | 69 | // Bind functions to correct context 70 | this.clickTimer = $.proxy(this.clickTimer, this); 71 | this.addBullet = $.proxy(this.addBullet, this); 72 | this.resetAndUnlock = $.proxy(this.resetAndUnlock, this); 73 | this.stopClock = $.proxy(this.stopClock, this); 74 | this.startTimerAfterMouseLeave = $.proxy(this.startTimerAfterMouseLeave, this); 75 | this.clearClockMouseLeaveTimer = $.proxy(this.clearClockMouseLeaveTimer, this); 76 | this.rotateTimer = $.proxy(this.rotateTimer, this); 77 | 78 | this.options = $.extend({}, this.defaults, options); 79 | if (this.options.timer === 'false') this.options.timer = false; 80 | if (this.options.captions === 'false') this.options.captions = false; 81 | if (this.options.directionalNav === 'false') this.options.directionalNav = false; 82 | 83 | this.$element = $(element); 84 | this.$wrapper = this.$element.wrap(this.wrapperHTML).parent(); 85 | this.$slides = this.$element.children('img, a, div, figure, li'); 86 | 87 | this.$element.on('movestart', function(e) { 88 | // If the movestart is heading off in an upwards or downwards 89 | // direction, prevent it so that the browser scrolls normally. 90 | if ((e.distX > e.distY && e.distX < -e.distY) || 91 | (e.distX < e.distY && e.distX > -e.distY)) { 92 | e.preventDefault(); 93 | } 94 | }); 95 | 96 | this.$element.bind('orbit.next', function () { 97 | self.shift('next'); 98 | }); 99 | 100 | this.$element.bind('orbit.prev', function () { 101 | self.shift('prev'); 102 | }); 103 | 104 | this.$element.bind('swipeleft', function () { 105 | $(this).trigger('orbit.next'); 106 | }); 107 | 108 | this.$element.bind('swiperight', function () { 109 | $(this).trigger('orbit.prev'); 110 | }); 111 | 112 | this.$element.bind('orbit.goto', function (event, index) { 113 | self.shift(index); 114 | }); 115 | 116 | this.$element.bind('orbit.start', function (event, index) { 117 | self.startClock(); 118 | }); 119 | 120 | this.$element.bind('orbit.stop', function (event, index) { 121 | self.stopClock(); 122 | }); 123 | 124 | $imageSlides = this.$slides.filter('img'); 125 | 126 | if ($imageSlides.length === 0) { 127 | this.loaded(); 128 | } else { 129 | $imageSlides.bind('imageready', function () { 130 | imagesLoadedCount += 1; 131 | if (imagesLoadedCount === $imageSlides.length) { 132 | self.loaded(); 133 | } 134 | }); 135 | } 136 | }, 137 | 138 | loaded: function () { 139 | this.$element 140 | .addClass('orbit') 141 | .css({width: '1px', height: '1px'}); 142 | 143 | if (this.options.stackOnSmall) { 144 | this.$element.addClass('orbit-stack-on-small'); 145 | } 146 | 147 | this.$slides.addClass('orbit-slide').css({"opacity" : 0}); 148 | 149 | this.setDimentionsFromLargestSlide(); 150 | this.updateOptionsIfOnlyOneSlide(); 151 | this.setupFirstSlide(); 152 | this.notifySlideChange(); 153 | 154 | if (this.options.timer) { 155 | this.setupTimer(); 156 | this.startClock(); 157 | } 158 | 159 | if (this.options.captions) { 160 | this.setupCaptions(); 161 | } 162 | 163 | if (this.options.directionalNav) { 164 | this.setupDirectionalNav(); 165 | } 166 | 167 | if (this.options.bullets) { 168 | this.setupBulletNav(); 169 | this.setActiveBullet(); 170 | } 171 | 172 | this.options.afterLoadComplete.call(this); 173 | Holder.run(); 174 | }, 175 | 176 | currentSlide: function () { 177 | return this.$slides.eq(this.activeSlide); 178 | }, 179 | 180 | notifySlideChange: function() { 181 | if (this.options.slideNumber) { 182 | var txt = (this.activeSlide+1) + ' of ' + this.$slides.length; 183 | this.$element.trigger("orbit.change", {slideIndex: this.activeSlide, slideCount: this.$slides.length}); 184 | if (this.$counter === undefined) { 185 | var $counter = $(this.slideNumberHTML).html(txt); 186 | this.$counter = $counter; 187 | this.$wrapper.append(this.$counter); 188 | } else { 189 | this.$counter.html(txt); 190 | } 191 | } 192 | }, 193 | 194 | setDimentionsFromLargestSlide: function () { 195 | //Collect all slides and set slider size of largest image 196 | var self = this, 197 | $fluidPlaceholder; 198 | 199 | self.$element.add(self.$wrapper).width(this.$slides.first().outerWidth()); 200 | self.$element.add(self.$wrapper).height(this.$slides.first().height()); 201 | self.orbitWidth = this.$slides.first().outerWidth(); 202 | self.orbitHeight = this.$slides.first().height(); 203 | $fluidPlaceholder = this.$slides.first().findFirstImage().clone(); 204 | 205 | 206 | this.$slides.each(function () { 207 | var slide = $(this), 208 | slideWidth = slide.outerWidth(), 209 | slideHeight = slide.height(); 210 | 211 | if (slideWidth > self.$element.outerWidth()) { 212 | self.$element.add(self.$wrapper).width(slideWidth); 213 | self.orbitWidth = self.$element.outerWidth(); 214 | } 215 | if (slideHeight > self.$element.height()) { 216 | self.$element.add(self.$wrapper).height(slideHeight); 217 | self.orbitHeight = self.$element.height(); 218 | $fluidPlaceholder = $(this).findFirstImage().clone(); 219 | } 220 | self.numberSlides += 1; 221 | }); 222 | 223 | if (this.options.fluid) { 224 | if (typeof this.options.fluid === "string") { 225 | // $fluidPlaceholder = $("").attr("src", "http://placehold.it/" + this.options.fluid); 226 | $fluidPlaceholder = $("").attr("data-src", "holder.js/" + this.options.fluid); 227 | //var inner = $("
                ").css({"display":"inline-block", "width":"2px", "height":"2px"}); 228 | //$fluidPlaceholder = $("
                ").css({"float":"left"}); 229 | //$fluidPlaceholder.wrapInner(inner); 230 | 231 | //$fluidPlaceholder = $("
                ").css({"height":"1px", "width":"2px"}); 232 | //$fluidPlaceholder = $("
                "); 233 | } 234 | 235 | self.$element.prepend($fluidPlaceholder); 236 | $fluidPlaceholder.addClass('fluid-placeholder'); 237 | self.$element.add(self.$wrapper).css({width: 'inherit'}); 238 | self.$element.add(self.$wrapper).css({height: 'inherit'}); 239 | 240 | $(window).bind('resize', function () { 241 | self.orbitWidth = self.$element.outerWidth(); 242 | self.orbitHeight = self.$element.height(); 243 | }); 244 | } 245 | }, 246 | 247 | //Animation locking functions 248 | lock: function () { 249 | this.locked = true; 250 | }, 251 | 252 | unlock: function () { 253 | this.locked = false; 254 | }, 255 | 256 | updateOptionsIfOnlyOneSlide: function () { 257 | if(this.$slides.length === 1) { 258 | this.options.directionalNav = false; 259 | this.options.timer = false; 260 | this.options.bullets = false; 261 | } 262 | }, 263 | 264 | setupFirstSlide: function () { 265 | //Set initial front photo z-index and fades it in 266 | var self = this; 267 | this.$slides.first() 268 | .css({"z-index" : 3, "opacity" : 1}) 269 | .fadeIn(function() { 270 | //brings in all other slides IF css declares a display: none 271 | self.$slides.css({"display":"block"}) 272 | }); 273 | }, 274 | 275 | startClock: function () { 276 | var self = this; 277 | 278 | if(!this.options.timer) { 279 | return false; 280 | } 281 | 282 | if (this.$timer.is(':hidden')) { 283 | this.clock = setInterval(function () { 284 | self.$element.trigger('orbit.next'); 285 | }, this.options.advanceSpeed); 286 | } else { 287 | this.timerRunning = true; 288 | this.$pause.removeClass('active'); 289 | this.clock = setInterval(this.rotateTimer, this.options.advanceSpeed / 180, false); 290 | } 291 | }, 292 | 293 | rotateTimer: function (reset) { 294 | var degreeCSS = "rotate(" + this.degrees + "deg)"; 295 | this.degrees += 2; 296 | this.$rotator.css({ 297 | "-webkit-transform": degreeCSS, 298 | "-moz-transform": degreeCSS, 299 | "-o-transform": degreeCSS, 300 | "-ms-transform": degreeCSS 301 | }); 302 | if (reset) { 303 | this.degrees = 0; 304 | this.$rotator.removeClass('move'); 305 | this.$mask.removeClass('move'); 306 | } 307 | if(this.degrees > 180) { 308 | this.$rotator.addClass('move'); 309 | this.$mask.addClass('move'); 310 | } 311 | if(this.degrees > 360) { 312 | this.$rotator.removeClass('move'); 313 | this.$mask.removeClass('move'); 314 | this.degrees = 0; 315 | this.$element.trigger('orbit.next'); 316 | } 317 | }, 318 | 319 | stopClock: function () { 320 | if (!this.options.timer) { 321 | return false; 322 | } else { 323 | this.timerRunning = false; 324 | clearInterval(this.clock); 325 | this.$pause.addClass('active'); 326 | } 327 | }, 328 | 329 | setupTimer: function () { 330 | this.$timer = $(this.timerHTML); 331 | this.$wrapper.append(this.$timer); 332 | 333 | this.$rotator = this.$timer.find('.rotator'); 334 | this.$mask = this.$timer.find('.mask'); 335 | this.$pause = this.$timer.find('.pause'); 336 | 337 | this.$timer.click(this.clickTimer); 338 | 339 | if (this.options.startClockOnMouseOut) { 340 | this.$wrapper.mouseleave(this.startTimerAfterMouseLeave); 341 | this.$wrapper.mouseenter(this.clearClockMouseLeaveTimer); 342 | } 343 | 344 | if (this.options.pauseOnHover) { 345 | this.$wrapper.mouseenter(this.stopClock); 346 | } 347 | }, 348 | 349 | startTimerAfterMouseLeave: function () { 350 | var self = this; 351 | 352 | this.outTimer = setTimeout(function() { 353 | if(!self.timerRunning){ 354 | self.startClock(); 355 | } 356 | }, this.options.startClockOnMouseOutAfter) 357 | }, 358 | 359 | clearClockMouseLeaveTimer: function () { 360 | clearTimeout(this.outTimer); 361 | }, 362 | 363 | clickTimer: function () { 364 | if(!this.timerRunning) { 365 | this.startClock(); 366 | } else { 367 | this.stopClock(); 368 | } 369 | }, 370 | 371 | setupCaptions: function () { 372 | this.$caption = $(this.captionHTML); 373 | this.$wrapper.append(this.$caption); 374 | this.setCaption(); 375 | }, 376 | 377 | setCaption: function () { 378 | var captionLocation = this.currentSlide().attr('data-caption'), 379 | captionHTML; 380 | 381 | if (!this.options.captions) { 382 | return false; 383 | } 384 | 385 | //Set HTML for the caption if it exists 386 | if (captionLocation) { 387 | //if caption text is blank, don't show captions 388 | if ($.trim($(captionLocation).text()).length < 1){ 389 | return false; 390 | } 391 | 392 | // if location selector starts with '#', remove it so we don't see id="#selector" 393 | if (captionLocation.charAt(0) == '#') { 394 | captionLocation = captionLocation.substring(1, captionLocation.length); 395 | } 396 | captionHTML = $('#' + captionLocation).html(); //get HTML from the matching HTML entity 397 | this.$caption 398 | .attr('id', captionLocation) // Add ID caption TODO why is the id being set? 399 | .html(captionHTML); // Change HTML in Caption 400 | //Animations for Caption entrances 401 | switch (this.options.captionAnimation) { 402 | case 'none': 403 | this.$caption.show(); 404 | break; 405 | case 'fade': 406 | this.$caption.fadeIn(this.options.captionAnimationSpeed); 407 | break; 408 | case 'slideOpen': 409 | this.$caption.slideDown(this.options.captionAnimationSpeed); 410 | break; 411 | } 412 | } else { 413 | //Animations for Caption exits 414 | switch (this.options.captionAnimation) { 415 | case 'none': 416 | this.$caption.hide(); 417 | break; 418 | case 'fade': 419 | this.$caption.fadeOut(this.options.captionAnimationSpeed); 420 | break; 421 | case 'slideOpen': 422 | this.$caption.slideUp(this.options.captionAnimationSpeed); 423 | break; 424 | } 425 | } 426 | }, 427 | 428 | setupDirectionalNav: function () { 429 | var self = this, 430 | $directionalNav = $(this.directionalNavHTML); 431 | 432 | $directionalNav.find('.right').html(this.options.directionalNavRightText); 433 | $directionalNav.find('.left').html(this.options.directionalNavLeftText); 434 | 435 | this.$wrapper.append($directionalNav); 436 | 437 | this.$wrapper.find('.left').click(function () { 438 | self.stopClock(); 439 | if (self.options.resetTimerOnClick) { 440 | self.rotateTimer(true); 441 | self.startClock(); 442 | } 443 | self.$element.trigger('orbit.prev'); 444 | }); 445 | 446 | this.$wrapper.find('.right').click(function () { 447 | self.stopClock(); 448 | if (self.options.resetTimerOnClick) { 449 | self.rotateTimer(true); 450 | self.startClock(); 451 | } 452 | self.$element.trigger('orbit.next'); 453 | }); 454 | }, 455 | 456 | setupBulletNav: function () { 457 | this.$bullets = $(this.bulletHTML); 458 | this.$wrapper.append(this.$bullets); 459 | this.$slides.each(this.addBullet); 460 | this.$element.addClass('with-bullets'); 461 | if (this.options.centerBullets) this.$bullets.css('margin-left', -this.$bullets.outerWidth() / 2); 462 | if (this.options.bulletThumbsHideOnSmall) this.$bullets.addClass('hide-for-small'); 463 | }, 464 | 465 | addBullet: function (index, slide) { 466 | var position = index + 1, 467 | $li = $('
              • ' + (position) + '
              • '), 468 | thumbName, 469 | self = this; 470 | 471 | if (this.options.bulletThumbs) { 472 | thumbName = $(slide).attr('data-thumb'); 473 | if (thumbName) { 474 | $li 475 | .addClass('has-thumb') 476 | .css({background: "url(" + this.options.bulletThumbLocation + thumbName + ") no-repeat"});; 477 | } 478 | } 479 | this.$bullets.append($li); 480 | $li.data('index', index); 481 | $li.click(function () { 482 | self.stopClock(); 483 | if (self.options.resetTimerOnClick) { 484 | self.rotateTimer(true); 485 | self.startClock(); 486 | } 487 | self.$element.trigger('orbit.goto', [$li.data('index')]) 488 | }); 489 | }, 490 | 491 | setActiveBullet: function () { 492 | if(!this.options.bullets) { return false; } else { 493 | this.$bullets.find('li') 494 | .removeClass('active') 495 | .eq(this.activeSlide) 496 | .addClass('active'); 497 | } 498 | }, 499 | 500 | resetAndUnlock: function () { 501 | this.$slides 502 | .eq(this.prevActiveSlide) 503 | .css({"z-index" : 1}); 504 | this.unlock(); 505 | this.options.afterSlideChange.call(this, this.$slides.eq(this.prevActiveSlide), this.$slides.eq(this.activeSlide)); 506 | }, 507 | 508 | shift: function (direction) { 509 | var slideDirection = direction; 510 | 511 | //remember previous activeSlide 512 | this.prevActiveSlide = this.activeSlide; 513 | 514 | //exit function if bullet clicked is same as the current image 515 | if (this.prevActiveSlide == slideDirection) { return false; } 516 | 517 | if (this.$slides.length == "1") { return false; } 518 | if (!this.locked) { 519 | this.lock(); 520 | //deduce the proper activeImage 521 | if (direction == "next") { 522 | this.activeSlide++; 523 | if (this.activeSlide == this.numberSlides) { 524 | this.activeSlide = 0; 525 | } 526 | } else if (direction == "prev") { 527 | this.activeSlide-- 528 | if (this.activeSlide < 0) { 529 | this.activeSlide = this.numberSlides - 1; 530 | } 531 | } else { 532 | this.activeSlide = direction; 533 | if (this.prevActiveSlide < this.activeSlide) { 534 | slideDirection = "next"; 535 | } else if (this.prevActiveSlide > this.activeSlide) { 536 | slideDirection = "prev" 537 | } 538 | } 539 | 540 | //set to correct bullet 541 | this.setActiveBullet(); 542 | this.notifySlideChange(); 543 | 544 | //set previous slide z-index to one below what new activeSlide will be 545 | this.$slides 546 | .eq(this.prevActiveSlide) 547 | .css({"z-index" : 2}); 548 | 549 | //fade 550 | if (this.options.animation == "fade") { 551 | this.$slides 552 | .eq(this.activeSlide) 553 | .css({"opacity" : 0, "z-index" : 3}) 554 | .animate({"opacity" : 1}, this.options.animationSpeed, this.resetAndUnlock); 555 | this.$slides 556 | .eq(this.prevActiveSlide) 557 | .animate({"opacity":0}, this.options.animationSpeed); 558 | } 559 | 560 | //horizontal-slide 561 | if (this.options.animation == "horizontal-slide") { 562 | if (slideDirection == "next") { 563 | this.$slides 564 | .eq(this.activeSlide) 565 | .css({"left": this.orbitWidth, "z-index" : 3}) 566 | .css("opacity", 1) 567 | .animate({"left" : 0}, this.options.animationSpeed, this.resetAndUnlock); 568 | } 569 | if (slideDirection == "prev") { 570 | this.$slides 571 | .eq(this.activeSlide) 572 | .css({"left": -this.orbitWidth, "z-index" : 3}) 573 | .css("opacity", 1) 574 | .animate({"left" : 0}, this.options.animationSpeed, this.resetAndUnlock); 575 | } 576 | this.$slides 577 | .eq(this.prevActiveSlide) 578 | .css("opacity", 0); 579 | } 580 | 581 | //vertical-slide 582 | if (this.options.animation == "vertical-slide") { 583 | if (slideDirection == "prev") { 584 | this.$slides 585 | .eq(this.activeSlide) 586 | .css({"top": this.orbitHeight, "z-index" : 3}) 587 | .css("opacity", 1) 588 | .animate({"top" : 0}, this.options.animationSpeed, this.resetAndUnlock); 589 | this.$slides 590 | .eq(this.prevActiveSlide) 591 | .css("opacity", 0); 592 | } 593 | if (slideDirection == "next") { 594 | this.$slides 595 | .eq(this.activeSlide) 596 | .css({"top": -this.orbitHeight, "z-index" : 3}) 597 | .css("opacity", 1) 598 | .animate({"top" : 0}, this.options.animationSpeed, this.resetAndUnlock); 599 | } 600 | this.$slides 601 | .eq(this.prevActiveSlide) 602 | .css("opacity", 0); 603 | } 604 | 605 | //horizontal-push 606 | if (this.options.animation == "horizontal-push") { 607 | if (slideDirection == "next") { 608 | this.$slides 609 | .eq(this.activeSlide) 610 | .css({"left": this.orbitWidth, "z-index" : 3}) 611 | .animate({"left" : 0, "opacity" : 1}, this.options.animationSpeed, this.resetAndUnlock); 612 | this.$slides 613 | .eq(this.prevActiveSlide) 614 | .animate({"left" : -this.orbitWidth}, this.options.animationSpeed, "", function(){ 615 | $(this).css({"opacity" : 0}); 616 | }); 617 | } 618 | if (slideDirection == "prev") { 619 | this.$slides 620 | .eq(this.activeSlide) 621 | .css({"left": -this.orbitWidth, "z-index" : 3}) 622 | .animate({"left" : 0, "opacity" : 1}, this.options.animationSpeed, this.resetAndUnlock); 623 | this.$slides 624 | .eq(this.prevActiveSlide) 625 | .animate({"left" : this.orbitWidth}, this.options.animationSpeed, "", function(){ 626 | $(this).css({"opacity" : 0}); 627 | }); 628 | } 629 | } 630 | 631 | //vertical-push 632 | if (this.options.animation == "vertical-push") { 633 | if (slideDirection == "next") { 634 | this.$slides 635 | .eq(this.activeSlide) 636 | .css({top: -this.orbitHeight, "z-index" : 3}) 637 | .css("opacity", 1) 638 | .animate({top : 0, "opacity":1}, this.options.animationSpeed, this.resetAndUnlock); 639 | this.$slides 640 | .eq(this.prevActiveSlide) 641 | .css("opacity", 0) 642 | .animate({top : this.orbitHeight}, this.options.animationSpeed, ""); 643 | } 644 | if (slideDirection == "prev") { 645 | this.$slides 646 | .eq(this.activeSlide) 647 | .css({top: this.orbitHeight, "z-index" : 3}) 648 | .css("opacity", 1) 649 | .animate({top : 0}, this.options.animationSpeed, this.resetAndUnlock); 650 | this.$slides 651 | .eq(this.prevActiveSlide) 652 | .css("opacity", 0) 653 | .animate({top : -this.orbitHeight}, this.options.animationSpeed); 654 | } 655 | } 656 | 657 | this.setCaption(); 658 | } 659 | 660 | // if on last slide and singleCycle is true, don't loop through slides again 661 | // .length is zero based so must minus 1 to match activeSlide index 662 | if (this.activeSlide === this.$slides.length-1 && this.options.singleCycle) { 663 | this.stopClock(); 664 | } 665 | } 666 | }; 667 | 668 | $.fn.orbit = function (options) { 669 | return this.each(function () { 670 | var orbit = $.extend({}, ORBIT); 671 | orbit.init(this, options); 672 | }); 673 | }; 674 | 675 | })(jQuery); 676 | 677 | /*! 678 | * jQuery imageready Plugin 679 | * http://www.zurb.com/playground/ 680 | * 681 | * Copyright 2011, ZURB 682 | * Released under the MIT License 683 | */ 684 | (function ($) { 685 | 686 | var options = {}; 687 | 688 | $.event.special.imageready = { 689 | 690 | setup: function (data, namespaces, eventHandle) { 691 | options = data || options; 692 | }, 693 | 694 | add: function (handleObj) { 695 | var $this = $(this), 696 | src; 697 | 698 | if ( this.nodeType === 1 && this.tagName.toLowerCase() === 'img' && this.src !== '' ) { 699 | if (options.forceLoad) { 700 | src = $this.attr('src'); 701 | $this.attr('src', ''); 702 | bindToLoad(this, handleObj.handler); 703 | $this.attr('src', src); 704 | } else if ( this.complete || this.readyState === 4 ) { 705 | handleObj.handler.apply(this, arguments); 706 | } else { 707 | bindToLoad(this, handleObj.handler); 708 | } 709 | } 710 | }, 711 | 712 | teardown: function (namespaces) { 713 | $(this).unbind('.imageready'); 714 | } 715 | }; 716 | 717 | function bindToLoad(element, callback) { 718 | var $this = $(element); 719 | 720 | $this.bind('load.imageready', function () { 721 | callback.apply(element, arguments); 722 | $this.unbind('load.imageready'); 723 | }); 724 | } 725 | 726 | }(jQuery)); 727 | 728 | /* 729 | 730 | Holder - 1.3 - client side image placeholders 731 | (c) 2012 Ivan Malopinsky / http://imsky.co 732 | 733 | Provided under the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0 734 | Commercial use requires attribution. 735 | 736 | */ 737 | 738 | var Holder = Holder || {}; 739 | (function (app, win) { 740 | 741 | var preempted = false, 742 | fallback = false, 743 | canvas = document.createElement('canvas'); 744 | 745 | //http://javascript.nwbox.com/ContentLoaded by Diego Perini with modifications 746 | function contentLoaded(n,t){var l="complete",s="readystatechange",u=!1,h=u,c=!0,i=n.document,a=i.documentElement,e=i.addEventListener?"addEventListener":"attachEvent",v=i.addEventListener?"removeEventListener":"detachEvent",f=i.addEventListener?"":"on",r=function(e){(e.type!=s||i.readyState==l)&&((e.type=="load"?n:i)[v](f+e.type,r,u),!h&&(h=!0)&&t.call(n,null))},o=function(){try{a.doScroll("left")}catch(n){setTimeout(o,50);return}r("poll")};if(i.readyState==l)t.call(n,"lazy");else{if(i.createEventObject&&a.doScroll){try{c=!n.frameElement}catch(y){}c&&o()}i[e](f+"DOMContentLoaded",r,u),i[e](f+s,r,u),n[e](f+"load",r,u)}}; 747 | 748 | //https://gist.github.com/991057 by Jed Schmidt with modifications 749 | function selector(a){ 750 | a=a.match(/^(\W)?(.*)/);var b=document["getElement"+(a[1]?a[1]=="#"?"ById":"sByClassName":"sByTagName")](a[2]); 751 | var ret=[]; b!=null&&(b.length?ret=b:b.length==0?ret=b:ret=[b]); return ret; 752 | } 753 | 754 | //shallow object property extend 755 | function extend(a,b){var c={};for(var d in a)c[d]=a[d];for(var e in b)c[e]=b[e];return c} 756 | 757 | function draw(ctx, dimensions, template) { 758 | var dimension_arr = [dimensions.height, dimensions.width].sort(); 759 | var maxFactor = Math.round(dimension_arr[1] / 16), 760 | minFactor = Math.round(dimension_arr[0] / 16); 761 | var text_height = Math.max(template.size, maxFactor); 762 | canvas.width = dimensions.width; 763 | canvas.height = dimensions.height; 764 | ctx.textAlign = "center"; 765 | ctx.textBaseline = "middle"; 766 | ctx.fillStyle = template.background; 767 | ctx.fillRect(0, 0, dimensions.width, dimensions.height); 768 | ctx.fillStyle = template.foreground; 769 | ctx.font = "bold " + text_height + "px sans-serif"; 770 | var text = template.text ? template.text : (dimensions.width + "x" + dimensions.height); 771 | if (Math.round(ctx.measureText(text).width) / dimensions.width > 1) { 772 | text_height = Math.max(minFactor, template.size); 773 | } 774 | ctx.font = "bold " + text_height + "px sans-serif"; 775 | ctx.fillText(text, (dimensions.width / 2), (dimensions.height / 2), dimensions.width); 776 | return canvas.toDataURL("image/png"); 777 | } 778 | 779 | if (!canvas.getContext) { 780 | fallback = true; 781 | } else { 782 | if (canvas.toDataURL("image/png").indexOf("data:image/png") < 0) { 783 | //Android doesn't support data URI 784 | fallback = true; 785 | } else { 786 | var ctx = canvas.getContext("2d"); 787 | } 788 | } 789 | 790 | var settings = { 791 | domain: "holder.js", 792 | images: "img", 793 | themes: { 794 | "gray": { 795 | background: "#eee", 796 | foreground: "#aaa", 797 | size: 12 798 | }, 799 | "social": { 800 | background: "#3a5a97", 801 | foreground: "#fff", 802 | size: 12 803 | }, 804 | "industrial": { 805 | background: "#434A52", 806 | foreground: "#C2F200", 807 | size: 12 808 | } 809 | } 810 | }; 811 | 812 | 813 | 814 | app.flags = { 815 | dimensions: { 816 | regex: /([0-9]+)x([0-9]+)/, 817 | output: function(val){ 818 | var exec = this.regex.exec(val); 819 | return { 820 | width: +exec[1], 821 | height: +exec[2] 822 | } 823 | } 824 | }, 825 | colors: { 826 | regex: /#([0-9a-f]{3,})\:#([0-9a-f]{3,})/i, 827 | output: function(val){ 828 | var exec = this.regex.exec(val); 829 | return { 830 | size: settings.themes.gray.size, 831 | foreground: "#" + exec[2], 832 | background: "#" + exec[1] 833 | } 834 | } 835 | }, 836 | text: { 837 | regex: /text\:(.*)/, 838 | output: function(val){ 839 | return this.regex.exec(val)[1]; 840 | } 841 | } 842 | } 843 | 844 | for(var flag in app.flags){ 845 | app.flags[flag].match = function (val){ 846 | return val.match(this.regex) 847 | } 848 | } 849 | 850 | app.add_theme = function (name, theme) { 851 | name != null && theme != null && (settings.themes[name] = theme); 852 | return app; 853 | }; 854 | 855 | app.add_image = function (src, el) { 856 | var node = selector(el); 857 | if (node.length) { 858 | for (var i = 0, l = node.length; i < l; i++) { 859 | var img = document.createElement("img") 860 | img.setAttribute("data-src", src); 861 | node[i].appendChild(img); 862 | } 863 | } 864 | return app; 865 | }; 866 | 867 | app.run = function (o) { 868 | var options = extend(settings, o), 869 | images = selector(options.images), 870 | preempted = true; 871 | 872 | for (var l = images.length, i = 0; i < l; i++) { 873 | var theme = settings.themes.gray; 874 | var src = images[i].getAttribute("data-src") || images[i].getAttribute("src"); 875 | if (src && !! ~src.indexOf(options.domain)) { 876 | var render = false, 877 | dimensions = null, 878 | text = null; 879 | var flags = src.substr(src.indexOf(options.domain) + options.domain.length + 1).split("/"); 880 | for (sl = flags.length, j = 0; j < sl; j++) { 881 | if (app.flags.dimensions.match(flags[j])) { 882 | render = true; 883 | dimensions = app.flags.dimensions.output(flags[j]); 884 | } else if (app.flags.colors.match(flags[j])) { 885 | theme = app.flags.colors.output(flags[j]); 886 | } else if (options.themes[flags[j]]) { 887 | //If a theme is specified, it will override custom colors 888 | theme = options.themes[flags[j]]; 889 | } else if (app.flags.text.match(flags[j])) { 890 | text = app.flags.text.output(flags[j]); 891 | } 892 | } 893 | if (render) { 894 | images[i].setAttribute("data-src", src); 895 | var dimensions_caption = dimensions.width + "x" + dimensions.height; 896 | images[i].setAttribute("alt", text ? text : theme.text ? theme.text + " [" + dimensions_caption + "]" : dimensions_caption); 897 | 898 | // Fallback 899 | // images[i].style.width = dimensions.width + "px"; 900 | // images[i].style.height = dimensions.height + "px"; 901 | images[i].style.backgroundColor = theme.background; 902 | 903 | var theme = (text ? extend(theme, { 904 | text: text 905 | }) : theme); 906 | 907 | if (!fallback) { 908 | images[i].setAttribute("src", draw(ctx, dimensions, theme)); 909 | } 910 | } 911 | } 912 | } 913 | return app; 914 | }; 915 | contentLoaded(win, function () { 916 | preempted || app.run() 917 | }) 918 | 919 | })(Holder, window); 920 | --------------------------------------------------------------------------------