mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
Compare commits
585 Commits
v1.8.5
...
v1.8.13-tr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1a2a66d21 | ||
|
|
0117e2e8b5 | ||
|
|
2650dc209e | ||
|
|
58d7d8f016 | ||
|
|
1fbb4b25d1 | ||
|
|
b43b92dcfd | ||
|
|
649c25622a | ||
|
|
1f2820f6d4 | ||
|
|
22f018f2bc | ||
|
|
8c5ac4cb23 | ||
|
|
b9ff5674af | ||
|
|
f0968109c6 | ||
|
|
eeb41ccfdd | ||
|
|
587a53d36d | ||
|
|
ec7b7e0391 | ||
|
|
7f982c0c90 | ||
|
|
6c71ef8760 | ||
|
|
936355d54b | ||
|
|
07620c2e62 | ||
|
|
686a8f3af9 | ||
|
|
199bfe531e | ||
|
|
e4627fe0d0 | ||
|
|
ec6a365227 | ||
|
|
c6f6f5bc55 | ||
|
|
5166a3d958 | ||
|
|
9429695e15 | ||
|
|
f396d30747 | ||
|
|
2637574c93 | ||
|
|
d2ba4650e5 | ||
|
|
3adb13e62c | ||
|
|
f69d86ab8f | ||
|
|
7c0feab08f | ||
|
|
ea784d6362 | ||
|
|
6e57f917d2 | ||
|
|
ba97f61c9e | ||
|
|
c5eca68d79 | ||
|
|
92814162dc | ||
|
|
44374e8499 | ||
|
|
2ca04bb84e | ||
|
|
66a85bb99f | ||
|
|
9f6931ba18 | ||
|
|
8fe6800151 | ||
|
|
e86122cb3e | ||
|
|
7641dcc1be | ||
|
|
8648070a05 | ||
|
|
5200937165 | ||
|
|
6215777986 | ||
|
|
0eb4c7f7ba | ||
|
|
782a812596 | ||
|
|
113f6565be | ||
|
|
b1452f097d | ||
|
|
6384b5abb3 | ||
|
|
2c14ed848f | ||
|
|
5dfac10599 | ||
|
|
250062bd2f | ||
|
|
3f2299e52e | ||
|
|
327753b7ca | ||
|
|
ba447b547d | ||
|
|
8ebd49ec0f | ||
|
|
155a2574bb | ||
|
|
b8c2e54194 | ||
|
|
9f243e6d3c | ||
|
|
ece8d8b518 | ||
|
|
0624c49a4f | ||
|
|
71742a80b5 | ||
|
|
f4b1667005 | ||
|
|
e5c9845b10 | ||
|
|
d3fc89f42a | ||
|
|
9c6454b47a | ||
|
|
7d2484c8bf | ||
|
|
9723c8b82b | ||
|
|
8b2b51d511 | ||
|
|
872a150c7d | ||
|
|
3a0c0fd638 | ||
|
|
739d06cf03 | ||
|
|
9fa7a30c7e | ||
|
|
ba0b17e168 | ||
|
|
5caaec8ef3 | ||
|
|
9971c9f923 | ||
|
|
974099747b | ||
|
|
1920ee7e88 | ||
|
|
55b2c19b64 | ||
|
|
60060a7017 | ||
|
|
ef488133e8 | ||
|
|
5c66a2fc9d | ||
|
|
5f8890e963 | ||
|
|
58c463497a | ||
|
|
3bb6d68adf | ||
|
|
705295049e | ||
|
|
a07fd854f6 | ||
|
|
b2bae242d9 | ||
|
|
1a57a0b3ca | ||
|
|
a0595bc45a | ||
|
|
8853340fa1 | ||
|
|
bde3fa4ce6 | ||
|
|
cee24dcca7 | ||
|
|
c1789c4833 | ||
|
|
6fbf902562 | ||
|
|
dc0da6f7b7 | ||
|
|
385847d7da | ||
|
|
9d7f63db42 | ||
|
|
d0c6292e9d | ||
|
|
994023ec10 | ||
|
|
1028b49719 | ||
|
|
b7f99c3185 | ||
|
|
ce85027b79 | ||
|
|
94b6a61665 | ||
|
|
f84acf44f3 | ||
|
|
386d651678 | ||
|
|
23a6e2dd8f | ||
|
|
6c69eebcbf | ||
|
|
d8a158c56d | ||
|
|
dfda30f4cb | ||
|
|
d26970d04c | ||
|
|
63e453e2c7 | ||
|
|
c7ed27286a | ||
|
|
e5340cb53a | ||
|
|
7079952f6b | ||
|
|
f79dcaba15 | ||
|
|
33a1d97d5e | ||
|
|
28ea23965b | ||
|
|
fbdbbb980f | ||
|
|
fc5b339e2a | ||
|
|
4acb3f1962 | ||
|
|
7bb58342fc | ||
|
|
b277ff03ea | ||
|
|
5061d0c4cd | ||
|
|
931a5be162 | ||
|
|
e437cba155 | ||
|
|
ec53d9df7a | ||
|
|
3330e9b219 | ||
|
|
884743ce97 | ||
|
|
b482d1e57c | ||
|
|
78f5002be5 | ||
|
|
a42799dff4 | ||
|
|
1196cd7df4 | ||
|
|
3c1eae1f47 | ||
|
|
ba27d63f9c | ||
|
|
0083733c4c | ||
|
|
a1ffc869f3 | ||
|
|
7a07e8fa16 | ||
|
|
699da16049 | ||
|
|
18c7b03f3d | ||
|
|
8b560e6cee | ||
|
|
7974ac45f2 | ||
|
|
41b5cf10dd | ||
|
|
b6955cb98c | ||
|
|
6c36c269c8 | ||
|
|
b879ea5a96 | ||
|
|
a6ed4a2c6a | ||
|
|
6972822c49 | ||
|
|
db63f30a76 | ||
|
|
848193434b | ||
|
|
570f0344da | ||
|
|
38c25c412f | ||
|
|
3b4ffe1f70 | ||
|
|
4699c654fc | ||
|
|
c1c5d00f45 | ||
|
|
220693f4e3 | ||
|
|
fcce858ea4 | ||
|
|
1f9698f7a2 | ||
|
|
1766da9d60 | ||
|
|
15ee62aaa8 | ||
|
|
6fc4a297a0 | ||
|
|
74d8dc48b4 | ||
|
|
b6f4ce373e | ||
|
|
c9f186f48f | ||
|
|
daab0dfd7a | ||
|
|
22b5dafad2 | ||
|
|
110f74eee8 | ||
|
|
61cb78fc93 | ||
|
|
38d3b446cc | ||
|
|
e47e10d267 | ||
|
|
77c8c85775 | ||
|
|
fab6d70832 | ||
|
|
9586666248 | ||
|
|
f5ab9a3445 | ||
|
|
1ac8c85113 | ||
|
|
56c2350d36 | ||
|
|
6eafed00f5 | ||
|
|
74661c0b77 | ||
|
|
c4fbcb19d0 | ||
|
|
08e391856c | ||
|
|
8c8b40c5a8 | ||
|
|
c3eda435eb | ||
|
|
5eadb33db9 | ||
|
|
f977a05b08 | ||
|
|
217eda8362 | ||
|
|
579f3bf90a | ||
|
|
348ab81c42 | ||
|
|
3df629bc6e | ||
|
|
07b2f0a7c2 | ||
|
|
c0445d46f3 | ||
|
|
6c90b4e6d0 | ||
|
|
e79a23a554 | ||
|
|
314ccc2f27 | ||
|
|
68c8759af1 | ||
|
|
314e9a4f15 | ||
|
|
0029a1b6cf | ||
|
|
bfcde72855 | ||
|
|
3d0ada803f | ||
|
|
840c936a6f | ||
|
|
7ea74ccf4a | ||
|
|
b55036e165 | ||
|
|
47011e11ff | ||
|
|
ae28d7a96b | ||
|
|
0dd8959bf7 | ||
|
|
316b0915e4 | ||
|
|
e21bfd95f4 | ||
|
|
893331c7bb | ||
|
|
b94bcd697f | ||
|
|
b0ff7ca767 | ||
|
|
493a537f2c | ||
|
|
cda43f075b | ||
|
|
5d9f92eaa7 | ||
|
|
c6afa1849c | ||
|
|
eec3a21c89 | ||
|
|
768240a5ba | ||
|
|
5af8668560 | ||
|
|
630b8a2577 | ||
|
|
12a6f652ad | ||
|
|
db4a528ba3 | ||
|
|
479c7ba24b | ||
|
|
1f08729df3 | ||
|
|
811671661e | ||
|
|
936df71d0d | ||
|
|
f3f6714472 | ||
|
|
3bce2eb7b5 | ||
|
|
bf05866f92 | ||
|
|
219ad4a3a7 | ||
|
|
a7d8028d5a | ||
|
|
d49469a3e6 | ||
|
|
4835ef067f | ||
|
|
4112c3cc75 | ||
|
|
0fe4030d71 | ||
|
|
e8d2d4d96f | ||
|
|
88c3f414fb | ||
|
|
c0d6b68233 | ||
|
|
65f62c42b9 | ||
|
|
fe7bd5e2cd | ||
|
|
e1b40142b8 | ||
|
|
963b4617a9 | ||
|
|
95ddfc4e40 | ||
|
|
01746ed470 | ||
|
|
f25e3bc6f7 | ||
|
|
e63f1c2991 | ||
|
|
29e2886b05 | ||
|
|
a97bcf74de | ||
|
|
1e6f4aa73d | ||
|
|
7c7933f8bb | ||
|
|
dc69c6e825 | ||
|
|
41e91765ca | ||
|
|
19569f9316 | ||
|
|
d91c3d1241 | ||
|
|
b302deb7a3 | ||
|
|
2fae467e9a | ||
|
|
6a5e4bb592 | ||
|
|
c72d17dc83 | ||
|
|
78ffdec693 | ||
|
|
49c19a1d6a | ||
|
|
e854eb0426 | ||
|
|
4a9c17cb28 | ||
|
|
0d1547f439 | ||
|
|
fa5ed529cb | ||
|
|
accb3076e9 | ||
|
|
a4e4e1ec68 | ||
|
|
507e12adba | ||
|
|
4809237ecc | ||
|
|
81877fedb6 | ||
|
|
1f2c6f2a85 | ||
|
|
4fe5e60967 | ||
|
|
f4eb9cb790 | ||
|
|
775f9b3ada | ||
|
|
188b33921c | ||
|
|
20c033317f | ||
|
|
e7a5d063ac | ||
|
|
1fda781d7e | ||
|
|
45fc801a08 | ||
|
|
5fa45c0716 | ||
|
|
21337a5b50 | ||
|
|
ec36a843cf | ||
|
|
e99dbaf4d8 | ||
|
|
c83ad2ecc4 | ||
|
|
80d8d18eb2 | ||
|
|
903d1afb53 | ||
|
|
cd55d2e2ff | ||
|
|
05cf8c4351 | ||
|
|
b04d815408 | ||
|
|
7b370a2eb6 | ||
|
|
5808b601b8 | ||
|
|
fdcd3dc3e3 | ||
|
|
c4bd085393 | ||
|
|
0e91d01412 | ||
|
|
fcb9e9fa56 | ||
|
|
3591354cb1 | ||
|
|
b38eab11eb | ||
|
|
c43dea60b7 | ||
|
|
268bea25d0 | ||
|
|
e94ae20b31 | ||
|
|
a94961c0a7 | ||
|
|
0d5fde919b | ||
|
|
429ef4e2ba | ||
|
|
e8999d23e1 | ||
|
|
209c9242d9 | ||
|
|
6defb09d2e | ||
|
|
2774c09d7a | ||
|
|
c62a044598 | ||
|
|
f73fbe7f23 | ||
|
|
5e1e4c1d19 | ||
|
|
cc5a335fb7 | ||
|
|
91fc3f33a0 | ||
|
|
648753b412 | ||
|
|
24fcc3dd34 | ||
|
|
14fb40a996 | ||
|
|
f4511fc74d | ||
|
|
3d0f192490 | ||
|
|
6b7cdf3a37 | ||
|
|
052d6c6b02 | ||
|
|
6e5c878491 | ||
|
|
c0c6cd1a60 | ||
|
|
2ad433590d | ||
|
|
2cb3da56ab | ||
|
|
8582e6d6b4 | ||
|
|
170101cbfe | ||
|
|
8107f49373 | ||
|
|
7ef0964af2 | ||
|
|
18472ea8c3 | ||
|
|
36e0f45a89 | ||
|
|
bea0b2b1e5 | ||
|
|
9a69951136 | ||
|
|
e19bab1aa2 | ||
|
|
8e2a111a0b | ||
|
|
70707969f3 | ||
|
|
2fe25c6219 | ||
|
|
cc1ef5b28b | ||
|
|
3fc2070b2c | ||
|
|
d22f5678be | ||
|
|
0429906eed | ||
|
|
88a09da325 | ||
|
|
963f0d601f | ||
|
|
8570471c00 | ||
|
|
7925af30d6 | ||
|
|
6f59751582 | ||
|
|
2d2792225a | ||
|
|
a079a64cbe | ||
|
|
656be690a3 | ||
|
|
167045f695 | ||
|
|
dbe968afbb | ||
|
|
179b995fa0 | ||
|
|
4791086207 | ||
|
|
be6b09a6e0 | ||
|
|
f235099859 | ||
|
|
ff8ca521ff | ||
|
|
98f7d52493 | ||
|
|
4815405839 | ||
|
|
42a6e35185 | ||
|
|
408a57479e | ||
|
|
beaf54107c | ||
|
|
e45d1d42b4 | ||
|
|
bc442c7819 | ||
|
|
6a361f2d7b | ||
|
|
a62998e5f1 | ||
|
|
ebcb8ff3e7 | ||
|
|
da8c107331 | ||
|
|
5870927518 | ||
|
|
e008a154e5 | ||
|
|
a2d01b5144 | ||
|
|
8afd5c509b | ||
|
|
311f72e4cb | ||
|
|
78563a7d75 | ||
|
|
9284dd9b63 | ||
|
|
92981e4fcd | ||
|
|
9235727d45 | ||
|
|
fc4ead9b05 | ||
|
|
b8622e95b7 | ||
|
|
f8341dccd4 | ||
|
|
b8ed7789f0 | ||
|
|
6d19613ecc | ||
|
|
0d56cbf169 | ||
|
|
67730e82c3 | ||
|
|
940ca7ade1 | ||
|
|
05f9747f15 | ||
|
|
27903ab744 | ||
|
|
931e528e14 | ||
|
|
6bed94a09b | ||
|
|
165b437f31 | ||
|
|
b526307ad1 | ||
|
|
a7bfddfcb5 | ||
|
|
52e4722dcb | ||
|
|
017916b193 | ||
|
|
02e5ba4dfd | ||
|
|
651626eb4f | ||
|
|
20d01c3047 | ||
|
|
a391b6f076 | ||
|
|
ade73f66c8 | ||
|
|
44970a13bb | ||
|
|
d80f080af5 | ||
|
|
6ec7276cfc | ||
|
|
2444d3b547 | ||
|
|
e899633aff | ||
|
|
a9f01c0f0d | ||
|
|
e021afdd8a | ||
|
|
88dea0f2b8 | ||
|
|
5150025641 | ||
|
|
fc400741b4 | ||
|
|
5cb2194f5e | ||
|
|
64f6a794fc | ||
|
|
764c95488c | ||
|
|
6cabba4cd8 | ||
|
|
bd1cd527d3 | ||
|
|
d17f9dc504 | ||
|
|
f62c583130 | ||
|
|
b1e27e0dad | ||
|
|
6ae1272281 | ||
|
|
e0cb6ed60a | ||
|
|
8aeec74fed | ||
|
|
7cd7e7367b | ||
|
|
4f4fe90db4 | ||
|
|
7a7cd3a937 | ||
|
|
bfc01e7c89 | ||
|
|
bc5672b5eb | ||
|
|
d77f775c4c | ||
|
|
7531c8cbc9 | ||
|
|
38fe0afc03 | ||
|
|
252f876827 | ||
|
|
6d9bae8ef9 | ||
|
|
0b2281dfe2 | ||
|
|
72cff0688a | ||
|
|
9793450ed0 | ||
|
|
c8f0502e71 | ||
|
|
b075ed373a | ||
|
|
eef308c4f6 | ||
|
|
70225afa13 | ||
|
|
0a67876815 | ||
|
|
b59e5ad248 | ||
|
|
287e0b5b55 | ||
|
|
c6a1560845 | ||
|
|
45dc1341d3 | ||
|
|
7d7197da58 | ||
|
|
066f42070a | ||
|
|
cad3464f56 | ||
|
|
bbcaef20a8 | ||
|
|
43726a0b23 | ||
|
|
6e6efea328 | ||
|
|
a2a6ce1b3e | ||
|
|
3a69c958ef | ||
|
|
14ee7a06ae | ||
|
|
6cd8289b27 | ||
|
|
d0509b54bf | ||
|
|
ee905cad5f | ||
|
|
01efb63ad3 | ||
|
|
7981feefa1 | ||
|
|
d4fd66461e | ||
|
|
071ba5285d | ||
|
|
6795237a2d | ||
|
|
57363e2da5 | ||
|
|
da9a3ce9f3 | ||
|
|
c4318030d3 | ||
|
|
44a301edb1 | ||
|
|
dabac50128 | ||
|
|
6030e9a294 | ||
|
|
9b656eaf4f | ||
|
|
22080a9a08 | ||
|
|
d93fe3cf2c | ||
|
|
1ea4f4274c | ||
|
|
bd11c6ce14 | ||
|
|
e8848451a5 | ||
|
|
f4f38b4183 | ||
|
|
27283c50b8 | ||
|
|
3e77534dcf | ||
|
|
5e214a32b3 | ||
|
|
7498b7f098 | ||
|
|
268c8dbcdd | ||
|
|
dbbd52cace | ||
|
|
1770a67cd9 | ||
|
|
3678d4d018 | ||
|
|
3de69987e6 | ||
|
|
cbbb047fc1 | ||
|
|
338d3cbc38 | ||
|
|
4c438ff101 | ||
|
|
631b19084a | ||
|
|
63e815c7fc | ||
|
|
b7e9ffc9da | ||
|
|
d8ce0e7d58 | ||
|
|
a115f2a268 | ||
|
|
c0c8b07add | ||
|
|
5913004e14 | ||
|
|
f4034b1065 | ||
|
|
db93b74490 | ||
|
|
d574b8943b | ||
|
|
46fcf7b62e | ||
|
|
3e565ad7cb | ||
|
|
0e01350107 | ||
|
|
7d79fffa33 | ||
|
|
4117b32ebd | ||
|
|
7a68cc7da1 | ||
|
|
20e6b703d9 | ||
|
|
a1535d6c04 | ||
|
|
f33df883a0 | ||
|
|
48acf80c85 | ||
|
|
d8f8c0df16 | ||
|
|
8ce917a422 | ||
|
|
6546d2763b | ||
|
|
d3a3b2da9a | ||
|
|
fdd6400cb8 | ||
|
|
225e436293 | ||
|
|
0e354f8fc1 | ||
|
|
a6a0bdb063 | ||
|
|
6753320336 | ||
|
|
a3b91dabe5 | ||
|
|
257441c9be | ||
|
|
1497d2c3bb | ||
|
|
8f0bc367d0 | ||
|
|
764219b9ed | ||
|
|
7f7ee25e27 | ||
|
|
1765ba0422 | ||
|
|
32d2adc8a2 | ||
|
|
d890770104 | ||
|
|
376c4c3e0e | ||
|
|
a0b740f52d | ||
|
|
0d4c4f20df | ||
|
|
ab707cf312 | ||
|
|
9989b76b7d | ||
|
|
04a714426f | ||
|
|
b66cf14bcb | ||
|
|
b78739f777 | ||
|
|
fb08759bec | ||
|
|
a4755865ca | ||
|
|
5318aaedcf | ||
|
|
3e56571e59 | ||
|
|
e57a25d05f | ||
|
|
b59a1cc232 | ||
|
|
720ca17533 | ||
|
|
d48b00c77c | ||
|
|
77f43e3ca7 | ||
|
|
23b8fbbbc7 | ||
|
|
b0402daf32 | ||
|
|
079788b4eb | ||
|
|
21ed37189a | ||
|
|
80d755da0d | ||
|
|
8d534041b2 | ||
|
|
e91c313f1e | ||
|
|
2f241485a2 | ||
|
|
f14ca87eb5 | ||
|
|
1caf648fe5 | ||
|
|
ac39c93bbf | ||
|
|
63617f80c5 | ||
|
|
a94a30f422 | ||
|
|
63dc48a075 | ||
|
|
bc798504e0 | ||
|
|
fd32152e88 | ||
|
|
1877bea68d | ||
|
|
f7523ad88c | ||
|
|
ae2357d309 | ||
|
|
8afbdcaf79 | ||
|
|
3e590f92ff | ||
|
|
a6cfa061e4 | ||
|
|
d59db1cd97 | ||
|
|
7cfb25ace9 | ||
|
|
51f97f5b28 | ||
|
|
33d940c736 | ||
|
|
08b9b50f33 | ||
|
|
7c3968b64e | ||
|
|
c59cd21698 | ||
|
|
92694c729f | ||
|
|
7b2b285ba7 | ||
|
|
caeb8f08e7 | ||
|
|
499237715e | ||
|
|
7eb2dfba48 | ||
|
|
815cf16822 | ||
|
|
a3722dee80 | ||
|
|
79ea2fd39d | ||
|
|
b349c28b9b | ||
|
|
40ca2ccee4 | ||
|
|
84b4a9bcbe | ||
|
|
1742367b36 | ||
|
|
8a1d34e711 | ||
|
|
fba72498e3 | ||
|
|
c533f6a15e | ||
|
|
23a216004e | ||
|
|
528af8759d | ||
|
|
baeabdd668 | ||
|
|
1de2300099 | ||
|
|
53e8056450 | ||
|
|
5773876cbc |
@@ -1,11 +1,9 @@
|
||||
engines:
|
||||
rubocop:
|
||||
enabled: true
|
||||
exclude_fingerprints:
|
||||
- ac41db8d4ec4cbf508c353d9b65a024f
|
||||
- 8e3b6322aef5be9f38700b3fd0cd347e
|
||||
channel: rubocop-0-48
|
||||
scss-lint:
|
||||
enabled: true
|
||||
enabled: false
|
||||
ratings:
|
||||
paths:
|
||||
- app/**
|
||||
|
||||
28
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
28
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#### What? Why?
|
||||
|
||||
[Explain why is this change needed and the solution you propose. Provide
|
||||
context for others to understand it]
|
||||
|
||||
#### What should we test?
|
||||
|
||||
[List which features should be tested and how]
|
||||
|
||||
#### Release notes
|
||||
|
||||
[In case this should be present in the release notes, please write them or
|
||||
remove this section otherwise]
|
||||
|
||||
#### How is this related to the Spree upgrade?
|
||||
|
||||
[Any known conflicts with the Spree Upgrade? explain them or remove this section
|
||||
otherwise]
|
||||
|
||||
#### Discourse thread
|
||||
|
||||
[Is there a discussion about this in Discourse? add the link if so or remove
|
||||
this section otherwise]
|
||||
|
||||
#### Dependencies
|
||||
|
||||
[Does this PR depend on another one? add the link of so or remove this section
|
||||
otherwise]
|
||||
166
.rubocop.yml
166
.rubocop.yml
@@ -1,4 +1,9 @@
|
||||
inherit_from:
|
||||
- .rubocop_todo.yml
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.1
|
||||
TargetRailsVersion: 3.2
|
||||
Include:
|
||||
- '**/Rakefile'
|
||||
- '**/config.ru'
|
||||
@@ -6,24 +11,169 @@ AllCops:
|
||||
- 'db/**/*'
|
||||
- 'config/**/*'
|
||||
- 'script/**/*'
|
||||
- 'spec/**/*'
|
||||
- 'vendor/**/*'
|
||||
- 'node_modules/**/*'
|
||||
- !ruby/regexp /old_and_unused\.rb$/
|
||||
|
||||
Documentation:
|
||||
# OFN SETTINGS
|
||||
# Cop settings that have been agreed upon by the OFN community
|
||||
|
||||
Rails:
|
||||
Enabled: true
|
||||
|
||||
Style/Documentation:
|
||||
Enabled: false
|
||||
|
||||
Style/EmptyLinesAroundClassBody:
|
||||
Style/StringLiterals:
|
||||
Enabled: false
|
||||
|
||||
Style/BracesAroundHashParameters:
|
||||
Layout/MultilineMethodCallIndentation:
|
||||
Enabled: true
|
||||
EnforcedStyle: indented
|
||||
|
||||
# TEMPORARY/CONTESTED SETTINGS
|
||||
# These are still to be decided upon, but recommended for inclusion by
|
||||
# oeoeaio after scrutinising offenses the codebase
|
||||
|
||||
# Don't think this is a big issue, mostly picking up RPSEC scope definitions
|
||||
# with lamdas and RSpec '.to change{}' blocks
|
||||
Lint/AmbiguousBlockAssociation:
|
||||
Enabled: false
|
||||
|
||||
|
||||
# Heaps of offences (> 100) in specs, mostly in situations where two or more
|
||||
# instances of a model are required, but only one is referenced. Difficult to
|
||||
# fix without making the spec look messy or rewriting it.
|
||||
# Should definitely fix at some point.
|
||||
Lint/UselessAssignment:
|
||||
Exclude:
|
||||
- spec/**/*
|
||||
|
||||
# AFAIK, there is no good alternative to dynamic matchers until we upgrade
|
||||
# to Rails 4 and can use #find_by. If there is a better approach, let's do it.
|
||||
Rails/DynamicFindBy:
|
||||
Enabled: false
|
||||
|
||||
# This should be the programmer's discretion, perhaps we should review all of
|
||||
# the uses of it an make specific exceptions though.
|
||||
Rails/SkipsModelValidations:
|
||||
Enabled: false
|
||||
|
||||
# Relaxed.Ruby.Style SETTINGS
|
||||
# These styles are a starting point for the conversation around conventions
|
||||
# They should be removed or tweaked and moved above as decisions are made
|
||||
# NOTE: Cops which did not fail at the time of writing were removed
|
||||
|
||||
Layout/DotPosition:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#styledotposition
|
||||
|
||||
Layout/SpaceBeforeBlockBraces:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylespacebeforeblockbraces
|
||||
|
||||
Layout/SpaceInsideParens:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylespaceinsideparens
|
||||
|
||||
Style/Alias:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylealias
|
||||
|
||||
Style/BlockDelimiters:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#styleblockdelimiters
|
||||
|
||||
Style/CommentAnnotation:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylecommentannotation
|
||||
|
||||
Style/DoubleNegation:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#styledoublenegation
|
||||
|
||||
Style/FormatString:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#styleformatstring
|
||||
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#styleifunlessmodifier
|
||||
|
||||
Style/Lambda:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylelambda
|
||||
|
||||
Style/MultilineBlockChain:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylemultilineblockchain
|
||||
|
||||
Style/NegatedIf:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylenegatedif
|
||||
|
||||
Style/NegatedWhile:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylenegatedwhile
|
||||
|
||||
Style/ParallelAssignment:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#styleparallelassignment
|
||||
|
||||
Style/PercentLiteralDelimiters:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylepercentliteraldelimiters
|
||||
|
||||
Style/Semicolon:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylesemicolon
|
||||
|
||||
Style/SingleLineMethods:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylesinglelinemethods
|
||||
|
||||
Style/TrailingCommaInArguments:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#styletrailingcommainarguments
|
||||
|
||||
Style/TrailingCommaInLiteral:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#styletrailingcommainliteral
|
||||
|
||||
Style/WordArray:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#stylewordarray
|
||||
|
||||
Lint/AmbiguousRegexpLiteral:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#lintambiguousregexpliteral
|
||||
|
||||
Lint/AssignmentInCondition:
|
||||
Enabled: false
|
||||
StyleGuide: http://relaxed.ruby.style/#lintassignmentincondition
|
||||
|
||||
Metrics/AbcSize:
|
||||
Enabled: false
|
||||
|
||||
Metrics/BlockNesting:
|
||||
Enabled: false
|
||||
|
||||
Metrics/ClassLength:
|
||||
Enabled: false
|
||||
|
||||
Metrics/ModuleLength:
|
||||
Enabled: false
|
||||
|
||||
Metrics/CyclomaticComplexity:
|
||||
Enabled: false
|
||||
|
||||
Metrics/LineLength:
|
||||
Enabled: false
|
||||
Max: 120
|
||||
|
||||
MethodLength:
|
||||
Metrics/MethodLength:
|
||||
Enabled: false
|
||||
|
||||
StringLiterals:
|
||||
Metrics/ParameterLists:
|
||||
Enabled: false
|
||||
|
||||
Metrics/PerceivedComplexity:
|
||||
Enabled: false
|
||||
|
||||
2202
.rubocop_todo.yml
Normal file
2202
.rubocop_todo.yml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,9 @@ env:
|
||||
- CI_NODE_INDEX=3
|
||||
- CI_NODE_INDEX=4 KARMA="true" GITHUB_DEPLOY="true"
|
||||
|
||||
before_install:
|
||||
- ./script/upgrade_bundler.sh
|
||||
|
||||
before_script:
|
||||
- cp config/database.travis.yml config/database.yml
|
||||
- cp config/application.yml.example config/application.yml
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
See this here post on raising a github issue:
|
||||
https://community.openfoodnetwork.org/t/how-to-raise-a-github-issue/912
|
||||
|
||||
# Contributing
|
||||
|
||||
We love pull requests from everyone. Here are some instructions for
|
||||
|
||||
16
Gemfile
16
Gemfile
@@ -4,12 +4,13 @@ ruby "2.1.5"
|
||||
gem 'rails', '3.2.21'
|
||||
gem 'rails-i18n', '~> 3.0.0'
|
||||
gem 'i18n', '~> 0.6.11'
|
||||
gem 'i18n-js', '~> 3.0.0'
|
||||
|
||||
# Patched version. See http://rubysec.com/advisories/CVE-2015-5312/.
|
||||
gem 'nokogiri', '>= 1.6.7.1'
|
||||
|
||||
gem 'pg'
|
||||
gem 'spree', github: 'openfoodfoundation/spree', branch: '1-3-stable'
|
||||
gem 'spree', github: 'openfoodfoundation/spree', branch: 'spree-upgrade-step1c'
|
||||
gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable'
|
||||
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: '1-3-stable'
|
||||
|
||||
@@ -50,7 +51,7 @@ gem 'gmaps4rails'
|
||||
gem 'spinjs-rails'
|
||||
gem 'rack-ssl', :require => 'rack/ssl'
|
||||
gem 'custom_error_message', :github => 'jeremydurham/custom-err-msg'
|
||||
gem 'angularjs-file-upload-rails', '~> 1.1.0'
|
||||
gem 'angularjs-file-upload-rails', '~> 1.1.6'
|
||||
gem 'roadie-rails', '~> 1.0.3'
|
||||
gem 'figaro'
|
||||
gem 'blockenspiel'
|
||||
@@ -63,6 +64,7 @@ gem 'wkhtmltopdf-binary'
|
||||
|
||||
gem 'foreigner'
|
||||
gem 'immigrant'
|
||||
gem 'roo', '~> 2.7.0'
|
||||
|
||||
gem 'whenever', require: false
|
||||
|
||||
@@ -87,8 +89,10 @@ gem "foundation-rails"
|
||||
gem 'foundation_rails_helper', github: 'willrjmarshall/foundation_rails_helper', branch: "rails3"
|
||||
|
||||
gem 'jquery-rails'
|
||||
gem 'jquery-migrate-rails'
|
||||
gem 'css_splitter'
|
||||
|
||||
gem 'ofn-qz', github: 'openfoodfoundation/ofn-qz'
|
||||
|
||||
group :test, :development do
|
||||
# Pretty printed test output
|
||||
@@ -112,7 +116,6 @@ end
|
||||
|
||||
group :test do
|
||||
gem 'webmock'
|
||||
|
||||
# See spec/spec_helper.rb for instructions
|
||||
#gem 'perftools.rb'
|
||||
end
|
||||
@@ -124,7 +127,12 @@ group :development do
|
||||
gem 'guard-livereload'
|
||||
gem 'rack-livereload'
|
||||
gem 'guard-rails'
|
||||
gem 'guard-zeus'
|
||||
gem 'guard-rspec'
|
||||
gem 'parallel_tests'
|
||||
gem 'rubocop', '>= 0.49.1'
|
||||
|
||||
# 1.0.9 fixed openssl issues on macOS https://github.com/eventmachine/eventmachine/issues/602
|
||||
# While we don't require this gem directly, no dependents forced the upgrade to a version
|
||||
# greater than 1.0.9, so we just required the latest available version here.
|
||||
gem 'eventmachine', '>= 1.2.3'
|
||||
end
|
||||
|
||||
157
Gemfile.lock
157
Gemfile.lock
@@ -22,46 +22,56 @@ GIT
|
||||
spree_core (~> 1.3.4)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/openfoodfoundation/spree.git
|
||||
revision: 6e3edfe40a5de8eba0095b2c5f3db9ea54c3afda
|
||||
branch: 1-3-stable
|
||||
remote: git://github.com/openfoodfoundation/ofn-qz.git
|
||||
revision: 024680ccea429b2e5428d7b964fa67c52add34ec
|
||||
specs:
|
||||
spree (1.3.6.beta)
|
||||
spree_api (= 1.3.6.beta)
|
||||
spree_cmd (= 1.3.6.beta)
|
||||
spree_core (= 1.3.6.beta)
|
||||
spree_promo (= 1.3.6.beta)
|
||||
spree_sample (= 1.3.6.beta)
|
||||
spree_api (1.3.6.beta)
|
||||
spree_core (= 1.3.6.beta)
|
||||
ofn-qz (0.1.0)
|
||||
railties (~> 3.1)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/openfoodfoundation/spree.git
|
||||
revision: a4c439570b77afa50f9e36299811f293232bd281
|
||||
branch: spree-upgrade-step1c
|
||||
specs:
|
||||
spree (1.3.99)
|
||||
spree_api (= 1.3.99)
|
||||
spree_cmd (= 1.3.99)
|
||||
spree_core (= 1.3.99)
|
||||
spree_dash (= 1.3.99)
|
||||
spree_promo (= 1.3.99)
|
||||
spree_sample (= 1.3.99)
|
||||
spree_api (1.3.99)
|
||||
spree_core (= 1.3.99)
|
||||
versioncake (= 0.4.0)
|
||||
spree_cmd (1.3.6.beta)
|
||||
spree_cmd (1.3.99)
|
||||
thor (>= 0.14.6)
|
||||
spree_core (1.3.6.beta)
|
||||
activemerchant (~> 1.34)
|
||||
spree_core (1.3.99)
|
||||
activemerchant (~> 1.50.0)
|
||||
acts_as_list (= 0.1.4)
|
||||
awesome_nested_set (= 2.1.5)
|
||||
aws-sdk (~> 1.11.1)
|
||||
cancan (= 1.6.8)
|
||||
deface (>= 0.9.0)
|
||||
ffaker (~> 1.15.0)
|
||||
highline (= 1.6.18)
|
||||
jquery-rails (~> 2.2.0)
|
||||
highline (= 1.6.11)
|
||||
jquery-rails (~> 2.0)
|
||||
json (>= 1.5.5)
|
||||
kaminari (= 0.14.1)
|
||||
money (= 5.1.1)
|
||||
kaminari (= 0.13.0)
|
||||
money (= 5.0.0)
|
||||
paperclip (~> 3.0)
|
||||
rabl (= 0.7.2)
|
||||
rails (~> 3.2.16)
|
||||
rails (~> 3.2.13)
|
||||
ransack (= 0.7.2)
|
||||
select2-rails (= 3.5.9.3)
|
||||
state_machine (= 1.1.2)
|
||||
select2-rails (~> 3.2)
|
||||
state_machine (= 1.2.0)
|
||||
stringex (~> 1.3.2)
|
||||
truncate_html (~> 0.5.5)
|
||||
spree_promo (1.3.6.beta)
|
||||
spree_core (= 1.3.6.beta)
|
||||
spree_sample (1.3.6.beta)
|
||||
spree_core (= 1.3.6.beta)
|
||||
spree_dash (1.3.99)
|
||||
httparty (~> 0.8.1)
|
||||
spree_core (= 1.3.99)
|
||||
spree_promo (1.3.99)
|
||||
spree_core (= 1.3.99)
|
||||
spree_sample (1.3.99)
|
||||
spree_core (= 1.3.99)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/spree/deface.git
|
||||
@@ -123,8 +133,8 @@ GEM
|
||||
sprockets (~> 2.2.1)
|
||||
active_model_serializers (0.8.3)
|
||||
activemodel (>= 3.0)
|
||||
activemerchant (1.57.0)
|
||||
activesupport (>= 3.2.14, < 5.1)
|
||||
activemerchant (1.50.0)
|
||||
activesupport (>= 3.2.14, < 5.0.0)
|
||||
builder (>= 2.1.2, < 4.0.0)
|
||||
i18n (>= 0.6.9)
|
||||
nokogiri (~> 1.4)
|
||||
@@ -151,10 +161,11 @@ GEM
|
||||
railties (>= 3.1)
|
||||
sprockets (~> 2)
|
||||
tilt
|
||||
angularjs-file-upload-rails (1.1.0)
|
||||
angularjs-file-upload-rails (1.1.6)
|
||||
angularjs-rails (1.5.5)
|
||||
ansi (1.4.2)
|
||||
arel (3.0.3)
|
||||
ast (2.3.0)
|
||||
atomic (1.1.99)
|
||||
awesome_nested_set (2.1.5)
|
||||
activerecord (>= 3.0.0)
|
||||
@@ -167,9 +178,7 @@ GEM
|
||||
bcrypt-ruby (3.1.5)
|
||||
bcrypt (>= 3.1.3)
|
||||
blockenspiel (0.4.5)
|
||||
bugsnag (1.5.2)
|
||||
httparty (>= 0.6, < 1.0)
|
||||
multi_json (~> 1.0)
|
||||
bugsnag (4.1.0)
|
||||
builder (3.0.4)
|
||||
byebug (2.7.0)
|
||||
columnize (~> 0.3)
|
||||
@@ -189,7 +198,7 @@ GEM
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cliver (0.3.2)
|
||||
cocaine (0.5.7)
|
||||
cocaine (0.5.8)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
coderay (1.0.9)
|
||||
coffee-rails (3.2.2)
|
||||
@@ -249,7 +258,7 @@ GEM
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.5.3)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.8)
|
||||
eventmachine (1.2.3)
|
||||
excon (0.45.4)
|
||||
execjs (2.6.0)
|
||||
factory_girl (3.3.0)
|
||||
@@ -399,34 +408,35 @@ GEM
|
||||
guard-rspec (4.0.4)
|
||||
guard (>= 2.1.1)
|
||||
rspec (~> 2.14)
|
||||
guard-zeus (0.0.1)
|
||||
guard
|
||||
zeus
|
||||
haml (4.0.4)
|
||||
tilt
|
||||
highline (1.6.18)
|
||||
highline (1.6.11)
|
||||
hike (1.2.3)
|
||||
http_parser.rb (0.5.3)
|
||||
httparty (0.13.1)
|
||||
json (~> 1.8)
|
||||
multi_xml (>= 0.5.2)
|
||||
httparty (0.8.3)
|
||||
multi_json (~> 1.0)
|
||||
multi_xml
|
||||
i18n (0.6.11)
|
||||
i18n-js (3.0.0)
|
||||
i18n (~> 0.6, >= 0.6.6)
|
||||
immigrant (0.1.6)
|
||||
activerecord (>= 3.0)
|
||||
foreigner (>= 1.2.1)
|
||||
inflecto (0.0.2)
|
||||
ipaddress (0.8.0)
|
||||
journey (1.0.4)
|
||||
jquery-rails (2.2.2)
|
||||
jquery-migrate-rails (1.2.1)
|
||||
jquery-rails (2.3.0)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (1.8.3)
|
||||
json_spec (1.1.1)
|
||||
multi_json (~> 1.0)
|
||||
rspec (~> 2.0)
|
||||
kaminari (0.14.1)
|
||||
kaminari (0.13.0)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
railties (>= 3.0.0)
|
||||
kgio (2.9.3)
|
||||
knapsack (1.5.1)
|
||||
rake
|
||||
@@ -449,8 +459,9 @@ GEM
|
||||
mini_portile2 (2.0.0)
|
||||
momentjs-rails (2.5.1)
|
||||
railties (>= 3.1)
|
||||
money (5.1.1)
|
||||
i18n (~> 0.6.0)
|
||||
money (5.0.0)
|
||||
i18n (~> 0.4)
|
||||
json
|
||||
multi_json (1.12.1)
|
||||
multi_xml (0.5.5)
|
||||
newrelic_rpm (3.12.0.288)
|
||||
@@ -466,9 +477,11 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
cocaine (~> 0.5.3)
|
||||
mime-types
|
||||
parallel (1.4.1)
|
||||
parallel_tests (1.3.7)
|
||||
parallel (1.11.2)
|
||||
parallel_tests (2.14.1)
|
||||
parallel
|
||||
parser (2.4.0.0)
|
||||
ast (~> 2.2)
|
||||
paypal-sdk-core (0.2.10)
|
||||
multi_json (~> 1.0)
|
||||
xml-simple
|
||||
@@ -483,6 +496,7 @@ GEM
|
||||
polyamorous (0.5.0)
|
||||
activerecord (~> 3.0)
|
||||
polyglot (0.3.5)
|
||||
powerpack (0.1.1)
|
||||
pry (0.9.12.2)
|
||||
coderay (~> 1.0.5)
|
||||
method_source (~> 0.8)
|
||||
@@ -494,7 +508,7 @@ GEM
|
||||
activesupport (>= 2.3.14)
|
||||
multi_json (~> 1.0)
|
||||
rack (1.4.7)
|
||||
rack-cache (1.2)
|
||||
rack-cache (1.6.1)
|
||||
rack (>= 0.4)
|
||||
rack-livereload (0.3.15)
|
||||
rack
|
||||
@@ -520,8 +534,10 @@ GEM
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rainbow (2.2.2)
|
||||
rake
|
||||
raindrops (0.13.0)
|
||||
rake (10.4.2)
|
||||
rake (11.3.0)
|
||||
ransack (0.7.2)
|
||||
actionpack (~> 3.0)
|
||||
activerecord (~> 3.0)
|
||||
@@ -547,6 +563,9 @@ GEM
|
||||
roadie-rails (1.0.3)
|
||||
rails (>= 3.0, < 4.2)
|
||||
roadie (~> 3.0)
|
||||
roo (2.7.1)
|
||||
nokogiri (~> 1)
|
||||
rubyzip (~> 1.1, < 2.0.0)
|
||||
rspec (2.14.1)
|
||||
rspec-core (~> 2.14.0)
|
||||
rspec-expectations (~> 2.14.0)
|
||||
@@ -564,14 +583,22 @@ GEM
|
||||
rspec-mocks (~> 2.14.0)
|
||||
rspec-retry (0.4.2)
|
||||
rspec-core
|
||||
ruby-progressbar (1.7.1)
|
||||
rubocop (0.49.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.3.3.1, < 3.0)
|
||||
powerpack (~> 0.1)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||
ruby-progressbar (1.8.1)
|
||||
rubyzip (1.2.0)
|
||||
safe_yaml (0.9.5)
|
||||
sass (3.3.14)
|
||||
sass-rails (3.2.6)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
select2-rails (3.5.9.3)
|
||||
select2-rails (3.5.10)
|
||||
thor (~> 0.14)
|
||||
shoulda-matchers (1.1.0)
|
||||
activesupport (>= 3.0.0)
|
||||
@@ -583,14 +610,14 @@ GEM
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
state_machine (1.1.2)
|
||||
state_machine (1.2.0)
|
||||
stringex (1.3.3)
|
||||
therubyracer (0.12.0)
|
||||
libv8 (~> 3.16.14.0)
|
||||
ref
|
||||
thor (0.19.1)
|
||||
tilt (1.4.1)
|
||||
timecop (0.6.2.2)
|
||||
timecop (0.8.1)
|
||||
timers (1.1.0)
|
||||
treetop (1.4.15)
|
||||
polyglot
|
||||
@@ -601,10 +628,11 @@ GEM
|
||||
sprockets (>= 2.0.0)
|
||||
turn (0.8.3)
|
||||
ansi
|
||||
tzinfo (0.3.44)
|
||||
tzinfo (0.3.49)
|
||||
uglifier (2.7.1)
|
||||
execjs (>= 0.3.0)
|
||||
json (>= 1.8.0)
|
||||
unicode-display_width (1.3.0)
|
||||
unicorn (4.9.0)
|
||||
kgio (~> 2.6)
|
||||
rack
|
||||
@@ -628,14 +656,11 @@ GEM
|
||||
whenever (0.9.2)
|
||||
activesupport (>= 2.3.4)
|
||||
chronic (>= 0.6.3)
|
||||
wicked_pdf (0.11.0)
|
||||
rails
|
||||
wkhtmltopdf-binary (0.9.9.3)
|
||||
wicked_pdf (1.1.0)
|
||||
wkhtmltopdf-binary (0.12.3.1)
|
||||
xml-simple (1.1.4)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
zeus (0.15.4)
|
||||
method_source (>= 0.6.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@@ -645,7 +670,7 @@ DEPENDENCIES
|
||||
acts-as-taggable-on (~> 3.4)
|
||||
andand
|
||||
angular-rails-templates (~> 0.2.0)
|
||||
angularjs-file-upload-rails (~> 1.1.0)
|
||||
angularjs-file-upload-rails (~> 1.1.6)
|
||||
angularjs-rails (= 1.5.5)
|
||||
atomic
|
||||
awesome_print
|
||||
@@ -665,6 +690,7 @@ DEPENDENCIES
|
||||
deface!
|
||||
delayed_job_active_record
|
||||
diffy
|
||||
eventmachine (>= 1.2.3)
|
||||
factory_girl_rails
|
||||
figaro
|
||||
foreigner
|
||||
@@ -678,10 +704,11 @@ DEPENDENCIES
|
||||
guard-livereload
|
||||
guard-rails
|
||||
guard-rspec
|
||||
guard-zeus
|
||||
haml
|
||||
i18n (~> 0.6.11)
|
||||
i18n-js (~> 3.0.0)
|
||||
immigrant
|
||||
jquery-migrate-rails
|
||||
jquery-rails
|
||||
json_spec
|
||||
knapsack
|
||||
@@ -689,6 +716,7 @@ DEPENDENCIES
|
||||
momentjs-rails
|
||||
newrelic_rpm
|
||||
nokogiri (>= 1.6.7.1)
|
||||
ofn-qz!
|
||||
oj
|
||||
paper_trail (~> 3.0.8)
|
||||
paperclip
|
||||
@@ -704,8 +732,10 @@ DEPENDENCIES
|
||||
redcarpet
|
||||
representative_view
|
||||
roadie-rails (~> 1.0.3)
|
||||
roo (~> 2.7.0)
|
||||
rspec-rails
|
||||
rspec-retry
|
||||
rubocop (>= 0.49.1)
|
||||
sass (~> 3.3)
|
||||
sass-rails (~> 3.2.3)
|
||||
shoulda-matchers
|
||||
@@ -728,5 +758,8 @@ DEPENDENCIES
|
||||
wicked_pdf
|
||||
wkhtmltopdf-binary
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.1.5p273
|
||||
|
||||
BUNDLED WITH
|
||||
1.12.5
|
||||
1.15.2
|
||||
|
||||
@@ -47,4 +47,3 @@ end
|
||||
#watch(%r{^spec/acceptance/(.+)\.feature$})
|
||||
#watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
||||
#end
|
||||
|
||||
|
||||
12
README.md
12
README.md
@@ -54,6 +54,7 @@ First, check your dependencies: Ensure that you have Ruby 2.1.5 installed:
|
||||
Install the project's gem dependencies:
|
||||
|
||||
cd openfoodnetwork
|
||||
./script/upgrade_bundler.sh
|
||||
bundle install
|
||||
|
||||
Configure the site:
|
||||
@@ -98,6 +99,17 @@ The site is configured to use
|
||||
startup time while Rails loads. See the Zeus github page for
|
||||
usage instructions.
|
||||
|
||||
Once [npm dependencies are
|
||||
installed](https://github.com/openfoodfoundation/openfoodnetwork/wiki/Karma), AngularJS tests can be run with:
|
||||
|
||||
./script/karma run
|
||||
|
||||
If you want karma to automatically rerun the tests on file modification, use:
|
||||
|
||||
./script/karma start
|
||||
|
||||
### Multilingual
|
||||
Do not forget to run `rake tmp:cache:clear` after locales are updated to reload I18n js translations.
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
//= require jquery
|
||||
//= require jquery-migrate-min
|
||||
//= require jquery_ujs
|
||||
//= require jquery-ui
|
||||
//= require shared/jquery-ui-timepicker-addon
|
||||
@@ -36,6 +37,7 @@
|
||||
//= require ./order_cycles/order_cycles
|
||||
//= require ./payment_methods/payment_methods
|
||||
//= require ./products/products
|
||||
//= require ./resources/resources
|
||||
//= require ./shipping_methods/shipping_methods
|
||||
//= require ./side_menu/side_menu
|
||||
//= require ./tag_rules/tag_rules
|
||||
@@ -46,7 +48,7 @@
|
||||
//= require textAngular-rangy.min.js
|
||||
//= require textAngular-sanitize.min.js
|
||||
//= require textAngular.min.js
|
||||
//= require darkswarm/i18n.js
|
||||
//= require i18n/translations
|
||||
//= require darkswarm/i18n.translate.js
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
|
||||
|
||||
$scope.producers = producers
|
||||
$scope.taxons = Taxons.taxons
|
||||
$scope.taxons = Taxons.all
|
||||
$scope.tax_categories = tax_categories
|
||||
$scope.filterProducers = [{id: "0", name: ""}].concat $scope.producers
|
||||
$scope.filterTaxons = [{id: "0", name: ""}].concat $scope.taxons
|
||||
|
||||
@@ -14,8 +14,8 @@ angular.module("admin.businessModelConfiguration").controller "BusinessModelConf
|
||||
$scope.cappedBill()
|
||||
|
||||
$scope.capReached = ->
|
||||
return "No" if !$scope.cap? || Number($scope.cap) == 0
|
||||
if $scope.bill() >= Number($scope.cap) then "Yes" else "No"
|
||||
return t('no') if !$scope.cap? || Number($scope.cap) == 0
|
||||
if $scope.bill() >= Number($scope.cap) then t('yes') else t('no')
|
||||
|
||||
$scope.includedTax = ->
|
||||
return 0 if !$scope.taxRate? || Number($scope.taxRate) == 0
|
||||
|
||||
@@ -3,9 +3,8 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt
|
||||
$scope.availableCountries = availableCountries
|
||||
$scope.RequestMonitor = RequestMonitor
|
||||
$scope.submitAll = pendingChanges.submitAll
|
||||
$scope.add = Customers.add
|
||||
$scope.deleteCustomer = Customers.remove
|
||||
$scope.customerLimit = 20
|
||||
$scope.customers = Customers.all
|
||||
$scope.columns = Columns.columns
|
||||
|
||||
$scope.confirmRefresh = (event) ->
|
||||
@@ -17,10 +16,13 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt
|
||||
Customers.index({enterprise_id: $scope.shop_id}).then (data) ->
|
||||
pendingChanges.removeAll()
|
||||
$scope.customers_form.$setPristine()
|
||||
$scope.customers = data
|
||||
|
||||
$scope.shop_id = shops[0].id if shops.length == 1
|
||||
|
||||
$scope.deleteCustomer = (customer) ->
|
||||
if confirm(t('admin.customers.index.confirm_delete'))
|
||||
Customers.remove(customer)
|
||||
|
||||
$scope.checkForDuplicateCodes = ->
|
||||
delete this.customer.code unless this.customer.code
|
||||
this.duplicate = $scope.isDuplicateCode(this.customer.code)
|
||||
|
||||
@@ -21,7 +21,7 @@ angular.module("admin.customers").directive 'newCustomerDialog', ($compile, $tem
|
||||
if response.data.errors
|
||||
scope.errors.push(error) for error in response.data.errors
|
||||
else
|
||||
scope.errors.push("Sorry! Could not create '#{scope.email}'")
|
||||
scope.errors.push(t('js.customers.could_not_create') + " '#{scope.email}'")
|
||||
return
|
||||
|
||||
# Compile modal template
|
||||
@@ -35,4 +35,4 @@ angular.module("admin.customers").directive 'newCustomerDialog', ($compile, $tem
|
||||
if CurrentShop.shop.id
|
||||
template.dialog('open')
|
||||
else
|
||||
alert('Please select a shop first')
|
||||
alert(t('js.customers.select_shop'))
|
||||
|
||||
@@ -2,7 +2,7 @@ angular.module('admin.enterpriseFees').directive 'spreeDeleteResource', ->
|
||||
(scope, element, attrs) ->
|
||||
if scope.enterprise_fee.id
|
||||
url = '/admin/enterprise_fees/' + scope.enterprise_fee.id
|
||||
html = '<a href="' + url + '" class="delete-resource icon_link icon-trash no-text" data-action="remove" data-confirm="Are you sure?" url="' + url + '"></a>'
|
||||
html = '<a href="' + url + '" class="delete-resource icon_link icon-trash no-text" data-action="remove" data-confirm="' + t('are_you_sure') + '" url="' + url + '"></a>'
|
||||
#var html = '<a href="'+url+'" class="delete-resource" data-confirm="Are you sure?"><img alt="Delete" src="/assets/admin/icons/delete.png" /> Delete</a>';
|
||||
element.append html
|
||||
return
|
||||
|
||||
@@ -11,7 +11,7 @@ angular.module("admin.enterprises")
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.$watch 'enterprise_form.$dirty', (newValue) ->
|
||||
StatusMessage.display 'notice', 'You have unsaved changes' if newValue
|
||||
StatusMessage.display 'notice', t('admin.unsaved_changes') if newValue
|
||||
|
||||
$scope.setFormDirty = ->
|
||||
$scope.$apply ->
|
||||
@@ -24,13 +24,12 @@ angular.module("admin.enterprises")
|
||||
$scope.navClear()
|
||||
enterprise_form.submit()
|
||||
|
||||
|
||||
# Provide a callback for generating warning messages displayed before leaving the page. This is passed in
|
||||
# from a directive "nav-check" in the page - if we pass it here it will be called in the test suite,
|
||||
# and on all new uses of this contoller, and we might not want that .
|
||||
# and on all new uses of this contoller, and we might not want that.
|
||||
enterpriseNavCallback = ->
|
||||
if $scope.Enterprise.$dirty
|
||||
"Your changes to the enterprise are not saved yet."
|
||||
if $scope.enterprise_form.$dirty
|
||||
t('admin.unsaved_confirm_leave')
|
||||
|
||||
# Register the NavigationCheck callback
|
||||
NavigationCheck.register(enterpriseNavCallback)
|
||||
@@ -39,6 +38,8 @@ angular.module("admin.enterprises")
|
||||
if manager.id?
|
||||
for i, user of $scope.Enterprise.users when user.id == manager.id
|
||||
$scope.Enterprise.users.splice i, 1
|
||||
if $scope.enterprise_form?
|
||||
$scope.enterprise_form.$setDirty()
|
||||
|
||||
$scope.addManager = (manager) ->
|
||||
if manager.id? and manager.email?
|
||||
|
||||
@@ -30,27 +30,27 @@ angular.module("admin.enterprises").controller 'enterprisesCtrl', ($scope, $q, E
|
||||
$scope.producerTextFor = (enterprise) ->
|
||||
switch enterprise.is_primary_producer
|
||||
when true
|
||||
"Producer"
|
||||
t('js.enterprises.producer')
|
||||
else
|
||||
"Non-Producer"
|
||||
t('js.enterprises.non_producer')
|
||||
|
||||
$scope.packageTextFor = (enterprise) ->
|
||||
switch enterprise.is_primary_producer
|
||||
when true
|
||||
switch enterprise.sells
|
||||
when "none"
|
||||
"Profile"
|
||||
t('js.profile')
|
||||
when "own"
|
||||
"Shop"
|
||||
t('js.shop')
|
||||
when "any"
|
||||
"Hub"
|
||||
t('js.hub')
|
||||
else
|
||||
"Choose"
|
||||
t('js.choose')
|
||||
else
|
||||
switch enterprise.sells
|
||||
when "none"
|
||||
"Profile"
|
||||
t('js.profile')
|
||||
when "any"
|
||||
"Hub"
|
||||
t('js.hub')
|
||||
else
|
||||
"Choose"
|
||||
t('js.choose')
|
||||
|
||||
@@ -14,7 +14,7 @@ angular.module("admin.enterprises").controller 'indexPanelCtrl', ($scope, Enterp
|
||||
, (response) ->
|
||||
$scope.saving = false
|
||||
if response.status == 422 && response.data.errors?
|
||||
message = 'Please resolve the following errors:\n'
|
||||
message = t('js.resolve_errors') + ':\n'
|
||||
for attr, msg of response.data.errors
|
||||
message += "#{attr} #{msg}\n"
|
||||
alert(message)
|
||||
|
||||
@@ -6,7 +6,6 @@ angular.module("admin.enterprises")
|
||||
|
||||
$scope.menu.setItems [
|
||||
{ name: 'primary_details', label: t('primary_details'), icon_class: "icon-home" }
|
||||
{ name: 'users', label: t('users'), icon_class: "icon-user" }
|
||||
{ name: 'address', label: t('address'), icon_class: "icon-map-marker" }
|
||||
{ name: 'contact', label: t('contact'), icon_class: "icon-phone" }
|
||||
{ name: 'social', label: t('social'), icon_class: "icon-twitter" }
|
||||
@@ -20,11 +19,11 @@ angular.module("admin.enterprises")
|
||||
{ name: 'inventory_settings', label: t('inventory_settings'), icon_class: "icon-list-ol", show: "enterpriseIsShop()" }
|
||||
{ name: 'tag_rules', label: t('tag_rules'), icon_class: "icon-random", show: "enterpriseIsShop()" }
|
||||
{ name: 'shop_preferences', label: t('shop_preferences'), icon_class: "icon-shopping-cart", show: "enterpriseIsShop()" }
|
||||
{ name: 'users', label: t('users'), icon_class: "icon-user" }
|
||||
]
|
||||
|
||||
$scope.select(0)
|
||||
|
||||
|
||||
$scope.showItem = (item) ->
|
||||
if item.show?
|
||||
$parse(item.show)($scope)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
angular.module('admin.enterprises').directive 'enterpriseSwitcher', (NavigationCheck) ->
|
||||
restrict: 'A'
|
||||
require: 'ngModel'
|
||||
link: (scope, element, attr, ngModel) ->
|
||||
initial = element[0].getAttribute('data-initial')
|
||||
|
||||
element.on 'change', ->
|
||||
if not NavigationCheck.confirmLeave()
|
||||
# Reset the current dropdown selection if staying on page
|
||||
ngModel.$setViewValue initial
|
||||
ngModel.$render()
|
||||
element.select2 'val', initial
|
||||
return
|
||||
|
||||
NavigationCheck.clear() # Don't ask twice if leaving
|
||||
window.location = element[0].querySelector('option[selected]').getAttribute('data-url')
|
||||
@@ -19,16 +19,16 @@ angular.module("admin.enterprises").factory 'PermalinkChecker', ($q, $http) ->
|
||||
if data.length > @MAX_PERMALINK_LENGTH || !data.match(/^[\w-]+$/)
|
||||
deferredRequest.resolve
|
||||
permalink: permalink
|
||||
available: "Error"
|
||||
available: t('js.error')
|
||||
else
|
||||
deferredRequest.resolve
|
||||
permalink: data
|
||||
available: "Available"
|
||||
available: t('available')
|
||||
).error (data,status) =>
|
||||
if status == 409
|
||||
deferredRequest.resolve
|
||||
permalink: data
|
||||
available: "Unavailable"
|
||||
available: t('js.unavailable')
|
||||
else
|
||||
# Something went wrong or request was aborted
|
||||
deferredRequest.reject()
|
||||
|
||||
@@ -3,19 +3,42 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout,
|
||||
restrict: 'C'
|
||||
scope:
|
||||
data: "="
|
||||
minSearch: "@?"
|
||||
text: "@?"
|
||||
minSearch: "@"
|
||||
text: "@"
|
||||
blank: "=?"
|
||||
filter: "=?"
|
||||
onSelecting: "=?"
|
||||
multiple: '@'
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
$timeout ->
|
||||
scope.text ||= 'name'
|
||||
scope.filter ||= -> true
|
||||
scope.text ?= 'name'
|
||||
scope.multiple ?= false
|
||||
scope.filter ?= -> true
|
||||
|
||||
if scope.data.$promise
|
||||
scope.data.$promise.then -> init()
|
||||
else
|
||||
init()
|
||||
|
||||
element.on "select2-opening", scope.onSelecting || angular.noop
|
||||
|
||||
attrs.$observe 'disabled', (value) ->
|
||||
element.select2('enable', !value)
|
||||
|
||||
ngModel.$formatters.push (value) ->
|
||||
element.select2('val', value)
|
||||
value
|
||||
|
||||
ngModel.$parsers.push (value) ->
|
||||
return value.split(",") if scope.multiple
|
||||
value
|
||||
|
||||
init = ->
|
||||
scope.data.unshift(scope.blank) if scope.blank? && typeof scope.blank is "object"
|
||||
|
||||
item.name = $sanitize(item.name) for item in scope.data
|
||||
element.select2
|
||||
multiple: scope.multiple
|
||||
minimumResultsForSearch: scope.minSearch || 0
|
||||
data: ->
|
||||
filtered = $filter('filter')(scope.data,scope.filter)
|
||||
@@ -24,12 +47,3 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout,
|
||||
item[scope.text]
|
||||
formatResult: (item) ->
|
||||
item[scope.text]
|
||||
|
||||
element.on "select2-opening", scope.onSelecting || angular.noop
|
||||
|
||||
attrs.$observe 'disabled', (value) ->
|
||||
element.select2('enable', !value)
|
||||
|
||||
ngModel.$formatters.push (value) ->
|
||||
element.select2('val', value)
|
||||
value
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.indexUtils", ['ngResource', 'ngSanitize', 'templates', 'admin.utils']).config ($httpProvider) ->
|
||||
angular.module("admin.indexUtils", ['admin.resources', 'ngSanitize', 'templates', 'admin.utils']).config ($httpProvider) ->
|
||||
@@ -3,7 +3,8 @@ angular.module("admin.indexUtils").factory 'Dereferencer', ->
|
||||
dereference: (array, data)->
|
||||
if array
|
||||
for object, i in array
|
||||
array[i] = data[object.id]
|
||||
match = data[object.id]
|
||||
array[i] = match if match?
|
||||
|
||||
dereferenceAttr: (array, attr, data)->
|
||||
if array
|
||||
|
||||
@@ -21,16 +21,16 @@ angular.module("admin.indexUtils").factory "pendingChanges", ($q, resources, Sta
|
||||
submitAll: (form=null) =>
|
||||
all = []
|
||||
@errors = []
|
||||
StatusMessage.display('progress', "Saving...")
|
||||
StatusMessage.display('progress', t('js.saving'))
|
||||
for id, objectChanges of @pendingChanges
|
||||
for attrName, change of objectChanges
|
||||
all.push @submit(change)
|
||||
$q.all(all).then =>
|
||||
if @errors.length == 0
|
||||
StatusMessage.display('success', "All changes saved successfully")
|
||||
StatusMessage.display('success', t('js.all_changes_saved_successfully'))
|
||||
form.$setPristine() if form?
|
||||
else
|
||||
StatusMessage.display('failure', "Oh no! I was unable to save your changes")
|
||||
StatusMessage.display('failure', t('js.oh_no'))
|
||||
all
|
||||
|
||||
submit: (change) ->
|
||||
|
||||
@@ -10,7 +10,7 @@ angular.module("admin.indexUtils").factory "SpreeApiAuth", ($q, $http, SpreeApiK
|
||||
deferred.resolve()
|
||||
|
||||
.error (response) ->
|
||||
error = response?.error || "You are unauthorised to access this page."
|
||||
error = response?.error || t('js.unauthorized')
|
||||
deferred.reject(error)
|
||||
|
||||
deferred.promise
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, blankOption, VariantUnitManager, RequestMonitor) ->
|
||||
angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, VariantUnitManager, RequestMonitor) ->
|
||||
$scope.initialized = false
|
||||
$scope.RequestMonitor = RequestMonitor
|
||||
$scope.filteredLineItems = []
|
||||
@@ -15,31 +15,31 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
|
||||
LineItems.allSaved() || confirm(t("unsaved_changes_warning"))
|
||||
|
||||
$scope.resetSelectFilters = ->
|
||||
$scope.distributorFilter = blankOption().id
|
||||
$scope.supplierFilter = blankOption().id
|
||||
$scope.orderCycleFilter = blankOption().id
|
||||
$scope.distributorFilter = 0
|
||||
$scope.supplierFilter = 0
|
||||
$scope.orderCycleFilter = 0
|
||||
$scope.quickSearch = ""
|
||||
|
||||
$scope.refreshData = ->
|
||||
unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == "0"
|
||||
$scope.startDate = OrderCycles.orderCyclesByID[$scope.orderCycleFilter].first_order
|
||||
$scope.endDate = OrderCycles.orderCyclesByID[$scope.orderCycleFilter].last_order
|
||||
unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == 0
|
||||
$scope.startDate = OrderCycles.byID[$scope.orderCycleFilter].first_order
|
||||
$scope.endDate = OrderCycles.byID[$scope.orderCycleFilter].last_order
|
||||
|
||||
RequestMonitor.load $scope.orders = Orders.index("q[state_not_eq]": "canceled", "q[completed_at_not_null]": "true", "q[completed_at_gt]": "#{parseDate($scope.startDate)}", "q[completed_at_lt]": "#{parseDate($scope.endDate)}")
|
||||
RequestMonitor.load $scope.lineItems = LineItems.index("q[order][state_not_eq]": "canceled", "q[order][completed_at_not_null]": "true", "q[order][completed_at_gt]": "#{parseDate($scope.startDate)}", "q[order][completed_at_lt]": "#{parseDate($scope.endDate)}")
|
||||
|
||||
unless $scope.initialized
|
||||
RequestMonitor.load $scope.distributors = Enterprises.index(includeBlank: true, action: "for_line_items", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
|
||||
RequestMonitor.load $scope.orderCycles = OrderCycles.index(includeBlank: true, ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{daysFromToday(-90)}")
|
||||
RequestMonitor.load $scope.suppliers = Enterprises.index(includeBlank: true, action: "for_line_items", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
|
||||
RequestMonitor.load $scope.distributors = Enterprises.index(action: "for_line_items", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
|
||||
RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{daysFromToday(-90)}")
|
||||
RequestMonitor.load $scope.suppliers = Enterprises.index(action: "for_line_items", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
|
||||
|
||||
RequestMonitor.load $q.all([$scope.orders.$promise, $scope.distributors.$promise, $scope.orderCycles.$promise]).then ->
|
||||
Dereferencer.dereferenceAttr $scope.orders, "distributor", Enterprises.enterprisesByID
|
||||
Dereferencer.dereferenceAttr $scope.orders, "order_cycle", OrderCycles.orderCyclesByID
|
||||
Dereferencer.dereferenceAttr $scope.orders, "distributor", Enterprises.byID
|
||||
Dereferencer.dereferenceAttr $scope.orders, "order_cycle", OrderCycles.byID
|
||||
|
||||
RequestMonitor.load $q.all([$scope.orders.$promise, $scope.suppliers.$promise, $scope.lineItems.$promise]).then ->
|
||||
Dereferencer.dereferenceAttr $scope.lineItems, "supplier", Enterprises.enterprisesByID
|
||||
Dereferencer.dereferenceAttr $scope.lineItems, "order", Orders.ordersByID
|
||||
Dereferencer.dereferenceAttr $scope.lineItems, "supplier", Enterprises.byID
|
||||
Dereferencer.dereferenceAttr $scope.lineItems, "order", Orders.byID
|
||||
$scope.bulk_order_form.$setPristine()
|
||||
StatusMessage.clear()
|
||||
unless $scope.initialized
|
||||
@@ -51,13 +51,13 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
|
||||
|
||||
$scope.$watch 'bulk_order_form.$dirty', (newVal, oldVal) ->
|
||||
if newVal == true
|
||||
StatusMessage.display 'notice', "You have unsaved changes"
|
||||
StatusMessage.display 'notice', t('js.unsaved_changes')
|
||||
|
||||
$scope.submit = ->
|
||||
if $scope.bulk_order_form.$valid
|
||||
StatusMessage.display 'progress', "Saving..."
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
$q.all(LineItems.saveAll()).then(->
|
||||
StatusMessage.display 'success', "All changes saved"
|
||||
StatusMessage.display 'success', t('js.all_changes_saved')
|
||||
$scope.bulk_order_form.$setPristine()
|
||||
).catch ->
|
||||
StatusMessage.display 'failure', t "unsaved_changes_error"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
angular.module("admin.lineItems").filter "selectFilter", (blankOption, RequestMonitor) ->
|
||||
angular.module("admin.lineItems").filter "selectFilter", (RequestMonitor) ->
|
||||
return (lineItems,selectedSupplier,selectedDistributor,selectedOrderCycle) ->
|
||||
filtered = []
|
||||
unless RequestMonitor.loading
|
||||
filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,"0") || lineItem.supplier.id == selectedSupplier) &&
|
||||
(angular.equals(selectedDistributor,"0") || lineItem.order.distributor.id == selectedDistributor) &&
|
||||
(angular.equals(selectedOrderCycle,"0") || lineItem.order.order_cycle.id == selectedOrderCycle)
|
||||
filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,0) || lineItem.supplier.id == selectedSupplier) &&
|
||||
(angular.equals(selectedDistributor,0) || lineItem.order.distributor.id == selectedDistributor) &&
|
||||
(angular.equals(selectedOrderCycle,0) || lineItem.order.order_cycle.id == selectedOrderCycle)
|
||||
filtered
|
||||
|
||||
@@ -12,7 +12,10 @@ angular.module('admin.orderCycles')
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.$watch 'order_cycle_form.$dirty', (newValue) ->
|
||||
StatusMessage.display 'notice', 'You have unsaved changes' if newValue
|
||||
StatusMessage.display 'notice', t("admin.unsaved_changes") if newValue
|
||||
|
||||
$scope.$watch 'order_cycle_form.$valid', (isValid) ->
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
@@ -81,7 +84,7 @@ angular.module('admin.orderCycles')
|
||||
|
||||
$scope.submit = ($event, destination) ->
|
||||
$event.preventDefault()
|
||||
StatusMessage.display 'progress', "Saving..."
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
OrderCycle.create(destination)
|
||||
|
||||
$scope.cancel = (destination) ->
|
||||
|
||||
@@ -13,7 +13,10 @@ angular.module('admin.orderCycles')
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.$watch 'order_cycle_form.$dirty', (newValue) ->
|
||||
StatusMessage.display 'notice', 'You have unsaved changes' if newValue
|
||||
StatusMessage.display 'notice', t("admin.unsaved_changes") if newValue
|
||||
|
||||
$scope.$watch 'order_cycle_form.$valid', (isValid) ->
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
@@ -68,6 +71,7 @@ angular.module('admin.orderCycles')
|
||||
$scope.removeCoordinatorFee = ($event, index) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.removeCoordinatorFee(index)
|
||||
$scope.order_cycle_form.$dirty = true
|
||||
|
||||
$scope.addExchangeFee = ($event, exchange) ->
|
||||
$event.preventDefault()
|
||||
@@ -76,17 +80,18 @@ angular.module('admin.orderCycles')
|
||||
$scope.removeExchangeFee = ($event, exchange, index) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.removeExchangeFee(exchange, index)
|
||||
$scope.order_cycle_form.$dirty = true
|
||||
|
||||
$scope.removeDistributionOfVariant = (variant_id) ->
|
||||
OrderCycle.removeDistributionOfVariant(variant_id)
|
||||
|
||||
$scope.submit = (destination) ->
|
||||
$event.preventDefault()
|
||||
StatusMessage.display 'progress', "Saving..."
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
|
||||
$scope.submit = ($event, destination) ->
|
||||
$event.preventDefault()
|
||||
StatusMessage.display 'progress', "Saving..."
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
OrderCycle.update(destination, $scope.order_cycle_form)
|
||||
|
||||
$scope.cancel = (destination) ->
|
||||
|
||||
@@ -8,7 +8,10 @@ angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl"
|
||||
$scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id)
|
||||
|
||||
$scope.$watch 'order_cycle_form.$dirty', (newValue) ->
|
||||
StatusMessage.display 'notice', 'You have unsaved changes' if newValue
|
||||
StatusMessage.display 'notice', t("admin.unsaved_changes") if newValue
|
||||
|
||||
$scope.$watch 'order_cycle_form.$valid', (isValid) ->
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.init = (enterprises) ->
|
||||
enterprise = enterprises[Object.keys(enterprises)[0]]
|
||||
@@ -46,7 +49,7 @@ angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl"
|
||||
|
||||
$scope.submit = ($event, destination) ->
|
||||
$event.preventDefault()
|
||||
StatusMessage.display 'progress', "Saving..."
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
OrderCycle.mirrorIncomingToOutgoingProducts()
|
||||
OrderCycle.create(destination)
|
||||
|
||||
|
||||
@@ -10,7 +10,10 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl",
|
||||
$scope.init()
|
||||
|
||||
$scope.$watch 'order_cycle_form.$dirty', (newValue) ->
|
||||
StatusMessage.display 'notice', 'You have unsaved changes' if newValue
|
||||
StatusMessage.display 'notice', t("admin.unsaved_changes") if newValue
|
||||
|
||||
$scope.$watch 'order_cycle_form.$valid', (isValid) ->
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
@@ -39,7 +42,7 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl",
|
||||
|
||||
$scope.submit = ($event, destination) ->
|
||||
$event.preventDefault()
|
||||
StatusMessage.display 'progress', "Saving..."
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
OrderCycle.mirrorIncomingToOutgoingProducts()
|
||||
OrderCycle.update(destination, $scope.order_cycle_form)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module('admin.orderCycles', ['ngResource', 'admin.utils', 'admin.indexUtils', 'ngTagsInput'])
|
||||
angular.module('admin.orderCycles', ['admin.utils', 'admin.indexUtils', 'ngTagsInput'])
|
||||
|
||||
.config ($httpProvider) ->
|
||||
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
|
||||
|
||||
@@ -165,13 +165,13 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, S
|
||||
if destination?
|
||||
$window.location = destination
|
||||
else
|
||||
StatusMessage.display 'success', 'Your order cycle has been updated.'
|
||||
StatusMessage.display 'success', t('js.order_cycles.update_success')
|
||||
else
|
||||
console.log('Failed to update order cycle')
|
||||
|
||||
confirmNoDistributors: ->
|
||||
if @order_cycle.outgoing_exchanges.length == 0
|
||||
confirm 'There are no distributors in this order cycle. This order cycle will not be visible to customers until you add one. Would you like to continue saving this order cycle?'
|
||||
confirm t('js.order_cycles.no_distributors')
|
||||
else
|
||||
true
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
angular.module("admin.orders").directive 'customerSearchOverride', ->
|
||||
restrict: 'C'
|
||||
link: (scope, element, attr) ->
|
||||
formatCustomerResult = (customer) ->
|
||||
customerTemplate
|
||||
customer: customer
|
||||
bill_address: customer.bill_address
|
||||
ship_address: customer.ship_address
|
||||
|
||||
element.select2
|
||||
placeholder: Spree.translations.choose_a_customer
|
||||
ajax:
|
||||
url: '/admin/search/customers.json'
|
||||
datatype: 'json'
|
||||
data: (term, page) ->
|
||||
{
|
||||
q: term
|
||||
distributor_id: $('#distributor_id').val() # modified
|
||||
}
|
||||
results: (data, page) ->
|
||||
{ results: data }
|
||||
dropdownCssClass: 'customer_search'
|
||||
formatResult: formatCustomerResult
|
||||
formatSelection: (customer) ->
|
||||
_.each [
|
||||
'bill_address'
|
||||
'ship_address'
|
||||
], (address) ->
|
||||
data = customer[address]
|
||||
address_parts = [
|
||||
'firstname'
|
||||
'lastname'
|
||||
'company'
|
||||
'address1'
|
||||
'address2'
|
||||
'city'
|
||||
'zipcode'
|
||||
'phone'
|
||||
]
|
||||
attribute_wrapper = '#order_' + address + '_attributes_'
|
||||
if data # modified
|
||||
_.each address_parts, (part) ->
|
||||
$(attribute_wrapper + part).val data[part]
|
||||
return
|
||||
$(attribute_wrapper + 'state_id').select2 'val', data['state_id']
|
||||
$(attribute_wrapper + 'country_id').select2 'val', data['country_id']
|
||||
else
|
||||
_.each address_parts, (part) ->
|
||||
$(attribute_wrapper + part).val ''
|
||||
return
|
||||
$(attribute_wrapper + 'state_id').select2 'val', ''
|
||||
$(attribute_wrapper + 'country_id').select2 'val', ''
|
||||
return
|
||||
$('#order_email').val customer.email
|
||||
$('#user_id').val customer.user_id # modified
|
||||
$('#guest_checkout_true').prop 'checked', false
|
||||
$('#guest_checkout_false').prop 'checked', true
|
||||
$('#guest_checkout_false').prop 'disabled', false
|
||||
customer.email
|
||||
@@ -1,3 +1,3 @@
|
||||
angular.module("admin.paymentMethods").controller "paymentMethodsCtrl", ($scope, PaymentMethods) ->
|
||||
$scope.findPaymentMethodByID = (id) ->
|
||||
$scope.PaymentMethod = PaymentMethods.findByID(id)
|
||||
$scope.PaymentMethod = PaymentMethods.byID[id]
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
angular.module("admin.paymentMethods")
|
||||
.factory "PaymentMethods", (paymentMethods) ->
|
||||
new class PaymentMethods
|
||||
paymentMethods: paymentMethods
|
||||
|
||||
findByID: (id) ->
|
||||
for paymentMethod in @paymentMethods
|
||||
return paymentMethod if paymentMethod.id is id
|
||||
@@ -0,0 +1,5 @@
|
||||
angular.module("ofn.admin").controller "DropdownPanelsCtrl", ($scope) ->
|
||||
$scope.active = false
|
||||
|
||||
$scope.togglePanel = ->
|
||||
$scope.active = !$scope.active
|
||||
@@ -0,0 +1,14 @@
|
||||
angular.module("ofn.admin").controller "ImportOptionsFormCtrl", ($scope, $rootScope, ProductImportService) ->
|
||||
|
||||
$scope.toggleResetAbsent = () ->
|
||||
confirmed = confirm t('js.product_import.confirmation') if $scope.resetAbsent
|
||||
|
||||
if confirmed or !$scope.resetAbsent
|
||||
ProductImportService.updateResetAbsent($scope.supplierId, $scope.resetCount, $scope.resetAbsent)
|
||||
else
|
||||
$scope.resetAbsent = false
|
||||
|
||||
$scope.resetTotal = ProductImportService.resetTotal
|
||||
|
||||
$rootScope.$watch 'resetTotal', (newValue) ->
|
||||
$scope.resetTotal = newValue if newValue || newValue == 0
|
||||
@@ -0,0 +1,15 @@
|
||||
angular.module("ofn.admin").factory "ProductImportService", ($rootScope) ->
|
||||
new class ProductImportService
|
||||
suppliers: {}
|
||||
resetTotal: 0
|
||||
|
||||
updateResetAbsent: (supplierId, resetCount, resetAbsent) ->
|
||||
if resetAbsent
|
||||
@suppliers[supplierId] = resetCount
|
||||
@resetTotal += resetCount
|
||||
else
|
||||
@suppliers[supplierId] = null
|
||||
@resetTotal -= resetCount
|
||||
|
||||
$rootScope.resetTotal = @resetTotal
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
angular.module("admin.products").controller "editUnitsCtrl", ($scope, VariantUnitManager) ->
|
||||
|
||||
$scope.product =
|
||||
variant_unit: angular.element('#variant_unit').val()
|
||||
variant_unit_scale: angular.element('#variant_unit_scale').val()
|
||||
|
||||
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()
|
||||
|
||||
if $scope.product.variant_unit == 'items'
|
||||
$scope.variant_unit_with_scale = 'items'
|
||||
else
|
||||
$scope.variant_unit_with_scale = $scope.product.variant_unit + '_' + $scope.product.variant_unit_scale
|
||||
|
||||
$scope.setFields = ->
|
||||
if $scope.variant_unit_with_scale == 'items'
|
||||
variant_unit = 'items'
|
||||
variant_unit_scale = null
|
||||
else
|
||||
options = $scope.variant_unit_with_scale.split('_')
|
||||
variant_unit = options[0]
|
||||
variant_unit_scale = options[1]
|
||||
|
||||
$scope.product.variant_unit = variant_unit
|
||||
$scope.product.variant_unit_scale = variant_unit_scale
|
||||
@@ -0,0 +1,14 @@
|
||||
angular.module("admin.products").controller "variantUnitsCtrl", ($scope, VariantUnitManager, $timeout) ->
|
||||
|
||||
$scope.unitName = (scale, type) ->
|
||||
VariantUnitManager.getUnitName(scale, type)
|
||||
|
||||
$scope.scale = angular.element('#product_variant_unit_scale').val()
|
||||
|
||||
$scope.updateValue = ->
|
||||
unit_value_human = angular.element('#unit_value_human').val()
|
||||
$scope.unit_value = unit_value_human * $scope.scale
|
||||
|
||||
variant_unit_value = angular.element('#variant_unit_value').val()
|
||||
$scope.unit_value_human = variant_unit_value / $scope.scale
|
||||
$timeout -> $scope.updateValue()
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.products", [])
|
||||
angular.module("admin.products", ["textAngular", "admin.utils"])
|
||||
@@ -0,0 +1 @@
|
||||
angular.module("admin.resources", ['ngResource'])
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.customers").factory 'CustomerResource', ($resource) ->
|
||||
angular.module("admin.resources").factory 'CustomerResource', ($resource) ->
|
||||
$resource('/admin/customers/:id.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.enterprises").factory 'EnterpriseResource', ($resource) ->
|
||||
angular.module("admin.resources").factory 'EnterpriseResource', ($resource) ->
|
||||
ignoredAttrs = ->
|
||||
["$$hashKey", "producer", "package", "producerError", "packageError", "status"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.lineItems").factory 'LineItemResource', ($resource) ->
|
||||
angular.module("admin.resources").factory 'LineItemResource', ($resource) ->
|
||||
$resource('/admin/:orders/:order_number/line_items/:id.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.orderCycles").factory 'OrderCycleResource', ($resource) ->
|
||||
angular.module("admin.resources").factory 'OrderCycleResource', ($resource) ->
|
||||
$resource('/admin/order_cycles/:id/:action.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.orders").factory 'OrderResource', ($resource) ->
|
||||
angular.module("admin.resources").factory 'OrderResource', ($resource) ->
|
||||
$resource('/admin/orders/:id/:action.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
@@ -1,31 +1,43 @@
|
||||
angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestMonitor, CustomerResource, CurrentShop) ->
|
||||
angular.module("admin.resources").factory "Customers", ($q, InfoDialog, RequestMonitor, CustomerResource, CurrentShop) ->
|
||||
new class Customers
|
||||
customers: []
|
||||
all: []
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
add: (email) ->
|
||||
params =
|
||||
enterprise_id: CurrentShop.shop.id
|
||||
email: email
|
||||
CustomerResource.create params, (customer) =>
|
||||
@customers.unshift customer if customer.id
|
||||
if customer.id
|
||||
@all.unshift customer
|
||||
@byID[customer.id] = customer
|
||||
@pristineByID[customer.id] = angular.copy(customer)
|
||||
|
||||
remove: (customer) ->
|
||||
params = id: customer.id
|
||||
CustomerResource.destroy params, =>
|
||||
i = @customers.indexOf customer
|
||||
@customers.splice i, 1 unless i < 0
|
||||
i = @all.indexOf customer
|
||||
@all.splice i, 1 unless i < 0
|
||||
, (response) =>
|
||||
errors = response.data.errors
|
||||
if errors?
|
||||
InfoDialog.open 'error', errors[0]
|
||||
else
|
||||
InfoDialog.open 'error', "Could not delete customer: #{customer.email}"
|
||||
InfoDialog.open 'error', t('js.resources.could_not_delete_customer') + ": #{customer.email}"
|
||||
|
||||
index: (params) ->
|
||||
request = CustomerResource.index(params, (data) => @customers = data)
|
||||
@clear()
|
||||
request = CustomerResource.index(params, (data) => @load(data))
|
||||
RequestMonitor.load(request.$promise)
|
||||
request.$promise
|
||||
|
||||
load: (customers) ->
|
||||
for customer in customers
|
||||
@all.push customer
|
||||
@byID[customer.id] = customer
|
||||
@pristineByID[customer.id] = angular.copy(customer)
|
||||
|
||||
update: (address, customer, addressType) ->
|
||||
params =
|
||||
id: customer.id
|
||||
@@ -33,3 +45,5 @@ angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestM
|
||||
"#{addressType}_attributes": address
|
||||
CustomerResource.update params
|
||||
|
||||
clear: ->
|
||||
@all.length = 0
|
||||
@@ -1,21 +1,18 @@
|
||||
angular.module("admin.enterprises").factory 'Enterprises', ($q, EnterpriseResource, blankOption) ->
|
||||
angular.module("admin.resources").factory 'Enterprises', ($q, EnterpriseResource) ->
|
||||
new class Enterprises
|
||||
enterprisesByID: {}
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
includeBlank = !!params['includeBlank']
|
||||
delete params['includeBlank']
|
||||
EnterpriseResource.index(params, (data) =>
|
||||
for enterprise in data
|
||||
@enterprisesByID[enterprise.id] = enterprise
|
||||
@pristineByID[enterprise.id] = angular.copy(enterprise)
|
||||
|
||||
EnterpriseResource.index params, (data) =>
|
||||
@load(data)
|
||||
(callback || angular.noop)(data)
|
||||
|
||||
data.unshift(blankOption()) if includeBlank
|
||||
data
|
||||
)
|
||||
|
||||
load: (enterprises) ->
|
||||
for enterprise in enterprises
|
||||
@byID[enterprise.id] = enterprise
|
||||
@pristineByID[enterprise.id] = angular.copy(enterprise)
|
||||
|
||||
save: (enterprise) ->
|
||||
deferred = $q.defer()
|
||||
@@ -1,23 +1,25 @@
|
||||
angular.module("admin.lineItems").factory 'LineItems', ($q, LineItemResource) ->
|
||||
angular.module("admin.resources").factory 'LineItems', ($q, LineItemResource) ->
|
||||
new class LineItems
|
||||
lineItemsByID: {}
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
LineItemResource.index params, (data) =>
|
||||
@resetData()
|
||||
for lineItem in data
|
||||
@lineItemsByID[lineItem.id] = lineItem
|
||||
@pristineByID[lineItem.id] = angular.copy(lineItem)
|
||||
|
||||
@load(data)
|
||||
(callback || angular.noop)(data)
|
||||
|
||||
resetData: ->
|
||||
@lineItemsByID = {}
|
||||
@byID = {}
|
||||
@pristineByID = {}
|
||||
|
||||
load: (lineItems) ->
|
||||
@resetData()
|
||||
for lineItem in lineItems
|
||||
@byID[lineItem.id] = lineItem
|
||||
@pristineByID[lineItem.id] = angular.copy(lineItem)
|
||||
|
||||
saveAll: ->
|
||||
for id, lineItem of @lineItemsByID
|
||||
for id, lineItem of @byID
|
||||
lineItem.errors = {} # removes errors when line_item has been returned to original state
|
||||
@save(lineItem) if !@isSaved(lineItem)
|
||||
|
||||
@@ -34,7 +36,7 @@ angular.module("admin.lineItems").factory 'LineItems', ($q, LineItemResource) ->
|
||||
deferred.promise
|
||||
|
||||
allSaved: ->
|
||||
for id, lineItem of @lineItemsByID
|
||||
for id, lineItem of @byID
|
||||
return false unless @isSaved(lineItem)
|
||||
true
|
||||
|
||||
@@ -54,7 +56,7 @@ angular.module("admin.lineItems").factory 'LineItems', ($q, LineItemResource) ->
|
||||
deferred = $q.defer()
|
||||
lineItem.$delete({id: lineItem.id, orders: "orders", order_number: lineItem.order.number})
|
||||
.then( (data) =>
|
||||
delete @lineItemsByID[lineItem.id]
|
||||
delete @byID[lineItem.id]
|
||||
delete @pristineByID[lineItem.id]
|
||||
(callback || angular.noop)(data)
|
||||
deferred.resolve(data)
|
||||
@@ -1,21 +1,24 @@
|
||||
angular.module("admin.orderCycles").factory 'OrderCycles', ($q, OrderCycleResource, blankOption) ->
|
||||
angular.module("admin.resources").factory 'OrderCycles', ($q, $injector, OrderCycleResource) ->
|
||||
new class OrderCycles
|
||||
orderCyclesByID: {}
|
||||
all: []
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
constructor: ->
|
||||
if $injector.has('orderCycles')
|
||||
@load($injector.get('orderCycles'))
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
includeBlank = !!params['includeBlank']
|
||||
delete params['includeBlank']
|
||||
OrderCycleResource.index(params, (data) =>
|
||||
for orderCycle in data
|
||||
@orderCyclesByID[orderCycle.id] = orderCycle
|
||||
@pristineByID[orderCycle.id] = angular.copy(orderCycle)
|
||||
|
||||
OrderCycleResource.index params, (data) =>
|
||||
@load(data)
|
||||
(callback || angular.noop)(data)
|
||||
|
||||
data.unshift(blankOption()) if includeBlank
|
||||
data
|
||||
)
|
||||
|
||||
load: (orderCycles) ->
|
||||
for orderCycle in orderCycles
|
||||
@all.push orderCycle
|
||||
@byID[orderCycle.id] = orderCycle
|
||||
@pristineByID[orderCycle.id] = angular.copy(orderCycle)
|
||||
|
||||
save: (order_cycle) ->
|
||||
deferred = $q.defer()
|
||||
@@ -1,16 +1,18 @@
|
||||
angular.module("admin.orders").factory 'Orders', ($q, OrderResource) ->
|
||||
angular.module("admin.resources").factory 'Orders', ($q, OrderResource) ->
|
||||
new class Orders
|
||||
ordersByID: {}
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
OrderResource.index params, (data) =>
|
||||
for order in data
|
||||
@ordersByID[order.id] = order
|
||||
@pristineByID[order.id] = angular.copy(order)
|
||||
|
||||
@load(data)
|
||||
(callback || angular.noop)(data)
|
||||
|
||||
load: (orders) ->
|
||||
for order in orders
|
||||
@byID[order.id] = order
|
||||
@pristineByID[order.id] = angular.copy(order)
|
||||
|
||||
save: (order) ->
|
||||
deferred = $q.defer()
|
||||
order.$update({id: order.number})
|
||||
@@ -0,0 +1,16 @@
|
||||
angular.module("admin.resources")
|
||||
.factory "PaymentMethods", ($injector) ->
|
||||
new class PaymentMethods
|
||||
paymentMethods: []
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
constructor: ->
|
||||
if $injector.has('paymentMethods')
|
||||
@load($injector.get('paymentMethods'))
|
||||
|
||||
load: (paymentMethods) ->
|
||||
for paymentMethod in paymentMethods
|
||||
@paymentMethods.push paymentMethod
|
||||
@byID[paymentMethod.id] = paymentMethod
|
||||
@pristineByID[paymentMethod.id] = angular.copy(paymentMethod)
|
||||
@@ -0,0 +1,16 @@
|
||||
angular.module("admin.resources")
|
||||
.factory "ShippingMethods", ($injector) ->
|
||||
new class ShippingMethods
|
||||
shippingMethods: []
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
constructor: ->
|
||||
if $injector.has('shippingMethods')
|
||||
@load($injector.get('shippingMethods'))
|
||||
|
||||
load: (shippingMethods) ->
|
||||
for shippingMethod in shippingMethods
|
||||
@shippingMethods.push shippingMethod
|
||||
@byID[shippingMethod.id] = shippingMethod
|
||||
@pristineByID[shippingMethod.id] = angular.copy(shippingMethod)
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("ofn.admin").factory "ofnConfirmHandler", (pendingChanges, $compile, $q) ->
|
||||
return (scope, callback) ->
|
||||
template = "<div id='dialog-div' style='padding: 10px'><h6>Unsaved changes currently exist, save now or ignore?</h6></div>"
|
||||
template = "<div id='dialog-div' style='padding: 10px'><h6>" + t('js.services.unsaved_changes_message') + "</h6></div>"
|
||||
dialogDiv = $compile(template)(scope)
|
||||
return ->
|
||||
if pendingChanges.changeCount(pendingChanges.pendingChanges) > 0
|
||||
|
||||
@@ -26,7 +26,7 @@ angular.module("ofn.admin").factory 'EnterpriseRelationships', ($http, enterpris
|
||||
|
||||
permission_presentation: (permission) ->
|
||||
switch permission
|
||||
when "add_to_order_cycle" then "add to order cycle"
|
||||
when "manage_products" then "manage products"
|
||||
when "edit_profile" then "edit profile"
|
||||
when "create_variant_overrides" then "add products to inventory"
|
||||
when "add_to_order_cycle" then t('js.services.add_to_order_cycle')
|
||||
when "manage_products" then t('js.services.manage_products')
|
||||
when "edit_profile" then t('js.services.edit_profile')
|
||||
when "create_variant_overrides" then t('js.services.add_products_to_inventory')
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
angular.module("admin.shippingMethods").controller "shippingMethodsCtrl", ($scope, ShippingMethods) ->
|
||||
$scope.findShippingMethodByID = (id) ->
|
||||
$scope.ShippingMethod = ShippingMethods.findByID(id)
|
||||
$scope.ShippingMethod = ShippingMethods.byID[id]
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
angular.module("admin.shippingMethods")
|
||||
.factory "ShippingMethods", (shippingMethods) ->
|
||||
new class ShippingMethods
|
||||
shippingMethods: shippingMethods
|
||||
|
||||
findByID: (id) ->
|
||||
for shippingMethod in @shippingMethods
|
||||
return shippingMethod if shippingMethod.id is id
|
||||
@@ -2,7 +2,7 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $fil
|
||||
$scope.tagGroups = enterprise.tag_groups
|
||||
$scope.defaultTagGroup = enterprise.default_tag_group
|
||||
|
||||
$scope.visibilityOptions = [ { id: "visible", name: "VISIBLE" }, { id: "hidden", name: "NOT VISIBLE" } ]
|
||||
$scope.visibilityOptions = [ { id: "visible", name: t('js.tag_rules.visible') }, { id: "hidden", name: t('js.tag_rules.not_visible') } ]
|
||||
|
||||
$scope.updateRuleCounts = ->
|
||||
index = $scope.defaultTagGroup.rules.length
|
||||
@@ -38,7 +38,6 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $fil
|
||||
newRule.peferred_exchange_tags = []
|
||||
newRule.preferred_matched_order_cycles_visibility = "visible"
|
||||
tagGroup.rules.push(newRule)
|
||||
$scope.enterprise_form.$setDirty()
|
||||
$scope.updateRuleCounts()
|
||||
|
||||
$scope.addNewTag = ->
|
||||
@@ -58,3 +57,4 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $fil
|
||||
.success ->
|
||||
tagGroup.rules.splice(index, 1)
|
||||
$scope.updateRuleCounts()
|
||||
$scope.enterprise_form.$setDirty()
|
||||
|
||||
@@ -9,10 +9,10 @@ angular.module("admin.tagRules").directive 'newTagRuleDialog', ($compile, $templ
|
||||
|
||||
scope.ruleTypes = [
|
||||
# { id: "DiscountOrder", name: 'Apply a discount to orders' }
|
||||
{ id: "FilterProducts", name: 'Show or Hide variants in my shopfront' }
|
||||
{ id: "FilterShippingMethods", name: 'Show or Hide shipping methods at checkout' }
|
||||
{ id: "FilterPaymentMethods", name: 'Show or Hide payment methods at checkout' }
|
||||
{ id: "FilterOrderCycles", name: 'Show or Hide order cycles in my shopfront' }
|
||||
{ id: "FilterProducts", name: t('js.tag_rules.show_hide_variants') }
|
||||
{ id: "FilterShippingMethods", name: t('js.tag_rules.show_hide_shipping') }
|
||||
{ id: "FilterPaymentMethods", name: t('js.tag_rules.show_hide_payment') }
|
||||
{ id: "FilterOrderCycles", name: t('js.tag_rules.show_hide_order_cycles') }
|
||||
]
|
||||
|
||||
scope.ruleType = scope.ruleTypes[0].id
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
angular.module("admin.taxons").factory "Taxons", (taxons, $filter) ->
|
||||
new class Taxons
|
||||
taxons: taxons
|
||||
taxonsByID: {}
|
||||
all: []
|
||||
byID: {}
|
||||
|
||||
constructor: ->
|
||||
for taxon in @taxons
|
||||
@taxonsByID[taxon.id] = taxon
|
||||
for taxon in taxons
|
||||
@all.push taxon
|
||||
@byID[taxon.id] = taxon
|
||||
|
||||
# For finding a single Taxon
|
||||
findByID: (id) ->
|
||||
@taxonsByID[id]
|
||||
@byID[id]
|
||||
|
||||
# For finding multiple Taxons represented by comma delimited string
|
||||
findByIDs: (ids) ->
|
||||
@taxonsByID[taxon_id] for taxon_id in ids.split(",") when @taxonsByID[taxon_id]
|
||||
@byID[taxon_id] for taxon_id in ids.split(",") when @byID[taxon_id]
|
||||
|
||||
findByTerm: (term) ->
|
||||
$filter('filter')(@taxons, term)
|
||||
$filter('filter')(@all, term)
|
||||
|
||||
@@ -30,8 +30,16 @@ show_flash_error = function(message) {
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$('a.close').click(function(event){
|
||||
event.preventDefault();
|
||||
$(this).parent().slideUp(250);
|
||||
});
|
||||
$('a.close').click(function(event){
|
||||
event.preventDefault();
|
||||
$(this).parent().slideUp(250);
|
||||
});
|
||||
|
||||
// Spree locates hidden with prev(), which with our current version of jQuery
|
||||
// does not locate the hidden field, resulting in the delete failing. This
|
||||
// handler updates the hidden field, fixing the problem.
|
||||
$('body').on('click', 'a.remove_fields', function() {
|
||||
$(this).next("input[type=hidden]").val("1");
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
angular.module("admin.utils").directive "textangularStrip", () ->
|
||||
restrict: 'CA'
|
||||
link: (scope, element, attrs) ->
|
||||
scope.stripFormatting = ($html) ->
|
||||
return String($html).replace(/<[^>]+>/gm, '')
|
||||
@@ -1,2 +0,0 @@
|
||||
angular.module("admin.utils").value "blankOption", ->
|
||||
{ id: "0", name: "All" }
|
||||
@@ -10,7 +10,6 @@ angular.module("admin.utils")
|
||||
|
||||
$rootScope.$on "$locationChangeStart", @locationChangeStartHandler
|
||||
|
||||
|
||||
# Action for regular browser navigation.
|
||||
onBeforeUnloadHandler: ($event) =>
|
||||
message = @getMessage()
|
||||
@@ -21,13 +20,17 @@ angular.module("admin.utils")
|
||||
|
||||
# Action for angular navigation.
|
||||
locationChangeStartHandler: ($event) =>
|
||||
message = @getMessage()
|
||||
if message and not $window.confirm(message)
|
||||
if not @confirmLeave()
|
||||
$event.stopPropagation() if $event.stopPropagation
|
||||
$event.preventDefault() if $event.preventDefault
|
||||
$event.cancelBubble = true
|
||||
$event.returnValue = false
|
||||
|
||||
# Check if leaving is okay
|
||||
confirmLeave: =>
|
||||
message = @getMessage()
|
||||
!message or $window.confirm(message)
|
||||
|
||||
# Runs callback functions to retreive most recently added non-empty message.
|
||||
getMessage: ->
|
||||
message = null
|
||||
|
||||
@@ -11,6 +11,14 @@ angular.module("admin.utils").factory "StatusMessage", ($timeout) ->
|
||||
text: ""
|
||||
style: {}
|
||||
|
||||
invalidMessage: ""
|
||||
|
||||
setValidation: (isValid) ->
|
||||
if isValid
|
||||
StatusMessage.invalidMessage = ''
|
||||
else
|
||||
StatusMessage.invalidMessage = t("admin.form_invalid")
|
||||
|
||||
active: ->
|
||||
@statusMessage.text != ''
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
|
||||
$scope.currentView = -> Views.currentView
|
||||
|
||||
$scope.views = Views.setViews
|
||||
inventory: { name: "Inventory Products", visible: true }
|
||||
hidden: { name: "Hidden Products", visible: false }
|
||||
new: { name: "New Products", visible: false }
|
||||
inventory: { name: t('js.variant_overrides.inventory_products'), visible: true }
|
||||
hidden: { name: t('js.variant_overrides.hidden_products'), visible: false }
|
||||
new: { name: t('js.variant_overrides.new_products'), visible: false }
|
||||
|
||||
$scope.bulkActions = [ name: "Reset Stock Levels To Defaults", callback: 'resetStock' ]
|
||||
$scope.bulkActions = [ name: t('js.variant_overrides.reset_stock_levels'), callback: 'resetStock' ]
|
||||
|
||||
$scope.columns = Columns.columns
|
||||
|
||||
@@ -52,22 +52,22 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
|
||||
|
||||
$scope.displayDirty = ->
|
||||
if DirtyVariantOverrides.count() > 0
|
||||
num = if DirtyVariantOverrides.count() == 1 then "one override" else "#{DirtyVariantOverrides.count()} overrides"
|
||||
StatusMessage.display 'notice', "Changes to #{num} remain unsaved."
|
||||
num = if DirtyVariantOverrides.count() == 1 then t('js.variant_overrides.one_override') else "#{DirtyVariantOverrides.count()} " + t('js.variant_overrides.overrides')
|
||||
StatusMessage.display 'notice', t('js.variant_overrides.changes_to') + ' ' + num + ' ' + t('js.variant_overrides.remain_unsaved')
|
||||
else
|
||||
StatusMessage.clear()
|
||||
|
||||
$scope.update = ->
|
||||
if DirtyVariantOverrides.count() == 0
|
||||
StatusMessage.display 'alert', 'No changes to save.'
|
||||
StatusMessage.display 'alert', t('js.variant_overrides.no_changes_to_save')
|
||||
else
|
||||
StatusMessage.display 'progress', 'Saving...'
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
DirtyVariantOverrides.save()
|
||||
.success (updatedVos) ->
|
||||
DirtyVariantOverrides.clear()
|
||||
VariantOverrides.updateIds updatedVos
|
||||
$scope.variant_overrides_form.$setPristine()
|
||||
StatusMessage.display 'success', 'Changes saved.'
|
||||
StatusMessage.display 'success', t('js.changes_saved')
|
||||
VariantOverrides.updateData updatedVos # Refresh page data
|
||||
.error (data, status) ->
|
||||
StatusMessage.display 'failure', $scope.updateError(data, status)
|
||||
@@ -75,32 +75,32 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
|
||||
|
||||
$scope.updateError = (data, status) ->
|
||||
if status == 401
|
||||
"I couldn't get authorisation to save those changes, so they remain unsaved."
|
||||
t('js.variant_overrides.no_authorisation')
|
||||
|
||||
else if status == 400 && data.errors?
|
||||
errors = []
|
||||
for field, field_errors of data.errors
|
||||
errors = errors.concat field_errors
|
||||
errors = errors.join ', '
|
||||
"I had some trouble saving: #{errors}"
|
||||
t('js.variant_overrides.some_trouble', {errors: errors})
|
||||
else
|
||||
"Oh no! I was unable to save your changes."
|
||||
t('js.oh_no')
|
||||
|
||||
$scope.resetStock = ->
|
||||
if DirtyVariantOverrides.count() > 0
|
||||
StatusMessage.display 'alert', 'Save changes first.'
|
||||
StatusMessage.display 'alert', t('js.save_changes_first')
|
||||
$timeout ->
|
||||
$scope.displayDirty()
|
||||
, 3000 # 3 second delay
|
||||
else
|
||||
return unless $scope.hub_id?
|
||||
StatusMessage.display 'progress', 'Changing on hand stock levels...'
|
||||
StatusMessage.display 'progress', t('js.variant_overrides.changing_on_hand_stock')
|
||||
$http
|
||||
method: "POST"
|
||||
url: "/admin/variant_overrides/bulk_reset"
|
||||
data: { hub_id: $scope.hub_id }
|
||||
.success (updatedVos) ->
|
||||
VariantOverrides.updateData updatedVos
|
||||
StatusMessage.display 'success', 'Stocks reset to defaults.'
|
||||
StatusMessage.display 'success', t('js.variant_overrides.stock_reset')
|
||||
.error (data, status) ->
|
||||
$timeout -> StatusMessage.display 'failure', $scope.updateError(data, status)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#= require ../shared/angular-local-storage.js
|
||||
#= require ../shared/angular-slideables.js
|
||||
#= require angularjs-file-upload
|
||||
|
||||
#= require i18n/translations
|
||||
|
||||
#= require angular-rails-templates
|
||||
#= require_tree ../templates
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
$ ->
|
||||
if ($ 'form#update-cart').is('*')
|
||||
($ 'form#update-cart a.delete').show().one 'click', ->
|
||||
($ this).parents('.line-item').first().find('input.line_item_quantity').val 0
|
||||
($ this).parents('form').first().submit()
|
||||
if $('form#update-cart').is('*') || $('form#update-order').is('*')
|
||||
$('form#update-cart a.delete, form#update-order a.delete').show().one 'click', ->
|
||||
$(this).parents('.line-item').first().find('input.line_item_quantity').val 0
|
||||
$(this).parents('form').first().submit()
|
||||
false
|
||||
|
||||
($ 'form#update-cart').submit ->
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
Darkswarm.controller "AccordionCtrl", ($scope, storage, $timeout, $document, CurrentHub) ->
|
||||
$scope.accordion =
|
||||
details: true
|
||||
billing: false
|
||||
shipping: false
|
||||
payment: false
|
||||
Darkswarm.controller "AccordionCtrl", ($scope, localStorageService, $timeout, $document, CurrentHub) ->
|
||||
key = "accordion_#{$scope.order.id}#{CurrentHub.hub.id}#{$scope.order.user_id}"
|
||||
value = if localStorageService.get(key) then {} else { details: true, billing: false, shipping: false, payment: false }
|
||||
localStorageService.bind $scope, "accordion", value, key
|
||||
$scope.accordionSections = ["details", "billing", "shipping", "payment"]
|
||||
storage.bind $scope, "accordion", {storeName: "accordion_#{$scope.order.id}#{CurrentHub.hub.id}#{$scope.order.user_id}"}
|
||||
|
||||
$scope.show = (section)->
|
||||
$scope.accordion[section] = true
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.controller "CheckoutCtrl", ($scope, storage, Checkout, CurrentUser, CurrentHub) ->
|
||||
Darkswarm.controller "CheckoutCtrl", ($scope, localStorageService, Checkout, CurrentUser, CurrentHub) ->
|
||||
$scope.Checkout = Checkout
|
||||
$scope.submitted = false
|
||||
|
||||
@@ -7,11 +7,11 @@ Darkswarm.controller "CheckoutCtrl", ($scope, storage, Checkout, CurrentUser, Cu
|
||||
prefix = "order_#{Checkout.order.id}#{CurrentUser.id or ""}#{CurrentHub.hub.id}"
|
||||
|
||||
for field in $scope.fieldsToBind
|
||||
storage.bind $scope, "Checkout.order.#{field}",
|
||||
storeName: "#{prefix}_#{field}"
|
||||
storage.bind $scope, "Checkout.ship_address_same_as_billing",
|
||||
storeName: "#{prefix}_sameasbilling"
|
||||
defaultValue: true
|
||||
localStorageService.bind $scope, "Checkout.order.#{field}", Checkout.order[field], "#{prefix}_#{field}"
|
||||
|
||||
localStorageService.bind $scope, "Checkout.ship_address_same_as_billing", true, "#{prefix}_sameasbilling"
|
||||
localStorageService.bind $scope, "Checkout.default_bill_address", false, "#{prefix}_defaultasbilladdress"
|
||||
localStorageService.bind $scope, "Checkout.default_ship_address", false, "#{prefix}_defaultasshipaddress"
|
||||
|
||||
$scope.order = Checkout.order # Ordering is important
|
||||
$scope.secrets = Checkout.secrets
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
Darkswarm.controller "EditBoughtOrderController", ($scope, $resource, Cart) ->
|
||||
$scope.showBought = false
|
||||
|
||||
$scope.deleteLineItem = (id) ->
|
||||
params = {id: id}
|
||||
success = (response) ->
|
||||
$(".line-item-" + id).remove()
|
||||
Cart.removeFinalisedLineItem(id)
|
||||
fail = (error) ->
|
||||
console.log error
|
||||
|
||||
$resource("/line_items/:id").delete(params, success, fail)
|
||||
@@ -10,7 +10,7 @@ Darkswarm.controller "OrderCycleCtrl", ($scope, $timeout, OrderCycle) ->
|
||||
$("#order_cycle_id").trigger("openTrigger")
|
||||
|
||||
|
||||
Darkswarm.controller "OrderCycleChangeCtrl", ($scope, $timeout, OrderCycle, Products, Variants, Cart) ->
|
||||
Darkswarm.controller "OrderCycleChangeCtrl", ($scope, $timeout, OrderCycle, Products, Variants, Cart, ChangeableOrdersAlert) ->
|
||||
# Track previous order cycle id for use with revertOrderCycle()
|
||||
$scope.previous_order_cycle_id = OrderCycle.order_cycle.order_cycle_id
|
||||
$scope.$watch 'order_cycle.order_cycle_id', (newValue, oldValue)->
|
||||
@@ -30,3 +30,5 @@ Darkswarm.controller "OrderCycleChangeCtrl", ($scope, $timeout, OrderCycle, Prod
|
||||
Variants.clear()
|
||||
Cart.clear()
|
||||
Products.update()
|
||||
Cart.reloadFinalisedLineItems()
|
||||
ChangeableOrdersAlert.reload()
|
||||
|
||||
@@ -5,7 +5,20 @@ Darkswarm.controller "RegistrationCtrl", ($scope, RegistrationService, Enterpris
|
||||
|
||||
$scope.steps = ['details', 'contact', 'type', 'about', 'images', 'social']
|
||||
|
||||
$scope.countries = availableCountries
|
||||
# Filter countries without states since the form requires a state to be selected.
|
||||
# Consider changing the form to require a state only if a country requires them (Spree option).
|
||||
# Invalid countries still need to be filtered (better server-side).
|
||||
$scope.countries = availableCountries.filter (country) ->
|
||||
country.states.length > 0
|
||||
|
||||
$scope.countriesById = $scope.countries.reduce (obj, country) ->
|
||||
obj[country.id] = country
|
||||
obj
|
||||
, {}
|
||||
|
||||
$scope.setDefaultCountry = (id) ->
|
||||
country = $scope.countriesById[id]
|
||||
$scope.enterprise.country = country if country
|
||||
|
||||
$scope.countryHasStates = ->
|
||||
$scope.enterprise.country.states.length > 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.controller "ShoppingTabsCtrl", ($scope, $controller, Navigation) ->
|
||||
Darkswarm.controller "ShoppingTabsCtrl", ($scope, $controller, Navigation, $location) ->
|
||||
angular.extend this, $controller('TabsCtrl', {$scope: $scope})
|
||||
|
||||
$scope.tabs =
|
||||
@@ -6,3 +6,7 @@ Darkswarm.controller "ShoppingTabsCtrl", ($scope, $controller, Navigation) ->
|
||||
producers: { active: Navigation.isActive('/producers') }
|
||||
contact: { active: Navigation.isActive('/contact') }
|
||||
groups: { active: Navigation.isActive('/groups') }
|
||||
|
||||
$scope.$on '$locationChangeStart', (event, url) ->
|
||||
tab = $location.path().replace(/^\//, '')
|
||||
$scope.tabs[tab]?.active = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
window.Darkswarm = angular.module("Darkswarm", ["ngResource",
|
||||
'mm.foundation',
|
||||
'angularLocalStorage',
|
||||
'LocalStorageModule',
|
||||
'infinite-scroll',
|
||||
'angular-flash.service',
|
||||
'templates',
|
||||
@@ -11,8 +11,7 @@ window.Darkswarm = angular.module("Darkswarm", ["ngResource",
|
||||
'angularFileUpload',
|
||||
'angularSlideables'
|
||||
]).config ($httpProvider, $tooltipProvider, $locationProvider, $anchorScrollProvider) ->
|
||||
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers.put['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers['common']['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers['common']['X-Requested-With'] = 'XMLHttpRequest'
|
||||
$httpProvider.defaults.headers.common.Accept = "application/json, text/javascript, */*"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.directive "ofnChangeOrderCycle", (OrderCycle, Cart, storage) ->
|
||||
Darkswarm.directive "ofnChangeOrderCycle", (OrderCycle, Cart) ->
|
||||
# Compares chosen order cycle with pre-set OrderCycle. Will trigger
|
||||
# a confirmation if they are different, and Cart isn't empty
|
||||
restrict: "A"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Darkswarm.directive "changeableOrdersAlert", (ChangeableOrdersAlert) ->
|
||||
restrict: "C"
|
||||
scope: true
|
||||
link: (scope, element, attrs) ->
|
||||
scope.alert = ChangeableOrdersAlert
|
||||
@@ -0,0 +1,9 @@
|
||||
Darkswarm.directive "confirmLinkClick", ($window) ->
|
||||
restrict: 'A'
|
||||
scope:
|
||||
confirmMsg: '@confirmLinkClick'
|
||||
link: (scope, elem, attr) ->
|
||||
elem.bind 'click', (event) ->
|
||||
unless confirm(scope.confirmMsg)
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
@@ -15,7 +15,7 @@ Darkswarm.directive 'mapOsmTiles', ($timeout) ->
|
||||
if x < 0
|
||||
x = tilesPerGlobe + x
|
||||
# Wrap y (latitude) in a like manner if you want to enable vertical infinite scroll
|
||||
'http://tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png'
|
||||
'https://a.tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png'
|
||||
tileSize: new google.maps.Size(256, 256)
|
||||
name: 'OpenStreetMap'
|
||||
maxZoom: 18
|
||||
|
||||
@@ -6,7 +6,11 @@ Darkswarm.directive "ofnOnHand", ->
|
||||
# In cases where this field gets its value from the HTML element rather than the model,
|
||||
# initialise the model with the HTML value.
|
||||
if scope.$eval(attr.ngModel) == undefined
|
||||
ngModel.$setViewValue elem.val()
|
||||
# Don't dirty the model when we do this
|
||||
setDirty = ngModel.$setDirty
|
||||
ngModel.$setDirty = angular.noop
|
||||
ngModel.$setViewValue(elem.val())
|
||||
ngModel.$setDirty = setDirty
|
||||
|
||||
ngModel.$parsers.push (viewValue) ->
|
||||
on_hand = parseInt(attr.ofnOnHand)
|
||||
|
||||
@@ -4,5 +4,5 @@ Darkswarm.filter 'products', (Matcher) ->
|
||||
text ?= ""
|
||||
return products if text == ""
|
||||
products.filter (product) =>
|
||||
propertiesToMatch = [product.name, product.supplier.name, product.primary_taxon.name]
|
||||
Matcher.match propertiesToMatch, text
|
||||
propertiesToMatch = [product.name, product.variant_names, product.supplier.name, product.primary_taxon.name]
|
||||
Matcher.matchBeginning propertiesToMatch, text
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
Darkswarm.filter 'properties', ->
|
||||
# Filter anything that responds to object.supplied_properties
|
||||
(objects, ids) ->
|
||||
(objects, ids, source) ->
|
||||
objects ||= []
|
||||
ids ?= []
|
||||
|
||||
source ||= 'properties'
|
||||
return [] unless source in ['properties', 'supplied_properties', 'distributed_properties']
|
||||
|
||||
if ids.length == 0
|
||||
# No properties selected, pass all objects through.
|
||||
objects
|
||||
else
|
||||
objects.filter (obj) ->
|
||||
properties = obj.supplied_properties || obj.properties
|
||||
properties = obj[source]
|
||||
properties.some (property) ->
|
||||
property.id in ids
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Darkswarm.filter 'propertiesOf', ->
|
||||
(objects) ->
|
||||
(objects, source) ->
|
||||
source ||= 'properties'
|
||||
return {} unless source in ['properties', 'supplied_properties', 'distributed_properties']
|
||||
|
||||
properties = {}
|
||||
for object in objects
|
||||
if object.supplied_properties?
|
||||
for property in object.supplied_properties
|
||||
properties[property.id] = property
|
||||
else
|
||||
for property in object.properties
|
||||
if object[source]?
|
||||
for property in object[source]
|
||||
properties[property.id] = property
|
||||
|
||||
properties
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<%# Defines a global I18n object containing the language of the current locale %>
|
||||
<%
|
||||
# Invalidate this asset if locale changes.
|
||||
Dir[Rails.root.join('config', 'locales', "#{I18n.default_locale}.yml").to_s].each do |f|
|
||||
depend_on(f)
|
||||
end
|
||||
%>
|
||||
<%- I18n.backend.send(:init_translations) unless I18n.backend.initialized? %>
|
||||
window.I18n = <%= I18n.backend.send(:translations)[I18n.default_locale].with_indifferent_access.to_json.html_safe %>
|
||||
@@ -1,17 +1,11 @@
|
||||
# Old aliases before i18n-js was introduced.
|
||||
# TODO - delete it after everything is moved to i18n-js
|
||||
|
||||
# Declares the translation function t.
|
||||
# You can use translate('login') or t('login') in Javascript.
|
||||
window.translate = (key, options = {}) ->
|
||||
unless 'I18n' of window
|
||||
console.log 'The I18n object is undefined. Cannot translate text.'
|
||||
return key
|
||||
dict = I18n
|
||||
parts = key.split '.'
|
||||
while (parts.length)
|
||||
part = parts.shift()
|
||||
return key unless part of dict
|
||||
dict = dict[part]
|
||||
text = dict
|
||||
for name, value of options
|
||||
text = text.split("%{#{name}}").join(value)
|
||||
text
|
||||
I18n.t(key, options)
|
||||
window.t = window.translate
|
||||
|
||||
@@ -25,9 +25,7 @@ Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redir
|
||||
isActive: Navigation.isActive
|
||||
|
||||
close: ->
|
||||
if location.pathname in ["/", "/checkout"]
|
||||
Navigation.navigate "/"
|
||||
else
|
||||
if location.pathname in ["/register", "/register/auth"]
|
||||
Loading.message = t 'going_back_to_home_page'
|
||||
location.hash = ""
|
||||
location.pathname = "/"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, storage)->
|
||||
Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, $resource, localStorageService) ->
|
||||
# Handles syncing of current cart/order state to server
|
||||
new class Cart
|
||||
dirty: false
|
||||
@@ -6,11 +6,15 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
|
||||
update_enqueued: false
|
||||
order: CurrentOrder.order
|
||||
line_items: CurrentOrder.order?.line_items || []
|
||||
line_items_finalised: CurrentOrder.order?.finalised_line_items || []
|
||||
|
||||
constructor: ->
|
||||
for line_item in @line_items
|
||||
line_item.variant.line_item = line_item
|
||||
Variants.register line_item.variant
|
||||
for line_item in @line_items_finalised
|
||||
line_item.variant.line_item = line_item
|
||||
Variants.extend line_item.variant
|
||||
|
||||
adjust: (line_item) =>
|
||||
line_item.total_price = line_item.variant.price_with_fees * line_item.quantity
|
||||
@@ -114,4 +118,16 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
|
||||
|
||||
clear: ->
|
||||
@line_items = []
|
||||
storage.clearAll() # One day this will have to be moar GRANULAR
|
||||
localStorageService.clearAll() # One day this will have to be moar GRANULAR
|
||||
|
||||
removeFinalisedLineItem: (id) =>
|
||||
@line_items_finalised = @line_items_finalised.filter (item) ->
|
||||
item.id != id
|
||||
|
||||
reloadFinalisedLineItems: =>
|
||||
@line_items_finalised = []
|
||||
$resource("/line_items/bought").query (items) =>
|
||||
for line_item in items
|
||||
line_item.variant.line_item = line_item
|
||||
Variants.extend line_item.variant
|
||||
@line_items_finalised = items
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
Darkswarm.factory 'ChangeableOrdersAlert', ($http) ->
|
||||
new class ChangeableOrdersAlert
|
||||
html: ''
|
||||
visible: true
|
||||
|
||||
constructor: ->
|
||||
@reload()
|
||||
|
||||
reload: ->
|
||||
$http.get('/shop/changeable_orders_alert').then (response) =>
|
||||
@html = response.data.trim()
|
||||
|
||||
close: =>
|
||||
@visible = false
|
||||
@@ -3,7 +3,6 @@ Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $h
|
||||
errors: {}
|
||||
secrets: {}
|
||||
order: CurrentOrder.order
|
||||
ship_address_same_as_billing: true
|
||||
|
||||
submit: ->
|
||||
Loading.message = t 'submitting_order'
|
||||
@@ -19,7 +18,10 @@ Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $h
|
||||
|
||||
# Rails wants our Spree::Address data to be provided with _attributes
|
||||
preprocess: ->
|
||||
munged_order = {}
|
||||
munged_order =
|
||||
default_bill_address: !!@default_bill_address
|
||||
default_ship_address: !!@default_ship_address
|
||||
|
||||
for name, value of @order # Clone all data from the order JSON object
|
||||
switch name
|
||||
when "bill_address"
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
Darkswarm.factory "Matcher", ->
|
||||
# Match text fragment in an array of strings.
|
||||
new class Matcher
|
||||
|
||||
# Match text fragment in an array of strings.
|
||||
match: (properties, text)->
|
||||
properties.some (prop)->
|
||||
prop ||= ""
|
||||
prop.toLowerCase().indexOf(text.toLowerCase()) != -1
|
||||
|
||||
# Return true if text occurs at the beginning of any word present in an array of strings
|
||||
matchBeginning: (properties, text) ->
|
||||
text = text.trim()
|
||||
regexp = new RegExp("(?:^|[\\s-])#{text}", "i")
|
||||
properties.some (prop) -> (prop || "").search(regexp) >= 0
|
||||
|
||||
@@ -3,10 +3,12 @@ Darkswarm.factory 'Orders', (orders_by_distributor, currencyConfig, CurrentHub,
|
||||
constructor: ->
|
||||
# Populate Orders.orders from json in page.
|
||||
@orders_by_distributor = orders_by_distributor
|
||||
@changeable_orders = []
|
||||
@currency_symbol = currencyConfig.symbol
|
||||
|
||||
for distributor in @orders_by_distributor
|
||||
@updateRunningBalance(distributor.distributed_orders)
|
||||
@findChangeableOrders(distributor.distributed_orders)
|
||||
@updateRunningBalance(distributor.distributed_orders)
|
||||
|
||||
|
||||
updateRunningBalance: (orders) ->
|
||||
@@ -14,3 +16,7 @@ Darkswarm.factory 'Orders', (orders_by_distributor, currencyConfig, CurrentHub,
|
||||
balances = orders.slice(i,orders.length).map (o) -> parseFloat(o.outstanding_balance)
|
||||
running_balance = balances.reduce (a,b) -> a+b
|
||||
order.running_balance = running_balance.toFixed(2)
|
||||
|
||||
findChangeableOrders: (orders) ->
|
||||
for order in orders when order.changes_allowed
|
||||
@changeable_orders.push(order)
|
||||
|
||||
@@ -25,7 +25,6 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
|
||||
prices = (v.price for v in product.variants)
|
||||
product.price = Math.min.apply(null, prices)
|
||||
product.hasVariants = product.variants?.length > 0
|
||||
|
||||
product.primaryImage = product.images[0]?.small_url if product.images
|
||||
product.primaryImageOrMissing = product.primaryImage || "/assets/noimage/small.png"
|
||||
product.largeImage = product.images[0]?.large_url if product.images
|
||||
@@ -43,7 +42,10 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
|
||||
registerVariants: ->
|
||||
for product in @products
|
||||
if product.variants
|
||||
product.variant_names = ""
|
||||
product.variants = for variant in product.variants
|
||||
variant = Variants.register variant
|
||||
if product.name != variant.name_to_display
|
||||
product.variant_names += variant.name_to_display + " "
|
||||
variant.product = product
|
||||
variant
|
||||
|
||||
@@ -1,171 +1,546 @@
|
||||
/*
|
||||
* Angular.js localStorage module
|
||||
* https://github.com/agrublev/angularLocalStorage
|
||||
/**
|
||||
* An Angular module that gives you access to the browsers local storage
|
||||
* @version v0.5.0 - 2016-08-29
|
||||
* @link https://github.com/grevory/angular-local-storage
|
||||
* @author grevory <greg@gregpike.ca>
|
||||
* @license MIT License, http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
(function (window, angular) {
|
||||
var isDefined = angular.isDefined,
|
||||
isUndefined = angular.isUndefined,
|
||||
isNumber = angular.isNumber,
|
||||
isObject = angular.isObject,
|
||||
isArray = angular.isArray,
|
||||
extend = angular.extend,
|
||||
toJson = angular.toJson;
|
||||
|
||||
(function (window, angular, undefined) {
|
||||
'use strict';
|
||||
angular
|
||||
.module('LocalStorageModule', [])
|
||||
.provider('localStorageService', function() {
|
||||
// You should set a prefix to avoid overwriting any local storage variables from the rest of your app
|
||||
// e.g. localStorageServiceProvider.setPrefix('yourAppName');
|
||||
// With provider you can use config as this:
|
||||
// myApp.config(function (localStorageServiceProvider) {
|
||||
// localStorageServiceProvider.prefix = 'yourAppName';
|
||||
// });
|
||||
this.prefix = 'ls';
|
||||
|
||||
angular.module('angularLocalStorage', ['ngCookies']).factory('storage', ['$parse', '$cookieStore', '$window', '$log', function ($parse, $cookieStore, $window, $log) {
|
||||
/**
|
||||
* Global Vars
|
||||
*/
|
||||
var storage = (typeof $window.localStorage === 'undefined') ? undefined : $window.localStorage;
|
||||
var supported = typeof storage !== 'undefined';
|
||||
// You could change web storage type localstorage or sessionStorage
|
||||
this.storageType = 'localStorage';
|
||||
|
||||
var privateMethods = {
|
||||
/**
|
||||
* Pass any type of a string from the localStorage to be parsed so it returns a usable version (like an Object)
|
||||
* @param res - a string that will be parsed for type
|
||||
* @returns {*} - whatever the real type of stored value was
|
||||
*/
|
||||
parseValue: function (res) {
|
||||
var val;
|
||||
try {
|
||||
val = angular.fromJson(res);
|
||||
if (typeof val === 'undefined') {
|
||||
val = res;
|
||||
}
|
||||
if (val === 'true') {
|
||||
val = true;
|
||||
}
|
||||
if (val === 'false') {
|
||||
val = false;
|
||||
}
|
||||
if ($window.parseFloat(val) === val && !angular.isObject(val)) {
|
||||
val = $window.parseFloat(val);
|
||||
}
|
||||
} catch (e) {
|
||||
val = res;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
// Cookie options (usually in case of fallback)
|
||||
// expiry = Number of days before cookies expire // 0 = Does not expire
|
||||
// path = The web path the cookie represents
|
||||
// secure = Wether the cookies should be secure (i.e only sent on HTTPS requests)
|
||||
this.cookie = {
|
||||
expiry: 30,
|
||||
path: '/',
|
||||
secure: false
|
||||
};
|
||||
|
||||
var publicMethods = {
|
||||
/**
|
||||
* Set - let's you set a new localStorage key pair set
|
||||
* @param key - a string that will be used as the accessor for the pair
|
||||
* @param value - the value of the localStorage item
|
||||
* @returns {*} - will return whatever it is you've stored in the local storage
|
||||
*/
|
||||
set: function (key, value) {
|
||||
if (!supported) {
|
||||
try {
|
||||
$cookieStore.put(key, value);
|
||||
return value;
|
||||
} catch(e) {
|
||||
$log.log('Local Storage not supported, make sure you have angular-cookies enabled.');
|
||||
}
|
||||
}
|
||||
var saver = angular.toJson(value);
|
||||
storage.setItem(key, saver);
|
||||
return privateMethods.parseValue(saver);
|
||||
},
|
||||
// Decides wether we should default to cookies if localstorage is not supported.
|
||||
this.defaultToCookie = true;
|
||||
|
||||
/**
|
||||
* Get - let's you get the value of any pair you've stored
|
||||
* @param key - the string that you set as accessor for the pair
|
||||
* @returns {*} - Object,String,Float,Boolean depending on what you stored
|
||||
*/
|
||||
get: function (key) {
|
||||
if (!supported) {
|
||||
try {
|
||||
return privateMethods.parseValue($.cookie(key));
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
var item = storage.getItem(key);
|
||||
return privateMethods.parseValue(item);
|
||||
},
|
||||
// Send signals for each of the following actions?
|
||||
this.notify = {
|
||||
setItem: true,
|
||||
removeItem: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove - let's you nuke a value from localStorage
|
||||
* @param key - the accessor value
|
||||
* @returns {boolean} - if everything went as planned
|
||||
*/
|
||||
remove: function (key) {
|
||||
if (!supported) {
|
||||
try {
|
||||
$cookieStore.remove(key);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
storage.removeItem(key);
|
||||
return true;
|
||||
},
|
||||
// Setter for the prefix
|
||||
this.setPrefix = function(prefix) {
|
||||
this.prefix = prefix;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Bind - let's you directly bind a localStorage value to a $scope variable
|
||||
* @param {Angular $scope} $scope - the current scope you want the variable available in
|
||||
* @param {String} key - the name of the variable you are binding
|
||||
* @param {Object} opts - (optional) custom options like default value or unique store name
|
||||
* Here are the available options you can set:
|
||||
* * defaultValue: the default value
|
||||
* * storeName: add a custom store key value instead of using the scope variable name
|
||||
* @returns {*} - returns whatever the stored value is
|
||||
*/
|
||||
bind: function ($scope, key, opts) {
|
||||
var defaultOpts = {
|
||||
defaultValue: '',
|
||||
storeName: ''
|
||||
};
|
||||
// Backwards compatibility with old defaultValue string
|
||||
if (angular.isString(opts)) {
|
||||
opts = angular.extend({},defaultOpts,{defaultValue:opts});
|
||||
} else {
|
||||
// If no defined options we use defaults otherwise extend defaults
|
||||
opts = (angular.isUndefined(opts)) ? defaultOpts : angular.extend(defaultOpts,opts);
|
||||
}
|
||||
// Setter for the storageType
|
||||
this.setStorageType = function(storageType) {
|
||||
this.storageType = storageType;
|
||||
return this;
|
||||
};
|
||||
// Setter for defaultToCookie value, default is true.
|
||||
this.setDefaultToCookie = function (shouldDefault) {
|
||||
this.defaultToCookie = !!shouldDefault; // Double-not to make sure it's a bool value.
|
||||
return this;
|
||||
};
|
||||
// Setter for cookie config
|
||||
this.setStorageCookie = function(exp, path, secure) {
|
||||
this.cookie.expiry = exp;
|
||||
this.cookie.path = path;
|
||||
this.cookie.secure = secure;
|
||||
return this;
|
||||
};
|
||||
|
||||
// Set the storeName key for the localStorage entry
|
||||
// use user defined in specified
|
||||
var storeName = opts.storeName || key;
|
||||
// Setter for cookie domain
|
||||
this.setStorageCookieDomain = function(domain) {
|
||||
this.cookie.domain = domain;
|
||||
return this;
|
||||
};
|
||||
|
||||
// If a value doesn't already exist store it as is
|
||||
if (!publicMethods.get(storeName)) {
|
||||
publicMethods.set(storeName, $parse(key)($scope) || opts.defaultValue);
|
||||
} else {
|
||||
// If it does exist assign it to the $scope value
|
||||
$parse(key).assign($scope, publicMethods.get(storeName));
|
||||
// Setter for notification config
|
||||
// itemSet & itemRemove should be booleans
|
||||
this.setNotify = function(itemSet, itemRemove) {
|
||||
this.notify = {
|
||||
setItem: itemSet,
|
||||
removeItem: itemRemove
|
||||
};
|
||||
return this;
|
||||
};
|
||||
|
||||
this.$get = ['$rootScope', '$window', '$document', '$parse','$timeout', function($rootScope, $window, $document, $parse, $timeout) {
|
||||
var self = this;
|
||||
var prefix = self.prefix;
|
||||
var cookie = self.cookie;
|
||||
var notify = self.notify;
|
||||
var storageType = self.storageType;
|
||||
var webStorage;
|
||||
|
||||
// When Angular's $document is not available
|
||||
if (!$document) {
|
||||
$document = document;
|
||||
} else if ($document[0]) {
|
||||
$document = $document[0];
|
||||
}
|
||||
|
||||
// If there is a prefix set in the config lets use that with an appended period for readability
|
||||
if (prefix.substr(-1) !== '.') {
|
||||
prefix = !!prefix ? prefix + '.' : '';
|
||||
}
|
||||
var deriveQualifiedKey = function(key) {
|
||||
return prefix + key;
|
||||
};
|
||||
|
||||
// Removes prefix from the key.
|
||||
var underiveQualifiedKey = function (key) {
|
||||
return key.replace(new RegExp('^' + prefix, 'g'), '');
|
||||
};
|
||||
|
||||
// Check if the key is within our prefix namespace.
|
||||
var isKeyPrefixOurs = function (key) {
|
||||
return key.indexOf(prefix) === 0;
|
||||
};
|
||||
|
||||
// Checks the browser to see if local storage is supported
|
||||
var checkSupport = function () {
|
||||
try {
|
||||
var supported = (storageType in $window && $window[storageType] !== null);
|
||||
|
||||
// When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage
|
||||
// is available, but trying to call .setItem throws an exception.
|
||||
//
|
||||
// "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage
|
||||
// that exceeded the quota."
|
||||
var key = deriveQualifiedKey('__' + Math.round(Math.random() * 1e7));
|
||||
if (supported) {
|
||||
webStorage = $window[storageType];
|
||||
webStorage.setItem(key, '');
|
||||
webStorage.removeItem(key);
|
||||
}
|
||||
|
||||
return supported;
|
||||
} catch (e) {
|
||||
// Only change storageType to cookies if defaulting is enabled.
|
||||
if (self.defaultToCookie)
|
||||
storageType = 'cookie';
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
var browserSupportsLocalStorage = checkSupport();
|
||||
|
||||
// Directly adds a value to local storage
|
||||
// If local storage is not available in the browser use cookies
|
||||
// Example use: localStorageService.add('library','angular');
|
||||
var addToLocalStorage = function (key, value, type) {
|
||||
setStorageType(type);
|
||||
|
||||
// Let's convert undefined values to null to get the value consistent
|
||||
if (isUndefined(value)) {
|
||||
value = null;
|
||||
} else {
|
||||
value = toJson(value);
|
||||
}
|
||||
|
||||
// If this browser does not support local storage use cookies
|
||||
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
|
||||
if (!browserSupportsLocalStorage) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
||||
}
|
||||
|
||||
// Register a listener for changes on the $scope value
|
||||
// to update the localStorage value
|
||||
$scope.$watch(key, function (val) {
|
||||
if (angular.isDefined(val)) {
|
||||
publicMethods.set(storeName, val);
|
||||
}
|
||||
}, true);
|
||||
if (notify.setItem) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'cookie'});
|
||||
}
|
||||
return addToCookies(key, value);
|
||||
}
|
||||
|
||||
return publicMethods.get(storeName);
|
||||
},
|
||||
/**
|
||||
* Unbind - let's you unbind a variable from localStorage while removing the value from both
|
||||
* the localStorage and the local variable and sets it to null
|
||||
* @param $scope - the scope the variable was initially set in
|
||||
* @param key - the name of the variable you are unbinding
|
||||
* @param storeName - (optional) if you used a custom storeName you will have to specify it here as well
|
||||
*/
|
||||
unbind: function($scope,key,storeName) {
|
||||
storeName = storeName || key;
|
||||
$parse(key).assign($scope, null);
|
||||
$scope.$watch(key, function () { });
|
||||
publicMethods.remove(storeName);
|
||||
},
|
||||
/**
|
||||
* Clear All - let's you clear out ALL localStorage variables, use this carefully!
|
||||
*/
|
||||
clearAll: function() {
|
||||
storage.clear();
|
||||
}
|
||||
};
|
||||
try {
|
||||
if (webStorage) {
|
||||
webStorage.setItem(deriveQualifiedKey(key), value);
|
||||
}
|
||||
if (notify.setItem) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: self.storageType});
|
||||
}
|
||||
} catch (e) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||
return addToCookies(key, value);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
return publicMethods;
|
||||
}]);
|
||||
// Directly get a value from local storage
|
||||
// Example use: localStorageService.get('library'); // returns 'angular'
|
||||
var getFromLocalStorage = function (key, type) {
|
||||
setStorageType(type);
|
||||
|
||||
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
|
||||
if (!browserSupportsLocalStorage) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
||||
}
|
||||
|
||||
return getFromCookies(key);
|
||||
}
|
||||
|
||||
var item = webStorage ? webStorage.getItem(deriveQualifiedKey(key)) : null;
|
||||
// angular.toJson will convert null to 'null', so a proper conversion is needed
|
||||
// FIXME not a perfect solution, since a valid 'null' string can't be stored
|
||||
if (!item || item === 'null') {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(item);
|
||||
} catch (e) {
|
||||
return item;
|
||||
}
|
||||
};
|
||||
|
||||
// Remove an item from local storage
|
||||
// Example use: localStorageService.remove('library'); // removes the key/value pair of library='angular'
|
||||
//
|
||||
// This is var-arg removal, check the last argument to see if it is a storageType
|
||||
// and set type accordingly before removing.
|
||||
//
|
||||
var removeFromLocalStorage = function () {
|
||||
// can't pop on arguments, so we do this
|
||||
var consumed = 0;
|
||||
if (arguments.length >= 1 &&
|
||||
(arguments[arguments.length - 1] === 'localStorage' ||
|
||||
arguments[arguments.length - 1] === 'sessionStorage')) {
|
||||
consumed = 1;
|
||||
setStorageType(arguments[arguments.length - 1]);
|
||||
}
|
||||
|
||||
var i, key;
|
||||
for (i = 0; i < arguments.length - consumed; i++) {
|
||||
key = arguments[i];
|
||||
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
|
||||
if (!browserSupportsLocalStorage) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
||||
}
|
||||
|
||||
if (notify.removeItem) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'});
|
||||
}
|
||||
removeFromCookies(key);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
webStorage.removeItem(deriveQualifiedKey(key));
|
||||
if (notify.removeItem) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.removeitem', {
|
||||
key: key,
|
||||
storageType: self.storageType
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||
removeFromCookies(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Return array of keys for local storage
|
||||
// Example use: var keys = localStorageService.keys()
|
||||
var getKeysForLocalStorage = function (type) {
|
||||
setStorageType(type);
|
||||
|
||||
if (!browserSupportsLocalStorage) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
||||
return [];
|
||||
}
|
||||
|
||||
var prefixLength = prefix.length;
|
||||
var keys = [];
|
||||
for (var key in webStorage) {
|
||||
// Only return keys that are for this app
|
||||
if (key.substr(0, prefixLength) === prefix) {
|
||||
try {
|
||||
keys.push(key.substr(prefixLength));
|
||||
} catch (e) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.error', e.Description);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
};
|
||||
|
||||
// Remove all data for this app from local storage
|
||||
// Also optionally takes a regular expression string and removes the matching key-value pairs
|
||||
// Example use: localStorageService.clearAll();
|
||||
// Should be used mostly for development purposes
|
||||
var clearAllFromLocalStorage = function (regularExpression, type) {
|
||||
setStorageType(type);
|
||||
|
||||
// Setting both regular expressions independently
|
||||
// Empty strings result in catchall RegExp
|
||||
var prefixRegex = !!prefix ? new RegExp('^' + prefix) : new RegExp();
|
||||
var testRegex = !!regularExpression ? new RegExp(regularExpression) : new RegExp();
|
||||
|
||||
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
|
||||
if (!browserSupportsLocalStorage) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
||||
}
|
||||
return clearAllFromCookies();
|
||||
}
|
||||
if (!browserSupportsLocalStorage && !self.defaultToCookie)
|
||||
return false;
|
||||
var prefixLength = prefix.length;
|
||||
|
||||
for (var key in webStorage) {
|
||||
// Only remove items that are for this app and match the regular expression
|
||||
if (prefixRegex.test(key) && testRegex.test(key.substr(prefixLength))) {
|
||||
try {
|
||||
removeFromLocalStorage(key.substr(prefixLength));
|
||||
} catch (e) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||
return clearAllFromCookies();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Checks the browser to see if cookies are supported
|
||||
var browserSupportsCookies = (function() {
|
||||
try {
|
||||
return $window.navigator.cookieEnabled ||
|
||||
("cookie" in $document && ($document.cookie.length > 0 ||
|
||||
($document.cookie = "test").indexOf.call($document.cookie, "test") > -1));
|
||||
} catch (e) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||
return false;
|
||||
}
|
||||
}());
|
||||
|
||||
// Directly adds a value to cookies
|
||||
// Typically used as a fallback if local storage is not available in the browser
|
||||
// Example use: localStorageService.cookie.add('library','angular');
|
||||
var addToCookies = function (key, value, daysToExpiry, secure) {
|
||||
|
||||
if (isUndefined(value)) {
|
||||
return false;
|
||||
} else if(isArray(value) || isObject(value)) {
|
||||
value = toJson(value);
|
||||
}
|
||||
|
||||
if (!browserSupportsCookies) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
var expiry = '',
|
||||
expiryDate = new Date(),
|
||||
cookieDomain = '';
|
||||
|
||||
if (value === null) {
|
||||
// Mark that the cookie has expired one day ago
|
||||
expiryDate.setTime(expiryDate.getTime() + (-1 * 24 * 60 * 60 * 1000));
|
||||
expiry = "; expires=" + expiryDate.toGMTString();
|
||||
value = '';
|
||||
} else if (isNumber(daysToExpiry) && daysToExpiry !== 0) {
|
||||
expiryDate.setTime(expiryDate.getTime() + (daysToExpiry * 24 * 60 * 60 * 1000));
|
||||
expiry = "; expires=" + expiryDate.toGMTString();
|
||||
} else if (cookie.expiry !== 0) {
|
||||
expiryDate.setTime(expiryDate.getTime() + (cookie.expiry * 24 * 60 * 60 * 1000));
|
||||
expiry = "; expires=" + expiryDate.toGMTString();
|
||||
}
|
||||
if (!!key) {
|
||||
var cookiePath = "; path=" + cookie.path;
|
||||
if (cookie.domain) {
|
||||
cookieDomain = "; domain=" + cookie.domain;
|
||||
}
|
||||
/* Providing the secure parameter always takes precedence over config
|
||||
* (allows developer to mix and match secure + non-secure) */
|
||||
if (typeof secure === 'boolean') {
|
||||
if (secure === true) {
|
||||
/* We've explicitly specified secure,
|
||||
* add the secure attribute to the cookie (after domain) */
|
||||
cookieDomain += "; secure";
|
||||
}
|
||||
// else - secure has been supplied but isn't true - so don't set secure flag, regardless of what config says
|
||||
}
|
||||
else if (cookie.secure === true) {
|
||||
// secure parameter wasn't specified, get default from config
|
||||
cookieDomain += "; secure";
|
||||
}
|
||||
$document.cookie = deriveQualifiedKey(key) + "=" + encodeURIComponent(value) + expiry + cookiePath + cookieDomain;
|
||||
}
|
||||
} catch (e) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Directly get a value from a cookie
|
||||
// Example use: localStorageService.cookie.get('library'); // returns 'angular'
|
||||
var getFromCookies = function (key) {
|
||||
if (!browserSupportsCookies) {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
|
||||
return false;
|
||||
}
|
||||
|
||||
var cookies = $document.cookie && $document.cookie.split(';') || [];
|
||||
for(var i=0; i < cookies.length; i++) {
|
||||
var thisCookie = cookies[i];
|
||||
while (thisCookie.charAt(0) === ' ') {
|
||||
thisCookie = thisCookie.substring(1,thisCookie.length);
|
||||
}
|
||||
if (thisCookie.indexOf(deriveQualifiedKey(key) + '=') === 0) {
|
||||
var storedValues = decodeURIComponent(thisCookie.substring(prefix.length + key.length + 1, thisCookie.length));
|
||||
try {
|
||||
return JSON.parse(storedValues);
|
||||
} catch(e) {
|
||||
return storedValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
var removeFromCookies = function (key) {
|
||||
addToCookies(key,null);
|
||||
};
|
||||
|
||||
var clearAllFromCookies = function () {
|
||||
var thisCookie = null;
|
||||
var prefixLength = prefix.length;
|
||||
var cookies = $document.cookie.split(';');
|
||||
for(var i = 0; i < cookies.length; i++) {
|
||||
thisCookie = cookies[i];
|
||||
|
||||
while (thisCookie.charAt(0) === ' ') {
|
||||
thisCookie = thisCookie.substring(1, thisCookie.length);
|
||||
}
|
||||
|
||||
var key = thisCookie.substring(prefixLength, thisCookie.indexOf('='));
|
||||
removeFromCookies(key);
|
||||
}
|
||||
};
|
||||
|
||||
var getStorageType = function() {
|
||||
return storageType;
|
||||
};
|
||||
|
||||
var setStorageType = function(type) {
|
||||
if (type && storageType !== type) {
|
||||
storageType = type;
|
||||
browserSupportsLocalStorage = checkSupport();
|
||||
}
|
||||
return browserSupportsLocalStorage;
|
||||
};
|
||||
|
||||
// Add a listener on scope variable to save its changes to local storage
|
||||
// Return a function which when called cancels binding
|
||||
var bindToScope = function(scope, key, def, lsKey, type) {
|
||||
lsKey = lsKey || key;
|
||||
var value = getFromLocalStorage(lsKey, type);
|
||||
|
||||
if (value === null && isDefined(def)) {
|
||||
value = def;
|
||||
} else if (isObject(value) && isObject(def)) {
|
||||
value = extend(value, def);
|
||||
}
|
||||
|
||||
$parse(key).assign(scope, value);
|
||||
|
||||
return scope.$watch(key, function(newVal) {
|
||||
addToLocalStorage(lsKey, newVal, type);
|
||||
}, isObject(scope[key]));
|
||||
};
|
||||
|
||||
// Add listener to local storage, for update callbacks.
|
||||
if (browserSupportsLocalStorage) {
|
||||
if ($window.addEventListener) {
|
||||
$window.addEventListener("storage", handleStorageChangeCallback, false);
|
||||
$rootScope.$on('$destroy', function() {
|
||||
$window.removeEventListener("storage", handleStorageChangeCallback);
|
||||
});
|
||||
} else if($window.attachEvent){
|
||||
// attachEvent and detachEvent are proprietary to IE v6-10
|
||||
$window.attachEvent("onstorage", handleStorageChangeCallback);
|
||||
$rootScope.$on('$destroy', function() {
|
||||
$window.detachEvent("onstorage", handleStorageChangeCallback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Callback handler for storage changed.
|
||||
function handleStorageChangeCallback(e) {
|
||||
if (!e) { e = $window.event; }
|
||||
if (notify.setItem) {
|
||||
if (isKeyPrefixOurs(e.key)) {
|
||||
var key = underiveQualifiedKey(e.key);
|
||||
// Use timeout, to avoid using $rootScope.$apply.
|
||||
$timeout(function () {
|
||||
$rootScope.$broadcast('LocalStorageModule.notification.changed', { key: key, newvalue: e.newValue, storageType: self.storageType });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return localStorageService.length
|
||||
// ignore keys that not owned
|
||||
var lengthOfLocalStorage = function(type) {
|
||||
setStorageType(type);
|
||||
|
||||
var count = 0;
|
||||
var storage = $window[storageType];
|
||||
for(var i = 0; i < storage.length; i++) {
|
||||
if(storage.key(i).indexOf(prefix) === 0 ) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
return {
|
||||
isSupported: browserSupportsLocalStorage,
|
||||
getStorageType: getStorageType,
|
||||
setStorageType: setStorageType,
|
||||
set: addToLocalStorage,
|
||||
add: addToLocalStorage, //DEPRECATED
|
||||
get: getFromLocalStorage,
|
||||
keys: getKeysForLocalStorage,
|
||||
remove: removeFromLocalStorage,
|
||||
clearAll: clearAllFromLocalStorage,
|
||||
bind: bindToScope,
|
||||
deriveKey: deriveQualifiedKey,
|
||||
underiveKey: underiveQualifiedKey,
|
||||
length: lengthOfLocalStorage,
|
||||
defaultToCookie: this.defaultToCookie,
|
||||
cookie: {
|
||||
isSupported: browserSupportsCookies,
|
||||
set: addToCookies,
|
||||
add: addToCookies, //DEPRECATED
|
||||
get: getFromCookies,
|
||||
remove: removeFromCookies,
|
||||
clearAll: clearAllFromCookies
|
||||
}
|
||||
};
|
||||
}];
|
||||
});
|
||||
})(window, window.angular);
|
||||
|
||||
@@ -11,6 +11,18 @@
|
||||
%table.no-borders
|
||||
%tr
|
||||
%td{style: 'width: 30%'}
|
||||
= t('spree.firstname')
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'firstname', required: true, ng: { model: 'address.firstname'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.lastname')
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'lastname', required: true, ng: { model: 'address.lastname'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.street_address')
|
||||
%span.required *
|
||||
%td
|
||||
@@ -20,12 +32,6 @@
|
||||
= t('spree.street_address_1')
|
||||
%td
|
||||
%input{ type: 'text', name: 'address2', ng: { model: 'address.address2'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.phone')
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'phone', required: true, ng: { model: 'address.phone'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.city')
|
||||
@@ -43,19 +49,29 @@
|
||||
= t('spree.country')
|
||||
%span.required *
|
||||
%td
|
||||
%select{name: 'country', required: true, ng: {model: 'address.country_id', options: 'country.id as country.name for country in availableCountries'}}
|
||||
%select{ name: 'country', required: true, ng: { model: 'address.country_id' } }
|
||||
%option{value: ''}
|
||||
= t('admin.customers.index.select_country')
|
||||
%option{ ng: { repeat: 'country in availableCountries' }, value: '{{country.id}}' }
|
||||
{{country.name}}
|
||||
%tr
|
||||
%td
|
||||
= t('spree.state')
|
||||
%span.required *
|
||||
%td
|
||||
%select{name: 'state', required: true, ng: {model: 'address.state_id', options: 'state.id as state.name for state in states'}}
|
||||
%select{ name: 'state', required: true, ng: { model: 'address.state_id' } }
|
||||
%option{value: ''}
|
||||
= t('admin.customers.index.select_state')
|
||||
%option{ ng: { repeat: 'state in states' }, value: '{{state.id}}' }
|
||||
{{state.name}}
|
||||
%tr
|
||||
%td
|
||||
= t('spree.phone')
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'phone', required: true, ng: { model: 'address.phone'} }
|
||||
|
||||
.text-center
|
||||
%input.button.red.icon-plus{ type: 'submit', value: 'Update Address'}
|
||||
%input.button.red.icon-plus{ type: 'submit', value: t('admin.customers.index.update_address')}
|
||||
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
{{ message }}
|
||||
.action-buttons.text-center
|
||||
%button{ ng: { click: "close()" } }
|
||||
OK
|
||||
= t(:ok)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.ofn-drop-down
|
||||
%span
|
||||
%i.icon-check
|
||||
Actions
|
||||
= t('admin.actions')
|
||||
%i{ 'ng-class' => "expanded && 'icon-caret-up' || !expanded && 'icon-caret-down'" }
|
||||
%div.menu{ 'ng-show' => "expanded" }
|
||||
%a.menu_item{ 'ng-repeat' => "link in links", href: '{{link.url}}', target: "{{link.target || '_self'}}", data: { method: "{{ link.method || 'get' }}", confirm: "{{link.confirm}}" } }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user