From e094bd1492eefcc21d0e638f2f93d38a3b9a1741 Mon Sep 17 00:00:00 2001 From: Bill Bushey Date: Fri, 15 Jul 2016 16:57:24 -0500 Subject: [PATCH 01/25] Adding react_rails --- Gemfile | 1 + Gemfile.lock | 12 ++++++++++++ app/assets/javascripts/application.js | 3 +++ app/assets/javascripts/components.js | 1 + app/assets/javascripts/components/.gitkeep | 0 config/application.rb | 5 +++++ config/environments/development.rb | 5 +++++ config/environments/production.rb | 5 +++++ config/environments/stage.rb | 5 +++++ config/environments/test.rb | 5 +++++ 10 files changed, 42 insertions(+) create mode 100644 app/assets/javascripts/components.js create mode 100644 app/assets/javascripts/components/.gitkeep diff --git a/Gemfile b/Gemfile index 607c4fe4..b0cd86ca 100644 --- a/Gemfile +++ b/Gemfile @@ -15,6 +15,7 @@ gem 'pg' gem 'puma' gem 'rails_admin' gem 'rails_admin_enum4' +gem 'react-rails' gem 'sass-rails' gem 'validates_formatting_of' diff --git a/Gemfile.lock b/Gemfile.lock index c467a712..fcb9d82d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -37,6 +37,10 @@ GEM arel (5.0.1.20140414130214) autoprefixer-rails (6.5.3.1) execjs + babel-source (5.8.35) + babel-transpiler (0.7.0) + babel-source (>= 4.0, < 6) + execjs (~> 2.0) bcrypt (3.1.11) bootstrap-sass (3.3.7) autoprefixer-rails (>= 5.2.1) @@ -238,6 +242,13 @@ GEM rb-fsevent (0.9.8) rb-inotify (0.9.7) ffi (>= 0.5.0) + react-rails (1.8.0) + babel-transpiler (>= 0.7.0) + coffee-script-source (~> 1.8) + connection_pool + execjs + railties (>= 3.2) + tilt remotipart (1.3.1) responders (1.1.2) railties (>= 3.2, < 4.2) @@ -355,6 +366,7 @@ DEPENDENCIES rails_12factor rails_admin rails_admin_enum4 + react-rails rspec-rails sandi_meter sass-rails diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 5bc2e1c8..e60db41a 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -10,4 +10,7 @@ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details // about supported directives. // +//= require react +//= require react_ujs +//= require components //= require_tree . diff --git a/app/assets/javascripts/components.js b/app/assets/javascripts/components.js new file mode 100644 index 00000000..9ce7a4f3 --- /dev/null +++ b/app/assets/javascripts/components.js @@ -0,0 +1 @@ +//= require_tree ./components diff --git a/app/assets/javascripts/components/.gitkeep b/app/assets/javascripts/components/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/config/application.rb b/config/application.rb index 55377b81..69f9beb8 100644 --- a/config/application.rb +++ b/config/application.rb @@ -28,5 +28,10 @@ class Application < Rails::Application # config.i18n.default_locale = :de ::AppConfig = Hashie::Mash.new(YAML.load(ERB.new(File.read(Rails.root.join('config/config.yml'))).result)) + + ####################### + # React Configuraiton + ####################### + config.react.addons = true end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 3bdffc5b..b38dabd9 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -29,4 +29,9 @@ # From http://mailcatcher.me/ config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { address: 'localhost', port: 1025 } + + ####################### + # React Configuraiton + ####################### + config.react.variant = :development end diff --git a/config/environments/production.rb b/config/environments/production.rb index 89862429..06afc5d2 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -76,4 +76,9 @@ # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false + + ####################### + # React Configuraiton + ####################### + config.react.variant = :production end diff --git a/config/environments/stage.rb b/config/environments/stage.rb index 960d4b38..bf016dd5 100644 --- a/config/environments/stage.rb +++ b/config/environments/stage.rb @@ -76,4 +76,9 @@ # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false + + ####################### + # React Configuraiton + ####################### + config.react.variant = :development end diff --git a/config/environments/test.rb b/config/environments/test.rb index 053f5b66..7b9198b2 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -36,4 +36,9 @@ # Raises error for missing translations # config.action_view.raise_on_missing_translations = true + + ####################### + # React Configuraiton + ####################### + config.react.variant = :production end From 0f70e8f67f1f70ba3dbb2665831bc46488483f6f Mon Sep 17 00:00:00 2001 From: Bill Bushey Date: Fri, 15 Jul 2016 17:10:38 -0500 Subject: [PATCH 02/25] First React component --- .../javascripts/components/field.es6.jsx | 21 +++++++++++++++++++ app/views/sidebar/edit_profile.html.haml | 2 ++ 2 files changed, 23 insertions(+) create mode 100644 app/assets/javascripts/components/field.es6.jsx diff --git a/app/assets/javascripts/components/field.es6.jsx b/app/assets/javascripts/components/field.es6.jsx new file mode 100644 index 00000000..8f62d9b7 --- /dev/null +++ b/app/assets/javascripts/components/field.es6.jsx @@ -0,0 +1,21 @@ +class Field extends React.Component { + render () { + return ( +
+
Name: {this.props.name}
+
Type: {this.props.type}
+
Label: {this.props.label}
+
Required: {this.props.required}
+
Private: {this.props.private}
+
+ ); + } +} + +Field.propTypes = { + name: React.PropTypes.string, + type: React.PropTypes.oneOf(['text', 'password', 'checkbox', 'radio', 'select']), + label: React.PropTypes.string, + required: React.PropTypes.bool, + private: React.PropTypes.bool +}; diff --git a/app/views/sidebar/edit_profile.html.haml b/app/views/sidebar/edit_profile.html.haml index 537d8496..2adb6109 100644 --- a/app/views/sidebar/edit_profile.html.haml +++ b/app/views/sidebar/edit_profile.html.haml @@ -2,6 +2,7 @@ = f.hidden_field "id" = render :partial => "user_email", locals: {f: f} = render :partial => "user_username", locals: {f: f} + = react_component 'Field', name: 'foobar', type: 'text', label: 'Hi' %h2 = t("labels.shipping_info_heading") = render :partial => "user_realnames", locals: {f: f} @@ -26,5 +27,6 @@ = t("buttons.back") :javascript $(function() { + ReactRailsUJS.mountComponents(); $('#user_email').focus(); }); From f32d4b75a9903559fd87c0d1e4a54084555c02dd Mon Sep 17 00:00:00 2001 From: Bill Bushey Date: Sat, 16 Jul 2016 17:34:41 -0500 Subject: [PATCH 03/25] Added Jasmine, and first React spec --- Gemfile | 1 + Gemfile.lock | 10 ++++ app/assets/javascripts/application.js | 2 +- config/environments/test.rb | 2 +- config/initializers/jasmine_rails.rb | 15 ++++++ config/routes.rb | 1 + spec/javascripts/components/field_spec.js.jsx | 11 ++++ spec/javascripts/helpers/react_helper.js | 1 + spec/javascripts/support/jasmine.yml | 52 +++++++++++++++++++ 9 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 config/initializers/jasmine_rails.rb create mode 100644 spec/javascripts/components/field_spec.js.jsx create mode 100644 spec/javascripts/helpers/react_helper.js create mode 100644 spec/javascripts/support/jasmine.yml diff --git a/Gemfile b/Gemfile index b0cd86ca..ce8982cd 100644 --- a/Gemfile +++ b/Gemfile @@ -38,6 +38,7 @@ group :development, :test do gem 'capistrano3-puma' gem 'dotenv-rails' gem 'factory_girl_rails' + gem 'jasmine-rails' gem 'pry-rails' gem 'rspec-rails' end diff --git a/Gemfile.lock b/Gemfile.lock index fcb9d82d..e29837c6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -145,7 +145,15 @@ GEM haml (4.0.7) tilt hashie (3.4.6) + hike (1.2.3) + hitimes (1.2.2) i18n (0.7.0) + jasmine-core (2.4.1) + jasmine-rails (0.12.6) + jasmine-core (>= 1.3, < 3.0) + phantomjs (>= 1.9) + railties (>= 3.2.0) + sprockets-rails jquery-rails (3.1.4) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) @@ -185,6 +193,7 @@ GEM shellany (~> 0.0) orm_adapter (0.5.0) pg (0.19.0) + phantomjs (2.1.1.0) poltergeist (1.12.0) capybara (~> 2.1) cliver (~> 0.3.1) @@ -355,6 +364,7 @@ DEPENDENCIES guard-rspec haml hashie + jasmine-rails jquery-rails launchy libnotify diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e60db41a..f7e79b38 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -9,7 +9,7 @@ // // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details // about supported directives. -// +//= require jquery //= require react //= require react_ujs //= require components diff --git a/config/environments/test.rb b/config/environments/test.rb index 7b9198b2..4260349c 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -40,5 +40,5 @@ ####################### # React Configuraiton ####################### - config.react.variant = :production + config.react.variant = :development end diff --git a/config/initializers/jasmine_rails.rb b/config/initializers/jasmine_rails.rb new file mode 100644 index 00000000..f6540c9b --- /dev/null +++ b/config/initializers/jasmine_rails.rb @@ -0,0 +1,15 @@ +#if Rails.env.in? %w(test development) +# require 'jasmine_rails/runner' +# +# module JasmineRails +# module Runner +# class << self +# private +# def run_cmd(cmd) +# puts "Running `#{cmd}`" +# system(cmd) +# end +# end +# end +# end +#end diff --git a/config/routes.rb b/config/routes.rb index 5698d6be..0ad36a67 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + mount JasmineRails::Engine => '/specs' if defined?(JasmineRails) devise_for :users, controllers: { passwords: 'passwords', registrations: 'users', diff --git a/spec/javascripts/components/field_spec.js.jsx b/spec/javascripts/components/field_spec.js.jsx new file mode 100644 index 00000000..6a81cfe3 --- /dev/null +++ b/spec/javascripts/components/field_spec.js.jsx @@ -0,0 +1,11 @@ +describe('Field', function(){ + it('Has a name', function(){ + var field = TestUtils.renderIntoDocument( + + ); + + var fieldNode = ReactDOM.findDOMNode(field); + + expect(fieldNode.textContent).toContain('foobar'); + }); +}); diff --git a/spec/javascripts/helpers/react_helper.js b/spec/javascripts/helpers/react_helper.js new file mode 100644 index 00000000..edd7f453 --- /dev/null +++ b/spec/javascripts/helpers/react_helper.js @@ -0,0 +1 @@ +window.TestUtils = React.addons.TestUtils; diff --git a/spec/javascripts/support/jasmine.yml b/spec/javascripts/support/jasmine.yml new file mode 100644 index 00000000..87f06de8 --- /dev/null +++ b/spec/javascripts/support/jasmine.yml @@ -0,0 +1,52 @@ +# path to parent directory of src_files +# relative path from Rails.root +# defaults to app/assets/javascripts +src_dir: "app/assets/javascripts" + +# path to additional directory of source file that are not part of assets pipeline and need to be included +# relative path from Rails.root +# defaults to [] +# include_dir: +# - ../mobile_app/public/js + +# path to parent directory of css_files +# relative path from Rails.root +# defaults to app/assets/stylesheets +css_dir: "app/assets/stylesheets" + +# list of file expressions to include as source files +# relative path from src_dir +src_files: + - "application.{js.coffee,js,coffee}" + +# list of file expressions to include as css files +# relative path from css_dir +css_files: + +# path to parent directory of spec_files +# relative path from Rails.root +# +# Alternatively accept an array of directory to include external spec files +# spec_dir: +# - spec/javascripts +# - ../engine/spec/javascripts +# +# defaults to spec/javascripts +spec_dir: spec/javascripts + +# list of file expressions to include as helpers into spec runner +# relative path from spec_dir +helpers: + - "helpers/**/*.{js.coffee,js,coffee}" + +# list of file expressions to include as specs into spec runner +# relative path from spec_dir +spec_files: + - "**/*[Ss]pec.{js.jsx,js,jsx}" + +# path to directory of temporary files +# (spec runner and asset cache) +# defaults to tmp/jasmine +tmp_dir: "tmp/jasmine" + +use_phantom_gem: false From c4549047b0769f4df1dfbadde14761733ed01e6a Mon Sep 17 00:00:00 2001 From: Bill Bushey Date: Sat, 16 Jul 2016 20:06:11 -0500 Subject: [PATCH 04/25] Using jquery-rails version of jQuery Using jquery-ui-rails --- Gemfile | 1 + Gemfile.lock | 1 + app/assets/javascripts/application.js | 1 + app/assets/stylesheets/application.css | 1 + app/views/layouts/application.html.haml | 2 -- 5 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index ce8982cd..30d6007d 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ gem 'geokit' gem 'haml' gem 'hashie' gem 'jquery-rails' +gem 'jquery-ui-rails' gem 'pg' gem 'puma' gem 'rails_admin' diff --git a/Gemfile.lock b/Gemfile.lock index e29837c6..7cb34b47 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -366,6 +366,7 @@ DEPENDENCIES hashie jasmine-rails jquery-rails + jquery-ui-rails launchy libnotify pg diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index f7e79b38..e35b96b3 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -10,6 +10,7 @@ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details // about supported directives. //= require jquery +//= require jquery-ui //= require react //= require react_ujs //= require components diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index dfe7fecd..42beb9c6 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -10,6 +10,7 @@ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new * file per style scope. * + *= require jquery-ui *= require_self *= require_tree . */ diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index fd0ebb6c..44aadcc8 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -9,8 +9,6 @@ /[if lt IE 9] = javascript_include_tag "//html5shim.googlecode.com/svn/trunk/html5.js" = javascript_include_tag "//maps.googleapis.com/maps/api/js?key=#{AppConfig.google_maps.api_key}" - = javascript_include_tag "//ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js" - = javascript_include_tag "//ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js" = javascript_include_tag "application" - if (Rails.env.production? || Rails.env.stage?) && AppConfig.google_analytics.id.present? %script{:type => "text/javascript"} From 0cf5d40e2f86e98a40d1102969b08813b5a1c957 Mon Sep 17 00:00:00 2001 From: Bill Bushey Date: Sat, 16 Jul 2016 20:11:49 -0500 Subject: [PATCH 05/25] Upgrading bootstrap.js to 2.3.2 --- app/assets/javascripts/bootstrap.js | 1512 ++++++++++++++++++--------- 1 file changed, 1033 insertions(+), 479 deletions(-) diff --git a/app/assets/javascripts/bootstrap.js b/app/assets/javascripts/bootstrap.js index ca868671..44109f62 100644 --- a/app/assets/javascripts/bootstrap.js +++ b/app/assets/javascripts/bootstrap.js @@ -1,8 +1,8 @@ /* =================================================== - * bootstrap-transition.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#transitions + * bootstrap-transition.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#transitions * =================================================== - * Copyright 2012 Twitter, Inc. + * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,42 +17,51 @@ * limitations under the License. * ========================================================== */ -!function( $ ) { - $(function () { +!function ($) { + + "use strict"; // jshint ;_; - "use strict" - /* CSS TRANSITION SUPPORT (https://gist.github.com/373874) - * ======================================================= */ + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ + + $(function () { $.support.transition = (function () { - var thisBody = document.body || document.documentElement - , thisStyle = thisBody.style - , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined - - return support && { - end: (function () { - var transitionEnd = "TransitionEnd" - if ( $.browser.webkit ) { - transitionEnd = "webkitTransitionEnd" - } else if ( $.browser.mozilla ) { - transitionEnd = "transitionend" - } else if ( $.browser.opera ) { - transitionEnd = "oTransitionEnd" + + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] } - return transitionEnd - }()) + } + + }()) + + return transitionEnd && { + end: transitionEnd } + })() }) -}( window.jQuery );/* ========================================================== - * bootstrap-alert.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#alerts +}(window.jQuery);/* ========================================================== + * bootstrap-alert.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#alerts * ========================================================== - * Copyright 2012 Twitter, Inc. + * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -68,61 +77,59 @@ * ========================================================== */ -!function( $ ){ +!function ($) { + + "use strict"; // jshint ;_; - "use strict" /* ALERT CLASS DEFINITION * ====================== */ var dismiss = '[data-dismiss="alert"]' - , Alert = function ( el ) { + , Alert = function (el) { $(el).on('click', dismiss, this.close) } - Alert.prototype = { + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent - constructor: Alert - - , close: function ( e ) { - var $this = $(this) - , selector = $this.attr('data-target') - , $parent + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } + $parent = $(selector) - $parent = $(selector) - $parent.trigger('close') + e && e.preventDefault() - e && e.preventDefault() + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) - $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + $parent.trigger(e = $.Event('close')) - $parent - .trigger('close') - .removeClass('in') + if (e.isDefaultPrevented()) return - function removeElement() { - $parent - .trigger('closed') - .remove() - } + $parent.removeClass('in') - $.support.transition && $parent.hasClass('fade') ? - $parent.on($.support.transition.end, removeElement) : - removeElement() + function removeElement() { + $parent + .trigger('closed') + .remove() } + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() } /* ALERT PLUGIN DEFINITION * ======================= */ - $.fn.alert = function ( option ) { + var old = $.fn.alert + + $.fn.alert = function (option) { return this.each(function () { var $this = $(this) , data = $this.data('alert') @@ -134,18 +141,25 @@ $.fn.alert.Constructor = Alert + /* ALERT NO CONFLICT + * ================= */ + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + /* ALERT DATA-API * ============== */ - $(function () { - $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) - }) + $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) -}( window.jQuery );/* ============================================================ - * bootstrap-button.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#buttons +}(window.jQuery);/* ============================================================ + * bootstrap-button.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#buttons * ============================================================ - * Copyright 2012 Twitter, Inc. + * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -160,58 +174,56 @@ * limitations under the License. * ============================================================ */ -!function( $ ){ - "use strict" +!function ($) { + + "use strict"; // jshint ;_; + /* BUTTON PUBLIC CLASS DEFINITION * ============================== */ - var Button = function ( element, options ) { + var Button = function (element, options) { this.$element = $(element) this.options = $.extend({}, $.fn.button.defaults, options) } - Button.prototype = { - - constructor: Button - - , setState: function ( state ) { - var d = 'disabled' - , $el = this.$element - , data = $el.data() - , val = $el.is('input') ? 'val' : 'html' + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' - state = state + 'Text' - data.resetText || $el.data('resetText', $el[val]()) + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) - $el[val](data[state] || this.options[state]) + $el[val](data[state] || this.options[state]) - // push to event loop to allow forms to submit - setTimeout(function () { - state == 'loadingText' ? - $el.addClass(d).attr(d, d) : - $el.removeClass(d).removeAttr(d) - }, 0) - } + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } - , toggle: function () { - var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons-radio"]') - $parent && $parent - .find('.active') - .removeClass('active') - - this.$element.toggleClass('active') - } + $parent && $parent + .find('.active') + .removeClass('active') + this.$element.toggleClass('active') } /* BUTTON PLUGIN DEFINITION * ======================== */ - $.fn.button = function ( option ) { + var old = $.fn.button + + $.fn.button = function (option) { return this.each(function () { var $this = $(this) , data = $this.data('button') @@ -229,22 +241,29 @@ $.fn.button.Constructor = Button + /* BUTTON NO CONFLICT + * ================== */ + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + /* BUTTON DATA-API * =============== */ - $(function () { - $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - $btn.button('toggle') - }) + $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') }) -}( window.jQuery );/* ========================================================== - * bootstrap-carousel.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#carousel +}(window.jQuery);/* ========================================================== + * bootstrap-carousel.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#carousel * ========================================================== - * Copyright 2012 Twitter, Inc. + * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -260,17 +279,18 @@ * ========================================================== */ -!function( $ ){ +!function ($) { + + "use strict"; // jshint ;_; - "use strict" /* CAROUSEL CLASS DEFINITION * ========================= */ var Carousel = function (element, options) { this.$element = $(element) - this.options = $.extend({}, $.fn.carousel.defaults, options) - this.options.slide && this.slide(this.options.slide) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options this.options.pause == 'hover' && this.$element .on('mouseenter', $.proxy(this.pause, this)) .on('mouseleave', $.proxy(this.cycle, this)) @@ -278,18 +298,26 @@ Carousel.prototype = { - cycle: function () { - this.interval = setInterval($.proxy(this.next, this), this.options.interval) + cycle: function (e) { + if (!e) this.paused = false + if (this.interval) clearInterval(this.interval); + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) return this } + , getActiveIndex: function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + return this.$items.index(this.$active) + } + , to: function (pos) { - var $active = this.$element.find('.active') - , children = $active.parent().children() - , activePos = children.index($active) + var activeIndex = this.getActiveIndex() , that = this - if (pos > (children.length - 1) || pos < 0) return + if (pos > (this.$items.length - 1) || pos < 0) return if (this.sliding) { return this.$element.one('slid', function () { @@ -297,14 +325,19 @@ }) } - if (activePos == pos) { + if (activeIndex == pos) { return this.pause().cycle() } - return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) } - , pause: function () { + , pause: function (e) { + if (!e) this.paused = true + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } clearInterval(this.interval) this.interval = null return this @@ -321,12 +354,13 @@ } , slide: function (type, next) { - var $active = this.$element.find('.active') + var $active = this.$element.find('.item.active') , $next = next || $active[type]() , isCycling = this.interval , direction = type == 'next' ? 'left' : 'right' , fallback = type == 'next' ? 'first' : 'last' , that = this + , e this.sliding = true @@ -334,26 +368,41 @@ $next = $next.length ? $next : this.$element.find('.item')[fallback]() + e = $.Event('slide', { + relatedTarget: $next[0] + , direction: direction + }) + if ($next.hasClass('active')) return - if (!$.support.transition && this.$element.hasClass('slide')) { - this.$element.trigger('slide') - $active.removeClass('active') - $next.addClass('active') - this.sliding = false - this.$element.trigger('slid') - } else { + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return $next.addClass(type) $next[0].offsetWidth // force reflow $active.addClass(direction) $next.addClass(direction) - this.$element.trigger('slide') this.$element.one($.support.transition.end, function () { $next.removeClass([type, direction].join(' ')).addClass('active') $active.removeClass(['active', direction].join(' ')) that.sliding = false setTimeout(function () { that.$element.trigger('slid') }, 0) }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') } isCycling && this.cycle() @@ -367,15 +416,18 @@ /* CAROUSEL PLUGIN DEFINITION * ========================== */ - $.fn.carousel = function ( option ) { + var old = $.fn.carousel + + $.fn.carousel = function (option) { return this.each(function () { var $this = $(this) , data = $this.data('carousel') - , options = typeof option == 'object' && option + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + , action = typeof option == 'string' ? option : options.slide if (!data) $this.data('carousel', (data = new Carousel(this, options))) if (typeof option == 'number') data.to(option) - else if (typeof option == 'string' || (option = options.slide)) data[option]() - else data.cycle() + else if (action) data[action]() + else if (options.interval) data.pause().cycle() }) } @@ -387,24 +439,37 @@ $.fn.carousel.Constructor = Carousel + /* CAROUSEL NO CONFLICT + * ==================== */ + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + /* CAROUSEL DATA-API * ================= */ - $(function () { - $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { - var $this = $(this), href - , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 - , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) - $target.carousel(options) - e.preventDefault() - }) + $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = $.extend({}, $target.data(), $this.data()) + , slideIndex + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('carousel').pause().to(slideIndex).cycle() + } + + e.preventDefault() }) -}( window.jQuery );/* ============================================================= - * bootstrap-collapse.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#collapse +}(window.jQuery);/* ============================================================= + * bootstrap-collapse.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#collapse * ============================================================= - * Copyright 2012 Twitter, Inc. + * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -419,16 +484,21 @@ * limitations under the License. * ============================================================ */ -!function( $ ){ - "use strict" +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ - var Collapse = function ( element, options ) { - this.$element = $(element) + var Collapse = function (element, options) { + this.$element = $(element) this.options = $.extend({}, $.fn.collapse.defaults, options) - if (this.options["parent"]) { - this.$parent = $(this.options["parent"]) + if (this.options.parent) { + this.$parent = $(this.options.parent) } this.options.toggle && this.toggle() @@ -444,31 +514,39 @@ } , show: function () { - var dimension = this.dimension() - , scroll = $.camelCase(['scroll', dimension].join('-')) - , actives = this.$parent && this.$parent.find('.in') + var dimension + , scroll + , actives , hasData + if (this.transitioning || this.$element.hasClass('in')) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + if (actives && actives.length) { hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return actives.collapse('hide') hasData || actives.data('collapse', null) } this.$element[dimension](0) - this.transition('addClass', 'show', 'shown') - this.$element[dimension](this.$element[0][scroll]) - + this.transition('addClass', $.Event('show'), 'shown') + $.support.transition && this.$element[dimension](this.$element[0][scroll]) } , hide: function () { - var dimension = this.dimension() + var dimension + if (this.transitioning || !this.$element.hasClass('in')) return + dimension = this.dimension() this.reset(this.$element[dimension]()) - this.transition('removeClass', 'hide', 'hidden') + this.transition('removeClass', $.Event('hide'), 'hidden') this.$element[dimension](0) } - , reset: function ( size ) { + , reset: function (size) { var dimension = this.dimension() this.$element @@ -476,41 +554,49 @@ [dimension](size || 'auto') [0].offsetWidth - this.$element[size ? 'addClass' : 'removeClass']('collapse') + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') return this } - , transition: function ( method, startEvent, completeEvent ) { + , transition: function (method, startEvent, completeEvent) { var that = this , complete = function () { - if (startEvent == 'show') that.reset() + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 that.$element.trigger(completeEvent) } - this.$element - .trigger(startEvent) - [method]('in') + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') $.support.transition && this.$element.hasClass('collapse') ? this.$element.one($.support.transition.end, complete) : complete() - } + } , toggle: function () { this[this.$element.hasClass('in') ? 'hide' : 'show']() - } + } } - /* COLLAPSIBLE PLUGIN DEFINITION - * ============================== */ - $.fn.collapse = function ( option ) { + /* COLLAPSE PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.collapse + + $.fn.collapse = function (option) { return this.each(function () { var $this = $(this) , data = $this.data('collapse') - , options = typeof option == 'object' && option + , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option) if (!data) $this.data('collapse', (data = new Collapse(this, options))) if (typeof option == 'string') data[option]() }) @@ -523,25 +609,33 @@ $.fn.collapse.Constructor = Collapse - /* COLLAPSIBLE DATA-API + /* COLLAPSE NO CONFLICT * ==================== */ - $(function () { - $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { - var $this = $(this), href - , target = $this.attr('data-target') - || e.preventDefault() - || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 - , option = $(target).data('collapse') ? 'toggle' : $this.data() - $(target).collapse(option) - }) + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + /* COLLAPSE DATA-API + * ================= */ + + $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + $(target).collapse(option) }) -}( window.jQuery );/* ============================================================ - * bootstrap-dropdown.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#dropdowns +}(window.jQuery);/* ============================================================ + * bootstrap-dropdown.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#dropdowns * ============================================================ - * Copyright 2012 Twitter, Inc. + * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -557,15 +651,16 @@ * ============================================================ */ -!function( $ ){ +!function ($) { + + "use strict"; // jshint ;_; - "use strict" /* DROPDOWN CLASS DEFINITION * ========================= */ - var toggle = '[data-toggle="dropdown"]' - , Dropdown = function ( element ) { + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { var $el = $(element).on('click.dropdown.data-api', this.toggle) $('html').on('click.dropdown.data-api', function () { $el.parent().removeClass('open') @@ -576,39 +671,105 @@ constructor: Dropdown - , toggle: function ( e ) { + , toggle: function (e) { var $this = $(this) - , selector = $this.attr('data-target') , $parent , isActive - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } + if ($this.is('.disabled, :disabled')) return - $parent = $(selector) - $parent.length || ($parent = $this.parent()) + $parent = getParent($this) isActive = $parent.hasClass('open') clearMenus() - !isActive && $parent.toggleClass('open') + + if (!isActive) { + if ('ontouchstart' in document.documentElement) { + // if mobile we we use a backdrop because click events don't delegate + $('