├── .gitignore
├── LICENSE
├── README.md
├── project.clj
├── src
└── reagent
│ ├── cookies.cljs
│ ├── crypt.cljs
│ ├── format.cljs
│ ├── session.cljs
│ └── validation.cljs
└── test
└── reagent
├── cookies_test.cljs
└── runner.cljs
/.gitignore:
--------------------------------------------------------------------------------
1 | pom.xml
2 | pom.xml.asc
3 | *jar
4 | /lib/
5 | /classes/
6 | /target/
7 | /checkouts/
8 | .lein-deps-sum
9 | .lein-repl-history
10 | .lein-plugins/
11 | .lein-failures
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
4 |
5 | 1. DEFINITIONS
6 |
7 | "Contribution" means:
8 |
9 | a) in the case of the initial Contributor, the initial code and
10 | documentation distributed under this Agreement, and
11 |
12 | b) in the case of each subsequent Contributor:
13 |
14 | i) changes to the Program, and
15 |
16 | ii) additions to the Program;
17 |
18 | where such changes and/or additions to the Program originate from and are
19 | distributed by that particular Contributor. A Contribution 'originates' from
20 | a Contributor if it was added to the Program by such Contributor itself or
21 | anyone acting on such Contributor's behalf. Contributions do not include
22 | additions to the Program which: (i) are separate modules of software
23 | distributed in conjunction with the Program under their own license
24 | agreement, and (ii) are not derivative works of the Program.
25 |
26 | "Contributor" means any person or entity that distributes the Program.
27 |
28 | "Licensed Patents" mean patent claims licensable by a Contributor which are
29 | necessarily infringed by the use or sale of its Contribution alone or when
30 | combined with the Program.
31 |
32 | "Program" means the Contributions distributed in accordance with this
33 | Agreement.
34 |
35 | "Recipient" means anyone who receives the Program under this Agreement,
36 | including all Contributors.
37 |
38 | 2. GRANT OF RIGHTS
39 |
40 | a) Subject to the terms of this Agreement, each Contributor hereby grants
41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to
42 | reproduce, prepare derivative works of, publicly display, publicly perform,
43 | distribute and sublicense the Contribution of such Contributor, if any, and
44 | such derivative works, in source code and object code form.
45 |
46 | b) Subject to the terms of this Agreement, each Contributor hereby grants
47 | Recipient a non-exclusive, worldwide, royalty-free patent license under
48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise
49 | transfer the Contribution of such Contributor, if any, in source code and
50 | object code form. This patent license shall apply to the combination of the
51 | Contribution and the Program if, at the time the Contribution is added by the
52 | Contributor, such addition of the Contribution causes such combination to be
53 | covered by the Licensed Patents. The patent license shall not apply to any
54 | other combinations which include the Contribution. No hardware per se is
55 | licensed hereunder.
56 |
57 | c) Recipient understands that although each Contributor grants the licenses
58 | to its Contributions set forth herein, no assurances are provided by any
59 | Contributor that the Program does not infringe the patent or other
60 | intellectual property rights of any other entity. Each Contributor disclaims
61 | any liability to Recipient for claims brought by any other entity based on
62 | infringement of intellectual property rights or otherwise. As a condition to
63 | exercising the rights and licenses granted hereunder, each Recipient hereby
64 | assumes sole responsibility to secure any other intellectual property rights
65 | needed, if any. For example, if a third party patent license is required to
66 | allow Recipient to distribute the Program, it is Recipient's responsibility
67 | to acquire that license before distributing the Program.
68 |
69 | d) Each Contributor represents that to its knowledge it has sufficient
70 | copyright rights in its Contribution, if any, to grant the copyright license
71 | set forth in this Agreement.
72 |
73 | 3. REQUIREMENTS
74 |
75 | A Contributor may choose to distribute the Program in object code form under
76 | its own license agreement, provided that:
77 |
78 | a) it complies with the terms and conditions of this Agreement; and
79 |
80 | b) its license agreement:
81 |
82 | i) effectively disclaims on behalf of all Contributors all warranties and
83 | conditions, express and implied, including warranties or conditions of title
84 | and non-infringement, and implied warranties or conditions of merchantability
85 | and fitness for a particular purpose;
86 |
87 | ii) effectively excludes on behalf of all Contributors all liability for
88 | damages, including direct, indirect, special, incidental and consequential
89 | damages, such as lost profits;
90 |
91 | iii) states that any provisions which differ from this Agreement are offered
92 | by that Contributor alone and not by any other party; and
93 |
94 | iv) states that source code for the Program is available from such
95 | Contributor, and informs licensees how to obtain it in a reasonable manner on
96 | or through a medium customarily used for software exchange.
97 |
98 | When the Program is made available in source code form:
99 |
100 | a) it must be made available under this Agreement; and
101 |
102 | b) a copy of this Agreement must be included with each copy of the Program.
103 |
104 | Contributors may not remove or alter any copyright notices contained within
105 | the Program.
106 |
107 | Each Contributor must identify itself as the originator of its Contribution,
108 | if any, in a manner that reasonably allows subsequent Recipients to identify
109 | the originator of the Contribution.
110 |
111 | 4. COMMERCIAL DISTRIBUTION
112 |
113 | Commercial distributors of software may accept certain responsibilities with
114 | respect to end users, business partners and the like. While this license is
115 | intended to facilitate the commercial use of the Program, the Contributor who
116 | includes the Program in a commercial product offering should do so in a
117 | manner which does not create potential liability for other Contributors.
118 | Therefore, if a Contributor includes the Program in a commercial product
119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend
120 | and indemnify every other Contributor ("Indemnified Contributor") against any
121 | losses, damages and costs (collectively "Losses") arising from claims,
122 | lawsuits and other legal actions brought by a third party against the
123 | Indemnified Contributor to the extent caused by the acts or omissions of such
124 | Commercial Contributor in connection with its distribution of the Program in
125 | a commercial product offering. The obligations in this section do not apply
126 | to any claims or Losses relating to any actual or alleged intellectual
127 | property infringement. In order to qualify, an Indemnified Contributor must:
128 | a) promptly notify the Commercial Contributor in writing of such claim, and
129 | b) allow the Commercial Contributor tocontrol, and cooperate with the
130 | Commercial Contributor in, the defense and any related settlement
131 | negotiations. The Indemnified Contributor may participate in any such claim
132 | at its own expense.
133 |
134 | For example, a Contributor might include the Program in a commercial product
135 | offering, Product X. That Contributor is then a Commercial Contributor. If
136 | that Commercial Contributor then makes performance claims, or offers
137 | warranties related to Product X, those performance claims and warranties are
138 | such Commercial Contributor's responsibility alone. Under this section, the
139 | Commercial Contributor would have to defend claims against the other
140 | Contributors related to those performance claims and warranties, and if a
141 | court requires any other Contributor to pay any damages as a result, the
142 | Commercial Contributor must pay those damages.
143 |
144 | 5. NO WARRANTY
145 |
146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON
147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR
149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the
151 | appropriateness of using and distributing the Program and assumes all risks
152 | associated with its exercise of rights under this Agreement , including but
153 | not limited to the risks and costs of program errors, compliance with
154 | applicable laws, damage to or loss of data, programs or equipment, and
155 | unavailability or interruption of operations.
156 |
157 | 6. DISCLAIMER OF LIABILITY
158 |
159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
166 | OF SUCH DAMAGES.
167 |
168 | 7. GENERAL
169 |
170 | If any provision of this Agreement is invalid or unenforceable under
171 | applicable law, it shall not affect the validity or enforceability of the
172 | remainder of the terms of this Agreement, and without further action by the
173 | parties hereto, such provision shall be reformed to the minimum extent
174 | necessary to make such provision valid and enforceable.
175 |
176 | If Recipient institutes patent litigation against any entity (including a
177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself
178 | (excluding combinations of the Program with other software or hardware)
179 | infringes such Recipient's patent(s), then such Recipient's rights granted
180 | under Section 2(b) shall terminate as of the date such litigation is filed.
181 |
182 | All Recipient's rights under this Agreement shall terminate if it fails to
183 | comply with any of the material terms or conditions of this Agreement and
184 | does not cure such failure in a reasonable period of time after becoming
185 | aware of such noncompliance. If all Recipient's rights under this Agreement
186 | terminate, Recipient agrees to cease use and distribution of the Program as
187 | soon as reasonably practicable. However, Recipient's obligations under this
188 | Agreement and any licenses granted by Recipient relating to the Program shall
189 | continue and survive.
190 |
191 | Everyone is permitted to copy and distribute copies of this Agreement, but in
192 | order to avoid inconsistency the Agreement is copyrighted and may only be
193 | modified in the following manner. The Agreement Steward reserves the right to
194 | publish new versions (including revisions) of this Agreement from time to
195 | time. No one other than the Agreement Steward has the right to modify this
196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The
197 | Eclipse Foundation may assign the responsibility to serve as the Agreement
198 | Steward to a suitable separate entity. Each new version of the Agreement will
199 | be given a distinguishing version number. The Program (including
200 | Contributions) may always be distributed subject to the version of the
201 | Agreement under which it was received. In addition, after a new version of
202 | the Agreement is published, Contributor may elect to distribute the Program
203 | (including its Contributions) under the new version. Except as expressly
204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
205 | licenses to the intellectual property of any Contributor under this
206 | Agreement, whether expressly, by implication, estoppel or otherwise. All
207 | rights in the Program not expressly granted under this Agreement are
208 | reserved.
209 |
210 | This Agreement is governed by the laws of the State of New York and the
211 | intellectual property laws of the United States of America. No party to this
212 | Agreement will bring a legal action under this Agreement more than one year
213 | after the cause of action arose. Each party waives its rights to a jury trial
214 | in any resulting litigation.
215 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## reagent-utils
2 |
3 |
4 | This library provides a number of convenience helpers for use with Reagent.
5 |
6 | [](https://clojars.org/reagent-utils)
7 |
8 |
reagent.cookies
contains-key?
(contains-key? k)
is the key present in the cookies
10 |
contains-val?
(contains-val? v)
is the value present in the cookies (as string)
11 |
count
(count)
returns the number of cookies
12 |
empty?
(empty?)
true if no cookies are set
13 |
get
(get k & [default])
gets the value at the key (as edn), optional default when value is not found
14 |
get-raw
(get-raw k & [default])
gets the value at the key (as string), optional default when value is not found
15 |
keys
(keys)
returns all the keys for the cookies
16 |
raw-vals
(raw-vals)
returns cookie values (as strings)
17 |
remove!
(remove! k)
(remove! k path domain)
removes a cookie, optionally for a specific path and/or domain
18 |
set!
(set! k content & [{:keys [max-age path domain secure? raw?]} :as opts])
sets a cookie, the max-age for session cookie
19 | following optional parameters may be passed in as a map:
20 | :max-age - defaults to -1
21 | :path - path of the cookie, defaults to the full request path
22 | :domain - domain of the cookie, when null the browser will use the full request host name
23 | :secure? - boolean specifying whether the cookie should only be sent over a secure channel
24 | :raw? - boolean specifying whether content should be stored raw, or as EDN
25 |
vals
(vals)
returns cookie values (as edn)
26 |
27 |
28 | reagent.crypt
bytes->hex
(bytes->hex bytes-in)
convert bytes to hex
29 |
digest
(digest hasher bytes)
hash
(hash s hash-type & [hex?])
hash-bytes
(hash-bytes s hash-type)
string->bytes
(string->bytes s)
30 |
31 | reagent.format
add-slashes
(add-slashes s)
capitalize-words
(capitalize-words s)
encode-uri
(encode-uri uri)
line-numbers
(line-numbers s)
pluralize
(pluralize items & [word ending1 ending2 :as opts])
pluralizes the word based on the number of items
38 | (util/pluralize ["John"] "lad")
39 | (util/pluralize ["John" "James"] "lad")
40 | (util/pluralize ["Alice"] "lad" "y" "ies")
printf
(printf fmt & args)
Prints formatted output, as per format
41 |
43 |
44 | reagent.session
assoc-in!
(assoc-in! ks v)
Associates a value in the session, where ks is a
45 | sequence of keys and v is the new value and returns
46 | a new nested structure. If any levels do not exist,
47 | hash-maps will be created.
clear!
(clear!)
Remove all data from the session and start over cleanly.
48 |
get
(get k & [default])
Get the key's value from the session, returns nil if it doesn't exist.
49 |
get!
(get! k & [default])
Destructive get from the session. This returns the current value of the key
50 | and then removes it from the session.
get-in
(get-in ks & [default])
Gets the value at the path specified by the vector ks from the session,
51 | returns nil if it doesn't exist.
get-in!
(get-in! ks & [default])
Destructive get from the session. This returns the current value of the path
52 | specified by the vector ks and then removes it from the session.
remove!
(remove! k)
Remove a key from the session
53 |
swap!
(swap! f & args)
Replace the current session's value with the result of executing f with
54 | the current value and args.
update!
(update! k f & args)
Updates a value in session where k is a key and f
55 | is the function that takes the old value along with any
56 | supplied args and return the new value. If key is not
57 | present it will be added.
update-in!
(update-in! ks f & args)
Updates a value in the session, where ks is a
58 | sequence of keys and f is a function that will
59 | take the old value along with any supplied args and return
60 | the new value. If any levels do not exist, hash-maps
61 | will be created.
62 |
63 | reagent.validation
Functions for validating input and setting string errors on fields.
64 |
equal-to?
(equal-to? v n)
Returns true if the string represents a number = given.
65 |
greater-than?
(greater-than? v n)
Returns true if the string represents a number > given.
66 |
has-value?
(has-value? v)
Returns true if v is truthy and not an empty string.
67 |
has-values?
(has-values? coll)
Returns true if all members of the collection has-value? This works on maps as well.
68 |
is-email?
(is-email? v)
Returns true if v is an email address
69 |
less-than?
(less-than? v n)
Returns true if the string represents a number < given.
70 |
matches-regex?
(matches-regex? v regex)
Returns true if the string matches the given regular expression
71 |
max-length?
(max-length? v len)
Returns true if v is less than or equal to the given len
72 |
min-length?
(min-length? v len)
Returns true if v is greater than or equal to the given len
73 |
not-nil?
(not-nil? v)
Returns true if v is not nil
74 |
valid-number?
(valid-number? v)
Returns true if the string can be parsed to a Long
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | (defproject reagent-utils "0.3.8"
2 | :description "various utility functions for Reagent based projects"
3 | :url "https://github.com/reagent-project/reagent-utils"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 | :clojurescript? true
7 |
8 | :plugins [[lein-codox "0.9.1"]
9 | [lein-cljsbuild "1.1.7"]]
10 |
11 | :codox {:language :clojurescript
12 | :exclude clojure.string}
13 |
14 | :profiles {:dev {:dependencies [[org.clojure/clojure "1.10.0"]
15 | [org.clojure/clojurescript "1.10.439"]
16 | [reagent "0.8.1"]]
17 | :plugins [[lein-doo "0.1.7"]]}
18 | :gcl-v20210505 [:dev {:dependencies [[org.clojure/clojurescript "1.10.866" :exclusions [com.google.javascript/closure-compiler-unshaded
19 | org.clojure/google-closure-library
20 | org.clojure/google-closure-library-third-party]]
21 | [com.google.javascript/closure-compiler-unshaded "v20210505"]
22 | [org.clojure/google-closure-library "0.0-20201211-3e6c510d"]
23 | [org.clojure/google-closure-library-third-party "0.0-20201211-3e6c510d"]]}]}
24 |
25 | :cljsbuild {:builds
26 | {:test
27 | {:source-paths ["src/reagent" "test/reagent"]
28 | :compiler {:main "reagent.runner"
29 | :output-to "target/cljsbuild/public/js/testable.js"
30 | :source-map true
31 | :optimizations :none
32 | :pretty-print true}}}})
33 |
--------------------------------------------------------------------------------
/src/reagent/cookies.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.cookies
2 | (:refer-clojure :exclude [count get keys vals empty? reset!])
3 | (:require
4 | [cljs.reader :as reader]
5 | [goog.net.Cookies :refer [SetOptions]]))
6 |
7 | (defonce ^:dynamic *cookies* (or goog.net.cookies (.getInstance goog.net.Cookies)))
8 |
9 | ;Pre Google Closure library v20200204
10 | (defonce ^:private legacy-setter?
11 | (delay (= 6 (.-length (.-set *cookies*)))))
12 |
13 | (defn supports-same-site?
14 | "True if the underlying version of `goog.net.Cookies` supports the same-site attribute
15 | when setting cookies
16 | "
17 | []
18 | (not @legacy-setter?))
19 |
20 | (defn set!
21 | "sets a cookie, the max-age for session cookie
22 | following optional parameters may be passed in as a map:
23 | :max-age - defaults to -1
24 | :path - path of the cookie, defaults to the full request path
25 | :domain - domain of the cookie, when null the browser will use the full request host name
26 | :secure? - boolean specifying whether the cookie should only be sent over a secure channel
27 | :raw? - boolean specifying whether content should be stored raw, or as EDN
28 | :same-site - A keyword of either :strict, :lax, or :none (defaults to :none). Only supported when `supports-same-site?` is true
29 | "
30 | [k content & [{:keys [max-age path domain secure? raw? same-site] :as opts}]]
31 | (let [k (name k)
32 | content (if raw?
33 | (str content)
34 | (pr-str content))]
35 | (cond
36 | (clojure.core/empty? (dissoc opts :raw?))
37 | (.set *cookies* k content)
38 |
39 | @legacy-setter?
40 | (.set *cookies* k content (or max-age -1) path domain (boolean secure?))
41 |
42 | :else
43 | (.set *cookies* k content
44 | (doto (SetOptions.)
45 | (set! -maxAge (or max-age -1))
46 | (set! -path path)
47 | (set! -domain domain)
48 | (set! -secure (boolean secure?))
49 | (set! -sameSite (condp = same-site
50 | :strict (.-STRICT goog.net.Cookies.SameSite)
51 | :lax (.-LAX goog.net.Cookies.SameSite)
52 | :none (.-NONE goog.net.Cookies.SameSite)
53 | nil)))))))
54 |
55 | (defn- read-edn-value [v]
56 | (when v
57 | (reader/read-string v)))
58 |
59 | (defn- read-raw-value [v] v)
60 |
61 | (defn- get-value
62 | [k r default]
63 | (or (->> (name k) (.get *cookies*) r) default))
64 |
65 | (defn get
66 | "gets the value at the key (as edn), optional default when value is not found"
67 | [k & [default]]
68 | (get-value k read-edn-value default))
69 |
70 | (defn get-raw
71 | "gets the value at the key (as string), optional default when value is not found"
72 | [k & [default]]
73 | (get-value k read-raw-value default))
74 |
75 | (defn contains-key?
76 | "is the key present in the cookies"
77 | [k]
78 | (.containsKey *cookies* (name k)))
79 |
80 | (defn contains-val?
81 | "is the value present in the cookies (as string)"
82 | [v]
83 | (.containsValue *cookies* v))
84 |
85 | (defn count
86 | "returns the number of cookies"
87 | []
88 | (.getCount *cookies*))
89 |
90 | (defn keys
91 | "returns all the keys for the cookies"
92 | []
93 | (map keyword (.getKeys *cookies*)))
94 |
95 | (defn vals
96 | "returns cookie values (as edn)"
97 | []
98 | (map read-edn-value (.getValues *cookies*)))
99 |
100 | (defn raw-vals
101 | "returns cookie values (as strings)"
102 | []
103 | (map read-raw-value (.getValues *cookies*)))
104 |
105 | (defn empty?
106 | "true if no cookies are set"
107 | []
108 | (.isEmpty *cookies*))
109 |
110 | (defn remove!
111 | "removes a cookie, optionally for a specific path and/or domain"
112 | ([k]
113 | (.remove *cookies* (name k)))
114 | ([k path domain]
115 | (.remove *cookies* (name k) path domain)))
116 |
117 | (defn clear!
118 | "removes all cookies"
119 | []
120 | (.clear *cookies*))
121 |
--------------------------------------------------------------------------------
/src/reagent/crypt.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.crypt
2 | (:refer-clojure :exclude [hash])
3 | (:require
4 | [goog.crypt :as crypt]
5 | [goog.crypt.Md5 :as Md5]
6 | [goog.crypt.Sha1 :as Sha1]
7 | [goog.crypt.Sha2 :as Sha2]
8 | [goog.crypt.Sha256 :as Sha256]
9 | [goog.crypt.Sha384 :as Sha384]
10 | [goog.crypt.Sha512 :as Sha512]))
11 |
12 | (defn string->bytes [s]
13 | (crypt/stringToUtf8ByteArray s))
14 |
15 | (defn bytes->hex
16 | "convert bytes to hex"
17 | [bytes-in]
18 | (crypt/byteArrayToHex bytes-in))
19 |
20 | (defn digest [hasher bytes]
21 | (.update hasher bytes)
22 | (.digest hasher))
23 |
24 | (defn hash-bytes [s hash-type]
25 | (digest
26 | (case hash-type
27 | :md5 (goog.crypt.Md5.)
28 | :sha1 (goog.crypt.Sha1.)
29 | :sha2 (goog.crypt.Sha2.)
30 | :sha256 (goog.crypt.Sha256.)
31 | :sha384 (goog.crypt.Sha384.)
32 | :sha512 (goog.crypt.Sha512.)
33 | (throw (js/Error. (str "'" hash-type "' is not a valid hash algorithm."))))
34 | (string->bytes s)))
35 |
36 | (defn hash [s hash-type & [hex?]]
37 | (let [hashed (hash-bytes s hash-type)]
38 | (if hex? (bytes->hex hashed) hashed)))
39 |
--------------------------------------------------------------------------------
/src/reagent/format.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.format
2 | (:refer-clojure :exclude [hash])
3 | (:require
4 | [clojure.string :as s]
5 | [goog.string :as gstring]
6 | [goog.string.format]
7 | [goog.i18n.DateTimeFormat :as dtf]
8 | [goog.crypt :as crypt]
9 | [goog.crypt.Md5 :as Md5]
10 | [goog.crypt.Sha1 :as Sha1]
11 | [goog.crypt.Sha2 :as Sha2]
12 | [goog.crypt.Sha256 :as Sha256]
13 | [goog.crypt.Sha384 :as Sha384]
14 | [goog.crypt.Sha512 :as Sha512]))
15 |
16 | (defn add-slashes [s]
17 | (->> s
18 | (str)
19 | (mapcat (fn [c]
20 | (if (or (= \" c) (= \' c))
21 | [\\ c]
22 | [c])))
23 | (apply str)))
24 |
25 | (defn center [text w]
26 | (let [c (count text)
27 | l (.ceil js/Math (/ (- w c) 2))
28 | r (.floor js/Math (/ (- w c) 2))]
29 | (str
30 | (apply str (repeat l \space))
31 | text
32 | (apply str (repeat r \space)))))
33 |
34 | (defn format
35 | "Formats a string using goog.string.format.
36 | e.g: (format \"Cost: %.2f\" 10.0234)"
37 | [fmt & args]
38 | (apply gstring/format fmt args))
39 |
40 | (defn printf
41 | "Prints formatted output, as per format"
42 | [fmt & args]
43 | (print (apply format fmt args)))
44 |
45 | (defn currency-format
46 | "formats currency using the current locale
47 | to change locale set goog.i18n.NumberFormatSymbols eg:
48 | (set! goog.i18n.NumberFormatSymbols goog.i18n.NumberFormatSymbols_it_IT)
49 | see here for supported locales
50 | https://github.com/google/closure-library/blob/master/closure/goog/i18n/numberformatsymbols.js
51 | "
52 | [n]
53 | (.format (goog.i18n.NumberFormat. (.-CURRENCY goog.i18n.NumberFormat.Format)) n))
54 |
55 | (defn date-format [date fmt & [tz]]
56 | (let [formatter (goog.i18n.DateTimeFormat. fmt)]
57 | (if tz
58 | (.format formatter date tz)
59 | (.format formatter date))))
60 |
61 | (defn line-numbers [s]
62 | (let [s (str s)]
63 | (->> (s/split s #"\n")
64 | (map-indexed #(str (inc %1) ". " %2))
65 | (s/join "\n"))))
66 |
67 | (defn pluralize
68 | "pluralizes the word based on the number of items
69 | (util/pluralize [\"John\"] \"lad\")
70 | (util/pluralize [\"John\" \"James\"] \"lad\")
71 | (util/pluralize [\"Alice\"] \"lad\" \"y\" \"ies\")"
72 | [items & [word ending1 ending2 :as opts]]
73 | (let [n (count items)
74 | plural (case (count opts)
75 | 1 "s"
76 | 2 ending1
77 | 3 ending2)
78 | singular (case (count opts)
79 | (list 1 2) ""
80 | 3 ending1)]
81 | (str n " " word (if (== 1 n) singular plural))))
82 |
83 | (defn capitalize-words [s]
84 | (->> (s/split (str s) #" ")
85 | (map s/capitalize)
86 | (s/join " ")))
87 |
88 | (defn remove-tags
89 | "removes specified tags, eg:
90 | (remove-tags \"foo bar
\" \"p\")"
91 | [s & tags]
92 | (if-not tags
93 | s
94 | (let [s (str s)
95 | tags (str "(" (s/join "|" tags) ")")
96 | opening (re-pattern (str "(?i)<" tags "(/?>|(\\s+[^>]*>))"))
97 | closing (re-pattern (str "(?i)" tags ">"))]
98 | (-> s
99 | (s/replace opening "")
100 | (s/replace closing "")))))
101 |
102 | (defn encode-uri [uri]
103 | (js/encodeURIComponent uri))
104 |
105 |
--------------------------------------------------------------------------------
/src/reagent/session.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.session
2 | (:refer-clojure :exclude [get get-in reset! swap!])
3 | (:require [reagent.core :as reagent :refer [atom]]))
4 |
5 | (defonce state (atom {}))
6 |
7 | (defn cursor
8 | "Returns a cursor from the state atom."
9 | [ks]
10 | (reagent/cursor state ks))
11 |
12 | (defn get
13 | "Get the key's value from the session, returns nil if it doesn't exist."
14 | [k & [default]]
15 | (let [temp-a @(cursor [k])]
16 | (if-not (nil? temp-a) temp-a default)))
17 |
18 | (defn put! [k v]
19 | (clojure.core/swap! state assoc k v))
20 |
21 | (defn get-in
22 | "Gets the value at the path specified by the vector ks from the session,
23 | returns nil if it doesn't exist."
24 | [ks & [default]]
25 | (let [result @(cursor ks)]
26 | (if-not (nil? result) result default)))
27 |
28 | (defn swap!
29 | "Replace the current session's value with the result of executing f with
30 | the current value and args."
31 | [f & args]
32 | (apply clojure.core/swap! state f args))
33 |
34 | (defn clear!
35 | "Remove all data from the session and start over cleanly."
36 | []
37 | (clojure.core/reset! state {}))
38 |
39 | (defn reset! [m]
40 | (clojure.core/reset! state m))
41 |
42 | (defn remove!
43 | "Remove a key from the session"
44 | [k]
45 | (clojure.core/swap! state dissoc k))
46 |
47 | (defn assoc-in!
48 | "Associates a value in the session, where ks is a
49 | sequence of keys and v is the new value and returns
50 | a new nested structure. If any levels do not exist,
51 | hash-maps will be created."
52 | [ks v]
53 | (clojure.core/swap! state assoc-in ks v))
54 |
55 | (defn get!
56 | "Destructive get from the session. This returns the current value of the key
57 | and then removes it from the session."[k & [default]]
58 | (let [cur (get k default)]
59 | (remove! k)
60 | cur))
61 |
62 | (defn get-in!
63 | "Destructive get from the session. This returns the current value of the path
64 | specified by the vector ks and then removes it from the session."
65 | [ks & [default]]
66 | (let [cur (get-in ks default)]
67 | (assoc-in! ks nil)
68 | cur))
69 |
70 | (defn update!
71 | "Updates a value in session where k is a key and f
72 | is the function that takes the old value along with any
73 | supplied args and return the new value. If key is not
74 | present it will be added."
75 | [k f & args]
76 | (clojure.core/swap!
77 | state
78 | #(apply (partial update % k f) args)))
79 |
80 | (defn update-in!
81 | "Updates a value in the session, where ks is a
82 | sequence of keys and f is a function that will
83 | take the old value along with any supplied args and return
84 | the new value. If any levels do not exist, hash-maps
85 | will be created."
86 | [ks f & args]
87 | (clojure.core/swap!
88 | state
89 | #(apply (partial update-in % ks f) args)))
90 |
--------------------------------------------------------------------------------
/src/reagent/validation.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.validation
2 | "Functions for validating input and setting string errors on fields.")
3 |
4 | ;; validation helpers
5 |
6 | (defn has-value?
7 | "Returns true if v is truthy and not an empty string."
8 | [v]
9 | (and v (not= v "")))
10 |
11 | (defn has-values?
12 | "Returns true if all members of the collection has-value? This works on maps as well."
13 | [coll]
14 | (let [vs (if (map? coll)
15 | (vals coll)
16 | coll)]
17 | (every? has-value? vs)))
18 |
19 | (defn not-nil?
20 | "Returns true if v is not nil"
21 | [v]
22 | (boolean (or v (false? v))))
23 |
24 | (defn min-length?
25 | "Returns true if v is greater than or equal to the given len"
26 | [v len]
27 | (>= (count v) len))
28 |
29 | (defn max-length?
30 | "Returns true if v is less than or equal to the given len"
31 | [v len]
32 | (<= (count v) len))
33 |
34 |
35 | (defn matches-regex?
36 | "Returns true if the string matches the given regular expression"
37 | [v regex]
38 | (boolean (re-matches regex v)))
39 |
40 |
41 | (defn is-email?
42 | "Returns true if v is an email address"
43 | [v]
44 | (if (nil? v)
45 | false
46 | (matches-regex? v #"(?i)[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")))
47 |
48 | (defn valid-number?
49 | "Returns true if the string can be parsed to a Long"
50 | [v]
51 | (try
52 | (js/parseFloat v)
53 | true
54 | (catch :default e
55 | false)))
56 |
57 | (defn greater-than?
58 | "Returns true if the string represents a number > given."
59 | [v n]
60 | (and (valid-number? v)
61 | (> (js/parseFloat v) n)))
62 |
63 | (defn less-than?
64 | "Returns true if the string represents a number < given."
65 | [v n]
66 | (and (valid-number? v)
67 | (< (js/parseFloat v) n)))
68 |
69 | (defn equal-to?
70 | "Returns true if the string represents a number = given."
71 | [v n]
72 | (and (valid-number? v)
73 | (== (js/parseFloat v) n)))
74 |
--------------------------------------------------------------------------------
/test/reagent/cookies_test.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.cookies-test
2 | (:require
3 | [cljs.test :refer-macros [deftest testing is use-fixtures]]
4 | [clojure.string :as str]
5 | [reagent.cookies :as cookies]))
6 |
7 | (defn- stub-cookies [f]
8 | (binding [cookies/*cookies* (new goog.net.Cookies nil)]
9 | (f)))
10 |
11 | (defn- raw-cookie-val []
12 | (-> cookies/*cookies*
13 | (.-document_)
14 | (.-cookie)))
15 |
16 | (use-fixtures :once stub-cookies)
17 |
18 | (deftest reading-cookie-values
19 |
20 | (testing "get provides default if cookie not set"
21 | (is (= (cookies/get :non-existent "default-val") "default-val")))
22 |
23 | (testing "get reads edn from cookie"
24 | (.set cookies/*cookies* "some-cookie" "{:edn 123}")
25 | (is (= (cookies/get :some-cookie) {:edn 123})))
26 |
27 | (testing "get can't read invalid edn from cookie"
28 | (.set cookies/*cookies* "some-cookie" "123abc")
29 | (is (thrown-with-msg? js/Error #"Invalid number: 123abc" (cookies/get :some-cookie))))
30 |
31 | (testing "get raw provides default value if cookie not set"
32 | (is (= (cookies/get-raw :non-existent "default-val") "default-val")))
33 |
34 | (testing "set writes raw string to cookie"
35 | (cookies/set! :some-cookie "123abc" {:raw? true})
36 | (is (= (.get cookies/*cookies* "some-cookie") "123abc")))
37 |
38 | (testing "get reads raw string from cookie"
39 | (.set cookies/*cookies* "some-cookie" "123abc")
40 | (is (= (cookies/get-raw :some-cookie) "123abc")))
41 |
42 | (testing "get reads edn vals from cookie"
43 | (.set cookies/*cookies* "some-cookie" "{:edn 123}")
44 | (is (= (cookies/vals) [{:edn 123}])))
45 |
46 | (testing "get reads raw vals from cookie"
47 | (.set cookies/*cookies* "some-cookie" "123abc")
48 | (is (= (cookies/raw-vals) ["123abc"])))
49 |
50 | (testing "can specify options"
51 |
52 | (testing "path"
53 | (let [path "reagent-utils/cookie/path"]
54 | (cookies/set! :path-cookie "path-cookie" {:path path})
55 | (is (= (cookies/get :path-cookie) "path-cookie"))
56 | (is (str/includes? (raw-cookie-val) (str "path=" path)))))
57 |
58 | (testing "domain"
59 | (let [domain "http://reagent-utils.cookie.local"]
60 | (cookies/set! :domain-cookie "domain-cookie" {:domain domain})
61 | (is (= (cookies/get :domain-cookie) "domain-cookie"))
62 | (is (str/includes? (raw-cookie-val) (str "domain=" domain)))))
63 |
64 | (testing "max-age"
65 | (cookies/set! :max-age-cookie "max-age" {:max-age 200})
66 | (is (= (cookies/get :max-age-cookie) "max-age"))
67 | (is (str/includes? (raw-cookie-val) "\"max-age\";expires")))
68 |
69 | (when (cookies/supports-same-site?)
70 | (testing "same-site"
71 | (doseq [opt [:lax :strict :none]]
72 | (let [v (name opt)]
73 | (cookies/set! :same-site-cookie v {:same-site opt})
74 | (is (= (cookies/get :same-site-cookie) v))
75 | (is (str/includes? (raw-cookie-val) (str "samesite=" v)))))))))
76 |
--------------------------------------------------------------------------------
/test/reagent/runner.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.runner
2 | (:require [doo.runner :refer-macros [doo-tests]]
3 | [reagent.cookies-test]))
4 |
5 | ; run the tests from the command line with
6 | ; lein doo phantom test [auto|once]
7 |
8 | ; add tests by 'requiring them and adding them to the list below
9 |
10 | (enable-console-print!)
11 |
12 | (doo-tests
13 | 'reagent.cookies-test)
14 |
15 | ; see https://github.com/bensu/doo for more information
16 |
--------------------------------------------------------------------------------