require 'erb' require 'tzinfo' module DatePicker module FormTagHelper def date_picker_tag(name, value, options = {}, html_options = nil) # Clean object and attribute names object_name = name.gsub(/\[\w*\]$/, "") attribute_name = name.gsub(/.*\[(\w*)\]$/, "\\1") # Setup Options option_names = [:time_zone, :format, :type, :default, :min, :max] opts = options.clone html_opts = html_options.clone options||= {} options = opts.slice(*option_names) options = ({ type: :date, time_zone: false, }).merge(options) html_options||= {} # Merge html_options with options html_options = { # Use text-type as default instead of date, since Datepicker should not mix up with native html5 components type: :text, # Generate unique ID with UI id: "date_picker_" + Digest::SHA1.hexdigest(name.to_s)[8..16], name: name, data: html_options[:data] || options[:data] || {} }.merge(opts.except(*option_names)).merge(html_options) # Get the type type = options[:type] # Set default values if !options.key?(:default) case type when :date default = Date.current when :datetime default = DateTime.current when :time default = Time.current end else default = options[:default] end # Override value from html_options if html_options.key?(:value) value = html_options[:value] end # Set default value if blank if value.blank? value = default end # Get Type format if not specified format = nil if options[:format].present? format = options[:format] elsif DatePicker.config.formats.present? format = DatePicker.config.formats[type] end # Apply string format identifier or default format if format.blank? || !format.is_a?(String) case type when :date format_id = format.present? && format.is_a?(Symbol) ? format.to_s : 'default' format = I18n.t('date.formats.' + format_id, default: "%Y-%m-%d") when :datetime format_id = format.present? && format.is_a?(Symbol) ? format.to_s : 'default' format = I18n.t('time.formats.' + format_id, default: "%a, %d %b %Y %H:%M:%S") when :time format_id = format.present? && format.is_a?(Symbol) ? format.to_s : 'only_time' format = I18n.t('time.formats.' + format_id, default: "%H:%M:%S") end else format = format.to_s end # Get Style if options[:style].present? style = options[:style] elsif DatePicker.config.style.present? style = DatePicker.config.style else style = :none end path = File.join(File.dirname(__FILE__), "styles", style.to_s) # Require the selected style and retrieve as object if style && style != 'none' && File.exist?(path + '.rb') require path obj = Object::const_get('DatePicker::Styles::' + style.to_s.classify).new end # Merge with types and options from style template types = [:date] if obj && obj.respond_to?(:types) types = obj.send(:types) end # Mobile Fallback is_mobile = (request.headers["HTTP_USER_AGENT"].present? && request.headers["HTTP_USER_AGENT"] =~ /\b(Mobile|webOS|Android|iPhone|iPad|iPod|Windows Phone|Opera Mobi|Kindle|BackBerry|PlayBook)\b/i).present? if is_mobile case options[:type] when :date return date_field(object_name, attribute_name, html_options.merge({type: 'date', value: value.present? ? value : ''})) when :datetime return datetime_field(object_name, attribute_name, html_options.merge({type: 'datetime-local', value: value.present? ? value.strftime("%Y-%m-%dT%H:%M:%S") : ''})) when :time return time_field(object_name, attribute_name, html_options.merge({type: 'time', value: value.present? ? value.strftime("%H:%M") : ''})) end end # Desktop Fallback if !obj || !types.include?(options[:type]) # Presence of attribute name prevents auto-generating html_options.delete(:name) # Choose the right form helper by type case options[:type] when :date return date_select(object_name, attribute_name, {default: value}, html_options) when :datetime return datetime_select(object_name, attribute_name, {default: value}, html_options) when :time return time_select(object_name, attribute_name, {default: value}, html_options) end end # Get options from implementation if obj.respond_to?(:options) html_options = html_options.merge(obj.send(:options)) end # Get mapping from style if obj.mapping.present? mapping = obj.mapping end # Resolve mapping by identifier if obj.mapping.is_a? Symbol mapping = DatePicker::Mappings.send(obj.mapping) end # Setup picker format picker_format = format.clone # Escape special chars in format if mapping[:__].present? replace = mapping[:__].gsub(/\*/, "\\\\1") # Get strftime patterns keys = mapping.keys.select{ |key| !mapping[key].blank? && !key.to_s.start_with?('__') } # Get picker patterns values = keys.map{ |key| mapping[key] } # Escape any special characters of picker format not preceded by % picker_format.gsub!(/(?