Skip to content

Commit

Permalink
datepicker: loosen model validation in datepicker to DateTimeProtocol
Browse files Browse the repository at this point in the history
Rename re-com.validate/goog-date? to date-like? and test arg via
cljs-time.core/date? which ensures it satisfies DateTimeProtocol instead
of concrete type checks. This allows consumers to provide their own
date like objects which may not subclass goog.date.Date for :model,
 :minimum & :maximum args.
  • Loading branch information
hipitihop authored and Gregg8 committed Dec 19, 2018
1 parent b3d31ba commit 45f6d7e
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 22 deletions.
18 changes: 9 additions & 9 deletions src/re_com/datepicker.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
(:require
[reagent.core :as reagent]
[cljs-time.core :refer [now today minus plus months days year month day day-of-week first-day-of-the-month before? after?]]
[re-com.validate :refer [goog-date? css-style? html-attr?] :refer-macros [validate-args-macro]]
[re-com.validate :refer [date-like? css-style? html-attr?] :refer-macros [validate-args-macro]]
[cljs-time.predicates :refer [sunday?]]
[cljs-time.format :refer [parse unparse formatters formatter]]
[re-com.box :refer [border h-box flex-child-style]]
Expand Down Expand Up @@ -34,9 +34,9 @@

(defn previous
"If date fails pred, subtract period until true, otherwise answer date"
;; date - a goog.date.UtcDateTime OR goog.date.Date, depending on type of date.
;; If omitted, use now->utc, which returns a goog.date.UtcDateTime version of now with time removed
;; pred - can be one of cljs-time.predicate e.g. sunday? but anything that can deal with goog.date.UtcDateTime/Date
;; date - a date object that satisfies cljs-time.core/DateTimeProtocol.
;; If omitted, use now->utc, which returns a goog.date.UtcDateTime version of now with time removed.
;; pred - can be one of cljs-time.predicate e.g. sunday? but any valid pred is supported.
;; period - a period which will be subtracted see cljs-time.core periods
;; Note: If period and pred do not represent same granularity, some steps may be skipped
; e.g Pass a Wed date, specify sunday? as pred and a period (days 2) will skip one Sunday.
Expand Down Expand Up @@ -203,14 +203,14 @@


(def datepicker-args-desc
[{:name :model :required false :type "goog.date.UtcDateTime/Date | atom" :validate-fn goog-date? :description [:span "the selected date. If provided, should pass pred " [:code ":selectable-fn"] ". If not provided, (now->utc) will be used and the returned date will be a " [:code "goog.date.UtcDateTime"]]}
{:name :on-change :required true :type "goog.date.UtcDateTime/Date -> nil" :validate-fn fn? :description [:span "called when a new selection is made. Returned type is the same as model (unless model is nil, in which case it will be " [:code "goog.date.UtcDateTime"] ")"]}
[{:name :model :required false :type "satisfies DateTimeProtocol | atom" :validate-fn date-like? :description [:span "the selected date. If provided, should pass pred " [:code ":selectable-fn"] ". If not provided, (now->utc) will be used and the returned date will be a " [:code "goog.date.UtcDateTime"]]}
{:name :on-change :required true :type "satisfies DateTimeProtocol -> nil" :validate-fn fn? :description [:span "called when a new selection is made. Returned type is the same as model (unless model is nil, in which case it will be " [:code "goog.date.UtcDateTime"] ")"]}
{:name :disabled? :required false :default false :type "boolean | atom" :description "when true, the user can't select dates but can navigate"}
{:name :selectable-fn :required false :default "(fn [date] true)" :type "pred" :validate-fn fn? :description "Predicate is passed a date. If it answers false, day will be shown disabled and can't be selected."}
{:name :show-weeks? :required false :default false :type "boolean" :description "when true, week numbers are shown to the left"}
{:name :show-today? :required false :default false :type "boolean" :description "when true, today's date is highlighted"}
{:name :minimum :required false :type "goog.date.UtcDateTime/Date | atom" :validate-fn goog-date? :description "no selection or navigation before this date"}
{:name :maximum :required false :type "goog.date.UtcDateTime/Date | atom" :validate-fn goog-date? :description "no selection or navigation after this date"}
{:name :minimum :required false :type "satisfies DateTimeProtocol | atom" :validate-fn date-like? :description "no selection or navigation before this date"}
{:name :maximum :required false :type "satisfies DateTimeProtocol | atom" :validate-fn date-like? :description "no selection or navigation after this date"}
{:name :start-of-week :required false :default 6 :type "int" :description "first day of week (Monday = 0 ... Sunday = 6)"}
{:name :hide-border? :required false :default false :type "boolean" :description "when true, the border is not displayed"}
{:name :class :required false :type "string" :validate-fn string? :description "CSS class names, space separated (applies to the outer border div, not the wrapping div)"}
Expand Down Expand Up @@ -262,7 +262,7 @@
:min-width "10em"
:max-width "10em"
:children [[:label {:class "form-control dropdown-button"}
(if (goog-date? (deref-or-value model))
(if (date-like? (deref-or-value model))
(unparse (if (seq format) (formatter format) date-format) (deref-or-value model))
[:span {:style {:color "#bbb"}} placeholder])]
[:span.dropdown-button.activator.input-group-addon
Expand Down
13 changes: 6 additions & 7 deletions src/re_com/validate.cljs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
(ns re-com.validate
(:require
[cljs-time.core :as time.core]
[clojure.set :refer [superset?]]
[re-com.util :refer [deref-or-value-peek]]
[reagent.core :as reagent]
[reagent.impl.template :refer [valid-tag?]]
[goog.string :as gstring]
[goog.date.UtcDateTime]
[goog.date.Date]))
[goog.string :as gstring]))


;; -- Helpers -----------------------------------------------------------------
Expand Down Expand Up @@ -344,11 +343,11 @@
{:status (if (or contains-class? contains-style?) :error :warning)
:message result}))))))

(defn goog-date?
"Returns true if the passed argument is a valid goog.date.UtcDateTime or goog.date.Date, otherwise false/error"
(defn date-like?
"Returns true if arg satisfies cljs-time.core/DateTimeProtocol typically goog.date.UtcDateTime or goog.date.Date,
otherwise false/error."
[arg]
(let [arg (deref-or-value-peek arg)]
(or (= js/goog.date.UtcDateTime (type arg)) (= js/goog.date.Date (type arg)))))
(-> arg deref-or-value-peek time.core/date?))

(defn regex?
"Returns true if the passed argument is a valid regular expression, otherwise false/error"
Expand Down
12 changes: 6 additions & 6 deletions src/re_demo/datepicker.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[cljs-time.format :refer [formatter unparse]]
[re-com.core :refer [h-box v-box box gap single-dropdown datepicker datepicker-dropdown checkbox label title p button md-icon-button]]
[re-com.datepicker :refer [iso8601->date datepicker-dropdown-args-desc]]
[re-com.validate :refer [goog-date?]]
[re-com.validate :refer [date-like?]]
[re-com.util :refer [now->utc]]
[re-demo.utils :refer [panel-title title2 args-table github-hyperlink status-text]]))

Expand Down Expand Up @@ -77,7 +77,7 @@

(defn- date->string
[date]
(if (goog-date? date)
(if (date-like? date)
(unparse (formatter "dd MMM, yyyy") date)
"no date"))

Expand Down Expand Up @@ -123,17 +123,17 @@
[md-icon-button
:md-icon-name "zmdi-arrow-left"
:size :smaller
:disabled? (not (goog-date? @model1))
:on-click #(when (goog-date? @model1)
:disabled? (not (date-like? @model1))
:on-click #(when (date-like? @model1)
(reset! model1 (minus @model1 (days 1))))]
[md-icon-button
:md-icon-name "zmdi-arrow-right"
:size :smaller
:disabled? (if (and (goog-date? @model1) (goog-date? @model2))
:disabled? (if (and (date-like? @model1) (date-like? @model2))
(not (before? (to-local-date @model1)
(to-local-date @model2)))
true)
:on-click #(when (goog-date? @model1)
:on-click #(when (date-like? @model1)
(reset! model1 (plus @model1 (days 1))))]
[button
:label "Reset"
Expand Down

0 comments on commit 45f6d7e

Please sign in to comment.