UNPKG

coffeescript-ui

Version:
1,452 lines (1,191 loc) 35.6 kB
### * coffeescript-ui - Coffeescript User Interface System (CUI) * Copyright (c) 2013 - 2016 Programmfabrik GmbH * MIT Licence * https://github.com/programmfabrik/coffeescript-ui, http://www.coffeescript-ui.org ### CUI.Template.loadTemplateText(require('./DateTime.html')); # CUI.tz_data = {} moment = require('moment') class CUI.DateTime extends CUI.Input constructor: (opts) -> super(opts) @init() @defaults: button_tooltip: "Open calendar" bc_appendix: ["B.C.","BC"] initOpts: -> super() locale = CUI.DateTime.getLocale() @addOpts locale: mandatory: true default: locale check: (v) -> CUI.util.isArray(CUI.DateTimeFormats[v]?.formats) input_types: check: Array display_type: default: "long" check: ["long", "short"] min_year: mandatory: true default: 0 check: "Integer" max_year: mandatory: true default: 9999 check: "Integer" store_invalid: mandatory: true default: false check: Boolean @removeOpt("getValueForDisplay") @removeOpt("getValueForInput") # @removeOpt("correctValueForInput") @removeOpt("checkInput") @removeOpt("getInputBlocks") init: -> @__regexpMatcher = @regexpMatcher() @__input_formats_known = CUI.DateTimeFormats[@_locale].formats @__locale_format = CUI.DateTimeFormats[@_locale] @__input_formats = [] if not @_input_types?.length @__input_formats = @__input_formats_known.slice(0) else for type in @_input_types found = false for f in @__input_formats_known if f.type == type @__input_formats.push(f) found = true CUI.util.assert(found, "new CUI.DateTime", "opts.input_types contains unknown type: #{type}", formats: @__input_formats_known, input_type: @_input_types) @__default_format = @__input_formats[0] for format in @__input_formats if format.clock == false @__input_format_no_time = format @__default_format = format break @__input_format = @initFormat(@__default_format) return setInputFormat: (use_clock = @__input_formats[0].clock) -> if use_clock == true @__input_format = @initFormat(@__input_formats[0]) else @__input_format = @initFormat(@__input_format_no_time) @ initDateTimePicker: -> if @__dateTimeTmpl return @__dateTimeTmpl @__dateTimeTmpl = new CUI.Template name: "date-time" map: calendar: true analog_clock: true hour_minute: true digi_clock: true # timezone_display: true # timezone: true header_left: true header_center: true header_right: true hour: true minute: true second: true for k in [ "calendar" "hour_minute" "hour" "minute" "second" ] @["__#{k}"] = @__dateTimeTmpl.map[k] @__dateTimeTmpl.append( new CUI.defaults.class.Button( class: "cui-date-time-browser-date" icon_left: "left" text: @__locale_format.tab_date onClick: => @setCursor("day") ) , "header_left") @__dateTimeTmpl.append( new CUI.defaults.class.Button( class: "cui-date-time-browser-time" icon_right: "right" text: @__locale_format.tab_time onClick: => @setCursor("hour") ) , "header_right") # @__timezone_display = tmpl.map.timezone_display # @__timeZone = new CUI.Select # data: CUI.tz_data # name: "tz" # mark_changed: false # undo_support: false # onDataChanged: (data) => # @setPrintClock(@__current_moment) # options: => # @getTimezoneOpts() # .start() # # tmpl.append(@__timeZone, "timezone") @setCursor("day") # if @__input_format.digi_clock # @__dateTimeTmpl.append(@getDigiDisplay(@__input_format.digi_clock), "digi_clock") @__dateTimeTmpl getTemplate: -> new CUI.Template name: "date-time-input" map: center: true right: true readOpts: -> super() @_checkInput = @__checkInput @_getInputBlocks = @__getInputBlocks # @_correctValueForInput = (dateTime, value) => # corrected_value = @parseAndFormatValue(value, "input") # if corrected_value # corrected_value # else # # keep the invalid value # value getCurrentFormat: -> @__input_format getCurrentFormatDisplay: -> @__input_format?.__display setCursor: (cursor) -> switch cursor when "hour", "minute", "second", "am_pm" title = @__locale_format.tab_time CUI.dom.setAttribute(@__dateTimeTmpl.DOM, "browser", "time") @setDigiClock() else title = @__locale_format.tab_date CUI.dom.setAttribute(@__dateTimeTmpl.DOM, "browser", "date") @__dateTimeTmpl.replace(new CUI.Label(text: title), "header_center") @ initFormat: (input_format) -> moment.locale(@__locale_format.moment_locale or @_locale) switch @_display_type when "short" input_format.__display = input_format.display_short else input_format.__display = input_format.display @_invalidHint = text: input_format.invalid for k, v of @__regexpMatcher v.match_str = k input = input_format.input rstr = "("+Object.keys(@__regexpMatcher).join("|")+")" re = new RegExp(rstr, "g") s = input.split("") regexp = [] matcher = [] last_match_end = 0 while (match = re.exec(input)) != null match_str = match[0] match_start = match.index regexp.push("("+CUI.util.escapeRegExp(s.slice(last_match_end, match_start).join(""))+")") regexp.push("("+@__regexpMatcher[match_str].regexp+")") matcher.push(@__regexpMatcher[match_str]) last_match_end = match_start + match_str.length regexp.push("("+CUI.util.escapeRegExp(s.slice(last_match_end).join(""))+")") input_format.regexp = new RegExp("^"+regexp.join("")+"$") input_format.matcher = matcher input_format getTemplateKeyForRender: -> "center" render: -> super() if CUI.util.isEmpty(@_placeholder) @__input.setAttribute("placeholder", @__input_formats[0].text) switch @_display_type when "short" display_key = "display_short" else display_key = "display" attr = @__input_formats[0][display_key+'_attribute'] if not attr attr = @__input_formats[0][display_key].replace(/[:, \.]/g, "-").replace(/-+/g,"-") @DOM.setAttribute("data-cui-date-time-format", attr) @addClass("cui-data-field--with-button") @__calendarButton = new CUI.defaults.class.Button icon: "calendar" tooltip: text: CUI.DateTime.defaults.button_tooltip onClick: => @openPopover(@__calendarButton) @replace(@__calendarButton, "right") format: (_s, _output_format="display", output_type=null) -> CUI.util.assert(_output_format in CUI.DateTime.formatTypes, "CUI.DateTime.format", "output_format must be on of \"#{CUI.DateTime.formatTypes.join(',')}\".", parm1: _s, output_format: output_format) if moment.isMoment(_s) mom = _s else s = _s?.trim() if CUI.util.isEmpty(s) return null mom = @parse(s, @__input_formats_known) if mom.isValid() and CUI.util.isNull(output_type) output_type = @getCurrentFormat().type if not mom.isValid() formats_tried = [] for format in @__input_formats_known for k in CUI.DateTime.formatTypes formats_tried.push(format[k]) console.warn("CUI.DateTime.format: Moment '#{s}' is invalid. Tried formats:", formats_tried) return null output_format = null for f in @__input_formats_known if f.type == output_type output_format = f break CUI.util.assert(output_format, "CUI.DateTime.format", "output_type must be in known formats", formats: @__input_formats_known, output_type: output_type) switch _output_format when "store" return CUI.DateTime.formatMoment(mom, output_format[_output_format]) else return CUI.DateTime.formatMomentWithBc(mom, output_format[_output_format]) regexpMatcher: -> YYYY: regexp: "(?:-|)[0-9]{1,}" inc_func: "year" cursor: "year" MM: regexp: "(?:0[1-9]|1[0-2])" inc_func: "month" cursor: "month" DD: regexp: "[0-3][0-9]" inc_func: "day" cursor: "day" HH: regexp: "[0-2][0-9]" inc_func: "hour" cursor: "hour" hh: regexp: "[0-1][0-9]" inc_func: "hour" cursor: "hour" mm: regexp: "[0-5][0-9]" inc_func: "minute" cursor: "minute" ss: regexp: "[0-5][0-9]" inc_func: "second" cursor: "second" A: regexp: "(?:AM|PM)" inc_func: @incAMPM cursor: "am_pm" a: regexp: "(?:am|pm)" inc_func: @incAMPM cursor: "am_pm" Y: regexp: "(?:-|)[0-9]{1,}" inc_func: "year" cursor: "year" incAMPM: (mom) -> current_hour = mom.hour() if current_hour < 12 # AM # set PM mom.add(12,"hour") else mom.subtract(12,"hour") initValue: -> super() value = @getValue() corrected_value = @parseValue(value, "store") if corrected_value and corrected_value != value console.warn("CUI.DateTime.initValue: Corrected value in data:", corrected_value, "Original value:", value) @__data[@_name] = corrected_value @ getValueForDisplay: -> value = @getValue()?.trim?() if CUI.util.isEmpty(value) return "" mom = @parse(value) if not mom.isValid() return value return CUI.DateTime.formatMomentWithBc(mom, @getCurrentFormatDisplay()) getValueForInput: (v = @getValue()) -> if CUI.util.isEmpty(v?.trim()) return "" mom = @parse(v) if not mom.isValid() return v return CUI.DateTime.formatMomentWithBc(mom, @__input_format.input) __checkInput: (value) -> @__calendarButton.enable() if not CUI.util.isEmpty(value?.trim()) mom = @parse(value) if not mom.isValid() return false if mom.bc or value.startsWith("-") @__calendarButton.disable() else @__input_format = @initFormat(@__default_format) return true __getInputBlocks: (v) -> # console.debug "getInputBlocks", v, @__input_format.regexp match = v.match(@__input_format.regexp) if not match return false blocks = [] pos = 0 for m, idx in match if idx == 0 continue if idx % 2 == 0 blocks.push new CUI.DateTimeInputBlock start: pos string: m datetime: v input_format: @__input_format matcher: @__input_format.matcher[idx/2-1] pos += m.length if idx % 2 == 1 continue blocks start_day: 1 storeValue: (value, flags={}) -> mom = @parse(value) if mom.isValid() if mom.bc value = "-"+mom.bc else value = mom.format(@__input_format.store) else if @_store_invalid and value.trim().length > 0 value = 'invalid' else value = null super(value, flags) @ getDigiDisplay: (format) -> digits = [] for d in format.split("") if (idx = ["H","h","m","s","A","a"].indexOf(d)) > -1 cursor = ["hour", "hour", "minute", "second", "am_pm", "am_pm"][idx] if d in ["A", "a"] digits.push(mask: "[aApP]", attr: cursor: cursor, title: cursor) digits.push(mask: "[mM]", attr: cursor: cursor, title: cursor) else digits.push(mask: "[0-9]", attr: cursor: cursor) else if d == "*" digits.push(mask: "[0-9A-Z+\-:\. ]") else digits.push(static: ":") # console.debug digits @__digiDisplay = new CUI.DigiDisplay(digits: digits) openPopover: (btn) -> @initDateTimePicker() @__popover = new CUI.Popover element: btn handle_focus: false onHide: => @displayValue() @closePopover() placement: "se" class: "cui-date-time-popover" pane: content: @__dateTimeTmpl @updateDateTimePicker() @setCursor("day") # if not @__current_moment.__now # @setInputFromMoment() @__popover.show() @ closePopover: -> # if @__updatePopoverInterval # CUI.clearTimeout(@__updatePopoverInterval) # @__updatePopoverInterval = null if @__popover @__popover.destroy() delete(@__popover) @ updateDateTimePicker: -> @setMomentFromInput() # if @__current_moment.__now # @__updatePopoverInterval = CUI.setTimeout => # @updateDateTimePicker() # @__updatePopoverInterval = null # , # 1000*30 # update the popover every 30 seconds console.debug "updating popover...", @__input_format @drawDate() # @drawHourMinute() @setClock() @setDigiClock() @setPrintClock() # @pop.position() @ destroy: -> # console.debug "destroying popover" @closePopover() super() setClock: (mom = @__current_moment) -> hour = mom.hour() minute = mom.minute() second = mom.second() millisecond = 0 # mom.millisecond() seconds = second + millisecond / 1000 minutes = minute + seconds / 60 hours = (hour%12) + minutes / 60 CUI.dom.setStyleOne(@__hour, "transform", "rotate(" + hours * 30 + "deg)") CUI.dom.setStyleOne(@__minute, "transform", "rotate(" + minutes * 6 + "deg)") CUI.dom.setStyleOne(@__second, "transform", "rotate(" + seconds * 6 + "deg)") setDigiClock: (mom = @__current_moment) -> f = @__input_format.digi_clock console.debug "setDigiClock", f, mom, mom.format(f) if f @__digiDisplay.display(mom.format(f)) @ setPrintClock: (mom = @__current_moment) -> if not @__input_format.timezone_display return @ mom_tz = mom.clone() mom_tz.tz(CUI.tz_data.tz) # console.debug @__input_format.timezone_display, mom_tz.format(@__input_format.timezone_display) CUI.dom.empty(@__timezone_display) CUI.dom.append(@__timezone_display, mom_tz.format(@__input_format.timezone_display)) setTimezone: -> UNUSEDgetTimezoneData: -> if @__tz_data return CUI.resolvedPromise() $.get("#{CUI.getPathToScript()}/moment-timezone-meta.json") .done (tz_data) => names = [] by_name = {} for tz in tz_data tz.geo = tz.lat+"/"+tz.long # tz.print_name = tz.name.split("/").slice(-1)[0] tz.print_name = tz.name names.push(tz.print_name) by_name[tz.print_name] = tz names.sort() @__tz_data = [] for n in names @__tz_data.push(by_name[n]) # console.debug "timezone data loaded", @__tz_data getTimezoneOpts: -> if @__current_moment mom = @__current_moment.clone() opts = [] for tz, idx in @__tz_data if not mom and tz.name != CUI.DateTimeFormats["de-DE"].timezone continue if mom span = CUI.dom.span("cui-timezone-offset").setAttribute("title", tz.geo) span.textContent = mom.tz(tz.name).format("zZ") span else span = null opts.push text: tz.print_name right: span value: tz.name opts # s: string to parse # formats: format to check # use_formats: formats which are used to call our "initFormat", if format # matched is not among them, init to the first check format. # these formats are the "allowed" formats, this is used in __checkInput parse: (stringValue, formats = @__input_formats, use_formats = formats) -> if not (stringValue?.trim?().length > 0) return moment.invalid() for format in formats mom = @__parseFormat(format, stringValue) if mom if format in use_formats @__input_format = @initFormat(format) else @__input_format = @initFormat(@__default_format) mom.locale(moment.locale()) if mom.year() > @_max_year # Year must not be greater than max year. return moment.invalid() # console.debug "parsing ok", mom, f, moment.locale() return mom if not formats.some((format) -> format.support_bc) return moment.invalid() # Moment support not all BC dates, we get here # if the year is below that, or ends with a supported # appendix like "v. Chr." # lets see if the date is below zero checkBC = false hasBCAppendix = false if stringValue.startsWith("-") checkBC = true stringValue = stringValue.substring(1) else us = stringValue.toLocaleUpperCase() for appendix in CUI.DateTime.defaults.bc_appendix ua = appendix.toLocaleUpperCase() if us.endsWith(" "+ua) stringValue = stringValue.substring(0, stringValue.length - ua.length).trim() hasBCAppendix = checkBC = true break if not checkBC return moment.invalid() # set bc to the value m = stringValue.match(/^[0-9]+$/) if not m return moment.invalid() # fake a moment mom = moment() mom.bc = parseInt(stringValue) if hasBCAppendix # If it has BC appendix, means that the number value of the year is one less. mom.bc-- if mom.bc < 10 mom.bc = "000"+mom.bc else if mom.bc < 100 mom.bc = "00"+mom.bc else if mom.bc < 1000 mom.bc = "0"+mom.bc else mom.bc = ""+mom.bc return mom # like parse, but it used all known input formats # to recognize the value parseValue: (value, output_format = null) -> input_formats = @__input_formats.slice(0) for format in @__input_formats_known CUI.util.pushOntoArray(format, input_formats) mom = @parse(value, input_formats, @__input_formats) if not output_format return mom if not mom.isValid() return null if mom.bc return "-"+mom.bc else return mom.format(@__input_format[output_format]) __parseFormat: (f, s) -> for k in CUI.DateTime.formatTypes CUI.util.assert(f[k], "CUI.DateTime.__parseFormat", ".#{k} must be set", format: f) mom = moment(s, f[k], true) # true the input format if mom.isValid() return mom for p in f.parse mom = moment(s, p, true) if mom.isValid() return mom return setMomentFromInput: -> inp = @__input.value.trim() if inp.length > 0 @__current_moment = @parse(inp) if inp == "" or not @__current_moment.isValid() @__current_moment = moment() @__current_moment.__now = true @__input_format = @initFormat(@__default_format) return setInputFromMoment: -> @__clearOverwriteMonthAndYear() # @__input.value = @__current_moment.format(@__input_format.input) # console.error "stored value:", @__input.val() # @storeValue(@__input.val()) @setValue(@__current_moment.format(@__input_format.input), no_trigger: false) @ __clearOverwriteMonthAndYear: -> @__overwrite_month = null @__overwrite_year = null drawDate: (_mom) -> if not _mom mom = @__current_moment.clone() mom.bc = @__current_moment.bc else mom = _mom @updateCalendar(mom, false) updateCalendar: (mom, update_current_moment = true) -> CUI.dom.empty(@__calendar) CUI.dom.append(@__calendar, @getDateTimeDrawer(mom)) CUI.dom.append(@__calendar, @drawMonthTable(mom)) CUI.dom.append(@__calendar, @drawYearMonthsSelect(mom)) if update_current_moment @__current_moment = mom.clone() @__current_moment.bc = mom.bc @setInputFromMoment() console.info("CUI.DateTime.updateCalendar:", @__current_moment.format(@__input_format.input)) @markDay() @ getDateTimeDrawer: (mom) -> am_pm = @__input_formats[0].clock_am_pm data = month: mom.month() year: mom.year() date: mom.date() hour: null minute: null second: null am_pm: null if @__input_format.clock data.hour = mom.hour() data.minute = mom.minute() data.second = mom.second() if am_pm data.am_pm = Math.floor(data.hour / 12)*12 data.hour = data.hour%12 pad0 = (n) -> if n < 10 "0"+n else ""+n date_sel = new CUI.Select( name: "date" data: data group: "date" onDataChanged: => @updateCalendar(mom.date(data.date)) options: => opts = [] for day in [1..mom.daysInMonth()] opts.push text: pad0(day) value: day opts ).start() month_sel = new CUI.Select( name: "month" data: data group: "date" onDataChanged: => @updateCalendar(mom.month(data.month)) options: => opts = [] for month in [0..11] opts.push text: pad0(month+1) value: month opts ).start() year_sel = new CUI.Select( name: "year" data: data group: "date" onDataChanged: => @updateCalendar(mom.year(data.year)) options: => options = [] minYear = data.year - 20 if minYear < @_min_year minYear = @_min_year for year in [minYear..data.year + 20] options.push text: "#{year}" value: year options ).start() if @__input_formats[0].clock if @__input_format_no_time emtpy_clock_opts = [ text: '' value: null ] else emtpy_clock_opts = [] hour_sel = new CUI.Select( name: "hour" data: data group: "time" onDataChanged: (_data) => if _data.hour == null @setInputFormat(false) @updateCalendar(mom) else @setInputFormat(true) if am_pm @updateCalendar(mom.hour(data.hour+data.am_pm)) else @updateCalendar(mom.hour(data.hour)) @__popover.position() options: => opts = emtpy_clock_opts.slice(0) if am_pm for hour in [1..12] opts.push text: pad0(hour) value: hour%12 else for hour in [0..23] opts.push text: pad0(hour) value: hour opts ).start() # minute_colon = new CUI.Label(text: ":") minute_sel = new CUI.Select( class: "cui-date-time-60-select" name: "minute" group: "time" data: data onDataChanged: (_data) => if _data.minute == null @setInputFormat(false) @updateCalendar(mom) else @setInputFormat(true) @updateCalendar(mom.minute(data.minute)) @__popover.position() options: => opts = emtpy_clock_opts.slice(0) for minute in [0..59] opts.push text: pad0(minute) value: minute opts ).start() if am_pm am_pm_sel = new CUI.Select( class: "cui-date-time-am-pm-select" name: "am_pm" group: "time" data: data onDataChanged: (_data) => if _data.am_pm == null @setInputFormat(false) @updateCalendar(mom) else @setInputFormat(true) @updateCalendar(mom.hour(data.hour+data.am_pm)) @__popover.position() options: => opts = emtpy_clock_opts.slice(0) for am_pm in ["AM", "PM"] opts.push text: am_pm value: if am_pm == "AM" then 0 else 12 # offset in hours opts ).start() # second_colon = new CUI.Label(text: ":") # second_sel = new CUI.Select( # class: "cui-date-time-60-select" # name: "second" # data: data # onDataChanged: => # @updateCalendar(mom.second(data.second)) # options: => # opts = [] # for second in [0..59] # opts.push # text: pad0(second) # value: second # opts # ).start() new CUI.Buttonbar( buttons: [ date_sel month_sel year_sel hour_sel # minute_colon minute_sel am_pm_sel # second_colon # second_sel ] ).DOM drawYearMonthsSelect: (mom) -> year = null updateCalendar = => @updateCalendar(mom.year(year)) data = month: mom.month() year: mom.year() month_opts = [] for m, idx in moment.months() month_opts.push text: m value: idx now_year = moment().year() month_label_max_chars = 0 for opt in month_opts if opt.text?.length > month_label_max_chars month_label_max_chars = opt.text?.length month_label = new CUI.Label text: month_opts[data.month].text month_label.setTextMaxChars(month_label_max_chars) ##### HEADER includes YEAR and MONTH header_year_month = new CUI.HorizontalLayout maximize_vertical: false maximize_horizontal: true class: "cui-date-time-footer" left: content: new CUI.Buttonbar class: "cui-date-time-header-month" buttons: [ icon: "left" onClick: (ev) => if mom.clone().subtract(1, "months").year() < @_min_year return mom.subtract(1, "months") @drawDate(mom) , month_label # new CUI.Select( # attr: # cursor: "month" # class: "cui-date-time-month-select" # data: data # name: "month" # onShow: => # @setCursor("month") # onHide: => # @setCursor("month") # mark_changed: false # onDataChanged: (_data, element, ev) => # @updateCalendar(mom.month(data.month)) # options: month_opts # ).start() , icon: "right" onClick: (ev) => if mom.clone().add(1, "months").year() > @_max_year return mom.add(1, "months") @drawDate(mom) ] right: content: new CUI.Buttonbar class: "cui-date-time-header-year" buttons: [ icon: "left" group: "year" onClick: => if data.year - 1 < @_min_year return mom.subtract(1, "years") @drawDate(mom) , new CUI.NumberInput( attr: cursor: "year" max: @_max_year min: @_min_year placeholder: ""+now_year data: data name: "year" group: "year" onDataChanged: (data) => if CUI.util.isEmpty(data.year) year = now_year else year = data.year CUI.scheduleCallback(ms: 500, call: updateCalendar) ).start() , icon: "right" group: "year" onClick: => if data.year + 1 > @_max_year return mom.add(1, "years") @drawDate(mom) ] header_year_month.DOM drawMonthTable: (_mom) -> month = _mom.month() year = _mom.year() # set first day of month as start mom = moment([ year month 1 _mom.hour() _mom.minute() _mom.second() 0 ]) # .utc() month_table = CUI.dom.table("cui-date-time-date") CUI.Events.listen node: month_table type: "click" call: (ev) => ev.stopPropagation() target = ev.getTarget() # console.debug "click on date table", ev.getTarget() if CUI.dom.closest(target, ".cui-date-time-day") data = CUI.dom.data(CUI.dom.closest(target, "td,.cui-td")) @__input_format = @initFormat(@__default_format) # order here is important, we need to set the month # before we set the date! @__current_moment.year(data.year) @__current_moment.month(data.month) @__current_moment.date(data.date) @updateCalendar(@__current_moment) if @__input_formats[0].clock @__popover.position() else @closePopover() return # Wk, Mo, Tu, We, Th... tr = CUI.dom.tr("cui-date-time-month-header") CUI.dom.append(month_table, tr) td_func = CUI.dom.th tabWeekDiv = CUI.dom.div("cui-date-time-dow") tabWeekDiv.textContent = @__locale_format.tab_week CUI.dom.append(tr, CUI.dom.append(td_func("cui-date-time-week-title"), tabWeekDiv)) for dow in [@start_day..@start_day+6] weekday = moment.weekdaysMin(dow%7) day_div = CUI.dom.div("cui-date-time-dow") day_div.textContent = weekday CUI.dom.addClass(day_div, "cui-date-time-day-"+weekday.toLowerCase()) CUI.dom.append(tr, CUI.dom.append(td_func(), day_div)) # Weeks mom.subtract((mom.day()-@start_day+7)%7, "days") dow = @start_day weeks = 0 now = moment() loop curr_y = mom.year() curr_m = mom.month() day_no = mom.date() if (dow-@start_day)%7 == 0 if weeks ==6 # if ((curr_m > m and date.getUTCFullYear() == year) or date.getUTCFullYear() > year) break tr = CUI.dom.tr() CUI.dom.append(month_table, tr) week_no = mom.week() #@start_day==0) CUI.dom.append(tr, CUI.dom.append(CUI.dom.td("cui-date-time-week"), CUI.dom.text(week_no))) weeks++ div_type = CUI.dom.td day_span = CUI.dom.span() day_span.textContent = day_no day_div = div_type("cui-date-time-day", cursor: "day", datestr: [curr_y, curr_m, day_no].join("-")) CUI.dom.append(day_div, day_span) if curr_m < month CUI.dom.addClass(day_div, "cui-date-time-previous-month") else if curr_m > month CUI.dom.addClass(day_div, "cui-date-time-next-month") else CUI.dom.addClass(day_div, "cui-date-time-same-month") if year == now.year() and month == now.month() and day_no == now.date() CUI.dom.addClass(day_div, "cui-date-time-now") CUI.dom.addClass(day_div, "cui-date-time-day-"+mom.format("dd").toLowerCase()) td = day_div CUI.dom.append(tr, td) CUI.dom.data(td, date: day_no month: curr_m year: curr_y ) mom.add(1, "days") dow++ month_table markDay: -> for el in CUI.dom.matchSelector(@__dateTimeTmpl.DOM, ".cui-date-time-calendar .cui-date-time-selected") CUI.dom.removeClass(el, "cui-date-time-selected") # console.debug "markDay", @__current_moment, @__current_moment.__now if @__current_moment.__now return datestr = [ @__current_moment.year() @__current_moment.month() @__current_moment.date() ].join("-") # console.debug "markDay", datestr for el in CUI.dom.matchSelector(@__calendar, "[datestr=\"#{datestr}\"]") CUI.dom.addClass(el, "cui-date-time-selected") return # drawHourMinute: -> # if @__gridTable # @markTime() # return # @__gridTable = CUI.dom.table("cui-date-time-day-grid") # @__hour_minute.empty().append(@__gridTable) # CUI.Events.listen # node: @__hour_minute # type: "click" # call: (ev) => # if not @__gridTable # return # ev.stopPropagation() # $target = $(ev.getTarget()) # # console.debug "clicked on ", $target # if $target.closest(".cui-date-time-grid-hour").length # hour = DOM.data($target.closest("td,.cui-td")[0], "hour") # if @__input_formats[0].clock_am_pm # current_hour = @__current_moment.hour() # if current_hour < 12 # AM # @__current_moment.hour(hour%12) # else # @__current_moment.hour(hour%12+12) # else # @__current_moment.hour(hour) # @__current_moment.second(0) # if @__current_moment.minute() % 5 != 0 # @__current_moment.minute(0) # if @__input_formats[0].clock_am_pm # cursor = "am_pm" # else # cursor = "minute" # if $target.closest(".cui-date-time-grid-am-pm").length # current_hour = @__current_moment.hour() # am_pm = $target.closest("td,.cui-td").data("am_pm") # if am_pm == "AM" # if current_hour >= 12 # @__current_moment.hour(current_hour-12) # else # if current_hour < 12 # @__current_moment.hour(current_hour+12) # @__current_moment.second(0) # cursor = "minute" # if $target.closest(".cui-date-time-grid-minute").length # @__current_moment.minute(DOM.data($target.closest("td,.cui-td")[0], "minute")) # @__current_moment.second(0) # cursor = "blur" # delete(@__current_moment.__now) # @markTime() # @setInputFromMoment() # if cursor == "blur" # @closePopover() # else # @setCursor(cursor) # return # #CUI.dom.tr().appendTo(table).append( # # CUI.dom.td("cui-date-time-hour-minute-label", colspan: 6).append(CUI.dom.text("Hour")) # #) # if not @__input_formats[0].clock_am_pm # for hour in [0..23] # if hour % 6 == 0 # tr = CUI.dom.tr("cui-date-time-grid-hour-row").appendTo(@__gridTable) # tr.append( # td = CUI.dom.td("cui-date-time-grid-hour") # .setAttribute("hour", hour) # .append(CUI.dom.text(hour)) # ) # DOM.data(td[0], "hour", hour) # tr.addClass("cui-date-time-grid-row-last") # else # for hour in [1..12] # if (hour-1) % 6 == 0 # tr = CUI.dom.tr("cui-date-time-grid-hour-row").appendTo(@__gridTable) # tr.append( # td = CUI.dom.td("cui-date-time-grid-hour") # .setAttribute("hour", hour) # .append(CUI.dom.text(hour)) # ) # DOM.data(td[0], "hour", hour) # tr.addClass("cui-date-time-grid-row-last") # # ---------------------- # tr = CUI.dom.tr("cui-date-time-grid-am-pm-row").appendTo(@__gridTable) # for am_pm in ["AM","PM"] # tr.append( # td = CUI.dom.td("cui-date-time-grid-am-pm") # .setAttribute("am_pm", am_pm) # .append(CUI.dom.text(am_pm)) # ) # DOM.data(td[0], "am_pm", am_pm) # tr.append(CUI.dom.td("",colspan:4)) # tr.addClass("cui-date-time-grid-row-last") # #CUI.dom.tr().appendTo(table).append( # # CUI.dom.td("cui-date-time-hour-minute-label", colspan: 6).append(CUI.dom.text("Minute")) # #) # for minute in [0..59] by 5 # if minute % 6 == 0 # tr = CUI.dom.tr("cui-date-time-grid-minute-row").appendTo(@__gridTable) # if minute < 10 # _minute = ":0"+minute # else # _minute = ":"+minute # tr.append( # td = CUI.dom.td("cui-date-time-grid-minute") # .setAttribute("minute", minute) # .append(CUI.dom.text(_minute)) # ) # DOM.data(td[0], "minute", minute) # tr.addClass("cui-date-time-grid-minute-row-last") # @markTime() # return # markTime: -> # @__dateTimeTmpl.DOM.find(".cui-date-time-day-grid .cui-date-time-selected").removeClass("cui-date-time-selected") # for k in ["hour", "minute"] # if @__current_moment.__now # continue # units = @__current_moment[k]() # if k == "hour" and @__input_formats[0].clock_am_pm # units = (units+11)%12+1 # convert hours in visible hour format # if k == "minute" # units = units - (units % 5) # @__gridTable.find("[#{k}=\"#{units}\"]").addClass("cui-date-time-selected") # if @__input_formats[0].clock_am_pm # for _c in @__gridTable.find("[am_pm]") # c = _c # if @__current_moment.__now # continue # if @__current_moment.hour() < 12 # if c.getAttribute("am_pm") == "AM" # c.addClass("cui-date-time-selected") # else # if c.getAttribute("am_pm") == "PM" # c.addClass("cui-date-time-selected") # return # Keys when try parsing @formatTypes: ["store", "input", "display", "display_short"] @setLocale: (locale) -> CUI.util.assert(CUI.DateTimeFormats[locale], "CUI.DateTime.setLocale", "Locale #{locale} unknown", DateTimeFormats: CUI.DateTimeFormats) CUI.DateTime.__locale = locale @getLocale: -> if CUI.DateTime.__locale locale = CUI.DateTime.__locale else for locale of CUI.DateTimeFormats break return locale # format the date_str # output_format "display_short", "display", "store", "input" # output_type "date_time", "date", "date_time_secons", "year_month",v "year" @format: (datestr_or_moment, output_format, output_type) -> dt = new CUI.DateTime() str = dt.format(datestr_or_moment, output_format, output_type) # console.debug "DateTime.format", date, type, output_type, DateTime.__locale, str str # limit output to the given types # the library is very awkward here... @formatWithInputTypes: (datestr, output_types, output_format) -> if not datestr return null dt = new CUI.DateTime(input_types: output_types) mom = dt.parseValue(datestr) if not mom.isValid() return null dt.format(mom, output_format) @display: (datestr_or_moment, opts={}) -> if not opts.hasOwnProperty("input_types") opts.input_types = null dt = new CUI.DateTime(opts) mom = dt.parseValue(datestr_or_moment) if not mom.isValid() return null @formatMomentWithBc(mom, dt.getCurrentFormatDisplay()) @formatMoment: (mom, format) -> if mom.bc return "-"+mom.bc return mom.format(format) # BC appendix always adds one year. Therefore year 0 is 1 BC. @formatMomentWithBc: (mom, format) -> if mom.year() == 0 return "1 #{CUI.DateTime.defaults.bc_appendix[0]}" if mom.bc bc = parseInt(mom.bc) + 1 return "#{(bc)} #{CUI.DateTime.defaults.bc_appendix[0]}" if mom.year() > 0 v = mom.format(format) # remove the "+" return v.replace("+"+mom.year(), ""+mom.year()) mom.subtract(1, "year") v = mom.format(format) + " " + CUI.DateTime.defaults.bc_appendix[0] # remove the "-" return v.replace(mom.year(), ""+(-1 * mom.year())) @toMoment: (datestr) -> if CUI.util.isEmpty(datestr) return null dt = new CUI.DateTime(input_types: null) dt.parse(datestr) @stringToDateRange: (string) -> return CUI.DateTimeRangeGrammar.stringToDateRange(string) @dateRangeToString: (from, to) -> return CUI.DateTimeRangeGrammar.dateRangeToString(from, to)