mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
Compare commits
611 Commits
v1.8.2
...
v1.8.11-tr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c69eebcbf | ||
|
|
63e453e2c7 | ||
|
|
ec53d9df7a | ||
|
|
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 | ||
|
|
7d149ed198 | ||
|
|
e8f96e4818 | ||
|
|
3ca42ae055 | ||
|
|
c0db23af90 | ||
|
|
db583df198 | ||
|
|
306bd25dd9 | ||
|
|
f98b25b719 | ||
|
|
1bc477f6b1 | ||
|
|
c37bf3d077 | ||
|
|
3a2e0b7eff | ||
|
|
38c63fc88b | ||
|
|
8ec2ebbf94 | ||
|
|
e00846776e | ||
|
|
8339d247f8 | ||
|
|
ed2522f6d2 | ||
|
|
63ef5de0e5 | ||
|
|
38d5682762 | ||
|
|
4c40219352 | ||
|
|
7eeee78c4e | ||
|
|
0760d4cc1f | ||
|
|
261a574da9 | ||
|
|
da55eb6d27 | ||
|
|
be51a55f16 | ||
|
|
b2e14711ac | ||
|
|
1059c170d1 | ||
|
|
08465a531d | ||
|
|
58e0b95cf6 | ||
|
|
7b5e8fa603 | ||
|
|
c70993ce75 | ||
|
|
aa6e7cba30 | ||
|
|
4529ced3f2 | ||
|
|
509564819a | ||
|
|
24d0e4fcf8 | ||
|
|
308c24caf4 | ||
|
|
10b076562f | ||
|
|
701c047a0a | ||
|
|
fa30e28335 | ||
|
|
5b964ef502 | ||
|
|
b0eebc2e45 | ||
|
|
7b2f65a965 | ||
|
|
0dc12d8791 | ||
|
|
88b9514090 | ||
|
|
e5d7b545c9 | ||
|
|
c4f81b019e | ||
|
|
528af8759d | ||
|
|
c34e9c046b | ||
|
|
baeabdd668 | ||
|
|
1de2300099 | ||
|
|
53e8056450 | ||
|
|
5773876cbc | ||
|
|
ed1f05e674 | ||
|
|
98f3e15d87 | ||
|
|
95c152420c | ||
|
|
bdb2b5cce8 | ||
|
|
22ccbd5556 | ||
|
|
81d9ec71d9 | ||
|
|
45e3f8ab3a | ||
|
|
5b40c745f3 | ||
|
|
69addf056b | ||
|
|
34d5df69a5 | ||
|
|
d160142945 | ||
|
|
8234956a61 | ||
|
|
225bed9990 | ||
|
|
7f203f5491 | ||
|
|
add39f7401 | ||
|
|
ca0c3a028d | ||
|
|
b08a642377 | ||
|
|
37ace77734 | ||
|
|
8645144231 | ||
|
|
47df8d6d8e | ||
|
|
f9b58b7b90 | ||
|
|
b957555c82 | ||
|
|
d40733d447 | ||
|
|
1f5da8699d | ||
|
|
fcd422c6ce | ||
|
|
5eecdb8c9c | ||
|
|
3b0084025a | ||
|
|
8f4cbf1d9f | ||
|
|
0dba54a4b8 | ||
|
|
61c9355ffb | ||
|
|
0830a5bd85 | ||
|
|
1054fd2d05 | ||
|
|
f03839b70c | ||
|
|
0076b1b9a0 | ||
|
|
d3ab9faede | ||
|
|
ee2c1ef195 | ||
|
|
57a2f1b339 | ||
|
|
d93d1653db | ||
|
|
140589fc2d | ||
|
|
1216da38d1 | ||
|
|
5b43d7a87a | ||
|
|
87e063593a | ||
|
|
23827d6c57 | ||
|
|
e966b474b4 | ||
|
|
1388c077ea | ||
|
|
4d1a5c6ffc | ||
|
|
1586cd3992 | ||
|
|
4db29ce322 | ||
|
|
243dfa7a93 | ||
|
|
d9d3a4a645 | ||
|
|
b13360d2d0 | ||
|
|
13cf5d29de | ||
|
|
1257ee09f2 | ||
|
|
e3173c955d | ||
|
|
69382c4c13 | ||
|
|
0b84afd67a | ||
|
|
6f947380cb | ||
|
|
160c535fd7 | ||
|
|
377074416e | ||
|
|
932edeb1c1 | ||
|
|
d3ad823d97 | ||
|
|
b637b5b75a | ||
|
|
eb8cedc497 | ||
|
|
ba854d12c8 | ||
|
|
9e03a130c2 | ||
|
|
dee0fa6724 | ||
|
|
84c434c279 | ||
|
|
f8898bc722 | ||
|
|
2b7da4738c | ||
|
|
11a702667d | ||
|
|
11ec903131 | ||
|
|
e57c06c610 | ||
|
|
984641e46c | ||
|
|
477d48e9da | ||
|
|
ddb54d1924 | ||
|
|
c6bd548413 | ||
|
|
af6d0ec107 | ||
|
|
e693f71775 | ||
|
|
0ff1c95c3d | ||
|
|
b5bc3a4ca3 | ||
|
|
b587a72eb6 | ||
|
|
8e73a2e0d6 | ||
|
|
e373284934 | ||
|
|
b5a9a1b6bf | ||
|
|
13c8f0a230 | ||
|
|
f733c7f207 | ||
|
|
d3c423f7ce | ||
|
|
52f68dac33 | ||
|
|
f984871b23 | ||
|
|
f09cd9e477 | ||
|
|
d6f21b24da | ||
|
|
34b2f72ae8 | ||
|
|
e6bdd2303d | ||
|
|
a9a68151ec | ||
|
|
f586dbc3e1 | ||
|
|
5fb5ef1974 | ||
|
|
54028f4e7e | ||
|
|
e8b83bef41 | ||
|
|
78b22c4a82 | ||
|
|
e252414263 | ||
|
|
320db21d5c | ||
|
|
c253d73d11 | ||
|
|
08fdc8a5bd | ||
|
|
12df5de43c | ||
|
|
4da7668dfc | ||
|
|
9c29e56fc3 | ||
|
|
e253590c1c | ||
|
|
43b5216002 | ||
|
|
e7adacc541 | ||
|
|
fa52712e35 | ||
|
|
36093c0f64 | ||
|
|
02d8f52426 | ||
|
|
5b22e19ec9 | ||
|
|
99d22649a2 | ||
|
|
98548e15c5 | ||
|
|
f37f89dd07 | ||
|
|
ed37604bc2 | ||
|
|
e284ad62b2 | ||
|
|
61a4228e6b | ||
|
|
f0a2098826 |
@@ -45,7 +45,7 @@ script:
|
||||
|
||||
after_success:
|
||||
- >
|
||||
if [ "$GITHUB_DEPLOY" = "true" -a "$TRAVIS_PULL_REQUEST" = "false" -a -n "$TRAVIS_BRANCH" -a -n "$GITHUB_API_SECRET" ]; then
|
||||
if [ "$GITHUB_DEPLOY" = "true" -a "$TRAVIS_PULL_REQUEST" = "false" -a -n "$TRAVIS_BRANCH" -a "$TRAVIS_BRANCH" != "transifex" -a -n "$GITHUB_API_SECRET" ]; then
|
||||
description="`git show "$TRAVIS_BRANCH" -s --oneline --no-color`"
|
||||
data="{
|
||||
\"ref\":\"$TRAVIS_BRANCH\",
|
||||
|
||||
@@ -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
|
||||
|
||||
9
Gemfile
9
Gemfile
@@ -9,7 +9,7 @@ gem 'i18n', '~> 0.6.11'
|
||||
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'
|
||||
|
||||
@@ -21,7 +21,6 @@ gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_e
|
||||
|
||||
gem 'delayed_job_active_record'
|
||||
gem 'daemons'
|
||||
gem 'comfortable_mexican_sofa'
|
||||
|
||||
# Fix bug in simple_form preventing collection_check_boxes usage within form_for block
|
||||
# When merged, revert to upstream gem
|
||||
@@ -51,7 +50,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'
|
||||
@@ -64,6 +63,7 @@ gem 'wkhtmltopdf-binary'
|
||||
|
||||
gem 'foreigner'
|
||||
gem 'immigrant'
|
||||
gem 'roo', '~> 2.7.0'
|
||||
|
||||
gem 'whenever', require: false
|
||||
|
||||
@@ -88,8 +88,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
|
||||
@@ -113,7 +115,6 @@ end
|
||||
|
||||
group :test do
|
||||
gem 'webmock'
|
||||
|
||||
# See spec/spec_helper.rb for instructions
|
||||
#gem 'perftools.rb'
|
||||
end
|
||||
|
||||
134
Gemfile.lock
134
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
|
||||
@@ -121,11 +131,10 @@ GEM
|
||||
rack-cache (~> 1.2)
|
||||
rack-test (~> 0.6.1)
|
||||
sprockets (~> 2.2.1)
|
||||
active_link_to (1.0.0)
|
||||
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)
|
||||
@@ -152,7 +161,7 @@ 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)
|
||||
@@ -168,9 +177,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)
|
||||
@@ -190,7 +197,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)
|
||||
@@ -202,10 +209,6 @@ GEM
|
||||
coffee-script-source (1.10.0)
|
||||
colorize (0.7.7)
|
||||
columnize (0.9.0)
|
||||
comfortable_mexican_sofa (1.6.24)
|
||||
active_link_to (~> 1.0.0)
|
||||
paperclip (>= 2.3.0)
|
||||
rails (>= 3.0.0)
|
||||
compass (1.0.3)
|
||||
chunky_png (~> 1.2)
|
||||
compass-core (~> 1.0.2)
|
||||
@@ -226,7 +229,7 @@ GEM
|
||||
safe_yaml (~> 0.9.0)
|
||||
css_parser (1.3.5)
|
||||
addressable
|
||||
css_splitter (0.4.1)
|
||||
css_splitter (0.4.5)
|
||||
sprockets (>= 2.0.0)
|
||||
daemons (1.2.2)
|
||||
dalli (2.7.2)
|
||||
@@ -409,12 +412,12 @@ GEM
|
||||
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)
|
||||
immigrant (0.1.6)
|
||||
activerecord (>= 3.0)
|
||||
@@ -422,16 +425,18 @@ GEM
|
||||
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
|
||||
@@ -454,9 +459,10 @@ GEM
|
||||
mini_portile2 (2.0.0)
|
||||
momentjs-rails (2.5.1)
|
||||
railties (>= 3.1)
|
||||
money (5.1.1)
|
||||
i18n (~> 0.6.0)
|
||||
multi_json (1.12.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)
|
||||
nokogiri (1.6.7.2)
|
||||
@@ -499,7 +505,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
|
||||
@@ -526,7 +532,7 @@ GEM
|
||||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
raindrops (0.13.0)
|
||||
rake (10.4.2)
|
||||
rake (11.1.2)
|
||||
ransack (0.7.2)
|
||||
actionpack (~> 3.0)
|
||||
activerecord (~> 3.0)
|
||||
@@ -552,6 +558,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)
|
||||
@@ -570,13 +579,14 @@ GEM
|
||||
rspec-retry (0.4.2)
|
||||
rspec-core
|
||||
ruby-progressbar (1.7.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)
|
||||
@@ -588,14 +598,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
|
||||
@@ -606,7 +616,7 @@ 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)
|
||||
@@ -633,9 +643,8 @@ 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)
|
||||
@@ -650,7 +659,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
|
||||
@@ -659,7 +668,6 @@ DEPENDENCIES
|
||||
bugsnag
|
||||
capybara
|
||||
coffee-rails (~> 3.2.1)
|
||||
comfortable_mexican_sofa
|
||||
compass-rails
|
||||
css_splitter
|
||||
custom_error_message!
|
||||
@@ -688,6 +696,7 @@ DEPENDENCIES
|
||||
haml
|
||||
i18n (~> 0.6.11)
|
||||
immigrant
|
||||
jquery-migrate-rails
|
||||
jquery-rails
|
||||
json_spec
|
||||
knapsack
|
||||
@@ -695,6 +704,7 @@ DEPENDENCIES
|
||||
momentjs-rails
|
||||
newrelic_rpm
|
||||
nokogiri (>= 1.6.7.1)
|
||||
ofn-qz!
|
||||
oj
|
||||
paper_trail (~> 3.0.8)
|
||||
paperclip
|
||||
@@ -710,6 +720,7 @@ DEPENDENCIES
|
||||
redcarpet
|
||||
representative_view
|
||||
roadie-rails (~> 1.0.3)
|
||||
roo (~> 2.7.0)
|
||||
rspec-rails
|
||||
rspec-retry
|
||||
sass (~> 3.3)
|
||||
@@ -734,5 +745,8 @@ DEPENDENCIES
|
||||
wicked_pdf
|
||||
wkhtmltopdf-binary
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.1.5p273
|
||||
|
||||
BUNDLED WITH
|
||||
1.11.2
|
||||
1.14.3
|
||||
|
||||
@@ -98,6 +98,14 @@ 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
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
2
Rakefile
2
Rakefile
@@ -2,7 +2,7 @@
|
||||
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
||||
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
||||
|
||||
require File.expand_path('../config/application', __FILE__)
|
||||
require_relative 'config/application'
|
||||
|
||||
Openfoodnetwork::Application.load_tasks
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filter, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, pendingChanges, shops) ->
|
||||
angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filter, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, pendingChanges, shops, availableCountries) ->
|
||||
$scope.shops = shops
|
||||
$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) ->
|
||||
@@ -16,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)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
angular.module("admin.customers").directive 'editAddressDialog', ($compile, $templateCache, $filter, DialogDefaults, Customers, StatusMessage) ->
|
||||
restrict: 'A'
|
||||
scope: true
|
||||
link: (scope, element, attr) ->
|
||||
scope.errors = []
|
||||
|
||||
scope.$watch 'address.country_id', (newVal) ->
|
||||
if newVal
|
||||
scope.states = scope.filter_states(newVal)
|
||||
|
||||
scope.updateAddress = ->
|
||||
scope.edit_address_form.$setPristine()
|
||||
if scope.edit_address_form.$valid
|
||||
Customers.update(scope.address, scope.customer, scope.addressType).$promise.then (data) ->
|
||||
scope.customer = data
|
||||
template.dialog('close')
|
||||
StatusMessage.display('success', t('admin.customers.index.update_address_success'))
|
||||
else
|
||||
scope.errors.push(t('admin.customers.index.update_address_error'))
|
||||
|
||||
|
||||
template = $compile($templateCache.get('admin/edit_address_dialog.html'))(scope)
|
||||
template.dialog(DialogDefaults)
|
||||
|
||||
element.bind 'click', (e) ->
|
||||
if e.target.id == 'bill-address-link'
|
||||
scope.addressType = 'bill_address'
|
||||
else
|
||||
scope.addressType = 'ship_address'
|
||||
scope.address = scope.customer[scope.addressType]
|
||||
|
||||
template.dialog('open')
|
||||
scope.$apply()
|
||||
|
||||
scope.filter_states = (countryID) ->
|
||||
$filter('filter')(scope.availableCountries, {id: countryID})[0].states
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.customers").directive 'newCustomerDialog', ($compile, $injector, $templateCache, DialogDefaults, CurrentShop, Customers) ->
|
||||
angular.module("admin.customers").directive 'newCustomerDialog', ($compile, $templateCache, DialogDefaults, CurrentShop, Customers) ->
|
||||
restrict: 'A'
|
||||
scope: true
|
||||
link: (scope, element, attr) ->
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestMonitor, CustomerResource, CurrentShop) ->
|
||||
new class Customers
|
||||
customers: []
|
||||
|
||||
add: (email) ->
|
||||
params =
|
||||
enterprise_id: CurrentShop.shop.id
|
||||
email: email
|
||||
CustomerResource.create params, (customer) =>
|
||||
@customers.unshift customer if customer.id
|
||||
|
||||
remove: (customer) ->
|
||||
params = id: customer.id
|
||||
CustomerResource.destroy params, =>
|
||||
i = @customers.indexOf customer
|
||||
@customers.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}"
|
||||
|
||||
index: (params) ->
|
||||
request = CustomerResource.index(params, (data) => @customers = data)
|
||||
RequestMonitor.load(request.$promise)
|
||||
request.$promise
|
||||
@@ -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?
|
||||
|
||||
@@ -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')
|
||||
@@ -24,7 +24,7 @@ angular.module("admin.indexUtils").directive "objForUpdate", (switchClass, pendi
|
||||
scope.savedValue = value
|
||||
|
||||
scope.success = ->
|
||||
switchClass( element, "update-success", ["update-pending", "update-error"], 3000 )
|
||||
switchClass( element, "update-success", ["update-pending", "update-error"], 5000 )
|
||||
|
||||
scope.pending = ->
|
||||
switchClass( element, "update-pending", ["update-error", "update-success"], false )
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
angular.module("admin.indexUtils").factory "switchClass", ($timeout) ->
|
||||
return (element,classToAdd,removeClasses,timeout) ->
|
||||
return (element, classToAdd, removeClasses, timeout) ->
|
||||
$timeout.cancel element.timeout if element.timeout
|
||||
element.removeClass className for className in removeClasses
|
||||
element.addClass classToAdd
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,6 +80,7 @@ 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)
|
||||
|
||||
@@ -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]]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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,15 @@
|
||||
angular.module("ofn.admin").controller "ImportOptionsFormCtrl", ($scope, $rootScope, ProductImportService) ->
|
||||
|
||||
$scope.toggleResetAbsent = () ->
|
||||
confirmed = confirm 'This will set stock level to zero on all products for this \n' +
|
||||
'enterprise that are not present in the uploaded file.' 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'
|
||||
@@ -14,4 +14,8 @@ angular.module("admin.customers").factory 'CustomerResource', ($resource) ->
|
||||
method: 'DELETE'
|
||||
params:
|
||||
id: '@id'
|
||||
'update':
|
||||
method: 'PUT'
|
||||
params:
|
||||
id: '@id'
|
||||
})
|
||||
@@ -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'
|
||||
@@ -0,0 +1,49 @@
|
||||
angular.module("admin.resources").factory "Customers", ($q, InfoDialog, RequestMonitor, CustomerResource, CurrentShop) ->
|
||||
new class Customers
|
||||
all: []
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
add: (email) ->
|
||||
params =
|
||||
enterprise_id: CurrentShop.shop.id
|
||||
email: email
|
||||
CustomerResource.create params, (customer) =>
|
||||
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 = @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}"
|
||||
|
||||
index: (params) ->
|
||||
@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
|
||||
customer:
|
||||
"#{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,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
|
||||
@@ -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()
|
||||
@@ -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 != ''
|
||||
|
||||
|
||||
@@ -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,10 +1,2 @@
|
||||
Darkswarm.controller "CartCtrl", ($scope, Cart, $timeout) ->
|
||||
$scope.Cart = Cart
|
||||
initializing = true
|
||||
|
||||
$scope.$watchCollection "Cart.line_items_present()", ->
|
||||
if initializing
|
||||
$timeout ->
|
||||
initializing = false
|
||||
else
|
||||
$scope.Cart.orderChanged()
|
||||
|
||||
@@ -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)
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) ->
|
||||
Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, $location, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) ->
|
||||
$scope.Enterprises = Enterprises
|
||||
$scope.producers_to_filter = Enterprises.producers
|
||||
$scope.filterSelectors = FilterSelectorsService.createSelectors()
|
||||
@@ -21,6 +21,12 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris
|
||||
Enterprises.calculateDistance query, $scope.firstNameMatch()
|
||||
$rootScope.$broadcast 'enterprisesChanged'
|
||||
|
||||
$timeout ->
|
||||
if $location.search()['show_closed']?
|
||||
$scope.showClosedShops()
|
||||
|
||||
$scope.$watch "filtersActive", (value) ->
|
||||
$scope.$broadcast 'filtersToggled'
|
||||
|
||||
$rootScope.$on "enterprisesChanged", ->
|
||||
$scope.filterEnterprises()
|
||||
@@ -30,7 +36,7 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris
|
||||
# When filter settings change, this could change which name match is at the top, or even
|
||||
# result in no matches. This affects the reference point that the distance matches are
|
||||
# calculated from, so we need to recalculate distances.
|
||||
$scope.$watch '[activeTaxons, shippingTypes, show_profiles]', ->
|
||||
$scope.$watch '[activeTaxons, activeProperties, shippingTypes, show_profiles]', ->
|
||||
$timeout ->
|
||||
Enterprises.calculateDistance $scope.query, $scope.firstNameMatch()
|
||||
$rootScope.$broadcast 'enterprisesChanged'
|
||||
@@ -69,6 +75,8 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris
|
||||
|
||||
$scope.showClosedShops = ->
|
||||
delete $scope.filterExpression['active']
|
||||
$location.search('show_closed', '1')
|
||||
|
||||
$scope.hideClosedShops = ->
|
||||
$scope.filterExpression['active'] = true
|
||||
$location.search('show_closed', null)
|
||||
|
||||
@@ -8,3 +8,6 @@ Darkswarm.controller "GroupEnterprisesCtrl", ($scope, Search, FilterSelectorsSer
|
||||
|
||||
$scope.$watch "query", (query)->
|
||||
Search.search query
|
||||
|
||||
$scope.$watch "filtersActive", (value) ->
|
||||
$scope.$broadcast 'filtersToggled'
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
Darkswarm.controller "GroupsCtrl", ($scope, Groups) ->
|
||||
Darkswarm.controller "GroupsCtrl", ($scope, Groups, Search) ->
|
||||
$scope.Groups = Groups
|
||||
$scope.order = 'position'
|
||||
$scope.query = Search.search()
|
||||
|
||||
$scope.$watch "query", (query)->
|
||||
Search.search query
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
Darkswarm.controller "LineItemCtrl", ($scope)->
|
||||
$scope.$watch '[line_item.quantity, line_item.max_quantity]', (newValue, oldValue)->
|
||||
if newValue != oldValue
|
||||
$scope.Cart.orderChanged()
|
||||
, true
|
||||
@@ -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()
|
||||
|
||||
@@ -1,18 +1,41 @@
|
||||
Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Products, OrderCycle, FilterSelectorsService, Cart, Taxons, Properties) ->
|
||||
Darkswarm.controller "ProductsCtrl", ($scope, $filter, $rootScope, Products, OrderCycle, FilterSelectorsService, Cart, Taxons, Properties) ->
|
||||
$scope.Products = Products
|
||||
$scope.Cart = Cart
|
||||
$scope.query = ""
|
||||
$scope.taxonSelectors = FilterSelectorsService.createSelectors()
|
||||
$scope.propertySelectors = FilterSelectorsService.createSelectors()
|
||||
$scope.filtersActive = true
|
||||
$scope.limit = 3
|
||||
$scope.limit = 10
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
# $scope.infiniteDisabled = true
|
||||
|
||||
# All of this logic basically just replicates the functionality filtering an ng-repeat
|
||||
# except that it allows us to filter a separate list before rendering, meaning that
|
||||
# we can get much better performance when applying filters by resetting the limit on the
|
||||
# number of products being rendered each time a filter is changed.
|
||||
|
||||
$scope.$watch "Products.loading", (newValue, oldValue) ->
|
||||
$scope.updateFilteredProducts()
|
||||
$scope.$broadcast("loadFilterSelectors") if !newValue
|
||||
|
||||
$scope.incrementLimit = ->
|
||||
if $scope.limit < Products.products.length
|
||||
$scope.limit = $scope.limit + 1
|
||||
$scope.limit += 10
|
||||
$scope.updateVisibleProducts()
|
||||
|
||||
$scope.$watch 'query', -> $scope.updateFilteredProducts()
|
||||
$scope.$watchCollection 'activeTaxons', -> $scope.updateFilteredProducts()
|
||||
$scope.$watchCollection 'activeProperties', -> $scope.updateFilteredProducts()
|
||||
|
||||
$scope.updateFilteredProducts = ->
|
||||
$scope.limit = 10
|
||||
f1 = $filter('products')(Products.products, $scope.query)
|
||||
f2 = $filter('taxons')(f1, $scope.activeTaxons)
|
||||
$scope.filteredProducts = $filter('properties')(f2, $scope.activeProperties)
|
||||
$scope.updateVisibleProducts()
|
||||
|
||||
$scope.updateVisibleProducts = ->
|
||||
$scope.visibleProducts = $filter('limitTo')($scope.filteredProducts, $scope.limit)
|
||||
|
||||
$scope.searchKeypress = (e)->
|
||||
code = e.keyCode || e.which
|
||||
|
||||
@@ -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()
|
||||
@@ -1,9 +1,15 @@
|
||||
Darkswarm.directive "enterpriseModal", ($modal)->
|
||||
Darkswarm.directive "enterpriseModal", ($modal, Enterprises, EnterpriseResource) ->
|
||||
restrict: 'E'
|
||||
replace: true
|
||||
template: "<a ng-transclude></a>"
|
||||
transclude: true
|
||||
link: (scope, elem, attrs, ctrl)->
|
||||
elem.on "click", (ev)=>
|
||||
link: (scope, elem, attrs, ctrl) ->
|
||||
elem.on "click", (ev) =>
|
||||
ev.stopPropagation()
|
||||
params =
|
||||
id: scope.enterprise.id
|
||||
EnterpriseResource.relatives params, (data) =>
|
||||
Enterprises.addEnterprises data
|
||||
scope.enterprise = Enterprises.enterprises_by_id[scope.enterprise.id]
|
||||
Enterprises.dereferenceEnterprise scope.enterprise
|
||||
scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'enterprise_modal.html', scope: scope)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
Darkswarm.directive 'mapOsmTiles', ($timeout) ->
|
||||
restrict: 'E'
|
||||
require: '^googleMap'
|
||||
scope: {}
|
||||
link: (scope, elem, attrs, ctrl) ->
|
||||
$timeout =>
|
||||
map = ctrl.getMap()
|
||||
|
||||
map.mapTypes.set 'OSM', new google.maps.ImageMapType
|
||||
getTileUrl: (coord, zoom) ->
|
||||
# "Wrap" x (logitude) at 180th meridian properly
|
||||
# NB: Don't touch coord.x because coord param is by reference, and changing its x property breaks something in Google's lib
|
||||
tilesPerGlobe = 1 << zoom
|
||||
x = coord.x % tilesPerGlobe
|
||||
if x < 0
|
||||
x = tilesPerGlobe + x
|
||||
# Wrap y (latitude) in a like manner if you want to enable vertical infinite scroll
|
||||
'https://a.tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png'
|
||||
tileSize: new google.maps.Size(256, 256)
|
||||
name: 'OpenStreetMap'
|
||||
maxZoom: 18
|
||||
@@ -1,46 +1,54 @@
|
||||
Darkswarm.directive 'mapSearch', ($timeout)->
|
||||
Darkswarm.directive 'mapSearch', ($timeout, Search) ->
|
||||
# Install a basic search field in a map
|
||||
restrict: 'E'
|
||||
require: '^googleMap'
|
||||
require: ['^googleMap', 'ngModel']
|
||||
replace: true
|
||||
template: '<input id="pac-input" placeholder="' + t('location_placeholder') + '"></input>'
|
||||
link: (scope, elem, attrs, ctrl)->
|
||||
template: '<input id="pac-input" ng-model="query" placeholder="' + t('location_placeholder') + '"></input>'
|
||||
scope: {}
|
||||
|
||||
controller: ($scope) ->
|
||||
$scope.query = Search.search()
|
||||
|
||||
$scope.$watch 'query', (query) ->
|
||||
Search.search query
|
||||
|
||||
|
||||
link: (scope, elem, attrs, ctrls) ->
|
||||
[ctrl, model] = ctrls
|
||||
scope.input = document.getElementById("pac-input")
|
||||
|
||||
$timeout =>
|
||||
map = ctrl.getMap()
|
||||
|
||||
# Use OSM tiles server
|
||||
map.mapTypes.set 'OSM', new (google.maps.ImageMapType)(
|
||||
getTileUrl: (coord, zoom) ->
|
||||
# "Wrap" x (logitude) at 180th meridian properly
|
||||
# NB: Don't touch coord.x because coord param is by reference, and changing its x property breakes something in Google's lib
|
||||
tilesPerGlobe = 1 << zoom
|
||||
x = coord.x % tilesPerGlobe
|
||||
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'
|
||||
tileSize: new (google.maps.Size)(256, 256)
|
||||
name: 'OpenStreetMap'
|
||||
maxZoom: 18)
|
||||
searchBox = scope.createSearchBox map
|
||||
scope.bindSearchResponse map, searchBox
|
||||
scope.biasResults map, searchBox
|
||||
scope.performUrlSearch map
|
||||
|
||||
input = (document.getElementById("pac-input"))
|
||||
map.controls[google.maps.ControlPosition.TOP_LEFT].push input
|
||||
searchBox = new google.maps.places.SearchBox((input))
|
||||
scope.createSearchBox = (map) ->
|
||||
map.controls[google.maps.ControlPosition.TOP_LEFT].push scope.input
|
||||
return new google.maps.places.SearchBox(scope.input)
|
||||
|
||||
google.maps.event.addListener searchBox, "places_changed", ->
|
||||
places = searchBox.getPlaces()
|
||||
return if places.length is 0
|
||||
# For each place, get the icon, place name, and location.
|
||||
markers = []
|
||||
bounds = new google.maps.LatLngBounds()
|
||||
for place in places
|
||||
#map.setCenter place.geometry.location
|
||||
map.fitBounds place.geometry.viewport
|
||||
#map.fitBounds bounds
|
||||
scope.bindSearchResponse = (map, searchBox) ->
|
||||
google.maps.event.addListener searchBox, "places_changed", =>
|
||||
scope.showSearchResult map, searchBox
|
||||
|
||||
# Bias the SearchBox results towards places that are within the bounds of the
|
||||
# current map's viewport.
|
||||
scope.showSearchResult = (map, searchBox) ->
|
||||
places = searchBox.getPlaces()
|
||||
for place in places when place.geometry.viewport?
|
||||
map.fitBounds place.geometry.viewport
|
||||
scope.$apply ->
|
||||
model.$setViewValue elem.val()
|
||||
|
||||
# When the map loads, and we have a search from ?query, perform that search
|
||||
scope.performUrlSearch = (map) ->
|
||||
google.maps.event.addListenerOnce map, "idle", =>
|
||||
google.maps.event.trigger(scope.input, 'focus');
|
||||
google.maps.event.trigger(scope.input, 'keydown', {keyCode: 13});
|
||||
|
||||
# Bias the SearchBox results towards places that are within the bounds of the
|
||||
# current map's viewport.
|
||||
scope.biasResults = (map, searchBox) ->
|
||||
google.maps.event.addListener map, "bounds_changed", ->
|
||||
bounds = map.getBounds()
|
||||
searchBox.setBounds bounds
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
Darkswarm.directive "shopVariant", ->
|
||||
Darkswarm.directive "shopVariant", ->
|
||||
restrict: 'E'
|
||||
replace: true
|
||||
templateUrl: 'shop_variant.html'
|
||||
scope:
|
||||
variant: '='
|
||||
controller: ($scope, Cart) ->
|
||||
$scope.$watchGroup ['variant.line_item.quantity', 'variant.line_item.max_quantity'], ->
|
||||
Cart.adjust($scope.variant.line_item)
|
||||
|
||||
@@ -6,40 +6,15 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) ->
|
||||
objects: "&"
|
||||
activeSelectors: "="
|
||||
selectorName: "@activeSelectors"
|
||||
link: (scope,element,attrs) ->
|
||||
link: (scope, element, attrs) ->
|
||||
scope.fitting = false
|
||||
|
||||
scope.overFlowSelectors = ->
|
||||
return [] unless scope.allSelectors?
|
||||
$filter('filter')(scope.allSelectors, { fits: false })
|
||||
|
||||
scope.selectedOverFlowSelectors = ->
|
||||
$filter('filter')(scope.overFlowSelectors(), { active: true })
|
||||
|
||||
# had to duplicate this to make overflow selectors work
|
||||
scope.emit = ->
|
||||
scope.activeSelectors = scope.allSelectors.filter (selector)->
|
||||
selector.active
|
||||
.map (selector)->
|
||||
selector.object.id
|
||||
|
||||
# From: http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
|
||||
debouncer = (func, timeout) ->
|
||||
timeoutID = undefined
|
||||
timeout = timeout or 50
|
||||
->
|
||||
subject = this
|
||||
args = arguments
|
||||
clearTimeout timeoutID
|
||||
timeoutID = setTimeout(->
|
||||
func.apply subject, Array::slice.call(args)
|
||||
, timeout)
|
||||
|
||||
loadWidths = ->
|
||||
$(element).find("li").not(".more").each (i) ->
|
||||
scope.allSelectors[i].width = $(this).outerWidth(true)
|
||||
return null # So we don't exit the loop weirdly
|
||||
|
||||
scope.refit = ->
|
||||
if scope.allSelectors?
|
||||
scope.fitting = true
|
||||
selector.fits = true for selector in scope.allSelectors
|
||||
$timeout(loadWidths, 0, true).then ->
|
||||
$timeout fit, 0, true
|
||||
|
||||
fit = ->
|
||||
used = $(element).find("li.more").outerWidth(true)
|
||||
@@ -61,12 +36,45 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) ->
|
||||
available += selector.width
|
||||
scope.fitting = false
|
||||
|
||||
loadWidths = ->
|
||||
$(element).find("li").not(".more").each (i) ->
|
||||
if i < scope.allSelectors.length
|
||||
scope.allSelectors[i].width = $(this).outerWidth(true)
|
||||
return null # So we don't exit the loop weirdly
|
||||
|
||||
scope.overFlowSelectors = ->
|
||||
return [] unless scope.allSelectors?
|
||||
$filter('filter')(scope.allSelectors, { fits: false })
|
||||
|
||||
scope.selectedOverFlowSelectors = ->
|
||||
$filter('filter')(scope.overFlowSelectors(), { active: true })
|
||||
|
||||
# had to duplicate this to make overflow selectors work
|
||||
scope.emit = ->
|
||||
scope.activeSelectors = scope.allSelectors.filter (selector)->
|
||||
selector.active
|
||||
.map (selector) ->
|
||||
selector.object.id
|
||||
|
||||
# From: http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
|
||||
debouncer = (func, timeout) ->
|
||||
timeoutID = undefined
|
||||
timeout = timeout or 50
|
||||
->
|
||||
subject = this
|
||||
args = arguments
|
||||
clearTimeout timeoutID
|
||||
timeoutID = setTimeout(->
|
||||
func.apply subject, Array::slice.call(args)
|
||||
, timeout)
|
||||
|
||||
|
||||
# -- Event management
|
||||
scope.$watchCollection "allSelectors", ->
|
||||
if scope.allSelectors?
|
||||
scope.fitting = true
|
||||
selector.fits = true for selector in scope.allSelectors
|
||||
$timeout(loadWidths, 0, true).then ->
|
||||
$timeout fit, 0, true
|
||||
scope.refit()
|
||||
|
||||
scope.$on "filtersToggled", ->
|
||||
scope.refit()
|
||||
|
||||
$(window).resize debouncer (e) ->
|
||||
scope.fitting = true
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
Darkswarm.directive "ofnSmoothScrollTo", ($location, $document)->
|
||||
# Onclick sets $location.hash to attrs.ofnScrollTo
|
||||
# Then triggers $document.scrollTo
|
||||
restrict: 'A'
|
||||
link: (scope, element, attrs)->
|
||||
element.bind 'click', (ev)->
|
||||
ev.stopPropagation()
|
||||
$location.hash attrs.ofnScrollTo
|
||||
target = $("a[name='#{attrs.ofnSmoothScrollTo}']")
|
||||
# Scrolling is confused by our position:fixed top bar and page alert bar
|
||||
# - add an offset to scroll to the correct location, plus 5px buffer
|
||||
offset = $("nav.top-bar").height()
|
||||
offset += $(".page-alert.move-down").height()
|
||||
offset += 5
|
||||
$document.scrollTo target, offset, 1000
|
||||
@@ -1,7 +1,8 @@
|
||||
Darkswarm.filter 'products', (Matcher)->
|
||||
(products, text)->
|
||||
Darkswarm.filter 'products', (Matcher) ->
|
||||
(products, text) ->
|
||||
products ||= []
|
||||
text ?= ""
|
||||
products.filter (product)=>
|
||||
propertiesToMatch = [product.name, product.supplier.name, product.primary_taxon.name]
|
||||
return products if text == ""
|
||||
products.filter (product) =>
|
||||
propertiesToMatch = [product.name, product.variant_names, product.supplier.name, product.primary_taxon.name]
|
||||
Matcher.match propertiesToMatch, text
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
Darkswarm.filter 'properties', ()->
|
||||
# Filter anything that responds to object.properties
|
||||
(objects, ids) ->
|
||||
Darkswarm.filter 'properties', ->
|
||||
# Filter anything that responds to object.supplied_properties
|
||||
(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.properties
|
||||
# Combine object properties with supplied properties, if they exist.
|
||||
# properties = properties.concat obj.supplied_properties if obj.supplied_properties
|
||||
# Match property array.
|
||||
properties.some (property)->
|
||||
objects.filter (obj) ->
|
||||
properties = obj[source]
|
||||
properties.some (property) ->
|
||||
property.id in ids
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
Darkswarm.filter 'propertiesOf', ->
|
||||
(objects)->
|
||||
(objects, source) ->
|
||||
source ||= 'properties'
|
||||
return {} unless source in ['properties', 'supplied_properties', 'distributed_properties']
|
||||
|
||||
properties = {}
|
||||
for object in objects
|
||||
for property in object.properties
|
||||
properties[property.id] = property
|
||||
if object[source]?
|
||||
for property in object[source]
|
||||
properties[property.id] = property
|
||||
|
||||
properties
|
||||
|
||||
@@ -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,12 +6,24 @@ 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
|
||||
line_item.variant.extended_name = @extendedVariantName(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
|
||||
if line_item.quantity > 0
|
||||
@line_items.push line_item unless line_item in @line_items
|
||||
else
|
||||
index = @line_items.indexOf(line_item)
|
||||
@line_items.splice(index, 1) if index >= 0
|
||||
@orderChanged()
|
||||
|
||||
orderChanged: =>
|
||||
@unsaved()
|
||||
@@ -48,7 +60,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
|
||||
# TODO: These changes to quantity/max_quantity trigger another cart update, which
|
||||
# is unnecessary.
|
||||
|
||||
for li in @line_items_present()
|
||||
for li in @line_items when li.quantity > 0
|
||||
if stockLevels[li.variant.id]?
|
||||
li.variant.count_on_hand = stockLevels[li.variant.id].on_hand
|
||||
if li.quantity > li.variant.count_on_hand
|
||||
@@ -67,7 +79,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
|
||||
|
||||
data: =>
|
||||
variants = {}
|
||||
for li in @line_items_present()
|
||||
for li in @line_items when li.quantity > 0
|
||||
variants[li.variant.id] =
|
||||
quantity: li.quantity
|
||||
max_quantity: li.max_quantity
|
||||
@@ -89,45 +101,33 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
|
||||
$(window).bind "beforeunload", ->
|
||||
t 'order_not_saved_yet'
|
||||
|
||||
line_items_present: =>
|
||||
@line_items.filter (li)->
|
||||
li.quantity > 0
|
||||
|
||||
total_item_count: =>
|
||||
@line_items_present().reduce (sum,li) ->
|
||||
@line_items.reduce (sum,li) ->
|
||||
sum = sum + li.quantity
|
||||
, 0
|
||||
|
||||
empty: =>
|
||||
@line_items_present().length == 0
|
||||
@line_items.length == 0
|
||||
|
||||
total: =>
|
||||
@line_items_present().map (li)->
|
||||
li.variant.totalPrice()
|
||||
@line_items.map (li)->
|
||||
li.total_price
|
||||
.reduce (t, price)->
|
||||
t + price
|
||||
, 0
|
||||
|
||||
register_variant: (variant)=>
|
||||
exists = @line_items.some (li)-> li.variant == variant
|
||||
@create_line_item(variant) unless exists
|
||||
|
||||
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
|
||||
|
||||
create_line_item: (variant)->
|
||||
variant.extended_name = @extendedVariantName(variant)
|
||||
variant.line_item =
|
||||
variant: variant
|
||||
quantity: null
|
||||
max_quantity: null
|
||||
@line_items.push variant.line_item
|
||||
removeFinalisedLineItem: (id) =>
|
||||
@line_items_finalised = @line_items_finalised.filter (item) ->
|
||||
item.id != id
|
||||
|
||||
extendedVariantName: (variant) =>
|
||||
if variant.product_name == variant.name_to_display
|
||||
variant.product_name
|
||||
else
|
||||
name = "#{variant.product_name} - #{variant.name_to_display}"
|
||||
name += " (#{variant.options_text})" if variant.options_text
|
||||
name
|
||||
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,6 +1,17 @@
|
||||
Darkswarm.factory 'Dereferencer', ->
|
||||
new class Dereferencer
|
||||
dereference: (array, data)->
|
||||
if array
|
||||
for object, i in array
|
||||
array[i] = data[object.id]
|
||||
dereference: (array, data) ->
|
||||
@dereference_from(array, array, data)
|
||||
|
||||
dereference_from: (source, target, data) ->
|
||||
unreferenced = []
|
||||
if source && target
|
||||
for object, i in source
|
||||
# skip empty entries in sparse array
|
||||
continue unless source.hasOwnProperty(i)
|
||||
key = object?.id
|
||||
if data.hasOwnProperty(key)
|
||||
target[i] = data[key]
|
||||
else
|
||||
unreferenced[i] = object
|
||||
unreferenced
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Darkswarm.factory 'EnterpriseResource', ($resource) ->
|
||||
$resource('/enterprise/:id.json', {}, {
|
||||
'relatives':
|
||||
method: 'GET'
|
||||
url: '/enterprises/:id/relatives.json'
|
||||
isArray: true
|
||||
cache: true
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope)->
|
||||
Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope) ->
|
||||
new class Enterprises
|
||||
enterprises_by_id: {}
|
||||
constructor: ->
|
||||
@@ -9,7 +9,6 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer,
|
||||
@enterprises_by_id[enterprise.id] = enterprise
|
||||
# Replace enterprise and taxons ids with actual objects.
|
||||
@dereferenceEnterprises()
|
||||
@dereferenceTaxons()
|
||||
@visible_enterprises = visibleFilter @enterprises
|
||||
@producers = @visible_enterprises.filter (enterprise)->
|
||||
enterprise.category in ["producer_hub", "producer_shop", "producer"]
|
||||
@@ -20,13 +19,27 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer,
|
||||
if CurrentHub.hub?.id
|
||||
CurrentHub.hub = @enterprises_by_id[CurrentHub.hub.id]
|
||||
for enterprise in @enterprises
|
||||
Dereferencer.dereference enterprise.hubs, @enterprises_by_id
|
||||
Dereferencer.dereference enterprise.producers, @enterprises_by_id
|
||||
@dereferenceEnterprise enterprise
|
||||
|
||||
dereferenceTaxons: ->
|
||||
for enterprise in @enterprises
|
||||
Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id
|
||||
Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id
|
||||
dereferenceEnterprise: (enterprise) ->
|
||||
@dereferenceProperty(enterprise, 'hubs', @enterprises_by_id)
|
||||
@dereferenceProperty(enterprise, 'producers', @enterprises_by_id)
|
||||
@dereferenceProperty(enterprise, 'taxons', Taxons.taxons_by_id)
|
||||
@dereferenceProperty(enterprise, 'supplied_taxons', Taxons.taxons_by_id)
|
||||
|
||||
dereferenceProperty: (enterprise, property, data) ->
|
||||
# keep unreferenced enterprise ids
|
||||
# in case we dereference again after adding more enterprises
|
||||
enterprise.unreferenced |= {}
|
||||
collection = enterprise[property]
|
||||
unreferenced = enterprise.unreferenced[property] || collection
|
||||
enterprise.unreferenced[property] =
|
||||
Dereferencer.dereference_from unreferenced, collection, data
|
||||
|
||||
addEnterprises: (new_enterprises) ->
|
||||
return unless new_enterprises && new_enterprises.length
|
||||
for enterprise in new_enterprises
|
||||
@enterprises_by_id[enterprise.id] = enterprise
|
||||
|
||||
flagMatching: (query) ->
|
||||
for enterprise in @enterprises
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -17,7 +17,6 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
|
||||
@extend()
|
||||
@dereference()
|
||||
@registerVariants()
|
||||
@registerVariantsWithCart()
|
||||
@loading = false
|
||||
|
||||
extend: ->
|
||||
@@ -26,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
|
||||
@@ -44,15 +42,9 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
|
||||
registerVariants: ->
|
||||
for product in @products
|
||||
if product.variants
|
||||
product.variants = (Variants.register variant for variant in product.variants)
|
||||
variant.product = product for variant in product.variants
|
||||
if product.master
|
||||
product.master.product = product
|
||||
product.master = Variants.register product.master
|
||||
|
||||
registerVariantsWithCart: ->
|
||||
for product in @products
|
||||
if product.variants
|
||||
for variant in product.variants
|
||||
Cart.register_variant variant
|
||||
Cart.register_variant product.master if product.master
|
||||
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
|
||||
|
||||
@@ -9,8 +9,21 @@ Darkswarm.factory 'Variants', ->
|
||||
@variants[variant.id] ||= @extend variant
|
||||
|
||||
extend: (variant)->
|
||||
# Add totalPrice method to calculate line item total. This should be on a line item!
|
||||
variant.totalPrice = ->
|
||||
variant.price_with_fees * variant.line_item.quantity
|
||||
variant.basePricePercentage = Math.round(variant.price / variant.price_with_fees * 100)
|
||||
variant.extended_name = @extendedVariantName(variant)
|
||||
variant.base_price_percentage = Math.round(variant.price / variant.price_with_fees * 100)
|
||||
variant.line_item ||= @lineItemFor(variant) # line_item may have been initialised in Cart#constructor
|
||||
variant.line_item.total_price = variant.price_with_fees * variant.line_item.quantity
|
||||
variant
|
||||
|
||||
extendedVariantName: (variant) =>
|
||||
if variant.product_name == variant.name_to_display
|
||||
variant.product_name
|
||||
else
|
||||
name = "#{variant.product_name} - #{variant.name_to_display}"
|
||||
name += " (#{variant.options_text})" if variant.options_text
|
||||
name
|
||||
|
||||
lineItemFor: (variant) ->
|
||||
variant: variant
|
||||
quantity: null
|
||||
max_quantity: null
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
/* ng-infinite-scroll - v1.0.0 - 2013-02-23 */
|
||||
var mod;mod=angular.module("infinite-scroll",[]),mod.directive("infiniteScroll",["$rootScope","$window","$timeout",function(i,n,e){return{link:function(t,l,o){var r,c,f,a;return n=angular.element(n),f=0,null!=o.infiniteScrollDistance&&t.$watch(o.infiniteScrollDistance,function(i){return f=parseInt(i,10)}),a=!0,r=!1,null!=o.infiniteScrollDisabled&&t.$watch(o.infiniteScrollDisabled,function(i){return a=!i,a&&r?(r=!1,c()):void 0}),c=function(){var e,c,u,d;return d=n.height()+n.scrollTop(),e=l.offset().top+l.height(),c=e-d,u=n.height()*f>=c,u&&a?i.$$phase?t.$eval(o.infiniteScroll):t.$apply(o.infiniteScroll):u?r=!0:void 0},n.on("scroll",c),t.$on("$destroy",function(){return n.off("scroll",c)}),e(function(){return o.infiniteScrollImmediateCheck?t.$eval(o.infiniteScrollImmediateCheck)?c():void 0:c()},0)}}}]);
|
||||
/* ng-infinite-scroll - v1.3.0 - 2016-06-30 */
|
||||
angular.module("infinite-scroll",[]).value("THROTTLE_MILLISECONDS",null).directive("infiniteScroll",["$rootScope","$window","$interval","THROTTLE_MILLISECONDS",function(a,b,c,d){return{scope:{infiniteScroll:"&",infiniteScrollContainer:"=",infiniteScrollDistance:"=",infiniteScrollDisabled:"=",infiniteScrollUseDocumentBottom:"=",infiniteScrollListenForEvent:"@"},link:function(e,f,g){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;return z=angular.element(b),u=null,v=null,j=null,k=null,r=!0,y=!1,x=null,i=!1,q=function(a){return a=a[0]||a,isNaN(a.offsetHeight)?a.document.documentElement.clientHeight:a.offsetHeight},s=function(a){if(a[0].getBoundingClientRect&&!a.css("none"))return a[0].getBoundingClientRect().top+t(a)},t=function(a){return a=a[0]||a,isNaN(window.pageYOffset)?a.document.documentElement.scrollTop:a.ownerDocument.defaultView.pageYOffset},p=function(){var b,d,g,h,l;return k===z?(b=q(k)+t(k[0].document.documentElement),g=s(f)+q(f)):(b=q(k),d=0,void 0!==s(k)&&(d=s(k)),g=s(f)-d+q(f)),y&&(g=q((f[0].ownerDocument||f[0].document).documentElement)),h=g-b,l=h<=q(k)*u+1,l?(j=!0,v?e.$$phase||a.$$phase?e.infiniteScroll():e.$apply(e.infiniteScroll):void 0):(i&&c.cancel(i),j=!1)},w=function(a,b){var d,e,f;return f=null,e=0,d=function(){return e=(new Date).getTime(),c.cancel(f),f=null,a.call()},function(){var g,h;return g=(new Date).getTime(),h=b-(g-e),h<=0?(c.cancel(f),f=null,e=g,a.call()):f?void 0:f=c(d,h,1)}},null!=d&&(p=w(p,d)),e.$on("$destroy",function(){if(k.unbind("scroll",p),null!=x&&(x(),x=null),i)return c.cancel(i)}),n=function(a){return u=parseFloat(a)||0},e.$watch("infiniteScrollDistance",n),n(e.infiniteScrollDistance),m=function(a){if(v=!a,v&&j)return j=!1,p()},e.$watch("infiniteScrollDisabled",m),m(e.infiniteScrollDisabled),o=function(a){return y=a},e.$watch("infiniteScrollUseDocumentBottom",o),o(e.infiniteScrollUseDocumentBottom),h=function(a){if(null!=k&&k.unbind("scroll",p),k=a,null!=a)return k.bind("scroll",p)},h(z),e.infiniteScrollListenForEvent&&(x=a.$on(e.infiniteScrollListenForEvent,p)),l=function(a){if(null!=a&&0!==a.length){if(a.nodeType&&1===a.nodeType?a=angular.element(a):"function"==typeof a.append?a=angular.element(a[a.length-1]):"string"==typeof a&&(a=angular.element(document.querySelector(a))),null!=a)return h(a);throw new Error("invalid infinite-scroll-container attribute.")}},e.$watch("infiniteScrollContainer",l),l(e.infiniteScrollContainer||[]),null!=g.infiniteScrollParent&&h(angular.element(f.parent())),null!=g.infiniteScrollImmediateCheck&&(r=e.$eval(g.infiniteScrollImmediateCheck)),i=c(function(){return r&&p(),c.cancel(i)})}}}]),"undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="infinite-scroll");
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
#edit-address-dialog
|
||||
%h2 {{ addressType === 'bill_address' ? "#{t('admin.customers.index.edit_bill_address')}" : "#{t('admin.customers.index.edit_ship_address')}" }}
|
||||
%form{ name: 'edit_address_form', novalidate: true, ng: { submit: 'updateAddress()'}}
|
||||
.row
|
||||
= t('admin.customers.index.required_fileds')
|
||||
(
|
||||
%span.required *
|
||||
)
|
||||
.error{ ng: { repeat: "error in errors", bind: "error" } }
|
||||
|
||||
%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
|
||||
%input{ type: 'text', name: 'address1', required: true, ng: { model: 'address.address1'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.street_address_1')
|
||||
%td
|
||||
%input{ type: 'text', name: 'address2', ng: { model: 'address.address2'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.city')
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'city', required: true, ng: { model: 'address.city'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.zipcode')
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'zipcode', required: true, ng: { model: 'address.zipcode'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.country')
|
||||
%span.required *
|
||||
%td
|
||||
%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' } }
|
||||
%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: t('admin.customers.index.update_address')}
|
||||
|
||||
|
||||
@@ -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}}" } }
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
#tag-rule-help
|
||||
.margin-bottom-30.text-center
|
||||
.text-big Tag Rules
|
||||
.text-big
|
||||
= t('js.admin.modals.tag_rule_help.title')
|
||||
|
||||
.margin-bottom-30
|
||||
.text-normal Overview
|
||||
%p Tag rules provide a way to describe which items are visible or otherwise to which customers. Items can be Shipping Methods, Payment Methods, Products and Order Cycles.
|
||||
.text-normal= t('js.admin.modals.tag_rule_help.overview')
|
||||
%p= t('js.admin.modals.tag_rule_help.overview_text')
|
||||
|
||||
.margin-bottom-30
|
||||
.text-normal 'By Default...' Rules
|
||||
%p Default rules allow you to hide items so that they are not visible by default. This behaviour can then be overriden by non-default rules for customers with particular tags.
|
||||
.text-normal= t('js.admin.modals.tag_rule_help.by_default_rules')
|
||||
%p= t('js.admin.modals.tag_rule_help.by_default_rules_text')
|
||||
|
||||
.margin-bottom-30
|
||||
.text-normal 'Customers Tagged...' Rules
|
||||
%p By creating rules related to a specific customer tag, you can override the default behaviour (whether it be to show or to hide items) for customers with the specified tag.
|
||||
.text-normal= t('js.admin.modals.tag_rule_help.customer_tagged_rules')
|
||||
%p= t('js.admin.modals.tag_rule_help.customer_tagged_rules_text')
|
||||
|
||||
.text-center
|
||||
%input.button.red.icon-plus{ type: 'button', value: 'Got it', ng: { click: 'close()' } }
|
||||
%input.button.red.icon-plus{ type: 'button', value: t('js.admin.modals.got_it'), ng: { click: 'close()' } }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#new-tag-rule-dialog
|
||||
.text-normal.margin-bottom-30.text-center
|
||||
Select a rule type:
|
||||
= t('js.admin.new_tag_rule_dialog.select_rule_type')
|
||||
|
||||
.text-center.margin-bottom-30
|
||||
-# %select.fullwidth{ 'select2-min-search' => 5, 'ng-model' => 'newRuleType', 'ng-options' => 'ruleType.id as ruleType.name for ruleType in availableRuleTypes' }
|
||||
|
||||
@@ -2,130 +2,128 @@
|
||||
.alpha.eight.columns
|
||||
%div{ ng: { if: "!enterprise.is_primary_producer", switch: "enterprise.sells" } }
|
||||
.info{ ng: { switch: { when: "none" } } }
|
||||
%h3 Hub Profile
|
||||
%h3= t('js.admin.panels.enterprise_package.hub_profile')
|
||||
|
||||
%p
|
||||
%strong COST: ALWAYS FREE
|
||||
%strong= t('js.admin.panels.enterprise_package.hub_profile_cost')
|
||||
|
||||
%p People can find and contact you on the Open Food Network. Your enterprise will be visible on the map, and will be searchable in listings.
|
||||
%p= t('js.admin.panels.enterprise_package.hub_profile_text1')
|
||||
|
||||
%p Having a profile, and making connections within your local food system through the Open Food Network will always be free.
|
||||
%p= t('js.admin.panels.enterprise_package.hub_profile_text2')
|
||||
|
||||
.info{ ng: { switch: { when: "any" } } }
|
||||
%h3 Hub Shop
|
||||
%h3= t('js.admin.panels.enterprise_package.hub_shop')
|
||||
|
||||
%p
|
||||
%strong
|
||||
%monthly-pricing-description{ joiner: "comma" }
|
||||
|
||||
%p Your enterprise is the backbone of your local food system. You aggregate produce from other enterprises and can sell it through your shop on the Open Food Network.
|
||||
%p= t('js.admin.panels.enterprise_package.hub_shop_text1')
|
||||
|
||||
%p Hubs can take many forms, whether they be a food co-op, a buying group, a veggie-box program, or a local grocery store.
|
||||
%p= t('js.admin.panels.enterprise_package.hub_shop_text2')
|
||||
|
||||
%p If you also want to sell your own products, you will need to switch this enterprise to be a producer.
|
||||
%p= t('js.admin.panels.enterprise_package.hub_shop_text3')
|
||||
|
||||
.info{ ng: { switch: { default: true } } }
|
||||
%h3
|
||||
Please Choose a Package
|
||||
= t('js.admin.panels.enterprise_package.choose_package')
|
||||
%i.icon-arrow-right
|
||||
|
||||
%p
|
||||
%strong Your enterprise will not be fully activated until a package is selected from the options on the left.
|
||||
%strong= t('js.admin.panels.enterprise_package.choose_package_text1')
|
||||
|
||||
%p
|
||||
Click on an option to see more detailed information about each package, and hit the red SAVE button when you are done!
|
||||
|
||||
|
||||
= t('js.admin.panels.enterprise_package.choose_package_text2')
|
||||
|
||||
%div{ ng: { if: "enterprise.is_primary_producer", switch: "enterprise.sells" } }
|
||||
.info{ ng: { switch: { when: "none" } } }
|
||||
%h3 Profile Only
|
||||
%h3= t('js.admin.panels.enterprise_package.profile_only')
|
||||
|
||||
%p
|
||||
%strong COST: ALWAYS FREE
|
||||
%strong= t('js.admin.panels.enterprise_package.profile_only_cost')
|
||||
|
||||
%p A profile makes you visible and contactable to others and is a way to share your story.
|
||||
%p= t('js.admin.panels.enterprise_package.profile_only_text1')
|
||||
|
||||
%p If you prefer to focus on producing food, and want to leave the work of selling it to someone else, you won't require a shop on the Open Food Network.
|
||||
%p= t('js.admin.panels.enterprise_package.profile_only_text2')
|
||||
|
||||
%p Add your products to Open Food Network, allowing hubs to stock your products in their stores.
|
||||
%p= t('js.admin.panels.enterprise_package.profile_only_text3')
|
||||
|
||||
.info{ ng: { switch: { when: "own" } } }
|
||||
%h3 Producer Shop
|
||||
%h3= t('js.admin.panels.enterprise_package.producer_shop')
|
||||
|
||||
%p
|
||||
%strong
|
||||
%monthly-pricing-description{ joiner: "comma" }
|
||||
|
||||
%p Sell your products directly to customers through your very own Open Food Network shopfront.
|
||||
%p= t('js.admin.panels.enterprise_package.producer_shop_text1')
|
||||
|
||||
%p A Producer Shop is for your produce only, if you want to sell produce grown/produced off site, please select 'Producer Hub'.
|
||||
%p= t('js.admin.panels.enterprise_package.producer_shop_text2')
|
||||
|
||||
.info{ ng: { switch: { when: "any" } } }
|
||||
%h3 Producer Hub
|
||||
%h3= t('js.admin.panels.enterprise_package.producer_hub')
|
||||
|
||||
%p
|
||||
%strong
|
||||
%monthly-pricing-description{ joiner: "comma" }
|
||||
|
||||
%p Your enterprise is the backbone of your local food system. You can sell your own produce as well as produce aggregated from other enterprises through your shopfront on the Open Food Network.
|
||||
%p= t('js.admin.panels.enterprise_package.producer_hub_text1')
|
||||
|
||||
%p Producer Hubs can take many forms, whether they be a CSA, a veggie-box program, or a food co-op with a rooftop garden.
|
||||
%p= t('js.admin.panels.enterprise_package.producer_hub_text2')
|
||||
|
||||
%p The Open Food Network aims to support as many hub models as possible, so no matter your situation, we want to provide the tools you need to run your organisation or local food business.
|
||||
%p= t('js.admin.panels.enterprise_package.producer_hub_text3')
|
||||
|
||||
.info{ ng: { switch: { default: true } } }
|
||||
%h3
|
||||
Please Choose a Package
|
||||
= t('js.admin.panels.enterprise_package.choose_package')
|
||||
%i.icon-arrow-right
|
||||
|
||||
%p
|
||||
%strong Your producer enterprise will not be fully activated until a package is selected from the options on the left.
|
||||
%strong= t('js.admin.panels.enterprise_package.choose_package_text1')
|
||||
|
||||
%p
|
||||
Click on an option to see more detailed information about each package, and hit the red SAVE button when you are done!
|
||||
= t('js.admin.panels.enterprise_package.choose_package_text2')
|
||||
|
||||
.omega.eight.columns{ ng: { switch: "enterprise.is_primary_producer" } }
|
||||
%div{ ng: { switch: { when: "false" } } }
|
||||
%a.button.selector.hub-profile{ ng: { click: "enterprise.owned && (enterprise.sells='none')", class: "{selected: enterprise.sells=='none', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Profile Only
|
||||
%p Get a listing
|
||||
.bottom ALWAYS FREE
|
||||
%h3= t('js.admin.panels.enterprise_package.profile_only')
|
||||
%p= t('js.admin.panels.enterprise_package.get_listing')
|
||||
.bottom= t('js.admin.panels.enterprise_package.always_free')
|
||||
%a.button.selector.hub{ ng: { click: "enterprise.owned && (enterprise.sells='any')", class: "{selected: enterprise.sells=='any', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Hub Shop
|
||||
%p Sell produce from others
|
||||
%h3= t('js.admin.panels.enterprise_package.hub_shop')
|
||||
%p= t('js.admin.panels.enterprise_package.sell_produce_others')
|
||||
.bottom
|
||||
%monthly-pricing-description{ joiner: "newline" }
|
||||
|
||||
%div{ ng: { switch: { when: "true" } } }
|
||||
%a.button.selector.producer-profile{ ng: { click: "enterprise.owned && (enterprise.sells='none')", class: "{selected: enterprise.sells=='none', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Profile Only
|
||||
%p Get a listing
|
||||
.bottom ALWAYS FREE
|
||||
%h3= t('js.admin.panels.enterprise_package.profile_only')
|
||||
%p= t('js.admin.panels.enterprise_package.get_listing')
|
||||
.bottom= t('js.admin.panels.enterprise_package.always_free')
|
||||
%a.button.selector.producer-shop{ ng: { click: "enterprise.owned && (enterprise.sells='own')", class: "{selected: enterprise.sells=='own', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Producer Shop
|
||||
%p Sell your own produce
|
||||
%h3= t('js.admin.panels.enterprise_package.producer_shop')
|
||||
%p= t('js.admin.panels.enterprise_package.sell_own_produce')
|
||||
.bottom
|
||||
%monthly-pricing-description{ joiner: "newline" }
|
||||
|
||||
%a.button.selector.producer-hub{ ng: { click: "enterprise.owned && (enterprise.sells='any')", class: "{selected: enterprise.sells=='any', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3 Producer Hub
|
||||
%p Sell produce from self and others
|
||||
%h3= t('js.admin.panels.enterprise_package.producer_hub')
|
||||
%p= t('js.admin.panels.enterprise_package.sell_both')
|
||||
.bottom
|
||||
%monthly-pricing-description{ joiner: "newline" }
|
||||
|
||||
%a.button.update.fullwidth{ ng: { show: "enterprise.owned", class: "{disabled: saved() && !saving, saving: saving}", click: "save()" } }
|
||||
%span{ ng: {hide: "saved() || saving" } }
|
||||
SAVE
|
||||
= t('js.admin.panels.save')
|
||||
%i.icon-save
|
||||
%span{ ng: {show: "saved() && !saving" } }
|
||||
SAVED
|
||||
= t('js.admin.panels.saved')
|
||||
%i.icon-ok-sign
|
||||
%span{ ng: {show: "saving" } }
|
||||
SAVING
|
||||
= t('js.admin.panels.saving')
|
||||
%i.icon-refresh
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user