├── spec ├── rails │ └── .keep ├── active_admin_datetimepicker_spec.rb ├── support │ ├── capybara.rb │ ├── admin.rb │ └── rails_template.rb ├── date_time_picker_input_spec.rb ├── base_spec.rb ├── edit_form_spec.rb ├── spec_helper.rb └── filter_form_spec.rb ├── .gitignore ├── lib ├── active_admin_datetimepicker │ ├── version.rb │ ├── inputs │ │ ├── date_time_picker_input.rb │ │ └── filters │ │ │ └── date_time_range_input.rb │ └── base.rb └── active_admin_datetimepicker.rb ├── screen └── screen.png ├── Rakefile ├── config └── initializers │ └── active_admin_datetimepicker.rb ├── tasks └── test.rake ├── Gemfile ├── app └── assets │ ├── javascripts │ ├── active_admin_datetimepicker.js │ └── vendor │ │ └── jquery.datetimepicker.full.js │ └── stylesheets │ ├── active_admin_datetimepicker.scss │ └── vendor │ └── jquery.datetimepicker.css ├── active_admin_datetimepicker.gemspec ├── LICENSE.txt ├── .github └── workflows │ └── ci.yml ├── package.json ├── CODE_OF_CONDUCT.md └── README.md /spec/rails/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | Gemfile.lock 3 | coverage/ 4 | spec/rails/rails-* 5 | pkg 6 | .bundle 7 | vendor/bundl 8 | -------------------------------------------------------------------------------- /lib/active_admin_datetimepicker/version.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdminDatetimepicker 2 | VERSION = "1.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /screen/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activeadmin-plugins/active_admin_datetimepicker/HEAD/screen/screen.png -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler" 2 | require 'rake' 3 | Bundler.setup 4 | Bundler::GemHelper.install_tasks 5 | 6 | # Import all our rake tasks 7 | FileList['tasks/**/*.rake'].each { |task| import task } 8 | -------------------------------------------------------------------------------- /spec/active_admin_datetimepicker_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ActiveAdminDatetimepicker do 4 | 5 | it 'has a version number' do 6 | expect(ActiveAdminDatetimepicker::VERSION).not_to be nil 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /lib/active_admin_datetimepicker/inputs/date_time_picker_input.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Inputs 3 | class DateTimePickerInput < ::Formtastic::Inputs::StringInput 4 | include ActiveAdminDatetimepicker::Base 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /config/initializers/active_admin_datetimepicker.rb: -------------------------------------------------------------------------------- 1 | Ransack.configure do |config| 2 | config.add_predicate 'gteq_datetime_picker', 3 | arel_predicate: 'gteq' 4 | 5 | config.add_predicate 'lteq_datetime_picker', 6 | arel_predicate: 'lt' 7 | end 8 | -------------------------------------------------------------------------------- /tasks/test.rake: -------------------------------------------------------------------------------- 1 | desc "Creates a test rails app for the specs to run against" 2 | task :setup do 3 | require 'rails/version' 4 | 5 | rails_new_opts = %w( 6 | --skip-turbolinks 7 | --skip-spring 8 | --skip-bootsnap 9 | -m 10 | spec/support/rails_template.rb 11 | ) 12 | system "bundle exec rails new spec/rails/rails-#{Rails::VERSION::STRING} #{rails_new_opts.join(' ')}" 13 | end 14 | -------------------------------------------------------------------------------- /lib/active_admin_datetimepicker.rb: -------------------------------------------------------------------------------- 1 | require 'activeadmin' 2 | require 'active_admin_datetimepicker/version' 3 | require 'active_admin_datetimepicker/base' 4 | require 'active_admin_datetimepicker/inputs/date_time_picker_input' 5 | require 'active_admin_datetimepicker/inputs/filters/date_time_range_input' 6 | 7 | module ActiveAdminDatetimepicker 8 | module Rails 9 | class Engine < ::Rails::Engine 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/support/capybara.rb: -------------------------------------------------------------------------------- 1 | Capybara.server = :webrick 2 | 3 | Capybara.configure do |config| 4 | config.match = :prefer_exact 5 | end 6 | 7 | Capybara.register_driver :selenium_chrome do |app| 8 | options = Selenium::WebDriver::Chrome::Options.new( 9 | args: %w[headless disable-gpu no-sandbox] 10 | ) 11 | Capybara::Selenium::Driver.new(app, browser: :chrome, options: options) 12 | end 13 | 14 | Capybara.javascript_driver = :selenium_chrome 15 | -------------------------------------------------------------------------------- /spec/date_time_picker_input_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ActiveAdmin::Inputs::DateTimePickerInput do 4 | 5 | it 'included from ActiveAdminDatetimepicker::Base' do 6 | input = ActiveAdmin::Inputs::DateTimePickerInput.new( 7 | # all dummy args for now 8 | Object.new, Object.new, Object.new, Object.new, Object.new, {}) 9 | expect(input.html_class).to eq "date-time-picker" 10 | expect(input.format).to eq '%Y-%m-%d %H:%M' 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /spec/base_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ActiveAdminDatetimepicker::Base do 4 | 5 | class Dummy 6 | include ActiveAdminDatetimepicker::Base 7 | end 8 | 9 | let(:dummy) { Dummy.new } 10 | 11 | it 'html_class' do 12 | expect(dummy.html_class).to eq "date-time-picker" 13 | end 14 | 15 | it 'format' do 16 | expect(dummy.format).to eq '%Y-%m-%d %H:%M' 17 | expect(ActiveAdminDatetimepicker::Base.format).to eq '%Y-%m-%d %H:%M' 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /spec/support/admin.rb: -------------------------------------------------------------------------------- 1 | def add_author_resource(options = {}, &block) 2 | ActiveAdmin.register Author do 3 | permit_params :name, :birthday 4 | 5 | config.filters = true 6 | 7 | filter :birthday, as: :date_time_range 8 | filter :created_at, as: :date_time_range 9 | filter :last_seen_at, as: :date_time_range 10 | 11 | form do |f| 12 | f.semantic_errors 13 | 14 | f.inputs 'General' do 15 | f.input :name 16 | f.input :birthday, as: :date_time_picker, input_html: { placeholder: 'Formtastic placeholder' } 17 | end 18 | 19 | f.actions 20 | end 21 | end 22 | 23 | Rails.application.reload_routes! 24 | end 25 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in active_admin_datetimepicker.gemspec 4 | gemspec 5 | 6 | group :test do 7 | default_rails_version = '7.1.0' 8 | default_activeadmin_version = '3.1.0' 9 | 10 | gem 'rails', "~> #{ENV['RAILS'] || default_rails_version}" 11 | gem 'activeadmin', "~> #{ENV['AA'] || default_activeadmin_version}" 12 | 13 | gem 'sprockets-rails' 14 | gem 'rspec-rails' 15 | gem 'coveralls_reborn', require: false 16 | gem 'sass-rails' 17 | gem 'sqlite3', '~> 1.4.0' 18 | gem 'launchy' 19 | gem 'database_cleaner' 20 | gem 'capybara' 21 | gem 'webdrivers' 22 | gem 'byebug' 23 | gem 'webrick', require: false 24 | end 25 | -------------------------------------------------------------------------------- /app/assets/javascripts/active_admin_datetimepicker.js: -------------------------------------------------------------------------------- 1 | //= require vendor/jquery.datetimepicker.full 2 | 3 | function setupDateTimePicker(container) { 4 | const defaults = { 5 | formatDate: 'y-m-d', 6 | format: 'Y-m-d H:i', 7 | allowBlank: true, 8 | defaultSelect: false, 9 | validateOnBlur: false 10 | } 11 | 12 | $(container).find('input.date-time-picker').each(function(index, entry) { 13 | $(entry).datetimepicker($.extend(defaults, $(entry).data('datepicker-options'))); 14 | }); 15 | } 16 | 17 | function initXdanDateTimePickerPlugin() { 18 | setupDateTimePicker($('body')); 19 | $(document).on('has_many_add:after', '.has_many_container', function(e, fieldset) { 20 | setupDateTimePicker(fieldset); 21 | }); 22 | } 23 | 24 | $(document).ready(initXdanDateTimePickerPlugin); 25 | $(document).on('turbolinks:load', initXdanDateTimePickerPlugin()); 26 | -------------------------------------------------------------------------------- /spec/edit_form_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'authors index', type: :feature, js: true do 4 | before do 5 | add_author_resource 6 | end 7 | 8 | context 'edit form' do 9 | before do 10 | visit '/admin/authors/new' 11 | end 12 | 13 | before do 14 | page.find('#author_birthday').click 15 | 16 | page.find('.xdsoft_datetimepicker', visible: true) 17 | .find('.xdsoft_calendar td.xdsoft_date[data-date="1"]').click 18 | page.find('.xdsoft_datetimepicker', visible: true) 19 | .find('.xdsoft_timepicker.active .xdsoft_time.xdsoft_current').click 20 | end 21 | 22 | it 'can set birthday' do 23 | date_birthday = Date.today.beginning_of_month.strftime("%Y-%m-%d") 24 | expect(page.find('#author_birthday').value).to start_with(date_birthday) 25 | expect(page).to have_css('#author_birthday[placeholder="Formtastic placeholder"]') 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/active_admin_datetimepicker/inputs/filters/date_time_range_input.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdmin 2 | module Inputs 3 | module Filters 4 | class DateTimeRangeInput < DateRangeInput 5 | include Base 6 | include ActiveAdminDatetimepicker::Base 7 | 8 | def input_html_options(input_name = gt_input_name, placeholder = gt_input_placeholder) 9 | super.tap do |options| 10 | options[:class] = html_class 11 | end 12 | end 13 | 14 | # This method is for compatibility for ActiveAdmin 2.6 15 | def input_html_options_for(input_name, placeholder) 16 | super.merge placeholder: placeholder, 17 | value: input_value(input_name) 18 | end 19 | 20 | def gt_input_name 21 | column && column.type == :date ? super : "#{method}_gteq_datetime_picker" 22 | end 23 | 24 | def lt_input_name 25 | column && column.type == :date ? super : "#{method}_lteq_datetime_picker" 26 | end 27 | 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /active_admin_datetimepicker.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'active_admin_datetimepicker/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "active_admin_datetimepicker" 8 | spec.version = ActiveAdminDatetimepicker::VERSION 9 | spec.authors = ["Igor Fedoronchuk"] 10 | spec.email = ["fedoronchuk@gmail.com"] 11 | 12 | spec.summary = %q{datetimepicker extension for ActiveAdmin} 13 | spec.description = %q{Integrate jQuery xdan datetimepicker plugin to ActiveAdmin} 14 | spec.homepage = "https://github.com/activeadmin-plugins/activeadmin_datetimepicker" 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 18 | spec.bindir = "bin" 19 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_dependency "activeadmin", ">= 2.14.0", "< 4.0" 23 | end 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Igor Fedoronchuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | test: 9 | name: Tests with Ruby ${{ matrix.ruby }} Rails ${{ matrix.rails }} Active Admin ${{ matrix.activeadmin }} 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | ruby: 14 | - '3.0.0' 15 | - '3.1.0' 16 | - '3.2.0' 17 | - '3.3.0' 18 | rails: 19 | - '6.1.0' 20 | - '7.0.0' 21 | - '7.1.0' 22 | activeadmin: 23 | - '2.14.0' 24 | - '3.0.0' 25 | - '3.1.0' 26 | - '3.2.0' 27 | exclude: 28 | - rails: '7.1.0' 29 | activeadmin: '2.14.0' 30 | - rails: '7.1.0' 31 | activeadmin: '3.0.0' 32 | env: 33 | RAILS: ${{ matrix.rails }} 34 | AA: ${{ matrix.activeadmin }} 35 | steps: 36 | - uses: actions/checkout@v4 37 | - uses: ruby/setup-ruby@v1 38 | with: 39 | ruby-version: ${{ matrix.ruby }} 40 | - name: Run tests 41 | run: | 42 | gem install bundler -v '< 2' 43 | bundle install 44 | bundle exec rspec spec 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@activeadmin-plugins/active_admin_datetimepicker", 3 | "version": "1.0.0", 4 | "description": "Integrate jQuery xdan datetimepicker plugin to ActiveAdmin", 5 | "main": "src/active_admin_datetimepicker.js", 6 | "style": "src/active_admin_datetimepicker.scss", 7 | "author": "Igor Fedoronchuk ", 8 | "license": "MIT", 9 | "private": false, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/activeadmin-plugins/active_admin_datetimepicker.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/activeadmin-plugins/active_admin_datetimepicker/issues" 16 | }, 17 | "homepage": "https://github.com/activeadmin-plugins/active_admin_datetimepicker#readme", 18 | "keywords": [ 19 | "active", 20 | "admin", 21 | "datetimepicker" 22 | ], 23 | "files": [ 24 | "src/**/*", 25 | "!src/*.bak" 26 | ], 27 | "scripts": { 28 | "prepare_src": "rm -rf src && cp -R app/assets/javascripts/ src && cp -R app/assets/stylesheets/ src", 29 | "prepare_import": "sed -i.bak 1s/'\\/\\/\\= require vendor\\/jquery.datetimepicker.full'/\"import '.\\/vendor\\/jquery.datetimepicker.full';\"/ src/active_admin_datetimepicker.js", 30 | "prepublishOnly": "npm run prepare_src && npm run prepare_import" 31 | }, 32 | "dependencies": { 33 | "jquery-mousewheel": ">= 3.1.13" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. 6 | 7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 8 | 9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 10 | 11 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 12 | 13 | This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) 14 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'coveralls' 2 | Coveralls.wear! 3 | 4 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 5 | $LOAD_PATH << File.expand_path('../support', __FILE__) 6 | 7 | ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__) 8 | require "bundler" 9 | Bundler.setup 10 | 11 | ENV['RAILS_ENV'] = 'test' 12 | # Ensure the Active Admin load path is happy 13 | require 'rails' 14 | ENV['RAILS'] = Rails.version 15 | ENV['RAILS_ROOT'] = File.expand_path("../rails/rails-#{ENV['RAILS']}", __FILE__) 16 | # Create the test app if it doesn't exists 17 | unless File.exist?(ENV['RAILS_ROOT']) 18 | system 'rake setup' 19 | end 20 | 21 | require 'active_model' 22 | # require ActiveRecord to ensure that Ransack loads correctly 23 | require 'active_record' 24 | require 'action_view' 25 | require 'active_admin' 26 | ActiveAdmin.application.load_paths = [ENV['RAILS_ROOT'] + "/app/admin"] 27 | require ENV['RAILS_ROOT'] + '/config/environment.rb' 28 | # Disabling authentication in specs so that we don't have to worry about 29 | # it allover the place 30 | ActiveAdmin.application.authentication_method = false 31 | ActiveAdmin.application.current_user_method = false 32 | 33 | require 'rspec/rails' 34 | require 'capybara/rails' 35 | require 'capybara/rspec' 36 | require 'selenium-webdriver' 37 | 38 | require 'support/admin' 39 | require 'support/capybara' 40 | 41 | RSpec.configure do |config| 42 | config.use_transactional_fixtures = false 43 | 44 | config.before(:suite) do 45 | DatabaseCleaner.strategy = :truncation 46 | DatabaseCleaner.clean_with(:truncation) 47 | end 48 | 49 | config.before(:each) do 50 | DatabaseCleaner.strategy = :truncation 51 | DatabaseCleaner.start 52 | end 53 | 54 | config.after(:each) do 55 | DatabaseCleaner.clean 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/active_admin_datetimepicker/base.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdminDatetimepicker 2 | module Base 3 | mattr_accessor :default_datetime_picker_options 4 | @@default_datetime_picker_options = {} 5 | mattr_accessor :format 6 | @@format = '%Y-%m-%d %H:%M' 7 | 8 | def html_class 9 | 'date-time-picker' 10 | end 11 | 12 | def input_html_data 13 | {} 14 | end 15 | 16 | def input_html_options(input_name = nil, placeholder = nil) 17 | super().tap do |options| 18 | options[:class] = [self.options[:class], html_class].compact.join(' ') 19 | options[:data] ||= input_html_data 20 | options[:data].merge!(datepicker_options: datetime_picker_options) 21 | options[:value] = input_value(input_name) 22 | options[:maxlength] = 19 23 | options[:placeholder] = placeholder unless placeholder.nil? 24 | end 25 | end 26 | 27 | def input_value(input_name = nil) 28 | val = object.public_send(input_name || method) 29 | val.is_a?(Date) ? val : parse_datetime(val) 30 | end 31 | 32 | def parse_datetime(val) 33 | DateTime.parse(val.to_s).strftime(format) 34 | rescue ArgumentError 35 | nil 36 | end 37 | 38 | def datetime_picker_options 39 | @datetime_picker_options ||= begin 40 | # backport support both :datepicker_options AND :datetime_picker_options 41 | options = self.options.fetch(:datepicker_options, {}) 42 | options = self.options.fetch(:datetime_picker_options, options) 43 | options = Hash[options.map { |k, v| [k.to_s.camelcase(:lower), v] }] 44 | _default_datetime_picker_options.merge(options) 45 | end 46 | end 47 | 48 | protected 49 | 50 | def _default_datetime_picker_options 51 | res = default_datetime_picker_options.map do |k, v| 52 | if v.respond_to?(:call) || v.is_a?(Proc) 53 | [k, v.call] 54 | else 55 | [k, v] 56 | end 57 | end 58 | Hash[res] 59 | end 60 | end 61 | end 62 | 63 | -------------------------------------------------------------------------------- /spec/support/rails_template.rb: -------------------------------------------------------------------------------- 1 | # Rails template to build the sample app for specs 2 | 3 | generate :model, 'author name:string{10}:uniq last_name:string birthday:date' 4 | generate :model, 'post title:string:uniq body:text author:references' 5 | 6 | # Compatibility with old ransack 7 | inject_into_file "app/models/application_record.rb", after: "primary_abstract_class\n" do 8 | <<-STRING 9 | 10 | def self.ransackable_attributes(auth_object=nil) 11 | if respond_to?(:authorizable_ransackable_attributes) 12 | authorizable_ransackable_attributes 13 | else 14 | super 15 | end 16 | end 17 | 18 | def self.ransackable_associations(auth_object=nil) 19 | if respond_to?(:authorizable_ransackable_associations) 20 | authorizable_ransackable_associations 21 | else 22 | super 23 | end 24 | end 25 | STRING 26 | end 27 | 28 | # Virtual attributes 29 | inject_into_file "app/models/author.rb", after: "ApplicationRecord\n" do 30 | <<-STRING 31 | validates_presence_of :name 32 | validates_uniqueness_of :last_name 33 | 34 | def self.ransackable_attributes(auth_object=nil) 35 | if respond_to?(:authorizable_ransackable_attributes) 36 | authorizable_ransackable_attributes 37 | else 38 | %w(birthday created_at last_seen_at updated_at) 39 | end 40 | end 41 | 42 | attr_accessor :last_seen_at 43 | 44 | ransacker :last_seen_at do 45 | Arel.sql('updated_at') 46 | end 47 | STRING 48 | end 49 | 50 | # Configure default_url_options in test environment 51 | inject_into_file "config/environments/test.rb", after: "config.cache_classes = true\n" do 52 | " config.action_mailer.default_url_options = { :host => 'example.com' }\n" 53 | end 54 | 55 | # Add our local Active Admin to the load path 56 | inject_into_file "config/environment.rb", after: "require File.expand_path('../application', __FILE__)" do 57 | "\n$LOAD_PATH.unshift('#{File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib'))}')\nrequire \"active_admin\"\n" 58 | end 59 | 60 | run "rm Gemfile" 61 | 62 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 63 | 64 | generate :'active_admin:install --skip-users' 65 | generate :'formtastic:install' 66 | 67 | # Install active_admin_date_time_datetimepicker assets 68 | inject_into_file "app/assets/stylesheets/active_admin.scss" do 69 | "@import \"active_admin_datetimepicker\";\n" 70 | end 71 | 72 | inject_into_file "app/assets/javascripts/active_admin.js" do 73 | "//= require active_admin_datetimepicker\n" 74 | end 75 | 76 | run "rm -r test" 77 | run "rm -r spec" 78 | 79 | route "root :to => 'admin/dashboard#index'" 80 | 81 | rake "db:migrate" 82 | -------------------------------------------------------------------------------- /app/assets/stylesheets/active_admin_datetimepicker.scss: -------------------------------------------------------------------------------- 1 | @import 'vendor/jquery.datetimepicker'; 2 | 3 | form.filter_form { 4 | .filter_form_field { 5 | &.filter_date_time_range { 6 | .seperator { 7 | display: inline-block; 8 | text-align: center; 9 | width: $filter-field-seperator-width; 10 | } 11 | 12 | input[type=text] { 13 | width: $side-by-side-filter-input-width - 2; 14 | } 15 | } 16 | } 17 | } 18 | 19 | 20 | div.xdsoft_datetimepicker { 21 | .xdsoft_label i:hover, 22 | .xdsoft_today_button:hover, 23 | .xdsoft_next:hover, 24 | .xdsoft_prev:hover { 25 | background-color: #666; 26 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAeCAYAAADaW7vzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUExQUUzOTA0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUExQUUzOTE0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQTFBRTM4RTQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQTFBRTM4RjQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pp0VxGEAAAIASURBVHja7JrNSgMxEMebtgh+3MSLr1T1Xn2CHoSKB08+QmR8Bx9A8e7RixdB9CKCoNdexIugxFlJa7rNZneTbLIpM/CnNLsdMvNjM8l0mRCiQ9Ye61IKCAgZAUnH+mU3MMZaHYChBnJUDzWOFZdVfc5+ZFLbrWDeXPwbxIqrLLfaeS0hEBVGIRQCEiZoHQwtlGSByCCdYBl8g8egTTAWoKQMRBRBcZxYlhzhKegqMOageErsCHVkk3hXIFooDgHB1KkHIHVgzKB4ADJQ/A1jAFmAYhkQqA5TOBtocrKrgXwQA8gcFIuAIO8sQSA7hidvPwaQGZSaAYHOUWJABhWWw2EMIH9QagQERU4SArJXo0ZZL18uvaxejXt/Em8xjVBXmvFr1KVm/AJ10tRe2XnraNqaJvKE3KHuUbfK1E+VHB0q40/y3sdQSxY4FHWeKJCunP8UyDdqJZenT3ntVV5jIYCAh20vT7ioP8tpf6E2lfEMwERe+whV1MHjwZB7PBiCxcGQWwKZKD62lfGNnP/1poFAA60T7rF1UgcKd2id3KDeUS+oLWV8DfWAepOfq00CgQabi9zjcgJVYVD7PVzQUAUGAQkbNJTBICDhgwYTjDYD6XeW08ZKh+A4pYkzenOxXUbvZcWz7E8ykRMnIHGX1XPl+1m2vPYpL+2qdb8CDAARlKFEz/ZVkAAAAABJRU5ErkJggg==); 27 | } 28 | .xdsoft_label i:hover { 29 | background-position: -92px -19px; 30 | } 31 | .xdsoft_today_button:hover { 32 | background-position: -70px 0; 33 | } 34 | .xdsoft_next:hover { 35 | background-position: 0 0; 36 | } 37 | .xdsoft_prev:hover { 38 | background-position: -20px 0; 39 | } 40 | .xdsoft_timepicker .xdsoft_next:hover { 41 | background-position: -40px -15px; 42 | } 43 | .xdsoft_timepicker .xdsoft_prev:hover{ 44 | background-position: -40px 0; 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Gem Version](https://badge.fury.io/rb/active_admin_datetimepicker.svg)](http://badge.fury.io/rb/active_admin_datetimepicker) 2 | [![NPM Version](https://badge.fury.io/js/@activeadmin-plugins%2Factive_admin_datetimepicker.svg)](https://badge.fury.io/js/@activeadmin-plugins%2Factive_admin_datetimepicker) 3 | ![npm](https://img.shields.io/npm/dm/@activeadmin-plugins/active_admin_datetimepicker) 4 | [![Build Status](https://img.shields.io/travis/activeadmin-plugins/active_admin_datetimepicker.svg)](https://travis-ci.org/activeadmin-plugins/active_admin_datetimepicker) 5 | [![Coverage](https://coveralls.io/repos/activeadmin-plugins/active_admin_datetimepicker/badge.svg?branch=master)](https://coveralls.io/r/activeadmin-plugins/active_admin_datetimepicker) 6 | 7 | # ActiveAdminDatetimepicker 8 | 9 | Adds XDSoft's DateTime picker as a `date_time_picker` input for forms, and `date_time_range` for filters. 10 | 11 | ![ActiveAdminDatetimepicker](https://raw.githubusercontent.com/ActiveAdminPlugins/activeadmin_datetimepicker/master/screen/screen.png "ActiveAdminDatetimepicker") 12 | 13 | ## Installation 14 | 15 | Add this line to your application's `Gemfile`: 16 | 17 | ```ruby 18 | gem 'active_admin_datetimepicker' 19 | ``` 20 | 21 | And then execute: 22 | 23 | $ bundle 24 | 25 | Or install it yourself as: 26 | 27 | $ gem install active_admin_datetimepicker 28 | 29 | ##### Using assets via Sprockets 30 | Add the following line into `app/assets/stylesheets/active_admin.scss`: 31 | 32 | ```css 33 | @import "active_admin_datetimepicker"; 34 | ``` 35 | 36 | Add the following line into `app/assets/javascripts/active_admin.js`: 37 | 38 | ```javascript 39 | //= require active_admin_datetimepicker 40 | ``` 41 | 42 | ##### Using assets via Webpacker (or any other assets bundler) as a NPM module (Yarn package) 43 | 44 | Execute: 45 | 46 | $ npm i @activeadmin-plugins/active_admin_datetimepicker 47 | 48 | Or 49 | 50 | $ yarn add @activeadmin-plugins/active_admin_datetimepicker 51 | 52 | Or add manually to `package.json`: 53 | 54 | ``` 55 | "dependencies": { 56 | "@activeadmin-plugins/active_admin_datetimepicker": "1.0.0" 57 | } 58 | ``` 59 | and execute: 60 | 61 | $ yarn 62 | 63 | Add the following line into `app/assets/javascripts/active_admin.js`: 64 | 65 | ```javascript 66 | import '@activeadmin-plugins/active_admin_datetimepicker'; 67 | ``` 68 | 69 | Add the following line into `app/assets/stylesheets/active_admin.scss`: 70 | 71 | ```css 72 | @import '@activeadmin-plugins/active_admin_datetimepicker'; 73 | ``` 74 | 75 | ## Usage 76 | 77 | This plugin adds the `date_time_picker` input and `date_time_range` filter, which use the [XDSoft DateTime Picker](https://github.com/xdan/datetimepicker/). 78 | 79 | The `date_time_picker` input accepts many of the options available to the standard jQueryUI Datepicker. For example: 80 | 81 | ```ruby 82 | # Index page filters 83 | filter :created_at, as: :date_time_range 84 | 85 | # New/Edit form 86 | form do |f| 87 | f.input :starts_at, as: :date_time_picker, datepicker_options: { min_date: "2013-10-8", max_date: "+3D" } 88 | f.input :ends_at, as: :date_time_picker, datepicker_options: { min_date: 3.days.ago.to_date, max_date: "+1W +5D" } 89 | end 90 | ``` 91 | 92 | ## Override behaviour in initializer 93 | 94 | ```ruby 95 | # This if for the front-end JavaScript side 96 | ActiveAdminDatetimepicker::Base.default_datetime_picker_options = { 97 | defaultDate: proc { Time.current.strftime("%Y-%m-%d 00:00") } 98 | } 99 | # This if for the Ruby backend 100 | ActiveAdminDatetimepicker::Base.format = "%Y-%m-%d %H:%M:%S" 101 | ``` 102 | 103 | ## Change datetime format 104 | 105 | If you want to change the format you need to make sure that front-end and back-end formats are identical. 106 | And remember JS and Ruby datetime format have different syntaxes. 107 | 108 | Create configuration file `config/initializers/init_datetimepicker.rb`: 109 | 110 | ```ruby 111 | # Example "11/03/2016 13:00" 112 | ActiveAdminDatetimepicker::Base.default_datetime_picker_options = { 113 | format: 'd/m/Y H:i', # JS format 114 | defaultTime: proc { Time.current.strftime('%H:00') } # not necessary 115 | } 116 | ActiveAdminDatetimepicker::Base.format = "%d/%m/%Y %H:%M" # Ruby format 117 | ``` 118 | 119 | See [the datetimepicker documentation for more details](http://xdsoft.net/jqplugins/datetimepicker/). 120 | 121 | 122 | ## Contributing 123 | 124 | 1. Fork it ( https://github.com/activeadmin-plugins/activeadmin_datetimepicker/fork ) 125 | 2. Create your feature branch (`git checkout -b my-new-feature`) 126 | 3. Commit your changes (`git commit -am 'Add some feature'`) 127 | 4. Push to the branch (`git push origin my-new-feature`) 128 | 5. Create a new Pull Request 129 | -------------------------------------------------------------------------------- /spec/filter_form_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'authors index', type: :feature, js: true do 4 | before do 5 | add_author_resource 6 | end 7 | 8 | context 'index filters' do 9 | before do 10 | visit '/admin/authors' 11 | end 12 | 13 | context 'filter by Date column' do 14 | before do 15 | page.find('input#q_birthday_gteq').click 16 | 17 | page.find('.xdsoft_datetimepicker', visible: true) 18 | .find('.xdsoft_calendar td.xdsoft_date[data-date="1"]').click 19 | page.find('.xdsoft_datetimepicker', visible: true) 20 | .find('.xdsoft_timepicker.active .xdsoft_time.xdsoft_current').click 21 | 22 | page.find('input#q_birthday_lteq').click 23 | 24 | page.find('.xdsoft_datetimepicker', visible: true) 25 | .find('.xdsoft_calendar td.xdsoft_date[data-date="20"]').click 26 | page.find('.xdsoft_datetimepicker', visible: true) 27 | .find('.xdsoft_timepicker.active .xdsoft_time.xdsoft_current').click 28 | end 29 | 30 | it 'can set date from/to' do 31 | date_from = Date.today.beginning_of_month.strftime("%Y-%m-%d") 32 | date_to = (Date.today.beginning_of_month + 19.days).strftime("%Y-%m-%d") 33 | 34 | expect(page.find('input#q_birthday_gteq').value).to start_with(date_from) 35 | expect(page.find('input#q_birthday_lteq').value).to start_with(date_to) 36 | 37 | expect(page).to have_css('input#q_birthday_gteq[placeholder="From"]') 38 | expect(page).to have_css('input#q_birthday_lteq[placeholder="To"]') 39 | 40 | page.find('#sidebar input[type=submit]').click 41 | page.has_css?('h4', text: 'Current filters:') 42 | 43 | # birthday(Date type) is a Date column, should not contain H:M 44 | expect(page.find('#q_birthday_gteq').value).to match(/\A\d{4}-\d{2}-\d{2}\z/) 45 | end 46 | end 47 | 48 | context 'filter by DateTime/Timestamp column' do 49 | before do 50 | Author.create!(name: "Ren", 51 | last_name: "from-20-day-of-month", 52 | created_at: (Time.now.change(day: 20) - 1.hour).to_formatted_s(:db)) 53 | 54 | Author.create!(name: "Rey", 55 | last_name: "from-the-future", 56 | created_at: (Time.now.change(day: 20) + 2.hours).to_formatted_s(:db)) 57 | 58 | # chose 01 and 20 day of the current month 59 | 60 | page.find('input#q_created_at_gteq_datetime_picker').click 61 | 62 | page.find('.xdsoft_datetimepicker', visible: true) 63 | .find('.xdsoft_calendar td.xdsoft_date[data-date="1"]').click 64 | page.find('.xdsoft_datetimepicker', visible: true) 65 | .find('.xdsoft_timepicker.active .xdsoft_time.xdsoft_current').click 66 | 67 | page.find('input#q_created_at_lteq_datetime_picker').click 68 | 69 | page.find('.xdsoft_datetimepicker', visible: true) 70 | .find('.xdsoft_calendar td.xdsoft_date[data-date="20"]').click 71 | page.find('.xdsoft_datetimepicker', visible: true) 72 | .find('.xdsoft_timepicker.active .xdsoft_time.xdsoft_current').click 73 | 74 | @value_from = page.find('#q_created_at_gteq_datetime_picker').value 75 | @value_to = page.find('#q_created_at_lteq_datetime_picker').value 76 | 77 | page.find('#sidebar input[type=submit]').click 78 | page.has_css?('h4', text: 'Current filters:') 79 | end 80 | 81 | it 'q_created_at_lteq_datetime send correct value to SQL' do 82 | expect(page).to have_text('from-20-day-of-month') 83 | expect(page).not_to have_text('from-the-future') 84 | end 85 | 86 | it 'input#value and placeholder is the same as before form submit' do 87 | # created_at(Timestamp type) should contain Hours:Minutes, as selected before submit 88 | expect(page.find('#q_created_at_gteq_datetime_picker').value).to match(@value_from) 89 | expect(page.find('#q_created_at_lteq_datetime_picker').value).to match(@value_to) 90 | 91 | expect(page).to have_css('#q_created_at_gteq_datetime_picker[placeholder=From]') 92 | expect(page).to have_css('#q_created_at_lteq_datetime_picker[placeholder=To]') 93 | end 94 | end 95 | 96 | context 'filter by virtual attribute last_seen_at - without column&type properties (search by updated_at)' do 97 | before do 98 | Author.create!(name: 'Ren', last_name: 'One', updated_at: (Time.now.change(day: 1) + 1.hour).to_formatted_s(:db)) 99 | Author.create!(name: 'Ron', last_name: 'Two', updated_at: (Time.now.change(day: 20) - 1.hour).to_formatted_s(:db)) 100 | Author.create!(name: 'Rey', last_name: 'future', updated_at: Time.now.change(day: 21).to_formatted_s(:db)) 101 | 102 | # chose 01 and 20 day of the current month 103 | page.find('input#q_last_seen_at_gteq_datetime_picker').click 104 | page.find('.xdsoft_datetimepicker', visible: true) 105 | .find('.xdsoft_calendar td.xdsoft_date[data-date="1"]').click 106 | page.find('.xdsoft_datetimepicker', visible: true) 107 | .find('.xdsoft_timepicker.active .xdsoft_time.xdsoft_current').click 108 | 109 | page.find('input#q_last_seen_at_lteq_datetime_picker').click 110 | page.find('.xdsoft_datetimepicker', visible: true) 111 | .find('.xdsoft_calendar td.xdsoft_date[data-date="20"]').click 112 | page.find('.xdsoft_datetimepicker', visible: true) 113 | .find('.xdsoft_timepicker.active .xdsoft_time.xdsoft_current').click 114 | 115 | @value_from = page.find('#q_last_seen_at_gteq_datetime_picker').value 116 | @value_to = page.find('#q_last_seen_at_lteq_datetime_picker').value 117 | 118 | page.find('#sidebar input[type=submit]').click 119 | page.has_css?('h4', text: 'Current filters:') 120 | end 121 | 122 | it 'finds the first and second authors, but not the third one, because he is outside of the filtered dates' do 123 | expect(page).to have_text('Ren') 124 | expect(page).to have_text('Ron') 125 | expect(page).not_to have_text('Rey') 126 | end 127 | 128 | it 'input#value and placeholder is the same as before form submit' do 129 | # last_seen_at (without typecasting just a string) should contain Hours:Minutes, as selected before submit 130 | expect(page.find('#q_last_seen_at_gteq_datetime_picker').value).to match(@value_from) 131 | expect(page.find('#q_last_seen_at_lteq_datetime_picker').value).to match(@value_to) 132 | 133 | expect(page).to have_css('#q_last_seen_at_gteq_datetime_picker[placeholder=From]') 134 | expect(page).to have_css('#q_last_seen_at_lteq_datetime_picker[placeholder=To]') 135 | end 136 | end 137 | end 138 | end 139 | -------------------------------------------------------------------------------- /app/assets/stylesheets/vendor/jquery.datetimepicker.css: -------------------------------------------------------------------------------- 1 | .xdsoft_datetimepicker { 2 | box-shadow: 0 5px 15px -5px rgba(0, 0, 0, 0.506); 3 | background: #fff; 4 | border-bottom: 1px solid #bbb; 5 | border-left: 1px solid #ccc; 6 | border-right: 1px solid #ccc; 7 | border-top: 1px solid #ccc; 8 | color: #333; 9 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 10 | padding: 8px; 11 | padding-left: 0; 12 | padding-top: 2px; 13 | position: absolute; 14 | z-index: 9999; 15 | -moz-box-sizing: border-box; 16 | box-sizing: border-box; 17 | display: none; 18 | } 19 | .xdsoft_datetimepicker.xdsoft_rtl { 20 | padding: 8px 0 8px 8px; 21 | } 22 | 23 | .xdsoft_datetimepicker iframe { 24 | position: absolute; 25 | left: 0; 26 | top: 0; 27 | width: 75px; 28 | height: 210px; 29 | background: transparent; 30 | border: none; 31 | } 32 | 33 | /*For IE8 or lower*/ 34 | .xdsoft_datetimepicker button { 35 | border: none !important; 36 | } 37 | 38 | .xdsoft_noselect { 39 | -webkit-touch-callout: none; 40 | -webkit-user-select: none; 41 | -khtml-user-select: none; 42 | -moz-user-select: none; 43 | -ms-user-select: none; 44 | -o-user-select: none; 45 | user-select: none; 46 | } 47 | 48 | .xdsoft_noselect::selection { background: transparent } 49 | .xdsoft_noselect::-moz-selection { background: transparent } 50 | 51 | .xdsoft_datetimepicker.xdsoft_inline { 52 | display: inline-block; 53 | position: static; 54 | box-shadow: none; 55 | } 56 | 57 | .xdsoft_datetimepicker * { 58 | -moz-box-sizing: border-box; 59 | box-sizing: border-box; 60 | padding: 0; 61 | margin: 0; 62 | } 63 | 64 | .xdsoft_datetimepicker .xdsoft_datepicker, .xdsoft_datetimepicker .xdsoft_timepicker { 65 | display: none; 66 | } 67 | 68 | .xdsoft_datetimepicker .xdsoft_datepicker.active, .xdsoft_datetimepicker .xdsoft_timepicker.active { 69 | display: block; 70 | } 71 | 72 | .xdsoft_datetimepicker .xdsoft_datepicker { 73 | width: 224px; 74 | float: left; 75 | margin-left: 8px; 76 | } 77 | .xdsoft_datetimepicker.xdsoft_rtl .xdsoft_datepicker { 78 | float: right; 79 | margin-right: 8px; 80 | margin-left: 0; 81 | } 82 | 83 | .xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_datepicker { 84 | width: 256px; 85 | } 86 | 87 | .xdsoft_datetimepicker .xdsoft_timepicker { 88 | width: 58px; 89 | float: left; 90 | text-align: center; 91 | margin-left: 8px; 92 | margin-top: 0; 93 | } 94 | .xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker { 95 | float: right; 96 | margin-right: 8px; 97 | margin-left: 0; 98 | } 99 | 100 | .xdsoft_datetimepicker .xdsoft_datepicker.active+.xdsoft_timepicker { 101 | margin-top: 8px; 102 | margin-bottom: 3px 103 | } 104 | 105 | .xdsoft_datetimepicker .xdsoft_monthpicker { 106 | position: relative; 107 | text-align: center; 108 | } 109 | 110 | .xdsoft_datetimepicker .xdsoft_label i, 111 | .xdsoft_datetimepicker .xdsoft_prev, 112 | .xdsoft_datetimepicker .xdsoft_next, 113 | .xdsoft_datetimepicker .xdsoft_today_button { 114 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAeCAYAAADaW7vzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Q0NBRjI1NjM0M0UwMTFFNDk4NkFGMzJFQkQzQjEwRUIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6Q0NBRjI1NjQ0M0UwMTFFNDk4NkFGMzJFQkQzQjEwRUIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDQ0FGMjU2MTQzRTAxMUU0OTg2QUYzMkVCRDNCMTBFQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDQ0FGMjU2MjQzRTAxMUU0OTg2QUYzMkVCRDNCMTBFQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoNEP54AAAIOSURBVHja7Jq9TsMwEMcxrZD4WpBYeKUCe+kTMCACHZh4BFfHO/AAIHZGFhYkBBsSEqxsLCAgXKhbXYOTxh9pfJVP+qutnZ5s/5Lz2Y5I03QhWji2GIcgAokWgfCxNvcOCCGKqiSqhUp0laHOne05vdEyGMfkdxJDVjgwDlEQgYQBgx+ULJaWSXXS6r/ER5FBVR8VfGftTKcITNs+a1XpcFoExREIDF14AVIFxgQUS+h520cdud6wNkC0UBw6BCO/HoCYwBhD8QCkQ/x1mwDyD4plh4D6DDV0TAGyo4HcawLIBBSLDkHeH0Mg2yVP3l4TQMZQDDsEOl/MgHQqhMNuE0D+oBh0CIr8MAKyazBH9WyBuKxDWgbXfjNf32TZ1KWm/Ap1oSk/R53UtQ5xTh3LUlMmT8gt6g51Q9p+SobxgJQ/qmsfZhWywGFSl0yBjCLJCMgXail3b7+rumdVJ2YRss4cN+r6qAHDkPWjPjdJCF4n9RmAD/V9A/Wp4NQassDjwlB6XBiCxcJQWmZZb8THFilfy/lfrTvLghq2TqTHrRMTKNJ0sIhdo15RT+RpyWwFdY96UZ/LdQKBGjcXpcc1AlSFEfLmouD+1knuxBDUVrvOBmoOC/rEcN7OQxKVeJTCiAdUzUJhA2Oez9QTkp72OTVcxDcXY8iKNkxGAJXmJCOQwOa6dhyXsOa6XwEGAKdeb5ET3rQdAAAAAElFTkSuQmCC); 115 | } 116 | 117 | .xdsoft_datetimepicker .xdsoft_label i { 118 | opacity: 0.5; 119 | background-position: -92px -19px; 120 | display: inline-block; 121 | width: 9px; 122 | height: 20px; 123 | vertical-align: middle; 124 | } 125 | 126 | .xdsoft_datetimepicker .xdsoft_prev { 127 | float: left; 128 | background-position: -20px 0; 129 | } 130 | .xdsoft_datetimepicker .xdsoft_today_button { 131 | float: left; 132 | background-position: -70px 0; 133 | margin-left: 5px; 134 | } 135 | 136 | .xdsoft_datetimepicker .xdsoft_next { 137 | float: right; 138 | background-position: 0 0; 139 | } 140 | 141 | .xdsoft_datetimepicker .xdsoft_next, 142 | .xdsoft_datetimepicker .xdsoft_prev , 143 | .xdsoft_datetimepicker .xdsoft_today_button { 144 | background-color: transparent; 145 | background-repeat: no-repeat; 146 | border: 0 none; 147 | cursor: pointer; 148 | display: block; 149 | height: 30px; 150 | opacity: 0.5; 151 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; 152 | outline: medium none; 153 | overflow: hidden; 154 | padding: 0; 155 | position: relative; 156 | text-indent: 100%; 157 | white-space: nowrap; 158 | width: 20px; 159 | min-width: 0; 160 | } 161 | 162 | .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_prev, 163 | .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_next { 164 | float: none; 165 | background-position: -40px -15px; 166 | height: 15px; 167 | width: 30px; 168 | display: block; 169 | margin-left: 14px; 170 | margin-top: 7px; 171 | } 172 | .xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker .xdsoft_prev, 173 | .xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker .xdsoft_next { 174 | float: none; 175 | margin-left: 0; 176 | margin-right: 14px; 177 | } 178 | 179 | .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_prev { 180 | background-position: -40px 0; 181 | margin-bottom: 7px; 182 | margin-top: 0; 183 | } 184 | 185 | .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box { 186 | height: 151px; 187 | overflow: hidden; 188 | border-bottom: 1px solid #ddd; 189 | } 190 | 191 | .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div { 192 | background: #f5f5f5; 193 | border-top: 1px solid #ddd; 194 | color: #666; 195 | font-size: 12px; 196 | text-align: center; 197 | border-collapse: collapse; 198 | cursor: pointer; 199 | border-bottom-width: 0; 200 | height: 25px; 201 | line-height: 25px; 202 | } 203 | 204 | .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div > div:first-child { 205 | border-top-width: 0; 206 | } 207 | 208 | .xdsoft_datetimepicker .xdsoft_today_button:hover, 209 | .xdsoft_datetimepicker .xdsoft_next:hover, 210 | .xdsoft_datetimepicker .xdsoft_prev:hover { 211 | opacity: 1; 212 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 213 | } 214 | 215 | .xdsoft_datetimepicker .xdsoft_label { 216 | display: inline; 217 | position: relative; 218 | z-index: 9999; 219 | margin: 0; 220 | padding: 5px 3px; 221 | font-size: 14px; 222 | line-height: 20px; 223 | font-weight: bold; 224 | background-color: #fff; 225 | float: left; 226 | width: 182px; 227 | text-align: center; 228 | cursor: pointer; 229 | } 230 | 231 | .xdsoft_datetimepicker .xdsoft_label:hover>span { 232 | text-decoration: underline; 233 | } 234 | 235 | .xdsoft_datetimepicker .xdsoft_label:hover i { 236 | opacity: 1.0; 237 | } 238 | 239 | .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select { 240 | border: 1px solid #ccc; 241 | position: absolute; 242 | right: 0; 243 | top: 30px; 244 | z-index: 101; 245 | display: none; 246 | background: #fff; 247 | max-height: 160px; 248 | overflow-y: hidden; 249 | } 250 | 251 | .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select.xdsoft_monthselect{ right: -7px } 252 | .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select.xdsoft_yearselect{ right: 2px } 253 | .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option:hover { 254 | color: #fff; 255 | background: #ff8000; 256 | } 257 | 258 | .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option { 259 | padding: 2px 10px 2px 5px; 260 | text-decoration: none !important; 261 | } 262 | 263 | .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option.xdsoft_current { 264 | background: #33aaff; 265 | box-shadow: #178fe5 0 1px 3px 0 inset; 266 | color: #fff; 267 | font-weight: 700; 268 | } 269 | 270 | .xdsoft_datetimepicker .xdsoft_month { 271 | width: 100px; 272 | text-align: right; 273 | } 274 | 275 | .xdsoft_datetimepicker .xdsoft_calendar { 276 | clear: both; 277 | } 278 | 279 | .xdsoft_datetimepicker .xdsoft_year{ 280 | width: 48px; 281 | margin-left: 5px; 282 | } 283 | 284 | .xdsoft_datetimepicker .xdsoft_calendar table { 285 | border-collapse: collapse; 286 | width: 100%; 287 | 288 | } 289 | 290 | .xdsoft_datetimepicker .xdsoft_calendar td > div { 291 | padding-right: 5px; 292 | } 293 | 294 | .xdsoft_datetimepicker .xdsoft_calendar th { 295 | height: 25px; 296 | } 297 | 298 | .xdsoft_datetimepicker .xdsoft_calendar td,.xdsoft_datetimepicker .xdsoft_calendar th { 299 | width: 14.2857142%; 300 | background: #f5f5f5; 301 | border: 1px solid #ddd; 302 | color: #666; 303 | font-size: 12px; 304 | text-align: right; 305 | vertical-align: middle; 306 | padding: 0; 307 | border-collapse: collapse; 308 | cursor: pointer; 309 | height: 25px; 310 | } 311 | .xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_calendar td,.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_calendar th { 312 | width: 12.5%; 313 | } 314 | 315 | .xdsoft_datetimepicker .xdsoft_calendar th { 316 | background: #f1f1f1; 317 | } 318 | 319 | .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_today { 320 | color: #33aaff; 321 | } 322 | 323 | .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_highlighted_default { 324 | background: #ffe9d2; 325 | box-shadow: #ffb871 0 1px 4px 0 inset; 326 | color: #000; 327 | } 328 | .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_highlighted_mint { 329 | background: #c1ffc9; 330 | box-shadow: #00dd1c 0 1px 4px 0 inset; 331 | color: #000; 332 | } 333 | 334 | .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_default, 335 | .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current, 336 | .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_current { 337 | background: #33aaff; 338 | box-shadow: #178fe5 0 1px 3px 0 inset; 339 | color: #fff; 340 | font-weight: 700; 341 | } 342 | 343 | .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month, 344 | .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled, 345 | .xdsoft_datetimepicker .xdsoft_time_box >div >div.xdsoft_disabled { 346 | opacity: 0.5; 347 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; 348 | cursor: default; 349 | } 350 | 351 | .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month.xdsoft_disabled { 352 | opacity: 0.2; 353 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)"; 354 | } 355 | 356 | .xdsoft_datetimepicker .xdsoft_calendar td:hover, 357 | .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div:hover { 358 | color: #fff !important; 359 | background: #ff8000 !important; 360 | box-shadow: none !important; 361 | } 362 | 363 | .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current.xdsoft_disabled:hover, 364 | .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current.xdsoft_disabled:hover { 365 | background: #33aaff !important; 366 | box-shadow: #178fe5 0 1px 3px 0 inset !important; 367 | color: #fff !important; 368 | } 369 | 370 | .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled:hover, 371 | .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_disabled:hover { 372 | color: inherit !important; 373 | background: inherit !important; 374 | box-shadow: inherit !important; 375 | } 376 | 377 | .xdsoft_datetimepicker .xdsoft_calendar th { 378 | font-weight: 700; 379 | text-align: center; 380 | color: #999; 381 | cursor: default; 382 | } 383 | 384 | .xdsoft_datetimepicker .xdsoft_copyright { 385 | color: #ccc !important; 386 | font-size: 10px; 387 | clear: both; 388 | float: none; 389 | margin-left: 8px; 390 | } 391 | 392 | .xdsoft_datetimepicker .xdsoft_copyright a { color: #eee !important } 393 | .xdsoft_datetimepicker .xdsoft_copyright a:hover { color: #aaa !important } 394 | 395 | .xdsoft_time_box { 396 | position: relative; 397 | border: 1px solid #ccc; 398 | } 399 | .xdsoft_scrollbar >.xdsoft_scroller { 400 | background: #ccc !important; 401 | height: 20px; 402 | border-radius: 3px; 403 | } 404 | .xdsoft_scrollbar { 405 | position: absolute; 406 | width: 7px; 407 | right: 0; 408 | top: 0; 409 | bottom: 0; 410 | cursor: pointer; 411 | } 412 | .xdsoft_datetimepicker.xdsoft_rtl .xdsoft_scrollbar { 413 | left: 0; 414 | right: auto; 415 | } 416 | .xdsoft_scroller_box { 417 | position: relative; 418 | } 419 | 420 | .xdsoft_datetimepicker.xdsoft_dark { 421 | box-shadow: 0 5px 15px -5px rgba(255, 255, 255, 0.506); 422 | background: #000; 423 | border-bottom: 1px solid #444; 424 | border-left: 1px solid #333; 425 | border-right: 1px solid #333; 426 | border-top: 1px solid #333; 427 | color: #ccc; 428 | } 429 | 430 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box { 431 | border-bottom: 1px solid #222; 432 | } 433 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box >div >div { 434 | background: #0a0a0a; 435 | border-top: 1px solid #222; 436 | color: #999; 437 | } 438 | 439 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_label { 440 | background-color: #000; 441 | } 442 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_label > .xdsoft_select { 443 | border: 1px solid #333; 444 | background: #000; 445 | } 446 | 447 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_label > .xdsoft_select > div > .xdsoft_option:hover { 448 | color: #000; 449 | background: #007fff; 450 | } 451 | 452 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_label > .xdsoft_select > div > .xdsoft_option.xdsoft_current { 453 | background: #cc5500; 454 | box-shadow: #b03e00 0 1px 3px 0 inset; 455 | color: #000; 456 | } 457 | 458 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_label i, 459 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_prev, 460 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_next, 461 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_today_button { 462 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAeCAYAAADaW7vzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUExQUUzOTA0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUExQUUzOTE0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQTFBRTM4RTQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQTFBRTM4RjQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pp0VxGEAAAIASURBVHja7JrNSgMxEMebtgh+3MSLr1T1Xn2CHoSKB08+QmR8Bx9A8e7RixdB9CKCoNdexIugxFlJa7rNZneTbLIpM/CnNLsdMvNjM8l0mRCiQ9Ye61IKCAgZAUnH+mU3MMZaHYChBnJUDzWOFZdVfc5+ZFLbrWDeXPwbxIqrLLfaeS0hEBVGIRQCEiZoHQwtlGSByCCdYBl8g8egTTAWoKQMRBRBcZxYlhzhKegqMOageErsCHVkk3hXIFooDgHB1KkHIHVgzKB4ADJQ/A1jAFmAYhkQqA5TOBtocrKrgXwQA8gcFIuAIO8sQSA7hidvPwaQGZSaAYHOUWJABhWWw2EMIH9QagQERU4SArJXo0ZZL18uvaxejXt/Em8xjVBXmvFr1KVm/AJ10tRe2XnraNqaJvKE3KHuUbfK1E+VHB0q40/y3sdQSxY4FHWeKJCunP8UyDdqJZenT3ntVV5jIYCAh20vT7ioP8tpf6E2lfEMwERe+whV1MHjwZB7PBiCxcGQWwKZKD62lfGNnP/1poFAA60T7rF1UgcKd2id3KDeUS+oLWV8DfWAepOfq00CgQabi9zjcgJVYVD7PVzQUAUGAQkbNJTBICDhgwYTjDYD6XeW08ZKh+A4pYkzenOxXUbvZcWz7E8ykRMnIHGX1XPl+1m2vPYpL+2qdb8CDAARlKFEz/ZVkAAAAABJRU5ErkJggg==); 463 | } 464 | 465 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td, 466 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th { 467 | background: #0a0a0a; 468 | border: 1px solid #222; 469 | color: #999; 470 | } 471 | 472 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th { 473 | background: #0e0e0e; 474 | } 475 | 476 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_today { 477 | color: #cc5500; 478 | } 479 | 480 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_highlighted_default { 481 | background: #ffe9d2; 482 | box-shadow: #ffb871 0 1px 4px 0 inset; 483 | color:#000; 484 | } 485 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_highlighted_mint { 486 | background: #c1ffc9; 487 | box-shadow: #00dd1c 0 1px 4px 0 inset; 488 | color:#000; 489 | } 490 | 491 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_default, 492 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_current, 493 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_current { 494 | background: #cc5500; 495 | box-shadow: #b03e00 0 1px 3px 0 inset; 496 | color: #000; 497 | } 498 | 499 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td:hover, 500 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box >div >div:hover { 501 | color: #000 !important; 502 | background: #007fff !important; 503 | } 504 | 505 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th { 506 | color: #666; 507 | } 508 | 509 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright { color: #333 !important } 510 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright a { color: #111 !important } 511 | .xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright a:hover { color: #555 !important } 512 | 513 | .xdsoft_dark .xdsoft_time_box { 514 | border: 1px solid #333; 515 | } 516 | 517 | .xdsoft_dark .xdsoft_scrollbar >.xdsoft_scroller { 518 | background: #333 !important; 519 | } 520 | .xdsoft_datetimepicker .xdsoft_save_selected { 521 | display: block; 522 | border: 1px solid #dddddd !important; 523 | margin-top: 5px; 524 | width: 100%; 525 | color: #454551; 526 | font-size: 13px; 527 | } 528 | .xdsoft_datetimepicker .blue-gradient-button { 529 | font-family: "museo-sans", "Book Antiqua", sans-serif; 530 | font-size: 12px; 531 | font-weight: 300; 532 | color: #82878c; 533 | height: 28px; 534 | position: relative; 535 | padding: 4px 17px 4px 33px; 536 | border: 1px solid #d7d8da; 537 | background: -moz-linear-gradient(top, #fff 0%, #f4f8fa 73%); 538 | /* FF3.6+ */ 539 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(73%, #f4f8fa)); 540 | /* Chrome,Safari4+ */ 541 | background: -webkit-linear-gradient(top, #fff 0%, #f4f8fa 73%); 542 | /* Chrome10+,Safari5.1+ */ 543 | background: -o-linear-gradient(top, #fff 0%, #f4f8fa 73%); 544 | /* Opera 11.10+ */ 545 | background: -ms-linear-gradient(top, #fff 0%, #f4f8fa 73%); 546 | /* IE10+ */ 547 | background: linear-gradient(to bottom, #fff 0%, #f4f8fa 73%); 548 | /* W3C */ 549 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fff', endColorstr='#f4f8fa',GradientType=0 ); 550 | /* IE6-9 */ 551 | } 552 | .xdsoft_datetimepicker .blue-gradient-button:hover, .xdsoft_datetimepicker .blue-gradient-button:focus, .xdsoft_datetimepicker .blue-gradient-button:hover span, .xdsoft_datetimepicker .blue-gradient-button:focus span { 553 | color: #454551; 554 | background: -moz-linear-gradient(top, #f4f8fa 0%, #FFF 73%); 555 | /* FF3.6+ */ 556 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f4f8fa), color-stop(73%, #FFF)); 557 | /* Chrome,Safari4+ */ 558 | background: -webkit-linear-gradient(top, #f4f8fa 0%, #FFF 73%); 559 | /* Chrome10+,Safari5.1+ */ 560 | background: -o-linear-gradient(top, #f4f8fa 0%, #FFF 73%); 561 | /* Opera 11.10+ */ 562 | background: -ms-linear-gradient(top, #f4f8fa 0%, #FFF 73%); 563 | /* IE10+ */ 564 | background: linear-gradient(to bottom, #f4f8fa 0%, #FFF 73%); 565 | /* W3C */ 566 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f8fa', endColorstr='#FFF',GradientType=0 ); 567 | /* IE6-9 */ 568 | } 569 | -------------------------------------------------------------------------------- /app/assets/javascripts/vendor/jquery.datetimepicker.full.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2016 3 | * @version 1.3.4 4 | * 5 | * Date formatter utility library that allows formatting date/time variables or Date objects using PHP DateTime format. 6 | * @see http://php.net/manual/en/function.date.php 7 | * 8 | * For more JQuery plugins visit http://plugins.krajee.com 9 | * For more Yii related demos visit http://demos.krajee.com 10 | */var DateFormatter;!function(){"use strict";var t,e,r,n,a,u,i;u=864e5,i=3600,t=function(t,e){return"string"==typeof t&&"string"==typeof e&&t.toLowerCase()===e.toLowerCase()},e=function(t,r,n){var a=n||"0",u=t.toString();return u.lengths?"20":"19")+i):s,g=!0;break;case"m":case"n":case"M":case"F":if(isNaN(s)){if(o=d.getMonth(i),!(o>0))return null;y.month=o}else{if(!(s>=1&&12>=s))return null;y.month=s}g=!0;break;case"d":case"j":if(!(s>=1&&31>=s))return null;y.day=s,g=!0;break;case"g":case"h":if(c=n.indexOf("a")>-1?n.indexOf("a"):n.indexOf("A")>-1?n.indexOf("A"):-1,h=a[c],c>-1)f=t(h,p.meridiem[0])?0:t(h,p.meridiem[1])?12:-1,s>=1&&12>=s&&f>-1?y.hour=s+f-1:s>=0&&23>=s&&(y.hour=s);else{if(!(s>=0&&23>=s))return null;y.hour=s}m=!0;break;case"G":case"H":if(!(s>=0&&23>=s))return null;y.hour=s,m=!0;break;case"i":if(!(s>=0&&59>=s))return null;y.min=s,m=!0;break;case"s":if(!(s>=0&&59>=s))return null;y.sec=s,m=!0}if(g===!0&&y.year&&y.month&&y.day)y.date=new Date(y.year,y.month-1,y.day,y.hour,y.min,y.sec,0);else{if(m!==!0)return null;y.date=new Date(0,0,0,y.hour,y.min,y.sec,0)}return y.date},guessDate:function(t,e){if("string"!=typeof t)return t;var r,n,a,u,i,s,o=this,c=t.replace(o.separators,"\x00").split("\x00"),f=/^[djmn]/g,l=e.match(o.validParts),h=new Date,d=0;if(!f.test(l[0]))return t;for(a=0;ar?r:4,n=parseInt(4>r?n.toString().substr(0,4-r)+i:i.substr(0,4)),!n)return null;h.setFullYear(n);break;case 3:h.setHours(s);break;case 4:h.setMinutes(s);break;case 5:h.setSeconds(s)}u=i.substr(d),u.length>0&&c.splice(a+1,0,u)}return h},parseFormat:function(t,r){var n,a=this,s=a.dateSettings,o=/\\?(.?)/gi,c=function(t,e){return n[t]?n[t]():e};return n={d:function(){return e(n.j(),2)},D:function(){return s.daysShort[n.w()]},j:function(){return r.getDate()},l:function(){return s.days[n.w()]},N:function(){return n.w()||7},w:function(){return r.getDay()},z:function(){var t=new Date(n.Y(),n.n()-1,n.j()),e=new Date(n.Y(),0,1);return Math.round((t-e)/u)},W:function(){var t=new Date(n.Y(),n.n()-1,n.j()-n.N()+3),r=new Date(t.getFullYear(),0,4);return e(1+Math.round((t-r)/u/7),2)},F:function(){return s.months[r.getMonth()]},m:function(){return e(n.n(),2)},M:function(){return s.monthsShort[r.getMonth()]},n:function(){return r.getMonth()+1},t:function(){return new Date(n.Y(),n.n(),0).getDate()},L:function(){var t=n.Y();return t%4===0&&t%100!==0||t%400===0?1:0},o:function(){var t=n.n(),e=n.W(),r=n.Y();return r+(12===t&&9>e?1:1===t&&e>9?-1:0)},Y:function(){return r.getFullYear()},y:function(){return n.Y().toString().slice(-2)},a:function(){return n.A().toLowerCase()},A:function(){var t=n.G()<12?0:1;return s.meridiem[t]},B:function(){var t=r.getUTCHours()*i,n=60*r.getUTCMinutes(),a=r.getUTCSeconds();return e(Math.floor((t+n+a+i)/86.4)%1e3,3)},g:function(){return n.G()%12||12},G:function(){return r.getHours()},h:function(){return e(n.g(),2)},H:function(){return e(n.G(),2)},i:function(){return e(r.getMinutes(),2)},s:function(){return e(r.getSeconds(),2)},u:function(){return e(1e3*r.getMilliseconds(),6)},e:function(){var t=/\((.*)\)/.exec(String(r))[1];return t||"Coordinated Universal Time"},I:function(){var t=new Date(n.Y(),0),e=Date.UTC(n.Y(),0),r=new Date(n.Y(),6),a=Date.UTC(n.Y(),6);return t-e!==r-a?1:0},O:function(){var t=r.getTimezoneOffset(),n=Math.abs(t);return(t>0?"-":"+")+e(100*Math.floor(n/60)+n%60,4)},P:function(){var t=n.O();return t.substr(0,3)+":"+t.substr(3,2)},T:function(){var t=(String(r).match(a.tzParts)||[""]).pop().replace(a.tzClip,"");return t||"UTC"},Z:function(){return 60*-r.getTimezoneOffset()},c:function(){return"Y-m-d\\TH:i:sP".replace(o,c)},r:function(){return"D, d M Y H:i:s O".replace(o,c)},U:function(){return r.getTime()/1e3||0}},c(t,t)},formatDate:function(t,e){var r,n,a,u,i,s=this,o="",c="\\";if("string"==typeof t&&(t=s.parseDate(t,e),!t))return null;if(t instanceof Date){for(a=e.length,r=0;a>r;r++)i=e.charAt(r),"S"!==i&&i!==c&&(r>0&&e.charAt(r-1)===c?o+=i:(u=s.parseFormat(i,t),r!==a-1&&s.intParts.test(i)&&"S"===e.charAt(r+1)&&(n=parseInt(u)||0,u+=s.dateSettings.ordinal(n)),o+=u));return o}return""}}}();/** 11 | * @preserve jQuery DateTimePicker 12 | * @homepage http://xdsoft.net/jqplugins/datetimepicker/ 13 | * @author Chupurnov Valeriy () 14 | */ 15 | 16 | /** 17 | * @param {jQuery} $ 18 | */ 19 | var datetimepickerFactory = function ($) { 20 | 'use strict'; 21 | 22 | var default_options = { 23 | i18n: { 24 | ar: { // Arabic 25 | months: [ 26 | "كانون الثاني", "شباط", "آذار", "نيسان", "مايو", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول" 27 | ], 28 | dayOfWeekShort: [ 29 | "ن", "ث", "ع", "خ", "ج", "س", "ح" 30 | ], 31 | dayOfWeek: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"] 32 | }, 33 | ro: { // Romanian 34 | months: [ 35 | "Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie" 36 | ], 37 | dayOfWeekShort: [ 38 | "Du", "Lu", "Ma", "Mi", "Jo", "Vi", "Sâ" 39 | ], 40 | dayOfWeek: ["Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă"] 41 | }, 42 | id: { // Indonesian 43 | months: [ 44 | "Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember" 45 | ], 46 | dayOfWeekShort: [ 47 | "Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab" 48 | ], 49 | dayOfWeek: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"] 50 | }, 51 | is: { // Icelandic 52 | months: [ 53 | "Janúar", "Febrúar", "Mars", "Apríl", "Maí", "Júní", "Júlí", "Ágúst", "September", "Október", "Nóvember", "Desember" 54 | ], 55 | dayOfWeekShort: [ 56 | "Sun", "Mán", "Þrið", "Mið", "Fim", "Fös", "Lau" 57 | ], 58 | dayOfWeek: ["Sunnudagur", "Mánudagur", "Þriðjudagur", "Miðvikudagur", "Fimmtudagur", "Föstudagur", "Laugardagur"] 59 | }, 60 | bg: { // Bulgarian 61 | months: [ 62 | "Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември" 63 | ], 64 | dayOfWeekShort: [ 65 | "Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб" 66 | ], 67 | dayOfWeek: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота"] 68 | }, 69 | fa: { // Persian/Farsi 70 | months: [ 71 | 'فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند' 72 | ], 73 | dayOfWeekShort: [ 74 | 'یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه' 75 | ], 76 | dayOfWeek: ["یک‌شنبه", "دوشنبه", "سه‌شنبه", "چهارشنبه", "پنج‌شنبه", "جمعه", "شنبه", "یک‌شنبه"] 77 | }, 78 | ru: { // Russian 79 | months: [ 80 | 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь' 81 | ], 82 | dayOfWeekShort: [ 83 | "Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб" 84 | ], 85 | dayOfWeek: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"] 86 | }, 87 | uk: { // Ukrainian 88 | months: [ 89 | 'Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень' 90 | ], 91 | dayOfWeekShort: [ 92 | "Ндл", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Сбт" 93 | ], 94 | dayOfWeek: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятниця", "Субота"] 95 | }, 96 | en: { // English 97 | months: [ 98 | "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" 99 | ], 100 | dayOfWeekShort: [ 101 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 102 | ], 103 | dayOfWeek: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] 104 | }, 105 | el: { // Ελληνικά 106 | months: [ 107 | "Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος" 108 | ], 109 | dayOfWeekShort: [ 110 | "Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ" 111 | ], 112 | dayOfWeek: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"] 113 | }, 114 | de: { // German 115 | months: [ 116 | 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' 117 | ], 118 | dayOfWeekShort: [ 119 | "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa" 120 | ], 121 | dayOfWeek: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"] 122 | }, 123 | nl: { // Dutch 124 | months: [ 125 | "januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december" 126 | ], 127 | dayOfWeekShort: [ 128 | "zo", "ma", "di", "wo", "do", "vr", "za" 129 | ], 130 | dayOfWeek: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"] 131 | }, 132 | tr: { // Turkish 133 | months: [ 134 | "Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık" 135 | ], 136 | dayOfWeekShort: [ 137 | "Paz", "Pts", "Sal", "Çar", "Per", "Cum", "Cts" 138 | ], 139 | dayOfWeek: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"] 140 | }, 141 | fr: { //French 142 | months: [ 143 | "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" 144 | ], 145 | dayOfWeekShort: [ 146 | "Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam" 147 | ], 148 | dayOfWeek: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"] 149 | }, 150 | es: { // Spanish 151 | months: [ 152 | "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" 153 | ], 154 | dayOfWeekShort: [ 155 | "Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb" 156 | ], 157 | dayOfWeek: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"] 158 | }, 159 | th: { // Thai 160 | months: [ 161 | 'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน', 'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม' 162 | ], 163 | dayOfWeekShort: [ 164 | 'อา.', 'จ.', 'อ.', 'พ.', 'พฤ.', 'ศ.', 'ส.' 165 | ], 166 | dayOfWeek: ["อาทิตย์", "จันทร์", "อังคาร", "พุธ", "พฤหัส", "ศุกร์", "เสาร์", "อาทิตย์"] 167 | }, 168 | pl: { // Polish 169 | months: [ 170 | "styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień" 171 | ], 172 | dayOfWeekShort: [ 173 | "nd", "pn", "wt", "śr", "cz", "pt", "sb" 174 | ], 175 | dayOfWeek: ["niedziela", "poniedziałek", "wtorek", "środa", "czwartek", "piątek", "sobota"] 176 | }, 177 | pt: { // Portuguese 178 | months: [ 179 | "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro" 180 | ], 181 | dayOfWeekShort: [ 182 | "Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab" 183 | ], 184 | dayOfWeek: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"] 185 | }, 186 | ch: { // Simplified Chinese 187 | months: [ 188 | "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月" 189 | ], 190 | dayOfWeekShort: [ 191 | "日", "一", "二", "三", "四", "五", "六" 192 | ] 193 | }, 194 | se: { // Swedish 195 | months: [ 196 | "Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December" 197 | ], 198 | dayOfWeekShort: [ 199 | "Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör" 200 | ] 201 | }, 202 | km: { // Khmer (ភាសាខ្មែរ) 203 | months: [ 204 | "មករា​", "កុម្ភៈ", "មិនា​", "មេសា​", "ឧសភា​", "មិថុនា​", "កក្កដា​", "សីហា​", "កញ្ញា​", "តុលា​", "វិច្ឆិកា", "ធ្នូ​" 205 | ], 206 | dayOfWeekShort: ["អាទិ​", "ច័ន្ទ​", "អង្គារ​", "ពុធ​", "ព្រហ​​", "សុក្រ​", "សៅរ៍"], 207 | dayOfWeek: ["អាទិត្យ​", "ច័ន្ទ​", "អង្គារ​", "ពុធ​", "ព្រហស្បតិ៍​", "សុក្រ​", "សៅរ៍"] 208 | }, 209 | kr: { // Korean 210 | months: [ 211 | "1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월" 212 | ], 213 | dayOfWeekShort: [ 214 | "일", "월", "화", "수", "목", "금", "토" 215 | ], 216 | dayOfWeek: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"] 217 | }, 218 | it: { // Italian 219 | months: [ 220 | "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre" 221 | ], 222 | dayOfWeekShort: [ 223 | "Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab" 224 | ], 225 | dayOfWeek: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"] 226 | }, 227 | da: { // Dansk 228 | months: [ 229 | "Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December" 230 | ], 231 | dayOfWeekShort: [ 232 | "Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør" 233 | ], 234 | dayOfWeek: ["søndag", "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag"] 235 | }, 236 | no: { // Norwegian 237 | months: [ 238 | "Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember" 239 | ], 240 | dayOfWeekShort: [ 241 | "Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør" 242 | ], 243 | dayOfWeek: ['Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'] 244 | }, 245 | ja: { // Japanese 246 | months: [ 247 | "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月" 248 | ], 249 | dayOfWeekShort: [ 250 | "日", "月", "火", "水", "木", "金", "土" 251 | ], 252 | dayOfWeek: ["日曜", "月曜", "火曜", "水曜", "木曜", "金曜", "土曜"] 253 | }, 254 | vi: { // Vietnamese 255 | months: [ 256 | "Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12" 257 | ], 258 | dayOfWeekShort: [ 259 | "CN", "T2", "T3", "T4", "T5", "T6", "T7" 260 | ], 261 | dayOfWeek: ["Chủ nhật", "Thứ hai", "Thứ ba", "Thứ tư", "Thứ năm", "Thứ sáu", "Thứ bảy"] 262 | }, 263 | sl: { // Slovenščina 264 | months: [ 265 | "Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December" 266 | ], 267 | dayOfWeekShort: [ 268 | "Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob" 269 | ], 270 | dayOfWeek: ["Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota"] 271 | }, 272 | cs: { // Čeština 273 | months: [ 274 | "Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec" 275 | ], 276 | dayOfWeekShort: [ 277 | "Ne", "Po", "Út", "St", "Čt", "Pá", "So" 278 | ] 279 | }, 280 | hu: { // Hungarian 281 | months: [ 282 | "Január", "Február", "Március", "Április", "Május", "Június", "Július", "Augusztus", "Szeptember", "Október", "November", "December" 283 | ], 284 | dayOfWeekShort: [ 285 | "Va", "Hé", "Ke", "Sze", "Cs", "Pé", "Szo" 286 | ], 287 | dayOfWeek: ["vasárnap", "hétfő", "kedd", "szerda", "csütörtök", "péntek", "szombat"] 288 | }, 289 | az: { //Azerbaijanian (Azeri) 290 | months: [ 291 | "Yanvar", "Fevral", "Mart", "Aprel", "May", "Iyun", "Iyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr" 292 | ], 293 | dayOfWeekShort: [ 294 | "B", "Be", "Ça", "Ç", "Ca", "C", "Ş" 295 | ], 296 | dayOfWeek: ["Bazar", "Bazar ertəsi", "Çərşənbə axşamı", "Çərşənbə", "Cümə axşamı", "Cümə", "Şənbə"] 297 | }, 298 | bs: { //Bosanski 299 | months: [ 300 | "Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar" 301 | ], 302 | dayOfWeekShort: [ 303 | "Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub" 304 | ], 305 | dayOfWeek: ["Nedjelja","Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota"] 306 | }, 307 | ca: { //Català 308 | months: [ 309 | "Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre" 310 | ], 311 | dayOfWeekShort: [ 312 | "Dg", "Dl", "Dt", "Dc", "Dj", "Dv", "Ds" 313 | ], 314 | dayOfWeek: ["Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte"] 315 | }, 316 | 'en-GB': { //English (British) 317 | months: [ 318 | "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" 319 | ], 320 | dayOfWeekShort: [ 321 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 322 | ], 323 | dayOfWeek: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] 324 | }, 325 | et: { //"Eesti" 326 | months: [ 327 | "Jaanuar", "Veebruar", "Märts", "Aprill", "Mai", "Juuni", "Juuli", "August", "September", "Oktoober", "November", "Detsember" 328 | ], 329 | dayOfWeekShort: [ 330 | "P", "E", "T", "K", "N", "R", "L" 331 | ], 332 | dayOfWeek: ["Pühapäev", "Esmaspäev", "Teisipäev", "Kolmapäev", "Neljapäev", "Reede", "Laupäev"] 333 | }, 334 | eu: { //Euskara 335 | months: [ 336 | "Urtarrila", "Otsaila", "Martxoa", "Apirila", "Maiatza", "Ekaina", "Uztaila", "Abuztua", "Iraila", "Urria", "Azaroa", "Abendua" 337 | ], 338 | dayOfWeekShort: [ 339 | "Ig.", "Al.", "Ar.", "Az.", "Og.", "Or.", "La." 340 | ], 341 | dayOfWeek: ['Igandea', 'Astelehena', 'Asteartea', 'Asteazkena', 'Osteguna', 'Ostirala', 'Larunbata'] 342 | }, 343 | fi: { //Finnish (Suomi) 344 | months: [ 345 | "Tammikuu", "Helmikuu", "Maaliskuu", "Huhtikuu", "Toukokuu", "Kesäkuu", "Heinäkuu", "Elokuu", "Syyskuu", "Lokakuu", "Marraskuu", "Joulukuu" 346 | ], 347 | dayOfWeekShort: [ 348 | "Su", "Ma", "Ti", "Ke", "To", "Pe", "La" 349 | ], 350 | dayOfWeek: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai"] 351 | }, 352 | gl: { //Galego 353 | months: [ 354 | "Xan", "Feb", "Maz", "Abr", "Mai", "Xun", "Xul", "Ago", "Set", "Out", "Nov", "Dec" 355 | ], 356 | dayOfWeekShort: [ 357 | "Dom", "Lun", "Mar", "Mer", "Xov", "Ven", "Sab" 358 | ], 359 | dayOfWeek: ["Domingo", "Luns", "Martes", "Mércores", "Xoves", "Venres", "Sábado"] 360 | }, 361 | hr: { //Hrvatski 362 | months: [ 363 | "Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac" 364 | ], 365 | dayOfWeekShort: [ 366 | "Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub" 367 | ], 368 | dayOfWeek: ["Nedjelja", "Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota"] 369 | }, 370 | ko: { //Korean (한국어) 371 | months: [ 372 | "1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월" 373 | ], 374 | dayOfWeekShort: [ 375 | "일", "월", "화", "수", "목", "금", "토" 376 | ], 377 | dayOfWeek: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"] 378 | }, 379 | lt: { //Lithuanian (lietuvių) 380 | months: [ 381 | "Sausio", "Vasario", "Kovo", "Balandžio", "Gegužės", "Birželio", "Liepos", "Rugpjūčio", "Rugsėjo", "Spalio", "Lapkričio", "Gruodžio" 382 | ], 383 | dayOfWeekShort: [ 384 | "Sek", "Pir", "Ant", "Tre", "Ket", "Pen", "Šeš" 385 | ], 386 | dayOfWeek: ["Sekmadienis", "Pirmadienis", "Antradienis", "Trečiadienis", "Ketvirtadienis", "Penktadienis", "Šeštadienis"] 387 | }, 388 | lv: { //Latvian (Latviešu) 389 | months: [ 390 | "Janvāris", "Februāris", "Marts", "Aprīlis ", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris" 391 | ], 392 | dayOfWeekShort: [ 393 | "Sv", "Pr", "Ot", "Tr", "Ct", "Pk", "St" 394 | ], 395 | dayOfWeek: ["Svētdiena", "Pirmdiena", "Otrdiena", "Trešdiena", "Ceturtdiena", "Piektdiena", "Sestdiena"] 396 | }, 397 | mk: { //Macedonian (Македонски) 398 | months: [ 399 | "јануари", "февруари", "март", "април", "мај", "јуни", "јули", "август", "септември", "октомври", "ноември", "декември" 400 | ], 401 | dayOfWeekShort: [ 402 | "нед", "пон", "вто", "сре", "чет", "пет", "саб" 403 | ], 404 | dayOfWeek: ["Недела", "Понеделник", "Вторник", "Среда", "Четврток", "Петок", "Сабота"] 405 | }, 406 | mn: { //Mongolian (Монгол) 407 | months: [ 408 | "1-р сар", "2-р сар", "3-р сар", "4-р сар", "5-р сар", "6-р сар", "7-р сар", "8-р сар", "9-р сар", "10-р сар", "11-р сар", "12-р сар" 409 | ], 410 | dayOfWeekShort: [ 411 | "Дав", "Мяг", "Лха", "Пүр", "Бсн", "Бям", "Ням" 412 | ], 413 | dayOfWeek: ["Даваа", "Мягмар", "Лхагва", "Пүрэв", "Баасан", "Бямба", "Ням"] 414 | }, 415 | 'pt-BR': { //Português(Brasil) 416 | months: [ 417 | "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro" 418 | ], 419 | dayOfWeekShort: [ 420 | "Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb" 421 | ], 422 | dayOfWeek: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"] 423 | }, 424 | sk: { //Slovenčina 425 | months: [ 426 | "Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December" 427 | ], 428 | dayOfWeekShort: [ 429 | "Ne", "Po", "Ut", "St", "Št", "Pi", "So" 430 | ], 431 | dayOfWeek: ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota"] 432 | }, 433 | sq: { //Albanian (Shqip) 434 | months: [ 435 | "Janar", "Shkurt", "Mars", "Prill", "Maj", "Qershor", "Korrik", "Gusht", "Shtator", "Tetor", "Nëntor", "Dhjetor" 436 | ], 437 | dayOfWeekShort: [ 438 | "Die", "Hën", "Mar", "Mër", "Enj", "Pre", "Shtu" 439 | ], 440 | dayOfWeek: ["E Diel", "E Hënë", "E Martē", "E Mërkurë", "E Enjte", "E Premte", "E Shtunë"] 441 | }, 442 | 'sr-YU': { //Serbian (Srpski) 443 | months: [ 444 | "Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar" 445 | ], 446 | dayOfWeekShort: [ 447 | "Ned", "Pon", "Uto", "Sre", "čet", "Pet", "Sub" 448 | ], 449 | dayOfWeek: ["Nedelja","Ponedeljak", "Utorak", "Sreda", "Četvrtak", "Petak", "Subota"] 450 | }, 451 | sr: { //Serbian Cyrillic (Српски) 452 | months: [ 453 | "јануар", "фебруар", "март", "април", "мај", "јун", "јул", "август", "септембар", "октобар", "новембар", "децембар" 454 | ], 455 | dayOfWeekShort: [ 456 | "нед", "пон", "уто", "сре", "чет", "пет", "суб" 457 | ], 458 | dayOfWeek: ["Недеља","Понедељак", "Уторак", "Среда", "Четвртак", "Петак", "Субота"] 459 | }, 460 | sv: { //Svenska 461 | months: [ 462 | "Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December" 463 | ], 464 | dayOfWeekShort: [ 465 | "Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör" 466 | ], 467 | dayOfWeek: ["Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag"] 468 | }, 469 | 'zh-TW': { //Traditional Chinese (繁體中文) 470 | months: [ 471 | "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月" 472 | ], 473 | dayOfWeekShort: [ 474 | "日", "一", "二", "三", "四", "五", "六" 475 | ], 476 | dayOfWeek: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"] 477 | }, 478 | zh: { //Simplified Chinese (简体中文) 479 | months: [ 480 | "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月" 481 | ], 482 | dayOfWeekShort: [ 483 | "日", "一", "二", "三", "四", "五", "六" 484 | ], 485 | dayOfWeek: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"] 486 | }, 487 | ug:{ // Uyghur(ئۇيغۇرچە) 488 | months: [ 489 | "1-ئاي","2-ئاي","3-ئاي","4-ئاي","5-ئاي","6-ئاي","7-ئاي","8-ئاي","9-ئاي","10-ئاي","11-ئاي","12-ئاي" 490 | ], 491 | dayOfWeek: [ 492 | "يەكشەنبە", "دۈشەنبە","سەيشەنبە","چارشەنبە","پەيشەنبە","جۈمە","شەنبە" 493 | ] 494 | }, 495 | he: { //Hebrew (עברית) 496 | months: [ 497 | 'ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר' 498 | ], 499 | dayOfWeekShort: [ 500 | 'א\'', 'ב\'', 'ג\'', 'ד\'', 'ה\'', 'ו\'', 'שבת' 501 | ], 502 | dayOfWeek: ["ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"] 503 | }, 504 | hy: { // Armenian 505 | months: [ 506 | "Հունվար", "Փետրվար", "Մարտ", "Ապրիլ", "Մայիս", "Հունիս", "Հուլիս", "Օգոստոս", "Սեպտեմբեր", "Հոկտեմբեր", "Նոյեմբեր", "Դեկտեմբեր" 507 | ], 508 | dayOfWeekShort: [ 509 | "Կի", "Երկ", "Երք", "Չոր", "Հնգ", "Ուրբ", "Շբթ" 510 | ], 511 | dayOfWeek: ["Կիրակի", "Երկուշաբթի", "Երեքշաբթի", "Չորեքշաբթի", "Հինգշաբթի", "Ուրբաթ", "Շաբաթ"] 512 | }, 513 | kg: { // Kyrgyz 514 | months: [ 515 | 'Үчтүн айы', 'Бирдин айы', 'Жалган Куран', 'Чын Куран', 'Бугу', 'Кулжа', 'Теке', 'Баш Оона', 'Аяк Оона', 'Тогуздун айы', 'Жетинин айы', 'Бештин айы' 516 | ], 517 | dayOfWeekShort: [ 518 | "Жек", "Дүй", "Шей", "Шар", "Бей", "Жум", "Ише" 519 | ], 520 | dayOfWeek: [ 521 | "Жекшемб", "Дүйшөмб", "Шейшемб", "Шаршемб", "Бейшемби", "Жума", "Ишенб" 522 | ] 523 | }, 524 | rm: { // Romansh 525 | months: [ 526 | "Schaner", "Favrer", "Mars", "Avrigl", "Matg", "Zercladur", "Fanadur", "Avust", "Settember", "October", "November", "December" 527 | ], 528 | dayOfWeekShort: [ 529 | "Du", "Gli", "Ma", "Me", "Gie", "Ve", "So" 530 | ], 531 | dayOfWeek: [ 532 | "Dumengia", "Glindesdi", "Mardi", "Mesemna", "Gievgia", "Venderdi", "Sonda" 533 | ] 534 | }, 535 | ka: { // Georgian 536 | months: [ 537 | 'იანვარი', 'თებერვალი', 'მარტი', 'აპრილი', 'მაისი', 'ივნისი', 'ივლისი', 'აგვისტო', 'სექტემბერი', 'ოქტომბერი', 'ნოემბერი', 'დეკემბერი' 538 | ], 539 | dayOfWeekShort: [ 540 | "კვ", "ორშ", "სამშ", "ოთხ", "ხუთ", "პარ", "შაბ" 541 | ], 542 | dayOfWeek: ["კვირა", "ორშაბათი", "სამშაბათი", "ოთხშაბათი", "ხუთშაბათი", "პარასკევი", "შაბათი"] 543 | } 544 | }, 545 | 546 | ownerDocument: document, 547 | contentWindow: window, 548 | 549 | value: '', 550 | rtl: false, 551 | 552 | format: 'Y/m/d H:i', 553 | formatTime: 'H:i', 554 | formatDate: 'Y/m/d', 555 | 556 | startDate: false, // new Date(), '1986/12/08', '-1970/01/05','-1970/01/05', 557 | step: 60, 558 | monthChangeSpinner: true, 559 | 560 | closeOnDateSelect: false, 561 | closeOnTimeSelect: true, 562 | closeOnWithoutClick: true, 563 | closeOnInputClick: true, 564 | openOnFocus: true, 565 | 566 | timepicker: true, 567 | datepicker: true, 568 | weeks: false, 569 | 570 | defaultTime: false, // use formatTime format (ex. '10:00' for formatTime: 'H:i') 571 | defaultDate: false, // use formatDate format (ex new Date() or '1986/12/08' or '-1970/01/05' or '-1970/01/05') 572 | 573 | minDate: false, 574 | maxDate: false, 575 | minTime: false, 576 | maxTime: false, 577 | minDateTime: false, 578 | maxDateTime: false, 579 | 580 | allowTimes: [], 581 | opened: false, 582 | initTime: true, 583 | inline: false, 584 | theme: '', 585 | touchMovedThreshold: 5, 586 | 587 | onSelectDate: function () {}, 588 | onSelectTime: function () {}, 589 | onChangeMonth: function () {}, 590 | onGetWeekOfYear: function () {}, 591 | onChangeYear: function () {}, 592 | onChangeDateTime: function () {}, 593 | onShow: function () {}, 594 | onClose: function () {}, 595 | onGenerate: function () {}, 596 | 597 | withoutCopyright: true, 598 | inverseButton: false, 599 | hours12: false, 600 | next: 'xdsoft_next', 601 | prev : 'xdsoft_prev', 602 | dayOfWeekStart: 0, 603 | parentID: 'body', 604 | timeHeightInTimePicker: 25, 605 | timepickerScrollbar: true, 606 | todayButton: true, 607 | prevButton: true, 608 | nextButton: true, 609 | defaultSelect: true, 610 | 611 | scrollMonth: true, 612 | scrollTime: true, 613 | scrollInput: true, 614 | 615 | lazyInit: false, 616 | mask: false, 617 | validateOnBlur: true, 618 | allowBlank: true, 619 | yearStart: 1950, 620 | yearEnd: 2050, 621 | monthStart: 0, 622 | monthEnd: 11, 623 | style: '', 624 | id: '', 625 | fixed: false, 626 | roundTime: 'round', // ceil, floor 627 | className: '', 628 | weekends: [], 629 | highlightedDates: [], 630 | highlightedPeriods: [], 631 | allowDates : [], 632 | allowDateRe : null, 633 | disabledDates : [], 634 | disabledWeekDays: [], 635 | yearOffset: 0, 636 | beforeShowDay: null, 637 | 638 | enterLikeTab: true, 639 | showApplyButton: false, 640 | insideParent: false, 641 | }; 642 | 643 | var dateHelper = null, 644 | defaultDateHelper = null, 645 | globalLocaleDefault = 'en', 646 | globalLocale = 'en'; 647 | 648 | var dateFormatterOptionsDefault = { 649 | meridiem: ['AM', 'PM'] 650 | }; 651 | 652 | var initDateFormatter = function(){ 653 | var locale = default_options.i18n[globalLocale], 654 | opts = { 655 | days: locale.dayOfWeek, 656 | daysShort: locale.dayOfWeekShort, 657 | months: locale.months, 658 | monthsShort: $.map(locale.months, function(n){ return n.substring(0, 3) }) 659 | }; 660 | 661 | if (typeof DateFormatter === 'function') { 662 | dateHelper = defaultDateHelper = new DateFormatter({ 663 | dateSettings: $.extend({}, dateFormatterOptionsDefault, opts) 664 | }); 665 | } 666 | }; 667 | 668 | var dateFormatters = { 669 | moment: { 670 | default_options:{ 671 | format: 'YYYY/MM/DD HH:mm', 672 | formatDate: 'YYYY/MM/DD', 673 | formatTime: 'HH:mm', 674 | }, 675 | formatter: { 676 | parseDate: function (date, format) { 677 | if(isFormatStandard(format)){ 678 | return defaultDateHelper.parseDate(date, format); 679 | } 680 | var d = moment(date, format); 681 | return d.isValid() ? d.toDate() : false; 682 | }, 683 | 684 | formatDate: function (date, format) { 685 | if(isFormatStandard(format)){ 686 | return defaultDateHelper.formatDate(date, format); 687 | } 688 | return moment(date).format(format); 689 | }, 690 | 691 | formatMask: function(format){ 692 | return format 693 | .replace(/Y{4}/g, '9999') 694 | .replace(/Y{2}/g, '99') 695 | .replace(/M{2}/g, '19') 696 | .replace(/D{2}/g, '39') 697 | .replace(/H{2}/g, '29') 698 | .replace(/m{2}/g, '59') 699 | .replace(/s{2}/g, '59'); 700 | }, 701 | } 702 | } 703 | } 704 | 705 | // for locale settings 706 | $.datetimepicker = { 707 | setLocale: function(locale){ 708 | var newLocale = default_options.i18n[locale] ? locale : globalLocaleDefault; 709 | if (globalLocale !== newLocale) { 710 | globalLocale = newLocale; 711 | // reinit date formatter 712 | initDateFormatter(); 713 | } 714 | }, 715 | 716 | setDateFormatter: function(dateFormatter) { 717 | if(typeof dateFormatter === 'string' && dateFormatters.hasOwnProperty(dateFormatter)){ 718 | var df = dateFormatters[dateFormatter]; 719 | $.extend(default_options, df.default_options); 720 | dateHelper = df.formatter; 721 | } 722 | else { 723 | dateHelper = dateFormatter; 724 | } 725 | }, 726 | }; 727 | 728 | var standardFormats = { 729 | RFC_2822: 'D, d M Y H:i:s O', 730 | ATOM: 'Y-m-d\TH:i:sP', 731 | ISO_8601: 'Y-m-d\TH:i:sO', 732 | RFC_822: 'D, d M y H:i:s O', 733 | RFC_850: 'l, d-M-y H:i:s T', 734 | RFC_1036: 'D, d M y H:i:s O', 735 | RFC_1123: 'D, d M Y H:i:s O', 736 | RSS: 'D, d M Y H:i:s O', 737 | W3C: 'Y-m-d\TH:i:sP' 738 | } 739 | 740 | var isFormatStandard = function(format){ 741 | return Object.values(standardFormats).indexOf(format) === -1 ? false : true; 742 | } 743 | 744 | $.extend($.datetimepicker, standardFormats); 745 | 746 | // first init date formatter 747 | initDateFormatter(); 748 | 749 | // fix for ie8 750 | if (!window.getComputedStyle) { 751 | window.getComputedStyle = function (el) { 752 | this.el = el; 753 | this.getPropertyValue = function (prop) { 754 | var re = /(-([a-z]))/g; 755 | if (prop === 'float') { 756 | prop = 'styleFloat'; 757 | } 758 | if (re.test(prop)) { 759 | prop = prop.replace(re, function (a, b, c) { 760 | return c.toUpperCase(); 761 | }); 762 | } 763 | return el.currentStyle[prop] || null; 764 | }; 765 | return this; 766 | }; 767 | } 768 | if (!Array.prototype.indexOf) { 769 | Array.prototype.indexOf = function (obj, start) { 770 | var i, j; 771 | for (i = (start || 0), j = this.length; i < j; i += 1) { 772 | if (this[i] === obj) { return i; } 773 | } 774 | return -1; 775 | }; 776 | } 777 | 778 | Date.prototype.countDaysInMonth = function () { 779 | return new Date(this.getFullYear(), this.getMonth() + 1, 0).getDate(); 780 | }; 781 | 782 | $.fn.xdsoftScroller = function (options, percent) { 783 | return this.each(function () { 784 | var timeboxparent = $(this), 785 | pointerEventToXY = function (e) { 786 | var out = {x: 0, y: 0}, 787 | touch; 788 | if (e.type === 'touchstart' || e.type === 'touchmove' || e.type === 'touchend' || e.type === 'touchcancel') { 789 | touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0]; 790 | out.x = touch.clientX; 791 | out.y = touch.clientY; 792 | } else if (e.type === 'mousedown' || e.type === 'mouseup' || e.type === 'mousemove' || e.type === 'mouseover' || e.type === 'mouseout' || e.type === 'mouseenter' || e.type === 'mouseleave') { 793 | out.x = e.clientX; 794 | out.y = e.clientY; 795 | } 796 | return out; 797 | }, 798 | timebox, 799 | parentHeight, 800 | height, 801 | scrollbar, 802 | scroller, 803 | maximumOffset = 100, 804 | start = false, 805 | startY = 0, 806 | startTop = 0, 807 | h1 = 0, 808 | touchStart = false, 809 | startTopScroll = 0, 810 | calcOffset = function () {}; 811 | 812 | if (percent === 'hide') { 813 | timeboxparent.find('.xdsoft_scrollbar').hide(); 814 | return; 815 | } 816 | 817 | if (!$(this).hasClass('xdsoft_scroller_box')) { 818 | timebox = timeboxparent.children().eq(0); 819 | parentHeight = timeboxparent[0].clientHeight; 820 | height = timebox[0].offsetHeight; 821 | scrollbar = $('
'); 822 | scroller = $('
'); 823 | scrollbar.append(scroller); 824 | 825 | timeboxparent.addClass('xdsoft_scroller_box').append(scrollbar); 826 | calcOffset = function calcOffset(event) { 827 | var offset = pointerEventToXY(event).y - startY + startTopScroll; 828 | if (offset < 0) { 829 | offset = 0; 830 | } 831 | if (offset + scroller[0].offsetHeight > h1) { 832 | offset = h1 - scroller[0].offsetHeight; 833 | } 834 | timeboxparent.trigger('scroll_element.xdsoft_scroller', [maximumOffset ? offset / maximumOffset : 0]); 835 | }; 836 | 837 | scroller 838 | .on('touchstart.xdsoft_scroller mousedown.xdsoft_scroller', function (event) { 839 | if (!parentHeight) { 840 | timeboxparent.trigger('resize_scroll.xdsoft_scroller', [percent]); 841 | } 842 | 843 | startY = pointerEventToXY(event).y; 844 | startTopScroll = parseInt(scroller.css('margin-top'), 10); 845 | h1 = scrollbar[0].offsetHeight; 846 | 847 | if (event.type === 'mousedown' || event.type === 'touchstart') { 848 | if (options.ownerDocument) { 849 | $(options.ownerDocument.body).addClass('xdsoft_noselect'); 850 | } 851 | $([options.ownerDocument.body, options.contentWindow]).on('touchend mouseup.xdsoft_scroller', function arguments_callee() { 852 | $([options.ownerDocument.body, options.contentWindow]).off('touchend mouseup.xdsoft_scroller', arguments_callee) 853 | .off('mousemove.xdsoft_scroller', calcOffset) 854 | .removeClass('xdsoft_noselect'); 855 | }); 856 | $(options.ownerDocument.body).on('mousemove.xdsoft_scroller', calcOffset); 857 | } else { 858 | touchStart = true; 859 | event.stopPropagation(); 860 | event.preventDefault(); 861 | } 862 | }) 863 | .on('touchmove', function (event) { 864 | if (touchStart) { 865 | event.preventDefault(); 866 | calcOffset(event); 867 | } 868 | }) 869 | .on('touchend touchcancel', function () { 870 | touchStart = false; 871 | startTopScroll = 0; 872 | }); 873 | 874 | timeboxparent 875 | .on('scroll_element.xdsoft_scroller', function (event, percentage) { 876 | if (!parentHeight) { 877 | timeboxparent.trigger('resize_scroll.xdsoft_scroller', [percentage, true]); 878 | } 879 | percentage = percentage > 1 ? 1 : (percentage < 0 || isNaN(percentage)) ? 0 : percentage; 880 | 881 | scroller.css('margin-top', maximumOffset * percentage); 882 | 883 | setTimeout(function () { 884 | timebox.css('marginTop', -parseInt((timebox[0].offsetHeight - parentHeight) * percentage, 10)); 885 | }, 10); 886 | }) 887 | .on('resize_scroll.xdsoft_scroller', function (event, percentage, noTriggerScroll) { 888 | var percent, sh; 889 | parentHeight = timeboxparent[0].clientHeight; 890 | height = timebox[0].offsetHeight; 891 | percent = parentHeight / height; 892 | sh = percent * scrollbar[0].offsetHeight; 893 | if (percent > 1) { 894 | scroller.hide(); 895 | } else { 896 | scroller.show(); 897 | scroller.css('height', parseInt(sh > 10 ? sh : 10, 10)); 898 | maximumOffset = scrollbar[0].offsetHeight - scroller[0].offsetHeight; 899 | if (noTriggerScroll !== true) { 900 | timeboxparent.trigger('scroll_element.xdsoft_scroller', [percentage || Math.abs(parseInt(timebox.css('marginTop'), 10)) / (height - parentHeight)]); 901 | } 902 | } 903 | }); 904 | 905 | timeboxparent.on('mousewheel', function (event) { 906 | var top = Math.abs(parseInt(timebox.css('marginTop'), 10)); 907 | 908 | top = top - (event.deltaY * 20); 909 | if (top < 0) { 910 | top = 0; 911 | } 912 | 913 | timeboxparent.trigger('scroll_element.xdsoft_scroller', [top / (height - parentHeight)]); 914 | event.stopPropagation(); 915 | return false; 916 | }); 917 | 918 | timeboxparent.on('touchstart', function (event) { 919 | start = pointerEventToXY(event); 920 | startTop = Math.abs(parseInt(timebox.css('marginTop'), 10)); 921 | }); 922 | 923 | timeboxparent.on('touchmove', function (event) { 924 | if (start) { 925 | event.preventDefault(); 926 | var coord = pointerEventToXY(event); 927 | timeboxparent.trigger('scroll_element.xdsoft_scroller', [(startTop - (coord.y - start.y)) / (height - parentHeight)]); 928 | } 929 | }); 930 | 931 | timeboxparent.on('touchend touchcancel', function () { 932 | start = false; 933 | startTop = 0; 934 | }); 935 | } 936 | timeboxparent.trigger('resize_scroll.xdsoft_scroller', [percent]); 937 | }); 938 | }; 939 | 940 | $.fn.datetimepicker = function (opt, opt2) { 941 | var result = this, 942 | KEY0 = 48, 943 | KEY9 = 57, 944 | _KEY0 = 96, 945 | _KEY9 = 105, 946 | CTRLKEY = 17, 947 | CMDKEY = 91, 948 | DEL = 46, 949 | ENTER = 13, 950 | ESC = 27, 951 | BACKSPACE = 8, 952 | ARROWLEFT = 37, 953 | ARROWUP = 38, 954 | ARROWRIGHT = 39, 955 | ARROWDOWN = 40, 956 | TAB = 9, 957 | F5 = 116, 958 | AKEY = 65, 959 | CKEY = 67, 960 | VKEY = 86, 961 | ZKEY = 90, 962 | YKEY = 89, 963 | ctrlDown = false, 964 | cmdDown = false, 965 | options = ($.isPlainObject(opt) || !opt) ? $.extend(true, {}, default_options, opt) : $.extend(true, {}, default_options), 966 | 967 | lazyInitTimer = 0, 968 | createDateTimePicker, 969 | destroyDateTimePicker, 970 | 971 | lazyInit = function (input) { 972 | input 973 | .on('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', function initOnActionCallback() { 974 | if (input.is(':disabled') || input.data('xdsoft_datetimepicker')) { 975 | return; 976 | } 977 | clearTimeout(lazyInitTimer); 978 | lazyInitTimer = setTimeout(function () { 979 | 980 | if (!input.data('xdsoft_datetimepicker')) { 981 | createDateTimePicker(input); 982 | } 983 | input 984 | .off('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', initOnActionCallback) 985 | .trigger('open.xdsoft'); 986 | }, 100); 987 | }); 988 | }; 989 | 990 | createDateTimePicker = function (input) { 991 | var datetimepicker = $('
'), 992 | xdsoft_copyright = $(''), 993 | datepicker = $('
'), 994 | month_picker = $('
' + 995 | '
' + 996 | '
' + 997 | '
'), 998 | calendar = $('
'), 999 | timepicker = $('
'), 1000 | timeboxparent = timepicker.find('.xdsoft_time_box').eq(0), 1001 | timebox = $('
'), 1002 | applyButton = $(''), 1003 | 1004 | monthselect = $('
'), 1005 | yearselect = $('
'), 1006 | triggerAfterOpen = false, 1007 | XDSoft_datetime, 1008 | 1009 | xchangeTimer, 1010 | timerclick, 1011 | current_time_index, 1012 | setPos, 1013 | timer = 0, 1014 | _xdsoft_datetime, 1015 | forEachAncestorOf; 1016 | 1017 | if (options.id) { 1018 | datetimepicker.attr('id', options.id); 1019 | } 1020 | if (options.style) { 1021 | datetimepicker.attr('style', options.style); 1022 | } 1023 | if (options.weeks) { 1024 | datetimepicker.addClass('xdsoft_showweeks'); 1025 | } 1026 | if (options.rtl) { 1027 | datetimepicker.addClass('xdsoft_rtl'); 1028 | } 1029 | 1030 | datetimepicker.addClass('xdsoft_' + options.theme); 1031 | datetimepicker.addClass(options.className); 1032 | 1033 | month_picker 1034 | .find('.xdsoft_month span') 1035 | .after(monthselect); 1036 | month_picker 1037 | .find('.xdsoft_year span') 1038 | .after(yearselect); 1039 | 1040 | month_picker 1041 | .find('.xdsoft_month,.xdsoft_year') 1042 | .on('touchstart mousedown.xdsoft', function (event) { 1043 | var select = $(this).find('.xdsoft_select').eq(0), 1044 | val = 0, 1045 | top = 0, 1046 | visible = select.is(':visible'), 1047 | items, 1048 | i; 1049 | 1050 | month_picker 1051 | .find('.xdsoft_select') 1052 | .hide(); 1053 | if (_xdsoft_datetime.currentTime) { 1054 | val = _xdsoft_datetime.currentTime[$(this).hasClass('xdsoft_month') ? 'getMonth' : 'getFullYear'](); 1055 | } 1056 | 1057 | select[visible ? 'hide' : 'show'](); 1058 | for (items = select.find('div.xdsoft_option'), i = 0; i < items.length; i += 1) { 1059 | if (items.eq(i).data('value') === val) { 1060 | break; 1061 | } else { 1062 | top += items[0].offsetHeight; 1063 | } 1064 | } 1065 | 1066 | select.xdsoftScroller(options, top / (select.children()[0].offsetHeight - (select[0].clientHeight))); 1067 | event.stopPropagation(); 1068 | return false; 1069 | }); 1070 | 1071 | var handleTouchMoved = function (event) { 1072 | var evt = event.originalEvent; 1073 | var touchPosition = evt.touches ? evt.touches[0] : evt; 1074 | this.touchStartPosition = this.touchStartPosition || touchPosition; 1075 | var xMovement = Math.abs(this.touchStartPosition.clientX - touchPosition.clientX); 1076 | var yMovement = Math.abs(this.touchStartPosition.clientY - touchPosition.clientY); 1077 | var distance = Math.sqrt(xMovement * xMovement + yMovement * yMovement); 1078 | if(distance > options.touchMovedThreshold) { 1079 | this.touchMoved = true; 1080 | } 1081 | } 1082 | 1083 | month_picker 1084 | .find('.xdsoft_select') 1085 | .xdsoftScroller(options) 1086 | .on('touchstart mousedown.xdsoft', function (event) { 1087 | var evt = event.originalEvent; 1088 | this.touchMoved = false; 1089 | this.touchStartPosition = evt.touches ? evt.touches[0] : evt; 1090 | event.stopPropagation(); 1091 | event.preventDefault(); 1092 | }) 1093 | .on('touchmove', '.xdsoft_option', handleTouchMoved) 1094 | .on('touchend mousedown.xdsoft', '.xdsoft_option', function () { 1095 | if (!this.touchMoved) { 1096 | if (_xdsoft_datetime.currentTime === undefined || _xdsoft_datetime.currentTime === null) { 1097 | _xdsoft_datetime.currentTime = _xdsoft_datetime.now(); 1098 | } 1099 | 1100 | var year = _xdsoft_datetime.currentTime.getFullYear(); 1101 | if (_xdsoft_datetime && _xdsoft_datetime.currentTime) { 1102 | _xdsoft_datetime.currentTime[$(this).parent().parent().hasClass('xdsoft_monthselect') ? 'setMonth' : 'setFullYear']($(this).data('value')); 1103 | } 1104 | 1105 | $(this).parent().parent().hide(); 1106 | 1107 | datetimepicker.trigger('xchange.xdsoft'); 1108 | if (options.onChangeMonth && $.isFunction(options.onChangeMonth)) { 1109 | options.onChangeMonth.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); 1110 | } 1111 | 1112 | if (year !== _xdsoft_datetime.currentTime.getFullYear() && $.isFunction(options.onChangeYear)) { 1113 | options.onChangeYear.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); 1114 | } 1115 | } 1116 | }); 1117 | 1118 | datetimepicker.getValue = function () { 1119 | return _xdsoft_datetime.getCurrentTime(); 1120 | }; 1121 | 1122 | datetimepicker.setOptions = function (_options) { 1123 | var highlightedDates = {}; 1124 | 1125 | options = $.extend(true, {}, options, _options); 1126 | 1127 | if (_options.allowTimes && $.isArray(_options.allowTimes) && _options.allowTimes.length) { 1128 | options.allowTimes = $.extend(true, [], _options.allowTimes); 1129 | } 1130 | 1131 | if (_options.weekends && $.isArray(_options.weekends) && _options.weekends.length) { 1132 | options.weekends = $.extend(true, [], _options.weekends); 1133 | } 1134 | 1135 | if (_options.allowDates && $.isArray(_options.allowDates) && _options.allowDates.length) { 1136 | options.allowDates = $.extend(true, [], _options.allowDates); 1137 | } 1138 | 1139 | if (_options.allowDateRe && Object.prototype.toString.call(_options.allowDateRe)==="[object String]") { 1140 | options.allowDateRe = new RegExp(_options.allowDateRe); 1141 | } 1142 | 1143 | if (_options.highlightedDates && $.isArray(_options.highlightedDates) && _options.highlightedDates.length) { 1144 | $.each(_options.highlightedDates, function (index, value) { 1145 | var splitData = $.map(value.split(','), $.trim), 1146 | exDesc, 1147 | hDate = new HighlightedDate(dateHelper.parseDate(splitData[0], options.formatDate), splitData[1], splitData[2]), // date, desc, style 1148 | keyDate = dateHelper.formatDate(hDate.date, options.formatDate); 1149 | if (highlightedDates[keyDate] !== undefined) { 1150 | exDesc = highlightedDates[keyDate].desc; 1151 | if (exDesc && exDesc.length && hDate.desc && hDate.desc.length) { 1152 | highlightedDates[keyDate].desc = exDesc + "\n" + hDate.desc; 1153 | } 1154 | } else { 1155 | highlightedDates[keyDate] = hDate; 1156 | } 1157 | }); 1158 | 1159 | options.highlightedDates = $.extend(true, [], highlightedDates); 1160 | } 1161 | 1162 | if (_options.highlightedPeriods && $.isArray(_options.highlightedPeriods) && _options.highlightedPeriods.length) { 1163 | highlightedDates = $.extend(true, [], options.highlightedDates); 1164 | $.each(_options.highlightedPeriods, function (index, value) { 1165 | var dateTest, // start date 1166 | dateEnd, 1167 | desc, 1168 | hDate, 1169 | keyDate, 1170 | exDesc, 1171 | style; 1172 | if ($.isArray(value)) { 1173 | dateTest = value[0]; 1174 | dateEnd = value[1]; 1175 | desc = value[2]; 1176 | style = value[3]; 1177 | } 1178 | else { 1179 | var splitData = $.map(value.split(','), $.trim); 1180 | dateTest = dateHelper.parseDate(splitData[0], options.formatDate); 1181 | dateEnd = dateHelper.parseDate(splitData[1], options.formatDate); 1182 | desc = splitData[2]; 1183 | style = splitData[3]; 1184 | } 1185 | 1186 | while (dateTest <= dateEnd) { 1187 | hDate = new HighlightedDate(dateTest, desc, style); 1188 | keyDate = dateHelper.formatDate(dateTest, options.formatDate); 1189 | dateTest.setDate(dateTest.getDate() + 1); 1190 | if (highlightedDates[keyDate] !== undefined) { 1191 | exDesc = highlightedDates[keyDate].desc; 1192 | if (exDesc && exDesc.length && hDate.desc && hDate.desc.length) { 1193 | highlightedDates[keyDate].desc = exDesc + "\n" + hDate.desc; 1194 | } 1195 | } else { 1196 | highlightedDates[keyDate] = hDate; 1197 | } 1198 | } 1199 | }); 1200 | 1201 | options.highlightedDates = $.extend(true, [], highlightedDates); 1202 | } 1203 | 1204 | if (_options.disabledDates && $.isArray(_options.disabledDates) && _options.disabledDates.length) { 1205 | options.disabledDates = $.extend(true, [], _options.disabledDates); 1206 | } 1207 | 1208 | if (_options.disabledWeekDays && $.isArray(_options.disabledWeekDays) && _options.disabledWeekDays.length) { 1209 | options.disabledWeekDays = $.extend(true, [], _options.disabledWeekDays); 1210 | } 1211 | 1212 | if ((options.open || options.opened) && (!options.inline)) { 1213 | input.trigger('open.xdsoft'); 1214 | } 1215 | 1216 | if (options.inline) { 1217 | triggerAfterOpen = true; 1218 | datetimepicker.addClass('xdsoft_inline'); 1219 | input.after(datetimepicker).hide(); 1220 | } 1221 | 1222 | if (options.inverseButton) { 1223 | options.next = 'xdsoft_prev'; 1224 | options.prev = 'xdsoft_next'; 1225 | } 1226 | 1227 | if (options.datepicker) { 1228 | datepicker.addClass('active'); 1229 | } else { 1230 | datepicker.removeClass('active'); 1231 | } 1232 | 1233 | if (options.timepicker) { 1234 | timepicker.addClass('active'); 1235 | } else { 1236 | timepicker.removeClass('active'); 1237 | } 1238 | 1239 | if (options.value) { 1240 | _xdsoft_datetime.setCurrentTime(options.value); 1241 | if (input && input.val) { 1242 | input.val(_xdsoft_datetime.str); 1243 | } 1244 | } 1245 | 1246 | if (isNaN(options.dayOfWeekStart)) { 1247 | options.dayOfWeekStart = 0; 1248 | } else { 1249 | options.dayOfWeekStart = parseInt(options.dayOfWeekStart, 10) % 7; 1250 | } 1251 | 1252 | if (!options.timepickerScrollbar) { 1253 | timeboxparent.xdsoftScroller(options, 'hide'); 1254 | } 1255 | 1256 | if (options.minDate && /^[\+\-](.*)$/.test(options.minDate)) { 1257 | options.minDate = dateHelper.formatDate(_xdsoft_datetime.strToDateTime(options.minDate), options.formatDate); 1258 | } 1259 | 1260 | if (options.maxDate && /^[\+\-](.*)$/.test(options.maxDate)) { 1261 | options.maxDate = dateHelper.formatDate(_xdsoft_datetime.strToDateTime(options.maxDate), options.formatDate); 1262 | } 1263 | 1264 | if (options.minDateTime && /^\+(.*)$/.test(options.minDateTime)) { 1265 | options.minDateTime = _xdsoft_datetime.strToDateTime(options.minDateTime).dateFormat(options.formatDate); 1266 | } 1267 | 1268 | if (options.maxDateTime && /^\+(.*)$/.test(options.maxDateTime)) { 1269 | options.maxDateTime = _xdsoft_datetime.strToDateTime(options.maxDateTime).dateFormat(options.formatDate); 1270 | } 1271 | 1272 | applyButton.toggle(options.showApplyButton); 1273 | 1274 | month_picker 1275 | .find('.xdsoft_today_button') 1276 | .css('visibility', !options.todayButton ? 'hidden' : 'visible'); 1277 | 1278 | month_picker 1279 | .find('.' + options.prev) 1280 | .css('visibility', !options.prevButton ? 'hidden' : 'visible'); 1281 | 1282 | month_picker 1283 | .find('.' + options.next) 1284 | .css('visibility', !options.nextButton ? 'hidden' : 'visible'); 1285 | 1286 | setMask(options); 1287 | 1288 | if (options.validateOnBlur) { 1289 | input 1290 | .off('blur.xdsoft') 1291 | .on('blur.xdsoft', function () { 1292 | if (options.allowBlank && (!$.trim($(this).val()).length || 1293 | (typeof options.mask === "string" && $.trim($(this).val()) === options.mask.replace(/[0-9]/g, '_')))) { 1294 | $(this).val(null); 1295 | datetimepicker.data('xdsoft_datetime').empty(); 1296 | } else { 1297 | var d = dateHelper.parseDate($(this).val(), options.format); 1298 | if (d) { // parseDate() may skip some invalid parts like date or time, so make it clear for user: show parsed date/time 1299 | $(this).val(dateHelper.formatDate(d, options.format)); 1300 | } else { 1301 | var splittedHours = +([$(this).val()[0], $(this).val()[1]].join('')), 1302 | splittedMinutes = +([$(this).val()[2], $(this).val()[3]].join('')); 1303 | 1304 | // parse the numbers as 0312 => 03:12 1305 | if (!options.datepicker && options.timepicker && splittedHours >= 0 && splittedHours < 24 && splittedMinutes >= 0 && splittedMinutes < 60) { 1306 | $(this).val([splittedHours, splittedMinutes].map(function (item) { 1307 | return item > 9 ? item : '0' + item; 1308 | }).join(':')); 1309 | } else { 1310 | $(this).val(dateHelper.formatDate(_xdsoft_datetime.now(), options.format)); 1311 | } 1312 | } 1313 | datetimepicker.data('xdsoft_datetime').setCurrentTime($(this).val()); 1314 | } 1315 | 1316 | datetimepicker.trigger('changedatetime.xdsoft'); 1317 | datetimepicker.trigger('close.xdsoft'); 1318 | }); 1319 | } 1320 | options.dayOfWeekStartPrev = (options.dayOfWeekStart === 0) ? 6 : options.dayOfWeekStart - 1; 1321 | 1322 | datetimepicker 1323 | .trigger('xchange.xdsoft') 1324 | .trigger('afterOpen.xdsoft'); 1325 | }; 1326 | 1327 | datetimepicker 1328 | .data('options', options) 1329 | .on('touchstart mousedown.xdsoft', function (event) { 1330 | event.stopPropagation(); 1331 | event.preventDefault(); 1332 | yearselect.hide(); 1333 | monthselect.hide(); 1334 | return false; 1335 | }); 1336 | 1337 | //scroll_element = timepicker.find('.xdsoft_time_box'); 1338 | timeboxparent.append(timebox); 1339 | timeboxparent.xdsoftScroller(options); 1340 | 1341 | datetimepicker.on('afterOpen.xdsoft', function () { 1342 | timeboxparent.xdsoftScroller(options); 1343 | }); 1344 | 1345 | datetimepicker 1346 | .append(datepicker) 1347 | .append(timepicker); 1348 | 1349 | if (options.withoutCopyright !== true) { 1350 | datetimepicker 1351 | .append(xdsoft_copyright); 1352 | } 1353 | 1354 | datepicker 1355 | .append(month_picker) 1356 | .append(calendar) 1357 | .append(applyButton); 1358 | 1359 | if (options.insideParent) { 1360 | $(input).parent().append(datetimepicker); 1361 | } else { 1362 | $(options.parentID).append(datetimepicker); 1363 | } 1364 | 1365 | XDSoft_datetime = function () { 1366 | var _this = this; 1367 | _this.now = function (norecursion) { 1368 | var d = new Date(), 1369 | date, 1370 | time; 1371 | 1372 | if (!norecursion && options.defaultDate) { 1373 | date = _this.strToDateTime(options.defaultDate); 1374 | d.setFullYear(date.getFullYear()); 1375 | d.setMonth(date.getMonth()); 1376 | d.setDate(date.getDate()); 1377 | } 1378 | 1379 | d.setFullYear(d.getFullYear()); 1380 | 1381 | if (!norecursion && options.defaultTime) { 1382 | time = _this.strtotime(options.defaultTime); 1383 | d.setHours(time.getHours()); 1384 | d.setMinutes(time.getMinutes()); 1385 | d.setSeconds(time.getSeconds()); 1386 | d.setMilliseconds(time.getMilliseconds()); 1387 | } 1388 | return d; 1389 | }; 1390 | 1391 | _this.isValidDate = function (d) { 1392 | if (Object.prototype.toString.call(d) !== "[object Date]") { 1393 | return false; 1394 | } 1395 | return !isNaN(d.getTime()); 1396 | }; 1397 | 1398 | _this.setCurrentTime = function (dTime, requireValidDate) { 1399 | if (typeof dTime === 'string') { 1400 | _this.currentTime = _this.strToDateTime(dTime); 1401 | } 1402 | else if (_this.isValidDate(dTime)) { 1403 | _this.currentTime = dTime; 1404 | } 1405 | else if (!dTime && !requireValidDate && options.allowBlank && !options.inline) { 1406 | _this.currentTime = null; 1407 | } 1408 | else { 1409 | _this.currentTime = _this.now(); 1410 | } 1411 | 1412 | datetimepicker.trigger('xchange.xdsoft'); 1413 | }; 1414 | 1415 | _this.empty = function () { 1416 | _this.currentTime = null; 1417 | }; 1418 | 1419 | _this.getCurrentTime = function () { 1420 | return _this.currentTime; 1421 | }; 1422 | 1423 | _this.nextMonth = function () { 1424 | 1425 | if (_this.currentTime === undefined || _this.currentTime === null) { 1426 | _this.currentTime = _this.now(); 1427 | } 1428 | 1429 | var month = _this.currentTime.getMonth() + 1, 1430 | year; 1431 | if (month === 12) { 1432 | _this.currentTime.setFullYear(_this.currentTime.getFullYear() + 1); 1433 | month = 0; 1434 | } 1435 | 1436 | year = _this.currentTime.getFullYear(); 1437 | 1438 | _this.currentTime.setDate( 1439 | Math.min( 1440 | new Date(_this.currentTime.getFullYear(), month + 1, 0).getDate(), 1441 | _this.currentTime.getDate() 1442 | ) 1443 | ); 1444 | _this.currentTime.setMonth(month); 1445 | 1446 | if (options.onChangeMonth && $.isFunction(options.onChangeMonth)) { 1447 | options.onChangeMonth.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); 1448 | } 1449 | 1450 | if (year !== _this.currentTime.getFullYear() && $.isFunction(options.onChangeYear)) { 1451 | options.onChangeYear.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); 1452 | } 1453 | 1454 | datetimepicker.trigger('xchange.xdsoft'); 1455 | return month; 1456 | }; 1457 | 1458 | _this.prevMonth = function () { 1459 | 1460 | if (_this.currentTime === undefined || _this.currentTime === null) { 1461 | _this.currentTime = _this.now(); 1462 | } 1463 | 1464 | var month = _this.currentTime.getMonth() - 1; 1465 | if (month === -1) { 1466 | _this.currentTime.setFullYear(_this.currentTime.getFullYear() - 1); 1467 | month = 11; 1468 | } 1469 | _this.currentTime.setDate( 1470 | Math.min( 1471 | new Date(_this.currentTime.getFullYear(), month + 1, 0).getDate(), 1472 | _this.currentTime.getDate() 1473 | ) 1474 | ); 1475 | _this.currentTime.setMonth(month); 1476 | if (options.onChangeMonth && $.isFunction(options.onChangeMonth)) { 1477 | options.onChangeMonth.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); 1478 | } 1479 | datetimepicker.trigger('xchange.xdsoft'); 1480 | return month; 1481 | }; 1482 | 1483 | _this.getWeekOfYear = function (datetime) { 1484 | if (options.onGetWeekOfYear && $.isFunction(options.onGetWeekOfYear)) { 1485 | var week = options.onGetWeekOfYear.call(datetimepicker, datetime); 1486 | if (typeof week !== 'undefined') { 1487 | return week; 1488 | } 1489 | } 1490 | var onejan = new Date(datetime.getFullYear(), 0, 1); 1491 | 1492 | //First week of the year is th one with the first Thursday according to ISO8601 1493 | if (onejan.getDay() !== 4) { 1494 | onejan.setMonth(0, 1 + ((4 - onejan.getDay()+ 7) % 7)); 1495 | } 1496 | 1497 | return Math.ceil((((datetime - onejan) / 86400000) + onejan.getDay() + 1) / 7); 1498 | }; 1499 | 1500 | _this.strToDateTime = function (sDateTime) { 1501 | var tmpDate = [], timeOffset, currentTime; 1502 | 1503 | if (sDateTime && sDateTime instanceof Date && _this.isValidDate(sDateTime)) { 1504 | return sDateTime; 1505 | } 1506 | 1507 | tmpDate = /^([+-]{1})(.*)$/.exec(sDateTime); 1508 | 1509 | if (tmpDate) { 1510 | tmpDate[2] = dateHelper.parseDate(tmpDate[2], options.formatDate); 1511 | } 1512 | 1513 | if (tmpDate && tmpDate[2]) { 1514 | timeOffset = tmpDate[2].getTime() - (tmpDate[2].getTimezoneOffset()) * 60000; 1515 | currentTime = new Date((_this.now(true)).getTime() + parseInt(tmpDate[1] + '1', 10) * timeOffset); 1516 | } else { 1517 | currentTime = sDateTime ? dateHelper.parseDate(sDateTime, options.format) : _this.now(); 1518 | } 1519 | 1520 | if (!_this.isValidDate(currentTime)) { 1521 | currentTime = _this.now(); 1522 | } 1523 | 1524 | return currentTime; 1525 | }; 1526 | 1527 | _this.strToDate = function (sDate) { 1528 | if (sDate && sDate instanceof Date && _this.isValidDate(sDate)) { 1529 | return sDate; 1530 | } 1531 | 1532 | var currentTime = sDate ? dateHelper.parseDate(sDate, options.formatDate) : _this.now(true); 1533 | if (!_this.isValidDate(currentTime)) { 1534 | currentTime = _this.now(true); 1535 | } 1536 | return currentTime; 1537 | }; 1538 | 1539 | _this.strtotime = function (sTime) { 1540 | if (sTime && sTime instanceof Date && _this.isValidDate(sTime)) { 1541 | return sTime; 1542 | } 1543 | var currentTime = sTime ? dateHelper.parseDate(sTime, options.formatTime) : _this.now(true); 1544 | if (!_this.isValidDate(currentTime)) { 1545 | currentTime = _this.now(true); 1546 | } 1547 | return currentTime; 1548 | }; 1549 | 1550 | _this.str = function () { 1551 | var format = options.format; 1552 | if (options.yearOffset) { 1553 | format = format.replace('Y', _this.currentTime.getFullYear() + options.yearOffset); 1554 | format = format.replace('y', String(_this.currentTime.getFullYear() + options.yearOffset).substring(2, 4)); 1555 | } 1556 | return dateHelper.formatDate(_this.currentTime, format); 1557 | }; 1558 | _this.currentTime = this.now(); 1559 | }; 1560 | 1561 | _xdsoft_datetime = new XDSoft_datetime(); 1562 | 1563 | applyButton.on('touchend click', function (e) {//pathbrite 1564 | e.preventDefault(); 1565 | datetimepicker.data('changed', true); 1566 | _xdsoft_datetime.setCurrentTime(getCurrentValue()); 1567 | input.val(_xdsoft_datetime.str()); 1568 | datetimepicker.trigger('close.xdsoft'); 1569 | }); 1570 | month_picker 1571 | .find('.xdsoft_today_button') 1572 | .on('touchend mousedown.xdsoft', function () { 1573 | datetimepicker.data('changed', true); 1574 | _xdsoft_datetime.setCurrentTime(0, true); 1575 | datetimepicker.trigger('afterOpen.xdsoft'); 1576 | }).on('dblclick.xdsoft', function () { 1577 | var currentDate = _xdsoft_datetime.getCurrentTime(), minDate, maxDate; 1578 | currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate()); 1579 | minDate = _xdsoft_datetime.strToDate(options.minDate); 1580 | minDate = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()); 1581 | if (currentDate < minDate) { 1582 | return; 1583 | } 1584 | maxDate = _xdsoft_datetime.strToDate(options.maxDate); 1585 | maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate()); 1586 | if (currentDate > maxDate) { 1587 | return; 1588 | } 1589 | input.val(_xdsoft_datetime.str()); 1590 | input.trigger('change'); 1591 | datetimepicker.trigger('close.xdsoft'); 1592 | }); 1593 | month_picker 1594 | .find('.xdsoft_prev,.xdsoft_next') 1595 | .on('touchend mousedown.xdsoft', function () { 1596 | var $this = $(this), 1597 | timer = 0, 1598 | stop = false; 1599 | 1600 | (function arguments_callee1(v) { 1601 | if ($this.hasClass(options.next)) { 1602 | _xdsoft_datetime.nextMonth(); 1603 | } else if ($this.hasClass(options.prev)) { 1604 | _xdsoft_datetime.prevMonth(); 1605 | } 1606 | if (options.monthChangeSpinner) { 1607 | if (!stop) { 1608 | timer = setTimeout(arguments_callee1, v || 100); 1609 | } 1610 | } 1611 | }(500)); 1612 | 1613 | $([options.ownerDocument.body, options.contentWindow]).on('touchend mouseup.xdsoft', function arguments_callee2() { 1614 | clearTimeout(timer); 1615 | stop = true; 1616 | $([options.ownerDocument.body, options.contentWindow]).off('touchend mouseup.xdsoft', arguments_callee2); 1617 | }); 1618 | }); 1619 | 1620 | timepicker 1621 | .find('.xdsoft_prev,.xdsoft_next') 1622 | .on('touchend mousedown.xdsoft', function () { 1623 | var $this = $(this), 1624 | timer = 0, 1625 | stop = false, 1626 | period = 110; 1627 | (function arguments_callee4(v) { 1628 | var pheight = timeboxparent[0].clientHeight, 1629 | height = timebox[0].offsetHeight, 1630 | top = Math.abs(parseInt(timebox.css('marginTop'), 10)); 1631 | if ($this.hasClass(options.next) && (height - pheight) - options.timeHeightInTimePicker >= top) { 1632 | timebox.css('marginTop', '-' + (top + options.timeHeightInTimePicker) + 'px'); 1633 | } else if ($this.hasClass(options.prev) && top - options.timeHeightInTimePicker >= 0) { 1634 | timebox.css('marginTop', '-' + (top - options.timeHeightInTimePicker) + 'px'); 1635 | } 1636 | /** 1637 | * Fixed bug: 1638 | * When using css3 transition, it will cause a bug that you cannot scroll the timepicker list. 1639 | * The reason is that the transition-duration time, if you set it to 0, all things fine, otherwise, this 1640 | * would cause a bug when you use jquery.css method. 1641 | * Let's say: * { transition: all .5s ease; } 1642 | * jquery timebox.css('marginTop') will return the original value which is before you clicking the next/prev button, 1643 | * meanwhile the timebox[0].style.marginTop will return the right value which is after you clicking the 1644 | * next/prev button. 1645 | * 1646 | * What we should do: 1647 | * Replace timebox.css('marginTop') with timebox[0].style.marginTop. 1648 | */ 1649 | timeboxparent.trigger('scroll_element.xdsoft_scroller', [Math.abs(parseInt(timebox[0].style.marginTop, 10) / (height - pheight))]); 1650 | period = (period > 10) ? 10 : period - 10; 1651 | if (!stop) { 1652 | timer = setTimeout(arguments_callee4, v || period); 1653 | } 1654 | }(500)); 1655 | $([options.ownerDocument.body, options.contentWindow]).on('touchend mouseup.xdsoft', function arguments_callee5() { 1656 | clearTimeout(timer); 1657 | stop = true; 1658 | $([options.ownerDocument.body, options.contentWindow]) 1659 | .off('touchend mouseup.xdsoft', arguments_callee5); 1660 | }); 1661 | }); 1662 | 1663 | xchangeTimer = 0; 1664 | // base handler - generating a calendar and timepicker 1665 | datetimepicker 1666 | .on('xchange.xdsoft', function (event) { 1667 | clearTimeout(xchangeTimer); 1668 | xchangeTimer = setTimeout(function () { 1669 | 1670 | if (_xdsoft_datetime.currentTime === undefined || _xdsoft_datetime.currentTime === null) { 1671 | _xdsoft_datetime.currentTime = _xdsoft_datetime.now(); 1672 | } 1673 | 1674 | var table = '', 1675 | start = new Date(_xdsoft_datetime.currentTime.getFullYear(), _xdsoft_datetime.currentTime.getMonth(), 1, 12, 0, 0), 1676 | i = 0, 1677 | j, 1678 | today = _xdsoft_datetime.now(), 1679 | maxDate = false, 1680 | minDate = false, 1681 | minDateTime = false, 1682 | maxDateTime = false, 1683 | hDate, 1684 | day, 1685 | d, 1686 | y, 1687 | m, 1688 | w, 1689 | classes = [], 1690 | customDateSettings, 1691 | newRow = true, 1692 | time = '', 1693 | h, 1694 | line_time, 1695 | description; 1696 | 1697 | while (start.getDay() !== options.dayOfWeekStart) { 1698 | start.setDate(start.getDate() - 1); 1699 | } 1700 | 1701 | table += ''; 1702 | 1703 | if (options.weeks) { 1704 | table += ''; 1705 | } 1706 | 1707 | for (j = 0; j < 7; j += 1) { 1708 | table += ''; 1709 | } 1710 | 1711 | table += ''; 1712 | table += ''; 1713 | 1714 | if (options.maxDate !== false) { 1715 | maxDate = _xdsoft_datetime.strToDate(options.maxDate); 1716 | maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate(), 23, 59, 59, 999); 1717 | } 1718 | 1719 | if (options.minDate !== false) { 1720 | minDate = _xdsoft_datetime.strToDate(options.minDate); 1721 | minDate = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()); 1722 | } 1723 | 1724 | if (options.minDateTime !== false) { 1725 | minDateTime = _xdsoft_datetime.strToDate(options.minDateTime); 1726 | minDateTime = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), minDateTime.getHours(), minDateTime.getMinutes(), minDateTime.getSeconds()); 1727 | } 1728 | 1729 | if (options.maxDateTime !== false) { 1730 | maxDateTime = _xdsoft_datetime.strToDate(options.maxDateTime); 1731 | maxDateTime = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), maxDateTime.getHours(), maxDateTime.getMinutes(), maxDateTime.getSeconds()); 1732 | } 1733 | 1734 | var maxDateTimeDay; 1735 | if (maxDateTime !== false) { 1736 | maxDateTimeDay = ((maxDateTime.getFullYear() * 12) + maxDateTime.getMonth()) * 31 + maxDateTime.getDate(); 1737 | } 1738 | 1739 | while (i < _xdsoft_datetime.currentTime.countDaysInMonth() || start.getDay() !== options.dayOfWeekStart || _xdsoft_datetime.currentTime.getMonth() === start.getMonth()) { 1740 | classes = []; 1741 | i += 1; 1742 | 1743 | day = start.getDay(); 1744 | d = start.getDate(); 1745 | y = start.getFullYear(); 1746 | m = start.getMonth(); 1747 | w = _xdsoft_datetime.getWeekOfYear(start); 1748 | description = ''; 1749 | 1750 | classes.push('xdsoft_date'); 1751 | 1752 | if (options.beforeShowDay && $.isFunction(options.beforeShowDay.call)) { 1753 | customDateSettings = options.beforeShowDay.call(datetimepicker, start); 1754 | } else { 1755 | customDateSettings = null; 1756 | } 1757 | 1758 | if(options.allowDateRe && Object.prototype.toString.call(options.allowDateRe) === "[object RegExp]"){ 1759 | if(!options.allowDateRe.test(dateHelper.formatDate(start, options.formatDate))){ 1760 | classes.push('xdsoft_disabled'); 1761 | } 1762 | } 1763 | 1764 | if(options.allowDates && options.allowDates.length>0){ 1765 | if(options.allowDates.indexOf(dateHelper.formatDate(start, options.formatDate)) === -1){ 1766 | classes.push('xdsoft_disabled'); 1767 | } 1768 | } 1769 | 1770 | var currentDay = ((start.getFullYear() * 12) + start.getMonth()) * 31 + start.getDate(); 1771 | if ((maxDate !== false && start > maxDate) || (minDateTime !== false && start < minDateTime) || (minDate !== false && start < minDate) || (maxDateTime !== false && currentDay > maxDateTimeDay) || (customDateSettings && customDateSettings[0] === false)) { 1772 | classes.push('xdsoft_disabled'); 1773 | } 1774 | 1775 | if (options.disabledDates.indexOf(dateHelper.formatDate(start, options.formatDate)) !== -1) { 1776 | classes.push('xdsoft_disabled'); 1777 | } 1778 | 1779 | if (options.disabledWeekDays.indexOf(day) !== -1) { 1780 | classes.push('xdsoft_disabled'); 1781 | } 1782 | 1783 | if (input.is('[disabled]')) { 1784 | classes.push('xdsoft_disabled'); 1785 | } 1786 | 1787 | if (customDateSettings && customDateSettings[1] !== "") { 1788 | classes.push(customDateSettings[1]); 1789 | } 1790 | 1791 | if (_xdsoft_datetime.currentTime.getMonth() !== m) { 1792 | classes.push('xdsoft_other_month'); 1793 | } 1794 | 1795 | if ((options.defaultSelect || datetimepicker.data('changed')) && dateHelper.formatDate(_xdsoft_datetime.currentTime, options.formatDate) === dateHelper.formatDate(start, options.formatDate)) { 1796 | classes.push('xdsoft_current'); 1797 | } 1798 | 1799 | if (dateHelper.formatDate(today, options.formatDate) === dateHelper.formatDate(start, options.formatDate)) { 1800 | classes.push('xdsoft_today'); 1801 | } 1802 | 1803 | if (start.getDay() === 0 || start.getDay() === 6 || options.weekends.indexOf(dateHelper.formatDate(start, options.formatDate)) !== -1) { 1804 | classes.push('xdsoft_weekend'); 1805 | } 1806 | 1807 | if (options.highlightedDates[dateHelper.formatDate(start, options.formatDate)] !== undefined) { 1808 | hDate = options.highlightedDates[dateHelper.formatDate(start, options.formatDate)]; 1809 | classes.push(hDate.style === undefined ? 'xdsoft_highlighted_default' : hDate.style); 1810 | description = hDate.desc === undefined ? '' : hDate.desc; 1811 | } 1812 | 1813 | if (options.beforeShowDay && $.isFunction(options.beforeShowDay)) { 1814 | classes.push(options.beforeShowDay(start)); 1815 | } 1816 | 1817 | if (newRow) { 1818 | table += ''; 1819 | newRow = false; 1820 | if (options.weeks) { 1821 | table += ''; 1822 | } 1823 | } 1824 | 1825 | table += ''; 1828 | 1829 | if (start.getDay() === options.dayOfWeekStartPrev) { 1830 | table += ''; 1831 | newRow = true; 1832 | } 1833 | 1834 | start.setDate(d + 1); 1835 | } 1836 | table += '
' + options.i18n[globalLocale].dayOfWeekShort[(j + options.dayOfWeekStart) % 7] + '
' + w + '' + 1826 | '
' + d + '
' + 1827 | '
'; 1837 | 1838 | calendar.html(table); 1839 | 1840 | month_picker.find('.xdsoft_label span').eq(0).text(options.i18n[globalLocale].months[_xdsoft_datetime.currentTime.getMonth()]); 1841 | month_picker.find('.xdsoft_label span').eq(1).text(_xdsoft_datetime.currentTime.getFullYear() + options.yearOffset); 1842 | 1843 | // generate timebox 1844 | time = ''; 1845 | h = ''; 1846 | m = ''; 1847 | 1848 | var minTimeMinutesOfDay = 0; 1849 | if (options.minTime !== false) { 1850 | var t = _xdsoft_datetime.strtotime(options.minTime); 1851 | minTimeMinutesOfDay = 60 * t.getHours() + t.getMinutes(); 1852 | } 1853 | var maxTimeMinutesOfDay = 24 * 60; 1854 | if (options.maxTime !== false) { 1855 | var t = _xdsoft_datetime.strtotime(options.maxTime); 1856 | maxTimeMinutesOfDay = 60 * t.getHours() + t.getMinutes(); 1857 | } 1858 | 1859 | if (options.minDateTime !== false) { 1860 | var t = _xdsoft_datetime.strToDateTime(options.minDateTime); 1861 | var currentDayIsMinDateTimeDay = dateHelper.formatDate(_xdsoft_datetime.currentTime, options.formatDate) === dateHelper.formatDate(t, options.formatDate); 1862 | if (currentDayIsMinDateTimeDay) { 1863 | var m = 60 * t.getHours() + t.getMinutes(); 1864 | if (m > minTimeMinutesOfDay) minTimeMinutesOfDay = m; 1865 | } 1866 | } 1867 | 1868 | if (options.maxDateTime !== false) { 1869 | var t = _xdsoft_datetime.strToDateTime(options.maxDateTime); 1870 | var currentDayIsMaxDateTimeDay = dateHelper.formatDate(_xdsoft_datetime.currentTime, options.formatDate) === dateHelper.formatDate(t, options.formatDate); 1871 | if (currentDayIsMaxDateTimeDay) { 1872 | var m = 60 * t.getHours() + t.getMinutes(); 1873 | if (m < maxTimeMinutesOfDay) maxTimeMinutesOfDay = m; 1874 | } 1875 | } 1876 | 1877 | line_time = function line_time(h, m) { 1878 | var now = _xdsoft_datetime.now(), current_time, 1879 | isALlowTimesInit = options.allowTimes && $.isArray(options.allowTimes) && options.allowTimes.length; 1880 | now.setHours(h); 1881 | h = parseInt(now.getHours(), 10); 1882 | now.setMinutes(m); 1883 | m = parseInt(now.getMinutes(), 10); 1884 | classes = []; 1885 | var currentMinutesOfDay = 60 * h + m; 1886 | if (input.is('[disabled]') || (currentMinutesOfDay >= maxTimeMinutesOfDay) || (currentMinutesOfDay < minTimeMinutesOfDay)) { 1887 | classes.push('xdsoft_disabled'); 1888 | } 1889 | 1890 | current_time = new Date(_xdsoft_datetime.currentTime); 1891 | current_time.setHours(parseInt(_xdsoft_datetime.currentTime.getHours(), 10)); 1892 | 1893 | if (!isALlowTimesInit) { 1894 | current_time.setMinutes(Math[options.roundTime](_xdsoft_datetime.currentTime.getMinutes() / options.step) * options.step); 1895 | } 1896 | 1897 | if ((options.initTime || options.defaultSelect || datetimepicker.data('changed')) && current_time.getHours() === parseInt(h, 10) && ((!isALlowTimesInit && options.step > 59) || current_time.getMinutes() === parseInt(m, 10))) { 1898 | if (options.defaultSelect || datetimepicker.data('changed')) { 1899 | classes.push('xdsoft_current'); 1900 | } else if (options.initTime) { 1901 | classes.push('xdsoft_init_time'); 1902 | } 1903 | } 1904 | if (parseInt(today.getHours(), 10) === parseInt(h, 10) && parseInt(today.getMinutes(), 10) === parseInt(m, 10)) { 1905 | classes.push('xdsoft_today'); 1906 | } 1907 | time += '
' + dateHelper.formatDate(now, options.formatTime) + '
'; 1908 | }; 1909 | 1910 | if (!options.allowTimes || !$.isArray(options.allowTimes) || !options.allowTimes.length) { 1911 | for (i = 0, j = 0; i < (options.hours12 ? 12 : 24); i += 1) { 1912 | for (j = 0; j < 60; j += options.step) { 1913 | var currentMinutesOfDay = i * 60 + j; 1914 | if (currentMinutesOfDay < minTimeMinutesOfDay) continue; 1915 | if (currentMinutesOfDay >= maxTimeMinutesOfDay) continue; 1916 | h = (i < 10 ? '0' : '') + i; 1917 | m = (j < 10 ? '0' : '') + j; 1918 | line_time(h, m); 1919 | } 1920 | } 1921 | } else { 1922 | for (i = 0; i < options.allowTimes.length; i += 1) { 1923 | h = _xdsoft_datetime.strtotime(options.allowTimes[i]).getHours(); 1924 | m = _xdsoft_datetime.strtotime(options.allowTimes[i]).getMinutes(); 1925 | line_time(h, m); 1926 | } 1927 | } 1928 | 1929 | timebox.html(time); 1930 | 1931 | opt = ''; 1932 | 1933 | for (i = parseInt(options.yearStart, 10); i <= parseInt(options.yearEnd, 10); i += 1) { 1934 | opt += '
' + (i + options.yearOffset) + '
'; 1935 | } 1936 | yearselect.children().eq(0) 1937 | .html(opt); 1938 | 1939 | for (i = parseInt(options.monthStart, 10), opt = ''; i <= parseInt(options.monthEnd, 10); i += 1) { 1940 | opt += '
' + options.i18n[globalLocale].months[i] + '
'; 1941 | } 1942 | monthselect.children().eq(0).html(opt); 1943 | $(datetimepicker) 1944 | .trigger('generate.xdsoft'); 1945 | }, 10); 1946 | event.stopPropagation(); 1947 | }) 1948 | .on('afterOpen.xdsoft', function () { 1949 | if (options.timepicker) { 1950 | var classType, pheight, height, top; 1951 | if (timebox.find('.xdsoft_current').length) { 1952 | classType = '.xdsoft_current'; 1953 | } else if (timebox.find('.xdsoft_init_time').length) { 1954 | classType = '.xdsoft_init_time'; 1955 | } 1956 | if (classType) { 1957 | pheight = timeboxparent[0].clientHeight; 1958 | height = timebox[0].offsetHeight; 1959 | top = timebox.find(classType).index() * options.timeHeightInTimePicker + 1; 1960 | if ((height - pheight) < top) { 1961 | top = height - pheight; 1962 | } 1963 | timeboxparent.trigger('scroll_element.xdsoft_scroller', [parseInt(top, 10) / (height - pheight)]); 1964 | } else { 1965 | timeboxparent.trigger('scroll_element.xdsoft_scroller', [0]); 1966 | } 1967 | } 1968 | }); 1969 | 1970 | timerclick = 0; 1971 | calendar 1972 | .on('touchend click.xdsoft', 'td', function (xdevent) { 1973 | xdevent.stopPropagation(); // Prevents closing of Pop-ups, Modals and Flyouts in Bootstrap 1974 | timerclick += 1; 1975 | var $this = $(this), 1976 | currentTime = _xdsoft_datetime.currentTime; 1977 | 1978 | if (currentTime === undefined || currentTime === null) { 1979 | _xdsoft_datetime.currentTime = _xdsoft_datetime.now(); 1980 | currentTime = _xdsoft_datetime.currentTime; 1981 | } 1982 | 1983 | if ($this.hasClass('xdsoft_disabled')) { 1984 | return false; 1985 | } 1986 | 1987 | currentTime.setDate(1); 1988 | currentTime.setFullYear($this.data('year')); 1989 | currentTime.setMonth($this.data('month')); 1990 | currentTime.setDate($this.data('date')); 1991 | 1992 | datetimepicker.trigger('select.xdsoft', [currentTime]); 1993 | 1994 | input.val(_xdsoft_datetime.str()); 1995 | 1996 | if (options.onSelectDate && $.isFunction(options.onSelectDate)) { 1997 | options.onSelectDate.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input'), xdevent); 1998 | } 1999 | 2000 | datetimepicker.data('changed', true); 2001 | datetimepicker.trigger('xchange.xdsoft'); 2002 | datetimepicker.trigger('changedatetime.xdsoft'); 2003 | if ((timerclick > 1 || (options.closeOnDateSelect === true || (options.closeOnDateSelect === false && !options.timepicker))) && !options.inline) { 2004 | datetimepicker.trigger('close.xdsoft'); 2005 | } 2006 | setTimeout(function () { 2007 | timerclick = 0; 2008 | }, 200); 2009 | }); 2010 | 2011 | timebox 2012 | .on('touchstart', 'div', function (xdevent) { 2013 | this.touchMoved = false; 2014 | }) 2015 | .on('touchmove', 'div', handleTouchMoved) 2016 | .on('touchend click.xdsoft', 'div', function (xdevent) { 2017 | if (!this.touchMoved) { 2018 | xdevent.stopPropagation(); 2019 | var $this = $(this), 2020 | currentTime = _xdsoft_datetime.currentTime; 2021 | 2022 | if (currentTime === undefined || currentTime === null) { 2023 | _xdsoft_datetime.currentTime = _xdsoft_datetime.now(); 2024 | currentTime = _xdsoft_datetime.currentTime; 2025 | } 2026 | 2027 | if ($this.hasClass('xdsoft_disabled')) { 2028 | return false; 2029 | } 2030 | currentTime.setHours($this.data('hour')); 2031 | currentTime.setMinutes($this.data('minute')); 2032 | datetimepicker.trigger('select.xdsoft', [currentTime]); 2033 | 2034 | datetimepicker.data('input').val(_xdsoft_datetime.str()); 2035 | 2036 | if (options.onSelectTime && $.isFunction(options.onSelectTime)) { 2037 | options.onSelectTime.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input'), xdevent); 2038 | } 2039 | datetimepicker.data('changed', true); 2040 | datetimepicker.trigger('xchange.xdsoft'); 2041 | datetimepicker.trigger('changedatetime.xdsoft'); 2042 | if (options.inline !== true && options.closeOnTimeSelect === true) { 2043 | datetimepicker.trigger('close.xdsoft'); 2044 | } 2045 | } 2046 | }); 2047 | 2048 | datepicker 2049 | .on('mousewheel.xdsoft', function (event) { 2050 | if (!options.scrollMonth) { 2051 | return true; 2052 | } 2053 | if (event.deltaY < 0) { 2054 | _xdsoft_datetime.nextMonth(); 2055 | } else { 2056 | _xdsoft_datetime.prevMonth(); 2057 | } 2058 | return false; 2059 | }); 2060 | 2061 | input 2062 | .on('mousewheel.xdsoft', function (event) { 2063 | if (!options.scrollInput) { 2064 | return true; 2065 | } 2066 | if (!options.datepicker && options.timepicker) { 2067 | current_time_index = timebox.find('.xdsoft_current').length ? timebox.find('.xdsoft_current').eq(0).index() : 0; 2068 | if (current_time_index + event.deltaY >= 0 && current_time_index + event.deltaY < timebox.children().length) { 2069 | current_time_index += event.deltaY; 2070 | } 2071 | if (timebox.children().eq(current_time_index).length) { 2072 | timebox.children().eq(current_time_index).trigger('mousedown'); 2073 | } 2074 | return false; 2075 | } 2076 | if (options.datepicker && !options.timepicker) { 2077 | datepicker.trigger(event, [event.deltaY, event.deltaX, event.deltaY]); 2078 | if (input.val) { 2079 | input.val(_xdsoft_datetime.str()); 2080 | } 2081 | datetimepicker.trigger('changedatetime.xdsoft'); 2082 | return false; 2083 | } 2084 | }); 2085 | 2086 | datetimepicker 2087 | .on('changedatetime.xdsoft', function (event) { 2088 | if (options.onChangeDateTime && $.isFunction(options.onChangeDateTime)) { 2089 | var $input = datetimepicker.data('input'); 2090 | options.onChangeDateTime.call(datetimepicker, _xdsoft_datetime.currentTime, $input, event); 2091 | delete options.value; 2092 | $input.trigger('change'); 2093 | } 2094 | }) 2095 | .on('generate.xdsoft', function () { 2096 | if (options.onGenerate && $.isFunction(options.onGenerate)) { 2097 | options.onGenerate.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); 2098 | } 2099 | if (triggerAfterOpen) { 2100 | datetimepicker.trigger('afterOpen.xdsoft'); 2101 | triggerAfterOpen = false; 2102 | } 2103 | }) 2104 | .on('click.xdsoft', function (xdevent) { 2105 | xdevent.stopPropagation(); 2106 | }); 2107 | 2108 | current_time_index = 0; 2109 | 2110 | /** 2111 | * Runs the callback for each of the specified node's ancestors. 2112 | * 2113 | * Return FALSE from the callback to stop ascending. 2114 | * 2115 | * @param {DOMNode} node 2116 | * @param {Function} callback 2117 | * @returns {undefined} 2118 | */ 2119 | forEachAncestorOf = function (node, callback) { 2120 | do { 2121 | node = node.parentNode; 2122 | 2123 | if (!node || callback(node) === false) { 2124 | break; 2125 | } 2126 | } while (node.nodeName !== 'HTML'); 2127 | }; 2128 | 2129 | /** 2130 | * Sets the position of the picker. 2131 | * 2132 | * @returns {undefined} 2133 | */ 2134 | setPos = function () { 2135 | var dateInputOffset, 2136 | dateInputElem, 2137 | verticalPosition, 2138 | left, 2139 | position, 2140 | datetimepickerElem, 2141 | dateInputHasFixedAncestor, 2142 | $dateInput, 2143 | windowWidth, 2144 | verticalAnchorEdge, 2145 | datetimepickerCss, 2146 | windowHeight, 2147 | windowScrollTop; 2148 | 2149 | $dateInput = datetimepicker.data('input'); 2150 | dateInputOffset = $dateInput.offset(); 2151 | dateInputElem = $dateInput[0]; 2152 | 2153 | verticalAnchorEdge = 'top'; 2154 | verticalPosition = (dateInputOffset.top + dateInputElem.offsetHeight) - 1; 2155 | left = dateInputOffset.left; 2156 | position = "absolute"; 2157 | 2158 | windowWidth = $(options.contentWindow).width(); 2159 | windowHeight = $(options.contentWindow).height(); 2160 | windowScrollTop = $(options.contentWindow).scrollTop(); 2161 | 2162 | if ((options.ownerDocument.documentElement.clientWidth - dateInputOffset.left) < datepicker.parent().outerWidth(true)) { 2163 | var diff = datepicker.parent().outerWidth(true) - dateInputElem.offsetWidth; 2164 | left = left - diff; 2165 | } 2166 | 2167 | if ($dateInput.parent().css('direction') === 'rtl') { 2168 | left -= (datetimepicker.outerWidth() - $dateInput.outerWidth()); 2169 | } 2170 | 2171 | if (options.fixed) { 2172 | verticalPosition -= windowScrollTop; 2173 | left -= $(options.contentWindow).scrollLeft(); 2174 | position = "fixed"; 2175 | } else { 2176 | dateInputHasFixedAncestor = false; 2177 | 2178 | forEachAncestorOf(dateInputElem, function (ancestorNode) { 2179 | if (ancestorNode === null) { 2180 | return false; 2181 | } 2182 | 2183 | if (options.contentWindow.getComputedStyle(ancestorNode).getPropertyValue('position') === 'fixed') { 2184 | dateInputHasFixedAncestor = true; 2185 | return false; 2186 | } 2187 | }); 2188 | 2189 | if (dateInputHasFixedAncestor && !options.insideParent) { 2190 | position = 'fixed'; 2191 | 2192 | //If the picker won't fit entirely within the viewport then display it above the date input. 2193 | if (verticalPosition + datetimepicker.outerHeight() > windowHeight + windowScrollTop) { 2194 | verticalAnchorEdge = 'bottom'; 2195 | verticalPosition = (windowHeight + windowScrollTop) - dateInputOffset.top; 2196 | } else { 2197 | verticalPosition -= windowScrollTop; 2198 | } 2199 | } else { 2200 | if (verticalPosition + datetimepicker[0].offsetHeight > windowHeight + windowScrollTop) { 2201 | verticalPosition = dateInputOffset.top - datetimepicker[0].offsetHeight + 1; 2202 | } 2203 | } 2204 | 2205 | if (verticalPosition < 0) { 2206 | verticalPosition = 0; 2207 | } 2208 | 2209 | if (left + dateInputElem.offsetWidth > windowWidth) { 2210 | left = windowWidth - dateInputElem.offsetWidth; 2211 | } 2212 | } 2213 | 2214 | datetimepickerElem = datetimepicker[0]; 2215 | 2216 | forEachAncestorOf(datetimepickerElem, function (ancestorNode) { 2217 | var ancestorNodePosition; 2218 | 2219 | ancestorNodePosition = options.contentWindow.getComputedStyle(ancestorNode).getPropertyValue('position'); 2220 | 2221 | if (ancestorNodePosition === 'relative' && windowWidth >= ancestorNode.offsetWidth) { 2222 | left = left - ((windowWidth - ancestorNode.offsetWidth) / 2); 2223 | return false; 2224 | } 2225 | }); 2226 | 2227 | datetimepickerCss = { 2228 | position: position, 2229 | left: options.insideParent ? dateInputElem.offsetLeft : left, 2230 | top: '', //Initialize to prevent previous values interfering with new ones. 2231 | bottom: '' //Initialize to prevent previous values interfering with new ones. 2232 | }; 2233 | 2234 | if (options.insideParent) { 2235 | datetimepickerCss[verticalAnchorEdge] = dateInputElem.offsetTop + dateInputElem.offsetHeight; 2236 | } else { 2237 | datetimepickerCss[verticalAnchorEdge] = verticalPosition; 2238 | } 2239 | 2240 | datetimepicker.css(datetimepickerCss); 2241 | }; 2242 | 2243 | datetimepicker 2244 | .on('open.xdsoft', function (event) { 2245 | var onShow = true; 2246 | if (options.onShow && $.isFunction(options.onShow)) { 2247 | onShow = options.onShow.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input'), event); 2248 | } 2249 | if (onShow !== false) { 2250 | datetimepicker.show(); 2251 | setPos(); 2252 | $(options.contentWindow) 2253 | .off('resize.xdsoft', setPos) 2254 | .on('resize.xdsoft', setPos); 2255 | 2256 | if (options.closeOnWithoutClick) { 2257 | $([options.ownerDocument.body, options.contentWindow]).on('touchstart mousedown.xdsoft', function arguments_callee6() { 2258 | datetimepicker.trigger('close.xdsoft'); 2259 | $([options.ownerDocument.body, options.contentWindow]).off('touchstart mousedown.xdsoft', arguments_callee6); 2260 | }); 2261 | } 2262 | } 2263 | }) 2264 | .on('close.xdsoft', function (event) { 2265 | var onClose = true; 2266 | month_picker 2267 | .find('.xdsoft_month,.xdsoft_year') 2268 | .find('.xdsoft_select') 2269 | .hide(); 2270 | if (options.onClose && $.isFunction(options.onClose)) { 2271 | onClose = options.onClose.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input'), event); 2272 | } 2273 | if (onClose !== false && !options.opened && !options.inline) { 2274 | datetimepicker.hide(); 2275 | } 2276 | event.stopPropagation(); 2277 | }) 2278 | .on('toggle.xdsoft', function () { 2279 | if (datetimepicker.is(':visible')) { 2280 | datetimepicker.trigger('close.xdsoft'); 2281 | } else { 2282 | datetimepicker.trigger('open.xdsoft'); 2283 | } 2284 | }) 2285 | .data('input', input); 2286 | 2287 | timer = 0; 2288 | 2289 | datetimepicker.data('xdsoft_datetime', _xdsoft_datetime); 2290 | datetimepicker.setOptions(options); 2291 | 2292 | function getCurrentValue() { 2293 | var ct = false, time; 2294 | 2295 | if (options.startDate) { 2296 | ct = _xdsoft_datetime.strToDate(options.startDate); 2297 | } else { 2298 | ct = options.value || ((input && input.val && input.val()) ? input.val() : ''); 2299 | if (ct) { 2300 | ct = _xdsoft_datetime.strToDateTime(ct); 2301 | if (options.yearOffset) { 2302 | ct = new Date(ct.getFullYear() - options.yearOffset, ct.getMonth(), ct.getDate(), ct.getHours(), ct.getMinutes(), ct.getSeconds(), ct.getMilliseconds()); 2303 | } 2304 | } else if (options.defaultDate) { 2305 | ct = _xdsoft_datetime.strToDateTime(options.defaultDate); 2306 | if (options.defaultTime) { 2307 | time = _xdsoft_datetime.strtotime(options.defaultTime); 2308 | ct.setHours(time.getHours()); 2309 | ct.setMinutes(time.getMinutes()); 2310 | } 2311 | } 2312 | } 2313 | 2314 | if (ct && _xdsoft_datetime.isValidDate(ct)) { 2315 | datetimepicker.data('changed', true); 2316 | } else { 2317 | ct = ''; 2318 | } 2319 | 2320 | return ct || 0; 2321 | } 2322 | 2323 | function setMask(options) { 2324 | 2325 | var isValidValue = function (mask, value) { 2326 | var reg = mask 2327 | .replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g, '\\$1') 2328 | .replace(/_/g, '{digit+}') 2329 | .replace(/([0-9]{1})/g, '{digit$1}') 2330 | .replace(/\{digit([0-9]{1})\}/g, '[0-$1_]{1}') 2331 | .replace(/\{digit[\+]\}/g, '[0-9_]{1}'); 2332 | return (new RegExp(reg)).test(value); 2333 | }, 2334 | getCaretPos = function (input) { 2335 | try { 2336 | if (options.ownerDocument.selection && options.ownerDocument.selection.createRange) { 2337 | var range = options.ownerDocument.selection.createRange(); 2338 | return range.getBookmark().charCodeAt(2) - 2; 2339 | } 2340 | if (input.setSelectionRange) { 2341 | return input.selectionStart; 2342 | } 2343 | } catch (e) { 2344 | return 0; 2345 | } 2346 | }, 2347 | setCaretPos = function (node, pos) { 2348 | node = (typeof node === "string" || node instanceof String) ? options.ownerDocument.getElementById(node) : node; 2349 | if (!node) { 2350 | return false; 2351 | } 2352 | if (node.createTextRange) { 2353 | var textRange = node.createTextRange(); 2354 | textRange.collapse(true); 2355 | textRange.moveEnd('character', pos); 2356 | textRange.moveStart('character', pos); 2357 | textRange.select(); 2358 | return true; 2359 | } 2360 | if (node.setSelectionRange) { 2361 | node.setSelectionRange(pos, pos); 2362 | return true; 2363 | } 2364 | return false; 2365 | }; 2366 | 2367 | if(options.mask) { 2368 | input.off('keydown.xdsoft'); 2369 | } 2370 | 2371 | if (options.mask === true) { 2372 | if (dateHelper.formatMask) { 2373 | options.mask = dateHelper.formatMask(options.format) 2374 | } else { 2375 | options.mask = options.format 2376 | .replace(/Y/g, '9999') 2377 | .replace(/F/g, '9999') 2378 | .replace(/m/g, '19') 2379 | .replace(/d/g, '39') 2380 | .replace(/H/g, '29') 2381 | .replace(/i/g, '59') 2382 | .replace(/s/g, '59'); 2383 | } 2384 | } 2385 | 2386 | if ($.type(options.mask) === 'string') { 2387 | if (!isValidValue(options.mask, input.val())) { 2388 | input.val(options.mask.replace(/[0-9]/g, '_')); 2389 | setCaretPos(input[0], 0); 2390 | } 2391 | 2392 | input.on('paste.xdsoft', function (event) { 2393 | // couple options here 2394 | // 1. return false - tell them they can't paste 2395 | // 2. insert over current characters - minimal validation 2396 | // 3. full fledged parsing and validation 2397 | // let's go option 2 for now 2398 | 2399 | // fires multiple times for some reason 2400 | 2401 | // https://stackoverflow.com/a/30496488/1366033 2402 | var clipboardData = event.clipboardData || event.originalEvent.clipboardData || window.clipboardData, 2403 | pastedData = clipboardData.getData('text'), 2404 | val = this.value, 2405 | pos = this.selectionStart 2406 | 2407 | var valueBeforeCursor = val.substr(0, pos); 2408 | var valueAfterPaste = val.substr(pos + pastedData.length); 2409 | 2410 | val = valueBeforeCursor + pastedData + valueAfterPaste; 2411 | pos += pastedData.length; 2412 | 2413 | if (isValidValue(options.mask, val)) { 2414 | this.value = val; 2415 | setCaretPos(this, pos); 2416 | } else if ($.trim(val) === '') { 2417 | this.value = options.mask.replace(/[0-9]/g, '_'); 2418 | } else { 2419 | input.trigger('error_input.xdsoft'); 2420 | } 2421 | 2422 | event.preventDefault(); 2423 | return false; 2424 | }); 2425 | 2426 | input.on('keydown.xdsoft', function (event) { 2427 | var val = this.value, 2428 | key = event.which, 2429 | pos = this.selectionStart, 2430 | selEnd = this.selectionEnd, 2431 | hasSel = pos !== selEnd, 2432 | digit; 2433 | 2434 | // only alow these characters 2435 | if (((key >= KEY0 && key <= KEY9) || 2436 | (key >= _KEY0 && key <= _KEY9)) || 2437 | (key === BACKSPACE || key === DEL)) { 2438 | 2439 | // get char to insert which is new character or placeholder ('_') 2440 | digit = (key === BACKSPACE || key === DEL) ? '_' : 2441 | String.fromCharCode((_KEY0 <= key && key <= _KEY9) ? key - KEY0 : key); 2442 | 2443 | // we're deleting something, we're not at the start, and have normal cursor, move back one 2444 | // if we have a selection length, cursor actually sits behind deletable char, not in front 2445 | if (key === BACKSPACE && pos && !hasSel) { 2446 | pos -= 1; 2447 | } 2448 | 2449 | // don't stop on a separator, continue whatever direction you were going 2450 | // value char - keep incrementing position while on separator char and we still have room 2451 | // del char - keep decrementing position while on separator char and we still have room 2452 | while (true) { 2453 | var maskValueAtCurPos = options.mask.substr(pos, 1); 2454 | var posShorterThanMaskLength = pos < options.mask.length; 2455 | var posGreaterThanZero = pos > 0; 2456 | var notNumberOrPlaceholder = /[^0-9_]/; 2457 | var curPosOnSep = notNumberOrPlaceholder.test(maskValueAtCurPos); 2458 | var continueMovingPosition = curPosOnSep && posShorterThanMaskLength && posGreaterThanZero 2459 | 2460 | // if we hit a real char, stay where we are 2461 | if (!continueMovingPosition) break; 2462 | 2463 | // hitting backspace in a selection, you can possibly go back any further - go forward 2464 | pos += (key === BACKSPACE && !hasSel) ? -1 : 1; 2465 | 2466 | } 2467 | 2468 | if (event.metaKey) { // cmd has been pressed 2469 | pos = 0; 2470 | hasSel = true; 2471 | } 2472 | 2473 | if (hasSel) { 2474 | // pos might have moved so re-calc length 2475 | var selLength = selEnd - pos 2476 | 2477 | // if we have a selection length we will wipe out entire selection and replace with default template for that range 2478 | var defaultBlank = options.mask.replace(/[0-9]/g, '_'); 2479 | var defaultBlankSelectionReplacement = defaultBlank.substr(pos, selLength); 2480 | var selReplacementRemainder = defaultBlankSelectionReplacement.substr(1) // might be empty 2481 | 2482 | var valueBeforeSel = val.substr(0, pos); 2483 | var insertChars = digit + selReplacementRemainder; 2484 | var charsAfterSelection = val.substr(pos + selLength); 2485 | 2486 | val = valueBeforeSel + insertChars + charsAfterSelection 2487 | 2488 | } else { 2489 | var valueBeforeCursor = val.substr(0, pos); 2490 | var insertChar = digit; 2491 | var valueAfterNextChar = val.substr(pos + 1); 2492 | 2493 | val = valueBeforeCursor + insertChar + valueAfterNextChar 2494 | } 2495 | 2496 | if ($.trim(val) === '') { 2497 | // if empty, set to default 2498 | val = defaultBlank 2499 | } else { 2500 | // if at the last character don't need to do anything 2501 | if (pos === options.mask.length) { 2502 | event.preventDefault(); 2503 | return false; 2504 | } 2505 | } 2506 | 2507 | // resume cursor location 2508 | pos += (key === BACKSPACE) ? 0 : 1; 2509 | // don't stop on a separator, continue whatever direction you were going 2510 | while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) { 2511 | pos += (key === BACKSPACE) ? 0 : 1; 2512 | } 2513 | 2514 | if (isValidValue(options.mask, val)) { 2515 | this.value = val; 2516 | setCaretPos(this, pos); 2517 | } else if ($.trim(val) === '') { 2518 | this.value = options.mask.replace(/[0-9]/g, '_'); 2519 | } else { 2520 | input.trigger('error_input.xdsoft'); 2521 | } 2522 | } else { 2523 | if (([AKEY, CKEY, VKEY, ZKEY, YKEY].indexOf(key) !== -1 && ctrlDown) || [ESC, ARROWUP, ARROWDOWN, ARROWLEFT, ARROWRIGHT, F5, CTRLKEY, TAB, ENTER].indexOf(key) !== -1) { 2524 | return true; 2525 | } 2526 | } 2527 | 2528 | event.preventDefault(); 2529 | return false; 2530 | }); 2531 | } 2532 | } 2533 | 2534 | _xdsoft_datetime.setCurrentTime(getCurrentValue()); 2535 | 2536 | input 2537 | .data('xdsoft_datetimepicker', datetimepicker) 2538 | .on('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', function () { 2539 | if (input.is(':disabled') || (input.data('xdsoft_datetimepicker').is(':visible') && options.closeOnInputClick)) { 2540 | return; 2541 | } 2542 | if (!options.openOnFocus) { 2543 | return; 2544 | } 2545 | clearTimeout(timer); 2546 | timer = setTimeout(function () { 2547 | if (input.is(':disabled')) { 2548 | return; 2549 | } 2550 | 2551 | triggerAfterOpen = true; 2552 | _xdsoft_datetime.setCurrentTime(getCurrentValue(), true); 2553 | if(options.mask) { 2554 | setMask(options); 2555 | } 2556 | datetimepicker.trigger('open.xdsoft'); 2557 | }, 100); 2558 | }) 2559 | .on('keydown.xdsoft', function (event) { 2560 | var elementSelector, 2561 | key = event.which; 2562 | if ([ENTER].indexOf(key) !== -1 && options.enterLikeTab) { 2563 | elementSelector = $("input:visible,textarea:visible,button:visible,a:visible"); 2564 | datetimepicker.trigger('close.xdsoft'); 2565 | elementSelector.eq(elementSelector.index(this) + 1).focus(); 2566 | return false; 2567 | } 2568 | if ([TAB].indexOf(key) !== -1) { 2569 | datetimepicker.trigger('close.xdsoft'); 2570 | return true; 2571 | } 2572 | }) 2573 | .on('blur.xdsoft', function () { 2574 | datetimepicker.trigger('close.xdsoft'); 2575 | }); 2576 | }; 2577 | destroyDateTimePicker = function (input) { 2578 | var datetimepicker = input.data('xdsoft_datetimepicker'); 2579 | if (datetimepicker) { 2580 | datetimepicker.data('xdsoft_datetime', null); 2581 | datetimepicker.remove(); 2582 | input 2583 | .data('xdsoft_datetimepicker', null) 2584 | .off('.xdsoft'); 2585 | $(options.contentWindow).off('resize.xdsoft'); 2586 | $([options.contentWindow, options.ownerDocument.body]).off('mousedown.xdsoft touchstart'); 2587 | if (input.unmousewheel) { 2588 | input.unmousewheel(); 2589 | } 2590 | } 2591 | }; 2592 | $(options.ownerDocument) 2593 | .off('keydown.xdsoftctrl keyup.xdsoftctrl') 2594 | .off('keydown.xdsoftcmd keyup.xdsoftcmd') 2595 | .on('keydown.xdsoftctrl', function (e) { 2596 | if (e.keyCode === CTRLKEY) { 2597 | ctrlDown = true; 2598 | } 2599 | }) 2600 | .on('keyup.xdsoftctrl', function (e) { 2601 | if (e.keyCode === CTRLKEY) { 2602 | ctrlDown = false; 2603 | } 2604 | }) 2605 | .on('keydown.xdsoftcmd', function (e) { 2606 | if (e.keyCode === CMDKEY) { 2607 | cmdDown = true; 2608 | } 2609 | }) 2610 | .on('keyup.xdsoftcmd', function (e) { 2611 | if (e.keyCode === CMDKEY) { 2612 | cmdDown = false; 2613 | } 2614 | }); 2615 | 2616 | this.each(function () { 2617 | var datetimepicker = $(this).data('xdsoft_datetimepicker'), $input; 2618 | if (datetimepicker) { 2619 | if ($.type(opt) === 'string') { 2620 | switch (opt) { 2621 | case 'show': 2622 | $(this).select().focus(); 2623 | datetimepicker.trigger('open.xdsoft'); 2624 | break; 2625 | case 'hide': 2626 | datetimepicker.trigger('close.xdsoft'); 2627 | break; 2628 | case 'toggle': 2629 | datetimepicker.trigger('toggle.xdsoft'); 2630 | break; 2631 | case 'destroy': 2632 | destroyDateTimePicker($(this)); 2633 | break; 2634 | case 'reset': 2635 | this.value = this.defaultValue; 2636 | if (!this.value || !datetimepicker.data('xdsoft_datetime').isValidDate(dateHelper.parseDate(this.value, options.format))) { 2637 | datetimepicker.data('changed', false); 2638 | } 2639 | datetimepicker.data('xdsoft_datetime').setCurrentTime(this.value); 2640 | break; 2641 | case 'validate': 2642 | $input = datetimepicker.data('input'); 2643 | $input.trigger('blur.xdsoft'); 2644 | break; 2645 | default: 2646 | if (datetimepicker[opt] && $.isFunction(datetimepicker[opt])) { 2647 | result = datetimepicker[opt](opt2); 2648 | } 2649 | } 2650 | } else { 2651 | datetimepicker 2652 | .setOptions(opt); 2653 | } 2654 | return 0; 2655 | } 2656 | if ($.type(opt) !== 'string') { 2657 | if (!options.lazyInit || options.open || options.inline) { 2658 | createDateTimePicker($(this)); 2659 | } else { 2660 | lazyInit($(this)); 2661 | } 2662 | } 2663 | }); 2664 | 2665 | return result; 2666 | }; 2667 | 2668 | $.fn.datetimepicker.defaults = default_options; 2669 | 2670 | function HighlightedDate(date, desc, style) { 2671 | "use strict"; 2672 | this.date = date; 2673 | this.desc = desc; 2674 | this.style = style; 2675 | } 2676 | }; 2677 | ;(function (factory) { 2678 | if ( typeof define === 'function' && define.amd ) { 2679 | // AMD. Register as an anonymous module. 2680 | define(['jquery', 'jquery-mousewheel'], factory); 2681 | } else if (typeof exports === 'object') { 2682 | // Node/CommonJS style for Browserify 2683 | module.exports = factory(require('jquery'));; 2684 | } else { 2685 | // Browser globals 2686 | factory(jQuery); 2687 | } 2688 | }(datetimepickerFactory)); 2689 | 2690 | 2691 | /*! 2692 | * jQuery Mousewheel 3.1.13 2693 | * 2694 | * Copyright jQuery Foundation and other contributors 2695 | * Released under the MIT license 2696 | * http://jquery.org/license 2697 | */ 2698 | 2699 | (function (factory) { 2700 | if ( typeof define === 'function' && define.amd ) { 2701 | // AMD. Register as an anonymous module. 2702 | define(['jquery'], factory); 2703 | } else if (typeof exports === 'object') { 2704 | // Node/CommonJS style for Browserify 2705 | module.exports = factory; 2706 | } else { 2707 | // Browser globals 2708 | factory(jQuery); 2709 | } 2710 | }(function ($) { 2711 | 2712 | var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'], 2713 | toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ? 2714 | ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'], 2715 | slice = Array.prototype.slice, 2716 | nullLowestDeltaTimeout, lowestDelta; 2717 | 2718 | if ( $.event.fixHooks ) { 2719 | for ( var i = toFix.length; i; ) { 2720 | $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks; 2721 | } 2722 | } 2723 | 2724 | var special = $.event.special.mousewheel = { 2725 | version: '3.1.12', 2726 | 2727 | setup: function() { 2728 | if ( this.addEventListener ) { 2729 | for ( var i = toBind.length; i; ) { 2730 | this.addEventListener( toBind[--i], handler, false ); 2731 | } 2732 | } else { 2733 | this.onmousewheel = handler; 2734 | } 2735 | // Store the line height and page height for this particular element 2736 | $.data(this, 'mousewheel-line-height', special.getLineHeight(this)); 2737 | $.data(this, 'mousewheel-page-height', special.getPageHeight(this)); 2738 | }, 2739 | 2740 | teardown: function() { 2741 | if ( this.removeEventListener ) { 2742 | for ( var i = toBind.length; i; ) { 2743 | this.removeEventListener( toBind[--i], handler, false ); 2744 | } 2745 | } else { 2746 | this.onmousewheel = null; 2747 | } 2748 | // Clean up the data we added to the element 2749 | $.removeData(this, 'mousewheel-line-height'); 2750 | $.removeData(this, 'mousewheel-page-height'); 2751 | }, 2752 | 2753 | getLineHeight: function(elem) { 2754 | var $elem = $(elem), 2755 | $parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent'](); 2756 | if (!$parent.length) { 2757 | $parent = $('body'); 2758 | } 2759 | return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16; 2760 | }, 2761 | 2762 | getPageHeight: function(elem) { 2763 | return $(elem).height(); 2764 | }, 2765 | 2766 | settings: { 2767 | adjustOldDeltas: true, // see shouldAdjustOldDeltas() below 2768 | normalizeOffset: true // calls getBoundingClientRect for each event 2769 | } 2770 | }; 2771 | 2772 | $.fn.extend({ 2773 | mousewheel: function(fn) { 2774 | return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel'); 2775 | }, 2776 | 2777 | unmousewheel: function(fn) { 2778 | return this.unbind('mousewheel', fn); 2779 | } 2780 | }); 2781 | 2782 | 2783 | function handler(event) { 2784 | var orgEvent = event || window.event, 2785 | args = slice.call(arguments, 1), 2786 | delta = 0, 2787 | deltaX = 0, 2788 | deltaY = 0, 2789 | absDelta = 0, 2790 | offsetX = 0, 2791 | offsetY = 0; 2792 | event = $.event.fix(orgEvent); 2793 | event.type = 'mousewheel'; 2794 | 2795 | // Old school scrollwheel delta 2796 | if ( 'detail' in orgEvent ) { deltaY = orgEvent.detail * -1; } 2797 | if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent.wheelDelta; } 2798 | if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY; } 2799 | if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; } 2800 | 2801 | // Firefox < 17 horizontal scrolling related to DOMMouseScroll event 2802 | if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { 2803 | deltaX = deltaY * -1; 2804 | deltaY = 0; 2805 | } 2806 | 2807 | // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy 2808 | delta = deltaY === 0 ? deltaX : deltaY; 2809 | 2810 | // New school wheel delta (wheel event) 2811 | if ( 'deltaY' in orgEvent ) { 2812 | deltaY = orgEvent.deltaY * -1; 2813 | delta = deltaY; 2814 | } 2815 | if ( 'deltaX' in orgEvent ) { 2816 | deltaX = orgEvent.deltaX; 2817 | if ( deltaY === 0 ) { delta = deltaX * -1; } 2818 | } 2819 | 2820 | // No change actually happened, no reason to go any further 2821 | if ( deltaY === 0 && deltaX === 0 ) { return; } 2822 | 2823 | // Need to convert lines and pages to pixels if we aren't already in pixels 2824 | // There are three delta modes: 2825 | // * deltaMode 0 is by pixels, nothing to do 2826 | // * deltaMode 1 is by lines 2827 | // * deltaMode 2 is by pages 2828 | if ( orgEvent.deltaMode === 1 ) { 2829 | var lineHeight = $.data(this, 'mousewheel-line-height'); 2830 | delta *= lineHeight; 2831 | deltaY *= lineHeight; 2832 | deltaX *= lineHeight; 2833 | } else if ( orgEvent.deltaMode === 2 ) { 2834 | var pageHeight = $.data(this, 'mousewheel-page-height'); 2835 | delta *= pageHeight; 2836 | deltaY *= pageHeight; 2837 | deltaX *= pageHeight; 2838 | } 2839 | 2840 | // Store lowest absolute delta to normalize the delta values 2841 | absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) ); 2842 | 2843 | if ( !lowestDelta || absDelta < lowestDelta ) { 2844 | lowestDelta = absDelta; 2845 | 2846 | // Adjust older deltas if necessary 2847 | if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { 2848 | lowestDelta /= 40; 2849 | } 2850 | } 2851 | 2852 | // Adjust older deltas if necessary 2853 | if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { 2854 | // Divide all the things by 40! 2855 | delta /= 40; 2856 | deltaX /= 40; 2857 | deltaY /= 40; 2858 | } 2859 | 2860 | // Get a whole, normalized value for the deltas 2861 | delta = Math[ delta >= 1 ? 'floor' : 'ceil' ](delta / lowestDelta); 2862 | deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta); 2863 | deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta); 2864 | 2865 | // Normalise offsetX and offsetY properties 2866 | if ( special.settings.normalizeOffset && this.getBoundingClientRect ) { 2867 | var boundingRect = this.getBoundingClientRect(); 2868 | offsetX = event.clientX - boundingRect.left; 2869 | offsetY = event.clientY - boundingRect.top; 2870 | } 2871 | 2872 | // Add information to the event object 2873 | event.deltaX = deltaX; 2874 | event.deltaY = deltaY; 2875 | event.deltaFactor = lowestDelta; 2876 | event.offsetX = offsetX; 2877 | event.offsetY = offsetY; 2878 | // Go ahead and set deltaMode to 0 since we converted to pixels 2879 | // Although this is a little odd since we overwrite the deltaX/Y 2880 | // properties with normalized deltas. 2881 | event.deltaMode = 0; 2882 | 2883 | // Add event and delta to the front of the arguments 2884 | args.unshift(event, delta, deltaX, deltaY); 2885 | 2886 | // Clearout lowestDelta after sometime to better 2887 | // handle multiple device types that give different 2888 | // a different lowestDelta 2889 | // Ex: trackpad = 3 and mouse wheel = 120 2890 | if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); } 2891 | nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200); 2892 | 2893 | return ($.event.dispatch || $.event.handle).apply(this, args); 2894 | } 2895 | 2896 | function nullLowestDelta() { 2897 | lowestDelta = null; 2898 | } 2899 | 2900 | function shouldAdjustOldDeltas(orgEvent, absDelta) { 2901 | // If this is an older event and the delta is divisable by 120, 2902 | // then we are assuming that the browser is treating this as an 2903 | // older mouse wheel event and that we should divide the deltas 2904 | // by 40 to try and get a more usable deltaFactor. 2905 | // Side note, this actually impacts the reported scroll distance 2906 | // in older browsers and can cause scrolling to be slower than native. 2907 | // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false. 2908 | return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0; 2909 | } 2910 | 2911 | })); 2912 | --------------------------------------------------------------------------------