diff --git a/Gemfile b/Gemfile
index 05a0a1e5..4c23e50d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -4,6 +4,7 @@ source 'https://rubygems.org'
gem 'simple_calendar'
gem 'rails'
+gem 'has_scope'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0.0.beta1'
diff --git a/Gemfile.lock b/Gemfile.lock
index 0c2451ac..99464f9a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,6 +1,6 @@
GIT
remote: git://github.com/activeadmin/activeadmin.git
- revision: c26ae0b1393311180b5137c6b4a271de3385d069
+ revision: 809142efe855e590331cdc41e72dcad76b719a46
specs:
activeadmin (1.0.0.pre)
arbre (~> 1.0, >= 1.0.2)
@@ -150,7 +150,7 @@ GEM
actionpack (>= 3.2.13)
formtastic_i18n (0.1.1)
geocoder (1.2.5)
- guard (2.7.1)
+ guard (2.8.0)
formatador (>= 0.2.4)
listen (~> 2.7)
lumberjack (~> 1.0)
@@ -169,7 +169,7 @@ GEM
guard-minitest (2.3.2)
guard (~> 2.0)
minitest (>= 3.0)
- guard-rubocop (1.1.0)
+ guard-rubocop (1.2.0)
guard (~> 2.0)
rubocop (~> 0.20)
haml (4.0.5)
@@ -219,7 +219,7 @@ GEM
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
lumberjack (1.0.9)
- mail (2.6.1)
+ mail (2.6.3)
mime-types (>= 1.16, < 3)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
@@ -234,7 +234,7 @@ GEM
mysql2 (0.3.16)
naught (1.0.0)
orm_adapter (0.5.0)
- parser (2.2.0.pre.6)
+ parser (2.2.0.pre.7)
ast (>= 1.1, < 3.0)
slop (~> 3.4, >= 3.4.5)
polyamorous (1.1.0)
@@ -290,7 +290,7 @@ GEM
powerpack (~> 0.0.6)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4)
- ruby-progressbar (1.6.1)
+ ruby-progressbar (1.7.0)
ruby2ruby (2.1.3)
ruby_parser (~> 3.1)
sexp_processor (~> 4.0)
@@ -341,7 +341,7 @@ GEM
tilt (1.4.1)
timers (4.0.1)
hitimes
- tinymce-rails (4.1.5)
+ tinymce-rails (4.1.6)
railties (>= 3.1.1)
tinymce-rails-langs (4.20140129)
tinymce-rails (~> 4.0)
@@ -393,6 +393,7 @@ DEPENDENCIES
guard-minitest
guard-rubocop
haml-rails
+ has_scope
http_accept_language
i18n-active_record!
jbuilder (~> 2.0)
diff --git a/Guardfile b/Guardfile
index 4baac254..51b3dae4 100644
--- a/Guardfile
+++ b/Guardfile
@@ -29,7 +29,7 @@ end
notification :notifysend
-guard 'brakeman', run_on_start: true, quiet: true, min_confidence: 10 do
+guard :brakeman, run_on_start: true, quiet: true, min_confidence: 10 do
watch(%r{^app/.+\.(erb|haml|rhtml|rb)$})
watch(%r{^config/.+\.rb$})
watch(%r{^lib/.+\.rb$})
diff --git a/app/admin/dashboard.rb b/app/admin/dashboard.rb
index 9722ae48..64f86785 100644
--- a/app/admin/dashboard.rb
+++ b/app/admin/dashboard.rb
@@ -29,7 +29,7 @@ ActiveAdmin.register_page 'Dashboard' do
#{link_to(`git rev-parse --short HEAD`,
"https://gitorious.org/agenda-du-libre-rails/agenda-du-libre-rails/commit/
#{`git rev-parse HEAD`}")})
- .html_safe
+ .html_safe
end
end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index cc5d1edd..efb4d53a 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -11,4 +11,11 @@ class ApplicationController < ActionController::Base
I18n.locale = http_accept_language
.compatible_language_from I18n.available_locales
end
+
+ protected
+
+ # Useful to manage absolute url in mails
+ def set_mailer_host
+ ActionMailer::Base.default_url_options[:host] = request.host_with_port
+ end
end
diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb
index 2b7c0e34..9b458651 100644
--- a/app/controllers/events_controller.rb
+++ b/app/controllers/events_controller.rb
@@ -1,33 +1,33 @@
# Event life cycle
# This is a central part to this project
class EventsController < ApplicationController
+ has_scope :region, :locality, :tag, :daylimit
+
before_action :set_events, only: [:index]
- before_action :set_event, only:
- [:show, :edit, :preview, :update, :cancel, :destroy]
- before_action :check_secret, only:
- [:edit, :preview, :update, :cancel, :destroy]
+ before_action :set_event, except: [:index, :new, :preview_create, :create]
+ before_action :set_create_event, only: [:preview_create, :create]
+ before_action :check_secret, only: [:edit, :preview, :update, :destroy]
+ before_action :set_old_event, only: [:update]
before_action :set_mailer_host
rescue_from ActiveRecord::StaleObjectError, with: :locked
def index
respond_to do |format|
format.html { render layout: 'iframe' if params[:iframe] }
- format.rss { @events = @events.future.in params[:daylimit] }
- format.ics { @events = @events.last_year.order :id }
- format.xml { @events = @events.includes(:related_region).order :id }
+ format.rss { @events = @events.future }
+ format.ics { @events = @events.last_year }
+ format.xml { @events = @events.includes :related_region }
end
end
# GET /users/new
def new
- @event = Event.new
- @event.start_time ||= Time.now.change(min: 0) + 1.day + 1.hour
- @event.end_time ||= Time.now.change(min: 0) + 1.day + 2.hour
+ @event = Event.new start_time: Time.now.change(min: 0) + 1.day + 1.hour,
+ end_time: Time.now.change(min: 0) + 1.day + 2.hour
end
# POST /events/preview
def preview_create
- @event = Event.new event_params
@event.valid?
render action: :new
end
@@ -35,8 +35,6 @@ class EventsController < ApplicationController
# POST /events
# POST /events.json
def create
- @event = Event.new event_params
-
respond_to do |format|
if @event.save && send_creation_mails
format.html { redirect_to :root, notice: t('.ok') }
@@ -60,7 +58,6 @@ class EventsController < ApplicationController
# PATCH/PUT /events/1
# PATCH/PUT /events/1.json
def update
- @older_event = Event.new @event.attributes
respond_to do |format|
if @event.update(event_params) && send_update_mails
format.html { redirect_to :root, notice: t('.ok') }
@@ -78,7 +75,7 @@ class EventsController < ApplicationController
def destroy
@event.destroy
respond_to do |format|
- format.html { redirect_to events_url, notice: t('.ok') }
+ format.html { redirect_to :root, notice: t('.ok') }
format.json { head :no_content }
end
end
@@ -86,10 +83,7 @@ class EventsController < ApplicationController
private
def set_events
- @events = Event.moderated
- @events = @events.region params[:region] if params[:region]
- @events = @events.locality params[:locality] if params[:locality]
- @events = @events.tag params[:tag] if params[:tag]
+ @events = apply_scopes Event.moderated
end
# Use callbacks to share common setup or constraints between actions
@@ -102,6 +96,14 @@ class EventsController < ApplicationController
@event = @event.find params[:id]
end
+ def set_create_event
+ @event = Event.new event_params
+ end
+
+ def set_old_event
+ @older_event = Event.new @event.attributes
+ end
+
# Never trust parameters from the scary internet, only allow the white list
# through
def event_params
@@ -117,11 +119,6 @@ class EventsController < ApplicationController
unless params[:secret] == @event.secret
end
- # Useful to manage absolute url in mails
- def set_mailer_host
- ActionMailer::Base.default_url_options[:host] = request.host_with_port
- end
-
def send_creation_mails
# Send an event creation mail to its author
EventMailer.create(@event).deliver
diff --git a/app/controllers/maps_controller.rb b/app/controllers/maps_controller.rb
index 474bfac1..84eb53c4 100644
--- a/app/controllers/maps_controller.rb
+++ b/app/controllers/maps_controller.rb
@@ -2,16 +2,12 @@
#
# Access to OSM controls
class MapsController < ApplicationController
+ has_scope :region, :locality, :tag
+
def index
respond_to do |format|
format.html
- format.json do
- @events = Event.moderated.future.geo
- @events = @events.region params[:region] if params[:region]
- @events = @events.locality params[:locality] if params[:locality]
- @events = @events.tag params[:tag] if params[:tag]
- render json: @events
- end
+ format.json { render json: apply_scopes(Event.moderated.future.geo) }
end
end
end
diff --git a/app/controllers/moderations_controller.rb b/app/controllers/moderations_controller.rb
index 2a78bc1d..5ba4d5b2 100644
--- a/app/controllers/moderations_controller.rb
+++ b/app/controllers/moderations_controller.rb
@@ -3,6 +3,7 @@ class ModerationsController < ApplicationController
before_action :authenticate_user!
before_action :set_moderation, :set_mailer_host, only:
[:show, :edit, :preview, :update, :validate, :accept, :refuse, :destroy]
+ before_action :set_old_mod, only: [:update]
rescue_from ActiveRecord::StaleObjectError, with: :locked
def index
@@ -18,10 +19,9 @@ class ModerationsController < ApplicationController
# PATCH/PUT /moderations/1
# PATCH/PUT /moderations/1.json
def update
- @older_mod = Event.new @event.attributes
respond_to do |format|
if @moderation.update_attributes(moderation_params) && send_mails
- format.html { redirect_to moderations_url, notice: t('.ok') }
+ format.html { redirect_to :moderations, notice: t('.ok') }
format.json { head :no_content }
else
format.html { render action: 'edit' }
@@ -34,28 +34,20 @@ class ModerationsController < ApplicationController
# PATCH/PUT /accept/1
# PATCH/PUT /accept/1.json
def accept
+ @moderation.update moderated: true
+ send_accept_mails
respond_to do |format|
- if @moderation.update(moderated: true) && send_accept_mails
- tweet
- format.html { redirect_to moderations_url, notice: t('.ok') }
- format.json { head :no_content }
- else
- format.html { render action: 'edit' }
- # 422 means :unprocessable_entity
- format.json { render json: @moderation.errors, status: 422 }
- end
+ format.html { redirect_to :moderations, notice: t('.ok') }
+ format.json { head :no_content }
end
end
# DELETE /events/1
# DELETE /events/1.json
def destroy
- if @moderation.destroy && send_destroy_mails
- EventMailer.destroy(@moderation, current_user, @reason).deliver
- ModerationMailer.destroy(@moderation, current_user, @reason).deliver
- end
+ send_destroy_mails if @moderation.destroy
respond_to do |format|
- format.html { redirect_to moderations_url, notice: t('.ok') }
+ format.html { redirect_to :moderations, notice: t('.ok') }
format.json { head :no_content }
end
end
@@ -68,6 +60,10 @@ class ModerationsController < ApplicationController
@moderation = @event
end
+ def set_old_mod
+ @older_mod = Event.new @event.attributes
+ end
+
# Never trust parameters from the scary internet, only allow the white list
# through.
def moderation_params
@@ -88,6 +84,8 @@ class ModerationsController < ApplicationController
end
def send_accept_mails
+ tweet
+
# Send an acceptation mail to its author
EventMailer.accept(@moderation, current_user).deliver
@@ -113,6 +111,9 @@ class ModerationsController < ApplicationController
else
@reason = t "moderations.refuse.reason_#{params[:reason]}_long"
end
+
+ EventMailer.destroy(@moderation, current_user, @reason).deliver
+ ModerationMailer.destroy(@moderation, current_user, @reason).deliver
end
def locked
diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb
index 28f48a39..a28ce1a6 100644
--- a/app/controllers/notes_controller.rb
+++ b/app/controllers/notes_controller.rb
@@ -1,6 +1,7 @@
# Events, particulary during moderation, can have notes associated to them
class NotesController < ApplicationController
- before_action :set_event, :set_mailer_host, only: [:new, :create]
+ before_action :set_event, only: [:new, :create]
+ before_action :create_note, :set_mailer_host, only: [:create]
# GET /moderations/id/new
def new
@@ -8,14 +9,12 @@ class NotesController < ApplicationController
end
def create
- @note = @moderation.notes.new note_params.merge author: current_user
-
respond_to do |format|
if @note.save && send_mails
format.html { redirect_to moderations_url, notice: t('.ok') }
format.json { render action: :show, status: :created, location: @event }
else
- format.html { render action: 'new' }
+ format.html { render action: :new }
format.json { render json: @note.errors, status: :unprocessable_entity }
end
end
@@ -29,6 +28,10 @@ class NotesController < ApplicationController
@moderation = @event
end
+ def create_note
+ @note = @moderation.notes.new note_params.merge author: current_user
+ end
+
# Never trust parameters from the scary internet, only allow the white list
# through.
def note_params
diff --git a/app/controllers/regions_controller.rb b/app/controllers/regions_controller.rb
index e18ebae2..8b465953 100644
--- a/app/controllers/regions_controller.rb
+++ b/app/controllers/regions_controller.rb
@@ -1,32 +1,3 @@
# Manage regions, mostly get stats out of them
class RegionsController < InheritedResources::Base
- def stats
- @region_events = Event.joins(:related_region).group(:name)
- .order('count(name) desc').count :name
-
- @city_events = Event.group(:city).having('count(city) > 3')
- .order('count(city) desc').count :city
-
- @year_events = Event.group(year_grouping).count
-
- @month_events = Event.group(year_grouping, month_grouping).count
- end
-
- private
-
- def year_grouping
- if %w(Mysql2 MySQL PostgreSQL).include? Event.connection.adapter_name
- 'extract(year from start_time)'
- elsif Event.connection.adapter_name == 'SQLite'
- 'strftime("%Y", start_time)'
- end
- end
-
- def month_grouping
- if %w(Mysql2 MySQL PostgreSQL).include? Event.connection.adapter_name
- 'extract(month from start_time)'
- elsif Event.connection.adapter_name == 'SQLite'
- 'strftime("%m", start_time)'
- end
- end
end
diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb
new file mode 100644
index 00000000..84fad600
--- /dev/null
+++ b/app/controllers/stats_controller.rb
@@ -0,0 +1,34 @@
+# Generate statistics, around events, by date or place
+class StatsController < ApplicationController
+ before_action :set_temporal, :set_local, only: [:index]
+
+ private
+
+ def set_temporal
+ @year_events = Event.group(year_grouping).count
+ @month_events = Event.group(year_grouping, month_grouping).count
+ end
+
+ def set_local
+ @region_events = Event.joins(:related_region).group(:name)
+ .order('count(name) desc').count
+ @city_events = Event.group(:city).having('count(city) > 3')
+ .order('count(city) desc').count
+ end
+
+ def year_grouping
+ if %w(Mysql2 MySQL PostgreSQL).include? Event.connection.adapter_name
+ 'extract(year from start_time)'
+ elsif Event.connection.adapter_name == 'SQLite'
+ 'strftime("%Y", start_time)'
+ end
+ end
+
+ def month_grouping
+ if %w(Mysql2 MySQL PostgreSQL).include? Event.connection.adapter_name
+ 'extract(month from start_time)'
+ elsif Event.connection.adapter_name == 'SQLite'
+ 'strftime("%m", start_time)'
+ end
+ end
+end
diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb
index 1964b2a9..9c310542 100644
--- a/app/controllers/tags_controller.rb
+++ b/app/controllers/tags_controller.rb
@@ -2,15 +2,15 @@
class TagsController < InheritedResources::Base
def index
@tags = Event
- .pluck(:tags).map(&:split).flatten
- .group_by { |i| i }
- .map { |k, v| [k, v.size] }
- .reject { |_k, v| v <= 3 }
- .sort
+ .pluck(:tags).map(&:split).flatten
+ .group_by { |i| i }
+ .map { |k, v| [k, v.size] }
+ .reject { |_k, v| v <= 3 }
+ .sort
respond_to do |format|
format.html
- format.json { render json: @tags.to_json }
+ format.json { render json: @tags }
end
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index da97cb1e..7c9aee9e 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -26,17 +26,25 @@ module EventsHelper
def display_date(event = @event)
if event.start_time.to_date == event.end_time.to_date
- t 'date.formats.same_day',
- date: l(event.start_time.to_date, format: :long),
- start: l(event.start_time, format: :hours),
- end: l(event.end_time, format: :hours)
+ display_sameday event
else
- t 'date.formats.period',
- start: l(event.start_time, format: :at),
- end: l(event.end_time, format: :at)
+ display_multi_days event
end
end
+ def display_sameday(event)
+ t 'date.formats.same_day',
+ date: l(event.start_time.to_date, format: :long),
+ start: l(event.start_time, format: :hours),
+ end: l(event.end_time, format: :hours)
+ end
+
+ def display_multi_days(event)
+ t 'date.formats.period',
+ start: l(event.start_time, format: :at),
+ end: l(event.end_time, format: :at)
+ end
+
def wrap(s, width = 78)
s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 321980c2..bc198d21 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -29,7 +29,7 @@ class Event < ActiveRecord::Base
scope :last_year, -> { where '? <= end_time', 1.year.ago }
scope :past, -> { where 'start_time <= ?', DateTime.now }
scope :future, -> { where '? <= end_time', DateTime.now }
- scope :in, -> days { where 'end_time <= ?', (days || 30).to_i.days.from_now }
+ scope :daylimit, -> d { where 'end_time <= ?', (d || 30).to_i.days.from_now }
scope :year, (lambda do |year|
where '? <= end_time and start_time <= ?',
Date.new(year, 1, 1).beginning_of_week,
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 3121a981..f934cfde 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -57,7 +57,7 @@
= link_to application_infos_path do
%em.fa.fa-info
=t '.infos'
- = link_to stats_regions_path do
+ = link_to stats_path do
%em.fa.fa-signal
=t '.stats'
= link_to application_contact_path do
diff --git a/app/views/regions/stats.html.haml b/app/views/stats/index.html.haml
similarity index 100%
rename from app/views/regions/stats.html.haml
rename to app/views/stats/index.html.haml
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index ac3ecacb..90c72653 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -138,7 +138,8 @@ it more readable or agreable.
Example: `%{tag}`
\n* You can modify the 30 days limit with the parameter `daylimit`. \n
Example: `%{daylimit}`"
- stats:
+ stats:
+ index:
title: Statistics
all: Validated events
allModeration: Events waiting for validation
diff --git a/config/locales/views/fr.yml b/config/locales/views/fr.yml
index 3768e385..fe925ec3 100644
--- a/config/locales/views/fr.yml
+++ b/config/locales/views/fr.yml
@@ -136,7 +136,8 @@ fr:
* Vous pouvez modifier la limite des 30 prochains jours des flux en
utilisant le paramètre `daylimit`. \n
Exemple: `%{daylimit}`"
- stats:
+ stats:
+ index:
title: Statistiques
all: Événements validés
allModeration: Événements en cours de modération
diff --git a/config/routes.rb b/config/routes.rb
index c282a348..120befa6 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -2,6 +2,7 @@ Rails.application.routes.draw do
get 'application/infos'
get 'application/contact'
get 'application/rules'
+ get 'stats', to: 'stats#index'
resources :users
resources :events do
@@ -15,9 +16,7 @@ Rails.application.routes.draw do
get :validate, :refuse, on: :member
put :accept, on: :member
end
- resources :regions, only: [:index] do
- get 'stats', on: :collection
- end
+ resources :regions, only: [:index]
resources :tags, only: [:index, :show]
resources :maps, only: [:index]
resources :lugs, only: [:index, :show]
diff --git a/deploy/before_restart b/deploy/before_restart
index 9fe8a96c..32593e3c 100755
--- a/deploy/before_restart
+++ b/deploy/before_restart
@@ -29,7 +29,7 @@ if File.file? 'Rakefile'
# precompile assets
changed_assets = `git diff #{oldrev} #{newrev} --name-only -z app/assets`
- .split("\0")
+ .split("\0")
tasks << 'assets:precompile' if changed_assets.size > 0
run "#{rake_cmd} #{tasks.join(' ')} RAILS_ENV=#{RAILS_ENV}" if tasks.any?
diff --git a/public/webshims/polyfiller.js b/public/webshims/polyfiller.js
index 528ace81..fe1c75f8 100644
--- a/public/webshims/polyfiller.js
+++ b/public/webshims/polyfiller.js
@@ -119,6 +119,7 @@
promise: 'es6',
URL: 'url'
};
+ var supportCapture = 'capture' in create('input');
clearInterval(webshims.timer);
support.advancedObjectProperties = support.objectAccessor = support.ES5 = !!('create' in Object && 'seal' in Object);
@@ -136,7 +137,7 @@
}
$.extend(webshims, {
- version: '1.15.3',
+ version: '1.15.4',
cfg: {
enhanceAuto: window.Audio && (!window.matchMedia || matchMedia('(min-device-width: 721px)').matches),
@@ -212,11 +213,13 @@
})(),
_polyfill: function(features){
var toLoadFeatures = [];
- var hasFormsExt;
+ var hasFormsExt, needExtStyles;
if(!firstRun.run){
hasFormsExt = $.inArray('forms-ext', features) !== -1;
firstRun();
+ needExtStyles = (hasFormsExt && !modules["form-number-date-ui"].test()) || (!supportCapture && $.inArray('mediacapture', features) !== -1);
+
if(hasFormsExt && $.inArray('forms', features) == -1){
features.push('forms');
if(WSDEBUG){
@@ -224,7 +227,7 @@
}
}
if(webCFG.loadStyles){
- loader.loadCSS('styles/shim'+((hasFormsExt && !modules["form-number-date-ui"].test()) ? '-ext' : '')+'.css');
+ loader.loadCSS('styles/shim'+(needExtStyles ? '-ext' : '')+'.css');
}
}
@@ -922,7 +925,7 @@
//
- //
-
//
+ //
+
+ //
+
+
//
- /*
- //
- */
-
//= 12){
@@ -2432,6 +2441,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
createFormat('d');
var tmp, obj;
var ret = '';
+
if(opts.splitInput){
obj = {yy: 0, mm: 1, dd: 2};
} else {
@@ -2453,8 +2463,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
}
ret = ([addZero(val[obj.yy]), addZero(val[obj.mm]), addZero(val[obj.dd])]).join('-');
}
- return ret
- ;
+ return ret;
},
color: function(val, opts){
var ret = '#000000';
@@ -2756,9 +2765,11 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
};
['defaultValue', 'value'].forEach(function(name){
+ var formatName = 'format'+name;
wsWidgetProto[name] = function(val, force){
- if(!this._init || force || val !== this.options[name]){
- this.element.prop(name, this.formatValue(val));
+ if(!this._init || force || val !== this.options[name] || this.options[formatName] != this.element.prop(name)){
+ this.options[formatName] = this.formatValue(val);
+ this.element.prop(name, this.options[formatName]);
this.options[name] = val;
this._propertyChange(name);
this.mirrorValidity();
@@ -2882,36 +2893,34 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
var isValue = name == 'value';
spinBtnProto[name] = function(val, force, isLive){
var selectionEnd;
- if(!this._init || force || this.options[name] !== val){
- if(isValue){
- this._beforeValue(val);
- } else {
- this.elemHelper.prop(name, val);
- }
-
- val = formatVal[this.type](val, this.options);
- if(this.options.splitInput){
- $.each(this.splits, function(i, elem){
- var setOption;
- if(!(name in elem) && !isValue && $.nodeName(elem, 'select')){
- $('option[value="'+ val[i] +'"]', elem).prop('defaultSelected', true);
- } else {
- $.prop(elem, name, val[i]);
- }
- });
- } else {
- val = this.toFixed(val);
- if(isLive && this._getSelectionEnd){
- selectionEnd = this._getSelectionEnd(val);
- }
- this.element.prop(name, val);
- if(selectionEnd != null){
- this.element.prop('selectionEnd', selectionEnd);
- }
- }
- this._propertyChange(name);
- this.mirrorValidity();
+ if(isValue){
+ this._beforeValue(val);
+ } else {
+ this.elemHelper.prop(name, val);
}
+
+ val = formatVal[this.type](val, this.options);
+ if(this.options.splitInput){
+ $.each(this.splits, function(i, elem){
+ var setOption;
+ if(!(name in elem) && !isValue && $.nodeName(elem, 'select')){
+ $('option[value="'+ val[i] +'"]', elem).prop('defaultSelected', true);
+ } else {
+ $.prop(elem, name, val[i]);
+ }
+ });
+ } else {
+ val = this.toFixed(val);
+ if(isLive && this._getSelectionEnd){
+ selectionEnd = this._getSelectionEnd(val);
+ }
+ this.element.prop(name, val);
+ if(selectionEnd != null){
+ this.element.prop('selectionEnd', selectionEnd);
+ }
+ }
+ this._propertyChange(name);
+ this.mirrorValidity();
};
});
diff --git a/public/webshims/shims/combos/11.js b/public/webshims/shims/combos/11.js
index b837903c..53cf8165 100644
--- a/public/webshims/shims/combos/11.js
+++ b/public/webshims/shims/combos/11.js
@@ -1044,9 +1044,13 @@
},
time: function(val, o, noCorrect){
var fVal, i;
+
if(val){
val = val.split(':');
+ if(val.length != 2 || isNaN(parseInt(val[0] || '', 10)) || isNaN(parseInt(val[1] || '', 10))){
+ return val.join(':');
+ }
if(curCfg.meridian){
fVal = (val[0] * 1);
if(fVal && fVal >= 12){
@@ -1201,6 +1205,7 @@
createFormat('d');
var tmp, obj;
var ret = '';
+
if(opts.splitInput){
obj = {yy: 0, mm: 1, dd: 2};
} else {
@@ -1222,8 +1227,7 @@
}
ret = ([addZero(val[obj.yy]), addZero(val[obj.mm]), addZero(val[obj.dd])]).join('-');
}
- return ret
- ;
+ return ret;
},
color: function(val, opts){
var ret = '#000000';
@@ -1525,9 +1529,11 @@
};
['defaultValue', 'value'].forEach(function(name){
+ var formatName = 'format'+name;
wsWidgetProto[name] = function(val, force){
- if(!this._init || force || val !== this.options[name]){
- this.element.prop(name, this.formatValue(val));
+ if(!this._init || force || val !== this.options[name] || this.options[formatName] != this.element.prop(name)){
+ this.options[formatName] = this.formatValue(val);
+ this.element.prop(name, this.options[formatName]);
this.options[name] = val;
this._propertyChange(name);
this.mirrorValidity();
@@ -1651,36 +1657,34 @@
var isValue = name == 'value';
spinBtnProto[name] = function(val, force, isLive){
var selectionEnd;
- if(!this._init || force || this.options[name] !== val){
- if(isValue){
- this._beforeValue(val);
- } else {
- this.elemHelper.prop(name, val);
- }
-
- val = formatVal[this.type](val, this.options);
- if(this.options.splitInput){
- $.each(this.splits, function(i, elem){
- var setOption;
- if(!(name in elem) && !isValue && $.nodeName(elem, 'select')){
- $('option[value="'+ val[i] +'"]', elem).prop('defaultSelected', true);
- } else {
- $.prop(elem, name, val[i]);
- }
- });
- } else {
- val = this.toFixed(val);
- if(isLive && this._getSelectionEnd){
- selectionEnd = this._getSelectionEnd(val);
- }
- this.element.prop(name, val);
- if(selectionEnd != null){
- this.element.prop('selectionEnd', selectionEnd);
- }
- }
- this._propertyChange(name);
- this.mirrorValidity();
+ if(isValue){
+ this._beforeValue(val);
+ } else {
+ this.elemHelper.prop(name, val);
}
+
+ val = formatVal[this.type](val, this.options);
+ if(this.options.splitInput){
+ $.each(this.splits, function(i, elem){
+ var setOption;
+ if(!(name in elem) && !isValue && $.nodeName(elem, 'select')){
+ $('option[value="'+ val[i] +'"]', elem).prop('defaultSelected', true);
+ } else {
+ $.prop(elem, name, val[i]);
+ }
+ });
+ } else {
+ val = this.toFixed(val);
+ if(isLive && this._getSelectionEnd){
+ selectionEnd = this._getSelectionEnd(val);
+ }
+ this.element.prop(name, val);
+ if(selectionEnd != null){
+ this.element.prop('selectionEnd', selectionEnd);
+ }
+ }
+ this._propertyChange(name);
+ this.mirrorValidity();
};
});
diff --git a/public/webshims/shims/combos/12.js b/public/webshims/shims/combos/12.js
index a497911c..22bcef70 100644
--- a/public/webshims/shims/combos/12.js
+++ b/public/webshims/shims/combos/12.js
@@ -893,10 +893,11 @@ webshims.register('mediaelement-core', function($, webshims, window, document, u
var copyName = {srclang: 'language'};
var updateMediaTrackList = function(baseData, trackList){
+ var i, len;
+ var callChange = false;
var removed = [];
var added = [];
var newTracks = [];
- var i, len;
if(!baseData){
baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {});
}
@@ -931,12 +932,13 @@ webshims.register('mediaelement-core', function($, webshims, window, document, u
removed.push(trackList[i]);
}
}
-
+
if(removed.length || added.length){
trackList.splice(0);
for(i = 0, len = newTracks.length; i < len; i++){
trackList.push(newTracks[i]);
+
}
for(i = 0, len = removed.length; i < len; i++){
$([trackList]).triggerHandler($.Event({type: 'removetrack', track: removed[i]}));
@@ -949,6 +951,16 @@ webshims.register('mediaelement-core', function($, webshims, window, document, u
$(this).triggerHandler('updatetrackdisplay');
}
}
+
+ for(i = 0, len = trackList.length; i < len; i++){
+ if(trackList[i].__wsmode != trackList[i].mode){
+ trackList[i].__wsmode = trackList[i].mode;
+ callChange = true;
+ }
+ }
+ if(callChange){
+ $([trackList]).triggerHandler('change');
+ }
};
var refreshTrack = function(track, trackData){
diff --git a/public/webshims/shims/combos/13.js b/public/webshims/shims/combos/13.js
index 12cb9955..28fc13ac 100644
--- a/public/webshims/shims/combos/13.js
+++ b/public/webshims/shims/combos/13.js
@@ -670,10 +670,11 @@ webshims.register('mediaelement-core', function($, webshims, window, document, u
var copyName = {srclang: 'language'};
var updateMediaTrackList = function(baseData, trackList){
+ var i, len;
+ var callChange = false;
var removed = [];
var added = [];
var newTracks = [];
- var i, len;
if(!baseData){
baseData = webshims.data(this, 'mediaelementBase') || webshims.data(this, 'mediaelementBase', {});
}
@@ -708,12 +709,13 @@ webshims.register('mediaelement-core', function($, webshims, window, document, u
removed.push(trackList[i]);
}
}
-
+
if(removed.length || added.length){
trackList.splice(0);
for(i = 0, len = newTracks.length; i < len; i++){
trackList.push(newTracks[i]);
+
}
for(i = 0, len = removed.length; i < len; i++){
$([trackList]).triggerHandler($.Event({type: 'removetrack', track: removed[i]}));
@@ -726,6 +728,16 @@ webshims.register('mediaelement-core', function($, webshims, window, document, u
$(this).triggerHandler('updatetrackdisplay');
}
}
+
+ for(i = 0, len = trackList.length; i < len; i++){
+ if(trackList[i].__wsmode != trackList[i].mode){
+ trackList[i].__wsmode = trackList[i].mode;
+ callChange = true;
+ }
+ }
+ if(callChange){
+ $([trackList]).triggerHandler('change');
+ }
};
var refreshTrack = function(track, trackData){
diff --git a/public/webshims/shims/combos/15.js b/public/webshims/shims/combos/15.js
index 4bb2d83d..741a9c8b 100644
--- a/public/webshims/shims/combos/15.js
+++ b/public/webshims/shims/combos/15.js
@@ -102,20 +102,25 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
};
//jquery mobile and jquery ui
- if(!$.widget){
+ if(!$.widget && (!$.pluginFactory || !$.pluginFactory.mixin)){
(function(){
var _cleanData = $.cleanData;
- $.cleanData = function( elems ) {
- if(!$.widget){
- for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ $.cleanData = (function( orig ) {
+ return function( elems ) {
+ var events, elem, i;
+ for ( i = 0; (elem = elems[i]) != null; i++ ) {
try {
- $( elem ).triggerHandler( "remove" );
- // http://bugs.jquery.com/ticket/8235
- } catch( e ) {}
+ // Only trigger remove when necessary to save time
+ events = $._data( elem, "events" );
+ if ( events && events.remove ) {
+ $( elem ).triggerHandler( "remove" );
+ }
+ // http://bugs.jquery.com/ticket/8235
+ } catch ( e ) {}
}
- }
- _cleanData( elems );
- };
+ orig( elems );
+ };
+ })( $.cleanData );
})();
}
@@ -536,7 +541,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
return id;
};
})(),
- domPrefixes: ["ws", "webkit", "moz", "ms", "o"],
+ domPrefixes: ["webkit", "moz", "ms", "o", "ws"],
prefixed: function (prop, obj){
var i, testProp;
@@ -1487,6 +1492,8 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
}
return message || '';
};
+
+ webshims.refreshCustomValidityRules = $.noop;
$.fn.getErrorMessage = function(key){
var message = '';
@@ -2149,22 +2156,25 @@ if(webshims.support.inputtypes.date && /webkit/i.test(navigator.userAgent)){
webshims.addReady(function(context, contextElem){
//start constrain-validation
- var focusElem;
+
$('form', context)
.add(contextElem.filter('form'))
.on('invalid', $.noop)
;
-
- try {
- if(context == document && !('form' in (document.activeElement || {}))) {
- focusElem = $(context.querySelector('input[autofocus], select[autofocus], textarea[autofocus]')).eq(0).getShadowFocusElement()[0];
- if (focusElem && focusElem.offsetHeight && focusElem.offsetWidth) {
- focusElem.focus();
+
+ setTimeout(function(){
+ var focusElem;
+ try {
+ if(!('form' in (document.activeElement || {}))) {
+ focusElem = $(context.querySelector('input[autofocus], select[autofocus], textarea[autofocus]')).eq(0).getShadowFocusElement()[0];
+ if (focusElem && (focusElem.offsetHeight || focusElem.offsetWidth)) {
+ focusElem.focus();
+ }
}
}
- }
- catch (er) {}
-
+ catch (er) {}
+ }, 9);
+
});
if(!webshims.support.datalist){
diff --git a/public/webshims/shims/combos/16.js b/public/webshims/shims/combos/16.js
index 6d835b00..dcf1e2f8 100644
--- a/public/webshims/shims/combos/16.js
+++ b/public/webshims/shims/combos/16.js
@@ -325,20 +325,25 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
};
//jquery mobile and jquery ui
- if(!$.widget){
+ if(!$.widget && (!$.pluginFactory || !$.pluginFactory.mixin)){
(function(){
var _cleanData = $.cleanData;
- $.cleanData = function( elems ) {
- if(!$.widget){
- for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ $.cleanData = (function( orig ) {
+ return function( elems ) {
+ var events, elem, i;
+ for ( i = 0; (elem = elems[i]) != null; i++ ) {
try {
- $( elem ).triggerHandler( "remove" );
- // http://bugs.jquery.com/ticket/8235
- } catch( e ) {}
+ // Only trigger remove when necessary to save time
+ events = $._data( elem, "events" );
+ if ( events && events.remove ) {
+ $( elem ).triggerHandler( "remove" );
+ }
+ // http://bugs.jquery.com/ticket/8235
+ } catch ( e ) {}
}
- }
- _cleanData( elems );
- };
+ orig( elems );
+ };
+ })( $.cleanData );
})();
}
@@ -759,7 +764,7 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
return id;
};
})(),
- domPrefixes: ["ws", "webkit", "moz", "ms", "o"],
+ domPrefixes: ["webkit", "moz", "ms", "o", "ws"],
prefixed: function (prop, obj){
var i, testProp;
@@ -1710,6 +1715,8 @@ webshims.register('dom-extend', function($, webshims, window, document, undefine
}
return message || '';
};
+
+ webshims.refreshCustomValidityRules = $.noop;
$.fn.getErrorMessage = function(key){
var message = '';
@@ -2372,22 +2379,25 @@ if(webshims.support.inputtypes.date && /webkit/i.test(navigator.userAgent)){
webshims.addReady(function(context, contextElem){
//start constrain-validation
- var focusElem;
+
$('form', context)
.add(contextElem.filter('form'))
.on('invalid', $.noop)
;
-
- try {
- if(context == document && !('form' in (document.activeElement || {}))) {
- focusElem = $(context.querySelector('input[autofocus], select[autofocus], textarea[autofocus]')).eq(0).getShadowFocusElement()[0];
- if (focusElem && focusElem.offsetHeight && focusElem.offsetWidth) {
- focusElem.focus();
+
+ setTimeout(function(){
+ var focusElem;
+ try {
+ if(!('form' in (document.activeElement || {}))) {
+ focusElem = $(context.querySelector('input[autofocus], select[autofocus], textarea[autofocus]')).eq(0).getShadowFocusElement()[0];
+ if (focusElem && (focusElem.offsetHeight || focusElem.offsetWidth)) {
+ focusElem.focus();
+ }
}
}
- }
- catch (er) {}
-
+ catch (er) {}
+ }, 9);
+
});
if(!webshims.support.datalist){
diff --git a/public/webshims/shims/combos/17.js b/public/webshims/shims/combos/17.js
index cd7e1c39..0f7d0c4e 100644
--- a/public/webshims/shims/combos/17.js
+++ b/public/webshims/shims/combos/17.js
@@ -1660,9 +1660,13 @@ webshims.register('form-number-date-api', function($, webshims, window, document
},
time: function(val, o, noCorrect){
var fVal, i;
+
if(val){
val = val.split(':');
+ if(val.length != 2 || isNaN(parseInt(val[0] || '', 10)) || isNaN(parseInt(val[1] || '', 10))){
+ return val.join(':');
+ }
if(curCfg.meridian){
fVal = (val[0] * 1);
if(fVal && fVal >= 12){
@@ -1817,6 +1821,7 @@ webshims.register('form-number-date-api', function($, webshims, window, document
createFormat('d');
var tmp, obj;
var ret = '';
+
if(opts.splitInput){
obj = {yy: 0, mm: 1, dd: 2};
} else {
@@ -1838,8 +1843,7 @@ webshims.register('form-number-date-api', function($, webshims, window, document
}
ret = ([addZero(val[obj.yy]), addZero(val[obj.mm]), addZero(val[obj.dd])]).join('-');
}
- return ret
- ;
+ return ret;
},
color: function(val, opts){
var ret = '#000000';
@@ -2141,9 +2145,11 @@ webshims.register('form-number-date-api', function($, webshims, window, document
};
['defaultValue', 'value'].forEach(function(name){
+ var formatName = 'format'+name;
wsWidgetProto[name] = function(val, force){
- if(!this._init || force || val !== this.options[name]){
- this.element.prop(name, this.formatValue(val));
+ if(!this._init || force || val !== this.options[name] || this.options[formatName] != this.element.prop(name)){
+ this.options[formatName] = this.formatValue(val);
+ this.element.prop(name, this.options[formatName]);
this.options[name] = val;
this._propertyChange(name);
this.mirrorValidity();
@@ -2267,36 +2273,34 @@ webshims.register('form-number-date-api', function($, webshims, window, document
var isValue = name == 'value';
spinBtnProto[name] = function(val, force, isLive){
var selectionEnd;
- if(!this._init || force || this.options[name] !== val){
- if(isValue){
- this._beforeValue(val);
- } else {
- this.elemHelper.prop(name, val);
- }
-
- val = formatVal[this.type](val, this.options);
- if(this.options.splitInput){
- $.each(this.splits, function(i, elem){
- var setOption;
- if(!(name in elem) && !isValue && $.nodeName(elem, 'select')){
- $('option[value="'+ val[i] +'"]', elem).prop('defaultSelected', true);
- } else {
- $.prop(elem, name, val[i]);
- }
- });
- } else {
- val = this.toFixed(val);
- if(isLive && this._getSelectionEnd){
- selectionEnd = this._getSelectionEnd(val);
- }
- this.element.prop(name, val);
- if(selectionEnd != null){
- this.element.prop('selectionEnd', selectionEnd);
- }
- }
- this._propertyChange(name);
- this.mirrorValidity();
+ if(isValue){
+ this._beforeValue(val);
+ } else {
+ this.elemHelper.prop(name, val);
}
+
+ val = formatVal[this.type](val, this.options);
+ if(this.options.splitInput){
+ $.each(this.splits, function(i, elem){
+ var setOption;
+ if(!(name in elem) && !isValue && $.nodeName(elem, 'select')){
+ $('option[value="'+ val[i] +'"]', elem).prop('defaultSelected', true);
+ } else {
+ $.prop(elem, name, val[i]);
+ }
+ });
+ } else {
+ val = this.toFixed(val);
+ if(isLive && this._getSelectionEnd){
+ selectionEnd = this._getSelectionEnd(val);
+ }
+ this.element.prop(name, val);
+ if(selectionEnd != null){
+ this.element.prop('selectionEnd', selectionEnd);
+ }
+ }
+ this._propertyChange(name);
+ this.mirrorValidity();
};
});
diff --git a/public/webshims/shims/combos/18.js b/public/webshims/shims/combos/18.js
index 9f38e644..a6542797 100644
--- a/public/webshims/shims/combos/18.js
+++ b/public/webshims/shims/combos/18.js
@@ -1,580 +1,440 @@
-webshim.ready('matchMedia', function($, webshim, w, doc, undefined){
- try {
- new Image();
- } catch(e){
- window.Image = function(){
- return document.createElement('img');
- };
+/*! respimage - v0.9.5 - 2014-10-22
+ Licensed MIT */
+!function(window, document, undefined) {
+ "use strict";
+ function trim(str) {
+ return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, "");
}
- webshim.isReady('picture', true);
-// Enable strict mode
+ function updateView() {
+ isVwDirty = !1, ri.vW = window.innerWidth || Math.max(docElem.offsetWidth || 0, docElem.clientWidth || 0),
+ vH = window.innerHeight || Math.max(docElem.offsetHeight || 0, docElem.clientHeight || 0);
+ }
+ function parseDescriptor(descriptor) {
+ if (!(descriptor in memDescriptor)) {
+ var descriptorObj = {
+ val: 1,
+ type: "x"
+ }, parsedDescriptor = trim(descriptor || "");
+ parsedDescriptor && (parsedDescriptor.match(regDescriptor) ? (descriptorObj.val = 1 * RegExp.$1,
+ descriptorObj.type = RegExp.$2) : descriptorObj = !1), memDescriptor[descriptor] = descriptorObj;
+ }
+ return memDescriptor[descriptor];
+ }
+ function chooseLowRes(lowRes, diff, dpr) {
+ return lowRes / dpr > .2 && (lowRes += diff * greed, diff > tHigh && (lowRes += tLow)),
+ lowRes > dpr;
+ }
+ function inView(el) {
+ if (!el.getBoundingClientRect) return !0;
+ var bottom, right, left, top, rect = el.getBoundingClientRect();
+ return !!((bottom = rect.bottom) >= -9 && (top = rect.top) <= vH + 9 && (right = rect.right) >= -9 && (left = rect.left) <= ri.vW + 9 && (bottom || right || left || top));
+ }
+ function applyBestCandidate(img) {
+ var srcSetCandidates, matchingSet = ri.getSet(img), evaluated = !1;
+ "pending" != matchingSet && (evaluated = !0, matchingSet && (srcSetCandidates = ri.setRes(matchingSet),
+ evaluated = ri.applySetCandidate(srcSetCandidates, img))), img[ri.ns].evaled = evaluated;
+ }
+ function ascendingSort(a, b) {
+ return a.res - b.res;
+ }
+ function setSrcToCur(img, src, set) {
+ var candidate;
+ return !set && src && (set = img[ri.ns].sets, set = set && set[set.length - 1]),
+ candidate = getCandidateForSrc(src, set), candidate && (src = ri.makeUrl(src), img[ri.ns].curSrc = src,
+ img[ri.ns].curCan = candidate, currentSrcSupported || (img.currentSrc = src), candidate.res || setResolution(candidate, candidate.set.sizes)),
+ candidate;
+ }
+ function getCandidateForSrc(src, set) {
+ var i, candidate, candidates;
+ if (src && set) for (candidates = ri.parseSet(set), src = ri.makeUrl(src), i = 0; i < candidates.length; i++) if (src == ri.makeUrl(candidates[i].url)) {
+ candidate = candidates[i];
+ break;
+ }
+ return candidate;
+ }
+ function hasOneX(set) {
+ var i, ret, candidates, desc;
+ if (set) for (candidates = ri.parseSet(set), i = 0; i < candidates.length; i++) if (desc = candidates[i].desc,
+ "x" == desc.type && 1 == desc.val) {
+ ret = !0;
+ break;
+ }
+ return ret;
+ }
+ function hasWDescripor(set) {
+ if (!set) return !1;
+ var candidates = ri.parseSet(set);
+ return candidates[0] && "w" == candidates[0].desc.type;
+ }
+ function getAllSourceElements(picture, candidates) {
+ var i, len, source, srcset, sources = picture.getElementsByTagName("source");
+ for (i = 0, len = sources.length; len > i; i++) source = sources[i], source[ri.ns] = !0,
+ srcset = source.getAttribute("srcset"), srcset && candidates.push({
+ srcset: srcset,
+ media: source.getAttribute("media"),
+ type: source.getAttribute("type"),
+ sizes: source.getAttribute("sizes")
+ });
+ }
+ function setResolution(candidate, sizesattr) {
+ var descriptor = candidate.desc;
+ return "w" == descriptor.type ? (candidate.cWidth = ri.calcListLength(sizesattr || "100vw"),
+ candidate.res = descriptor.val / candidate.cWidth) : candidate.res = descriptor.val,
+ candidate;
+ }
+ document.createElement("picture");
+ var lengthElInstered, lengthEl, currentSrcSupported, curSrcProp, ri = {}, noop = function() {}, image = document.createElement("img"), getImgAttr = image.getAttribute, setImgAttr = image.setAttribute, removeImgAttr = image.removeAttribute, docElem = document.documentElement, types = {}, cfg = {
+ addSize: !1,
+ xQuant: 1,
+ tLow: .1,
+ tHigh: .5,
+ tLazy: .1,
+ greed: .32
+ }, srcAttr = "data-risrc", srcsetAttr = srcAttr + "set";
+ ri.ns = ("ri" + new Date().getTime()).substr(0, 9), currentSrcSupported = "currentSrc" in image,
+ curSrcProp = currentSrcSupported ? "currentSrc" : "src", ri.supSrcset = "srcset" in image,
+ ri.supSizes = "sizes" in image, ri.selShort = "picture > img, img[srcset]", ri.sel = ri.selShort,
+ ri.cfg = cfg, ri.supSrcset && (ri.sel += ", img[" + srcsetAttr + "]");
+ var anchor = document.createElement("a");
+ ri.makeUrl = function(src) {
+ return anchor.href = src, anchor.href;
+ }, ri.qsa = function(context, sel) {
+ return context.querySelectorAll(sel);
+ };
+ {
+ var on = (window.console && "function" == typeof console.warn ? function(message) {
+ console.warn(message);
+ } : noop, function(obj, evt, fn, capture) {
+ obj.addEventListener ? obj.addEventListener(evt, fn, capture || !1) : obj.attachEvent && obj.attachEvent("on" + evt, fn);
+ }), off = function(obj, evt, fn, capture) {
+ obj.removeEventListener ? obj.removeEventListener(evt, fn, capture || !1) : obj.detachEvent && obj.detachEvent("on" + evt, fn);
+ };
+ "https:" == location.protocol;
+ }
+ ri.matchesMedia = function() {
+ return ri.matchesMedia = window.matchMedia && (matchMedia("(min-width: 0.1em)") || {}).matches ? function(media) {
+ return !media || matchMedia(media).matches;
+ } : ri.mMQ, ri.matchesMedia.apply(this, arguments);
+ }, ri.vW = 0;
+ var vH, isVwDirty = !0, regex = {
+ minw: /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,
+ maxw: /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/
+ }, mediaCache = {};
+ ri.mMQ = function(media) {
+ var min, max, ret = !1;
+ return media ? (mediaCache[media] || (min = media.match(regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
+ max = media.match(regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""), min && (min = parseFloat(min, 10) * (min.indexOf("em") > 0 ? ri.getEmValue() : 1)),
+ max && (max = parseFloat(max, 10) * (max.indexOf("em") > 0 ? ri.getEmValue() : 1)),
+ mediaCache[media] = {
+ min: min,
+ max: max
+ }), min = mediaCache[media].min, max = mediaCache[media].max, (min && ri.vW >= min || max && ri.vW <= max) && (ret = !0),
+ ret) : !0;
+ }, ri.DPR = window.devicePixelRatio || 1;
+ var lengthCache = {}, regLength = /^([\d\.]+)(em|vw|px)$/, baseStyle = "position:absolute;left:0;visibility:hidden;display:block;padding:0;border:none;font-size:1em;width:1em;";
+ ri.calcLength = function(sourceSizeValue) {
+ var failed, parsedLength, orirgValue = sourceSizeValue, value = !1;
+ if (!(orirgValue in lengthCache)) {
+ if (parsedLength = sourceSizeValue.match(regLength)) parsedLength[1] = parseFloat(parsedLength[1], 10),
+ value = parsedLength[1] ? "vw" == parsedLength[2] ? ri.vW * parsedLength[1] / 100 : "em" == parsedLength[2] ? ri.getEmValue() * parsedLength[1] : parsedLength[1] : !1; else if (sourceSizeValue.indexOf("calc") > -1 || parseInt(sourceSizeValue, 10)) {
+ sourceSizeValue = sourceSizeValue.replace("vw", "%"), lengthEl || (lengthEl = document.createElement("div"),
+ lengthEl.style.cssText = baseStyle), lengthElInstered || (lengthElInstered = !0,
+ docElem.insertBefore(lengthEl, docElem.firstChild)), lengthEl.style.width = "0px";
+ try {
+ lengthEl.style.width = sourceSizeValue;
+ } catch (e) {
+ failed = !0;
+ }
+ value = lengthEl.offsetWidth, failed && (value = !1);
+ }
+ 0 >= value && (value = !1), lengthCache[orirgValue] = value;
+ }
+ return lengthCache[orirgValue];
+ }, ri.types = types, types["image/jpeg"] = !0, types["image/gif"] = !0, types["image/png"] = !0,
+ types["image/svg+xml"] = document.implementation.hasFeature("http://wwwindow.w3.org/TR/SVG11/feature#Image", "1.1"),
+ ri.supportsType = function(type) {
+ return type ? types[type] : !0;
+ };
+ var regSize = /(\([^)]+\))?\s*(.+)/, memSize = {};
+ ri.parseSize = function(sourceSizeStr) {
+ var match;
+ return memSize[sourceSizeStr] || (match = (sourceSizeStr || "").match(regSize),
+ memSize[sourceSizeStr] = {
+ media: match && match[1],
+ length: match && match[2]
+ }), memSize[sourceSizeStr];
+ }, ri.parseSet = function(set) {
+ if (!set.cands) {
+ var pos, url, descriptor, last, descpos, srcset = set.srcset;
+ for (set.cands = []; srcset; ) srcset = srcset.replace(/^\s+/g, ""), pos = srcset.search(/\s/g),
+ descriptor = null, -1 != pos ? (url = srcset.slice(0, pos), last = url.charAt(url.length - 1),
+ "," != last && url || (url = url.replace(/,+$/, ""), descriptor = ""), srcset = srcset.slice(pos + 1),
+ null == descriptor && (descpos = srcset.indexOf(","), -1 != descpos ? (descriptor = srcset.slice(0, descpos),
+ srcset = srcset.slice(descpos + 1)) : (descriptor = srcset, srcset = ""))) : (url = srcset,
+ srcset = ""), url && (descriptor = parseDescriptor(descriptor)) && set.cands.push({
+ url: url.replace(/^,+/, ""),
+ desc: descriptor,
+ set: set
+ });
+ }
+ return set.cands;
+ };
+ var eminpx, memDescriptor = {}, regDescriptor = /^([\+eE\d\.]+)(w|x)$/, fsCss = "font-size:100% !important;";
+ ri.getEmValue = function() {
+ var body;
+ if (!eminpx && (body = document.body)) {
+ var div = document.createElement("div"), originalHTMLCSS = docElem.style.cssText, originalBodyCSS = body.style.cssText;
+ div.style.cssText = baseStyle, docElem.style.cssText = fsCss, body.style.cssText = fsCss,
+ body.appendChild(div), eminpx = div.offsetWidth, body.removeChild(div), eminpx = parseFloat(eminpx, 10),
+ docElem.style.cssText = originalHTMLCSS, body.style.cssText = originalBodyCSS;
+ }
+ return eminpx || 16;
+ };
+ var sizeLengthCache = {};
+ ri.calcListLength = function(sourceSizeListStr) {
+ if (!(sourceSizeListStr in sizeLengthCache) || cfg.uT) {
+ var sourceSize, parsedSize, length, media, i, len, sourceSizeList = trim(sourceSizeListStr).split(/\s*,\s*/), winningLength = !1;
+ for (i = 0, len = sourceSizeList.length; len > i && (sourceSize = sourceSizeList[i],
+ parsedSize = ri.parseSize(sourceSize), length = parsedSize.length, media = parsedSize.media,
+ !length || !ri.matchesMedia(media) || (winningLength = ri.calcLength(length)) === !1); i++) ;
+ sizeLengthCache[sourceSizeListStr] = winningLength ? winningLength : ri.vW;
+ }
+ return sizeLengthCache[sourceSizeListStr];
+ }, ri.setRes = function(set) {
+ var candidates, candidate;
+ if (set) {
+ candidates = ri.parseSet(set);
+ for (var i = 0, len = candidates.length; len > i; i++) candidate = candidates[i],
+ candidate.descriptor || setResolution(candidate, set.sizes);
+ }
+ return candidates;
+ };
+ var dprM, tLow, greed, tLazy, tHigh, tMemory, isWinComplete;
+ ri.applySetCandidate = function(candidates, img) {
+ if (candidates.length) {
+ var candidate, dpr, i, j, diff, length, bestCandidate, curSrc, curCan, isSameSet, candidateSrc, imageData = img[ri.ns], evaled = !0;
+ if (curSrc = imageData.curSrc || img[curSrcProp], curCan = imageData.curCan || setSrcToCur(img, curSrc, candidates[0].set),
+ dpr = ri.getX(candidates, curCan), curSrc && (curCan && (curCan.res += tLazy), isSameSet = !imageData.pic || curCan && curCan.set == candidates[0].set,
+ curCan && isSameSet && curCan.res >= dpr && tMemory > curCan.res - dpr ? bestCandidate = curCan : img.complete || imageData.src != getImgAttr.call(img, "src") || img.lazyload || (isSameSet || !isWinComplete && !inView(img)) && (bestCandidate = curCan,
+ candidateSrc = curSrc, evaled = "lazy", isWinComplete && reevaluateAfterLoad(img))),
+ !bestCandidate) for (candidates.sort(ascendingSort), length = candidates.length,
+ bestCandidate = candidates[length - 1], i = 0; length > i; i++) if (candidate = candidates[i],
+ candidate.res >= dpr) {
+ j = i - 1, bestCandidate = candidates[j] && (diff = candidate.res - dpr) && curSrc != ri.makeUrl(candidate.url) && chooseLowRes(candidates[j].res, diff, dpr) ? candidates[j] : candidate;
+ break;
+ }
+ return curSrc && curCan && (curCan.res -= tLazy), bestCandidate && (candidateSrc = ri.makeUrl(bestCandidate.url),
+ currentSrcSupported || (img.currentSrc = candidateSrc), imageData.curSrc = candidateSrc,
+ imageData.curCan = bestCandidate, candidateSrc != curSrc ? ri.setSrc(img, bestCandidate) : ri.setSize(img)),
+ evaled;
+ }
+ };
+ ri.getX = function() {
+ return ri.DPR * cfg.xQuant;
+ }, ri.setSrc = function(img, bestCandidate) {
+ var origWidth;
+ img.src = bestCandidate.url, "image/svg+xml" == bestCandidate.set.type && (origWidth = img.style.width,
+ img.style.width = img.offsetWidth + 1 + "px", img.offsetWidth + 1 && (img.style.width = origWidth));
+ };
+ var intrinsicSizeHandler = function() {
+ off(this, "load", intrinsicSizeHandler), ri.setSize(this);
+ };
+ ri.setSize = function(img) {
+ var width, curCandidate = img[ri.ns].curCan;
+ cfg.addSize && curCandidate && !img[ri.ns].dims && (img.complete || (off(img, "load", intrinsicSizeHandler),
+ on(img, "load", intrinsicSizeHandler)), width = img.naturalWidth, width && ("x" == curCandidate.desc.type ? setImgAttr.call(img, "width", parseInt(width / curCandidate.res / cfg.xQuant, 10)) : "w" == curCandidate.desc.type && setImgAttr.call(img, "width", parseInt(curCandidate.cWidth * (width / curCandidate.desc.val), 10))));
+ }, document.addEventListener && "naturalWidth" in image && "complete" in image || (ri.setSize = noop),
+ ri.getSet = function(img) {
+ var i, set, supportsType, match = !1, sets = img[ri.ns].sets;
+ for (i = 0; i < sets.length && !match; i++) if (set = sets[i], set.srcset && ri.matchesMedia(set.media) && (supportsType = ri.supportsType(set.type))) {
+ "pending" == supportsType && (set = supportsType), match = set;
+ break;
+ }
+ return match;
+ };
+ var alwaysCheckWDescriptor = ri.supSrcset && !ri.supSizes;
+ ri.parseSets = function(element, parent) {
+ var srcsetAttribute, fallbackCandidate, isWDescripor, srcsetParsed, hasPicture = "PICTURE" == parent.nodeName.toUpperCase(), imageData = element[ri.ns];
+ imageData.src === undefined && (imageData.src = getImgAttr.call(element, "src"),
+ imageData.src ? setImgAttr.call(element, srcAttr, imageData.src) : removeImgAttr.call(element, srcAttr)),
+ imageData.srcset === undefined && (srcsetAttribute = getImgAttr.call(element, "srcset"),
+ imageData.srcset = srcsetAttribute, srcsetParsed = !0), imageData.dims === undefined && (imageData.dims = getImgAttr.call(element, "height") && getImgAttr.call(element, "width")),
+ imageData.sets = [], hasPicture && (imageData.pic = !0, getAllSourceElements(parent, imageData.sets)),
+ imageData.srcset ? (fallbackCandidate = {
+ srcset: imageData.srcset,
+ sizes: getImgAttr.call(element, "sizes")
+ }, imageData.sets.push(fallbackCandidate), isWDescripor = alwaysCheckWDescriptor || imageData.src ? hasWDescripor(fallbackCandidate) : !1,
+ isWDescripor || !imageData.src || getCandidateForSrc(imageData.src, fallbackCandidate) || hasOneX(fallbackCandidate) || (fallbackCandidate.srcset += ", " + imageData.src,
+ fallbackCandidate.cands = !1)) : imageData.src && imageData.sets.push({
+ srcset: imageData.src,
+ sizes: null
+ }), imageData.curCan = null, imageData.supported = !(hasPicture || fallbackCandidate && !ri.supSrcset || isWDescripor),
+ srcsetParsed && ri.supSrcset && !imageData.supported && (srcsetAttribute ? (setImgAttr.call(element, srcsetAttr, srcsetAttribute),
+ element.srcset = "") : removeImgAttr.call(element, srcsetAttr)), imageData.parsed = !0;
+ };
+ var reevaluateAfterLoad = function() {
+ var onload = function() {
+ off(this, "load", onload), ri.fillImgs({
+ elements: [ this ]
+ });
+ };
+ return function(img) {
+ off(img, "load", onload), on(img, "load", onload);
+ };
+ }();
+ ri.fillImg = function(element, options) {
+ var parent, imageData, extreme = options.reparse || options.reevaluate;
+ if (element[ri.ns] || (element[ri.ns] = {}), imageData = element[ri.ns], "lazy" == imageData.evaled && (isWinComplete || element.complete) && (imageData.evaled = !1),
+ extreme || !imageData.evaled) {
+ if (!imageData.parsed || options.reparse) {
+ if (parent = element.parentNode, !parent) return;
+ ri.parseSets(element, parent, options);
+ }
+ imageData.supported ? imageData.evaled = !0 : applyBestCandidate(element);
+ }
+ };
+ var resizeThrottle;
+ ri.setupRun = function(options) {
+ (!alreadyRun || options.reevaluate || isVwDirty) && (cfg.uT || (ri.DPR = window.devicePixelRatio || 1),
+ dprM = Math.min(Math.max(ri.DPR * cfg.xQuant, 1), 2.5), tLow = cfg.tLow * dprM,
+ tLazy = cfg.tLazy * dprM, greed = cfg.greed * dprM, tHigh = cfg.tHigh, tMemory = .6 + .4 * dprM + tLazy),
+ isVwDirty && (lengthCache = {}, sizeLengthCache = {}, updateView(), options.elements || options.context || clearTimeout(resizeThrottle));
+ }, ri.teardownRun = function() {
+ var parent;
+ lengthElInstered && (lengthElInstered = !1, parent = lengthEl.parentNode, parent && parent.removeChild(lengthEl));
+ };
+ var alreadyRun = !1, respimage = function(opt) {
+ var elements, i, plen, options = opt || {};
+ if (options.elements && 1 == options.elements.nodeType && ("IMG" == options.elements.nodeName.toUpperCase() ? options.elements = [ options.elements ] : (options.context = options.elements,
+ options.elements = null)), elements = options.elements || ri.qsa(options.context || document, options.reevaluate || options.reparse ? ri.sel : ri.selShort),
+ plen = elements.length) {
+ for (ri.setupRun(options), alreadyRun = !0, i = 0; plen > i; i++) ri.fillImg(elements[i], options);
+ ri.teardownRun(options);
+ }
+ };
+ ri.fillImgs = respimage, window.HTMLPictureElement ? (respimage = noop, ri.fillImg = noop) : !function() {
+ var regWinComplete = /^loade|^c/, run = function() {
+ clearTimeout(timerId), timerId = setTimeout(run, 3e3), document.body && (regWinComplete.test(document.readyState || "") && (isWinComplete = !0,
+ clearTimeout(timerId), off(document, "readystatechange", run)), ri.fillImgs());
+ }, resizeEval = function() {
+ ri.fillImgs({
+ reevaluate: !0
+ });
+ }, onResize = function() {
+ clearTimeout(resizeThrottle), isVwDirty = !0, resizeThrottle = setTimeout(resizeEval, 99);
+ }, timerId = setTimeout(run, document.body ? 9 : 99);
+ on(window, "resize", onResize), on(document, "readystatechange", run);
+ }(), respimage._ = ri, respimage.config = function(name, value, value2) {
+ if ("addType" == name) {
+ if (types[value] = value2, "pending" == value2) return;
+ } else cfg[name] = value;
+ alreadyRun && ri.fillImgs({
+ reevaluate: !0
+ });
+ }, window.respimage = respimage;
+}(window, document);
+(function( factory ) {
+ "use strict";
+ var interValId;
+ var intervalIndex = 0;
+ var run = function(){
+ if ( window.respimage ) {
+ factory( window.respimage );
+ }
+ if(window.respimage || intervalIndex > 9999){
+ clearInterval(interValId);
+ }
+ intervalIndex++;
+ };
+ interValId = setInterval(run, 8);
+
+ run();
+
+}( function( respimage ) {
"use strict";
- // If picture is supported, well, that's awesome. Let's get outta here...
- if ( w.HTMLPictureElement ) {
- w.picturefill = function() { };
+ var ri = respimage._;
+ var runningTests = 0;
+ var setTypeValue = function(types, value){
+ var i;
+ for(i = 0; i < types.length; i++){
+ ri.types[types[i]] = value;
+ }
+ };
+
+ if(window.HTMLPictureElement && !ri.cfg.uT){
+ respimage.testTypeSupport = function(){};
return;
}
- // HTML shim|v it for old IE (IE9 will still need the HTML video tag workaround)
- doc.createElement( "picture" );
+ ri.types["image/bmp"] = true;
+ ri.types["image/x-bmp"] = true;
- // local object for method references and testing exposure
- var pf = {};
-
- // namespace
- pf.ns = "picturefill";
-
- // srcset support test
- pf.srcsetSupported = "srcset" in doc.createElement( "img" );
- pf.sizesSupported = w.HTMLImageElement.sizes;
-
- // just a string trim workaround
- pf.trim = function( str ) {
- return str.trim ? str.trim() : str.replace( /^\s+|\s+$/g, "" );
- };
-
- // just a string endsWith workaround
- pf.endsWith = function( str, suffix ) {
- return str.endsWith ? str.endsWith( suffix ) : str.indexOf( suffix, str.length - suffix.length ) !== -1;
- };
-
- /**
- * Shortcut method for matchMedia ( for easy overriding in tests )
- */
- pf.matchesMedia = function( media ) {
- return w.matchMedia && w.matchMedia( media ).matches;
- };
-
- /**
- * Shortcut method for `devicePixelRatio` ( for easy overriding in tests )
- */
- pf.getDpr = function() {
- return ( w.devicePixelRatio || 1 );
- };
-
- /**
- * Get width in css pixel value from a "length" value
- * http://dev.w3.org/csswg/css-values-3/#length-value
- */
- pf.getWidthFromLength = function( length ) {
- // If no length was specified, or it is 0 or negative, default to `100vw` (per the spec).
- length = length && ( parseFloat( length ) > 0 || length.indexOf( "calc(" ) > -1 ) ? length : "100vw";
-
- /**
- * If length is specified in `vw` units, use `%` instead since the div we’re measuring
- * is injected at the top of the document.
- *
- * TODO: maybe we should put this behind a feature test for `vw`?
- */
- length = length.replace( "vw", "%" );
-
- // Create a cached element for getting length value widths
- if ( !pf.lengthEl ) {
- pf.lengthEl = doc.createElement( "div" );
- doc.documentElement.insertBefore( pf.lengthEl, doc.documentElement.firstChild );
+ respimage.testTypeSupport = function(types, url, width, useCanvas){
+ if(typeof types == "string"){
+ types = types.split(/\s*\,*\s+/g);
}
-
- // Positioning styles help prevent padding/margin/width on `html` from throwing calculations off.
- pf.lengthEl.style.cssText = "position: absolute; left: 0; width: " + length + ";";
-
- if ( pf.lengthEl.offsetWidth <= 0 ) {
- // Something has gone wrong. `calc()` is in use and unsupported, most likely. Default to `100vw` (`100%`, for broader support.):
- pf.lengthEl.style.cssText = "width: 100%;";
- }
-
- return pf.lengthEl.offsetWidth;
- };
-
- // container of supported mime types that one might need to qualify before using
- pf.types = {};
-
- // Add support for standard mime types.
- pf.types["image/jpeg"] = true;
- pf.types["image/gif"] = true;
- pf.types["image/png"] = true;
-
- // test svg support
- pf.types[ "image/svg+xml" ] = doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image", "1.1");
-
- // test webp support, only when the markup calls for it
- pf.types[ "image/webp" ] = function() {
- // based on Modernizr's lossless img-webp test
- // note: asynchronous
- var img = new w.Image(),
- type = "image/webp";
-
- img.onerror = function() {
- pf.types[ type ] = false;
- picturefill();
+ var canvas;
+ var supports = "pending";
+ var img = document.createElement('img');
+ var onComplete = function(){
+ runningTests--;
+ setTypeValue(types, supports);
+ if(runningTests < 1){
+ respimage({reevaluate: true});
+ }
};
- img.onload = function() {
- pf.types[ type ] = img.width === 1;
- picturefill();
- };
- img.src = "data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=";
- };
- /**
- * Takes a source element and checks if its type attribute is present and if so, supported
- * Note: for type tests that require a async logic,
- * you can define them as a function that'll run only if that type needs to be tested. Just make the test function call picturefill again when it is complete.
- * see the async webp test above for example
- */
- pf.verifyTypeSupport = function( source ) {
- var type = source.getAttribute( "type" );
- // if type attribute exists, return test result, otherwise return true
- if ( type === null || type === "" ) {
- return true;
- } else {
- // if the type test is a function, run it and return "pending" status. The function will rerun picturefill on pending elements once finished.
- if ( typeof( pf.types[ type ] ) === "function" ) {
- pf.types[ type ]();
- return "pending";
- } else {
- return pf.types[ type ];
- }
- }
- };
-
- /**
- * Parses an individual `size` and returns the length, and optional media query
- */
- pf.parseSize = function( sourceSizeStr ) {
- var match = /(\([^)]+\))?\s*(.+)/g.exec( sourceSizeStr );
- return {
- media: match && match[1],
- length: match && match[2]
- };
- };
-
- /**
- * Takes a string of sizes and returns the width in pixels as a number
- */
- pf.findWidthFromSourceSize = function( sourceSizeListStr ) {
- // Split up source size list, ie ( max-width: 30em ) 100%, ( max-width: 50em ) 50%, 33%
- // or (min-width:30em) calc(30% - 15px)
- var sourceSizeList = pf.trim( sourceSizeListStr ).split( /\s*,\s*/ ),
- winningLength;
-
- for ( var i = 0, len = sourceSizeList.length; i < len; i++ ) {
- // Match ? length, ie ( min-width: 50em ) 100%
- var sourceSize = sourceSizeList[ i ],
- // Split "( min-width: 50em ) 100%" into separate strings
- parsedSize = pf.parseSize( sourceSize ),
- length = parsedSize.length,
- media = parsedSize.media;
-
- if ( !length ) {
- continue;
- }
- if ( !media || pf.matchesMedia( media ) ) {
- // if there is no media query or it matches, choose this as our winning length
- // and end algorithm
- winningLength = length;
- break;
- }
- }
-
- // pass the length to a method that can properly determine length
- // in pixels based on these formats: http://dev.w3.org/csswg/css-values-3/#length-value
- return pf.getWidthFromLength( winningLength );
- };
-
- pf.parseSrcset = function( srcset ) {
- /**
- * A lot of this was pulled from Boris Smus’ parser for the now-defunct WHATWG `srcset`
- * https://github.com/borismus/srcset-polyfill/blob/master/js/srcset-info.js
- *
- * 1. Let input (`srcset`) be the value passed to this algorithm.
- * 2. Let position be a pointer into input, initially pointing at the start of the string.
- * 3. Let raw candidates be an initially empty ordered list of URLs with associated
- * unparsed descriptors. The order of entries in the list is the order in which entries
- * are added to the list.
- */
- var candidates = [];
-
- while ( srcset !== "" ) {
- srcset = srcset.replace(/^\s+/g,"");
-
- // 5. Collect a sequence of characters that are not space characters, and let that be url.
- var pos = srcset.search(/\s/g),
- url, descriptor = null;
-
- if ( pos !== -1 ) {
- url = srcset.slice( 0, pos );
-
- var last = url[ url.length - 1 ];
-
- // 6. If url ends with a U+002C COMMA character (,), remove that character from url
- // and let descriptors be the empty string. Otherwise, follow these substeps
- // 6.1. If url is empty, then jump to the step labeled descriptor parser.
-
- if ( last === "," || url === "" ) {
- url = url.replace(/,+$/, "");
- descriptor = "";
- }
- srcset = srcset.slice( pos + 1 );
-
- // 6.2. Collect a sequence of characters that are not U+002C COMMA characters (,), and
- // let that be descriptors.
- if ( descriptor === null ) {
- var descpos = srcset.indexOf(",");
- if ( descpos !== -1 ) {
- descriptor = srcset.slice( 0, descpos );
- srcset = srcset.slice( descpos + 1 );
- } else {
- descriptor = srcset;
- srcset = "";
- }
- }
- } else {
- url = srcset;
- srcset = "";
- }
-
- // 7. Add url to raw candidates, associated with descriptors.
- if ( url || descriptor ) {
- candidates.push({
- url: url,
- descriptor: descriptor
- });
- }
- }
- return candidates;
- };
-
- pf.parseDescriptor = function( descriptor, sizesattr ) {
- // 11. Descriptor parser: Let candidates be an initially empty source set. The order of entries in the list
- // is the order in which entries are added to the list.
- var sizes = sizesattr || "100vw",
- sizeDescriptor = descriptor && descriptor.replace(/(^\s+|\s+$)/g, ""),
- widthInCssPixels = pf.findWidthFromSourceSize( sizes ),
- resCandidate;
-
- if ( sizeDescriptor ) {
- var splitDescriptor = sizeDescriptor.split(" ");
-
- for (var i = splitDescriptor.length + 1; i >= 0; i--) {
- if ( splitDescriptor[ i ] !== undefined ) {
- var curr = splitDescriptor[ i ],
- lastchar = curr && curr.slice( curr.length - 1 );
-
- if ( ( lastchar === "h" || lastchar === "w" ) && !pf.sizesSupported ) {
- resCandidate = parseFloat( ( parseInt( curr, 10 ) / widthInCssPixels ) );
- } else if ( lastchar === "x" ) {
- var res = curr && parseFloat( curr, 10 );
- resCandidate = res && !isNaN( res ) ? res : 1;
- }
- }
- }
- }
- return resCandidate || 1;
- };
-
- /**
- * Takes a srcset in the form of url/
- * ex. "images/pic-medium.png 1x, images/pic-medium-2x.png 2x" or
- * "images/pic-medium.png 400w, images/pic-medium-2x.png 800w" or
- * "images/pic-small.png"
- * Get an array of image candidates in the form of
- * {url: "/foo/bar.png", resolution: 1}
- * where resolution is http://dev.w3.org/csswg/css-values-3/#resolution-value
- * If sizes is specified, resolution is calculated
- */
- pf.getCandidatesFromSourceSet = function( srcset, sizes ) {
- var candidates = pf.parseSrcset( srcset ),
- formattedCandidates = [];
-
- for ( var i = 0, len = candidates.length; i < len; i++ ) {
- var candidate = candidates[ i ];
-
- formattedCandidates.push({
- url: candidate.url,
- resolution: pf.parseDescriptor( candidate.descriptor, sizes )
- });
- }
- return formattedCandidates;
- };
-
- /*
- * if it's an img element and it has a srcset property,
- * we need to remove the attribute so we can manipulate src
- * (the property's existence infers native srcset support, and a srcset-supporting browser will prioritize srcset's value over our winning picture candidate)
- * this moves srcset's value to memory for later use and removes the attr
- */
- pf.dodgeSrcset = function( img ) {
- if ( img.srcset ) {
- img[ pf.ns ].srcset = img.srcset;
- img.removeAttribute( "srcset" );
- }
- };
-
- /*
- * Accept a source or img element and process its srcset and sizes attrs
- */
- pf.processSourceSet = function( el ) {
- var srcset = el.getAttribute( "srcset" ),
- sizes = el.getAttribute( "sizes" ),
- candidates = [];
-
- // if it's an img element, use the cached srcset property (defined or not)
- if ( el.nodeName.toUpperCase() === "IMG" && el[ pf.ns ] && el[ pf.ns ].srcset ) {
- srcset = el[ pf.ns ].srcset;
- }
-
- if ( srcset ) {
- candidates = pf.getCandidatesFromSourceSet( srcset, sizes );
- }
- return candidates;
- };
-
- pf.applyBestCandidate = function( candidates, picImg ) {
- var candidate,
- length,
- bestCandidate;
-
- candidates.sort( pf.ascendingSort );
-
- length = candidates.length;
- bestCandidate = candidates[ length - 1 ];
-
- for ( var i = 0; i < length; i++ ) {
- candidate = candidates[ i ];
- if ( candidate.resolution >= pf.getDpr() ) {
- bestCandidate = candidate;
- break;
- }
- }
-
- if ( bestCandidate && !pf.endsWith( picImg.src, bestCandidate.url ) ) {
- picImg.src = bestCandidate.url;
- // currentSrc attribute and property to match
- // http://picture.responsiveimages.org/#the-img-element
- picImg.currentSrc = picImg.src;
- }
- };
-
- pf.ascendingSort = function( a, b ) {
- return a.resolution - b.resolution;
- };
-
- /*
- * In IE9,