Compare commits
1018 Commits
babel-test
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
72481b072e | ||
![]() |
cdee741a6d | ||
![]() |
68d03bc6c3 | ||
![]() |
0383f104dd | ||
![]() |
d38d55e2b4 | ||
![]() |
94a0c3ce8c | ||
![]() |
5ddbe433b9 | ||
![]() |
79d7c15d4f | ||
![]() |
d4c201fbc0 | ||
![]() |
d4097d90f6 | ||
![]() |
e67db436c6 | ||
![]() |
cfbb3d3d47 | ||
![]() |
bd5f2525dc | ||
![]() |
da5db4cb38 | ||
![]() |
2831e8be3e | ||
![]() |
8547dedca9 | ||
![]() |
46fc28dc16 | ||
![]() |
06a819bf34 | ||
![]() |
7f64c6803a | ||
![]() |
3c70dee5c1 | ||
![]() |
337144a5eb | ||
![]() |
7494e4d88c | ||
![]() |
2b49e94a61 | ||
![]() |
d0087d59d5 | ||
![]() |
854cb05883 | ||
![]() |
835bdf6941 | ||
![]() |
d98e89cf26 | ||
![]() |
4008848c64 | ||
![]() |
024b428fe6 | ||
![]() |
17f2025c53 | ||
![]() |
6ac65373a3 | ||
![]() |
2939b3ae95 | ||
![]() |
0f4e5ef508 | ||
![]() |
a894404ad3 | ||
![]() |
e46f1d06e0 | ||
![]() |
c5ba2e55f3 | ||
![]() |
f7e411d561 | ||
![]() |
603388c79d | ||
![]() |
547f1c29e3 | ||
![]() |
2dd0a560b7 | ||
![]() |
9220b2d9c2 | ||
![]() |
7271fdf6b7 | ||
![]() |
86b94ae713 | ||
![]() |
52737ec694 | ||
![]() |
6ff51103f5 | ||
![]() |
44fd598699 | ||
![]() |
a714f06670 | ||
![]() |
78e87a351c | ||
![]() |
3a3f46530d | ||
![]() |
3241faf503 | ||
![]() |
2f620c5f91 | ||
![]() |
763d7dec75 | ||
![]() |
4acd178819 | ||
![]() |
6960b7f86e | ||
![]() |
81ab8f7b20 | ||
![]() |
05843bb093 | ||
![]() |
5751838a3d | ||
![]() |
20dd81729b | ||
![]() |
3516598f4c | ||
![]() |
4a7aad03c4 | ||
![]() |
90677ae158 | ||
![]() |
23224f6093 | ||
![]() |
9165a0247f | ||
![]() |
e6dbd1ed92 | ||
![]() |
5a85d1ac9e | ||
![]() |
9ebe4037a4 | ||
![]() |
7dbfd5ce29 | ||
![]() |
040e0a726a | ||
![]() |
60e0d79e01 | ||
![]() |
609657a8e4 | ||
![]() |
c0a4fa43f0 | ||
![]() |
8f39e9cb36 | ||
![]() |
1ef2469b40 | ||
![]() |
5b595122b7 | ||
![]() |
b8e0c3f7e4 | ||
![]() |
81b876a5b2 | ||
![]() |
17b4c2e98e | ||
![]() |
6b4bce8754 | ||
![]() |
1649cae956 | ||
![]() |
41590741ba | ||
![]() |
a0d85c0673 | ||
![]() |
d0e42a1186 | ||
![]() |
c55b355548 | ||
![]() |
a4cd45ceb4 | ||
![]() |
6fb99d2d90 | ||
![]() |
6cf11f083b | ||
![]() |
ac24ffe636 | ||
![]() |
aad29a5469 | ||
![]() |
f69c7d2e2d | ||
![]() |
8b36f33513 | ||
![]() |
e31d706ee4 | ||
![]() |
d573a5b639 | ||
![]() |
390b8b2c86 | ||
![]() |
387109c1da | ||
![]() |
593153eebe | ||
![]() |
1c5e0475f5 | ||
![]() |
33f8fcfafb | ||
![]() |
5e5b567782 | ||
![]() |
7c093b4fb0 | ||
![]() |
00efd01aaf | ||
![]() |
6450d39933 | ||
![]() |
3bc08ba10c | ||
![]() |
0b4e1f9360 | ||
![]() |
b22e496b05 | ||
![]() |
16c2f6602a | ||
![]() |
653343149a | ||
![]() |
fa0576a4dd | ||
![]() |
8beda5eed4 | ||
![]() |
bf26c230be | ||
![]() |
8474c7b52a | ||
![]() |
3835bc9110 | ||
![]() |
8853f8ca47 | ||
![]() |
794d3880e7 | ||
![]() |
0cc3e64b8a | ||
![]() |
0e3071576b | ||
![]() |
460a423df3 | ||
![]() |
71f7ec5207 | ||
![]() |
ce834fc5f3 | ||
![]() |
94271325d7 | ||
![]() |
ceb9749937 | ||
![]() |
6f1833f936 | ||
![]() |
4248e59eeb | ||
![]() |
7da17ab63e | ||
![]() |
42bbcabdfe | ||
![]() |
ff2e8c9047 | ||
![]() |
029c9fc251 | ||
![]() |
ea8003c541 | ||
![]() |
9a304b6699 | ||
![]() |
ac4abf0ebb | ||
![]() |
b4244f8a25 | ||
![]() |
018ec79a74 | ||
![]() |
17f7bcbbad | ||
![]() |
eeadeaa1b1 | ||
![]() |
222bb5bad4 | ||
![]() |
7d424f6d12 | ||
![]() |
bddb5ed243 | ||
![]() |
ac180c2324 | ||
![]() |
21fadee7bb | ||
![]() |
d4fce3c855 | ||
![]() |
3b17681db3 | ||
![]() |
89d7dad126 | ||
![]() |
13f788f3f1 | ||
![]() |
be698e499f | ||
![]() |
4f9847da04 | ||
![]() |
a8d199967e | ||
![]() |
8d0dc359b4 | ||
![]() |
7f81e62bc8 | ||
![]() |
0b384abe66 | ||
![]() |
53df1b8dae | ||
![]() |
350b47364e | ||
![]() |
9e955bde99 | ||
![]() |
bc141ce36b | ||
![]() |
20df18636d | ||
![]() |
cd1c65a784 | ||
![]() |
37e850c67b | ||
![]() |
5a08d22dbf | ||
![]() |
fe5af63277 | ||
![]() |
52c1249523 | ||
![]() |
c5cd38b4a5 | ||
![]() |
9b9773db16 | ||
![]() |
a4aabd9f3e | ||
![]() |
00d85fb6da | ||
![]() |
0f6b712963 | ||
![]() |
46eb84e859 | ||
![]() |
38330e4c13 | ||
![]() |
bff7cee374 | ||
![]() |
9c7271c606 | ||
![]() |
9ae582e345 | ||
![]() |
292a033c1a | ||
![]() |
3c5bc44ddf | ||
![]() |
3db915516a | ||
![]() |
24b9612a56 | ||
![]() |
a9e047cc9e | ||
![]() |
6052f4c211 | ||
![]() |
4e977f91cc | ||
![]() |
b600885d11 | ||
![]() |
3445519714 | ||
![]() |
e746da4fab | ||
![]() |
32aebd388b | ||
![]() |
c96363746b | ||
![]() |
43692ee564 | ||
![]() |
39ed2217cd | ||
![]() |
2effad4f6a | ||
![]() |
b9837c690d | ||
![]() |
67b34b1482 | ||
![]() |
a673956787 | ||
![]() |
447659cdab | ||
![]() |
8782eaf507 | ||
![]() |
c71f657b08 | ||
![]() |
dabd7c1055 | ||
![]() |
3e39cb33d9 | ||
![]() |
d44cc05c3d | ||
![]() |
a12b997b8a | ||
![]() |
8d3e893aec | ||
![]() |
0bb2bdcbe3 | ||
![]() |
a659c6c6ff | ||
![]() |
749faabb46 | ||
![]() |
7b8f2e1dfe | ||
![]() |
cf12f1e9cc | ||
![]() |
da08d7f078 | ||
![]() |
06e17fd76d | ||
![]() |
d145cff000 | ||
![]() |
e3648dfda0 | ||
![]() |
25d8898ab0 | ||
![]() |
92346c8fb9 | ||
![]() |
6f6e18b406 | ||
![]() |
6c5aa06d6b | ||
![]() |
c04b85e746 | ||
![]() |
c89df69f14 | ||
![]() |
71bee9cfe7 | ||
![]() |
92dcd41a0a | ||
![]() |
90b975445e | ||
![]() |
877ff972a9 | ||
![]() |
137a0ebbfd | ||
![]() |
53bea1fb9f | ||
![]() |
3dcdd7f2ba | ||
![]() |
07efe0304e | ||
![]() |
efe5d8669c | ||
![]() |
5f6de1c787 | ||
![]() |
96e96c0348 | ||
![]() |
6745ea9868 | ||
![]() |
6c8cf71c9a | ||
![]() |
16ad422e89 | ||
![]() |
da30f9e25c | ||
![]() |
f5a2534169 | ||
![]() |
81a75d79be | ||
![]() |
f871da17c8 | ||
![]() |
2f7c93a4e6 | ||
![]() |
23ebdedf48 | ||
![]() |
7e3bad7390 | ||
![]() |
cc5c17a6e1 | ||
![]() |
c7d05ad2f9 | ||
![]() |
438d9669c1 | ||
![]() |
ea569b8b1a | ||
![]() |
37eb26df36 | ||
![]() |
647463cc61 | ||
![]() |
079cb258f4 | ||
![]() |
b25d99c241 | ||
![]() |
c4a64216ce | ||
![]() |
da09a3bb96 | ||
![]() |
f6926ccda6 | ||
![]() |
51ddc46322 | ||
![]() |
de4aa4c240 | ||
![]() |
23bbb5a1e5 | ||
![]() |
87efe75e24 | ||
![]() |
381351b433 | ||
![]() |
13766e1f6c | ||
![]() |
5a1cf3ab02 | ||
![]() |
3f905be77e | ||
![]() |
44632e2218 | ||
![]() |
724329d948 | ||
![]() |
bf122add81 | ||
![]() |
7a15c88972 | ||
![]() |
e8403b9679 | ||
![]() |
1f320e1f5d | ||
![]() |
e1e5178869 | ||
![]() |
6e4d6a2820 | ||
![]() |
18d0e980d1 | ||
![]() |
7e290b262c | ||
![]() |
0d4fd26be9 | ||
![]() |
00b2823612 | ||
![]() |
b50b055e44 | ||
![]() |
1cfc90186f | ||
![]() |
26dcaad76a | ||
![]() |
97661539dc | ||
![]() |
081793f72f | ||
![]() |
3cc92fe1e9 | ||
![]() |
f99038fd37 | ||
![]() |
757709cf43 | ||
![]() |
da49f9900f | ||
![]() |
aff2bef3f5 | ||
![]() |
16f228b2a3 | ||
![]() |
153ed728cb | ||
![]() |
7210653c0b | ||
![]() |
e03ecfae98 | ||
![]() |
1d367f0165 | ||
![]() |
f8b41c971c | ||
![]() |
68879a0ffc | ||
![]() |
b0d9a9c82e | ||
![]() |
f5b1ee44f3 | ||
![]() |
b5cc0f918a | ||
![]() |
c0b63e5928 | ||
![]() |
5ed10c6ba2 | ||
![]() |
7c64666167 | ||
![]() |
c28c8c820b | ||
![]() |
3fbb4633a6 | ||
![]() |
9ce9502b76 | ||
![]() |
a8312acfe0 | ||
![]() |
9cb2b8167d | ||
![]() |
164fea0cec | ||
![]() |
991a50d090 | ||
![]() |
ce0dd5cc5e | ||
![]() |
55b30dd08c | ||
![]() |
7fed34fa30 | ||
![]() |
30b59ebc95 | ||
![]() |
2200badef2 | ||
![]() |
63f206c80e | ||
![]() |
628bc536a0 | ||
![]() |
00e52ae62b | ||
![]() |
bb925723fd | ||
![]() |
081f6bc77d | ||
![]() |
d0aaa7165c | ||
![]() |
d810deaa9c | ||
![]() |
a8c19b4d8b | ||
![]() |
942b8b91f3 | ||
![]() |
542584eed3 | ||
![]() |
4fdfdd341b | ||
![]() |
a937c99f09 | ||
![]() |
aedd361569 | ||
![]() |
e72da417c0 | ||
![]() |
8e2c47933a | ||
![]() |
966c293dea | ||
![]() |
f04a8c3736 | ||
![]() |
4bbae6e17a | ||
![]() |
1aade0f268 | ||
![]() |
9ed1792d9e | ||
![]() |
e9a3f9b0e0 | ||
![]() |
84d8bb4020 | ||
![]() |
ad53b3311e | ||
![]() |
bd7e1b222d | ||
![]() |
3f6ecc0021 | ||
![]() |
80cfd609ea | ||
![]() |
c8cf9b9e6f | ||
![]() |
4731b8f905 | ||
![]() |
45ddf9827c | ||
![]() |
06fb74aafd | ||
![]() |
46854b6b23 | ||
![]() |
4add3ec44c | ||
![]() |
09ceaa953b | ||
![]() |
edc18a4fe4 | ||
![]() |
38411fb56c | ||
![]() |
ad216bcf97 | ||
![]() |
948a4dda64 | ||
![]() |
97a045fe0f | ||
![]() |
b7a24a58fb | ||
![]() |
31f0f0d210 | ||
![]() |
2d43518ef2 | ||
![]() |
e4a399671a | ||
![]() |
2219bd9861 | ||
![]() |
eca9d82aa2 | ||
![]() |
4a41f219d8 | ||
![]() |
5b46735204 | ||
![]() |
c5fa1303e3 | ||
![]() |
d67c654245 | ||
![]() |
3390f2405b | ||
![]() |
d857a813b9 | ||
![]() |
fe4b75758d | ||
![]() |
2523bca659 | ||
![]() |
8544618445 | ||
![]() |
0bb0912a7b | ||
![]() |
d41c8d6489 | ||
![]() |
553d2b00d8 | ||
![]() |
a1b6f072c1 | ||
![]() |
2194dff7a4 | ||
![]() |
ca9a7c685e | ||
![]() |
37eb597ee8 | ||
![]() |
db2ddfd493 | ||
![]() |
723b4d32e5 | ||
![]() |
5815088586 | ||
![]() |
5d39221afe | ||
![]() |
77ffc6ad5d | ||
![]() |
0d5ea8520a | ||
![]() |
e3dee4dee7 | ||
![]() |
9a9a4bf9e9 | ||
![]() |
d662a828d1 | ||
![]() |
48757f08ff | ||
![]() |
17d4515002 | ||
![]() |
e4cc28ac60 | ||
![]() |
cc9efde843 | ||
![]() |
2b8311d3d7 | ||
![]() |
0cd50b5560 | ||
![]() |
2b27e40308 | ||
![]() |
b985ef8a53 | ||
![]() |
fec3fa2a72 | ||
![]() |
09fc3c2b1c | ||
![]() |
7cb95f4129 | ||
![]() |
ea2feadbff | ||
![]() |
87cf336e22 | ||
![]() |
7d41047a9d | ||
![]() |
c83de8a6ea | ||
![]() |
3f6ef7fb01 | ||
![]() |
5847388862 | ||
![]() |
4ac368e052 | ||
![]() |
fdb9e20076 | ||
![]() |
4b78ebcd72 | ||
![]() |
47744e4ccd | ||
![]() |
2ad0dc00da | ||
![]() |
f8f403eca4 | ||
![]() |
2827f70daa | ||
![]() |
6d05c3472b | ||
![]() |
5805c7e562 | ||
![]() |
f44d563a15 | ||
![]() |
a1acbd4038 | ||
![]() |
54b4ec6f5c | ||
![]() |
4159c63a3b | ||
![]() |
41db61ecb9 | ||
![]() |
52fd0d992d | ||
![]() |
41c93ab034 | ||
![]() |
18e4e37b32 | ||
![]() |
430f58d3c4 | ||
![]() |
2baa537542 | ||
![]() |
374eefada1 | ||
![]() |
2bc44dddd1 | ||
![]() |
5350931617 | ||
![]() |
c4fde7ebbf | ||
![]() |
5fcac10db9 | ||
![]() |
a1c96f1db1 | ||
![]() |
b1b9dcf233 | ||
![]() |
22d3fbbc9b | ||
![]() |
7cd1439928 | ||
![]() |
fa33eb72b2 | ||
![]() |
7d98f04bd8 | ||
![]() |
545c800459 | ||
![]() |
6acf208a36 | ||
![]() |
a85ea18fd9 | ||
![]() |
0ad439395e | ||
![]() |
1a46196080 | ||
![]() |
90d948a6bc | ||
![]() |
aefeb1f613 | ||
![]() |
05eb3a340c | ||
![]() |
8f5903f5eb | ||
![]() |
9ca40890a9 | ||
![]() |
392687f9ee | ||
![]() |
341d4f169f | ||
![]() |
6051c245b4 | ||
![]() |
dcfaa5521e | ||
![]() |
b2c9a42103 | ||
![]() |
383f8d2219 | ||
![]() |
df38f4ded7 | ||
![]() |
c17695939c | ||
![]() |
c723e1ebe4 | ||
![]() |
f353b7ca61 | ||
![]() |
885ed6039f | ||
![]() |
da1dd75265 | ||
![]() |
e01cb38c5d | ||
![]() |
9a43b53ebe | ||
![]() |
045f1fbb7e | ||
![]() |
36436d0b43 | ||
![]() |
816fb52b76 | ||
![]() |
8f98398dfd | ||
![]() |
4c337e5294 | ||
![]() |
6941f96a5a | ||
![]() |
c3df3fcebf | ||
![]() |
2c47b6403d | ||
![]() |
cdaf73b3d0 | ||
![]() |
640846961a | ||
![]() |
fb74fe76b7 | ||
![]() |
b397ee2281 | ||
![]() |
6970556dbd | ||
![]() |
9b9af65f8a | ||
![]() |
e2eef779c5 | ||
![]() |
76b96a8b07 | ||
![]() |
d5dd5c5100 | ||
![]() |
bbad56a32a | ||
![]() |
45b0c3ab19 | ||
![]() |
575968929c | ||
![]() |
baeb846b5c | ||
![]() |
7bbb4a8e2d | ||
![]() |
202192bc72 | ||
![]() |
ae21b3113e | ||
![]() |
a854ce9dce | ||
![]() |
a70a517f7e | ||
![]() |
da387874a2 | ||
![]() |
81783070a2 | ||
![]() |
8241149079 | ||
![]() |
d45a9c22c5 | ||
![]() |
dfea8b5a6a | ||
![]() |
d4ae63ff0d | ||
![]() |
4a6922ba48 | ||
![]() |
921b21c3e1 | ||
![]() |
88a6e4f79f | ||
![]() |
f0b7a212e5 | ||
![]() |
f546fbda99 | ||
![]() |
d072c6233e | ||
![]() |
bdd9bfdd1c | ||
![]() |
10a5d8d02e | ||
![]() |
8f42a3ca29 | ||
![]() |
48928deba4 | ||
![]() |
f40b7ae6ac | ||
![]() |
9bf4bac292 | ||
![]() |
04a730da7f | ||
![]() |
7d3311679e | ||
![]() |
1cb49cc5d3 | ||
![]() |
810e0a3239 | ||
![]() |
c7fd46e6b4 | ||
![]() |
3c2bcf012f | ||
![]() |
20ad57a368 | ||
![]() |
cd90cfd388 | ||
![]() |
fbf2fbe0c6 | ||
![]() |
08eefeaf57 | ||
![]() |
6b031249ac | ||
![]() |
bbb6434524 | ||
![]() |
bb1cbdff26 | ||
![]() |
e935001586 | ||
![]() |
01c71fd970 | ||
![]() |
24507a73f6 | ||
![]() |
8012829992 | ||
![]() |
16175912ca | ||
![]() |
0bf546a0aa | ||
![]() |
a3e711b7b5 | ||
![]() |
c40e321c4b | ||
![]() |
0f743e55c7 | ||
![]() |
c784db88a8 | ||
![]() |
37521b62a1 | ||
![]() |
14ecf88ad4 | ||
![]() |
4137a61bc8 | ||
![]() |
676ab7852b | ||
![]() |
6150a08dc1 | ||
![]() |
33bf3b2e12 | ||
![]() |
196e45c849 | ||
![]() |
2184952551 | ||
![]() |
e22d7a8459 | ||
![]() |
241df13954 | ||
![]() |
34028d354e | ||
![]() |
15942b97ae | ||
![]() |
f0770fa84d | ||
![]() |
7f8699b937 | ||
![]() |
5901a3c7af | ||
![]() |
14f40218a9 | ||
![]() |
1deba232fa | ||
![]() |
56289b6693 | ||
![]() |
7de192cd3a | ||
![]() |
d08db42f7b | ||
![]() |
73d88421bb | ||
![]() |
1a779bb7aa | ||
![]() |
e35b035224 | ||
![]() |
4e717a0934 | ||
![]() |
677b2edd51 | ||
![]() |
39a2445d74 | ||
![]() |
2ecfff6681 | ||
![]() |
9c5a3ad820 | ||
![]() |
223c427888 | ||
![]() |
30ae61d60e | ||
![]() |
45357bdb85 | ||
![]() |
16792df11d | ||
![]() |
5b2af4845b | ||
![]() |
2b01a097c7 | ||
![]() |
1f5639da42 | ||
![]() |
68b5ac456f | ||
![]() |
8f3909713f | ||
![]() |
4fb8f44d01 | ||
![]() |
08d322932d | ||
![]() |
773a93f55d | ||
![]() |
d4569d3640 | ||
![]() |
982719bf83 | ||
![]() |
352cf310b4 | ||
![]() |
225fa2b5e2 | ||
![]() |
d073dec84d | ||
![]() |
492e7917b6 | ||
![]() |
e14b8f94bd | ||
![]() |
7d14da3a8c | ||
![]() |
ffcf608de1 | ||
![]() |
9209edd081 | ||
![]() |
23cf6bd007 | ||
![]() |
d5261841be | ||
![]() |
c44af1c7bd | ||
![]() |
819be60796 | ||
![]() |
5f9dc05956 | ||
![]() |
ff798d332b | ||
![]() |
6e1e2dcf76 | ||
![]() |
fcc366a176 | ||
![]() |
f880fd12d6 | ||
![]() |
f7e2cd6348 | ||
![]() |
959772dc00 | ||
![]() |
dc11b37ced | ||
![]() |
531170353b | ||
![]() |
c0143300c4 | ||
![]() |
699d5634e9 | ||
![]() |
4eb18e5eba | ||
![]() |
f75d7313dd | ||
![]() |
5f413b2ff3 | ||
![]() |
dec6b864c9 | ||
![]() |
52bbb79fd0 | ||
![]() |
e62433edfb | ||
![]() |
404e045a92 | ||
![]() |
89babf8832 | ||
![]() |
48d4d2d5a5 | ||
![]() |
18d15d8dc9 | ||
![]() |
7a062a7493 | ||
![]() |
da21c9c47b | ||
![]() |
42e2f229c0 | ||
![]() |
19447e7b90 | ||
![]() |
a455a72534 | ||
![]() |
0d3d4323b5 | ||
![]() |
10cae22c55 | ||
![]() |
d80aa97ebd | ||
![]() |
1777fd16f0 | ||
![]() |
241e596680 | ||
![]() |
d81e2a5cf0 | ||
![]() |
85d7c01c85 | ||
![]() |
c7639f328f | ||
![]() |
67ddc202d9 | ||
![]() |
365e58249d | ||
![]() |
a858368642 | ||
![]() |
8efbfb7c74 | ||
![]() |
fbca2e5c52 | ||
![]() |
459e26490a | ||
![]() |
afc7afeb9c | ||
![]() |
49506b6d94 | ||
![]() |
d83d70eb5c | ||
![]() |
6d53839fbc | ||
![]() |
d2a33f2613 | ||
![]() |
8ebff89c1c | ||
![]() |
fb61819f6b | ||
![]() |
e25af42ef3 | ||
![]() |
cc04ddbe4d | ||
![]() |
235d7c8dae | ||
![]() |
3872e646ac | ||
![]() |
7935d01a1c | ||
![]() |
8215ba7a1d | ||
![]() |
18c62be6a4 | ||
![]() |
9395af86f7 | ||
![]() |
103c16a563 | ||
![]() |
c442daedce | ||
![]() |
5ec7c97f30 | ||
![]() |
892d4fb5da | ||
![]() |
a47c332895 | ||
![]() |
e669bf03b0 | ||
![]() |
1cab2ba5fa | ||
![]() |
e9439c978b | ||
![]() |
d8d9758f27 | ||
![]() |
48778b5d50 | ||
![]() |
33128d1f59 | ||
![]() |
c6e6cb639c | ||
![]() |
64e840e418 | ||
![]() |
2901174ba3 | ||
![]() |
d271683968 | ||
![]() |
5248b08de0 | ||
![]() |
1100015d2c | ||
![]() |
69c27cd8a7 | ||
![]() |
fd5c48ac51 | ||
![]() |
ed6d628f4e | ||
![]() |
01ecff8e2b | ||
![]() |
91ef561474 | ||
![]() |
05d74c4cac | ||
![]() |
687f86af71 | ||
![]() |
94c4445475 | ||
![]() |
000e7f9744 | ||
![]() |
b9b1c0c508 | ||
![]() |
b0c0cd6e0c | ||
![]() |
a15b23e353 | ||
![]() |
f4b73d22b8 | ||
![]() |
b3043c98ab | ||
![]() |
e632f1c84d | ||
![]() |
1d19811bd2 | ||
![]() |
879ed11b69 | ||
![]() |
8e365298ba | ||
![]() |
2919486818 | ||
![]() |
f45d56113a | ||
![]() |
0391569f4d | ||
![]() |
267e3165a2 | ||
![]() |
2725d423ed | ||
![]() |
d368c4019a | ||
![]() |
bbfe4b92de | ||
![]() |
6673c64ac6 | ||
![]() |
d92f5669f3 | ||
![]() |
2d9284ba26 | ||
![]() |
de36a6e833 | ||
![]() |
871cbae499 | ||
![]() |
a65ae873e3 | ||
![]() |
7386b376f3 | ||
![]() |
acb990c75d | ||
![]() |
a4a786bac6 | ||
![]() |
1efe54e896 | ||
![]() |
da2dedf7af | ||
![]() |
d1de8b751a | ||
![]() |
13cd84e1be | ||
![]() |
065bac3b8a | ||
![]() |
db8bb3484d | ||
![]() |
b171b15d87 | ||
![]() |
dd0fafd41d | ||
![]() |
70ade61b75 | ||
![]() |
dae0986b9b | ||
![]() |
a5a7df328a | ||
![]() |
cee2e1d47a | ||
![]() |
c31f0b6b5c | ||
![]() |
8797c7f680 | ||
![]() |
a24f16eb85 | ||
![]() |
b0826fd91d | ||
![]() |
c9b9d4127d | ||
![]() |
6bcf92db46 | ||
![]() |
c59ae5cf40 | ||
![]() |
c293226453 | ||
![]() |
2770860968 | ||
![]() |
9069559050 | ||
![]() |
c768d48454 | ||
![]() |
4c13d51f24 | ||
![]() |
0df967418b | ||
![]() |
9202ab8b3c | ||
![]() |
3a2f0e6929 | ||
![]() |
0653ee3566 | ||
![]() |
65d63fad37 | ||
![]() |
21cc9f16bf | ||
![]() |
678a6e15cc | ||
![]() |
83fe445f8f | ||
![]() |
39bfeac86c | ||
![]() |
d3833b8afd | ||
![]() |
126fb86957 | ||
![]() |
a02eb3c328 | ||
![]() |
945da5e008 | ||
![]() |
aea378f105 | ||
![]() |
782e798973 | ||
![]() |
07ce273333 | ||
![]() |
fffa1badd4 | ||
![]() |
9920a845c6 | ||
![]() |
55992e341d | ||
![]() |
6232c83b4b | ||
![]() |
a0a2502947 | ||
![]() |
83dfd07306 | ||
![]() |
b3b9cac078 | ||
![]() |
8b7f33826e | ||
![]() |
34e23937a1 | ||
![]() |
7b0ed6da81 | ||
![]() |
198fb28e20 | ||
![]() |
2b3f6b4f1f | ||
![]() |
492293ef84 | ||
![]() |
03f8c5fa99 | ||
![]() |
c6ab18634d | ||
![]() |
ffc32d992d | ||
![]() |
cd86cfca98 | ||
![]() |
33eb31d6e2 | ||
![]() |
5123c21e0d | ||
![]() |
a8ba2fac33 | ||
![]() |
ee0b4f5d0d | ||
![]() |
991967d5bc | ||
![]() |
a92acfe7c4 | ||
![]() |
ac7c22a7c6 | ||
![]() |
9652b9f553 | ||
![]() |
168e4e4b45 | ||
![]() |
fba412fe4a | ||
![]() |
23d4992265 | ||
![]() |
4c9f389aa8 | ||
![]() |
a6564e92d7 | ||
![]() |
ae22ce7ecd | ||
![]() |
884d03b12a | ||
![]() |
34b99fb71c | ||
![]() |
d252a09cd3 | ||
![]() |
72fbee5523 | ||
![]() |
c110e64293 | ||
![]() |
67ccb632b4 | ||
![]() |
10637ca9ea | ||
![]() |
61f8a2c3c5 | ||
![]() |
36371630b5 | ||
![]() |
46531a4c69 | ||
![]() |
81d5618346 | ||
![]() |
e475b22f1d | ||
![]() |
d8b201487d | ||
![]() |
c6e4722289 | ||
![]() |
521f291b84 | ||
![]() |
c2234176aa | ||
![]() |
3bb8b5d24d | ||
![]() |
d01366a2f1 | ||
![]() |
c2bb4ac10b | ||
![]() |
e3947e7b45 | ||
![]() |
eb1cecf404 | ||
![]() |
a9594360cd | ||
![]() |
695dd4e65d | ||
![]() |
9a8ab522e1 | ||
![]() |
6ae2b58d3f | ||
![]() |
d5759e3724 | ||
![]() |
34d039ba48 | ||
![]() |
05ea309e2e | ||
![]() |
a9f0096929 | ||
![]() |
db496e13c2 | ||
![]() |
073d27311f | ||
![]() |
ef71a2c77c | ||
![]() |
0ceb5ec9a9 | ||
![]() |
225215842d | ||
![]() |
6d2c72fb54 | ||
![]() |
b033dedddc | ||
![]() |
efe8b65f84 | ||
![]() |
faecefa375 | ||
![]() |
33b40829b8 | ||
![]() |
2addf6b27b | ||
![]() |
2bd3aa9669 | ||
![]() |
40c84ecbc0 | ||
![]() |
39a8e8fb0c | ||
![]() |
316a6f91b2 | ||
![]() |
80c70d9bff | ||
![]() |
a7be5444ea | ||
![]() |
701a3d73fc | ||
![]() |
6de7fdedf9 | ||
![]() |
c39bdaa25b | ||
![]() |
cbc05baf02 | ||
![]() |
84c1367e7b | ||
![]() |
ece3491e21 | ||
![]() |
cd35962435 | ||
![]() |
97d46b79f1 | ||
![]() |
a158e8a71b | ||
![]() |
b3ce918dfb | ||
![]() |
6d265f448f | ||
![]() |
2928752d19 | ||
![]() |
cff84a71ed | ||
![]() |
df353bdc05 | ||
![]() |
ef7da3486a | ||
![]() |
09a859d7e3 | ||
![]() |
3715c8da1b | ||
![]() |
5268060802 | ||
![]() |
76030d2c4a | ||
![]() |
6d7dcc44bc | ||
![]() |
322b20fc12 | ||
![]() |
94a3921d0a | ||
![]() |
cf5a943ec6 | ||
![]() |
78dd1e132e | ||
![]() |
ba514b80d9 | ||
![]() |
918ae23418 | ||
![]() |
b0c1a9a613 | ||
![]() |
f829e4d6cc | ||
![]() |
7ef7a84122 | ||
![]() |
0f965b0de6 | ||
![]() |
57881ff587 | ||
![]() |
ea513edf73 | ||
![]() |
0513cd0eef | ||
![]() |
b46a2fc893 | ||
![]() |
0c49350cdf | ||
![]() |
542d68cc4c | ||
![]() |
df24917c2f | ||
![]() |
2d8132b6c8 | ||
![]() |
1247896d70 | ||
![]() |
4ffbf6fca5 | ||
![]() |
d0eb1c8753 | ||
![]() |
ae19ffcf9b | ||
![]() |
dd5d3a8668 | ||
![]() |
752e25e282 | ||
![]() |
02774ac6fe | ||
![]() |
aad12db2ff | ||
![]() |
8f2508e167 | ||
![]() |
63c69727cd | ||
![]() |
e841d62360 | ||
![]() |
fd2ba1d5b7 | ||
![]() |
a62161dfc1 | ||
![]() |
a7021f80ca | ||
![]() |
efae7073f2 | ||
![]() |
d1d62184be | ||
![]() |
62fa86af82 | ||
![]() |
d2421825c9 | ||
![]() |
9bbef844f6 | ||
![]() |
f61cf08a86 | ||
![]() |
b53e5b96ef | ||
![]() |
a982bd056d | ||
![]() |
18f3c2cfb0 | ||
![]() |
375b4341a6 | ||
![]() |
701a46ba84 | ||
![]() |
fd7c2a6f6f | ||
![]() |
c701f34aaa | ||
![]() |
e683b2be07 | ||
![]() |
3272387afe | ||
![]() |
32dedc6fb4 | ||
![]() |
e551777989 | ||
![]() |
6ffd7b11cb | ||
![]() |
55b2dc39bf | ||
![]() |
59edca783e | ||
![]() |
91512469d5 | ||
![]() |
2ca10b3d54 | ||
![]() |
a7e2e73e51 | ||
![]() |
73ac74332c | ||
![]() |
e5972b705f | ||
![]() |
2ba773d612 | ||
![]() |
043c0ac6b7 | ||
![]() |
de3b47fd78 | ||
![]() |
941ae5499c | ||
![]() |
f2af77498b | ||
![]() |
e2d7c7e999 | ||
![]() |
c55cacfb5a | ||
![]() |
3b2d7eb970 | ||
![]() |
71fb054efe | ||
![]() |
cb913ffccb | ||
![]() |
1da18e4ca7 | ||
![]() |
7729dcafc0 | ||
![]() |
b07fdc6335 | ||
![]() |
1ddb38036e | ||
![]() |
f7c1c56d7d | ||
![]() |
5ff5ea88fb | ||
![]() |
53c3f62f1e | ||
![]() |
198bd70b59 | ||
![]() |
909b4b31c8 | ||
![]() |
d73fc63273 | ||
![]() |
d40822c540 | ||
![]() |
dc71af9110 | ||
![]() |
22e99a421c | ||
![]() |
86cf7cbd07 | ||
![]() |
b476c7c7c5 | ||
![]() |
7769b5d09e | ||
![]() |
c867b3bb85 | ||
![]() |
2efd7121b8 | ||
![]() |
72feaab6f4 | ||
![]() |
dc89cfb3ba | ||
![]() |
88088c68db | ||
![]() |
b72f1c2a08 | ||
![]() |
9a3ff2d244 | ||
![]() |
b1fad5a310 | ||
![]() |
b633038bf9 | ||
![]() |
22eab3e09d | ||
![]() |
536d7254fb | ||
![]() |
010bf3b8f9 | ||
![]() |
16b2e82f74 | ||
![]() |
aca774e132 | ||
![]() |
2119b5ab75 | ||
![]() |
f6ac1732f2 | ||
![]() |
a56af4a101 | ||
![]() |
9b54ca9ca7 | ||
![]() |
a15261b3b3 | ||
![]() |
b2eea914e4 | ||
![]() |
1d564970dc | ||
![]() |
9372979fb5 | ||
![]() |
df2216960b | ||
![]() |
2414ec6472 | ||
![]() |
56f9f04340 | ||
![]() |
e9a80cb530 | ||
![]() |
145a45e8e1 | ||
![]() |
8f63a5e20d | ||
![]() |
5aaefff1d6 | ||
![]() |
2ab46d3697 | ||
![]() |
d8f8d8a3f8 | ||
![]() |
e89778c1ab | ||
![]() |
ef1715e9ee | ||
![]() |
92435f398d | ||
![]() |
79b98ddc54 | ||
![]() |
f2cc2204c9 | ||
![]() |
e8257813f1 | ||
![]() |
d2400de870 | ||
![]() |
38652f9362 | ||
![]() |
abf08deb9d | ||
![]() |
b53fabbb58 | ||
![]() |
3259b63081 | ||
![]() |
041f79379c | ||
![]() |
f3b461ae1d | ||
![]() |
a2d874c8bc | ||
![]() |
c11f1069d7 | ||
![]() |
dcfddac519 | ||
![]() |
7c020da594 | ||
![]() |
1372949523 | ||
![]() |
b590c43edb | ||
![]() |
26145c3892 | ||
![]() |
1a0f125d78 | ||
![]() |
444d77958d | ||
![]() |
15a0f3bbe3 | ||
![]() |
47741e75fa | ||
![]() |
24b43ae3a7 | ||
![]() |
6144c8f969 | ||
![]() |
13283b008d | ||
![]() |
859c506913 | ||
![]() |
2e74cd7831 | ||
![]() |
69041832e7 | ||
![]() |
c6cb46907e | ||
![]() |
2f93065986 | ||
![]() |
8de0b024f0 | ||
![]() |
3e0ab63b9b | ||
![]() |
5c45652887 | ||
![]() |
0d592a950c | ||
![]() |
384ce236de | ||
![]() |
97bac9fadc | ||
![]() |
d9eb8ff3c3 | ||
![]() |
1bb6217ec1 | ||
![]() |
4032edcf7d | ||
![]() |
3ebc238320 | ||
![]() |
ccb30351c0 | ||
![]() |
700aa5377b | ||
![]() |
db6e9841db | ||
![]() |
d2d5896b0b | ||
![]() |
7dd9cee0d4 | ||
![]() |
88089e290d | ||
![]() |
5e4d3a35b8 | ||
![]() |
a17b486e4b | ||
![]() |
98544edde5 | ||
![]() |
8913178cf2 | ||
![]() |
0495f2920a | ||
![]() |
3a6776f0fa | ||
![]() |
b5424b4a71 | ||
![]() |
ad37741fdd | ||
![]() |
d81e463507 | ||
![]() |
75ddd879bc | ||
![]() |
d9a8502e27 | ||
![]() |
a80d29d917 | ||
![]() |
294102b27d | ||
![]() |
98f1ac5edb | ||
![]() |
cd6079d869 | ||
![]() |
dcb3d740bc | ||
![]() |
4ca3cf1487 | ||
![]() |
e86bbfbda0 | ||
![]() |
e207124f88 | ||
![]() |
c335099465 | ||
![]() |
f98ccdee46 | ||
![]() |
b79ecfb5fe | ||
![]() |
71d636e8fb | ||
![]() |
653f041140 | ||
![]() |
47f7f3a93f | ||
![]() |
4b0e2a9554 | ||
![]() |
898a1dc679 | ||
![]() |
53842adefc | ||
![]() |
595ab592aa | ||
![]() |
140217d0fe | ||
![]() |
201af23484 | ||
![]() |
6c9f3864e7 | ||
![]() |
d889d26394 | ||
![]() |
05ff16c17f | ||
![]() |
ede03f4366 | ||
![]() |
522391bc3e | ||
![]() |
04db119ae8 | ||
![]() |
a59b78e59e | ||
![]() |
4ec6925220 | ||
![]() |
063e13ef22 | ||
![]() |
506b35840e | ||
![]() |
aa6037c088 | ||
![]() |
289b049377 | ||
![]() |
14bf3184bb | ||
![]() |
748c30206f | ||
![]() |
a55852ea1c | ||
![]() |
61452a835b | ||
![]() |
013dc958b3 | ||
![]() |
5d16352f57 | ||
![]() |
aa05920117 | ||
![]() |
d6c36ae9a3 | ||
![]() |
a73b2403b0 | ||
![]() |
d5a8a3420d | ||
![]() |
7fc188b172 | ||
![]() |
8f116f60c4 | ||
![]() |
8bc76dd2db |
26
.babelrc
26
.babelrc
|
@ -1,34 +1,22 @@
|
|||
{
|
||||
"compact": false,
|
||||
"retainLines": true,
|
||||
"presets": [],
|
||||
"ignore": [
|
||||
"resource/require.js",
|
||||
"chrome/content/zotero/include.js",
|
||||
"resource/tinymce/tinymce.js",
|
||||
"chrome/content/zotero/xpcom/citeproc.js",
|
||||
"resource/csl-validator.js",
|
||||
"resource/react.js",
|
||||
"resource/react-dom.js"
|
||||
"resource/react-dom.js",
|
||||
"resource/bluebird.js",
|
||||
"resource/bluebird/*.js",
|
||||
"test/resource/*.js"
|
||||
],
|
||||
"plugins": [
|
||||
"syntax-flow",
|
||||
"syntax-jsx",
|
||||
"syntax-async-generators",
|
||||
"syntax-class-properties",
|
||||
"syntax-decorators",
|
||||
"syntax-do-expressions",
|
||||
"syntax-export-extensions",
|
||||
"syntax-flow",
|
||||
"syntax-jsx",
|
||||
"syntax-object-rest-spread",
|
||||
"transform-react-jsx",
|
||||
"transform-react-display-name",
|
||||
[
|
||||
"transform-async-to-module-method",
|
||||
{
|
||||
"module": "resource://zotero/bluebird/bluebird.js",
|
||||
"method": "coroutine"
|
||||
}
|
||||
],
|
||||
[
|
||||
"transform-es2015-modules-commonjs",
|
||||
{
|
||||
|
@ -36,4 +24,4 @@
|
|||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
build
|
||||
build
|
||||
.signatures.json
|
||||
tmp
|
||||
|
|
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -1,18 +1,24 @@
|
|||
[submodule "translators"]
|
||||
path = translators
|
||||
url = git://github.com/zotero/translators.git
|
||||
branch = master
|
||||
[submodule "chrome/content/zotero/locale/csl"]
|
||||
path = chrome/content/zotero/locale/csl
|
||||
url = git://github.com/citation-style-language/locales.git
|
||||
branch = master
|
||||
[submodule "styles"]
|
||||
path = styles
|
||||
url = git://github.com/zotero/bundled-styles.git
|
||||
branch = master
|
||||
[submodule "test/resource/chai"]
|
||||
path = test/resource/chai
|
||||
url = https://github.com/chaijs/chai.git
|
||||
branch = master
|
||||
[submodule "test/resource/mocha"]
|
||||
path = test/resource/mocha
|
||||
url = https://github.com/mochajs/mocha.git
|
||||
branch = master
|
||||
[submodule "test/resource/chai-as-promised"]
|
||||
path = test/resource/chai-as-promised
|
||||
url = https://github.com/domenic/chai-as-promised.git
|
||||
branch = master
|
||||
|
|
50
.travis.yml
50
.travis.yml
|
@ -1,26 +1,54 @@
|
|||
sudo: false
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
language: node_js
|
||||
node_js:
|
||||
- "8"
|
||||
cache:
|
||||
directories:
|
||||
- "build"
|
||||
- "node_modules"
|
||||
env:
|
||||
- FX_VERSION="50.1.0"
|
||||
- FX_VERSION="45.0.2esr"
|
||||
global:
|
||||
secure: "NxvkbZ7/Op7BTGQRR3C4q8lLoO29f8WtyNN27NSH7AO3H0vBr1Vp5xO8gn+H2qHEug5HvM+YrZ/xAkNXaZVbOInmBmKVMxqVvdpKp9JM1Amf+gzsXWQphfySvs6iqzyP6cwU/jspdvX/WSakgU5v7PWXxtUIaKxdANt6Rw7W+Pc="
|
||||
matrix:
|
||||
- FX_VERSION="52.0.3"
|
||||
matrix:
|
||||
fast_finish: true
|
||||
#allow_failures:
|
||||
# - env: FX_CHANNEL="beta"
|
||||
notifications:
|
||||
email: false
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- dbus-x11
|
||||
install:
|
||||
- if [ $FX_VERSION = "45.0.2esr" ]; then
|
||||
wget -O tarball "https://archive.mozilla.org/pub/firefox/releases/45.0.2esr/linux-x86_64/en-US/firefox-45.0.2esr.tar.bz2";
|
||||
fi
|
||||
- if [ $FX_VERSION = "50.1.0" ]; then
|
||||
wget -O tarball "http://archive.mozilla.org/pub/firefox/tinderbox-builds/mozilla-release-linux64-add-on-devel/1481240107/firefox-50.1.0.en-US.linux-x86_64-add-on-devel.tar.bz2";
|
||||
- if [ $FX_VERSION = "52.0.3" ]; then
|
||||
wget -O tarball "https://archive.mozilla.org/pub/firefox/tinderbox-builds/mozilla-release-linux64-add-on-devel/1491732920/firefox-52.0.3.en-US.linux-x86_64-add-on-devel.tar.bz2";
|
||||
fi
|
||||
- tar xf tarball
|
||||
before_script:
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- npm i
|
||||
- npm run build
|
||||
- if [[ $TRAVIS_REPO_SLUG = "zotero/zotero" &&
|
||||
($TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = *-hotfix) &&
|
||||
$TRAVIS_PULL_REQUEST = "false" ]]; then
|
||||
mkdir build-zip;
|
||||
cd build;
|
||||
zip -r ../build-zip/$TRAVIS_COMMIT.zip *;
|
||||
cd ..;
|
||||
gem install dpl;
|
||||
dpl --provider=s3
|
||||
--access-key-id=AKIAJFDVJ54MCAEXPQ5Q
|
||||
--bucket=zotero-download
|
||||
--local-dir=build-zip
|
||||
--upload-dir=ci/client
|
||||
--acl=public-read
|
||||
--skip_cleanup=true;
|
||||
fi
|
||||
- unset AWS_SECRET_ACCESS_KEY
|
||||
# Fix warnings in output
|
||||
- dbus-launch
|
||||
script:
|
||||
- test/runtests.sh -x firefox/firefox
|
||||
- test/runtests.sh -x firefox/firefox -f
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
## Bug Reports and Feature Requests
|
||||
|
||||
In order to keep product discussions open to as many people as possible, Zotero does not use GitHub Issues for bug reports or feature requests. Please use the [Zotero Forums](https://forums.zotero.org) to report problems and suggest changes.
|
||||
Zotero does not use GitHub Issues for bug reports or feature requests. Please post all such requests to the [Zotero Forums](https://forums.zotero.org), where Zotero developers and many others can help. Keeping product discussions in the Zotero Forums allows the entire Zotero community to participate, including domain experts that can address many questions better than Zotero developers.
|
||||
|
||||
For confirmed bugs or agreed-upon changes, new issues will be created in the relevant repositories on GitHub by Zotero developers.
|
||||
For confirmed bugs or agreed-upon changes, Zotero developers will create new issues in the relevant repositories.
|
||||
|
||||
## Working with Zotero Code
|
||||
|
||||
|
|
11
COPYING
11
COPYING
|
@ -1,12 +1,15 @@
|
|||
Zotero is Copyright © 2006, 2007, 2008, 2009, 2010, 2011
|
||||
Center for History and New Media, George Mason University,
|
||||
Zotero is Copyright © 2018 Corporation for Digital Scholarship,
|
||||
Vienna, Virginia, USA http://digitalscholar.org
|
||||
|
||||
Copyright © 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
|
||||
Roy Rosenzweig Center for History and New Media, George Mason University,
|
||||
Fairfax, Virginia, USA http://zotero.org
|
||||
|
||||
The Center for History and New Media distributes the Zotero source code
|
||||
The Corporation for Digital Scholarship distributes the Zotero source code
|
||||
under the GNU Affero General Public License, version 3 (AGPLv3). The full text
|
||||
of this license is given below.
|
||||
|
||||
The Zotero name is a registered trademark of George Mason University.
|
||||
The Zotero name is a registered trademark of the Corporation for Digital Scholarship.
|
||||
See http://zotero.org/trademark for more information.
|
||||
|
||||
Third-party copyright in this distribution is noted where applicable.
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
content zotero chrome/content/zotero/
|
||||
content zotero-platform chrome/content/zotero-platform/ platform
|
||||
content zotero-platform chrome/content/zotero-platform/mac/ os=Darwin
|
||||
content zotero-platform chrome/content/zotero-platform/win/ os=WINNT
|
||||
content zotero-platform chrome/content/zotero-platform/unix/ os=Linux
|
||||
content zotero-platform chrome/content/zotero-platform/unix/ os=SunOS
|
||||
content zotero-platform chrome/content/zotero-platform/unix/ os=FreeBSD
|
||||
content zotero-platform chrome/content/zotero-platform/unix/ os=OpenBSD
|
||||
|
||||
resource zotero resource/
|
||||
|
||||
locale zotero en-US chrome/locale/en-US/zotero/
|
||||
|
@ -58,7 +64,6 @@ overlay chrome://zotero/content/preferences/preferences_general.xul chrome://zot
|
|||
overlay chrome://zotero/content/preferences/preferences_export.xul chrome://zotero/content/preferences/preferences_export_firefox.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
|
||||
overlay chrome://zotero/content/preferences/preferences_keys.xul chrome://zotero/content/preferences/preferences_keys_firefox.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
|
||||
overlay chrome://zotero/content/preferences/preferences_advanced.xul chrome://zotero/content/preferences/preferences_advanced_firefox.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
|
||||
overlay chrome://zotero/content/preferences/preferences_advanced.xul chrome://zotero/content/preferences/preferences_advanced_standalone.xul application=zotero@chnm.gmu.edu
|
||||
|
||||
overlay chrome://mozapps/content/downloads/unknownContentType.xul chrome://zotero/content/downloadOverlay.xul
|
||||
|
||||
|
|
|
@ -14,6 +14,10 @@ body[multiline="true"] {
|
|||
width: 800px;
|
||||
}
|
||||
|
||||
#quick-format-dialog.progress-bar #quick-format-deck {
|
||||
height: 37px;
|
||||
}
|
||||
|
||||
#quick-format-search {
|
||||
background: white;
|
||||
-moz-appearance: searchfield;
|
||||
|
|
|
@ -29,4 +29,10 @@ textbox
|
|||
{
|
||||
margin: -1px 5px -1px 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* BEGIN 2X BLOCK -- DO NOT EDIT MANUALLY -- USE 2XIZE */
|
||||
@media (min-resolution: 1.25dppx) {
|
||||
.creator-type-label > image { list-style-image: url('chrome://zotero/skin/mac/arrow-down@2x.png'); }
|
||||
}
|
||||
|
|
|
@ -107,21 +107,37 @@
|
|||
margin-left: 7px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.5dppx) {
|
||||
#zotero-pane .toolbarbutton-icon {
|
||||
max-width: 28px;
|
||||
}
|
||||
|
||||
#zotero-tb-sync-error .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
#zotero-tb-sync-stop .toolbarbutton-icon,
|
||||
#zotero-tb-sync-error .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.zotero-tb-button, .zotero-tb-button:first-child, .zotero-tb-button:last-child {
|
||||
.zotero-tb-button > .toolbarbutton-icon {
|
||||
max-width: 31px;
|
||||
}
|
||||
|
||||
.zotero-tb-button,
|
||||
.zotero-tb-button:first-child,
|
||||
.zotero-tb-button:last-child {
|
||||
-moz-margin-start: 0 !important;
|
||||
-moz-margin-end: 3px !important;
|
||||
-moz-padding-end: 10px !important;
|
||||
background: url("chrome://zotero/skin/mac/menubutton-end.png") right center no-repeat;
|
||||
background: url("chrome://zotero/skin/mac/menubutton-end.png") right center/auto 24px no-repeat;
|
||||
}
|
||||
|
||||
.zotero-tb-button[type=menu] {
|
||||
-moz-padding-end: 8px !important;
|
||||
}
|
||||
|
||||
.zotero-tb-button > .toolbarbutton-icon {
|
||||
background: url("chrome://zotero/skin/mac/menubutton-start.png") left center/auto 24px no-repeat;
|
||||
padding: 4px 4px 4px 11px;
|
||||
}
|
||||
|
||||
/* For menu buttons, decrease left padding by 1px */
|
||||
.zotero-tb-button[type=menu] > .toolbarbutton-icon {
|
||||
-moz-padding-start: 9px;
|
||||
max-width: 29px;
|
||||
}
|
||||
|
||||
#zotero-collections-toolbar {
|
||||
|
@ -129,12 +145,23 @@
|
|||
}
|
||||
|
||||
.zotero-tb-button:-moz-window-inactive {
|
||||
opacity: 0.7;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.zotero-tb-button:-moz-window-inactive > .toolbarbutton-icon {
|
||||
background: url("chrome://zotero/skin/mac/menubutton-start-inactive-window.png") left center/auto 24px no-repeat;
|
||||
}
|
||||
|
||||
/* Use a darker background when inactive so the button itself doesn't get too dark at 50% */
|
||||
.zotero-tb-button:-moz-window-inactive,
|
||||
.zotero-tb-button:-moz-window-inactive:first-child,
|
||||
.zotero-tb-button:-moz-window-inactive:last-child {
|
||||
background: url("chrome://zotero/skin/mac/menubutton-end-inactive-window.png") right center/auto 24px no-repeat;
|
||||
}
|
||||
|
||||
.zotero-tb-button[open="true"],
|
||||
.zotero-tb-button:not([disabled="true"]):hover:active {
|
||||
background: url("chrome://zotero/skin/mac/menubutton-end-pressed.png") right center no-repeat;
|
||||
background: url("chrome://zotero/skin/mac/menubutton-end-pressed.png") right center/auto 24px no-repeat;
|
||||
}
|
||||
|
||||
.zotero-tb-button > menupopup {
|
||||
|
@ -142,17 +169,9 @@
|
|||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.zotero-tb-button > .toolbarbutton-icon {
|
||||
/*-moz-binding: url('chrome://zotero-platform/content/zoterotbbutton.xml#zotero-tb-button');*/
|
||||
background: url("chrome://zotero/skin/mac/menubutton-start.png") left center no-repeat;
|
||||
padding: 5px 1px 5px 11px;
|
||||
}
|
||||
|
||||
#zotero-tb-search-menu-button
|
||||
{
|
||||
margin: -6px -2px -6px -16px;
|
||||
padding: 6px 2px 6px 14px;
|
||||
list-style-image: url("chrome://zotero/skin/mac/searchbar-dropmarker.png");
|
||||
#zotero-tb-search-menu-button {
|
||||
margin: -6px 0 -6px -16px;
|
||||
padding: 6px 0 6px 15px;
|
||||
}
|
||||
|
||||
#zotero-tb-sync > .toolbarbutton-icon {
|
||||
|
@ -167,7 +186,7 @@
|
|||
|
||||
.zotero-tb-button[open="true"] > .toolbarbutton-icon,
|
||||
.zotero-tb-button:not([disabled="true"]):hover:active > .toolbarbutton-icon {
|
||||
background: url("chrome://zotero/skin/mac/menubutton-start-pressed.png") left center no-repeat;
|
||||
background: url("chrome://zotero/skin/mac/menubutton-start-pressed.png") left center/auto 24px no-repeat;
|
||||
}
|
||||
|
||||
.zotero-tb-button > .toolbarbutton-text {
|
||||
|
@ -359,9 +378,7 @@
|
|||
#zotero-collections-splitter[state=collapsed] > grippy, #zotero-items-splitter[state=collapsed] > grippy
|
||||
{
|
||||
-moz-appearance: none;
|
||||
background-image: url("chrome://zotero/skin/mac/vgrippy.png");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background: url(chrome://zotero/skin/mac/vgrippy.png) center/auto 8px no-repeat;
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
|
@ -380,9 +397,7 @@
|
|||
#zotero-tags-splitter > grippy
|
||||
{
|
||||
-moz-appearance: none;
|
||||
background-image: url("chrome://zotero/skin/mac/hgrippy.png");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background: url(chrome://zotero/skin/mac/hgrippy.png) center/auto 8px no-repeat;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
|
@ -459,16 +474,6 @@ treechildren::-moz-tree-image {
|
|||
list-style-image: url('chrome://zotero/skin/mac/toolbar-note-add.png');
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.5dppx) {
|
||||
#zotero-tb-advanced-search {
|
||||
list-style-image: url('chrome://zotero/skin/mac/toolbar-advanced-search@2x.png');
|
||||
}
|
||||
|
||||
#zotero-tb-note-add {
|
||||
list-style-image: url('chrome://zotero/skin/mac/toolbar-note-add@2x.png');
|
||||
}
|
||||
}
|
||||
|
||||
#zotero-tb-actions-menu
|
||||
{
|
||||
list-style-image: url('chrome://zotero/skin/mac/cog.png');
|
||||
|
@ -482,4 +487,19 @@ treechildren::-moz-tree-image {
|
|||
|
||||
#zotero-collectionmenu > .menuitem-iconic > .menu-iconic-left, #zotero-itemmenu > .menuitem-iconic > .menu-iconic-left, #zotero-collectionmenu > .menu-iconic > .menu-iconic-left, #zotero-itemmenu > .menu-iconic > .menu-iconic-left {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* BEGIN 2X BLOCK -- DO NOT EDIT MANUALLY -- USE 2XIZE */
|
||||
@media (min-resolution: 1.25dppx) {
|
||||
.zotero-tb-button,.zotero-tb-button:first-child,.zotero-tb-button:last-child { background: url("chrome://zotero/skin/mac/menubutton-end@2x.png") right center/auto 24px no-repeat; }
|
||||
.zotero-tb-button > .toolbarbutton-icon { background: url("chrome://zotero/skin/mac/menubutton-start@2x.png") left center/auto 24px no-repeat; }
|
||||
.zotero-tb-button:-moz-window-inactive > .toolbarbutton-icon { background: url("chrome://zotero/skin/mac/menubutton-start-inactive-window@2x.png") left center/auto 24px no-repeat; }
|
||||
.zotero-tb-button:-moz-window-inactive,.zotero-tb-button:-moz-window-inactive:first-child,.zotero-tb-button:-moz-window-inactive:last-child { background: url("chrome://zotero/skin/mac/menubutton-end-inactive-window@2x.png") right center/auto 24px no-repeat; }
|
||||
.zotero-tb-button[open="true"],.zotero-tb-button:not([disabled="true"]):hover:active { background: url("chrome://zotero/skin/mac/menubutton-end-pressed@2x.png") right center/auto 24px no-repeat; }
|
||||
.zotero-tb-button[open="true"] > .toolbarbutton-icon,.zotero-tb-button:not([disabled="true"]):hover:active > .toolbarbutton-icon { background: url("chrome://zotero/skin/mac/menubutton-start-pressed@2x.png") left center/auto 24px no-repeat; }
|
||||
#zotero-collections-splitter[state=collapsed] > grippy, #zotero-items-splitter[state=collapsed] > grippy { background: url(chrome://zotero/skin/mac/vgrippy@2x.png) center/auto 8px no-repeat; }
|
||||
#zotero-tags-splitter > grippy { background: url(chrome://zotero/skin/mac/hgrippy@2x.png) center/auto 8px no-repeat; }
|
||||
#zotero-tb-advanced-search { list-style-image: url('chrome://zotero/skin/mac/toolbar-advanced-search@2x.png'); }
|
||||
#zotero-tb-note-add { list-style-image: url('chrome://zotero/skin/mac/toolbar-note-add@2x.png'); }
|
||||
}
|
||||
|
|
|
@ -42,6 +42,14 @@
|
|||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript" src="chrome://global/content/macWindowMenu.js"/>
|
||||
<script>
|
||||
function openPrefs() {
|
||||
var Zotero = Components.classes['@zotero.org/Zotero;1']
|
||||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
Zotero.Utilities.Internal.openPreferences();
|
||||
}
|
||||
</script>
|
||||
|
||||
<commandset id="mainCommandSet">
|
||||
<command id="minimizeWindow"
|
||||
|
@ -83,7 +91,7 @@
|
|||
<menuitem id="menu_preferences"
|
||||
label="&preferencesCmdMac.label;"
|
||||
key="key_preferencesCmdMac"
|
||||
oncommand="Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('navigator:browser').Zotero.Utilities.Internal.openPreferences();"/>
|
||||
oncommand="openPrefs()"/>
|
||||
<menuitem id="menu_mac_services"
|
||||
label="&servicesMenuMac.label;"/>
|
||||
<menuitem id="menu_mac_hide_app"
|
||||
|
|
BIN
chrome/content/zotero-platform/mac/treesource-collection@2x.png
Normal file
BIN
chrome/content/zotero-platform/mac/treesource-collection@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 589 B |
BIN
chrome/content/zotero-platform/mac/treesource-search@2x.png
Normal file
BIN
chrome/content/zotero-platform/mac/treesource-search@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
|
@ -168,8 +168,12 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
background-color: Highlight;
|
||||
}
|
||||
|
||||
#zotero-collections-tree treechildren::-moz-tree-row {
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.5dppx) {
|
||||
|
||||
@media (min-resolution: 1.25dppx) {
|
||||
#zotero-pane .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
@ -179,6 +183,11 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
}
|
||||
}
|
||||
|
||||
/* Dropmarker added automatically on Linux */
|
||||
.toolbarbutton-menu-dropmarker, #zotero-tb-search-menu-button {
|
||||
list-style-image: none;
|
||||
}
|
||||
|
||||
.zotero-tb-button:not([type=menu]) {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
@ -198,12 +207,12 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
}
|
||||
|
||||
/* Fixes tabs missing styling on (GTK 3.20) Ubuntu 16.10. See https://bugzilla.mozilla.org/show_bug.cgi?id=1306425 */
|
||||
#zotero-pane tabpanels, #zotero-prefs tabpanels {
|
||||
tabpanels {
|
||||
-moz-appearance: none;
|
||||
border: 1px solid hsla(0, 0%, 0%, 0.2);
|
||||
|
||||
}
|
||||
#zotero-pane tab, #zotero-prefs tab {
|
||||
tab {
|
||||
-moz-appearance: none;
|
||||
border-top: 1px solid hsla(0, 0%, 0%, 0.2);
|
||||
border-right: 1px solid hsla(0, 0%, 0%, 0.2);
|
||||
|
@ -219,8 +228,14 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
#zotero-prefs .numberbox-input-box{
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
/* Grippy icon missing anyway */
|
||||
#zotero-pane splitter{
|
||||
width: 6px;
|
||||
|
||||
#zotero-prefs #noteFontSize {
|
||||
min-width: 3.8em;
|
||||
}
|
||||
|
||||
#zotero-pane splitter {
|
||||
border: 0;
|
||||
width: 6px;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#view-settings-menu .toolbarbutton-icon {
|
||||
margin-right: 0; /* dropmarker spacing handled automatically on Linux */
|
||||
}
|
|
@ -1,3 +1,18 @@
|
|||
:root {
|
||||
--theme-border-color: #cecece;
|
||||
}
|
||||
|
||||
/* Hide horrible blue effect for menu bar and toolbar */
|
||||
#navigator-toolbox {
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
#zotero-pane #zotero-toolbar {
|
||||
-moz-appearance: none !important;
|
||||
margin-top: -3px;
|
||||
border-bottom-color: var(--theme-border-color);
|
||||
}
|
||||
|
||||
/*
|
||||
As of Fx36, the built-in styles don't properly handle a menu-button within combined buttons.
|
||||
|
||||
|
@ -176,7 +191,7 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
/* End toolbar buttons */
|
||||
|
||||
|
||||
@media (min-resolution: 1.5dppx) {
|
||||
@media (min-resolution: 1.25dppx) {
|
||||
#zotero-toolbar .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
@ -188,23 +203,15 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
|
||||
#zotero-tb-search-menu-button {
|
||||
margin: 0 -1px 0 -4px;
|
||||
padding: 5px 0 5px 5px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
/* Mozilla file copied from chrome://browser/skin/mainwindow-dropdown-arrow.png
|
||||
for availability in Standalone */
|
||||
list-style-image: url("chrome://zotero/skin/win/mainwindow-dropdown-arrow.png");
|
||||
-moz-image-region: rect(0, 13px, 11px, 0);
|
||||
}
|
||||
|
||||
#zotero-tb-search-menu-button .button-menu-dropmarker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#zotero-tb-search-menu-button:hover:active,
|
||||
#zotero-tb-search-menu-button[open="true"] {
|
||||
-moz-image-region: rect(0, 26px, 11px, 13px);
|
||||
}
|
||||
|
||||
#zotero-tb-search .textbox-search-icon {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
@ -229,13 +236,44 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
padding-left: 2px;
|
||||
}
|
||||
|
||||
#zotero-toolbar:-moz-system-metric(windows-compositor) {
|
||||
-moz-appearance: none !important;
|
||||
background-image: -moz-linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0));
|
||||
background-color: rgb(207, 219, 236) !important;
|
||||
border-width: 0 0 1px 0;
|
||||
border-style: solid;
|
||||
border-color: #818790;
|
||||
#zotero-collections-splitter:not([state=collapsed]),
|
||||
#zotero-items-splitter:not([state=collapsed]),
|
||||
#zotero-tags-splitter:not([state=collapsed]) {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
position: relative;
|
||||
/* Positive z-index positions the splitter on top of its siblings and makes
|
||||
it clickable on both sides. */
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#zotero-collections-splitter:not([state=collapsed]),
|
||||
#zotero-items-splitter:not([state=collapsed]):not([orient=vertical]),
|
||||
#zotero-tags-splitter:not([state=collapsed]) {
|
||||
border-inline-end: 1px solid var(--theme-border-color);
|
||||
min-width: 0;
|
||||
width: 3px;
|
||||
margin-inline-start: -3px;
|
||||
}
|
||||
|
||||
#zotero-tags-splitter:not([state=collapsed]),
|
||||
#zotero-items-splitter:not([state=collapsed])[orient=vertical] {
|
||||
border-block-end: 1px solid var(--theme-border-color);
|
||||
min-height: 0;
|
||||
height: 3px;
|
||||
margin-block-start: -3px;
|
||||
}
|
||||
|
||||
#zotero-collections-splitter > grippy,
|
||||
#zotero-items-splitter > grippy,
|
||||
#zotero-tags-splitter > grippy {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
#zotero-collections-splitter:not([state=collapsed]) > grippy,
|
||||
#zotero-items-splitter:not([state=collapsed]) > grippy,
|
||||
#zotero-tags-splitter:not([state=collapsed]) > grippy {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#zotero-collections-tree, #zotero-items-tree, #zotero-view-item {
|
||||
|
@ -250,6 +288,10 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
-moz-border-left-colors: none;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-twisty {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
/* Undo tree row spacing change in Fx25 on Windows */
|
||||
#zotero-collections-tree treechildren::-moz-tree-row,
|
||||
#zotero-items-tree treechildren::-moz-tree-row,
|
||||
|
@ -257,8 +299,8 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
height: 1.6em;
|
||||
}
|
||||
|
||||
#zotero-collections-tree {
|
||||
border-width: 0 1px 1px 0;
|
||||
tree {
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
/* Restore row highlighting on drag over, though I'm not sure how we're losing it to begin with. */
|
||||
|
@ -266,15 +308,31 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
background-color: Highlight;
|
||||
}
|
||||
|
||||
#zotero-items-tree {
|
||||
border-width: 0 1px;
|
||||
#zotero-tag-selector groupbox {
|
||||
-moz-appearance: none;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
#tags-box {
|
||||
padding-top: 0.1em;
|
||||
padding-left: 0.05em;
|
||||
}
|
||||
|
||||
#tags-box button {
|
||||
margin: .04em 0 0 .15em !important;
|
||||
}
|
||||
|
||||
#zotero-editpane-tabs spacer {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
#zotero-view-item {
|
||||
padding: 0 !important;
|
||||
-moz-appearance: none;
|
||||
background-color: -moz-field;
|
||||
border-width: 1px 0 0 1px;
|
||||
border-width: 1px 0 0 0;
|
||||
border-color: var(--theme-border-color);
|
||||
}
|
||||
|
||||
#zotero-view-tabbox > tabs {
|
||||
|
@ -283,10 +341,7 @@ toolbar:not([id="nav-bar"]) #zotero-toolbar-buttons separator {
|
|||
|
||||
#zotero-item-pane-groupbox {
|
||||
-moz-appearance: none !important;
|
||||
border-radius: 0;
|
||||
border-width: 0 0 0 1px;
|
||||
border-color: #818790;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
#zotero-editpane-item-box > scrollbox, #zotero-view-item > tabpanel > vbox,
|
||||
|
|
|
@ -47,11 +47,11 @@
|
|||
key="key_quitApplication"
|
||||
command="cmd_quitApplication"/>
|
||||
</menupopup>
|
||||
<menupopup id="menu_ToolsPopup">
|
||||
<menupopup id="menu_EditPopup">
|
||||
<menuseparator/>
|
||||
<menuitem id="menu_preferences"
|
||||
label="&preferencesCmd2.label;"
|
||||
accesskey="&preferencesCmd2.accesskey;"
|
||||
label="&preferencesCmdUnix.label;"
|
||||
accesskey="&preferencesCmdUnix.accesskey;"
|
||||
oncommand="Zotero.Utilities.Internal.openPreferences();"/>
|
||||
</menupopup>
|
||||
</overlay>
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
button {
|
||||
font-family: Segoe UI, sans-serif;
|
||||
}
|
|
@ -17,41 +17,53 @@
|
|||
|
||||
<vbox id="aboutcontent">
|
||||
<label id="name" value="Zotero"/>
|
||||
<hbox>
|
||||
<label class="zotero-text-link" href="https://www.zotero.org" value="https://www.zotero.org"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<label id="version"/>
|
||||
<label class="zotero-text-link" href="https://www.zotero.org/support/changelog" value="&zotero.whatsNew;"/>
|
||||
<label id="changelog" class="zotero-text-link" href="https://www.zotero.org/support/changelog" value="&zotero.whatsNew;"/>
|
||||
</hbox>
|
||||
<script>
|
||||
document.getElementById('version').textContent = Zotero.version;
|
||||
</script>
|
||||
<hbox>
|
||||
<vbox id="column1">
|
||||
<label class="subhead" value="&zotero.createdby;"/>
|
||||
<vbox class="subcontent">
|
||||
<label class="zotero-text-link" href="https://rrchnm.org/" value="Roy Rosenzweig Center for History and New Media"/>
|
||||
<label value="George Mason University"/>
|
||||
<label value="Fairfax, VA, USA"/>
|
||||
</vbox>
|
||||
<label class="subhead" value="&zotero.director;"/>
|
||||
<vbox class="subcontent">
|
||||
<label value="Sean Takats"/>
|
||||
</vbox>
|
||||
<label class="subhead" value="&zotero.developers;"/>
|
||||
<vbox class="subcontent">
|
||||
<label value="Dan Stillman"/>
|
||||
<label value="Simon Kornblith"/>
|
||||
<label value="Faolan Cheslack-Postava"/>
|
||||
</vbox>
|
||||
<div id="about-text" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="created-by"></p>
|
||||
<p id="get-involved"></p>
|
||||
<script><![CDATA[
|
||||
// Replace [links] in localized strings with spans with onclick handlers
|
||||
//
|
||||
// TODO: Use helper function in common with intro text in itemTreeView.js
|
||||
document.getElementById('created-by').innerHTML =
|
||||
Zotero.Utilities.htmlSpecialChars(Zotero.getString('about.createdBy'))
|
||||
.replace(
|
||||
/\[([^\]]+)](.+)\[([^\]]+)]/,
|
||||
`<span data-href="https://rrchnm.org/">$1</span>`
|
||||
+ '$2'
|
||||
+ `<span data-href="https://www.zotero.org/support/credits_and_acknowledgments">$3</span>`
|
||||
);
|
||||
|
||||
document.getElementById('get-involved').innerHTML =
|
||||
Zotero.Utilities.htmlSpecialChars(Zotero.getString('about.getInvolved'))
|
||||
.replace(
|
||||
/\[([^\]]+)]/,
|
||||
`<span data-href="https://www.zotero.org/getinvolved/">$1</span>`
|
||||
);
|
||||
|
||||
// Activate text links
|
||||
for (let span of document.getElementById('about-text').getElementsByTagName('span')) {
|
||||
span.className = 'text-link';
|
||||
span.onclick = function () {
|
||||
Zotero.launchURL(this.getAttribute('data-href'));
|
||||
};
|
||||
}
|
||||
]]></script>
|
||||
</div>
|
||||
<label class="subhead" value="&zotero.thanks;"/>
|
||||
<vbox class="subcontent">
|
||||
<label class="zotero-text-link" href="http://www.mellon.org/" value="Andrew W. Mellon Foundation"/>
|
||||
<label class="zotero-text-link" href="http://www.imls.gov/" value="Institute of Museum and Library Services"/>
|
||||
<label class="zotero-text-link" href="http://www.sloan.org/" value="Alfred P. Sloan Foundation"/>
|
||||
</vbox>
|
||||
<label class="zotero-text-link" href="https://www.zotero.org/support/credits_and_acknowledgments" value="&zotero.moreCreditsAndAcknowledgements;"/>
|
||||
</vbox>
|
||||
<vbox id="column2">
|
||||
<label class="subhead" value="&zotero.citationProcessing;"/>
|
||||
|
|
|
@ -59,6 +59,7 @@ var ZoteroAdvancedSearch = new function() {
|
|||
|
||||
// A minimal implementation of Zotero.CollectionTreeRow
|
||||
var collectionTreeRow = {
|
||||
view: {},
|
||||
ref: _searchBox.search,
|
||||
isSearchMode: function() { return true; },
|
||||
getItems: Zotero.Promise.coroutine(function* () {
|
||||
|
|
|
@ -146,31 +146,47 @@ var Zotero_File_Interface_Bibliography = new function() {
|
|||
if(_io.useEndnotes && _io.useEndnotes == 1) document.getElementById("displayAs").selectedIndex = 1;
|
||||
let dialog = document.getElementById("zotero-doc-prefs-dialog");
|
||||
dialog.setAttribute('title', `${Zotero.clientName} - ${dialog.getAttribute('title')}`);
|
||||
}
|
||||
if(document.getElementById("formatUsing")) {
|
||||
if(_io.fieldType == "Bookmark") document.getElementById("formatUsing").selectedIndex = 1;
|
||||
var formatOption = (_io.primaryFieldType == "ReferenceMark" ? "referenceMarks" : "fields");
|
||||
document.getElementById("fields").label =
|
||||
Zotero.getString("integration."+formatOption+".label");
|
||||
document.getElementById("fields-caption").textContent =
|
||||
Zotero.getString("integration."+formatOption+".caption");
|
||||
document.getElementById("fields-file-format-notice").textContent =
|
||||
Zotero.getString("integration."+formatOption+".fileFormatNotice");
|
||||
document.getElementById("bookmarks-file-format-notice").textContent =
|
||||
Zotero.getString("integration.fields.fileFormatNotice");
|
||||
}
|
||||
if(document.getElementById("automaticJournalAbbreviations-checkbox")) {
|
||||
if(_io.automaticJournalAbbreviations === undefined) {
|
||||
_io.automaticJournalAbbreviations = Zotero.Prefs.get("cite.automaticJournalAbbreviations");
|
||||
|
||||
if (document.getElementById("formatUsing-groupbox")) {
|
||||
if (["Field", "ReferenceMark"].includes(_io.primaryFieldType)) {
|
||||
if(_io.fieldType == "Bookmark") document.getElementById("formatUsing").selectedIndex = 1;
|
||||
var formatOption = (_io.primaryFieldType == "ReferenceMark" ? "referenceMarks" : "fields");
|
||||
document.getElementById("fields").label =
|
||||
Zotero.getString("integration."+formatOption+".label");
|
||||
document.getElementById("fields-caption").textContent =
|
||||
Zotero.getString("integration."+formatOption+".caption");
|
||||
document.getElementById("fields-file-format-notice").textContent =
|
||||
Zotero.getString("integration."+formatOption+".fileFormatNotice");
|
||||
document.getElementById("bookmarks-file-format-notice").textContent =
|
||||
Zotero.getString("integration.fields.fileFormatNotice");
|
||||
} else {
|
||||
document.getElementById("formatUsing-groupbox").style.display = "none";
|
||||
_io.fieldType = _io.primaryFieldType;
|
||||
}
|
||||
}
|
||||
if(_io.automaticJournalAbbreviations) {
|
||||
document.getElementById("automaticJournalAbbreviations-checkbox").checked = true;
|
||||
if(document.getElementById("automaticJournalAbbreviations-checkbox")) {
|
||||
if(_io.automaticJournalAbbreviations === undefined) {
|
||||
_io.automaticJournalAbbreviations = Zotero.Prefs.get("cite.automaticJournalAbbreviations");
|
||||
}
|
||||
if(_io.automaticJournalAbbreviations) {
|
||||
document.getElementById("automaticJournalAbbreviations-checkbox").checked = true;
|
||||
}
|
||||
|
||||
document.getElementById("automaticCitationUpdates-checkbox").checked = !_io.delayCitationUpdates;
|
||||
}
|
||||
}
|
||||
|
||||
// set style to false, in case this is cancelled
|
||||
_io.style = false;
|
||||
});
|
||||
|
||||
this.openHelpLink = function() {
|
||||
var url = "https://www.zotero.org/support/word_processor_plugin_usage";
|
||||
var win = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator)
|
||||
.getMostRecentWindow("navigator:browser");
|
||||
Zotero.launchURL(url);
|
||||
};
|
||||
|
||||
/*
|
||||
* Called when locale is changed
|
||||
|
@ -192,22 +208,18 @@ var Zotero_File_Interface_Bibliography = new function() {
|
|||
//
|
||||
// For integrationDocPrefs.xul
|
||||
//
|
||||
|
||||
// update status of displayAs box based on style class
|
||||
if(document.getElementById("displayAs-groupbox")) {
|
||||
if (isDocPrefs) {
|
||||
// update status of displayAs box based on style class
|
||||
var isNote = selectedStyleObj.class == "note";
|
||||
document.getElementById("displayAs-groupbox").hidden = !isNote;
|
||||
var multipleNotesSupported = _io.supportedNotes.length > 1;
|
||||
document.getElementById("displayAs-groupbox").hidden = !isNote || !multipleNotesSupported;
|
||||
|
||||
// update status of formatUsing box based on style class
|
||||
if(document.getElementById("formatUsing")) {
|
||||
if(isNote) document.getElementById("formatUsing").selectedIndex = 0;
|
||||
document.getElementById("bookmarks").disabled = isNote;
|
||||
document.getElementById("bookmarks-caption").disabled = isNote;
|
||||
}
|
||||
}
|
||||
|
||||
// update status of displayAs box based on style class
|
||||
if(document.getElementById("automaticJournalAbbreviations-vbox")) {
|
||||
if(isNote) document.getElementById("formatUsing").selectedIndex = 0;
|
||||
document.getElementById("bookmarks").disabled = isNote;
|
||||
document.getElementById("bookmarks-caption").disabled = isNote;
|
||||
|
||||
// update status of displayAs box based on style class
|
||||
document.getElementById("automaticJournalAbbreviations-vbox").hidden =
|
||||
!selectedStyleObj.usesAbbreviation;
|
||||
}
|
||||
|
@ -266,6 +278,7 @@ var Zotero_File_Interface_Bibliography = new function() {
|
|||
}
|
||||
_io.useEndnotes = document.getElementById("displayAs").selectedIndex;
|
||||
_io.fieldType = (document.getElementById("formatUsing").selectedIndex == 0 ? _io.primaryFieldType : _io.secondaryFieldType);
|
||||
_io.delayCitationUpdates = !document.getElementById("automaticCitationUpdates-checkbox").checked;
|
||||
}
|
||||
|
||||
// remember style and locale if user selected these explicitly
|
||||
|
@ -283,8 +296,7 @@ var Zotero_File_Interface_Bibliography = new function() {
|
|||
document.documentElement.getButton('cancel').click();
|
||||
var win = Zotero.Utilities.Internal.openPreferences('zotero-prefpane-cite', { tab: 'styles-tab' });
|
||||
if (isDocPrefs) {
|
||||
// TODO: Move activate() code elsewhere
|
||||
Zotero.Integration.activate(win);
|
||||
Zotero.Utilities.Internal.activate(win);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -160,12 +160,21 @@
|
|||
<parameter name="event"/>
|
||||
<parameter name="type"/>
|
||||
<parameter name="ids"/>
|
||||
<parameter name="extraData"/>
|
||||
<body><![CDATA[
|
||||
if (event != 'modify' || !this.item || !this.item.id) return;
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
if (ids[i] != this.item.id) {
|
||||
for (let id of ids) {
|
||||
if (id != this.item.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var noteEditor = this._id('attachment-note-editor')
|
||||
if (extraData && extraData[id]
|
||||
&& extraData[id].noteEditorID == noteEditor.instanceID) {
|
||||
//Zotero.debug("Skipping notification from current attachment note field");
|
||||
continue;
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
break;
|
||||
}
|
||||
|
@ -201,8 +210,8 @@
|
|||
}
|
||||
|
||||
var firstSpace = val.indexOf(" ");
|
||||
// Crop long uninterrupted text
|
||||
if ((firstSpace == -1 && val.length > 29 ) || firstSpace > 29) {
|
||||
// Crop long uninterrupted text, and use value attribute for empty field
|
||||
if ((firstSpace == -1 && val.length > 29 ) || firstSpace > 29 || val === "") {
|
||||
title.setAttribute('crop', 'end');
|
||||
title.setAttribute('value', val);
|
||||
}
|
||||
|
@ -230,6 +239,7 @@
|
|||
if (this.displayURL) {
|
||||
var urlSpec = this.item.getField('url');
|
||||
urlField.setAttribute('value', urlSpec);
|
||||
urlField.setAttribute('tooltiptext', urlSpec);
|
||||
urlField.setAttribute('hidden', false);
|
||||
if (this.clickableLink) {
|
||||
urlField.onclick = function (event) {
|
||||
|
@ -250,10 +260,17 @@
|
|||
if (this.displayAccessed) {
|
||||
this._id("accessed-label").value = Zotero.getString('itemFields.accessDate')
|
||||
+ Zotero.getString('punctuation.colon');
|
||||
this._id("accessed").value = Zotero.Date.sqlToDate(
|
||||
this.item.getField('accessDate'), true
|
||||
).toLocaleString();
|
||||
accessed.hidden = false;
|
||||
let val = this.item.getField('accessDate');
|
||||
if (val) {
|
||||
val = Zotero.Date.sqlToDate(val, true);
|
||||
}
|
||||
if (val) {
|
||||
this._id("accessed").value = val.toLocaleString();
|
||||
accessed.hidden = false;
|
||||
}
|
||||
else {
|
||||
accessed.hidden = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
accessed.hidden = true;
|
||||
|
@ -525,6 +542,9 @@
|
|||
case Zotero.Fulltext.INDEX_STATE_PARTIAL:
|
||||
str += 'partial';
|
||||
break;
|
||||
case Zotero.Fulltext.INDEX_STATE_QUEUED:
|
||||
str += 'queued';
|
||||
break;
|
||||
case Zotero.Fulltext.INDEX_STATE_INDEXED:
|
||||
str = 'general.yes';
|
||||
break;
|
||||
|
|
|
@ -313,7 +313,6 @@
|
|||
this.itemTypeMenu.parentNode.hidden = true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Clear and rebuild metadata fields
|
||||
//
|
||||
|
@ -427,7 +426,7 @@
|
|||
// Pull out DOI, in case there's a prefix
|
||||
var doi = Zotero.Utilities.cleanDOI(val);
|
||||
if (doi) {
|
||||
doi = "http://dx.doi.org/" + encodeURIComponent(doi);
|
||||
doi = "https://doi.org/" + encodeURIComponent(doi);
|
||||
label.classList.add("pointer");
|
||||
label.setAttribute("onclick", "ZoteroPane_Local.loadURI('" + doi + "', event)");
|
||||
label.setAttribute("tooltiptext", Zotero.getString('locate.online.tooltip'));
|
||||
|
@ -602,10 +601,11 @@
|
|||
}
|
||||
|
||||
// Move to next or previous field if (shift-)tab was pressed
|
||||
if (this._lastTabIndex && this._tabDirection)
|
||||
{
|
||||
this._focusNextField(this._dynamicFields, this._lastTabIndex, this._tabDirection == -1);
|
||||
if (this._lastTabIndex && this._lastTabIndex != -1) {
|
||||
this._focusNextField(this._lastTabIndex);
|
||||
}
|
||||
|
||||
this._refreshed = true;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
@ -933,7 +933,7 @@
|
|||
|
||||
// Switch to single-field mode
|
||||
if (fieldMode == 1) {
|
||||
button.style.backgroundImage = 'url("chrome://zotero/skin/textfield-dual.png")';
|
||||
button.style.background = `url("chrome://zotero/skin/textfield-dual${Zotero.hiDPISuffix}.png") center/21px auto no-repeat`;
|
||||
button.setAttribute('tooltiptext', Zotero.getString('pane.item.switchFieldMode.two'));
|
||||
lastName.setAttribute('fieldMode', '1');
|
||||
button.setAttribute('onclick', "document.getBindingParent(this).switchCreatorMode(Zotero.getAncestorByTagName(this, 'row'), 0, false, true)");
|
||||
|
@ -966,7 +966,7 @@
|
|||
}
|
||||
// Switch to two-field mode
|
||||
else {
|
||||
button.style.backgroundImage = 'url("chrome://zotero/skin/textfield-single.png")';
|
||||
button.style.background = `url("chrome://zotero/skin/textfield-single${Zotero.hiDPISuffix}.png") center/21px auto no-repeat`;
|
||||
button.setAttribute('tooltiptext', Zotero.getString('pane.item.switchFieldMode.one'));
|
||||
lastName.setAttribute('fieldMode', '0');
|
||||
button.setAttribute('onclick', "document.getBindingParent(this).switchCreatorMode(Zotero.getAncestorByTagName(this, 'row'), 1, false, true)");
|
||||
|
@ -1046,6 +1046,10 @@
|
|||
var fields = this.getCreatorFields(row);
|
||||
fields.fieldMode = fieldMode;
|
||||
this.modifyCreator(index, fields);
|
||||
if (this.saveOnEdit) {
|
||||
// See note in transformText()
|
||||
this.blurOpenField().then(() => this.item.saveTx());
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
|
@ -1083,12 +1087,17 @@
|
|||
<method name="changeTypeTo">
|
||||
<parameter name="itemTypeID"/>
|
||||
<parameter name="menu"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
<body><![CDATA[
|
||||
return (async function () {
|
||||
if (itemTypeID == this.item.itemTypeID) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.saveOnEdit) {
|
||||
await this.blurOpenField();
|
||||
await this.item.saveTx();
|
||||
}
|
||||
|
||||
var fieldsToDelete = this.item.getFieldsNotInType(itemTypeID, true);
|
||||
|
||||
// Special cases handled below
|
||||
|
@ -1144,15 +1153,16 @@
|
|||
this.item.setType(itemTypeID);
|
||||
|
||||
if (this.saveOnEdit) {
|
||||
this.item.saveTx();
|
||||
// See note in transformText()
|
||||
await this.blurOpenField();
|
||||
await this.item.saveTx();
|
||||
}
|
||||
else {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
if (this.eventHandlers['itemtypechange'] && this.eventHandlers['itemtypechange'].length) {
|
||||
var self = this;
|
||||
this.eventHandlers['itemtypechange'].forEach(function (f) f.bind(self)());
|
||||
this.eventHandlers['itemtypechange'].forEach(f => f.bind(this)());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1164,8 +1174,8 @@
|
|||
}
|
||||
|
||||
return false;
|
||||
]]>
|
||||
</body>
|
||||
}.bind(this))();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
||||
|
@ -1264,6 +1274,7 @@
|
|||
var valueElement = document.createElement("label");
|
||||
}
|
||||
|
||||
valueElement.setAttribute('id', `itembox-field-value-${fieldName}`);
|
||||
valueElement.setAttribute('fieldname', fieldName);
|
||||
valueElement.setAttribute('flex', 1);
|
||||
|
||||
|
@ -1303,7 +1314,10 @@
|
|||
if (date) {
|
||||
// If no time, interpret as local, not UTC
|
||||
if (Zotero.Date.isSQLDate(valueText)) {
|
||||
date = Zotero.Date.sqlToDate(valueText);
|
||||
// Add time to avoid showing previous day if date is in
|
||||
// DST (including the current date at 00:00:00) and we're
|
||||
// in standard time
|
||||
date = Zotero.Date.sqlToDate(valueText + ' 12:00:00');
|
||||
valueText = date.toLocaleDateString();
|
||||
}
|
||||
else {
|
||||
|
@ -1412,11 +1426,26 @@
|
|||
|
||||
<method name="showEditor">
|
||||
<parameter name="elem"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
// Blur any active fields
|
||||
if (this._dynamicFields) {
|
||||
this._dynamicFields.focus();
|
||||
<body><![CDATA[
|
||||
return (async function () {
|
||||
Zotero.debug(`Showing editor for ${elem.getAttribute('fieldname')}`);
|
||||
|
||||
var label = Zotero.getAncestorByTagName(elem, 'row').querySelector('label');
|
||||
var lastTabIndex = this._lastTabIndex = parseInt(elem.getAttribute('ztabindex'));
|
||||
|
||||
// If a field is open, hide it before selecting the new field, which might
|
||||
// trigger a refresh
|
||||
var activeField = this._dynamicFields.querySelector('textbox');
|
||||
if (activeField) {
|
||||
this._refreshed = false;
|
||||
await this.blurOpenField();
|
||||
this._lastTabIndex = lastTabIndex;
|
||||
// If the box was refreshed, the clicked element is no longer valid,
|
||||
// so just focus by tab index
|
||||
if (this._refreshed) {
|
||||
this._focusNextField(this._lastTabIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// In Firefox 45, when clicking a multiline field such as Extra, the event is
|
||||
|
@ -1425,8 +1454,6 @@
|
|||
elem = elem.parentNode;
|
||||
}
|
||||
|
||||
Zotero.debug('Showing editor');
|
||||
|
||||
var fieldName = elem.getAttribute('fieldname');
|
||||
var tabindex = elem.getAttribute('ztabindex');
|
||||
|
||||
|
@ -1468,6 +1495,7 @@
|
|||
}
|
||||
|
||||
var t = document.createElement("textbox");
|
||||
t.setAttribute('id', `itembox-field-textbox-${fieldName}`);
|
||||
t.setAttribute('value', value);
|
||||
t.setAttribute('fieldname', fieldName);
|
||||
t.setAttribute('ztabindex', tabindex);
|
||||
|
@ -1524,6 +1552,9 @@
|
|||
var box = elem.parentNode;
|
||||
box.replaceChild(t, elem);
|
||||
|
||||
// Associate textbox with label
|
||||
label.setAttribute('control', t.getAttribute('id'));
|
||||
|
||||
// Prevent error when clicking between a changed field
|
||||
// and another -- there's probably a better way
|
||||
if (!t.select) {
|
||||
|
@ -1552,12 +1583,9 @@
|
|||
});
|
||||
t.setAttribute('onkeypress', "return document.getBindingParent(this).handleKeyPress(event)");
|
||||
|
||||
this._tabDirection = false;
|
||||
this._lastTabIndex = tabindex;
|
||||
|
||||
return t;
|
||||
]]>
|
||||
</body>
|
||||
}.bind(this))();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
||||
|
@ -1600,8 +1628,8 @@
|
|||
textbox.getAttribute('fieldname').split('-');
|
||||
|
||||
if (stayFocused) {
|
||||
this._lastTabIndex = parseInt(textbox.getAttribute('ztabindex')) - 1;
|
||||
this._tabDirection = 1;
|
||||
this._lastTabIndex = parseInt(textbox.getAttribute('ztabindex'));
|
||||
this._tabDirection = false;
|
||||
}
|
||||
|
||||
var creator = Zotero.Creators.get(creatorID);
|
||||
|
@ -1634,11 +1662,13 @@
|
|||
fields[creatorField] = creator[creatorField];
|
||||
fields[otherField] = creator[otherField];
|
||||
|
||||
this.ignoreBlur = true;
|
||||
this.modifyCreator(creatorIndex, fields)
|
||||
.then(function () {
|
||||
this.ignoreBlur = false;
|
||||
}.bind(this));
|
||||
this.modifyCreator(creatorIndex, fields);
|
||||
if (this.saveOnEdit) {
|
||||
this.ignoreBlur = true;
|
||||
this.item.saveTx().then(() => {
|
||||
this.ignoreBlur = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise let the autocomplete popup handle matters
|
||||
|
@ -1662,7 +1692,6 @@
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
// Prevent blur on containing textbox
|
||||
// DEBUG: what happens if this isn't present?
|
||||
event.preventDefault();
|
||||
|
@ -1674,7 +1703,7 @@
|
|||
Zotero.debug("Value hasn't changed");
|
||||
// If + button is disabled, just focus next creator row
|
||||
if (Zotero.getAncestorByTagName(target, 'row').lastChild.lastChild.disabled) {
|
||||
this._focusNextField(this._dynamicFields, this._lastTabIndex, false);
|
||||
this._focusNextField(this._lastTabIndex);
|
||||
}
|
||||
else {
|
||||
var creatorFields = this.getCreatorFields(Zotero.getAncestorByTagName(target, 'row'));
|
||||
|
@ -1714,10 +1743,12 @@
|
|||
return false;
|
||||
|
||||
case event.DOM_VK_TAB:
|
||||
this._tabDirection = event.shiftKey ? -1 : 1;
|
||||
// Blur the old manually -- not sure why this is necessary,
|
||||
// but it prevents an immediate blur() on the next tag
|
||||
focused.blur();
|
||||
if (event.shiftKey) {
|
||||
this._focusNextField(this._lastTabIndex, true);
|
||||
}
|
||||
else {
|
||||
this._focusNextField(++this._lastTabIndex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1747,8 +1778,11 @@
|
|||
<method name="hideEditor">
|
||||
<parameter name="textbox"/>
|
||||
<body><![CDATA[
|
||||
return Zotero.spawn(function* () {
|
||||
Zotero.debug('Hiding editor');
|
||||
return (async function () {
|
||||
Zotero.debug(`Hiding editor for ${textbox.getAttribute('fieldname')}`);
|
||||
|
||||
var label = Zotero.getAncestorByTagName(textbox, 'row').querySelector('label');
|
||||
this._lastTabIndex = -1;
|
||||
|
||||
// Prevent autocomplete breakage in Firefox 3
|
||||
if (textbox.mController) {
|
||||
|
@ -1763,6 +1797,7 @@
|
|||
|
||||
var elem;
|
||||
var [field, creatorIndex, creatorField] = fieldName.split('-');
|
||||
var newVal;
|
||||
|
||||
// Creator fields
|
||||
if (field == 'creator') {
|
||||
|
@ -1793,7 +1828,7 @@
|
|||
if (creatorsToShift > 0) {
|
||||
//Add extra creators
|
||||
for (var i=0;i<nameArray.length;i++) {
|
||||
yield this.modifyCreator(i + initNumCreators, otherFields, true);
|
||||
this.modifyCreator(i + initNumCreators, otherFields);
|
||||
}
|
||||
|
||||
//Shift existing creators
|
||||
|
@ -1815,7 +1850,7 @@
|
|||
otherFields.lastName=tempName;
|
||||
otherFields.firstName='';
|
||||
}
|
||||
yield this.modifyCreator(creatorIndex, otherFields, true);
|
||||
this.modifyCreator(creatorIndex, otherFields);
|
||||
creatorIndex++;
|
||||
}
|
||||
this._tabDirection = tabDirectionBuffer;
|
||||
|
@ -1828,11 +1863,7 @@
|
|||
}
|
||||
}
|
||||
else {
|
||||
yield this.modifyCreator(creatorIndex, otherFields);
|
||||
}
|
||||
|
||||
if (this.saveOnEdit) {
|
||||
yield this.item.saveTx();
|
||||
this.modifyCreator(creatorIndex, otherFields);
|
||||
}
|
||||
|
||||
var val = this.item.getCreator(creatorIndex);
|
||||
|
@ -1849,7 +1880,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
var newVal = val;
|
||||
newVal = val;
|
||||
|
||||
// Reset creator mode settings here so that flex attribute gets reset
|
||||
this.switchCreatorMode(row, (otherFields.fieldMode ? 1 : 0), true);
|
||||
if (Zotero.ItemTypes.getName(this.item.itemTypeID) === "bookSection") {
|
||||
var creatorTypeLabels = document.getAnonymousNodes(this)[0].getElementsByClassName("creator-type-label");
|
||||
Zotero.debug(creatorTypeLabels[creatorTypeLabels.length-1] + "");
|
||||
document.getElementById("zotero-author-guidance").show({
|
||||
forEl: creatorTypeLabels[creatorTypeLabels.length-1]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Fields
|
||||
|
@ -1858,8 +1899,12 @@
|
|||
if (value != '') {
|
||||
switch (fieldName) {
|
||||
case 'accessDate':
|
||||
// Allow "now" to use current time
|
||||
if (value == 'now') {
|
||||
value = Zotero.Date.dateToSQL(new Date(), true);
|
||||
}
|
||||
// If just date, don't convert to UTC
|
||||
if (Zotero.Date.isSQLDate(value)) {
|
||||
else if (Zotero.Date.isSQLDate(value)) {
|
||||
var localDate = Zotero.Date.sqlToDate(value);
|
||||
value = Zotero.Date.dateToSQL(localDate).replace(' 00:00:00', '');
|
||||
}
|
||||
|
@ -1914,40 +1959,26 @@
|
|||
}
|
||||
}
|
||||
|
||||
yield this._modifyField(fieldName, value, this.saveOnEdit);
|
||||
|
||||
var newVal = this.item.getField(fieldName);
|
||||
this._modifyField(fieldName, value);
|
||||
newVal = this.item.getField(fieldName);
|
||||
}
|
||||
|
||||
// If box is still open (due to field not being modified and there not being
|
||||
// a refresh), close it manually
|
||||
if (textbox && textbox.parentNode) {
|
||||
elem = this.createValueElement(
|
||||
newVal,
|
||||
fieldName,
|
||||
tabindex
|
||||
);
|
||||
var box = textbox.parentNode;
|
||||
box.replaceChild(elem,textbox);
|
||||
}
|
||||
// Close box
|
||||
elem = this.createValueElement(
|
||||
newVal,
|
||||
fieldName,
|
||||
tabindex
|
||||
);
|
||||
var box = textbox.parentNode;
|
||||
box.replaceChild(elem, textbox);
|
||||
|
||||
if(field === 'creator') {
|
||||
// Reset creator mode settings here so that flex attribute gets reset
|
||||
this.switchCreatorMode(row, (otherFields.fieldMode ? 1 : 0), true);
|
||||
if(Zotero.ItemTypes.getName(this.item.itemTypeID) === "bookSection") {
|
||||
var creatorTypeLabels = document.getAnonymousNodes(this)[0].getElementsByClassName("creator-type-label");
|
||||
Zotero.debug(creatorTypeLabels[creatorTypeLabels.length-1] + "");
|
||||
document.getElementById("zotero-author-guidance").show({
|
||||
forEl: creatorTypeLabels[creatorTypeLabels.length-1]
|
||||
});
|
||||
}
|
||||
}
|
||||
// Disassociate textbox from label
|
||||
label.setAttribute('control', elem.getAttribute('id'));
|
||||
|
||||
if (this._tabDirection) {
|
||||
var focusBox = this._dynamicFields;
|
||||
this._focusNextField(focusBox, this._lastTabIndex, this._tabDirection == -1);
|
||||
if (this.saveOnEdit) {
|
||||
await this.item.saveTx();
|
||||
}
|
||||
}, this);
|
||||
}.bind(this))();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -1978,14 +2009,8 @@
|
|||
<method name="_modifyField">
|
||||
<parameter name="field"/>
|
||||
<parameter name="value"/>
|
||||
<parameter name="save"/>
|
||||
<body><![CDATA[
|
||||
return Zotero.spawn(function* () {
|
||||
this.item.setField(field, value);
|
||||
if (save) {
|
||||
yield this.item.saveTx();
|
||||
}
|
||||
}, this);
|
||||
this.item.setField(field, value);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -2022,7 +2047,7 @@
|
|||
<parameter name="label"/>
|
||||
<parameter name="mode"/>
|
||||
<body><![CDATA[
|
||||
return Zotero.spawn(function* () {
|
||||
return (async function () {
|
||||
var val = this._getFieldValue(label);
|
||||
switch (mode) {
|
||||
case 'title':
|
||||
|
@ -2040,12 +2065,14 @@
|
|||
throw ("Invalid transform mode '" + mode + "' in zoteroitembox.textTransform()");
|
||||
}
|
||||
this._setFieldValue(label, newVal);
|
||||
this._modifyField(label.getAttribute('fieldname'), newVal);
|
||||
if (this.saveOnEdit) {
|
||||
// See note in modifyCreator()
|
||||
yield this.blurOpenField();
|
||||
// If a field is open, blur it, which will trigger a save and cause
|
||||
// the saveTx() to be a no-op
|
||||
await this.blurOpenField();
|
||||
await this.item.saveTx();
|
||||
}
|
||||
return this._modifyField(label.getAttribute('fieldname'), newVal, this.saveOnEdit);
|
||||
}, this);
|
||||
}.bind(this))();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -2085,9 +2112,7 @@
|
|||
<method name="modifyCreator">
|
||||
<parameter name="index"/>
|
||||
<parameter name="fields"/>
|
||||
<parameter name="skipSave"/>
|
||||
<body><![CDATA[
|
||||
return Zotero.spawn(function* () {
|
||||
var libraryID = this.item.libraryID;
|
||||
var firstName = fields.firstName;
|
||||
var lastName = fields.lastName;
|
||||
|
@ -2099,28 +2124,12 @@
|
|||
// Don't save empty creators
|
||||
if (!firstName && !lastName){
|
||||
if (!oldCreator) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
this.item.removeCreator(index);
|
||||
if (this.saveOnEdit && !skipSave) {
|
||||
// Make sure any open field is saved, since a blur() isn't otherwise
|
||||
// triggered clicking directly to a popup menu. (If a field is open, the
|
||||
// saveTx() below will become a no-op.)
|
||||
yield this.blurOpenField();
|
||||
|
||||
return this.item.saveTx();
|
||||
}
|
||||
return;
|
||||
return this.item.removeCreator(index);
|
||||
}
|
||||
|
||||
var changed = this.item.setCreator(index, fields);
|
||||
if (changed && this.saveOnEdit && !skipSave) {
|
||||
// See note above
|
||||
yield this.blurOpenField();
|
||||
|
||||
return this.item.saveTx();
|
||||
}
|
||||
}, this);
|
||||
return this.item.setCreator(index, fields);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -2131,7 +2140,7 @@
|
|||
<method name="swapNames">
|
||||
<parameter name="event"/>
|
||||
<body><![CDATA[
|
||||
return Zotero.Promise.try(function () {
|
||||
return (async function () {
|
||||
var row = Zotero.getAncestorByTagName(document.popupNode, 'row');
|
||||
var typeBox = row.getElementsByAttribute('popup', 'creator-type-menu')[0];
|
||||
var creatorIndex = parseInt(typeBox.getAttribute('fieldname').split('-')[1]);
|
||||
|
@ -2140,8 +2149,13 @@
|
|||
var firstName = fields.firstName;
|
||||
fields.lastName = firstName;
|
||||
fields.firstName = lastName;
|
||||
return this.modifyCreator(creatorIndex, fields);
|
||||
}.bind(this));
|
||||
this.modifyCreator(creatorIndex, fields);
|
||||
if (this.saveOnEdit) {
|
||||
// See note in transformText()
|
||||
await this.blurOpenField();
|
||||
await this.item.saveTx();
|
||||
}
|
||||
}.bind(this))();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -2168,9 +2182,8 @@
|
|||
this.item.setCreator(newIndex, a);
|
||||
this.item.setCreator(index, b);
|
||||
if (this.saveOnEdit) {
|
||||
// See note in modifyCreator()
|
||||
// See note in transformText()
|
||||
yield this.blurOpenField();
|
||||
|
||||
return this.item.saveTx();
|
||||
}
|
||||
}, this);
|
||||
|
@ -2200,7 +2213,7 @@
|
|||
<method name="focusFirstField">
|
||||
<body>
|
||||
<![CDATA[
|
||||
this._focusNextField(this._dynamicFields, 0, false);
|
||||
this._focusNextField(1);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
@ -2215,11 +2228,11 @@
|
|||
completes, so it doesn't know where it's supposed to go next.)
|
||||
-->
|
||||
<method name="_focusNextField">
|
||||
<parameter name="box"/>
|
||||
<parameter name="tabindex"/>
|
||||
<parameter name="back"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
var box = this._dynamicFields;
|
||||
tabindex = parseInt(tabindex);
|
||||
|
||||
// Get all fields with ztabindex attributes
|
||||
|
@ -2241,9 +2254,9 @@
|
|||
}
|
||||
}
|
||||
else {
|
||||
Zotero.debug('Looking for next tabindex after ' + tabindex, 4);
|
||||
Zotero.debug('Looking for tabindex ' + tabindex, 4);
|
||||
for (var pos = 0; pos < tabbableFields.length; pos++) {
|
||||
if (parseInt(tabbableFields[pos].getAttribute('ztabindex')) > tabindex) {
|
||||
if (parseInt(tabbableFields[pos].getAttribute('ztabindex')) >= tabindex) {
|
||||
next = tabbableFields[pos];
|
||||
break;
|
||||
}
|
||||
|
@ -2278,12 +2291,13 @@
|
|||
|
||||
<method name="blurOpenField">
|
||||
<body><![CDATA[
|
||||
return Zotero.spawn(function* () {
|
||||
var textboxes = document.getAnonymousNodes(this)[0].getElementsByTagName('textbox');
|
||||
if (textboxes && textboxes.length) {
|
||||
yield this.blurHandler(textboxes[0]);
|
||||
return (async function () {
|
||||
var activeField = this._dynamicFields.querySelector('textbox');
|
||||
if (!activeField) {
|
||||
return false;
|
||||
}
|
||||
}, this);
|
||||
return this.blurHandler(activeField);
|
||||
}.bind(this))();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -2385,7 +2399,11 @@
|
|||
};
|
||||
itemBox._updateAutoCompleteParams(row, changedParams);
|
||||
|
||||
itemBox.modifyCreator(index, fields);"/>
|
||||
itemBox.modifyCreator(index, fields);
|
||||
if (itemBox.saveOnEdit) {
|
||||
itemBox.item.saveTx();
|
||||
}
|
||||
"/>
|
||||
<menupopup id="zotero-field-transform-menu">
|
||||
<menu label="&zotero.item.textTransform;">
|
||||
<menupopup>
|
||||
|
|
|
@ -380,10 +380,15 @@
|
|||
// Store JSON
|
||||
this._data = val;
|
||||
|
||||
// Create a copy of the JSON that we can clean for display, since the remote object
|
||||
// might reference things that don't exist locally
|
||||
var displayJSON = Object.assign({}, val);
|
||||
displayJSON.collections = [];
|
||||
|
||||
// Create item from JSON for metadata box
|
||||
var item = new Zotero.Item(val.itemType);
|
||||
item.libraryID = this.libraryID;
|
||||
item.fromJSON(val);
|
||||
item.fromJSON(displayJSON);
|
||||
objbox.item = item;
|
||||
]]>
|
||||
</setter>
|
||||
|
|
|
@ -65,6 +65,11 @@
|
|||
switch (val) {
|
||||
case 'view':
|
||||
case 'merge':
|
||||
// If there's an existing editor, mark it as read-only. This allows for
|
||||
// disabling an existing editable note (e.g., if there's a save error).
|
||||
if (this.noteField) {
|
||||
this.noteField.onInit(ed => ed.setMode('readonly'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
|
@ -144,7 +149,7 @@
|
|||
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
this._instanceID = Zotero.Utilities.randomString();
|
||||
this.instanceID = Zotero.Utilities.randomString();
|
||||
this._notifierID = Zotero.Notifier.registerObserver(this, ['item'], 'noteeditor');
|
||||
]]>
|
||||
</constructor>
|
||||
|
@ -167,7 +172,7 @@
|
|||
if (id != this.item.id) {
|
||||
continue;
|
||||
}
|
||||
if (extraData && extraData[id] && extraData[id].noteEditorID == this._instanceID) {
|
||||
if (extraData && extraData[id] && extraData[id].noteEditorID == this.instanceID) {
|
||||
//Zotero.debug("Skipping notification from current note field");
|
||||
continue;
|
||||
}
|
||||
|
@ -243,32 +248,34 @@
|
|||
</method>
|
||||
|
||||
<method name="save">
|
||||
<body>
|
||||
<![CDATA[
|
||||
return Zotero.spawn(function* () {
|
||||
<body><![CDATA[
|
||||
return Zotero.spawn(function* () {
|
||||
try {
|
||||
if (this._mode == 'view') {
|
||||
Zotero.debug("Not saving read-only note");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update note
|
||||
var noteField = this._id('noteField');
|
||||
var value = noteField.value;
|
||||
if (value === null) {
|
||||
Zotero.debug("Note value not available -- not saving", 2);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update note
|
||||
if (this.item) {
|
||||
// If note field doesn't match item, abort save and run error handler
|
||||
if (noteField.getAttribute('itemID') != this.item.id) {
|
||||
if (this.hasAttribute('onerror')) {
|
||||
let fn = new Function("", this.getAttribute('onerror'));
|
||||
fn.call(this)
|
||||
}
|
||||
throw new Error("Note field doesn't match current item");
|
||||
}
|
||||
|
||||
let changed = this.item.setNote(noteField.value);
|
||||
let changed = this.item.setNote(value);
|
||||
if (changed && this.saveOnEdit) {
|
||||
this.noteField.changed = false;
|
||||
yield this.item.saveTx({
|
||||
notifierData: {
|
||||
noteEditorID: this._instanceID
|
||||
noteEditorID: this.instanceID
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -280,7 +287,7 @@
|
|||
if (this.parentItem) {
|
||||
item.libraryID = this.parentItem.libraryID;
|
||||
}
|
||||
item.setNote(noteField.value);
|
||||
item.setNote(value);
|
||||
if (this.parentItem) {
|
||||
item.parentKey = this.parentItem.key;
|
||||
}
|
||||
|
@ -292,10 +299,21 @@
|
|||
}
|
||||
}
|
||||
|
||||
this.item = yield Zotero.Items.getAsync(id);
|
||||
}.bind(this));
|
||||
]]>
|
||||
</body>
|
||||
this.item = item;
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
|
||||
if (this.hasAttribute('onerror')) {
|
||||
let fn = new Function("", this.getAttribute('onerror'));
|
||||
fn.call(this)
|
||||
}
|
||||
if (this.onError) {
|
||||
this.onError(e);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- Used to insert a tab manually -->
|
||||
|
|
|
@ -152,28 +152,7 @@
|
|||
let id = relatedItem.id;
|
||||
let icon = document.createElement("image");
|
||||
icon.className = "zotero-box-icon";
|
||||
let type = Zotero.ItemTypes.getName(relatedItem.itemTypeID);
|
||||
if (type=='attachment')
|
||||
{
|
||||
switch (relatedItem.attaachmentLinkMode) {
|
||||
case Zotero.Attachments.LINK_MODE_LINKED_URL:
|
||||
type += '-web-link';
|
||||
break;
|
||||
|
||||
case Zotero.Attachments.LINK_MODE_IMPORTED_URL:
|
||||
type += '-snapshot';
|
||||
break;
|
||||
|
||||
case Zotero.Attachments.LINK_MODE_LINKED_FILE:
|
||||
type += '-link';
|
||||
break;
|
||||
|
||||
case Zotero.Attachments.LINK_MODE_IMPORTED_FILE:
|
||||
type += '-file';
|
||||
break;
|
||||
}
|
||||
}
|
||||
icon.setAttribute('src','chrome://zotero/skin/treeitem-' + type + '.png');
|
||||
icon.setAttribute('src', relatedItem.getImageSrc());
|
||||
|
||||
var label = document.createElement("label");
|
||||
label.className = "zotero-box-label";
|
||||
|
@ -183,7 +162,7 @@
|
|||
|
||||
var box = document.createElement('box');
|
||||
box.setAttribute('onclick',
|
||||
"document.getBindingParent(this).showItem('" + id + "')");
|
||||
"document.getBindingParent(this).showItem(" + id + ")");
|
||||
box.setAttribute('class','zotero-clicky');
|
||||
box.setAttribute('flex','1');
|
||||
box.appendChild(icon);
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
<constructor><![CDATA[
|
||||
this.mode = this.getAttribute('mode');
|
||||
|
||||
this._onInitCallbacks = [];
|
||||
this._iframe = document.getAnonymousElementByAttribute(this, "anonid", "rt-view");
|
||||
|
||||
// Atomic units, HTML -> RTF (cleanup)
|
||||
|
@ -405,17 +404,17 @@
|
|||
|
||||
var commandEvent = false;
|
||||
|
||||
//Zotero.debug(event.type);
|
||||
if (Zotero.Prefs.get('debugNoteEvents')) {
|
||||
Zotero.debug(event.type);
|
||||
Zotero.debug(event.which);
|
||||
}
|
||||
switch (event.type) {
|
||||
case 'keydown':
|
||||
// Intercept and manually trigger redo for Cmd-Shift-Z,
|
||||
// which keeps it from toggling the Zotero pane instead
|
||||
if (Zotero.isMac && event.metaKey && event.shiftKey && !event.ctrlKey
|
||||
&& !event.altKey && event.keyCode == 90) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
this.redo();
|
||||
return;
|
||||
// Handle forward-delete, which doesn't register as a keypress
|
||||
// when a selection is cleared
|
||||
if (event.which == event.DOM_VK_DELETE) {
|
||||
this._changed = true;
|
||||
commandEvent = true;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -500,6 +499,10 @@
|
|||
<!-- Sets or returns contents of rich text box -->
|
||||
<property name="value">
|
||||
<getter><![CDATA[
|
||||
if (!this._editor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var output = this._editor.getContent().trim();
|
||||
|
||||
if(this._format == "RTF") {
|
||||
|
@ -597,18 +600,13 @@
|
|||
</body>
|
||||
</method>
|
||||
|
||||
<method name="redo">
|
||||
<body>
|
||||
<![CDATA[
|
||||
this._editor.undoManager.redo();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="clearUndo">
|
||||
<body>
|
||||
<![CDATA[
|
||||
this._editor.undoManager.clear();
|
||||
if (this._editor) {
|
||||
this._editor.undoManager.clear();
|
||||
this._editor.undoManager.add();
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
@ -620,6 +618,9 @@
|
|||
callback(this._editor);
|
||||
}
|
||||
else {
|
||||
if (!this._onInitCallbacks) {
|
||||
this._onInitCallbacks = [];
|
||||
}
|
||||
this._onInitCallbacks.push(callback);
|
||||
}
|
||||
]]></body>
|
||||
|
@ -690,10 +691,16 @@
|
|||
}
|
||||
if (self._value) {
|
||||
self.value = self._value;
|
||||
|
||||
// Prevent undoing to empty note after initialization
|
||||
self._editor.undoManager.clear();
|
||||
self._editor.undoManager.add();
|
||||
}
|
||||
if (self._focus) {
|
||||
self._iframe.focus();
|
||||
self._editor.focus();
|
||||
setTimeout(function () {
|
||||
self._iframe.focus();
|
||||
self._editor.focus();
|
||||
});
|
||||
self._focus = false;
|
||||
}
|
||||
|
||||
|
@ -726,8 +733,10 @@
|
|||
}
|
||||
|
||||
let cb;
|
||||
while (cb = this._onInitCallbacks.shift()) {
|
||||
cb(this._editor);
|
||||
if (this._onInitCallbacks) {
|
||||
while (cb = this._onInitCallbacks.shift()) {
|
||||
cb(this._editor);
|
||||
}
|
||||
}
|
||||
}.bind(this);
|
||||
}
|
||||
|
|
|
@ -154,9 +154,10 @@
|
|||
}
|
||||
let data = extraData[ids[i]];
|
||||
let tagName = data.tag;
|
||||
let tagType = data.type;
|
||||
|
||||
if (event == 'add') {
|
||||
var newTabIndex = this.add(tagName);
|
||||
var newTabIndex = this.add(tagName, tagType);
|
||||
if (newTabIndex == -1) {
|
||||
return;
|
||||
}
|
||||
|
@ -174,7 +175,7 @@
|
|||
else if (event == 'modify') {
|
||||
let oldTagName = data.old.tag;
|
||||
this.remove(oldTagName);
|
||||
this.add(tagName);
|
||||
this.add(tagName, tagType);
|
||||
}
|
||||
else if (event == 'remove') {
|
||||
var oldTabIndex = this.remove(tagName);
|
||||
|
@ -320,19 +321,29 @@
|
|||
iconFile += '-automatic';
|
||||
icon.setAttribute('tooltiptext', Zotero.getString('pane.item.tags.icon.automatic'));
|
||||
}
|
||||
icon.setAttribute('src', 'chrome://zotero/skin/' + iconFile + '.png');
|
||||
icon.setAttribute('src', `chrome://zotero/skin/${iconFile}${Zotero.hiDPISuffix}.png`);
|
||||
|
||||
// "-" button
|
||||
if (this.editable) {
|
||||
remove.setAttribute('disabled', false);
|
||||
var self = this;
|
||||
remove.addEventListener('click', function () {
|
||||
remove.addEventListener('click', function (event) {
|
||||
Zotero.spawn(function* () {
|
||||
self._lastTabIndex = false;
|
||||
this._lastTabIndex = false;
|
||||
if (tagData) {
|
||||
let item = document.getBindingParent(this).item
|
||||
item.removeTag(tagName);
|
||||
yield item.saveTx()
|
||||
let item = this.item;
|
||||
this.remove(tagName);
|
||||
try {
|
||||
item.removeTag(tagName);
|
||||
yield item.saveTx()
|
||||
}
|
||||
catch (e) {
|
||||
this.reload();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
// Remove empty textbox row
|
||||
else {
|
||||
row.parentNode.removeChild(row);
|
||||
}
|
||||
|
||||
// Return focus to items pane
|
||||
|
@ -341,7 +352,7 @@
|
|||
tree.focus();
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
}.bind(this));
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
@ -447,7 +458,7 @@
|
|||
var box = elem.parentNode;
|
||||
box.replaceChild(t, elem);
|
||||
|
||||
t.setAttribute('onblur', "return document.getBindingParent(this).blurHandler(this)");
|
||||
t.setAttribute('onblur', "return document.getBindingParent(this).blurHandler(event)");
|
||||
t.setAttribute('onkeypress', "return document.getBindingParent(this).handleKeyPress(event)");
|
||||
t.setAttribute('onpaste', "return document.getBindingParent(this).handlePaste(event)");
|
||||
|
||||
|
@ -498,11 +509,12 @@
|
|||
var fieldname = 'tag';
|
||||
|
||||
var row = Zotero.getAncestorByTagName(target, 'row');
|
||||
let blurOnly = false;
|
||||
|
||||
// If non-empty last row, add new row
|
||||
// If non-empty last row, only blur, because the open textbox will
|
||||
// be cleared in hideEditor() and remain in place
|
||||
if (row == row.parentNode.lastChild && !empty) {
|
||||
var focusField = true;
|
||||
this._tabDirection = 1;
|
||||
blurOnly = true;
|
||||
}
|
||||
// If empty non-last row, refocus current row
|
||||
else if (row != row.parentNode.lastChild && empty) {
|
||||
|
@ -514,9 +526,11 @@
|
|||
this._lastTabIndex = false;
|
||||
}
|
||||
|
||||
target.onblur = null;
|
||||
yield this.blurHandler(target);
|
||||
yield this.blurHandler(event);
|
||||
|
||||
if (blurOnly) {
|
||||
return false;
|
||||
}
|
||||
if (focusField) {
|
||||
this._focusField();
|
||||
}
|
||||
|
@ -537,8 +551,7 @@
|
|||
var tagsbox = Zotero.getAncestorByTagName(focused, 'tagsbox');
|
||||
|
||||
this._lastTabIndex = false;
|
||||
target.onblur = null;
|
||||
yield this.blurHandler(target);
|
||||
yield this.blurHandler(event);
|
||||
|
||||
if (tagsbox) {
|
||||
tagsbox.closePopup();
|
||||
|
@ -562,8 +575,7 @@
|
|||
}
|
||||
|
||||
this._tabDirection = event.shiftKey ? -1 : 1;
|
||||
target.onblur = null;
|
||||
yield this.blurHandler(target);
|
||||
yield this.blurHandler(event);
|
||||
this._focusField();
|
||||
return false;
|
||||
}
|
||||
|
@ -633,8 +645,10 @@
|
|||
|
||||
|
||||
<method name="hideEditor">
|
||||
<parameter name="textbox"/>
|
||||
<parameter name="event"/>
|
||||
<body><![CDATA[
|
||||
var textbox = event.target;
|
||||
|
||||
return Zotero.spawn(function* () {
|
||||
Zotero.debug('Hiding editor');
|
||||
|
||||
|
@ -675,14 +689,35 @@
|
|||
if (value !== "") {
|
||||
if (oldValue !== value) {
|
||||
// The existing textbox will be removed in notify()
|
||||
this.item.replaceTag(oldValue, value);
|
||||
yield this.item.saveTx();
|
||||
this.removeRow(row);
|
||||
this.add(value);
|
||||
if (event.type != 'blur') {
|
||||
this._focusField();
|
||||
}
|
||||
try {
|
||||
this.item.replaceTag(oldValue, value);
|
||||
yield this.item.saveTx();
|
||||
}
|
||||
catch (e) {
|
||||
this.reload();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Existing tag cleared
|
||||
else {
|
||||
this.item.removeTag(oldValue);
|
||||
yield this.item.saveTx();
|
||||
try {
|
||||
this.removeRow(row);
|
||||
if (event.type != 'blur') {
|
||||
this._focusField();
|
||||
}
|
||||
this.item.removeTag(oldValue);
|
||||
yield this.item.saveTx();
|
||||
}
|
||||
catch (e) {
|
||||
this.reload();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Multiple tags
|
||||
|
@ -714,11 +749,21 @@
|
|||
}
|
||||
// Single tag at end
|
||||
else {
|
||||
// Remove the textbox row. The new tag will be added in notify()
|
||||
// if it doesn't already exist.
|
||||
row.parentNode.removeChild(row);
|
||||
if (event.type == 'blur') {
|
||||
this.removeRow(row);
|
||||
}
|
||||
else {
|
||||
textbox.value = '';
|
||||
}
|
||||
this.add(value);
|
||||
this.item.addTag(value);
|
||||
yield this.item.saveTx();
|
||||
try {
|
||||
yield this.item.saveTx();
|
||||
}
|
||||
catch (e) {
|
||||
this.reload();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
]]></body>
|
||||
|
@ -732,7 +777,7 @@
|
|||
var rows = rowsElement.childNodes;
|
||||
|
||||
// Don't add new row if there already is one
|
||||
if (rows.length > this.count) {
|
||||
if (rows.length && rows[rows.length - 1].querySelector('textbox')) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -758,6 +803,7 @@
|
|||
|
||||
<method name="add">
|
||||
<parameter name="tagName"/>
|
||||
<parameter name="tagType"/>
|
||||
<body><![CDATA[
|
||||
var rowsElement = this.id('tagRows');
|
||||
var rows = rowsElement.childNodes;
|
||||
|
@ -772,7 +818,7 @@
|
|||
|
||||
var tagData = {
|
||||
tag: tagName,
|
||||
type: this.item.getTagType(tagName)
|
||||
type: tagType
|
||||
};
|
||||
|
||||
if (row) {
|
||||
|
@ -810,7 +856,9 @@
|
|||
continue;
|
||||
}
|
||||
|
||||
if (collation.compareString(1, tagName, labels[i].textContent) > 0) {
|
||||
if (collation.compareString(1, tagName, labels[i].textContent) > 0
|
||||
// Ignore textbox at end
|
||||
&& labels[i].tagName != 'textbox') {
|
||||
labels[i].setAttribute('ztabindex', index);
|
||||
continue;
|
||||
}
|
||||
|
@ -826,6 +874,8 @@
|
|||
rowsElement.appendChild(row);
|
||||
}
|
||||
|
||||
this.updateCount(this.count + 1);
|
||||
|
||||
return newTabIndex;
|
||||
]]></body>
|
||||
</method>
|
||||
|
@ -841,16 +891,8 @@
|
|||
for (var i=0; i<rows.length; i++) {
|
||||
let value = rows[i].getAttribute('tagName');
|
||||
if (value === tagName) {
|
||||
oldTabIndex = i + 1;
|
||||
removed = true;
|
||||
rowsElement.removeChild(rows[i]);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
// After the removal, update tab indexes
|
||||
if (removed) {
|
||||
var elem = rows[i].getElementsByAttribute('fieldname', 'tag')[0];
|
||||
elem.setAttribute('ztabindex', i + 1);
|
||||
oldTabIndex = this.removeRow(rows[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return oldTabIndex;
|
||||
|
@ -858,6 +900,37 @@
|
|||
</method>
|
||||
|
||||
|
||||
<!--
|
||||
Remove the row and update tab indexes
|
||||
-->
|
||||
<method name="removeRow">
|
||||
<parameter name="row"/>
|
||||
<body><![CDATA[
|
||||
var origTabIndex = row.getElementsByAttribute('fieldname', 'tag')[0]
|
||||
.getAttribute('ztabindex');
|
||||
var origRow = row;
|
||||
var i = origTabIndex;
|
||||
while (row = row.nextSibling) {
|
||||
let elem = row.getElementsByAttribute('fieldname', 'tag')[0];
|
||||
elem.setAttribute('ztabindex', i++);
|
||||
}
|
||||
origRow.parentNode.removeChild(origRow);
|
||||
this.updateCount(this.count - 1);
|
||||
return origTabIndex;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
||||
<method name="removeAll">
|
||||
<body><![CDATA[
|
||||
if (Services.prompt.confirm(null, "", Zotero.getString('pane.item.tags.removeAll'))) {
|
||||
this.item.setTags([]);
|
||||
this.item.saveTx();
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
||||
<method name="updateCount">
|
||||
<parameter name="count"/>
|
||||
<body>
|
||||
|
@ -868,10 +941,12 @@
|
|||
|
||||
if(typeof count == 'undefined') {
|
||||
var tags = this.item.getTags();
|
||||
if(tags)
|
||||
if (tags) {
|
||||
count = tags.length;
|
||||
else
|
||||
}
|
||||
else {
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var str = 'pane.item.tags.count.';
|
||||
|
@ -983,6 +1058,24 @@
|
|||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_onAddButtonPress">
|
||||
<parameter name="event"/>
|
||||
<body><![CDATA[
|
||||
return async function () {
|
||||
await this.blurOpenField();
|
||||
this.newTag();
|
||||
}.bind(this)();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
||||
<method name="_onBackgroundContextMenuShowing">
|
||||
<body><![CDATA[
|
||||
var removeAllTags = this.id('remove-all-item-tags');
|
||||
removeAllTags.disabled = this.count == 0;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
||||
<!-- unused -->
|
||||
<method name="getTagIndex">
|
||||
|
@ -1026,14 +1119,20 @@
|
|||
|
||||
|
||||
<method name="blurOpenField">
|
||||
<parameter name="stayOpen"/>
|
||||
<body><![CDATA[
|
||||
return Zotero.spawn(function* () {
|
||||
this._lastTabIndex = false;
|
||||
|
||||
var textboxes = document.getAnonymousNodes(this)[0].getElementsByTagName('textbox');
|
||||
if (textboxes && textboxes.length) {
|
||||
textboxes[0].inputField.onblur = null;
|
||||
yield this.blurHandler(textboxes[0].inputField);
|
||||
yield this.blurHandler({
|
||||
target: textboxes[0],
|
||||
// If coming from the Add button, pretend user pressed return
|
||||
type: stayOpen ? 'keypress' : 'blur',
|
||||
// DOM_VK_RETURN
|
||||
keyCode: stayOpen ? 13 : undefined
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
]]>
|
||||
|
@ -1051,12 +1150,20 @@
|
|||
</method>
|
||||
</implementation>
|
||||
<content>
|
||||
<xul:scrollbox xbl:inherits="flex" orient="vertical" style="overflow:auto" class="zotero-box">
|
||||
<xul:scrollbox xbl:inherits="flex" orient="vertical" style="overflow:auto" class="zotero-box"
|
||||
context="tags-context-menu">
|
||||
<xul:popupset>
|
||||
<xul:menupopup id="tags-context-menu"
|
||||
onpopupshowing="document.getBindingParent(this)._onBackgroundContextMenuShowing()">
|
||||
<xul:menuitem id="remove-all-item-tags" label="&zotero.item.tags.removeAll;"
|
||||
oncommand="document.getBindingParent(this).removeAll()"/>
|
||||
</xul:menupopup>
|
||||
</xul:popupset>
|
||||
<xul:hbox align="center">
|
||||
<xul:label id="tagsNum"/>
|
||||
<xul:button id="addButton" label="&zotero.item.add;"
|
||||
onkeypress="return document.getBindingParent(this)._onAddButtonKeypress(event)"
|
||||
oncommand="document.getBindingParent(this).newTag();"/>
|
||||
oncommand="return document.getBindingParent(this)._onAddButtonPress(event)"/>
|
||||
</xul:hbox>
|
||||
<xul:grid>
|
||||
<xul:columns>
|
||||
|
|
|
@ -121,23 +121,25 @@
|
|||
|
||||
<field name="_hasScope">false</field>
|
||||
<field name="_scope">null</field>
|
||||
<property name="scope" onget="return this._scope">
|
||||
<property name="scope">
|
||||
<setter>
|
||||
<![CDATA[
|
||||
if (val.length) {
|
||||
this._hasScope = true;
|
||||
this._scope = {};
|
||||
this._scope = new Map();
|
||||
for (let i=0; i<val.length; i++) {
|
||||
let tag = val[i];
|
||||
if (!this._scope[tag.tag]) {
|
||||
this._scope[tag.tag] = [];
|
||||
let types = this._scope.get(tag.tag);
|
||||
if (!types) {
|
||||
types = []
|
||||
}
|
||||
this._scope[tag.tag].push(tag.type || 0);
|
||||
types.push(tag.type || 0);
|
||||
this._scope.set(tag.tag, types);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._hasScope = false;
|
||||
this._scope = {};
|
||||
this._scope = new Map();
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
|
@ -268,21 +270,21 @@
|
|||
// Otherwise just update based on visibility
|
||||
else {
|
||||
// If only a few tags, regenerate buttons from scratch
|
||||
if (this.filterToScope && Object.keys(this.scope).length <= 100) {
|
||||
if (this.filterToScope && this._scope.size <= 100) {
|
||||
// If full set is currently displayed, store it for later
|
||||
if (!this._tagsDiv) {
|
||||
this._tagsDiv = tagsBox.firstChild;
|
||||
}
|
||||
|
||||
let tags = [];
|
||||
for (let name in this.scope) {
|
||||
tags.push(...this.scope[name].map(type => {
|
||||
this._scope.forEach(function (types, name) {
|
||||
tags.push(...types.map(type => {
|
||||
return {
|
||||
tag: name,
|
||||
type: type
|
||||
type
|
||||
};
|
||||
}));
|
||||
}
|
||||
});
|
||||
let { div, emptyRegular } = this.createTagsList(tags);
|
||||
tagsBox.replaceChild(div, tagsBox.firstChild);
|
||||
this._emptyRegular = emptyRegular;
|
||||
|
@ -833,6 +835,59 @@
|
|||
</method>
|
||||
|
||||
|
||||
<method name="_updateDeleteAutomaticMenuOption">
|
||||
<body><![CDATA[
|
||||
(async function () {
|
||||
var hasAutomatic = !!(await Zotero.Tags.getAutomaticInLibrary(this.libraryID)).length;
|
||||
var menuitem = this.id('delete-automatic-tags');
|
||||
menuitem.disabled = !hasAutomatic;
|
||||
}.bind(this))();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
||||
<method name="_deleteAutomatic">
|
||||
<body><![CDATA[
|
||||
(async function () {
|
||||
var num = (await Zotero.Tags.getAutomaticInLibrary(this.libraryID)).length;
|
||||
if (!num) {
|
||||
return;
|
||||
}
|
||||
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
var confirmed = ps.confirm(
|
||||
window,
|
||||
Zotero.getString('pane.tagSelector.deleteAutomatic.title'),
|
||||
Zotero.getString(
|
||||
'pane.tagSelector.deleteAutomatic.message',
|
||||
new Intl.NumberFormat().format(num),
|
||||
num
|
||||
)
|
||||
+ "\n\n"
|
||||
+ Zotero.getString('general.actionCannotBeUndone')
|
||||
);
|
||||
if (confirmed) {
|
||||
Zotero.showZoteroPaneProgressMeter(null, true);
|
||||
try {
|
||||
await Zotero.Tags.removeAutomaticFromLibrary(
|
||||
this.libraryID,
|
||||
(progress, progressMax) => {
|
||||
Zotero.updateZoteroPaneProgressMeter(
|
||||
Math.round(progress / progressMax * 100)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
finally {
|
||||
Zotero.hideZoteroPaneOverlays();
|
||||
}
|
||||
}
|
||||
}.bind(this))();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
||||
<method name="_insertClickableTag">
|
||||
<parameter name="tagsBox"/>
|
||||
<parameter name="tagData"/>
|
||||
|
@ -859,6 +914,9 @@
|
|||
if (tagObj.type) {
|
||||
elem.setAttribute('tagType', tagObj.type);
|
||||
}
|
||||
// Take the tags out of the tab order so that tabbing moves from the collections
|
||||
// pane to the items pane
|
||||
elem.setAttribute('tabindex', "-1");
|
||||
return elem;
|
||||
]]></body>
|
||||
</method>
|
||||
|
@ -891,7 +949,7 @@
|
|||
|
||||
// Check tags against scope
|
||||
if (this._hasScope) {
|
||||
var inScope = !!this._scope[name];
|
||||
var inScope = this._scope.has(name);
|
||||
}
|
||||
|
||||
// If not in search, hide
|
||||
|
@ -1102,17 +1160,21 @@
|
|||
<label value="&zotero.tagSelector.noTagsToDisplay;"/>
|
||||
</box>
|
||||
|
||||
<html:div id="tags-box"/>
|
||||
<html:div id="tags-box" tabindex="-1"/>
|
||||
</deck>
|
||||
|
||||
<vbox id="tag-controls">
|
||||
<hbox>
|
||||
<textbox id="tags-search" flex="1" type="search" timeout="250" dir="reverse"
|
||||
oncommand="document.getBindingParent(this).handleKeyPress(); event.stopPropagation()"
|
||||
onkeypress="if (event.keyCode == event.DOM_VK_ESCAPE) { document.getBindingParent(this).handleKeyPress(true); }"/>
|
||||
<toolbarbutton id="view-settings-menu" tooltiptext="&zotero.toolbar.actions.label;"
|
||||
image="chrome://zotero/skin/tag-selector-menu.png" type="menu">
|
||||
onkeypress="if (event.keyCode == event.DOM_VK_ESCAPE) { document.getBindingParent(this).handleKeyPress(true); }"
|
||||
tabindex="-1"/>
|
||||
<toolbarbutton
|
||||
id="view-settings-menu"
|
||||
tooltiptext="&zotero.toolbar.actions.label;"
|
||||
type="menu">
|
||||
<menupopup id="view-settings-popup"
|
||||
onpopupshowing="document.getBindingParent(this)._updateDeleteAutomaticMenuOption()"
|
||||
onpopupshown="/*
|
||||
This is necessary to fix a bug with Display All Tags not
|
||||
being checked if enabled before menuu is shown (OS X only?)
|
||||
|
@ -1136,6 +1198,11 @@
|
|||
this.setAttribute('checked', !displayAll);
|
||||
document.getBindingParent(this).filterToScope = !displayAll;
|
||||
event.stopPropagation();"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="delete-automatic-tags" label="&zotero.tagSelector.deleteAutomaticInLibrary;" type="checkbox"
|
||||
oncommand="document.getBindingParent(this)._deleteAutomatic();
|
||||
this.setAttribute('checked', false);
|
||||
event.stopPropagation();"/>
|
||||
</menupopup>
|
||||
</toolbarbutton>
|
||||
</hbox>
|
||||
|
|
|
@ -49,7 +49,16 @@
|
|||
<![CDATA[
|
||||
this.searchRef = val;
|
||||
|
||||
this.buildLibraryMenu();
|
||||
var libraryMenu = this.id('libraryMenu');
|
||||
var libraries = Zotero.Libraries.getAll();
|
||||
Zotero.Utilities.Internal.buildLibraryMenu(
|
||||
libraryMenu, libraries, this.searchRef.libraryID
|
||||
);
|
||||
if (this.searchRef.id) {
|
||||
libraryMenu.disabled = true;
|
||||
}
|
||||
this.updateLibrary();
|
||||
|
||||
|
||||
var conditionsBox = this.id('conditions');
|
||||
while(conditionsBox.hasChildNodes())
|
||||
|
@ -81,43 +90,6 @@
|
|||
</setter>
|
||||
</property>
|
||||
|
||||
<method name="buildLibraryMenu">
|
||||
<body><![CDATA[
|
||||
var menulist = this.id('libraryMenu');
|
||||
var menupopup = menulist.firstChild;
|
||||
|
||||
while (menupopup.hasChildNodes()) {
|
||||
menupopup.removeChild(menupopup.firstChild);
|
||||
}
|
||||
|
||||
var libraryID = this.searchRef.libraryID;
|
||||
var libraryIndex = 0;
|
||||
|
||||
var libraries = Zotero.Libraries.getAll();
|
||||
var selectedIndex = 0;
|
||||
var i = 0;
|
||||
for (let library of libraries) {
|
||||
let menuitem = document.createElement('menuitem');
|
||||
menuitem.setAttribute('label', library.name);
|
||||
menuitem.setAttribute('libraryID', library.libraryID);
|
||||
menupopup.appendChild(menuitem);
|
||||
if (library.libraryID == libraryID) {
|
||||
selectedIndex = i;
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
menulist.appendChild(menupopup);
|
||||
menulist.selectedIndex = selectedIndex;
|
||||
|
||||
if (this.searchRef.id) {
|
||||
this.id('libraryMenu').disabled = true;
|
||||
}
|
||||
|
||||
this.updateLibrary();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="addCondition">
|
||||
<parameter name="ref"/>
|
||||
<body>
|
||||
|
@ -170,7 +142,7 @@
|
|||
<method name="updateLibrary">
|
||||
<body><![CDATA[
|
||||
var menu = this.id('libraryMenu');
|
||||
var libraryID = parseInt(menu.selectedItem.getAttribute('libraryID'));
|
||||
var libraryID = parseInt(menu.selectedItem.value);
|
||||
|
||||
if (this.onLibraryChange) {
|
||||
this.onLibraryChange(libraryID);
|
||||
|
@ -437,6 +409,7 @@
|
|||
case 'dateModified':
|
||||
case 'itemType':
|
||||
case 'fileTypeID':
|
||||
case 'publicationTitle':
|
||||
case 'tag':
|
||||
case 'note':
|
||||
case 'childNote':
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
margin-top: 38px;
|
||||
padding: 10px 9px;
|
||||
font-family: Monaco, Consolas, Inconsolata, monospace;
|
||||
font-size: 9pt;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
#errors {
|
||||
|
|
|
@ -3,8 +3,18 @@
|
|||
var interval = 1000;
|
||||
var intervalID;
|
||||
var stopping = false;
|
||||
var scrolling = false;
|
||||
var autoscroll = true;
|
||||
|
||||
function start() {
|
||||
// If scrolled to the bottom of the page, stay there
|
||||
document.body.onscroll = function (event) {
|
||||
if (!scrolling) {
|
||||
autoscroll = atPageBottom();
|
||||
}
|
||||
scrolling = false;
|
||||
};
|
||||
|
||||
updateErrors().then(function () {
|
||||
if (stopping) return;
|
||||
|
||||
|
@ -31,13 +41,9 @@ function updateErrors() {
|
|||
var errors = Zotero.getErrors(true);
|
||||
var errorStr = errors.length ? errors.join('\n\n') + '\n\n' : '';
|
||||
|
||||
var scroll = atPageBottom();
|
||||
|
||||
document.getElementById('errors').textContent = errorStr + sysInfo;
|
||||
|
||||
// TODO: This doesn't seem to work for some reason -- when errors are logged, it doesn't stay
|
||||
// at the bottom
|
||||
if (scroll) {
|
||||
if (autoscroll) {
|
||||
scrollToPageBottom();
|
||||
}
|
||||
});
|
||||
|
@ -50,15 +56,12 @@ function addInitialOutput() {
|
|||
}
|
||||
|
||||
function addLine(line) {
|
||||
var scroll = atPageBottom()
|
||||
|
||||
var p = document.createElement('p');
|
||||
p.textContent = line;
|
||||
var output = document.getElementById('output');
|
||||
output.appendChild(p);
|
||||
|
||||
// If scrolled to the bottom of the page, stay there
|
||||
if (scroll) {
|
||||
if (autoscroll) {
|
||||
scrollToPageBottom();
|
||||
}
|
||||
|
||||
|
@ -71,6 +74,8 @@ function atPageBottom() {
|
|||
}
|
||||
|
||||
function scrollToPageBottom() {
|
||||
// Set a flag when auto-scrolling to differentiate from manual scrolls
|
||||
scrolling = true;
|
||||
window.scrollTo(0, document.body.scrollHeight);
|
||||
}
|
||||
|
||||
|
@ -180,6 +185,7 @@ function clearSubmitStatus() {
|
|||
}
|
||||
|
||||
function clearOutput(button) {
|
||||
document.getElementById('submit-button').setAttribute('disabled', '');
|
||||
button.setAttribute('disabled', '');
|
||||
document.getElementById('output').textContent = '';
|
||||
clearSubmitStatus();
|
||||
|
|
|
@ -125,8 +125,7 @@ var Zotero_DownloadOverlay = new function() {
|
|||
try {
|
||||
if (item && item.getFile()) {
|
||||
timer.cancel();
|
||||
var recognizer = new win.Zotero_RecognizePDF.ItemRecognizer();
|
||||
recognizer.recognizeItems([item]);
|
||||
Zotero.RecognizePDF.recognizeItems([item]);
|
||||
}
|
||||
} catch(e) { dump(e.toSource()) };
|
||||
}, 1000, Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
|
||||
|
@ -145,15 +144,7 @@ var Zotero_DownloadOverlay = new function() {
|
|||
// to happen automatically
|
||||
if(zoteroSelected) document.getElementById('rememberChoice').selected = false;
|
||||
document.getElementById('rememberChoice').disabled = zoteroSelected;
|
||||
|
||||
// disable recognizePDF checkbox as necessary
|
||||
if(!Zotero.Fulltext.pdfConverterIsRegistered()) {
|
||||
document.getElementById('zotero-noPDFTools-description').hidden = !zoteroSelected;
|
||||
document.getElementById('zotero-recognizePDF').disabled = true;
|
||||
window.sizeToContent();
|
||||
} else {
|
||||
document.getElementById('zotero-recognizePDF').disabled = !zoteroSelected;
|
||||
}
|
||||
document.getElementById('zotero-recognizePDF').disabled = !zoteroSelected;
|
||||
|
||||
Zotero_DownloadOverlay.updateLibraryNote();
|
||||
};
|
||||
|
@ -212,9 +203,6 @@ var Zotero_DownloadOverlay = new function() {
|
|||
recognizePDF.label = Zotero.getString("pane.items.menu.recognizePDF");
|
||||
recognizePDF.hidden = false;
|
||||
recognizePDF.disabled = true;
|
||||
if(!Zotero.Fulltext.pdfConverterIsRegistered()) {
|
||||
recognizePDF.checked = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
<vbox style="margin-left: 15px">
|
||||
<description id="zotero-saveToLibrary-description" style="font: small-caption; font-weight: normal" hidden="true">&zotero.downloadManager.saveToLibrary.description;</description>
|
||||
<checkbox id="zotero-recognizePDF" hidden="true" persist="checked" disabled="true"/>
|
||||
<description style="margin-left: 20px; font: small-caption; font-weight: normal" id="zotero-noPDFTools-description" hidden="true">&zotero.downloadManager.noPDFTools.description;</description>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</radiogroup>
|
||||
|
|
|
@ -147,7 +147,6 @@
|
|||
<wizardpage onpageshow="Zotero_Error_Report.init()" label=" ">
|
||||
<description id="zotero-failure-message"/>
|
||||
<textbox id="zotero-error-message" class="plain" readonly="true" multiline="true" flex="1"/>
|
||||
<description id="zotero-unrelated-message">&zotero.general.note; &zotero.errorReport.unrelatedMessages;</description>
|
||||
<description id="zotero-advance-message"/>
|
||||
</wizardpage>
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ var Zotero_File_Interface_Export = new function() {
|
|||
}
|
||||
|
||||
// handle charset popup
|
||||
if(_charsets && translatorOptions.exportCharset) {
|
||||
if(_charsets && translatorOptions && translatorOptions.exportCharset) {
|
||||
optionsBox.hidden = undefined;
|
||||
document.getElementById("charset-box").hidden = undefined;
|
||||
var charsetMenu = document.getElementById(OPTION_PREFIX+"exportCharset");
|
||||
|
|
|
@ -42,7 +42,7 @@ var Zotero_Feed_Settings = new function() {
|
|||
if (/^https?:\/\/[^\/\s]+\/\S/.test(cleanURL)) {
|
||||
return cleanURL;
|
||||
} else {
|
||||
Zotero.debug(uri.scheme + " is not a supported protocol for feeds");
|
||||
Zotero.debug(url + " has an unsupported protocol for feeds");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm")
|
||||
|
||||
/****Zotero_File_Exporter****
|
||||
**
|
||||
* A class to handle exporting of items, collections, or the entire library
|
||||
|
@ -126,7 +128,6 @@ var Zotero_File_Interface = new function() {
|
|||
this.exportCollection = exportCollection;
|
||||
this.exportItemsToClipboard = exportItemsToClipboard;
|
||||
this.exportItems = exportItems;
|
||||
this.bibliographyFromCollection = bibliographyFromCollection;
|
||||
this.bibliographyFromItems = bibliographyFromItems;
|
||||
|
||||
/**
|
||||
|
@ -207,13 +208,119 @@ var Zotero_File_Interface = new function() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
this.getMendeleyDirectory = function () {
|
||||
Components.classes["@mozilla.org/net/osfileconstantsservice;1"]
|
||||
.getService(Components.interfaces.nsIOSFileConstantsService)
|
||||
.init();
|
||||
var path = OS.Constants.Path.homeDir;
|
||||
if (Zotero.isMac) {
|
||||
path = OS.Path.join(path, 'Library', 'Application Support', 'Mendeley Desktop');
|
||||
}
|
||||
else if (Zotero.isWin) {
|
||||
path = OS.Path.join(path, 'AppData', 'Local', 'Mendeley Ltd', 'Mendeley Desktop');
|
||||
}
|
||||
else if (Zotero.isLinux) {
|
||||
path = OS.Path.join(path, '.local', 'share', 'data', 'Mendeley Ltd.', 'Mendeley Desktop');
|
||||
}
|
||||
else {
|
||||
throw new Error("Invalid platform");
|
||||
}
|
||||
return path;
|
||||
};
|
||||
|
||||
|
||||
this.findMendeleyDatabases = async function () {
|
||||
var dbs = [];
|
||||
try {
|
||||
var dir = this.getMendeleyDirectory();
|
||||
if (!await OS.File.exists(dir)) {
|
||||
Zotero.debug(`${dir} does not exist`);
|
||||
return dbs;
|
||||
}
|
||||
await Zotero.File.iterateDirectory(dir, function* (iterator) {
|
||||
while (true) {
|
||||
let entry = yield iterator.next();
|
||||
if (entry.isDir) continue;
|
||||
// online.sqlite, counterintuitively, is the default database before you sign in
|
||||
if (entry.name == 'online.sqlite' || entry.name.endsWith('@www.mendeley.com.sqlite')) {
|
||||
dbs.push({
|
||||
name: entry.name,
|
||||
path: entry.path,
|
||||
lastModified: null,
|
||||
size: null
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < dbs.length; i++) {
|
||||
let dbPath = OS.Path.join(dir, dbs[i].name);
|
||||
let info = await OS.File.stat(dbPath);
|
||||
dbs[i].size = info.size;
|
||||
dbs[i].lastModified = info.lastModificationDate;
|
||||
}
|
||||
dbs.sort((a, b) => {
|
||||
return b.lastModified - a.lastModified;
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
return dbs;
|
||||
};
|
||||
|
||||
|
||||
this.showImportWizard = function () {
|
||||
var libraryID = Zotero.Libraries.userLibraryID;
|
||||
try {
|
||||
let zp = Zotero.getActiveZoteroPane();
|
||||
libraryID = zp.getSelectedLibraryID();
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
var args = {
|
||||
libraryID
|
||||
};
|
||||
args.wrappedJSObject = args;
|
||||
|
||||
Services.ww.openWindow(null, "chrome://zotero/content/import/importWizard.xul",
|
||||
"importFile", "chrome,dialog=yes,centerscreen,width=600,height=400", args);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates Zotero.Translate instance and shows file picker for file import
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {nsIFile|string|null} [options.file=null] - File to import, or none to show a filepicker
|
||||
* @param {Boolean} [options.addToLibraryRoot=false]
|
||||
* @param {Boolean} [options.createNewCollection=true] - Put items in a new collection
|
||||
* @param {Function} [options.onBeforeImport] - Callback to receive translation object, useful
|
||||
* for displaying progress in a different way. This also causes an error to be throw
|
||||
* instead of shown in the main window.
|
||||
*/
|
||||
this.importFile = Zotero.Promise.coroutine(function* (file, createNewCollection) {
|
||||
if(createNewCollection === undefined) {
|
||||
this.importFile = Zotero.Promise.coroutine(function* (options = {}) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (typeof options == 'string' || options instanceof Components.interfaces.nsIFile) {
|
||||
Zotero.debug("WARNING: importFile() now takes a single options object -- update your code");
|
||||
options = {
|
||||
file: options,
|
||||
createNewCollection: arguments[1]
|
||||
};
|
||||
}
|
||||
|
||||
var file = options.file ? Zotero.File.pathToFile(options.file) : null;
|
||||
var createNewCollection = options.createNewCollection;
|
||||
var addToLibraryRoot = options.addToLibraryRoot;
|
||||
var onBeforeImport = options.onBeforeImport;
|
||||
|
||||
if (createNewCollection === undefined && !addToLibraryRoot) {
|
||||
createNewCollection = true;
|
||||
} else if(!createNewCollection) {
|
||||
}
|
||||
else if (!createNewCollection) {
|
||||
try {
|
||||
if (!ZoteroPane.collectionsView.editable) {
|
||||
ZoteroPane.collectionsView.selectLibrary(null);
|
||||
|
@ -221,32 +328,40 @@ var Zotero_File_Interface = new function() {
|
|||
} catch(e) {}
|
||||
}
|
||||
|
||||
var translation = new Zotero.Translate.Import();
|
||||
if (!file) {
|
||||
let translators = yield translation.getTranslators();
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("fileInterface.import"), nsIFilePicker.modeOpen);
|
||||
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
translators.sort((a, b) => collation.compareString(1, a.label, b.label))
|
||||
for (let translator of translators) {
|
||||
fp.appendFilter(translator.label, "*." + translator.target);
|
||||
}
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv !== nsIFilePicker.returnOK && rv !== nsIFilePicker.returnReplace) {
|
||||
return false;
|
||||
}
|
||||
|
||||
file = fp.file;
|
||||
var defaultNewCollectionPrefix = Zotero.getString("fileInterface.imported");
|
||||
|
||||
var translation;
|
||||
// Check if the file is an SQLite database
|
||||
var sample = yield Zotero.File.getSample(file.path);
|
||||
if (file.path == Zotero.DataDirectory.getDatabase()) {
|
||||
// Blacklist the current Zotero database, which would cause a hang
|
||||
}
|
||||
else if (Zotero.MIME.sniffForMIMEType(sample) == 'application/x-sqlite3') {
|
||||
// Mendeley import doesn't use the real translation architecture, but we create a
|
||||
// translation object with the same interface
|
||||
translation = yield _getMendeleyTranslation();
|
||||
translation.createNewCollection = createNewCollection;
|
||||
defaultNewCollectionPrefix = Zotero.getString(
|
||||
'fileInterface.appImportCollection', 'Mendeley'
|
||||
);
|
||||
}
|
||||
else if (file.path.endsWith('@www.mendeley.com.sqlite')
|
||||
|| file.path.endsWith('online.sqlite')) {
|
||||
// Keep in sync with importWizard.js
|
||||
throw new Error('Encrypted Mendeley database');
|
||||
}
|
||||
|
||||
if (!translation) {
|
||||
translation = new Zotero.Translate.Import();
|
||||
}
|
||||
|
||||
translation.setLocation(file);
|
||||
yield _finishImport(translation, createNewCollection);
|
||||
return _finishImport({
|
||||
translation,
|
||||
createNewCollection,
|
||||
addToLibraryRoot,
|
||||
defaultNewCollectionPrefix,
|
||||
onBeforeImport
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
@ -274,7 +389,10 @@ var Zotero_File_Interface = new function() {
|
|||
}
|
||||
} catch(e) {}
|
||||
|
||||
yield _finishImport(translation, false);
|
||||
yield _finishImport({
|
||||
translation,
|
||||
createNewCollection: false
|
||||
});
|
||||
|
||||
// Select imported items
|
||||
try {
|
||||
|
@ -288,17 +406,36 @@ var Zotero_File_Interface = new function() {
|
|||
});
|
||||
|
||||
|
||||
var _finishImport = Zotero.Promise.coroutine(function* (translation, createNewCollection) {
|
||||
var _finishImport = Zotero.Promise.coroutine(function* (options) {
|
||||
var t = performance.now();
|
||||
|
||||
var translation = options.translation;
|
||||
var addToLibraryRoot = options.addToLibraryRoot;
|
||||
var createNewCollection = options.createNewCollection;
|
||||
var defaultNewCollectionPrefix = options.defaultNewCollectionPrefix;
|
||||
var onBeforeImport = options.onBeforeImport;
|
||||
|
||||
if (addToLibraryRoot && createNewCollection) {
|
||||
throw new Error("Can't add to library root and create new collection");
|
||||
}
|
||||
|
||||
var showProgressWindow = !onBeforeImport;
|
||||
|
||||
let translators = yield translation.getTranslators();
|
||||
|
||||
if(!translators.length) {
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_OK)
|
||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING);
|
||||
var index = ps.confirmEx(
|
||||
|
||||
// Unrecognized file
|
||||
if (!translators.length) {
|
||||
if (onBeforeImport) {
|
||||
yield onBeforeImport(false);
|
||||
}
|
||||
|
||||
let ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
let buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_OK
|
||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING;
|
||||
let index = ps.confirmEx(
|
||||
null,
|
||||
"",
|
||||
Zotero.getString('general.error'),
|
||||
Zotero.getString("fileInterface.unsupportedFormat"),
|
||||
buttonFlags,
|
||||
null,
|
||||
|
@ -306,17 +443,27 @@ var Zotero_File_Interface = new function() {
|
|||
null, null, {}
|
||||
);
|
||||
if (index == 1) {
|
||||
ZoteroPane_Local.loadURI("http://zotero.org/support/kb/importing");
|
||||
Zotero.launchURL("https://www.zotero.org/support/kb/importing");
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
let importCollection = null, libraryID = Zotero.Libraries.userLibraryID;
|
||||
|
||||
var libraryID = Zotero.Libraries.userLibraryID;
|
||||
var importCollection = null;
|
||||
try {
|
||||
libraryID = ZoteroPane.getSelectedLibraryID();
|
||||
importCollection = ZoteroPane.getSelectedCollection();
|
||||
} catch(e) {}
|
||||
|
||||
let zp = Zotero.getActiveZoteroPane();
|
||||
libraryID = zp.getSelectedLibraryID();
|
||||
if (addToLibraryRoot) {
|
||||
yield zp.collectionsView.selectLibrary(libraryID);
|
||||
}
|
||||
else if (!createNewCollection) {
|
||||
importCollection = zp.getSelectedCollection();
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
|
||||
if(createNewCollection) {
|
||||
// Create a new collection to take imported items
|
||||
let collectionName;
|
||||
|
@ -331,8 +478,9 @@ var Zotero_File_Interface = new function() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
collectionName = Zotero.getString("fileInterface.imported")+" "+(new Date()).toLocaleString();
|
||||
}
|
||||
else {
|
||||
collectionName = defaultNewCollectionPrefix + " " + (new Date()).toLocaleString();
|
||||
}
|
||||
importCollection = new Zotero.Collection;
|
||||
importCollection.libraryID = libraryID;
|
||||
|
@ -343,22 +491,29 @@ var Zotero_File_Interface = new function() {
|
|||
translation.setTranslator(translators[0]);
|
||||
|
||||
// Show progress popup
|
||||
var progressWin = new Zotero.ProgressWindow({
|
||||
closeOnClick: false
|
||||
});
|
||||
progressWin.changeHeadline(Zotero.getString('fileInterface.importing'));
|
||||
var icon = 'chrome://zotero/skin/treesource-unfiled' + (Zotero.hiDPI ? "@2x" : "") + '.png';
|
||||
let progress = new progressWin.ItemProgress(
|
||||
icon, translation.path ? OS.Path.basename(translation.path) : translators[0].label
|
||||
);
|
||||
progressWin.show();
|
||||
var progressWin;
|
||||
var progress;
|
||||
if (showProgressWindow) {
|
||||
progressWin = new Zotero.ProgressWindow({
|
||||
closeOnClick: false
|
||||
});
|
||||
progressWin.changeHeadline(Zotero.getString('fileInterface.importing'));
|
||||
let icon = 'chrome://zotero/skin/treesource-unfiled' + (Zotero.hiDPI ? "@2x" : "") + '.png';
|
||||
progress = new progressWin.ItemProgress(
|
||||
icon, translation.path ? OS.Path.basename(translation.path) : translators[0].label
|
||||
);
|
||||
progressWin.show();
|
||||
|
||||
translation.setHandler("itemDone", function () {
|
||||
progress.setProgress(translation.getProgress());
|
||||
});
|
||||
|
||||
yield Zotero.Promise.delay(0);
|
||||
}
|
||||
else {
|
||||
yield onBeforeImport(translation);
|
||||
}
|
||||
|
||||
translation.setHandler("itemDone", function () {
|
||||
progress.setProgress(translation.getProgress());
|
||||
});
|
||||
|
||||
yield Zotero.Promise.delay(0);
|
||||
|
||||
let failed = false;
|
||||
try {
|
||||
yield translation.translate({
|
||||
|
@ -366,59 +521,93 @@ var Zotero_File_Interface = new function() {
|
|||
collections: importCollection ? [importCollection.id] : null
|
||||
});
|
||||
} catch(e) {
|
||||
if (!showProgressWindow) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
progressWin.close();
|
||||
Zotero.logError(e);
|
||||
Zotero.alert(
|
||||
null,
|
||||
Zotero.getString('general.error'),
|
||||
Zotero.getString("fileInterface.importError")
|
||||
);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
var numItems = translation.newItems.length;
|
||||
|
||||
// Show popup on completion
|
||||
var numItems = translation.newItems.length;
|
||||
progressWin.changeHeadline(Zotero.getString('fileInterface.importComplete'));
|
||||
if (numItems == 1) {
|
||||
var icon = translation.newItems[0].getImageSrc();
|
||||
if (showProgressWindow) {
|
||||
progressWin.changeHeadline(Zotero.getString('fileInterface.importComplete'));
|
||||
let icon;
|
||||
if (numItems == 1) {
|
||||
icon = translation.newItems[0].getImageSrc();
|
||||
}
|
||||
else {
|
||||
icon = 'chrome://zotero/skin/treesource-unfiled' + (Zotero.hiDPI ? "@2x" : "") + '.png';
|
||||
}
|
||||
let text = Zotero.getString(`fileInterface.itemsWereImported`, numItems, numItems);
|
||||
progress.setIcon(icon);
|
||||
progress.setText(text);
|
||||
// For synchronous translators, which don't update progress
|
||||
progress.setProgress(100);
|
||||
progressWin.startCloseTimer(5000);
|
||||
}
|
||||
else {
|
||||
var icon = 'chrome://zotero/skin/treesource-unfiled' + (Zotero.hiDPI ? "@2x" : "") + '.png';
|
||||
}
|
||||
var text = Zotero.getString(`fileInterface.itemsWereImported`, numItems, numItems);
|
||||
progress.setIcon(icon);
|
||||
progress.setText(text);
|
||||
// For synchronous translators, which don't update progress
|
||||
progress.setProgress(100);
|
||||
progressWin.startCloseTimer(5000);
|
||||
|
||||
Zotero.debug(`Imported ${numItems} item(s) in ${performance.now() - t} ms`);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
/*
|
||||
|
||||
var _getMendeleyTranslation = async function () {
|
||||
if (true) {
|
||||
Components.utils.import("chrome://zotero/content/import/mendeley/mendeleyImport.js");
|
||||
}
|
||||
// TEMP: Load uncached from ~/zotero-client for development
|
||||
else {
|
||||
Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||
let file = FileUtils.getDir("Home", []);
|
||||
file = OS.Path.join(
|
||||
file.path,
|
||||
'zotero-client', 'chrome', 'content', 'zotero', 'import', 'mendeley', 'mendeleyImport.js'
|
||||
);
|
||||
let fileURI = OS.Path.toFileURI(file);
|
||||
let xmlhttp = await Zotero.HTTP.request(
|
||||
'GET',
|
||||
fileURI,
|
||||
{
|
||||
dontCache: true,
|
||||
responseType: 'text'
|
||||
}
|
||||
);
|
||||
eval(xmlhttp.response);
|
||||
}
|
||||
return new Zotero_Import_Mendeley();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a bibliography from a collection or saved search
|
||||
*/
|
||||
function bibliographyFromCollection() {
|
||||
// find sorted items
|
||||
var items = Zotero.Items.get(ZoteroPane_Local.getSortedItems(true));
|
||||
if(!items) return;
|
||||
this.bibliographyFromCollection = function () {
|
||||
var items = ZoteroPane.getSortedItems();
|
||||
|
||||
// find name
|
||||
// Find collection name
|
||||
var name = false;
|
||||
|
||||
var collection = ZoteroPane_Local.getSelectedCollection();
|
||||
if(collection) {
|
||||
name = collection.getName();
|
||||
} else {
|
||||
var searchRef = ZoteroPane_Local.getSelectedSavedSearch();
|
||||
if(searchRef) {
|
||||
var search = new Zotero.Search();
|
||||
search.id = searchRef.id;
|
||||
var collection = ZoteroPane.getSelectedCollection();
|
||||
if (collection) {
|
||||
name = collection.name;
|
||||
}
|
||||
else {
|
||||
let search = ZoteroPane.getSelectedSavedSearch();
|
||||
if (search) {
|
||||
name = search.name;
|
||||
}
|
||||
}
|
||||
|
||||
_doBibliographyOptions(name, items);
|
||||
return;
|
||||
|
||||
throw ("No collection or saved search currently selected");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -257,14 +257,10 @@ function getTooltipText(button) {
|
|||
|
||||
// Use defaults if necessary
|
||||
if (!text) {
|
||||
// Get the stringbundle manually
|
||||
let src = 'chrome://zotero/locale/zotero.properties';
|
||||
let localeService = Components.classes['@mozilla.org/intl/nslocaleservice;1']
|
||||
.getService(Components.interfaces.nsILocaleService);
|
||||
let appLocale = localeService.getApplicationLocale();
|
||||
let stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
|
||||
.getService(Components.interfaces.nsIStringBundleService);
|
||||
let stringBundle = stringBundleService.createBundle(src, appLocale);
|
||||
let stringBundle = stringBundleService.createBundle(src);
|
||||
text = stringBundle.GetStringFromName('startupError');
|
||||
}
|
||||
}
|
||||
|
|
332
chrome/content/zotero/import/importWizard.js
Normal file
332
chrome/content/zotero/import/importWizard.js
Normal file
|
@ -0,0 +1,332 @@
|
|||
var Zotero_Import_Wizard = {
|
||||
_wizard: null,
|
||||
_dbs: null,
|
||||
_file: null,
|
||||
_translation: null,
|
||||
|
||||
|
||||
init: async function () {
|
||||
this._wizard = document.getElementById('import-wizard');
|
||||
|
||||
var dbs = await Zotero_File_Interface.findMendeleyDatabases();
|
||||
if (dbs.length) {
|
||||
document.getElementById('radio-import-source-mendeley').hidden = false;
|
||||
}
|
||||
|
||||
// If no existing collections or non-trash items in the library, don't create a new
|
||||
// collection by default
|
||||
var args = window.arguments[0].wrappedJSObject;
|
||||
if (args && args.libraryID) {
|
||||
let sql = "SELECT ROWID FROM collections WHERE libraryID=?1 "
|
||||
+ "UNION "
|
||||
+ "SELECT ROWID FROM items WHERE libraryID=?1 "
|
||||
// Not in trash
|
||||
+ "AND itemID NOT IN (SELECT itemID FROM deletedItems) "
|
||||
// And not a child item (which doesn't necessarily show up in the trash)
|
||||
+ "AND itemID NOT IN (SELECT itemID FROM itemNotes WHERE parentItemID IS NOT NULL) "
|
||||
+ "AND itemID NOT IN (SELECT itemID FROM itemAttachments WHERE parentItemID IS NOT NULL) "
|
||||
+ "LIMIT 1";
|
||||
if (!await Zotero.DB.valueQueryAsync(sql, args.libraryID)) {
|
||||
document.getElementById('create-collection-checkbox').removeAttribute('checked');
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.Translators.init(); // async
|
||||
},
|
||||
|
||||
|
||||
onModeChosen: async function () {
|
||||
var wizard = this._wizard;
|
||||
|
||||
var mode = document.getElementById('import-source').selectedItem.id;
|
||||
try {
|
||||
switch (mode) {
|
||||
case 'radio-import-source-file':
|
||||
await this.chooseFile();
|
||||
break;
|
||||
|
||||
case 'radio-import-source-mendeley':
|
||||
this._dbs = await Zotero_File_Interface.findMendeleyDatabases();
|
||||
// This shouldn't happen, because we only show the wizard if there are databases
|
||||
if (!this._dbs.length) {
|
||||
throw new Error("No databases found");
|
||||
}
|
||||
this._populateFileList(this._dbs);
|
||||
document.getElementById('file-options-header').textContent
|
||||
= Zotero.getString('fileInterface.chooseAppDatabaseToImport', 'Mendeley')
|
||||
wizard.goTo('page-file-list');
|
||||
wizard.canRewind = true;
|
||||
this._enableCancel();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown mode ${mode}`);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
this._onDone(
|
||||
Zotero.getString('general.error'),
|
||||
Zotero.getString('fileInterface.importError'),
|
||||
true
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
goToStart: function () {
|
||||
this._wizard.goTo('page-start');
|
||||
this._wizard.canAdvance = true;
|
||||
return false;
|
||||
},
|
||||
|
||||
|
||||
chooseFile: async function (translation) {
|
||||
var translation = new Zotero.Translate.Import();
|
||||
var translators = await translation.getTranslators();
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString("fileInterface.import"), nsIFilePicker.modeOpen);
|
||||
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
|
||||
// Add Mendeley DB, which isn't a translator
|
||||
var mendeleyFilter = {
|
||||
label: "Mendeley Database", // TODO: Localize
|
||||
target: "*.sqlite"
|
||||
};
|
||||
var filters = [...translators];
|
||||
filters.push(mendeleyFilter);
|
||||
|
||||
filters.sort((a, b) => collation.compareString(1, a.label, b.label));
|
||||
for (let filter of filters) {
|
||||
fp.appendFilter(filter.label, "*." + filter.target);
|
||||
}
|
||||
|
||||
var rv = fp.show();
|
||||
if (rv !== nsIFilePicker.returnOK && rv !== nsIFilePicker.returnReplace) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Zotero.debug(`File is ${fp.file.path}`);
|
||||
|
||||
this._file = fp.file.path;
|
||||
this._wizard.canAdvance = true;
|
||||
this._wizard.goTo('page-options');
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* When a file is clicked on in the file list
|
||||
*/
|
||||
onFileSelected: async function () {
|
||||
var index = document.getElementById('file-list').selectedIndex;
|
||||
if (index != -1) {
|
||||
this._file = this._dbs[index].path;
|
||||
this._wizard.canAdvance = true;
|
||||
}
|
||||
else {
|
||||
this._file = null;
|
||||
this._wizard.canAdvance = false;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* When the user clicks "Other…" to choose a file not in the list
|
||||
*/
|
||||
chooseMendeleyDB: async function () {
|
||||
document.getElementById('file-list').selectedIndex = -1;
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, Zotero.getString('fileInterface.import'), nsIFilePicker.modeOpen);
|
||||
fp.appendFilter("Mendeley Database", "*.sqlite"); // TODO: Localize
|
||||
var rv = fp.show();
|
||||
if (rv != nsIFilePicker.returnOK) {
|
||||
return false;
|
||||
}
|
||||
this._file = fp.file.path;
|
||||
this._wizard.canAdvance = true;
|
||||
this._wizard.advance();
|
||||
},
|
||||
|
||||
|
||||
onOptionsShown: function () {
|
||||
|
||||
},
|
||||
|
||||
|
||||
onImportStart: async function () {
|
||||
if (!this._file) {
|
||||
let index = document.getElementById('file-list').selectedIndex;
|
||||
this._file = this._dbs[index].path;
|
||||
}
|
||||
this._disableCancel();
|
||||
this._wizard.canRewind = false;
|
||||
this._wizard.canAdvance = false;
|
||||
await this.doImport({
|
||||
createNewCollection: document.getElementById('create-collection-checkbox').hasAttribute('checked')
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
onBeforeImport: async function (translation) {
|
||||
// Unrecognized translator
|
||||
if (!translation) {
|
||||
// Allow error dialog to be displayed, and then close window
|
||||
setTimeout(function () {
|
||||
window.close();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this._translation = translation;
|
||||
|
||||
// Switch to progress pane
|
||||
this._wizard.goTo('page-progress');
|
||||
var pm = document.getElementById('import-progressmeter');
|
||||
|
||||
translation.setHandler('itemDone', function () {
|
||||
pm.value = translation.getProgress();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
doImport: async function (options) {
|
||||
try {
|
||||
let result = await Zotero_File_Interface.importFile({
|
||||
file: this._file,
|
||||
onBeforeImport: this.onBeforeImport.bind(this),
|
||||
addToLibraryRoot: !options.createNewCollection
|
||||
});
|
||||
|
||||
// Cancelled by user or due to error
|
||||
if (!result) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
||||
let numItems = this._translation.newItems.length;
|
||||
this._onDone(
|
||||
Zotero.getString('fileInterface.importComplete'),
|
||||
Zotero.getString(`fileInterface.itemsWereImported`, numItems, numItems)
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
if (e.message == 'Encrypted Mendeley database') {
|
||||
let url = 'https://www.zotero.org/support/kb/mendeley_import';
|
||||
this._onDone(
|
||||
Zotero.getString('general.error'),
|
||||
// TODO: Localize
|
||||
`The selected Mendeley database cannot be read, likely because it is encrypted. `
|
||||
+ `See <a href="${url}" class="text-link">How do I import a Mendeley library `
|
||||
+ `into Zotero?</a> for more information.`
|
||||
);
|
||||
}
|
||||
else {
|
||||
this._onDone(
|
||||
Zotero.getString('general.error'),
|
||||
Zotero.getString('fileInterface.importError'),
|
||||
true
|
||||
);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
reportError: function () {
|
||||
Zotero.getActiveZoteroPane().reportErrors();
|
||||
window.close();
|
||||
},
|
||||
|
||||
|
||||
_populateFileList: async function (files) {
|
||||
var listbox = document.getElementById('file-list');
|
||||
|
||||
// Remove existing entries
|
||||
var items = listbox.getElementsByTagName('listitem');
|
||||
for (let item of items) {
|
||||
listbox.removeChild(item);
|
||||
}
|
||||
|
||||
for (let file of files) {
|
||||
let li = document.createElement('listitem');
|
||||
|
||||
let name = document.createElement('listcell');
|
||||
// Simply filenames
|
||||
let nameStr = file.name
|
||||
.replace(/\.sqlite$/, '')
|
||||
.replace(/@www\.mendeley\.com$/, '');
|
||||
if (nameStr == 'online') {
|
||||
nameStr = Zotero.getString('dataDir.default', 'online.sqlite');
|
||||
}
|
||||
name.setAttribute('label', nameStr + ' ');
|
||||
li.appendChild(name);
|
||||
|
||||
let lastModified = document.createElement('listcell');
|
||||
lastModified.setAttribute('label', file.lastModified.toLocaleString() + ' ');
|
||||
li.appendChild(lastModified);
|
||||
|
||||
let size = document.createElement('listcell');
|
||||
size.setAttribute(
|
||||
'label',
|
||||
Zotero.getString('general.nMegabytes', (file.size / 1024 / 1024).toFixed(1)) + ' '
|
||||
);
|
||||
li.appendChild(size);
|
||||
|
||||
listbox.appendChild(li);
|
||||
}
|
||||
|
||||
if (files.length == 1) {
|
||||
listbox.selectedIndex = 0;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
_enableCancel: function () {
|
||||
this._wizard.getButton('cancel').disabled = false;
|
||||
},
|
||||
|
||||
|
||||
_disableCancel: function () {
|
||||
this._wizard.getButton('cancel').disabled = true;
|
||||
},
|
||||
|
||||
|
||||
_onDone: function (label, description, showReportErrorButton) {
|
||||
var wizard = this._wizard;
|
||||
wizard.getPageById('page-done').setAttribute('label', label);
|
||||
|
||||
var xulElem = document.getElementById('result-description');
|
||||
var htmlElem = document.getElementById('result-description-html');
|
||||
|
||||
if (description.includes('href')) {
|
||||
htmlElem.innerHTML = description;
|
||||
Zotero.Utilities.Internal.updateHTMLInXUL(htmlElem);
|
||||
xulElem.hidden = true;
|
||||
htmlElem.setAttribute('display', 'block');
|
||||
}
|
||||
else {
|
||||
xulElem.textContent = description;
|
||||
xulElem.hidden = false;
|
||||
htmlElem.setAttribute('display', 'none');
|
||||
}
|
||||
document.getElementById('result-description')
|
||||
|
||||
if (showReportErrorButton) {
|
||||
let button = document.getElementById('result-report-error');
|
||||
button.setAttribute('label', Zotero.getString('errorReport.reportError'));
|
||||
button.hidden = false;
|
||||
}
|
||||
|
||||
// When done, move to last page and allow closing
|
||||
wizard.canAdvance = true;
|
||||
wizard.goTo('page-done');
|
||||
wizard.canRewind = false;
|
||||
}
|
||||
};
|
75
chrome/content/zotero/import/importWizard.xul
Normal file
75
chrome/content/zotero/import/importWizard.xul
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/importWizard.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
|
||||
|
||||
<wizard id="import-wizard"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
title="&zotero.import;"
|
||||
onload="Zotero_Import_Wizard.init()">
|
||||
|
||||
<script src="../include.js"/>
|
||||
<script src="../fileInterface.js"/>
|
||||
<script src="importWizard.js"/>
|
||||
|
||||
<wizardpage pageid="page-start"
|
||||
label="&zotero.import.whereToImportFrom;"
|
||||
next="page-options"
|
||||
onpageadvanced="Zotero_Import_Wizard.onModeChosen(); return false;">
|
||||
<radiogroup id="import-source">
|
||||
<radio id="radio-import-source-file" label="&zotero.import.source.file;"/>
|
||||
<radio id="radio-import-source-mendeley" label="Mendeley" hidden="true"/>
|
||||
</radiogroup>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage pageid="page-file-list"
|
||||
next="page-options"
|
||||
onpagerewound="return Zotero_Import_Wizard.goToStart()">
|
||||
<description id="file-options-header"/>
|
||||
<listbox id="file-list" onselect="Zotero_Import_Wizard.onFileSelected()">
|
||||
<listhead>
|
||||
<listheader label="&zotero.import.database;"/>
|
||||
<listheader label="&zotero.import.lastModified;"/>
|
||||
<listheader label="&zotero.import.size;"/>
|
||||
</listhead>
|
||||
|
||||
<listcols>
|
||||
<listcol flex="1"/>
|
||||
<listcol/>
|
||||
<listcol/>
|
||||
</listcols>
|
||||
</listbox>
|
||||
<hbox>
|
||||
<button label="&zotero.general.other;" oncommand="Zotero_Import_Wizard.chooseMendeleyDB()"/>
|
||||
</hbox>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage pageid="page-options"
|
||||
label="&zotero.general.options;"
|
||||
next="page-progress"
|
||||
onpageshow="Zotero_Import_Wizard.onOptionsShown()"
|
||||
onpagerewound="return Zotero_Import_Wizard.goToStart()"
|
||||
onpageadvanced="Zotero_Import_Wizard.onImportStart()">
|
||||
<checkbox id="create-collection-checkbox" label="&zotero.import.createCollection;" checked="true" />
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage pageid="page-progress"
|
||||
label="&zotero.import.importing;"
|
||||
onpageshow="document.getElementById('import-wizard').canRewind = false;"
|
||||
next="page-done">
|
||||
<progressmeter id="import-progressmeter" mode="determined"/>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage pageid="page-done">
|
||||
<description id="result-description"/>
|
||||
<html:div id="result-description-html"/>
|
||||
<hbox>
|
||||
<button id="result-report-error"
|
||||
oncommand="Zotero_Import_Wizard.reportError()"
|
||||
hidden="true"/>
|
||||
</hbox>
|
||||
</wizardpage>
|
||||
</wizard>
|
1210
chrome/content/zotero/import/mendeley/mendeleyImport.js
Normal file
1210
chrome/content/zotero/import/mendeley/mendeleyImport.js
Normal file
File diff suppressed because it is too large
Load Diff
102
chrome/content/zotero/import/mendeley/mendeleySchemaMap.js
Normal file
102
chrome/content/zotero/import/mendeley/mendeleySchemaMap.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
var map = {
|
||||
83: {
|
||||
itemTypes: {
|
||||
Bill: "bill",
|
||||
Book: "book",
|
||||
BookSection: "bookSection",
|
||||
Case: "case",
|
||||
ComputerProgram: "computerProgram",
|
||||
ConferenceProceedings: "conferencePaper",
|
||||
EncyclopediaArticle: "encyclopediaArticle",
|
||||
Film: "film",
|
||||
Generic: "document",
|
||||
JournalArticle: "journalArticle",
|
||||
MagazineArticle: "magazineArticle",
|
||||
NewspaperArticle: "newspaperArticle",
|
||||
Patent: "patent",
|
||||
Report: "report",
|
||||
Statute: "statute",
|
||||
TelevisionBroadcast: "tvBroadcast",
|
||||
Thesis: "thesis",
|
||||
WebPage: "webpage",
|
||||
WorkingPaper: "report"
|
||||
},
|
||||
fields: {
|
||||
id: "",
|
||||
uuid: "",
|
||||
reviewedArticle: "",
|
||||
revisionNumber: "",
|
||||
publisher: "publisher",
|
||||
reprintEdition: "",
|
||||
series: "seriesTitle",
|
||||
seriesNumber: "seriesNumber",
|
||||
sections: "section",
|
||||
seriesEditor: "creator[seriesEditor]", // falls back to editor if necessary
|
||||
owner: "",
|
||||
pages: "func[pages]",
|
||||
month: "", // handled explicitly
|
||||
originalPublication: "",
|
||||
publication: "publicationTitle",
|
||||
publicLawNumber: "publicLawNumber",
|
||||
pmid: "extra[PMID]",
|
||||
sourceType: "",
|
||||
session: "session",
|
||||
shortTitle: "shortTitle",
|
||||
volume: "volume",
|
||||
year: "", // handled explicitly
|
||||
userType: "type",
|
||||
country: "place[country]",
|
||||
dateAccessed: "accessDate",
|
||||
committee: "committee",
|
||||
counsel: "creator[counsel]",
|
||||
doi: "DOI",
|
||||
edition: "edition",
|
||||
day: "", // handled explicitly
|
||||
department: "",
|
||||
citationKey: "citationKey", // put in Extra
|
||||
city: "place[city]",
|
||||
chapter: "",
|
||||
codeSection: "section",
|
||||
codeVolume: "codeVolume",
|
||||
code: "code",
|
||||
codeNumber: "codeNumber",
|
||||
issue: "issue",
|
||||
language: "language",
|
||||
isbn: "ISBN",
|
||||
issn: "ISSN",
|
||||
length: "",
|
||||
medium: "medium",
|
||||
lastUpdate: "",
|
||||
legalStatus: "legalStatus",
|
||||
hideFromMendeleyWebIndex: "",
|
||||
institution: "publisher",
|
||||
genre: "genre",
|
||||
internationalTitle: "",
|
||||
internationalUserType: "",
|
||||
internationalAuthor: "",
|
||||
internationalNumber: "",
|
||||
deletionPending: "",
|
||||
favourite: "", // tag?
|
||||
confirmed: "", // tag?
|
||||
deduplicated: "",
|
||||
read: "", // tag?
|
||||
type: "", // item type handled separately
|
||||
title: "title",
|
||||
privacy: "",
|
||||
applicationNumber: "applicationNumber",
|
||||
arxivId: "extra[arXiv]",
|
||||
advisor: "",
|
||||
articleColumn: "",
|
||||
modified: "func[fromUnixtime:dateModified]",
|
||||
abstract: "abstractNote",
|
||||
added: "func[fromUnixtime:dateAdded]",
|
||||
note: "func[note]",
|
||||
importer: ""
|
||||
},
|
||||
creatorTypes: {
|
||||
DocumentAuthor: "author",
|
||||
DocumentEditor: "editor",
|
||||
DocumentTranslator: "translator"
|
||||
}
|
||||
}
|
||||
};
|
|
@ -7,24 +7,4 @@ var Zotero = Components.classes['@zotero.org/Zotero;1']
|
|||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
|
||||
|
||||
var require = (function() {
|
||||
var { Loader, Require, Module } = Components.utils.import('resource://gre/modules/commonjs/toolkit/loader.js');
|
||||
var requirer = Module('/', '/');
|
||||
|
||||
var loader = Loader({
|
||||
id: 'zotero/require',
|
||||
paths: {
|
||||
'': 'resource://zotero/',
|
||||
},
|
||||
globals: {
|
||||
document,
|
||||
console,
|
||||
navigator,
|
||||
window,
|
||||
Zotero
|
||||
}
|
||||
});
|
||||
|
||||
return Require(loader, requirer);
|
||||
})();
|
||||
Components.utils.import('resource://zotero/require.js');
|
|
@ -59,10 +59,8 @@ var Zotero_Citation_Dialog = new function () {
|
|||
this.listItemSelected = listItemSelected;
|
||||
this.up = up;
|
||||
this.down = down;
|
||||
this.add = add;
|
||||
this.remove = remove;
|
||||
this.setSortToggle = setSortToggle;
|
||||
this.citationSortUnsort = citationSortUnsort;
|
||||
this.confirmRegenerate = confirmRegenerate;
|
||||
this.accept = accept;
|
||||
this.cancel = cancel;
|
||||
|
@ -373,13 +371,13 @@ var Zotero_Citation_Dialog = new function () {
|
|||
/*
|
||||
* Adds an item to the multipleSources list
|
||||
*/
|
||||
function add(first_item) {
|
||||
this.add = Zotero.Promise.coroutine(function* (first_item) {
|
||||
|
||||
var pos, len;
|
||||
var item = itemsView.getSelectedItems()[0]; // treeview from xpcom/itemTreeView.js
|
||||
|
||||
if (!item) {
|
||||
sortCitation();
|
||||
yield sortCitation();
|
||||
_updateAccept();
|
||||
_updatePreview();
|
||||
return;
|
||||
|
@ -412,11 +410,11 @@ var Zotero_Citation_Dialog = new function () {
|
|||
_citationList.ensureElementIsVisible(selectionNode);
|
||||
|
||||
// allow user to press OK
|
||||
selectionNode = sortCitation(selectionNode);
|
||||
selectionNode = yield sortCitation(selectionNode);
|
||||
_citationList.selectItem(selectionNode);
|
||||
_updateAccept();
|
||||
_updatePreview();
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Deletes a citation from the multipleSources list
|
||||
|
@ -446,11 +444,11 @@ var Zotero_Citation_Dialog = new function () {
|
|||
/*
|
||||
* Sorts preview citations, if preview is open.
|
||||
*/
|
||||
function citationSortUnsort() {
|
||||
this.citationSortUnsort = Zotero.Promise.coroutine(function* () {
|
||||
setSortToggle();
|
||||
sortCitation();
|
||||
yield sortCitation();
|
||||
_updatePreview();
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Sets the current sort toggle state persistently on the citation.
|
||||
|
@ -468,7 +466,7 @@ var Zotero_Citation_Dialog = new function () {
|
|||
/*
|
||||
* Sorts the list of citations
|
||||
*/
|
||||
function sortCitation(scrollToItem) {
|
||||
var sortCitation = Zotero.Promise.coroutine(function* (scrollToItem) {
|
||||
if(!_sortCheckbox) return scrollToItem;
|
||||
if(!_sortCheckbox.checked) {
|
||||
io.citation.properties.unsorted = true;
|
||||
|
@ -485,7 +483,7 @@ var Zotero_Citation_Dialog = new function () {
|
|||
|
||||
// run preview function to re-sort, if it hasn't already been
|
||||
// run
|
||||
io.sort();
|
||||
yield io.sort();
|
||||
|
||||
// add items back to list
|
||||
scrollToItem = null;
|
||||
|
@ -502,7 +500,7 @@ var Zotero_Citation_Dialog = new function () {
|
|||
|
||||
if(scrollToItem) _citationList.ensureElementIsVisible(scrollToItem);
|
||||
return scrollToItem;
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Ask whether to modifiy the preview
|
||||
|
|
|
@ -74,8 +74,8 @@ var Zotero_Bibliography_Dialog = new function () {
|
|||
if(selectedItemIDs.length) {
|
||||
for (let itemID of selectedItemIDs) {
|
||||
var itemIndexToSelect = false;
|
||||
for(var i in bibEditInterface.bibliography[0].entry_ids) {
|
||||
if(bibEditInterface.bibliography[0].entry_ids[i].indexOf(itemID) !== -1) {
|
||||
for(var i in bibEditInterface.bib[0].entry_ids) {
|
||||
if(bibEditInterface.bib[0].entry_ids[i].indexOf(itemID) !== -1) {
|
||||
itemIndexToSelect = i;
|
||||
continue;
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ var Zotero_Bibliography_Dialog = new function () {
|
|||
*/
|
||||
function _getSelectedListItemIDs() {
|
||||
return Array.from(_itemList.selectedItems)
|
||||
.map(item => bibEditInterface.bibliography[0].entry_ids[item.value][0]);
|
||||
.map(item => bibEditInterface.bib[0].entry_ids[item.value][0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -287,8 +287,8 @@ var Zotero_Bibliography_Dialog = new function () {
|
|||
|
||||
editor.readonly = index === undefined;
|
||||
if(index !== undefined) {
|
||||
var itemID = bibEditInterface.bibliography[0].entry_ids[index];
|
||||
editor.value = bibEditInterface.bibliography[1][index];
|
||||
var itemID = bibEditInterface.bib[0].entry_ids[index];
|
||||
editor.value = bibEditInterface.bib[1][index];
|
||||
_lastSelectedIndex = index;
|
||||
_lastSelectedItemID = itemID;
|
||||
_lastSelectedValue = editor.value;
|
||||
|
@ -304,7 +304,7 @@ var Zotero_Bibliography_Dialog = new function () {
|
|||
* loads items from itemSet
|
||||
*/
|
||||
function _loadItems() {
|
||||
var itemIDs = bibEditInterface.bibliography[0].entry_ids;
|
||||
var itemIDs = bibEditInterface.bib[0].entry_ids;
|
||||
var items = itemIDs.map(itemID => Zotero.Cite.getItem(itemID[0]));
|
||||
|
||||
// delete all existing items from list
|
||||
|
|
|
@ -31,10 +31,11 @@
|
|||
<dialog
|
||||
id="zotero-doc-prefs-dialog"
|
||||
orient="vertical"
|
||||
buttons="accept,cancel"
|
||||
buttons="accept,cancel,help"
|
||||
title="&zotero.integration.docPrefs.title;"
|
||||
onload="Zotero_File_Interface_Bibliography.init();"
|
||||
ondialogaccept="Zotero_File_Interface_Bibliography.acceptSelection();"
|
||||
ondialoghelp="Zotero_File_Interface_Bibliography.openHelpLink();"
|
||||
onclose="document.documentElement.cancelDialog(); event.preventDefault(); event.stopPropagation();"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
persist="screenX screenY"
|
||||
|
@ -52,7 +53,7 @@
|
|||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<groupbox>
|
||||
<groupbox id="locale-box">
|
||||
<hbox align="center">
|
||||
<caption label="&zotero.bibliography.locale.label;"/>
|
||||
<menulist id="locale-menu" oncommand="Zotero_File_Interface_Bibliography.localeChanged(this.selectedItem.value)"/>
|
||||
|
@ -67,7 +68,7 @@
|
|||
</radiogroup>
|
||||
</groupbox>
|
||||
|
||||
<groupbox>
|
||||
<groupbox id="formatUsing-groupbox">
|
||||
<caption label="&zotero.integration.prefs.formatUsing.label;"/>
|
||||
|
||||
<radiogroup id="formatUsing" orient="vertical">
|
||||
|
@ -84,5 +85,10 @@
|
|||
<checkbox id="automaticJournalAbbreviations-checkbox" label="&zotero.integration.prefs.automaticJournalAbbeviations.label;"/>
|
||||
<description class="radioDescription">&zotero.integration.prefs.automaticJournalAbbeviations.caption;</description>
|
||||
</vbox>
|
||||
|
||||
<vbox id="automaticCitationUpdates-vbox">
|
||||
<checkbox id="automaticCitationUpdates-checkbox" label="&zotero.integration.prefs.automaticCitationUpdates.label;" tooltiptext="&zotero.integration.prefs.automaticCitationUpdates.tooltip;"/>
|
||||
<description class="radioDescription">&zotero.integration.prefs.automaticCitationUpdates.description;</description>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</dialog>
|
121
chrome/content/zotero/integration/progressBar.js
Normal file
121
chrome/content/zotero/integration/progressBar.js
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2018 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var Zotero_ProgressBar = new function () {
|
||||
var initialized, io;
|
||||
|
||||
/**
|
||||
* Pre-initialization, when the dialog has loaded but has not yet appeared
|
||||
*/
|
||||
this.onDOMContentLoaded = function(event) {
|
||||
if(event.target === document) {
|
||||
initialized = true;
|
||||
io = window.arguments[0].wrappedJSObject;
|
||||
if (io.onLoad) {
|
||||
io.onLoad(_onProgress);
|
||||
}
|
||||
|
||||
// Only hide chrome on Windows or Mac
|
||||
if(Zotero.isMac) {
|
||||
document.documentElement.setAttribute("drawintitlebar", true);
|
||||
} else if(Zotero.isWin) {
|
||||
document.documentElement.setAttribute("hidechrome", true);
|
||||
}
|
||||
|
||||
new WindowDraggingElement(document.getElementById("quick-format-dialog"), window);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Center the window
|
||||
*/
|
||||
this.onLoad = function(event) {
|
||||
if(event.target !== document) return;
|
||||
// make sure we are visible
|
||||
window.focus();
|
||||
window.setTimeout(function() {
|
||||
var targetX = Math.floor(-window.outerWidth/2 + (window.screen.width / 2));
|
||||
var targetY = Math.floor(-window.outerHeight/2 + (window.screen.height / 2));
|
||||
Zotero.debug("Moving window to "+targetX+", "+targetY);
|
||||
window.moveTo(targetX, targetY);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when progress changes
|
||||
*/
|
||||
function _onProgress(percent) {
|
||||
var meter = document.getElementById("quick-format-progress-meter");
|
||||
if(percent === null) {
|
||||
meter.mode = "undetermined";
|
||||
} else {
|
||||
meter.mode = "determined";
|
||||
meter.value = Math.round(percent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes windows
|
||||
* @constructor
|
||||
*/
|
||||
var Resizer = function(panel, targetWidth, targetHeight, pixelsPerStep, stepsPerSecond) {
|
||||
this.panel = panel;
|
||||
this.curWidth = panel.clientWidth;
|
||||
this.curHeight = panel.clientHeight;
|
||||
this.difX = (targetWidth ? targetWidth - this.curWidth : 0);
|
||||
this.difY = (targetHeight ? targetHeight - this.curHeight : 0);
|
||||
this.step = 0;
|
||||
this.steps = Math.ceil(Math.max(Math.abs(this.difX), Math.abs(this.difY))/pixelsPerStep);
|
||||
this.timeout = (1000/stepsPerSecond);
|
||||
|
||||
var me = this;
|
||||
this._animateCallback = function() { me.animate() };
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a step of the animation
|
||||
*/
|
||||
Resizer.prototype.animate = function() {
|
||||
if(this.stopped) return;
|
||||
this.step++;
|
||||
this.panel.sizeTo(this.curWidth+Math.round(this.step*this.difX/this.steps),
|
||||
this.curHeight+Math.round(this.step*this.difY/this.steps));
|
||||
if(this.step !== this.steps) {
|
||||
window.setTimeout(this._animateCallback, this.timeout);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Halts resizing
|
||||
*/
|
||||
Resizer.prototype.stop = function() {
|
||||
this.stopped = true;
|
||||
};
|
||||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded", Zotero_ProgressBar.onDOMContentLoaded, false);
|
||||
window.addEventListener("load", Zotero_ProgressBar.onLoad, false);
|
51
chrome/content/zotero/integration/progressBar.xul
Normal file
51
chrome/content/zotero/integration/progressBar.xul
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2018 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
-->
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/browser.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/integration.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://zotero-platform/content/integration.css" type="text/css"?>
|
||||
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
|
||||
|
||||
<window
|
||||
id="quick-format-dialog"
|
||||
class="progress-bar"
|
||||
orient="vertical"
|
||||
title="&zotero.progress.title;"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
persist="screenX screenY">
|
||||
|
||||
<script src="../include.js"/>
|
||||
<script src="windowDraggingUtils.js" type="text/javascript"/>
|
||||
<script src="progressBar.js" type="text/javascript"/>
|
||||
|
||||
<box orient="horizontal" id="quick-format-entry">
|
||||
<deck id="quick-format-deck" selectedIndex="0" flex="1">
|
||||
<progressmeter id="quick-format-progress-meter" mode="undetermined" value="0" flex="1"/>
|
||||
</deck>
|
||||
</box>
|
||||
</window>
|
|
@ -37,9 +37,10 @@ var Zotero_QuickFormat = new function () {
|
|||
keepSorted, showEditor, referencePanel, referenceBox, referenceHeight = 0,
|
||||
separatorHeight = 0, currentLocator, currentLocatorLabel, currentSearchTime, dragging,
|
||||
panel, panelPrefix, panelSuffix, panelSuppressAuthor, panelLocatorLabel, panelLocator,
|
||||
panelLibraryLink, panelInfo, panelRefersToBubble, panelFrameHeight = 0, accepted = false,
|
||||
searchTimeout;
|
||||
panelLibraryLink, panelInfo, panelRefersToBubble, panelFrameHeight = 0, accepted = false;
|
||||
var _searchPromise;
|
||||
|
||||
const SEARCH_TIMEOUT = 250;
|
||||
const SHOWN_REFERENCES = 7;
|
||||
|
||||
/**
|
||||
|
@ -178,6 +179,7 @@ var Zotero_QuickFormat = new function () {
|
|||
*/
|
||||
function _getCurrentEditorTextNode() {
|
||||
var selection = qfiWindow.getSelection();
|
||||
if (!selection) return false;
|
||||
var range = selection.getRangeAt(0);
|
||||
|
||||
var node = range.startContainer;
|
||||
|
@ -710,7 +712,7 @@ var Zotero_QuickFormat = new function () {
|
|||
/**
|
||||
* Converts the selected item to a bubble
|
||||
*/
|
||||
function _bubbleizeSelected() {
|
||||
var _bubbleizeSelected = Zotero.Promise.coroutine(function* () {
|
||||
if(!referenceBox.hasChildNodes() || !referenceBox.selectedItem) return false;
|
||||
|
||||
var citationItem = {"id":referenceBox.selectedItem.getAttribute("zotero-item")};
|
||||
|
@ -733,11 +735,11 @@ var Zotero_QuickFormat = new function () {
|
|||
node.nodeValue = "";
|
||||
var bubble = _insertBubble(citationItem, node);
|
||||
_clearEntryList();
|
||||
_previewAndSort();
|
||||
yield _previewAndSort();
|
||||
_refocusQfe();
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Ignores clicks (for use on separators in the rich list box)
|
||||
|
@ -901,13 +903,13 @@ var Zotero_QuickFormat = new function () {
|
|||
/**
|
||||
* Generates the preview and sorts citations
|
||||
*/
|
||||
function _previewAndSort() {
|
||||
var _previewAndSort = Zotero.Promise.coroutine(function* () {
|
||||
var shouldKeepSorted = keepSorted.hasAttribute("checked"),
|
||||
editorShowing = showEditor.hasAttribute("checked");
|
||||
if(!shouldKeepSorted && !editorShowing) return;
|
||||
|
||||
_updateCitationObject();
|
||||
io.sort();
|
||||
yield io.sort();
|
||||
if(shouldKeepSorted) {
|
||||
// means we need to resort citations
|
||||
_clearCitation();
|
||||
|
@ -919,7 +921,7 @@ var Zotero_QuickFormat = new function () {
|
|||
|
||||
_moveCursorToEnd();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Shows the citation properties panel for a given bubble
|
||||
|
@ -1051,14 +1053,26 @@ var Zotero_QuickFormat = new function () {
|
|||
* keypress, since searches can be slow.
|
||||
*/
|
||||
function _resetSearchTimer() {
|
||||
if(searchTimeout) clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(_quickFormat, 250);
|
||||
// Show spinner
|
||||
var spinner = document.getElementById('quick-format-spinner');
|
||||
spinner.style.visibility = '';
|
||||
// Cancel current search if active
|
||||
if (_searchPromise && _searchPromise.isPending()) {
|
||||
_searchPromise.cancel();
|
||||
}
|
||||
// Start new search
|
||||
_searchPromise = Zotero.Promise.delay(SEARCH_TIMEOUT)
|
||||
.then(() => _quickFormat())
|
||||
.then(() => {
|
||||
_searchPromise = null;
|
||||
spinner.style.visibility = 'hidden';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle return or escape
|
||||
*/
|
||||
function _onQuickSearchKeyPress(event) {
|
||||
var _onQuickSearchKeyPress = Zotero.Promise.coroutine(function* (event) {
|
||||
// Prevent hang if another key is pressed after Enter
|
||||
// https://forums.zotero.org/discussion/59157/
|
||||
if (accepted) {
|
||||
|
@ -1070,7 +1084,7 @@ var Zotero_QuickFormat = new function () {
|
|||
var keyCode = event.keyCode;
|
||||
if (keyCode === event.DOM_VK_RETURN) {
|
||||
event.preventDefault();
|
||||
if(!_bubbleizeSelected() && !_getEditorContent()) {
|
||||
if(!(yield _bubbleizeSelected()) && !_getEditorContent()) {
|
||||
_accept();
|
||||
}
|
||||
} else if(keyCode === event.DOM_VK_TAB || event.charCode === 59 /* ; */) {
|
||||
|
@ -1149,7 +1163,7 @@ var Zotero_QuickFormat = new function () {
|
|||
} else {
|
||||
_resetSearchTimer();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Adds a dummy element to make dragging work
|
||||
|
@ -1177,7 +1191,7 @@ var Zotero_QuickFormat = new function () {
|
|||
/**
|
||||
* Replaces the dummy element with a node to make dropping work
|
||||
*/
|
||||
function _onBubbleDrop(event) {
|
||||
var _onBubbleDrop = Zotero.Promise.coroutine(function* (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
|
@ -1195,9 +1209,9 @@ var Zotero_QuickFormat = new function () {
|
|||
keepSorted.removeAttribute("checked");
|
||||
}
|
||||
|
||||
_previewAndSort();
|
||||
yield _previewAndSort();
|
||||
_moveCursorToEnd();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle a click on a bubble
|
||||
|
@ -1301,18 +1315,26 @@ var Zotero_QuickFormat = new function () {
|
|||
/**
|
||||
* Show an item in the library it came from
|
||||
*/
|
||||
this.showInLibrary = function() {
|
||||
this.showInLibrary = async function() {
|
||||
var id = panelRefersToBubble.citationItem.id;
|
||||
var pane = Zotero.getActiveZoteroPane();
|
||||
if(pane) {
|
||||
pane.show();
|
||||
pane.selectItem(id);
|
||||
} else {
|
||||
var win = window.open('zotero://select/item/'+id);
|
||||
// Open main window if it's not open (Mac)
|
||||
if (!pane) {
|
||||
let win = Zotero.openMainWindow();
|
||||
await new Zotero.Promise((resolve) => {
|
||||
let onOpen = function () {
|
||||
win.removeEventListener('load', onOpen);
|
||||
resolve();
|
||||
};
|
||||
win.addEventListener('load', onOpen);
|
||||
});
|
||||
pane = win.ZoteroPane;
|
||||
}
|
||||
pane.show();
|
||||
pane.selectItem(id);
|
||||
|
||||
// Pull window to foreground
|
||||
Zotero.Integration.activate(pane.document.defaultView);
|
||||
Zotero.Utilities.Internal.activate(pane.document.defaultView);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -62,6 +62,9 @@
|
|||
</toolbarbutton>
|
||||
<iframe id="quick-format-iframe" ondragstart="event.stopPropagation()" src="data:application/xhtml+xml,%3C!DOCTYPE%20html%20PUBLIC%20%22-//W3C//DTD%20XHTML%201.0%20Strict//EN%22%20%22http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd%22%3E%3Chtml%20xmlns=%22http://www.w3.org/1999/xhtml%22%3E%3Chead%3E%3Clink%20rel=%22stylesheet%22%20type=%22text/css%22%20href=%22chrome://zotero/skin/integration.css%22/%3E%3Clink%20rel=%22stylesheet%22%20type=%22text/css%22%20href=%22chrome://zotero-platform/content/integration.css%22/%3E%3C/head%3E%3Cbody%20contenteditable=%22true%22%20spellcheck=%22false%22%20id=%22quick-format-editor%22/%3E%3C/html%3E"
|
||||
tabindex="1" flex="1"/>
|
||||
<vbox id="quick-format-spinner" style="visibility: hidden">
|
||||
<image class="zotero-spinner-16"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<progressmeter id="quick-format-progress-meter" mode="undetermined" value="0" flex="1"/>
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
var ZoteroItemPane = new function() {
|
||||
var _lastItem, _itemBox, _notesLabel, _notesButton, _notesList, _tagsBox, _relatedBox;
|
||||
var _selectedNoteID;
|
||||
var _translationTarget;
|
||||
var _noteIDs;
|
||||
|
||||
|
@ -98,11 +99,6 @@ var ZoteroItemPane = new function() {
|
|||
var viewBox = document.getElementById('zotero-view-item');
|
||||
viewBox.classList.remove('no-tabs');
|
||||
|
||||
// Switch to info pane for feed items
|
||||
if (item.isFeedItem) {
|
||||
index = viewBox.selectedIndex = 0;
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
document.getElementById('zotero-editpane-tabs').setAttribute('hidden', item.isFeedItem);
|
||||
|
||||
|
@ -142,7 +138,7 @@ var ZoteroItemPane = new function() {
|
|||
|
||||
var icon = document.createElement('image');
|
||||
icon.className = "zotero-box-icon";
|
||||
icon.setAttribute('src','chrome://zotero/skin/treeitem-note.png');
|
||||
icon.setAttribute('src', `chrome://zotero/skin/treeitem-note${Zotero.hiDPISuffix}.png`);
|
||||
|
||||
var label = document.createElement('label');
|
||||
label.className = "zotero-box-label";
|
||||
|
@ -227,6 +223,61 @@ var ZoteroItemPane = new function() {
|
|||
});
|
||||
|
||||
|
||||
this.onNoteSelected = function (item, editable) {
|
||||
_selectedNoteID = item.id;
|
||||
|
||||
// If an external note window is open for this item, don't show the editor
|
||||
if (ZoteroPane.findNoteWindow(item.id)) {
|
||||
this.showNoteWindowMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
var noteEditor = document.getElementById('zotero-note-editor');
|
||||
|
||||
// If loading new or different note, disable undo while we repopulate the text field
|
||||
// so Undo doesn't end up clearing the field. This also ensures that Undo doesn't
|
||||
// undo content from another note into the current one.
|
||||
var clearUndo = noteEditor.item ? noteEditor.item.id != item.id : false;
|
||||
|
||||
noteEditor.mode = editable ? 'edit' : 'view';
|
||||
noteEditor.parent = null;
|
||||
noteEditor.item = item;
|
||||
|
||||
if (clearUndo) {
|
||||
noteEditor.clearUndo();
|
||||
}
|
||||
|
||||
document.getElementById('zotero-view-note-button').hidden = !editable;
|
||||
document.getElementById('zotero-item-pane-content').selectedIndex = 2;
|
||||
};
|
||||
|
||||
|
||||
this.showNoteWindowMessage = function () {
|
||||
ZoteroPane.setItemPaneMessage(Zotero.getString('pane.item.notes.editingInWindow'));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Select the parent item and open the note editor
|
||||
*/
|
||||
this.openNoteWindow = async function () {
|
||||
var selectedNote = Zotero.Items.get(_selectedNoteID);
|
||||
|
||||
// We don't want to show the note in two places, since it causes unnecessary UI updates
|
||||
// and can result in weird bugs where note content gets lost.
|
||||
//
|
||||
// If this is a child note, select the parent
|
||||
if (selectedNote.parentID) {
|
||||
await ZoteroPane.selectItem(selectedNote.parentID);
|
||||
}
|
||||
// Otherwise, hide note and replace with a message that we're editing externally
|
||||
else {
|
||||
this.showNoteWindowMessage();
|
||||
}
|
||||
ZoteroPane.openNoteWindow(selectedNote.id);
|
||||
};
|
||||
|
||||
|
||||
this.addNote = function (popup) {
|
||||
ZoteroPane_Local.newNote(popup, _lastItem.key);
|
||||
}
|
||||
|
@ -326,30 +377,18 @@ var ZoteroItemPane = new function() {
|
|||
ZoteroItemPane.setTranslateButton();
|
||||
};
|
||||
|
||||
|
||||
this.setToggleReadLabel = function() {
|
||||
var markRead = false;
|
||||
var items = ZoteroPane_Local.itemsView.getSelectedItems();
|
||||
for (let item of items) {
|
||||
if (!item.isRead) {
|
||||
markRead = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.setReadLabel = function (isRead) {
|
||||
var elem = document.getElementById('zotero-feed-item-toggleRead-button');
|
||||
if (markRead) {
|
||||
var label = Zotero.getString('pane.item.markAsRead');
|
||||
} else {
|
||||
label = Zotero.getString('pane.item.markAsUnread');
|
||||
}
|
||||
var label = Zotero.getString('pane.item.' + (isRead ? 'markAsUnread' : 'markAsRead'));
|
||||
elem.setAttribute('label', label);
|
||||
|
||||
var key = Zotero.Keys.getKeyForCommand('toggleRead');
|
||||
var tooltip = label + (Zotero.rtl ? ' \u202B' : ' ') + '(' + key + ')'
|
||||
elem.setAttribute('tooltiptext', tooltip);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
function _updateNoteCount() {
|
||||
var c = _notesList.childNodes.length;
|
||||
|
||||
|
|
|
@ -113,8 +113,10 @@
|
|||
-->
|
||||
<zoteronoteeditor id="zotero-note-editor" flex="1" notitle="1"
|
||||
previousfocus="zotero-items-tree"
|
||||
onerror="ZoteroPane.displayErrorMessage()"/>
|
||||
<button id="zotero-view-note-button" label="&zotero.notes.separate;" oncommand="ZoteroPane_Local.openNoteWindow(this.getAttribute('noteID')); if(this.hasAttribute('sourceID')) ZoteroPane_Local.selectItem(this.getAttribute('sourceID'));"/>
|
||||
onerror="ZoteroPane.displayErrorMessage(); this.mode = 'view'"/>
|
||||
<button id="zotero-view-note-button"
|
||||
label="&zotero.notes.separate;"
|
||||
oncommand="ZoteroItemPane.openNoteWindow()"/>
|
||||
</groupbox>
|
||||
|
||||
<!-- Attachment item -->
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 96042867e58040158417e457e3cb78c73d36b029
|
||||
Subproject commit b8c370c8a978790d2aeefa302f05f3bfb1478e75
|
|
@ -32,61 +32,8 @@ var Zotero_Lookup = new function () {
|
|||
* Performs a lookup by DOI, PMID, or ISBN
|
||||
*/
|
||||
this.accept = Zotero.Promise.coroutine(function* (textBox) {
|
||||
var foundIDs = []; //keep track of identifiers to avoid duplicates
|
||||
var identifier = textBox.value;
|
||||
//first look for DOIs
|
||||
var ids = identifier.split(/[\s\u00A0]+/); //whitespace + non-breaking space
|
||||
var items = [], doi;
|
||||
for(var i=0, n=ids.length; i<n; i++) {
|
||||
if((doi = Zotero.Utilities.cleanDOI(ids[i])) && foundIDs.indexOf(doi) == -1) {
|
||||
items.push({itemType:"journalArticle", DOI:doi});
|
||||
foundIDs.push(doi);
|
||||
}
|
||||
}
|
||||
|
||||
//then try ISBNs
|
||||
if(!items.length) {
|
||||
//first try replacing dashes
|
||||
ids = identifier.replace(/[\u002D\u00AD\u2010-\u2015\u2212]+/g, "") //hyphens and dashes
|
||||
.toUpperCase();
|
||||
|
||||
var ISBN_RE = /(?:\D|^)(97[89]\d{10}|\d{9}[\dX])(?!\d)/g;
|
||||
var isbn;
|
||||
|
||||
while(isbn = ISBN_RE.exec(ids)) {
|
||||
isbn = Zotero.Utilities.cleanISBN(isbn[1]);
|
||||
if(isbn && foundIDs.indexOf(isbn) == -1) {
|
||||
items.push({itemType:"book", ISBN:isbn});
|
||||
foundIDs.push(isbn);
|
||||
}
|
||||
}
|
||||
|
||||
//now try spaces
|
||||
if(!items.length) {
|
||||
ids = ids.replace(/[ \u00A0]+/g, ""); //space + non-breaking space
|
||||
while(isbn = ISBN_RE.exec(ids)) {
|
||||
isbn = Zotero.Utilities.cleanISBN(isbn[1]);
|
||||
if(isbn && foundIDs.indexOf(isbn) == -1) {
|
||||
items.push({itemType:"book", ISBN:isbn});
|
||||
foundIDs.push(isbn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//finally try for PMID
|
||||
if(!items.length) {
|
||||
// PMID; right now, the longest PMIDs are 8 digits, so it doesn't
|
||||
// seem like we will need to discriminate for a fairly long time
|
||||
var PMID_RE = /(?:\D|^)(\d{1,9})(?!\d)/g;
|
||||
var pmid;
|
||||
while((pmid = PMID_RE.exec(identifier)) && foundIDs.indexOf(pmid) == -1) {
|
||||
items.push({itemType:"journalArticle", contextObject:"rft_id=info:pmid/"+pmid[1]});
|
||||
foundIDs.push(pmid);
|
||||
}
|
||||
}
|
||||
|
||||
if(!items.length) {
|
||||
var identifiers = Zotero.Utilities.Internal.extractIdentifiers(textBox.value);
|
||||
if (!identifiers.length) {
|
||||
Zotero.alert(
|
||||
window,
|
||||
Zotero.getString("lookup.failure.title"),
|
||||
|
@ -104,47 +51,86 @@ var Zotero_Lookup = new function () {
|
|||
/** TODO: handle this **/
|
||||
}
|
||||
|
||||
var notDone = items.length; //counter for asynchronous fetching
|
||||
var successful = 0; //counter for successful retrievals
|
||||
|
||||
Zotero_Lookup.toggleProgress(true);
|
||||
|
||||
var item;
|
||||
while(item = items.pop()) {
|
||||
for (let identifier of identifiers) {
|
||||
var translate = new Zotero.Translate.Search();
|
||||
translate.setSearch(item);
|
||||
translate.setIdentifier(identifier);
|
||||
|
||||
// be lenient about translators
|
||||
let translators = yield translate.getTranslators();
|
||||
translate.setTranslator(translators);
|
||||
|
||||
translate.setHandler("done", function(translate, success) {
|
||||
notDone--;
|
||||
successful += success;
|
||||
|
||||
if(!notDone) { //i.e. done
|
||||
Zotero_Lookup.toggleProgress(false);
|
||||
if(successful) {
|
||||
document.getElementById("zotero-lookup-panel").hidePopup();
|
||||
} else {
|
||||
Zotero.alert(
|
||||
window,
|
||||
Zotero.getString("lookup.failure.title"),
|
||||
Zotero.getString("lookup.failure.description")
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
yield translate.translate({
|
||||
libraryID,
|
||||
collections: collection ? [collection.id] : false
|
||||
});
|
||||
try {
|
||||
yield translate.translate({
|
||||
libraryID,
|
||||
collections: collection ? [collection.id] : false
|
||||
})
|
||||
successful++;
|
||||
}
|
||||
// Continue with other ids on failure
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Zotero_Lookup.toggleProgress(false);
|
||||
// TODO: Give indication if some failed
|
||||
if (successful) {
|
||||
document.getElementById("zotero-lookup-panel").hidePopup();
|
||||
}
|
||||
else {
|
||||
Zotero.alert(
|
||||
window,
|
||||
Zotero.getString("lookup.failure.title"),
|
||||
Zotero.getString("lookup.failure.description")
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
this.showPanel = function (button) {
|
||||
var panel = document.getElementById('zotero-lookup-panel');
|
||||
panel.openPopup(button, "after_start", 16, -2, false, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Focuses the field
|
||||
*/
|
||||
this.onShowing = function (event) {
|
||||
// Ignore context menu
|
||||
if (event.originalTarget.id != 'zotero-lookup-panel') return;
|
||||
|
||||
document.getElementById("zotero-lookup-panel").style.padding = "10px";
|
||||
this.getActivePanel().getElementsByTagName('textbox')[0].focus();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cancels the popup and resets fields
|
||||
*/
|
||||
this.onHidden = function (event) {
|
||||
// Ignore context menu
|
||||
if (event.originalTarget.id != 'zotero-lookup-panel') return;
|
||||
|
||||
document.getElementById("zotero-lookup-textbox").value = "";
|
||||
document.getElementById("zotero-lookup-multiline-textbox").value = "";
|
||||
Zotero_Lookup.toggleProgress(false);
|
||||
}
|
||||
|
||||
|
||||
this.getActivePanel = function() {
|
||||
var mlPanel = document.getElementById("zotero-lookup-multiline");
|
||||
if (mlPanel.collapsed) return document.getElementById("zotero-lookup-singleLine");
|
||||
return mlPanel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles a key press
|
||||
*/
|
||||
|
@ -167,44 +153,27 @@ var Zotero_Lookup = new function () {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Focuses the field
|
||||
*/
|
||||
this.onShowing = function() {
|
||||
document.getElementById("zotero-lookup-panel").style.padding = "10px";
|
||||
|
||||
// Workaround for field being truncated in middle
|
||||
// https://github.com/zotero/zotero/issues/343
|
||||
this.toggleMultiline(true);
|
||||
|
||||
var identifierElement = Zotero_Lookup.toggleMultiline(false);
|
||||
Zotero_Lookup.toggleProgress(false);
|
||||
identifierElement.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the popup and resets fields
|
||||
*/
|
||||
this.onHidden = function() {
|
||||
var txtBox = Zotero_Lookup.toggleMultiline(false);
|
||||
var mlTextbox = document.getElementById("zotero-lookup-multiline-textbox");
|
||||
txtBox.value = "";
|
||||
mlTextbox.value = "";
|
||||
}
|
||||
|
||||
this.onInput = function (event, textbox) {
|
||||
this.adjustTextbox(textbox);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts the textbox to multiline if newlines are detected
|
||||
*/
|
||||
this.adjustTextbox = function(txtBox) {
|
||||
if(txtBox.value.trim().match(/[\r\n]/)) {
|
||||
this.adjustTextbox = function (textbox) {
|
||||
if (textbox.value.trim().match(/[\r\n]/)) {
|
||||
Zotero_Lookup.toggleMultiline(true);
|
||||
} else {
|
||||
//since we ignore trailing and leading newlines, we should also trim them for display
|
||||
//can't use trim, because then we cannot add leading/trailing spaces to the single line textbox
|
||||
txtBox.value = txtBox.value.replace(/^([ \t]*[\r\n]+[ \t]*)+|([ \t]*[\r\n]+[ \t]*)+$/g,"");
|
||||
}
|
||||
// Since we ignore trailing and leading newlines, we should also trim them for display
|
||||
// can't use trim, because then we cannot add leading/trailing spaces to the single line textbox
|
||||
else {
|
||||
textbox.value = textbox.value.replace(/^([ \t]*[\r\n]+[ \t]*)+|([ \t]*[\r\n]+[ \t]*)+$/g,"");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Performs the switch to multiline textbox and returns that textbox
|
||||
*/
|
||||
|
@ -237,21 +206,20 @@ var Zotero_Lookup = new function () {
|
|||
}
|
||||
|
||||
this.toggleProgress = function(on) {
|
||||
// In Firefox 52.6.0, progressmeters burn CPU at idle on Linux when undetermined, even
|
||||
// if they're hidden. (Being hidden is enough on macOS.)
|
||||
var mode = on ? 'undetermined' : 'determined';
|
||||
|
||||
//single line
|
||||
var txtBox = document.getElementById("zotero-lookup-textbox");
|
||||
txtBox.style.opacity = on ? 0.5 : 1;
|
||||
txtBox.disabled = !!on;
|
||||
document.getElementById("zotero-lookup-progress").setAttribute("collapsed", !on);
|
||||
var p1 = document.getElementById("zotero-lookup-progress");
|
||||
p1.mode = mode;
|
||||
|
||||
//multiline
|
||||
document.getElementById("zotero-lookup-multiline-textbox").disabled = !!on;
|
||||
document.getElementById("zotero-lookup-multiline-progress").setAttribute("collapsed", !on);
|
||||
}
|
||||
|
||||
this.getActivePanel = function() {
|
||||
var mlPanel = document.getElementById("zotero-lookup-multiline");
|
||||
if(mlPanel.collapsed) return document.getElementById("zotero-lookup-singleLine");
|
||||
|
||||
return mlPanel;
|
||||
var p2 = document.getElementById("zotero-lookup-multiline-progress");
|
||||
p2.mode = mode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,7 +168,6 @@ var Zotero_Merge_Window = new function () {
|
|||
if (x.data) {
|
||||
x.data.version = _conflicts[i][x.selected].version;
|
||||
}
|
||||
a[i] = x.data;
|
||||
})
|
||||
|
||||
_io.dataOut = _merged;
|
||||
|
|
|
@ -26,10 +26,9 @@
|
|||
var noteEditor;
|
||||
var notifierUnregisterID;
|
||||
|
||||
function onLoad() {
|
||||
async function onLoad() {
|
||||
noteEditor = document.getElementById('zotero-note-editor');
|
||||
noteEditor.mode = 'edit';
|
||||
noteEditor.focus();
|
||||
|
||||
// Set font size from pref
|
||||
Zotero.setFontSize(noteEditor);
|
||||
|
@ -37,60 +36,58 @@ function onLoad() {
|
|||
if (window.arguments) {
|
||||
var io = window.arguments[0];
|
||||
}
|
||||
var itemID = io.itemID;
|
||||
var collectionID = io.collectionID;
|
||||
|
||||
var itemID = parseInt(io.itemID);
|
||||
var collectionID = parseInt(io.collectionID);
|
||||
var parentItemKey = io.parentItemKey;
|
||||
|
||||
return Zotero.spawn(function* () {
|
||||
if (itemID) {
|
||||
var ref = yield Zotero.Items.getAsync(itemID);
|
||||
|
||||
var clearUndo = noteEditor.item ? noteEditor.item.id != ref.id : false;
|
||||
|
||||
noteEditor.item = ref;
|
||||
|
||||
// If loading new or different note, disable undo while we repopulate the text field
|
||||
// so Undo doesn't end up clearing the field. This also ensures that Undo doesn't
|
||||
// undo content from another note into the current one.
|
||||
if (clearUndo) {
|
||||
noteEditor.clearUndo();
|
||||
}
|
||||
|
||||
document.title = ref.getNoteTitle();
|
||||
if (itemID) {
|
||||
var ref = await Zotero.Items.getAsync(itemID);
|
||||
noteEditor.item = ref;
|
||||
document.title = ref.getNoteTitle();
|
||||
}
|
||||
else {
|
||||
if (parentItemKey) {
|
||||
var ref = Zotero.Items.getByLibraryAndKey(parentItemKey);
|
||||
noteEditor.parentItem = ref;
|
||||
}
|
||||
else {
|
||||
if (parentItemKey) {
|
||||
var ref = Zotero.Items.getByLibraryAndKey(parentItemKey);
|
||||
noteEditor.parentItem = ref;
|
||||
if (collectionID && collectionID != '' && collectionID != 'undefined') {
|
||||
noteEditor.collection = Zotero.Collections.get(collectionID);
|
||||
}
|
||||
else {
|
||||
if (collectionID && collectionID != '' && collectionID != 'undefined') {
|
||||
noteEditor.collection = Zotero.Collections.get(collectionID);
|
||||
}
|
||||
}
|
||||
noteEditor.refresh();
|
||||
}
|
||||
|
||||
notifierUnregisterID = Zotero.Notifier.registerObserver(NotifyCallback, 'item');
|
||||
});
|
||||
noteEditor.refresh();
|
||||
}
|
||||
|
||||
noteEditor.focus();
|
||||
notifierUnregisterID = Zotero.Notifier.registerObserver(NotifyCallback, 'item', 'noteWindow');
|
||||
}
|
||||
|
||||
function onUnload()
|
||||
{
|
||||
if(noteEditor && noteEditor.value)
|
||||
noteEditor.save();
|
||||
|
||||
// If there's an error saving a note, close the window and crash the app
|
||||
function onError() {
|
||||
try {
|
||||
window.opener.ZoteroPane.displayErrorMessage();
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
|
||||
|
||||
function onUnload() {
|
||||
Zotero.Notifier.unregisterObserver(notifierUnregisterID);
|
||||
|
||||
if (noteEditor.item) {
|
||||
window.opener.ZoteroPane.onNoteWindowClosed(noteEditor.item.id, noteEditor.value);
|
||||
}
|
||||
}
|
||||
|
||||
var NotifyCallback = {
|
||||
notify: function(action, type, ids){
|
||||
if (noteEditor.item && ids.indexOf(noteEditor.item.id) != -1) {
|
||||
// If the document title hasn't yet been set, reset undo so
|
||||
// undoing to empty isn't possible
|
||||
var noteTitle = noteEditor.note.getNoteTitle();
|
||||
if (noteEditor.item && ids.includes(noteEditor.item.id)) {
|
||||
var noteTitle = noteEditor.item.getNoteTitle();
|
||||
if (!document.title && noteTitle != '') {
|
||||
noteEditor.clearUndo();
|
||||
document.title = noteTitle;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script src="include.js"/>
|
||||
<script src="itemPane.js"/>
|
||||
<script src="note.js"/>
|
||||
|
||||
<keyset>
|
||||
|
@ -23,5 +22,5 @@
|
|||
</keyset>
|
||||
<command id="cmd_close" oncommand="window.close();"/>
|
||||
|
||||
<zoteronoteeditor id="zotero-note-editor" flex="1"/>
|
||||
<zoteronoteeditor id="zotero-note-editor" flex="1" onerror="onError()"/>
|
||||
</window>
|
|
@ -23,20 +23,47 @@
|
|||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
Zotero_Preferences.Advanced = {
|
||||
_openURLResolvers: null,
|
||||
|
||||
|
||||
init: function () {
|
||||
Zotero_Preferences.Debug_Output.init();
|
||||
Zotero_Preferences.Keys.init();
|
||||
|
||||
// Show Memory Info button if the Error Console menu option is enabled
|
||||
if (Zotero.Prefs.get('devtools.errorconsole.enabled', true)) {
|
||||
document.getElementById('memory-info').hidden = false;
|
||||
}
|
||||
|
||||
this.onDataDirLoad();
|
||||
this.refreshLocale();
|
||||
},
|
||||
|
||||
|
||||
updateTranslators: Zotero.Promise.coroutine(function* () {
|
||||
var updated = yield Zotero.Schema.updateFromRepository(Zotero.Schema.REPO_UPDATE_MANUAL);
|
||||
var button = document.getElementById('updateButton');
|
||||
if (button) {
|
||||
if (updated===-1) {
|
||||
var label = Zotero.getString('zotero.preferences.update.upToDate');
|
||||
}
|
||||
else if (updated) {
|
||||
var label = Zotero.getString('zotero.preferences.update.updated');
|
||||
}
|
||||
else {
|
||||
var label = Zotero.getString('zotero.preferences.update.error');
|
||||
}
|
||||
button.setAttribute('label', label);
|
||||
|
||||
if (updated && Zotero_Preferences.Cite) {
|
||||
yield Zotero_Preferences.Cite.refreshStylesList();
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
|
||||
migrateDataDirectory: Zotero.Promise.coroutine(function* () {
|
||||
var currentDir = Zotero.DataDirectory.dir;
|
||||
var defaultDir = Zotero.DataDirectory.defaultDir;
|
||||
|
@ -49,6 +76,19 @@ Zotero_Preferences.Advanced = {
|
|||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
// If there's a migration marker, point data directory back to the current location and remove
|
||||
// it to trigger the migration again
|
||||
var marker = OS.Path.join(defaultDir, Zotero.DataDirectory.MIGRATION_MARKER);
|
||||
if (yield OS.File.exists(marker)) {
|
||||
Zotero.Prefs.clear('dataDir');
|
||||
Zotero.Prefs.clear('useDataDir');
|
||||
yield OS.File.remove(marker);
|
||||
try {
|
||||
yield OS.File.remove(OS.Path.join(defaultDir, '.DS_Store'));
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
|
||||
// ~/Zotero exists and is non-empty
|
||||
if ((yield OS.File.exists(defaultDir)) && !(yield Zotero.File.directoryIsEmpty(defaultDir))) {
|
||||
let buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
||||
|
@ -115,70 +155,84 @@ Zotero_Preferences.Advanced = {
|
|||
}),
|
||||
|
||||
|
||||
runIntegrityCheck: Zotero.Promise.coroutine(function* () {
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
runIntegrityCheck: async function (button) {
|
||||
button.disabled = true;
|
||||
|
||||
var ok = yield Zotero.DB.integrityCheck();
|
||||
if (ok) {
|
||||
ok = yield Zotero.Schema.integrityCheck();
|
||||
if (!ok) {
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
|
||||
var index = ps.confirmEx(window,
|
||||
Zotero.getString('general.failed'),
|
||||
Zotero.getString('db.integrityCheck.failed') + "\n\n" +
|
||||
Zotero.getString('db.integrityCheck.repairAttempt') + " " +
|
||||
Zotero.getString('db.integrityCheck.appRestartNeeded', Zotero.appName),
|
||||
buttonFlags,
|
||||
Zotero.getString('db.integrityCheck.fixAndRestart', Zotero.appName),
|
||||
null, null, null, {}
|
||||
);
|
||||
|
||||
if (index == 0) {
|
||||
// Safety first
|
||||
yield Zotero.DB.backupDatabase();
|
||||
|
||||
// Fix the errors
|
||||
yield Zotero.Schema.integrityCheck(true);
|
||||
|
||||
// And run the check again
|
||||
ok = yield Zotero.Schema.integrityCheck();
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING);
|
||||
if (ok) {
|
||||
var str = 'success';
|
||||
var msg = Zotero.getString('db.integrityCheck.errorsFixed');
|
||||
}
|
||||
else {
|
||||
var str = 'failed';
|
||||
var msg = Zotero.getString('db.integrityCheck.errorsNotFixed')
|
||||
+ "\n\n" + Zotero.getString('db.integrityCheck.reportInForums');
|
||||
}
|
||||
|
||||
ps.confirmEx(window,
|
||||
Zotero.getString('general.' + str),
|
||||
msg,
|
||||
try {
|
||||
let ps = Services.prompt;
|
||||
|
||||
var ok = await Zotero.DB.integrityCheck();
|
||||
if (ok) {
|
||||
ok = await Zotero.Schema.integrityCheck();
|
||||
if (!ok) {
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
|
||||
var index = ps.confirmEx(window,
|
||||
Zotero.getString('general.failed'),
|
||||
Zotero.getString('db.integrityCheck.failed') + "\n\n" +
|
||||
Zotero.getString('db.integrityCheck.repairAttempt') + " " +
|
||||
Zotero.getString('db.integrityCheck.appRestartNeeded', Zotero.appName),
|
||||
buttonFlags,
|
||||
Zotero.getString('general.restartApp', Zotero.appName),
|
||||
Zotero.getString('db.integrityCheck.fixAndRestart', Zotero.appName),
|
||||
null, null, null, {}
|
||||
);
|
||||
|
||||
var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Components.interfaces.nsIAppStartup);
|
||||
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit
|
||||
| Components.interfaces.nsIAppStartup.eRestart);
|
||||
if (index == 0) {
|
||||
// Safety first
|
||||
await Zotero.DB.backupDatabase();
|
||||
|
||||
// Fix the errors
|
||||
await Zotero.Schema.integrityCheck(true);
|
||||
|
||||
// And run the check again
|
||||
ok = await Zotero.Schema.integrityCheck();
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING);
|
||||
if (ok) {
|
||||
var str = 'success';
|
||||
var msg = Zotero.getString('db.integrityCheck.errorsFixed');
|
||||
}
|
||||
else {
|
||||
var str = 'failed';
|
||||
var msg = Zotero.getString('db.integrityCheck.errorsNotFixed')
|
||||
+ "\n\n" + Zotero.getString('db.integrityCheck.reportInForums');
|
||||
}
|
||||
|
||||
ps.confirmEx(window,
|
||||
Zotero.getString('general.' + str),
|
||||
msg,
|
||||
buttonFlags,
|
||||
Zotero.getString('general.restartApp', Zotero.appName),
|
||||
null, null, null, {}
|
||||
);
|
||||
|
||||
var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Components.interfaces.nsIAppStartup);
|
||||
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit
|
||||
| Components.interfaces.nsIAppStartup.eRestart);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
try {
|
||||
await Zotero.DB.vacuum();
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
var str = ok ? 'passed' : 'failed';
|
||||
|
||||
ps.alert(window,
|
||||
Zotero.getString('general.' + str),
|
||||
Zotero.getString('db.integrityCheck.' + str)
|
||||
+ (!ok ? "\n\n" + Zotero.getString('db.integrityCheck.dbRepairTool') : ''));
|
||||
}
|
||||
var str = ok ? 'passed' : 'failed';
|
||||
|
||||
ps.alert(window,
|
||||
Zotero.getString('general.' + str),
|
||||
Zotero.getString('db.integrityCheck.' + str)
|
||||
+ (!ok ? "\n\n" + Zotero.getString('db.integrityCheck.dbRepairTool') : ''));
|
||||
}),
|
||||
finally {
|
||||
button.disabled = false;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
resetTranslatorsAndStyles: function () {
|
||||
|
@ -206,7 +260,7 @@ Zotero_Preferences.Advanced = {
|
|||
},
|
||||
|
||||
|
||||
resetTranslators: function () {
|
||||
resetTranslators: async function () {
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
|
@ -221,17 +275,22 @@ Zotero_Preferences.Advanced = {
|
|||
null, null, null, {});
|
||||
|
||||
if (index == 0) {
|
||||
Zotero.Schema.resetTranslators()
|
||||
.then(function () {
|
||||
let button = document.getElementById('reset-translators-button');
|
||||
button.disabled = true;
|
||||
try {
|
||||
await Zotero.Schema.resetTranslators();
|
||||
if (Zotero_Preferences.Export) {
|
||||
Zotero_Preferences.Export.populateQuickCopyList();
|
||||
}
|
||||
});
|
||||
}
|
||||
finally {
|
||||
button.disabled = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
resetStyles: function () {
|
||||
resetStyles: async function () {
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
|
@ -246,12 +305,17 @@ Zotero_Preferences.Advanced = {
|
|||
null, null, null, {});
|
||||
|
||||
if (index == 0) {
|
||||
Zotero.Schema.resetStyles()
|
||||
.then(function () {
|
||||
let button = document.getElementById('reset-styles-button');
|
||||
button.disabled = true;
|
||||
try {
|
||||
await Zotero.Schema.resetStyles()
|
||||
if (Zotero_Preferences.Export) {
|
||||
Zotero_Preferences.Export.populateQuickCopyList();
|
||||
}
|
||||
});
|
||||
}
|
||||
finally {
|
||||
button.disabled = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -262,6 +326,12 @@ Zotero_Preferences.Advanced = {
|
|||
var currentDir = Zotero.DataDirectory.dir;
|
||||
var defaultDataDir = Zotero.DataDirectory.defaultDir;
|
||||
|
||||
if (Zotero.forceDataDir) {
|
||||
document.getElementById('command-line-data-dir-path').textContent = currentDir;
|
||||
document.getElementById('command-line-data-dir').hidden = false;
|
||||
document.getElementById('data-dir').hidden = true;
|
||||
}
|
||||
|
||||
// Change "Use profile directory" label to home directory location unless using profile dir
|
||||
if (useDataDir || currentDir == defaultDataDir) {
|
||||
document.getElementById('default-data-dir').setAttribute(
|
||||
|
@ -387,6 +457,84 @@ Zotero_Preferences.Advanced = {
|
|||
|
||||
onOpenURLCustomized: function () {
|
||||
document.getElementById('openURLMenu').value = "custom";
|
||||
},
|
||||
|
||||
|
||||
_getAutomaticLocaleMenuLabel: function () {
|
||||
return Zotero.getString(
|
||||
'zotero.preferences.locale.automaticWithLocale',
|
||||
Zotero.Locale.availableLocales[Zotero.locale] || Zotero.locale
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
refreshLocale: function () {
|
||||
var matchOS = Zotero.Prefs.get('intl.locale.matchOS', true);
|
||||
var autoLocaleName, currentValue;
|
||||
|
||||
// If matching OS, get the name of the current locale
|
||||
if (matchOS) {
|
||||
autoLocaleName = this._getAutomaticLocaleMenuLabel();
|
||||
currentValue = 'automatic';
|
||||
}
|
||||
// Otherwise get the name of the locale specified in the pref
|
||||
else {
|
||||
let branch = Services.prefs.getBranch("");
|
||||
let locale = branch.getComplexValue(
|
||||
'general.useragent.locale', Components.interfaces.nsIPrefLocalizedString
|
||||
);
|
||||
autoLocaleName = Zotero.getString('zotero.preferences.locale.automatic');
|
||||
currentValue = locale;
|
||||
}
|
||||
|
||||
// Populate menu
|
||||
var menu = document.getElementById('locale-menu');
|
||||
var menupopup = menu.firstChild;
|
||||
menupopup.textContent = '';
|
||||
// Show "Automatic (English)", "Automatic (Français)", etc.
|
||||
menu.appendItem(autoLocaleName, 'automatic');
|
||||
menu.menupopup.appendChild(document.createElement('menuseparator'));
|
||||
// Add all available locales
|
||||
for (let locale in Zotero.Locale.availableLocales) {
|
||||
menu.appendItem(Zotero.Locale.availableLocales[locale], locale);
|
||||
}
|
||||
menu.value = currentValue;
|
||||
},
|
||||
|
||||
onLocaleChange: function () {
|
||||
var menu = document.getElementById('locale-menu');
|
||||
if (menu.value == 'automatic') {
|
||||
// Changed if not already set to automatic (unless we have the automatic locale name,
|
||||
// meaning we just switched away to the same manual locale and back to automatic)
|
||||
var changed = !Zotero.Prefs.get('intl.locale.matchOS', true)
|
||||
&& menu.label != this._getAutomaticLocaleMenuLabel();
|
||||
Zotero.Prefs.set('intl.locale.matchOS', true, true);
|
||||
}
|
||||
else {
|
||||
// Changed if moving to a locale other than the current one
|
||||
var changed = Zotero.locale != menu.value
|
||||
Zotero.Prefs.set('intl.locale.matchOS', false, true);
|
||||
Zotero.Prefs.set('general.useragent.locale', menu.value, true);
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
var ps = Services.prompt;
|
||||
var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
|
||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING;
|
||||
var index = ps.confirmEx(null,
|
||||
Zotero.getString('general.restartRequired'),
|
||||
Zotero.getString('general.restartRequiredForChange', Zotero.appName),
|
||||
buttonFlags,
|
||||
Zotero.getString('general.restartNow'),
|
||||
Zotero.getString('general.restartLater'),
|
||||
null, null, {});
|
||||
|
||||
if (index == 0) {
|
||||
Zotero.Utilities.Internal.quitZotero(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -667,202 +815,6 @@ Zotero_Preferences.Attachment_Base_Directory = {
|
|||
};
|
||||
|
||||
|
||||
Zotero_Preferences.Debug_Output = {
|
||||
_timer: null,
|
||||
|
||||
init: function () {
|
||||
var storing = Zotero.Debug.storing;
|
||||
this._updateButton();
|
||||
this.updateLines();
|
||||
if (storing) {
|
||||
this._initTimer();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
toggleStore: function () {
|
||||
this.setStore(!Zotero.Debug.storing);
|
||||
},
|
||||
|
||||
|
||||
setStore: function (set) {
|
||||
Zotero.Debug.setStore(set);
|
||||
if (set) {
|
||||
this._initTimer();
|
||||
}
|
||||
else {
|
||||
if (this._timerID) {
|
||||
this._timer.cancel();
|
||||
this._timerID = null;
|
||||
}
|
||||
}
|
||||
this._updateButton();
|
||||
this.updateLines();
|
||||
},
|
||||
|
||||
|
||||
view: function () {
|
||||
Zotero_Preferences.openInViewer("zotero://debug/");
|
||||
},
|
||||
|
||||
|
||||
submit: Zotero.Promise.coroutine(function* () {
|
||||
document.getElementById('debug-output-submit').disabled = true;
|
||||
var pm = document.getElementById('debug-output-submit-progress');
|
||||
pm.hidden = false;
|
||||
|
||||
Components.utils.import("resource://zotero/config.js");
|
||||
|
||||
var url = ZOTERO_CONFIG.REPOSITORY_URL + "report?debug=1";
|
||||
var output = yield Zotero.Debug.get(
|
||||
Zotero.Prefs.get('debug.store.submitSize'),
|
||||
Zotero.Prefs.get('debug.store.submitLineLength')
|
||||
);
|
||||
Zotero_Preferences.Debug_Output.setStore(false);
|
||||
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
try {
|
||||
var xmlhttp = yield Zotero.HTTP.request(
|
||||
"POST",
|
||||
url,
|
||||
{
|
||||
compressBody: true,
|
||||
body: output,
|
||||
logBodyLength: 30,
|
||||
timeout: 30000,
|
||||
requestObserver: function (req) {
|
||||
// Don't fail during tests, with fake XHR
|
||||
if (!req.channel) {
|
||||
return;
|
||||
}
|
||||
req.channel.notificationCallbacks = {
|
||||
onProgress: function (request, context, progress, progressMax) {
|
||||
pm.mode = 'determined';
|
||||
if (!pm.value || progress > pm.value) {
|
||||
pm.value = progress;
|
||||
}
|
||||
if (!pm.max || progressMax > pm.max) {
|
||||
pm.max = progressMax;
|
||||
}
|
||||
},
|
||||
|
||||
// nsIInterfaceRequestor
|
||||
getInterface: function (iid) {
|
||||
try {
|
||||
return this.QueryInterface(iid);
|
||||
}
|
||||
catch (e) {
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Components.interfaces.nsISupports) ||
|
||||
iid.equals(Components.interfaces.nsIInterfaceRequestor) ||
|
||||
iid.equals(Components.interfaces.nsIProgressEventSink)) {
|
||||
return this;
|
||||
}
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
let title = Zotero.getString('general.error');
|
||||
let msg;
|
||||
if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
|
||||
msg = Zotero.getString('general.invalidResponseServer');
|
||||
}
|
||||
else if (e instanceof Zotero.HTTP.BrowserOfflineException) {
|
||||
msg = Zotero.getString('general.browserIsOffline', Zotero.appName);
|
||||
}
|
||||
else {
|
||||
msg = Zotero.getString('zotero.preferences.advanced.debug.error');
|
||||
}
|
||||
ps.alert(null, title, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
document.getElementById('debug-output-submit').disabled = false;
|
||||
document.getElementById('debug-output-submit-progress').hidden = true;
|
||||
|
||||
Zotero.debug(xmlhttp.responseText);
|
||||
|
||||
var reported = xmlhttp.responseXML.getElementsByTagName('reported');
|
||||
if (reported.length != 1) {
|
||||
ps.alert(
|
||||
null,
|
||||
Zotero.getString('general.error'),
|
||||
Zotero.getString('general.serverError')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
var reportID = reported[0].getAttribute('reportID');
|
||||
ps.alert(
|
||||
null,
|
||||
Zotero.getString('zotero.preferences.advanced.debug.title'),
|
||||
Zotero.getString('zotero.preferences.advanced.debug.sent', reportID)
|
||||
);
|
||||
|
||||
return true;
|
||||
}),
|
||||
|
||||
|
||||
clear: function () {
|
||||
Zotero.Debug.clear();
|
||||
this.updateLines();
|
||||
},
|
||||
|
||||
|
||||
updateLines: function () {
|
||||
var enabled = Zotero.Debug.storing;
|
||||
var lines = Zotero.Debug.count();
|
||||
document.getElementById('debug-output-lines').value = lines;
|
||||
var empty = lines == 0;
|
||||
document.getElementById('debug-output-view').disabled = !enabled && empty;
|
||||
document.getElementById('debug-output-clear').disabled = empty;
|
||||
document.getElementById('debug-output-submit').disabled = empty;
|
||||
},
|
||||
|
||||
|
||||
_initTimer: function () {
|
||||
this._timer = Components.classes["@mozilla.org/timer;1"].
|
||||
createInstance(Components.interfaces.nsITimer);
|
||||
this._timer.initWithCallback({
|
||||
notify: function() {
|
||||
Zotero_Preferences.Debug_Output.updateLines();
|
||||
}
|
||||
}, 10000, Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
|
||||
},
|
||||
|
||||
|
||||
_updateButton: function () {
|
||||
var storing = Zotero.Debug.storing
|
||||
|
||||
var button = document.getElementById('debug-output-enable');
|
||||
if (storing) {
|
||||
button.label = Zotero.getString('general.disable');
|
||||
}
|
||||
else {
|
||||
button.label = Zotero.getString('general.enable');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
onUnload: function () {
|
||||
if (this._timer) {
|
||||
this._timer.cancel();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Zotero_Preferences.Keys = {
|
||||
init: function () {
|
||||
var rows = document.getElementById('zotero-prefpane-advanced-keys-tab').getElementsByTagName('row');
|
||||
|
|
|
@ -37,12 +37,16 @@
|
|||
onpaneload="Zotero_Preferences.Advanced.init()"
|
||||
helpTopic="advanced">
|
||||
<preferences>
|
||||
<preference id="pref-automaticScraperUpdates" name="extensions.zotero.automaticScraperUpdates" type="bool"/>
|
||||
<preference id="pref-reportTranslationFailure" name="extensions.zotero.reportTranslationFailure" type="bool"/>
|
||||
|
||||
<preference id="pref-baseAttachmentPath" name="extensions.zotero.baseAttachmentPath" type="string"/>
|
||||
<preference id="pref-useDataDir" name="extensions.zotero.useDataDir" type="bool"/>
|
||||
<preference id="pref-dataDir" name="extensions.zotero.dataDir" type="string"/>
|
||||
<preference id="pref-debug-output-enableAfterRestart" name="extensions.zotero.debug.store" type="bool"/>
|
||||
<preference id="pref-openURL-resolver" name="extensions.zotero.openURL.resolver" type="string"/>
|
||||
<preference id="pref-openURL-version" name="extensions.zotero.openURL.version" type="string"/>
|
||||
|
||||
<preference id="pref-keys-openZotero" name="extensions.zotero.keys.openZotero" type="string"/>
|
||||
<preference id="pref-keys-saveToZotero" name="extensions.zotero.keys.saveToZotero" type="string"/>
|
||||
<preference id="pref-keys-library" name="extensions.zotero.keys.library" type="string"/>
|
||||
|
@ -71,26 +75,23 @@
|
|||
|
||||
<tabpanels id="zotero-prefpane-advanced-tabpanels">
|
||||
<tabpanel id="zotero-prefpane-advanced-general-tab" orient="vertical">
|
||||
<groupbox>
|
||||
<caption label="&zotero.preferences.debugOutputLogging;"/>
|
||||
|
||||
<!-- This doesn't wrap without an explicit width -->
|
||||
<vbox>
|
||||
<description width="45em">&zotero.preferences.debugOutputLogging.message;</description>
|
||||
</vbox>
|
||||
<groupbox id="zotero-prefpane-advanced-miscellaneous">
|
||||
<caption label="&zotero.preferences.miscellaneous;"/>
|
||||
|
||||
<hbox align="center">
|
||||
<button id="debug-output-enable" oncommand="Zotero_Preferences.Debug_Output.toggleStore()"/>
|
||||
<label id="debug-output-lines" style="margin-right: 0"/>
|
||||
<label value="&zotero.preferences.debugOutputLogging.linesLogged;"/>
|
||||
<checkbox preference="pref-debug-output-enableAfterRestart" label="&zotero.preferences.debugOutputLogging.enableAfterRestart;" style="margin-left: 1.5em"/>
|
||||
<checkbox label="&zotero.preferences.autoUpdate;" preference="pref-automaticScraperUpdates"/>
|
||||
<button id="updateButton" style="margin-top:0" label="&zotero.preferences.updateNow;"
|
||||
oncommand="Zotero_Preferences.Advanced.updateTranslators()"/>
|
||||
</hbox>
|
||||
|
||||
<checkbox label="&zotero.preferences.reportTranslationFailure;" preference="pref-reportTranslationFailure"/>
|
||||
|
||||
<hbox align="center">
|
||||
<button id="debug-output-view" label="&zotero.preferences.debugOutputLogging.viewOutput;" oncommand="Zotero_Preferences.Debug_Output.view()"/>
|
||||
<button id="debug-output-clear" label="&zotero.preferences.debugOutputLogging.clearOutput;" oncommand="Zotero_Preferences.Debug_Output.clear()"/>
|
||||
<button id="debug-output-submit" label="&zotero.preferences.debugOutputLogging.submitToServer;" oncommand="Zotero_Preferences.Debug_Output.submit()"/>
|
||||
<progressmeter id="debug-output-submit-progress" mode="undetermined" hidden="true"/>
|
||||
<label value="&zotero.bibliography.locale.label;"/>
|
||||
<menulist id="locale-menu"
|
||||
oncommand="Zotero_Preferences.Advanced.onLocaleChange()">
|
||||
<menupopup/>
|
||||
</menulist>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
|
@ -131,18 +132,17 @@
|
|||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<groupbox id="zotero-prefpane-advanced-miscellaneous">
|
||||
<caption label="&zotero.preferences.miscellaneous;"/>
|
||||
<groupbox id="zotero-prefpane-advanced-advancedConfiguration">
|
||||
<caption label="&zotero.preferences.advanced.advancedConfiguration;"/>
|
||||
|
||||
<hbox id="zotero-prefpane-advanced-openbuttons" align="center" style="display: block">
|
||||
<button id="openAboutConfig"
|
||||
label="&zotero.preferences.openAboutConfig;"
|
||||
<button id="config-editor"
|
||||
label="&zotero.preferences.configEditor;"
|
||||
oncommand="Zotero_Preferences.openInViewer('about:config')"/>
|
||||
<button id="openCSLEdit"
|
||||
label="&zotero.preferences.openCSLEdit;"
|
||||
oncommand="Zotero_Preferences.openInViewer('chrome://zotero/content/tools/csledit.xul', true)"/>
|
||||
<button id="openCSLPreview"
|
||||
label="&zotero.preferences.openCSLPreview;"
|
||||
oncommand="Zotero_Preferences.openInViewer('chrome://zotero/content/tools/cslpreview.xul', true)"/>
|
||||
<button id="memory-info"
|
||||
label="Memory Info"
|
||||
oncommand="Zotero_Preferences.openInViewer('about:memory')"
|
||||
hidden="true"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</tabpanel>
|
||||
|
@ -196,6 +196,11 @@
|
|||
</hbox>
|
||||
</radiogroup>
|
||||
|
||||
<vbox id="command-line-data-dir" hidden="true">
|
||||
<description id="command-line-data-dir-path"/>
|
||||
<label value="&zotero.preferences.dataDir.viaCommandLine;"/>
|
||||
</vbox>
|
||||
|
||||
<hbox>
|
||||
<button label="&zotero.preferences.dataDir.reveal;"
|
||||
oncommand="Zotero.DataDirectory.reveal()"/>
|
||||
|
@ -209,10 +214,12 @@
|
|||
|
||||
<hbox style="display: block">
|
||||
<button label="&zotero.preferences.dbMaintenance.integrityCheck;"
|
||||
oncommand="Zotero_Preferences.Advanced.runIntegrityCheck()"/>
|
||||
<button label="&zotero.preferences.dbMaintenance.resetTranslators;"
|
||||
oncommand="Zotero_Preferences.Advanced.runIntegrityCheck(this)"/>
|
||||
<button id="reset-translators-button"
|
||||
label="&zotero.preferences.dbMaintenance.resetTranslators;"
|
||||
oncommand="Zotero_Preferences.Advanced.resetTranslators()"/>
|
||||
<button label="&zotero.preferences.dbMaintenance.resetStyles;"
|
||||
<button id="reset-styles-button"
|
||||
label="&zotero.preferences.dbMaintenance.resetStyles;"
|
||||
oncommand="Zotero_Preferences.Advanced.resetStyles()"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2013 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
-->
|
||||
<!DOCTYPE prefwindow SYSTEM "chrome://zotero/locale/preferences.dtd">
|
||||
|
||||
<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<groupbox id="zotero-prefpane-advanced-miscellaneous">
|
||||
<hbox id="zotero-standalone-buttons">
|
||||
<button id="openAboutMemory"
|
||||
label="&zotero.preferences.openAboutMemory;"
|
||||
oncommand="Zotero_Preferences.openInViewer('about:memory')"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</overlay>
|
|
@ -26,24 +26,50 @@
|
|||
"use strict";
|
||||
|
||||
Zotero_Preferences.Cite = {
|
||||
wordPluginIDs: new Set([
|
||||
'zoteroOpenOfficeIntegration@zotero.org',
|
||||
'zoteroMacWordIntegration@zotero.org',
|
||||
'zoteroWinWordIntegration@zotero.org'
|
||||
]),
|
||||
|
||||
init: Zotero.Promise.coroutine(function* () {
|
||||
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||
this.updateWordProcessorInstructions();
|
||||
yield this.refreshStylesList();
|
||||
}),
|
||||
|
||||
|
||||
/**
|
||||
* Determines if there are word processors, and if not, enables no word processor message
|
||||
* Determines if any word processors are disabled and if so, shows a message in the pref pane
|
||||
*/
|
||||
updateWordProcessorInstructions: function () {
|
||||
if(document.getElementById("wordProcessors").childNodes.length == 2) {
|
||||
document.getElementById("wordProcessors-noWordProcessorPluginsInstalled").hidden = undefined;
|
||||
}
|
||||
if(Zotero.isStandalone) {
|
||||
document.getElementById("wordProcessors-getWordProcessorPlugins").hidden = true;
|
||||
updateWordProcessorInstructions: async function () {
|
||||
var someDisabled = false;
|
||||
await new Promise(function(resolve) {
|
||||
AddonManager.getAllAddons(function(addons) {
|
||||
for (let addon of addons) {
|
||||
if (Zotero_Preferences.Cite.wordPluginIDs.has(addon.id) && addon.userDisabled) {
|
||||
someDisabled = true;
|
||||
}
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
if (someDisabled) {
|
||||
document.getElementById("wordProcessors-somePluginsDisabled").hidden = undefined;
|
||||
}
|
||||
},
|
||||
|
||||
enableWordPlugins: function () {
|
||||
AddonManager.getAllAddons(function(addons) {
|
||||
for (let addon of addons) {
|
||||
if (Zotero_Preferences.Cite.wordPluginIDs.has(addon.id) && addon.userDisabled) {
|
||||
addon.userDisabled = false;
|
||||
}
|
||||
}
|
||||
return Zotero.Utilities.Internal.quit(true);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Refreshes the list of styles in the styles pane
|
||||
|
@ -117,7 +143,11 @@ Zotero_Preferences.Cite = {
|
|||
|
||||
var rv = fp.show();
|
||||
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||
Zotero.Styles.install(fp.file);
|
||||
Zotero.Styles.install({ file: fp.file }, fp.file.path, true)
|
||||
.catch(function (e) {
|
||||
(new Zotero.Exception.Alert("styles.install.unexpectedError",
|
||||
fp.file.path, "styles.install.title", e)).present()
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -23,7 +23,12 @@
|
|||
|
||||
***** END LICENSE BLOCK *****
|
||||
-->
|
||||
<!DOCTYPE prefwindow SYSTEM "chrome://zotero/locale/preferences.dtd">
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % zoteroDTD SYSTEM "chrome://zotero/locale/zotero.dtd">
|
||||
%zoteroDTD;
|
||||
<!ENTITY % preferencesDTD SYSTEM "chrome://zotero/locale/preferences.dtd">
|
||||
%preferencesDTD;
|
||||
]>
|
||||
|
||||
<overlay id="zotero-prefpane-cite-overlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
@ -76,13 +81,30 @@
|
|||
&zotero.preferences.export.citePaperJournalArticleURL.description;
|
||||
</label>
|
||||
</groupbox>
|
||||
|
||||
<groupbox>
|
||||
<caption label="&zotero.general.tools;"/>
|
||||
|
||||
<hbox>
|
||||
<button id="openCSLEdit"
|
||||
label="&zotero.preferences.styleEditor;"
|
||||
oncommand="Zotero_Preferences.openInViewer('chrome://zotero/content/tools/csledit.xul', true)"/>
|
||||
<button id="openCSLPreview"
|
||||
label="&zotero.preferences.stylePreview;"
|
||||
oncommand="Zotero_Preferences.openInViewer('chrome://zotero/content/tools/cslpreview.xul', true)"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</tabpanel>
|
||||
<tabpanel orient="vertical" id="wordProcessors">
|
||||
<label id="wordProcessors-noWordProcessorPluginsInstalled" width="45em" hidden="true">
|
||||
&zotero.preferences.cite.wordProcessors.noWordProcessorPluginsInstalled;
|
||||
</label>
|
||||
<vbox id="wordProcessors-somePluginsDisabled" hidden="true">
|
||||
<label style="font-weight: bold; margin-top: 1em; text-align: center">Some word processor plugins are disabled.</label>
|
||||
<hbox pack="center" style="margin-bottom: 2em">
|
||||
<button id="wordProcessors-enablePlugins"
|
||||
label="Enable Plugins and Restart Zotero"
|
||||
oncommand="Zotero_Preferences.Cite.enableWordPlugins()"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<checkbox label="&zotero.preferences.cite.wordProcessors.useClassicAddCitationDialog;" preference="pref-cite-useClassicAddCitationDialog"/>
|
||||
<label id="wordProcessors-getWordProcessorPlugins" class="zotero-text-link" href="&zotero.preferences.cite.wordProcessors.getPlugins.url;" value="&zotero.preferences.cite.wordProcessors.getPlugins;"/>
|
||||
</tabpanel>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
|
|
|
@ -38,6 +38,17 @@ Zotero_Preferences.Export = {
|
|||
}),
|
||||
|
||||
|
||||
getQuickCopyTranslators: async function () {
|
||||
var translation = new Zotero.Translate("export");
|
||||
var translators = await translation.getTranslators();
|
||||
translators.sort((a, b) => {
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
return collation.compareString(1, a.label, b.label);
|
||||
});
|
||||
return translators;
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* Builds the main Quick Copy drop-down from the current global pref
|
||||
*/
|
||||
|
@ -47,12 +58,7 @@ Zotero_Preferences.Export = {
|
|||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
var menulist = document.getElementById("zotero-quickCopy-menu");
|
||||
yield Zotero.Styles.init();
|
||||
var translation = new Zotero.Translate("export");
|
||||
var translators = yield translation.getTranslators();
|
||||
translators.sort((a, b) => {
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
return collation.compareString(1, a.label, b.label);
|
||||
});
|
||||
var translators = yield this.getQuickCopyTranslators();
|
||||
this.buildQuickCopyFormatDropDown(
|
||||
menulist, format.contentType, format, translators
|
||||
);
|
||||
|
@ -66,9 +72,7 @@ Zotero_Preferences.Export = {
|
|||
this._lastSelectedLocale = Zotero.Prefs.get("export.quickCopy.locale");
|
||||
this.updateQuickCopyUI();
|
||||
|
||||
if (!Zotero.isStandalone) {
|
||||
yield this.refreshQuickCopySiteList();
|
||||
}
|
||||
yield this.refreshQuickCopySiteList();
|
||||
}),
|
||||
|
||||
|
||||
|
@ -96,7 +100,7 @@ Zotero_Preferences.Export = {
|
|||
menulist.appendChild(popup);
|
||||
|
||||
var itemNode = document.createElement("menuitem");
|
||||
itemNode.setAttribute("label", Zotero.getString('zotero.preferences.export.quickCopy.bibStyles'));
|
||||
itemNode.setAttribute("label", Zotero.getString('zotero.preferences.export.quickCopy.citationStyles'));
|
||||
itemNode.setAttribute("disabled", true);
|
||||
popup.appendChild(itemNode);
|
||||
|
||||
|
@ -121,6 +125,7 @@ Zotero_Preferences.Export = {
|
|||
popup.appendChild(itemNode);
|
||||
|
||||
// add export formats to list
|
||||
translators.sort((a, b) => a.label.localeCompare(b.label))
|
||||
translators.forEach(function (translator) {
|
||||
// Skip RDF formats
|
||||
switch (translator.translatorID) {
|
||||
|
@ -144,6 +149,13 @@ Zotero_Preferences.Export = {
|
|||
},
|
||||
|
||||
|
||||
onCopyAsHTMLChange: async function (checked) {
|
||||
var menulist = document.getElementById('zotero-quickCopy-menu');
|
||||
var translators = await this.getQuickCopyTranslators();
|
||||
this.buildQuickCopyFormatDropDown(menulist, checked ? 'html' : '', null, translators);
|
||||
},
|
||||
|
||||
|
||||
updateQuickCopyUI: function () {
|
||||
var format = document.getElementById('zotero-quickCopy-menu').value;
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
|
||||
<separator/>
|
||||
|
||||
<label value="&zotero.preferences.quickCopy.defaultOutputFormat;" control="quickCopy-menu"/>
|
||||
<label value="&zotero.preferences.quickCopy.defaultFormat;" control="quickCopy-menu"/>
|
||||
<menulist id="zotero-quickCopy-menu" label="&zotero.general.loading;"/>
|
||||
|
||||
<hbox align="center">
|
||||
|
@ -61,10 +61,33 @@
|
|||
<separator orient="vertical" width="15px"/>
|
||||
|
||||
<checkbox id="zotero-quickCopy-copyAsHTML" label="&zotero.preferences.quickCopy.copyAsHTML;"
|
||||
oncommand="Zotero_Preferences.Export.buildQuickCopyFormatDropDown(document.getElementById('zotero-quickCopy-menu'), this.checked ? 'html' : '');"/>
|
||||
oncommand="Zotero_Preferences.Export.onCopyAsHTMLChange(this.checked)"/>
|
||||
</hbox>
|
||||
|
||||
<vbox id="zotero-prefpane-export-siteSettings"/>
|
||||
<separator/>
|
||||
|
||||
<label value="&zotero.preferences.quickCopy.siteEditor.setings;" control="quickCopy-siteSettings"/>
|
||||
<tree flex="1" id="quickCopy-siteSettings" hidecolumnpicker="true" rows="6" seltype="single"
|
||||
ondblclick="Zotero_Preferences.Export.showQuickCopySiteEditor(this.currentIndex)"
|
||||
onselect="Zotero_Preferences.Export.enableQuickCopySiteButtons()"
|
||||
onkeypress="if (event.keyCode == event.DOM_VK_DELETE) { Zotero_Preferences.Export.deleteSelectedQuickCopySite(); }">
|
||||
<treecols>
|
||||
<treecol id="quickCopy-urlColumn" label="&zotero.preferences.quickCopy.siteEditor.domainPath;" flex="1"/>
|
||||
<treecol id="quickCopy-formatColumn" label="&zotero.preferences.quickCopy.siteEditor.format;" flex="2"/>
|
||||
<treecol id="quickCopy-localeColumn" label="&zotero.preferences.quickCopy.siteEditor.locale;"/>
|
||||
<treecol id="quickCopy-copyAsHTML" label="HTML"/>
|
||||
</treecols>
|
||||
<treechildren id="quickCopy-siteSettings-rows"/>
|
||||
</tree>
|
||||
<separator class="thin"/>
|
||||
<hbox>
|
||||
<button disabled="true" id="quickCopy-edit" label="&zotero.general.edit;"
|
||||
onclick="Zotero_Preferences.Export.showQuickCopySiteEditor(document.getElementById('quickCopy-siteSettings').currentIndex)"/>
|
||||
<spacer flex="1"/>
|
||||
<button disabled="true" id="quickCopy-delete" label="-" onclick="Zotero_Preferences.Export.deleteSelectedQuickCopySite()"/>
|
||||
<button label="+"
|
||||
onclick="Zotero_Preferences.Export.showQuickCopySiteEditor()"/>
|
||||
</hbox>
|
||||
|
||||
<hbox align="center">
|
||||
<label value="&zotero.preferences.quickCopy.dragLimit;"/>
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2006–2013 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
-->
|
||||
<!DOCTYPE prefwindow [
|
||||
<!ENTITY % preferencesDTD SYSTEM "chrome://zotero/locale/preferences.dtd"> %preferencesDTD;
|
||||
<!ENTITY % zoteroDTD SYSTEM "chrome://zotero/locale/zotero.dtd"> %zoteroDTD;
|
||||
]>
|
||||
|
||||
<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<prefpane id="zotero-prefpane-export">
|
||||
<groupbox id="zotero-prefpane-export-groupbox">
|
||||
<vbox id="zotero-prefpane-export-siteSettings">
|
||||
<separator/>
|
||||
|
||||
<label value="&zotero.preferences.quickCopy.siteEditor.setings;" control="quickCopy-siteSettings"/>
|
||||
<tree flex="1" id="quickCopy-siteSettings" hidecolumnpicker="true" rows="6" seltype="single"
|
||||
ondblclick="Zotero_Preferences.Export.showQuickCopySiteEditor(this.currentIndex)"
|
||||
onselect="Zotero_Preferences.Export.enableQuickCopySiteButtons()"
|
||||
onkeypress="if (event.keyCode == event.DOM_VK_DELETE) { Zotero_Preferences.Export.deleteSelectedQuickCopySite(); }">
|
||||
<treecols>
|
||||
<treecol id="quickCopy-urlColumn" label="&zotero.preferences.quickCopy.siteEditor.domainPath;" flex="1"/>
|
||||
<treecol id="quickCopy-formatColumn" label="&zotero.preferences.quickCopy.siteEditor.outputFormat;" flex="2"/>
|
||||
<treecol id="quickCopy-localeColumn" label="&zotero.preferences.quickCopy.siteEditor.locale;"/>
|
||||
<treecol id="quickCopy-copyAsHTML" label="HTML"/>
|
||||
</treecols>
|
||||
<treechildren id="quickCopy-siteSettings-rows"/>
|
||||
</tree>
|
||||
<separator class="thin"/>
|
||||
<hbox>
|
||||
<button disabled="true" id="quickCopy-edit" label="&zotero.general.edit;"
|
||||
onclick="Zotero_Preferences.Export.showQuickCopySiteEditor(document.getElementById('quickCopy-siteSettings').currentIndex)"/>
|
||||
<spacer flex="1"/>
|
||||
<button disabled="true" id="quickCopy-delete" label="-" onclick="Zotero_Preferences.Export.deleteSelectedQuickCopySite()"/>
|
||||
<button label="+"
|
||||
onclick="Zotero_Preferences.Export.showQuickCopySiteEditor()"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
</prefpane>
|
||||
</overlay>
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
Zotero_Preferences.General = {
|
||||
init: function () {
|
||||
// JS-based strings
|
||||
|
@ -36,27 +39,89 @@ Zotero_Preferences.General = {
|
|||
}
|
||||
|
||||
document.getElementById('noteFontSize').value = Zotero.Prefs.get('note.fontSize');
|
||||
|
||||
this._updateFileHandlerUI();
|
||||
},
|
||||
|
||||
//
|
||||
// File handlers
|
||||
//
|
||||
chooseFileHandler: function (type) {
|
||||
var pref = this._getFileHandlerPref(type);
|
||||
var currentPath = Zotero.Prefs.get(pref);
|
||||
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
if (currentPath) {
|
||||
fp.displayDirectory = Zotero.File.pathToFile(OS.Path.dirname(currentPath));
|
||||
}
|
||||
fp.init(
|
||||
window,
|
||||
Zotero.getString('zotero.preferences.chooseApplication'),
|
||||
nsIFilePicker.modeOpen
|
||||
);
|
||||
fp.appendFilters(nsIFilePicker.filterApps);
|
||||
if (fp.show() != nsIFilePicker.returnOK) {
|
||||
this._updateFileHandlerUI();
|
||||
return false;
|
||||
}
|
||||
var newPath = OS.Path.normalize(fp.file.path);
|
||||
this.setFileHandler(type, newPath);
|
||||
},
|
||||
|
||||
updateTranslators: Zotero.Promise.coroutine(function* () {
|
||||
var updated = yield Zotero.Schema.updateFromRepository(true);
|
||||
var button = document.getElementById('updateButton');
|
||||
if (button) {
|
||||
if (updated===-1) {
|
||||
var label = Zotero.getString('zotero.preferences.update.upToDate');
|
||||
setFileHandler: function (type, handler) {
|
||||
var pref = this._getFileHandlerPref(type);
|
||||
if (handler) {
|
||||
Zotero.Prefs.set(pref, handler);
|
||||
}
|
||||
else {
|
||||
Zotero.Prefs.clear(pref);
|
||||
}
|
||||
this._updateFileHandlerUI();
|
||||
},
|
||||
|
||||
_updateFileHandlerUI: function () {
|
||||
var handler = Zotero.Prefs.get('fileHandler.pdf');
|
||||
var menulist = document.getElementById('fileHandler-pdf');
|
||||
var customMenuItem = document.getElementById('fileHandler-custom');
|
||||
if (handler) {
|
||||
let icon;
|
||||
try {
|
||||
let fph = Services.io.getProtocolHandler("file")
|
||||
.QueryInterface(Components.interfaces.nsIFileProtocolHandler);
|
||||
let urlspec = fph.getURLSpecFromFile(Zotero.File.pathToFile(handler));
|
||||
icon = "moz-icon://" + urlspec + "?size=16";
|
||||
}
|
||||
else if (updated) {
|
||||
var label = Zotero.getString('zotero.preferences.update.updated');
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
|
||||
let handlerFilename = OS.Path.basename(handler);
|
||||
if (Zotero.isMac) {
|
||||
handlerFilename = handlerFilename.replace(/\.app$/, '');
|
||||
}
|
||||
customMenuItem.setAttribute('label', handlerFilename);
|
||||
if (icon) {
|
||||
customMenuItem.className = 'menuitem-iconic';
|
||||
customMenuItem.setAttribute('image', icon);
|
||||
}
|
||||
else {
|
||||
var label = Zotero.getString('zotero.preferences.update.error');
|
||||
}
|
||||
button.setAttribute('label', label);
|
||||
|
||||
if (updated && Zotero_Preferences.Cite) {
|
||||
yield Zotero_Preferences.Cite.refreshStylesList();
|
||||
customMenuItem.className = '';
|
||||
}
|
||||
customMenuItem.hidden = false;
|
||||
menulist.selectedIndex = 0;
|
||||
}
|
||||
})
|
||||
else {
|
||||
customMenuItem.hidden = true;
|
||||
menulist.selectedIndex = 1;
|
||||
}
|
||||
},
|
||||
|
||||
_getFileHandlerPref: function (type) {
|
||||
if (type != 'pdf') {
|
||||
throw new Error(`Unknown file type ${type}`);
|
||||
}
|
||||
return 'fileHandler.pdf';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,10 +33,12 @@
|
|||
<preferences id="zotero-prefpane-general-preferences">
|
||||
<preference id="pref-fontSize" name="extensions.zotero.fontSize" type="string"/>
|
||||
<preference id="pref-layout" name="extensions.zotero.layout" type="string"/>
|
||||
<preference id="pref-automaticScraperUpdates" name="extensions.zotero.automaticScraperUpdates" type="bool"/>
|
||||
<preference id="pref-reportTranslationFailure" name="extensions.zotero.reportTranslationFailure" type="bool"/>
|
||||
|
||||
<preference id="pref-automaticSnapshots" name="extensions.zotero.automaticSnapshots" type="bool"/>
|
||||
<preference id="pref-downloadAssociatedFiles" name="extensions.zotero.downloadAssociatedFiles" type="bool"/>
|
||||
<preference id="pref-autoRecognizeFiles" name="extensions.zotero.autoRecognizeFiles" type="bool"/>
|
||||
<preference id="pref-autoRenameFiles" name="extensions.zotero.autoRenameFiles" type="bool"/>
|
||||
|
||||
<preference id="pref-automaticTags" name="extensions.zotero.automaticTags" type="bool"/>
|
||||
<preference id="pref-trashAutoEmptyDays" name="extensions.zotero.trashAutoEmptyDays" type="int"/>
|
||||
|
||||
|
@ -108,20 +110,33 @@
|
|||
</grid>
|
||||
</groupbox>
|
||||
|
||||
<groupbox id="zotero-prefpane-miscellaneous-groupbox">
|
||||
<caption label="&zotero.preferences.miscellaneous;"/>
|
||||
<groupbox id="zotero-prefpane-file-handling-groupbox">
|
||||
<caption label="&zotero.preferences.fileHandling;"/>
|
||||
|
||||
<hbox align="center">
|
||||
<checkbox label="&zotero.preferences.autoUpdate;" preference="pref-automaticScraperUpdates"/>
|
||||
<button id="updateButton" style="margin-top:0" label="&zotero.preferences.updateNow;"
|
||||
oncommand="Zotero_Preferences.General.updateTranslators()"/>
|
||||
</hbox>
|
||||
|
||||
<checkbox label="&zotero.preferences.reportTranslationFailure;" preference="pref-reportTranslationFailure"/>
|
||||
<checkbox id="automaticSnapshots-checkbox"
|
||||
label="&zotero.preferences.automaticSnapshots;"
|
||||
preference="pref-automaticSnapshots"/>
|
||||
<checkbox label="&zotero.preferences.downloadAssociatedFiles;" preference="pref-downloadAssociatedFiles"/>
|
||||
<checkbox label="&zotero.preferences.autoRecognizeFiles;" preference="pref-autoRecognizeFiles"/>
|
||||
<checkbox label="&zotero.preferences.autoRenameFiles;" preference="pref-autoRenameFiles"/>
|
||||
|
||||
<hbox align="center">
|
||||
<label value="&zotero.preferences.fileHandler.openPDFsUsing;" control="file-handler-pdf"/>
|
||||
<menulist id="fileHandler-pdf" class="fileHandler-menu">
|
||||
<menupopup>
|
||||
<menuitem id="fileHandler-custom"/>
|
||||
<menuitem label="&zotero.preferences.fileHandler.systemDefault;"
|
||||
oncommand="Zotero_Preferences.General.setFileHandler('pdf', false)"/>
|
||||
<menuitem label="&zotero.preferences.custom;"
|
||||
oncommand="Zotero_Preferences.General.chooseFileHandler('pdf')"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<groupbox id="zotero-prefpane-miscellaneous-groupbox">
|
||||
<caption label="&zotero.preferences.miscellaneous;"/>
|
||||
|
||||
<checkbox label="&zotero.preferences.automaticTags;" preference="pref-automaticTags"/>
|
||||
<hbox align="center">
|
||||
<label value="&zotero.preferences.trashAutoEmptyDaysPre;"/>
|
||||
|
|
|
@ -33,264 +33,10 @@ Zotero_Preferences.Search = {
|
|||
document.getElementById('fulltext-clearIndex').setAttribute('label',
|
||||
Zotero.getString('zotero.preferences.search.clearIndex')
|
||||
+ Zotero.getString('punctuation.ellipsis'));
|
||||
this.updatePDFToolsStatus();
|
||||
|
||||
this.updateIndexStats();
|
||||
|
||||
// Quick hack to support install prompt from PDF recognize option
|
||||
var io = window.arguments[0];
|
||||
if (io.action && io.action == 'pdftools-install') {
|
||||
this.checkPDFToolsDownloadVersion();
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Update window according to installation status for PDF tools
|
||||
* (e.g. status line, install/update button, etc.)
|
||||
*/
|
||||
updatePDFToolsStatus: function () {
|
||||
var converterIsRegistered = Zotero.Fulltext.pdfConverterIsRegistered();
|
||||
var infoIsRegistered = Zotero.Fulltext.pdfInfoIsRegistered();
|
||||
|
||||
var converterStatusLabel = document.getElementById('pdfconverter-status');
|
||||
var infoStatusLabel = document.getElementById('pdfinfo-status');
|
||||
var requiredLabel = document.getElementById('pdftools-required');
|
||||
var updateButton = document.getElementById('pdftools-update-button');
|
||||
var documentationLink = document.getElementById('pdftools-documentation-link');
|
||||
var settingsBox = document.getElementById('pdftools-settings');
|
||||
|
||||
// If we haven't already generated the required and documentation messages
|
||||
if (!converterIsRegistered && !requiredLabel.hasChildNodes()) {
|
||||
|
||||
// Xpdf link
|
||||
var str = Zotero.getString('zotero.preferences.search.pdf.toolsRequired',
|
||||
[Zotero.Fulltext.pdfConverterName, Zotero.Fulltext.pdfInfoName,
|
||||
'<a href="' + Zotero.Fulltext.pdfToolsURL + '">'
|
||||
+ Zotero.Fulltext.pdfToolsName + '</a>']);
|
||||
var parts = Zotero.Utilities.parseMarkup(str);
|
||||
for (var i=0; i<parts.length; i++) {
|
||||
var part = parts[i];
|
||||
if (part.type == 'text') {
|
||||
var elem = document.createTextNode(part.text);
|
||||
}
|
||||
else if (part.type == 'link') {
|
||||
var elem = document.createElement('label');
|
||||
elem.setAttribute('value', part.text);
|
||||
elem.setAttribute('class', 'zotero-text-link');
|
||||
for (var key in part.attributes) {
|
||||
elem.setAttribute(key, part.attributes[key]);
|
||||
|
||||
if (key == 'href') {
|
||||
elem.setAttribute('tooltiptext', part.attributes[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
requiredLabel.appendChild(elem);
|
||||
}
|
||||
|
||||
requiredLabel.appendChild(document.createTextNode(' '
|
||||
+ Zotero.getString('zotero.preferences.search.pdf.automaticInstall')));
|
||||
|
||||
// Documentation link
|
||||
var link = '<a href="http://www.zotero.org/documentation/pdf_fulltext_indexing">'
|
||||
+ Zotero.getString('zotero.preferences.search.pdf.documentationLink')
|
||||
+ '</a>';
|
||||
var str = Zotero.getString('zotero.preferences.search.pdf.advancedUsers', link);
|
||||
var parts = Zotero.Utilities.parseMarkup(str);
|
||||
|
||||
for (var i=0; i<parts.length; i++) {
|
||||
var part = parts[i];
|
||||
if (part.type == 'text') {
|
||||
var elem = document.createTextNode(part.text);
|
||||
}
|
||||
else if (part.type == 'link') {
|
||||
var elem = document.createElement('label');
|
||||
elem.setAttribute('value', part.text);
|
||||
elem.setAttribute('class', 'zotero-text-link');
|
||||
for (var key in part.attributes) {
|
||||
elem.setAttribute(key, part.attributes[key]);
|
||||
|
||||
if (key == 'href') {
|
||||
elem.setAttribute('tooltiptext', part.attributes[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
documentationLink.appendChild(elem);
|
||||
}
|
||||
}
|
||||
|
||||
// converter status line
|
||||
var prefix = 'zotero.preferences.search.pdf.tool';
|
||||
if (converterIsRegistered) {
|
||||
var version = Zotero.Fulltext.pdfConverterVersion;
|
||||
str = Zotero.getString(prefix + 'Registered',
|
||||
Zotero.getString('zotero.preferences.search.pdf.toolVersionPlatform',
|
||||
[Zotero.Fulltext.pdfConverterName, version]));
|
||||
}
|
||||
else {
|
||||
str = Zotero.getString(prefix + 'NotRegistered',
|
||||
[Zotero.Fulltext.pdfConverterFileName]);
|
||||
}
|
||||
converterStatusLabel.setAttribute('value', str);
|
||||
|
||||
// pdfinfo status line
|
||||
if (infoIsRegistered) {
|
||||
var version = Zotero.Fulltext.pdfInfoVersion;
|
||||
str = Zotero.getString(prefix + 'Registered',
|
||||
Zotero.getString('zotero.preferences.search.pdf.toolVersionPlatform',
|
||||
[Zotero.Fulltext.pdfInfoName, version]));
|
||||
}
|
||||
else {
|
||||
str = Zotero.getString(prefix + 'NotRegistered',
|
||||
[Zotero.Fulltext.pdfInfoFileName]);
|
||||
}
|
||||
infoStatusLabel.setAttribute('value', str);
|
||||
|
||||
str = converterIsRegistered ?
|
||||
Zotero.getString('general.checkForUpdate') :
|
||||
Zotero.getString('zotero.preferences.search.pdf.checkForInstaller');
|
||||
updateButton.setAttribute('label', str);
|
||||
|
||||
requiredLabel.setAttribute('hidden', converterIsRegistered);
|
||||
documentationLink.setAttribute('hidden', converterIsRegistered);
|
||||
settingsBox.setAttribute('hidden', !converterIsRegistered);
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* Check available versions of PDF tools from server and prompt for installation
|
||||
* if a newer version is available
|
||||
*/
|
||||
checkPDFToolsDownloadVersion: Zotero.Promise.coroutine(function* () {
|
||||
try {
|
||||
var latestVersion = yield Zotero.Fulltext.getLatestPDFToolsVersion();
|
||||
|
||||
var converterIsRegistered = Zotero.Fulltext.pdfConverterIsRegistered();
|
||||
var infoIsRegistered = Zotero.Fulltext.pdfInfoIsRegistered();
|
||||
var bothRegistered = converterIsRegistered && infoIsRegistered;
|
||||
|
||||
// On Windows, install if not installed or anything other than 3.02a
|
||||
if (Zotero.isWin) {
|
||||
var converterVersionAvailable = !converterIsRegistered
|
||||
|| Zotero.Fulltext.pdfConverterVersion != '3.02a';
|
||||
var infoVersionAvailable = !infoIsRegistered
|
||||
|| Zotero.Fulltext.pdfInfoVersion != '3.02a';
|
||||
var bothAvailable = converterVersionAvailable && infoVersionAvailable;
|
||||
}
|
||||
// Install if not installed, version unknown, outdated, or
|
||||
// Xpdf 3.02/3.04 (to upgrade to Poppler),
|
||||
else {
|
||||
var converterVersionAvailable = (!converterIsRegistered ||
|
||||
Zotero.Fulltext.pdfConverterVersion == 'UNKNOWN'
|
||||
|| latestVersion > Zotero.Fulltext.pdfConverterVersion
|
||||
|| (!latestVersion.startsWith('3.02')
|
||||
&& Zotero.Fulltext.pdfConverterVersion.startsWith('3.02'))
|
||||
|| (!latestVersion.startsWith('3.02') && latestVersion != '3.04'
|
||||
&& Zotero.Fulltext.pdfConverterVersion == '3.04'));
|
||||
var infoVersionAvailable = (!infoIsRegistered ||
|
||||
Zotero.Fulltext.pdfInfoVersion == 'UNKNOWN'
|
||||
|| latestVersion > Zotero.Fulltext.pdfInfoVersion
|
||||
|| (!latestVersion.startsWith('3.02')
|
||||
&& Zotero.Fulltext.pdfInfoVersion.startsWith('3.02'))
|
||||
|| (!latestVersion.startsWith('3.02') && latestVersion != '3.04'
|
||||
&& Zotero.Fulltext.pdfInfoVersion == '3.04'));
|
||||
var bothAvailable = converterVersionAvailable && infoVersionAvailable;
|
||||
}
|
||||
|
||||
// Up to date -- disable update button
|
||||
if (!converterVersionAvailable && !infoVersionAvailable) {
|
||||
var button = document.getElementById('pdftools-update-button');
|
||||
button.setAttribute('label', Zotero.getString('zotero.preferences.update.upToDate'));
|
||||
button.setAttribute('disabled', true);
|
||||
return;
|
||||
}
|
||||
|
||||
// New version available -- display update prompt
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
|
||||
createInstance(Components.interfaces.nsIPromptService);
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
|
||||
|
||||
var msg = Zotero.getString('zotero.preferences.search.pdf.available'
|
||||
+ ((converterIsRegistered || infoIsRegistered) ? 'Updates' : 'Downloads'),
|
||||
[Zotero.platform, 'zotero.org']) + '\n\n';
|
||||
|
||||
if (converterVersionAvailable) {
|
||||
let tvp = Zotero.getString('zotero.preferences.search.pdf.toolVersionPlatform',
|
||||
[Zotero.Fulltext.pdfConverterName, latestVersion]);
|
||||
msg += '- ' + tvp + '\n';
|
||||
}
|
||||
if (infoVersionAvailable) {
|
||||
let tvp = Zotero.getString('zotero.preferences.search.pdf.toolVersionPlatform',
|
||||
[Zotero.Fulltext.pdfInfoName, latestVersion]);
|
||||
msg += '- ' + tvp + '\n';
|
||||
}
|
||||
msg += '\n';
|
||||
msg += Zotero.getString('zotero.preferences.search.pdf.zoteroCanInstallVersion'
|
||||
+ (bothAvailable ? 's' : ''));
|
||||
|
||||
var index = ps.confirmEx(null,
|
||||
converterIsRegistered ?
|
||||
Zotero.getString('general.updateAvailable') : '',
|
||||
msg,
|
||||
buttonFlags,
|
||||
converterIsRegistered ?
|
||||
Zotero.getString('general.upgrade') :
|
||||
Zotero.getString('general.install'),
|
||||
null, null, null, {});
|
||||
|
||||
if (index != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('pdftools-update-button').disabled = true;
|
||||
var str = Zotero.getString('zotero.preferences.search.pdf.downloading');
|
||||
document.getElementById('pdftools-update-button').setAttribute('label', str);
|
||||
|
||||
if (converterVersionAvailable) {
|
||||
yield Zotero.Fulltext.downloadPDFTool('converter', latestVersion)
|
||||
.catch(function (e) {
|
||||
Zotero.logError(e);
|
||||
throw new Error("Error downloading pdftotext");
|
||||
});
|
||||
}
|
||||
if (infoVersionAvailable) {
|
||||
yield Zotero.Fulltext.downloadPDFTool('info', latestVersion)
|
||||
.catch(function (e) {
|
||||
Zotero.logError(e);
|
||||
throw new Error("Error downloading pdfinfo");
|
||||
});
|
||||
}
|
||||
this.updatePDFToolsStatus();
|
||||
}
|
||||
catch (e) {
|
||||
this.onPDFToolsDownloadError(e);
|
||||
}
|
||||
}),
|
||||
|
||||
|
||||
onPDFToolsDownloadError: function (e) {
|
||||
if (e == 404) {
|
||||
var str = Zotero.getString('zotero.preferences.search.pdf.toolDownloadsNotAvailable',
|
||||
Zotero.Fulltext.pdfToolsName) + ' '
|
||||
+ Zotero.getString('zotero.preferences.search.pdf.viewManualInstructions');
|
||||
}
|
||||
else {
|
||||
Components.utils.reportError(e);
|
||||
var str = Zotero.getString('zotero.preferences.search.pdf.toolsDownloadError', Zotero.Fulltext.pdfToolsName)
|
||||
+ ' ' + Zotero.getString('zotero.preferences.search.pdf.tryAgainOrViewManualInstructions');
|
||||
}
|
||||
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.createInstance(Components.interfaces.nsIPromptService);
|
||||
ps.alert(
|
||||
null,
|
||||
Zotero.getString('pane.item.attachments.PDF.installTools.title'),
|
||||
str
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
updateIndexStats: Zotero.Promise.coroutine(function* () {
|
||||
var stats = yield Zotero.Fulltext.getIndexStats();
|
||||
document.getElementById('fulltext-stats-indexed').
|
||||
|
|
|
@ -49,34 +49,10 @@
|
|||
<textbox size="10" preference="pref-fulltext-textMaxLength"/>
|
||||
<label value="(&zotero.preferences.default; 500000)"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<groupbox id="pdftools-box">
|
||||
<caption label="&zotero.preferences.search.pdfIndexing;"/>
|
||||
|
||||
<label id="pdfconverter-status"/>
|
||||
|
||||
<separator class="thin"/>
|
||||
<label id="pdfinfo-status"/>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<!-- This doesn't wrap without an explicit width -->
|
||||
<label id="pdftools-required" width="45em" hidden="true"/>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<hbox>
|
||||
<button id="pdftools-update-button" flex="1" oncommand="Zotero_Preferences.Search.checkPDFToolsDownloadVersion()"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<!-- This doesn't wrap without an explicit width -->
|
||||
<label id="pdftools-documentation-link" width="45em" hidden="true"/>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<hbox id="pdftools-settings" align="center" hidden="true">
|
||||
|
||||
<hbox align="center">
|
||||
<label value="&zotero.preferences.fulltext.pdfMaxPages;"/>
|
||||
<textbox size="5" preference="pref-fulltext-pdfmaxpages"/>
|
||||
<label value="(&zotero.preferences.default; 100)"/>
|
||||
|
|
|
@ -26,10 +26,12 @@
|
|||
"use strict";
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
Components.utils.import("resource://zotero/config.js");
|
||||
|
||||
Zotero_Preferences.Sync = {
|
||||
init: Zotero.Promise.coroutine(function* () {
|
||||
this.updateStorageSettingsUI();
|
||||
this.updateStorageSettingsGroupsUI();
|
||||
|
||||
var username = Zotero.Users.getCurrentUsername() || Zotero.Prefs.get('sync.server.username') || " ";
|
||||
var apiKey = yield Zotero.Sync.Data.Local.getAPIKey();
|
||||
|
@ -47,13 +49,10 @@ Zotero_Preferences.Sync = {
|
|||
{timeout: 5000}
|
||||
);
|
||||
this.displayFields(keyInfo.username);
|
||||
Zotero.Users.setCurrentUsername(keyInfo.username);
|
||||
}
|
||||
catch (e) {
|
||||
// API key wrong/invalid
|
||||
if (!(e instanceof Zotero.HTTP.UnexpectedStatusException)
|
||||
&& !(e instanceof Zotero.HTTP.TimeoutException)
|
||||
&& !(e instanceof Zotero.HTTP.BrowserOfflineException)) {
|
||||
if (e instanceof Zotero.Error && e.error == Zotero.Error.ERROR_API_KEY_INVALID) {
|
||||
Zotero.alert(
|
||||
window,
|
||||
Zotero.getString('general.error'),
|
||||
|
@ -66,8 +65,10 @@ Zotero_Preferences.Sync = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.initResetPane();
|
||||
}),
|
||||
|
||||
|
||||
displayFields: function (username) {
|
||||
document.getElementById('sync-unauthorized').hidden = !!username;
|
||||
document.getElementById('sync-authorized').hidden = !username;
|
||||
|
@ -84,7 +85,7 @@ Zotero_Preferences.Sync = {
|
|||
},
|
||||
|
||||
|
||||
credentialsKeyPress: function (event) {
|
||||
credentialsChange: function (event) {
|
||||
var username = document.getElementById('sync-username-textbox');
|
||||
var password = document.getElementById('sync-password');
|
||||
|
||||
|
@ -98,9 +99,12 @@ Zotero_Preferences.Sync = {
|
|||
syncAuthButton.setAttribute('disabled', 'false');
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
credentialsKeyPress: function (event) {
|
||||
if (event.keyCode == 13) {
|
||||
Zotero_Preferences.Sync.linkAccount(event);
|
||||
this.linkAccount(event);
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
@ -225,7 +229,8 @@ Zotero_Preferences.Sync = {
|
|||
var row = {}, col = {}, child = {};
|
||||
tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, child);
|
||||
|
||||
if (col.value.element.id == 'libraries-to-sync-checked') {
|
||||
// Below the list or on checkmark column
|
||||
if (!col.value || col.value.element.id == 'libraries-to-sync-checked') {
|
||||
return;
|
||||
}
|
||||
// if dblclicked anywhere but the checkbox update pref
|
||||
|
@ -238,7 +243,8 @@ Zotero_Preferences.Sync = {
|
|||
var row = {}, col = {}, child = {};
|
||||
tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, child);
|
||||
|
||||
if (col.value.element.id != 'libraries-to-sync-checked') {
|
||||
// Below the list or not on checkmark column
|
||||
if (!col.value || col.value.element.id != 'libraries-to-sync-checked') {
|
||||
return;
|
||||
}
|
||||
// if clicked on checkbox update pref
|
||||
|
@ -333,6 +339,9 @@ Zotero_Preferences.Sync = {
|
|||
addRow(Zotero.getString("pane.collections.libraryAndFeeds"), "L" + Zotero.Libraries.userLibraryID,
|
||||
librariesToSkip.indexOf("L" + Zotero.Libraries.userLibraryID) == -1);
|
||||
|
||||
// Sort groups
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
groups.sort((a, b) => collation.compareString(1, a.data.name, b.data.name));
|
||||
// Add group rows
|
||||
for (let group of groups) {
|
||||
addRow(group.data.name, "G" + group.id, librariesToSkip.indexOf("G" + group.id) == -1);
|
||||
|
@ -360,30 +369,19 @@ Zotero_Preferences.Sync = {
|
|||
sep.hidden = true;
|
||||
}
|
||||
|
||||
var menulists = document.querySelectorAll('#storage-settings menulist.storage-mode');
|
||||
for (let menulist of menulists) {
|
||||
menulist.disabled = !enabled;
|
||||
}
|
||||
|
||||
document.getElementById('storage-user-download-mode').disabled = !enabled;
|
||||
this.updateStorageTerms();
|
||||
|
||||
window.sizeToContent();
|
||||
}),
|
||||
|
||||
|
||||
updateStorageSettingsGroups: function (enabled) {
|
||||
var storageSettings = document.getElementById('storage-settings');
|
||||
var menulists = storageSettings.getElementsByTagName('menulist');
|
||||
for (let menulist of menulists) {
|
||||
if (menulist.className == 'storage-groups') {
|
||||
menulist.disabled = !enabled;
|
||||
}
|
||||
}
|
||||
|
||||
var self = this;
|
||||
setTimeout(function () {
|
||||
self.updateStorageTerms();
|
||||
}, 1)
|
||||
updateStorageSettingsGroupsUI: function () {
|
||||
setTimeout(() => {
|
||||
var enabled = document.getElementById('pref-storage-groups-enabled').value;
|
||||
document.getElementById('storage-groups-download-mode').disabled = !enabled;
|
||||
this.updateStorageTerms();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
@ -392,7 +390,7 @@ Zotero_Preferences.Sync = {
|
|||
|
||||
var libraryEnabled = document.getElementById('pref-storage-enabled').value;
|
||||
var storageProtocol = document.getElementById('pref-storage-protocol').value;
|
||||
var groupsEnabled = document.getElementById('pref-group-storage-enabled').value;
|
||||
var groupsEnabled = document.getElementById('pref-storage-groups-enabled').value;
|
||||
|
||||
terms.hidden = !((libraryEnabled && storageProtocol == 'zotero') || groupsEnabled);
|
||||
},
|
||||
|
@ -400,7 +398,6 @@ Zotero_Preferences.Sync = {
|
|||
|
||||
onStorageSettingsKeyPress: Zotero.Promise.coroutine(function* (event) {
|
||||
if (event.keyCode == 13) {
|
||||
yield this.onStorageSettingsChange();
|
||||
yield this.verifyStorageServer();
|
||||
}
|
||||
}),
|
||||
|
@ -420,7 +417,7 @@ Zotero_Preferences.Sync = {
|
|||
var newEnabled = document.getElementById('pref-storage-enabled').value;
|
||||
|
||||
if (oldProtocol != newProtocol) {
|
||||
yield Zotero.Sync.Storage.Local.resetAllSyncStates();
|
||||
yield Zotero.Sync.Storage.Local.resetAllSyncStates(Zotero.Libraries.userLibraryID);
|
||||
}
|
||||
|
||||
if (oldProtocol == 'webdav') {
|
||||
|
@ -482,6 +479,11 @@ Zotero_Preferences.Sync = {
|
|||
|
||||
|
||||
verifyStorageServer: Zotero.Promise.coroutine(function* () {
|
||||
// onchange weirdly isn't triggered when clicking straight from a field to the button,
|
||||
// so we have to trigger this here (and we don't trigger it for Enter in
|
||||
// onStorageSettingsKeyPress()).
|
||||
yield this.onStorageSettingsChange();
|
||||
|
||||
Zotero.debug("Verifying storage");
|
||||
|
||||
var verifyButton = document.getElementById("storage-verify");
|
||||
|
@ -565,38 +567,87 @@ Zotero_Preferences.Sync = {
|
|||
},
|
||||
|
||||
|
||||
handleSyncResetSelect: function (obj) {
|
||||
var index = obj.selectedIndex;
|
||||
var rows = obj.getElementsByTagName('row');
|
||||
//
|
||||
// Reset pane
|
||||
//
|
||||
initResetPane: function () {
|
||||
//
|
||||
// Build library selector
|
||||
//
|
||||
var libraryMenu = document.getElementById('sync-reset-library-menu');
|
||||
// Some options need to be disabled when certain libraries are selected
|
||||
libraryMenu.onchange = (event) => {
|
||||
this.onResetLibraryChange(parseInt(event.target.value));
|
||||
}
|
||||
this.onResetLibraryChange(Zotero.Libraries.userLibraryID);
|
||||
var libraries = Zotero.Libraries.getAll()
|
||||
.filter(x => x.libraryType == 'user' || x.libraryType == 'group');
|
||||
Zotero.Utilities.Internal.buildLibraryMenuHTML(libraryMenu, libraries);
|
||||
// Disable read-only libraries, at least until there are options that make sense for those
|
||||
Array.from(libraryMenu.querySelectorAll('option'))
|
||||
.filter(x => x.getAttribute('data-editable') == 'false')
|
||||
.forEach(x => x.disabled = true);
|
||||
|
||||
for (var i=0; i<rows.length; i++) {
|
||||
if (i == index) {
|
||||
rows[i].setAttribute('selected', 'true');
|
||||
}
|
||||
else {
|
||||
rows[i].removeAttribute('selected');
|
||||
}
|
||||
var list = document.getElementById('sync-reset-list');
|
||||
for (let li of document.querySelectorAll('#sync-reset-list li')) {
|
||||
li.addEventListener('click', function (event) {
|
||||
// Ignore clicks if disabled
|
||||
if (this.hasAttribute('disabled')) {
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
document.getElementById('sync-reset-button').disabled = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
handleSyncReset: Zotero.Promise.coroutine(function* (action) {
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
onResetLibraryChange: function (libraryID) {
|
||||
var library = Zotero.Libraries.get(libraryID);
|
||||
var section = document.getElementById('reset-file-sync-history');
|
||||
var input = section.querySelector('input');
|
||||
if (library.filesEditable) {
|
||||
section.removeAttribute('disabled');
|
||||
input.disabled = false;
|
||||
}
|
||||
else {
|
||||
section.setAttribute('disabled', '');
|
||||
// If radio we're disabling is already selected, select the first one in the list
|
||||
// instead
|
||||
if (input.checked) {
|
||||
document.querySelector('#sync-reset-list li:first-child input').checked = true;
|
||||
}
|
||||
input.disabled = true;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
reset: async function () {
|
||||
var ps = Services.prompt;
|
||||
|
||||
if (!Zotero.Sync.Runner.enabled) {
|
||||
ps.alert(
|
||||
if (Zotero.Sync.Runner.syncInProgress) {
|
||||
Zotero.alert(
|
||||
null,
|
||||
Zotero.getString('general.error'),
|
||||
Zotero.getString('zotero.preferences.sync.reset.userInfoMissing',
|
||||
document.getElementById('zotero-prefpane-sync')
|
||||
.getElementsByTagName('tab')[0].label)
|
||||
Zotero.getString('sync.error.syncInProgress')
|
||||
+ "\n\n"
|
||||
+ Zotero.getString('general.operationInProgress.waitUntilFinishedAndTryAgain')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var libraryID = parseInt(
|
||||
Array.from(document.querySelectorAll('#sync-reset-library-menu option'))
|
||||
.filter(x => x.selected)[0]
|
||||
.value
|
||||
);
|
||||
var library = Zotero.Libraries.get(libraryID);
|
||||
var action = Array.from(document.querySelectorAll('#sync-reset-list input[name=sync-reset-radiogroup]'))
|
||||
.filter(x => x.checked)[0]
|
||||
.getAttribute('value');
|
||||
|
||||
switch (action) {
|
||||
case 'full-sync':
|
||||
/*case 'full-sync':
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL)
|
||||
+ ps.BUTTON_POS_1_DEFAULT;
|
||||
|
@ -617,7 +668,7 @@ Zotero_Preferences.Sync = {
|
|||
switch (index) {
|
||||
case 0:
|
||||
let libraries = Zotero.Libraries.getAll().filter(library => library.syncable);
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
await Zotero.DB.executeTransaction(function* () {
|
||||
for (let library of libraries) {
|
||||
library.libraryVersion = -1;
|
||||
yield library.save();
|
||||
|
@ -650,13 +701,13 @@ Zotero_Preferences.Sync = {
|
|||
// TODO: better error handling
|
||||
|
||||
// Verify username and password
|
||||
var callback = Zotero.Promise.coroutine(function* () {
|
||||
var callback = async function () {
|
||||
Zotero.Schema.stopRepositoryTimer();
|
||||
Zotero.Sync.Runner.clearSyncTimeout();
|
||||
|
||||
Zotero.DB.skipBackup = true;
|
||||
|
||||
yield Zotero.File.putContentsAsync(
|
||||
await Zotero.File.putContentsAsync(
|
||||
OS.Path.join(Zotero.DataDirectory.dir, 'restore-from-server'),
|
||||
''
|
||||
);
|
||||
|
@ -674,7 +725,7 @@ Zotero_Preferences.Sync = {
|
|||
var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Components.interfaces.nsIAppStartup);
|
||||
appStartup.quit(Components.interfaces.nsIAppStartup.eRestart | Components.interfaces.nsIAppStartup.eAttemptQuit);
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: better way of checking for an active session?
|
||||
if (Zotero.Sync.Server.sessionIDComponent == 'sessionid=') {
|
||||
|
@ -691,52 +742,37 @@ Zotero_Preferences.Sync = {
|
|||
case 1:
|
||||
return;
|
||||
}
|
||||
break;
|
||||
break;*/
|
||||
|
||||
case 'restore-to-server':
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL)
|
||||
+ ps.BUTTON_POS_1_DEFAULT;
|
||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL)
|
||||
+ ps.BUTTON_POS_1_DEFAULT;
|
||||
var index = ps.confirmEx(
|
||||
null,
|
||||
Zotero.getString('general.warning'),
|
||||
Zotero.getString('zotero.preferences.sync.reset.restoreToServer', account),
|
||||
Zotero.getString(
|
||||
'zotero.preferences.sync.reset.restoreToServer',
|
||||
[Zotero.clientName, library.name, ZOTERO_CONFIG.DOMAIN_NAME]
|
||||
),
|
||||
buttonFlags,
|
||||
Zotero.getString('zotero.preferences.sync.reset.replaceServerData'),
|
||||
Zotero.getString('zotero.preferences.sync.reset.restoreToServer.button'),
|
||||
null, null, null, {}
|
||||
);
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
// TODO: better error handling
|
||||
Zotero.Sync.Server.clear(function () {
|
||||
Zotero.Sync.Server.sync(/*{
|
||||
|
||||
// TODO: this doesn't work if the pref window is
|
||||
closed. fix, perhaps by making original callbacks
|
||||
available to the custom callbacks
|
||||
|
||||
onSuccess: function () {
|
||||
Zotero.Sync.Runner.updateIcons();
|
||||
ps.alert(
|
||||
null,
|
||||
"Restore Completed",
|
||||
"Data on the Zotero server has been successfully restored."
|
||||
);
|
||||
},
|
||||
onError: function (msg) {
|
||||
// TODO: combine with error dialog for regular syncs
|
||||
ps.alert(
|
||||
null,
|
||||
"Restore Failed",
|
||||
"An error occurred uploading your data to the server.\n\n"
|
||||
+ "Click the sync error icon in the Zotero toolbar "
|
||||
+ "for further information."
|
||||
);
|
||||
Zotero.Sync.Runner.error(msg);
|
||||
}
|
||||
}*/);
|
||||
});
|
||||
var resetButton = document.getElementById('sync-reset-button');
|
||||
resetButton.disabled = true;
|
||||
try {
|
||||
await Zotero.Sync.Runner.sync({
|
||||
libraries: [libraryID],
|
||||
resetMode: Zotero.Sync.Runner.RESET_MODE_TO_SERVER
|
||||
});
|
||||
}
|
||||
finally {
|
||||
resetButton.disabled = false;
|
||||
}
|
||||
break;
|
||||
|
||||
// Cancel
|
||||
|
@ -747,14 +783,17 @@ Zotero_Preferences.Sync = {
|
|||
break;
|
||||
|
||||
|
||||
case 'reset-storage-history':
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
|
||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL)
|
||||
+ ps.BUTTON_POS_1_DEFAULT;
|
||||
case 'reset-file-sync-history':
|
||||
var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
|
||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL
|
||||
+ ps.BUTTON_POS_1_DEFAULT;
|
||||
var index = ps.confirmEx(
|
||||
null,
|
||||
Zotero.getString('general.warning'),
|
||||
Zotero.getString('zotero.preferences.sync.reset.fileSyncHistory'),
|
||||
Zotero.getString(
|
||||
'zotero.preferences.sync.reset.fileSyncHistory',
|
||||
[Zotero.clientName, library.name]
|
||||
),
|
||||
buttonFlags,
|
||||
Zotero.getString('general.reset'),
|
||||
null, null, null, {}
|
||||
|
@ -762,11 +801,14 @@ Zotero_Preferences.Sync = {
|
|||
|
||||
switch (index) {
|
||||
case 0:
|
||||
yield Zotero.Sync.Storage.Local.resetAllSyncStates();
|
||||
await Zotero.Sync.Storage.Local.resetAllSyncStates(libraryID);
|
||||
ps.alert(
|
||||
null,
|
||||
"File Sync History Cleared",
|
||||
"The file sync history has been cleared."
|
||||
Zotero.getString('general.success'),
|
||||
Zotero.getString(
|
||||
'zotero.preferences.sync.reset.fileSyncHistory.cleared',
|
||||
library.name
|
||||
)
|
||||
);
|
||||
break;
|
||||
|
||||
|
@ -778,7 +820,7 @@ Zotero_Preferences.Sync = {
|
|||
break;
|
||||
|
||||
default:
|
||||
throw ("Invalid action '" + action + "' in handleSyncReset()");
|
||||
throw new Error(`Invalid action '${action}' in handleSyncReset()`);
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
<preference id="pref-storage-username" name="extensions.zotero.sync.storage.username" type="string"/>
|
||||
<preference id="pref-storage-downloadMode-personal" name="extensions.zotero.sync.storage.downloadMode.personal" type="string"/>
|
||||
<preference id="pref-storage-downloadMode-groups" name="extensions.zotero.sync.storage.downloadMode.groups" type="string"/>
|
||||
<preference id="pref-group-storage-enabled" name="extensions.zotero.sync.storage.groups.enabled" type="bool"/>
|
||||
<preference id="pref-storage-groups-enabled" name="extensions.zotero.sync.storage.groups.enabled" type="bool"/>
|
||||
</preferences>
|
||||
|
||||
<tabbox>
|
||||
|
@ -68,12 +68,16 @@
|
|||
<textbox id="sync-username-textbox"
|
||||
preference="pref-sync-username"
|
||||
onblur="Zotero_Preferences.Sync.trimUsername()"
|
||||
onkeypress="Zotero_Preferences.Sync.credentialsKeyPress(event);"/>
|
||||
oninput="Zotero_Preferences.Sync.credentialsChange(event)"
|
||||
onchange="Zotero_Preferences.Sync.credentialsChange(event)"
|
||||
onkeypress="Zotero_Preferences.Sync.credentialsKeyPress(event)"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="&zotero.preferences.sync.password;"/>
|
||||
<textbox id="sync-password" type="password"
|
||||
onkeypress="Zotero_Preferences.Sync.credentialsKeyPress(event);"/>
|
||||
oninput="Zotero_Preferences.Sync.credentialsChange(event)"
|
||||
onchange="Zotero_Preferences.Sync.credentialsChange(event)"
|
||||
onkeypress="Zotero_Preferences.Sync.credentialsKeyPress(event)"/>
|
||||
</row>
|
||||
<row>
|
||||
<box/>
|
||||
|
@ -215,7 +219,7 @@
|
|||
<row>
|
||||
<box/>
|
||||
<hbox>
|
||||
<button id="storage-verify" label="Verify Server"
|
||||
<button id="storage-verify" label="&zotero.preferences.sync.fileSyncing.verifyServer;"
|
||||
oncommand="Zotero_Preferences.Sync.verifyStorageServer()"/>
|
||||
<button id="storage-abort" label="Stop" hidden="true"/>
|
||||
<progressmeter id="storage-progress" hidden="true"
|
||||
|
@ -229,7 +233,10 @@
|
|||
|
||||
<hbox class="storage-settings-download-options" align="center">
|
||||
<label value="&zotero.preferences.sync.fileSyncing.download;"/>
|
||||
<menulist class="storage-mode" preference="pref-storage-downloadMode-personal" style="margin-left: 0">
|
||||
<menulist id="storage-user-download-mode"
|
||||
class="storage-mode"
|
||||
preference="pref-storage-downloadMode-personal"
|
||||
style="margin-left: 0">
|
||||
<menupopup>
|
||||
<menuitem label="&zotero.preferences.sync.fileSyncing.download.onDemand;" value="on-demand"/>
|
||||
<menuitem label="&zotero.preferences.sync.fileSyncing.download.atSyncTime;" value="on-sync"/>
|
||||
|
@ -241,12 +248,15 @@
|
|||
|
||||
<!-- Group Libraries -->
|
||||
<checkbox label="&zotero.preferences.sync.fileSyncing.groups;"
|
||||
preference="pref-group-storage-enabled"
|
||||
oncommand="Zotero_Preferences.Sync.updateStorageSettingsGroups(this.checked)"/>
|
||||
preference="pref-storage-groups-enabled"
|
||||
oncommand="Zotero_Preferences.Sync.updateStorageSettingsGroupsUI()"/>
|
||||
|
||||
<hbox class="storage-settings-download-options" align="center">
|
||||
<label value="&zotero.preferences.sync.fileSyncing.download;"/>
|
||||
<menulist class="storage-mode" preference="pref-storage-downloadMode-groups" style="margin-left: 0">
|
||||
<menulist id="storage-groups-download-mode"
|
||||
class="storage-mode"
|
||||
preference="pref-storage-downloadMode-groups"
|
||||
style="margin-left: 0">
|
||||
<menupopup>
|
||||
<menuitem label="&zotero.preferences.sync.fileSyncing.download.onDemand;" value="on-demand"/>
|
||||
<menuitem label="&zotero.preferences.sync.fileSyncing.download.atSyncTime;" value="on-sync"/>
|
||||
|
@ -256,8 +266,8 @@
|
|||
|
||||
<separator class="thin"/>
|
||||
|
||||
<vbox>
|
||||
<hbox id="storage-terms" style="margin-top: .4em; display: block" align="center">
|
||||
<vbox id="storage-terms">
|
||||
<hbox style="margin-top: .4em; display: block" align="center">
|
||||
<label>&zotero.preferences.sync.fileSyncing.tos1;</label>
|
||||
<label class="zotero-text-link" href="https://www.zotero.org/support/terms/terms_of_service" value="&zotero.preferences.sync.fileSyncing.tos2;"/>
|
||||
<label>&zotero.preferences.period;</label>
|
||||
|
@ -267,81 +277,47 @@
|
|||
</vbox>
|
||||
</tabpanel>
|
||||
|
||||
<tabpanel id="zotero-reset" orient="vertical">
|
||||
<tabpanel id="sync-reset" orient="vertical">
|
||||
<!-- This doesn't wrap without an explicit width, for some reason -->
|
||||
<description width="45em">&zotero.preferences.sync.reset.warning1;<label style="margin-left: 0; margin-right: 0" class="zotero-text-link" href="http://zotero.org/support/kb/sync_reset_options">&zotero.preferences.sync.reset.warning2;</label>&zotero.preferences.sync.reset.warning3;</description>
|
||||
<description id="reset-sync-warning" width="45em">&zotero.preferences.sync.reset.warning1;<label style="margin-left: 0; margin-right: 0" class="zotero-text-link" href="http://zotero.org/support/kb/sync_reset_options">&zotero.preferences.sync.reset.warning2;</label>&zotero.preferences.sync.reset.warning3;</description>
|
||||
|
||||
<radiogroup id="zotero-reset-sync-group"
|
||||
oncommand="Zotero_Preferences.Sync.handleSyncResetSelect(this)">
|
||||
<groupbox>
|
||||
<caption label="&zotero.preferences.sync.syncServer;"/>
|
||||
|
||||
<grid>
|
||||
<columns>
|
||||
<column/>
|
||||
<column align="start" pack="start" flex="1"/>
|
||||
</columns>
|
||||
|
||||
<rows id="sync-reset-rows">
|
||||
<!--
|
||||
<row id="zotero-restore-from-server" selected="true">
|
||||
<radio/>
|
||||
<vbox onclick="this.previousSibling.click()">
|
||||
<label value="&zotero.preferences.sync.reset.restoreFromServer;"/>
|
||||
<description>&zotero.preferences.sync.reset.restoreFromServer.desc;</description>
|
||||
</vbox>
|
||||
</row>
|
||||
|
||||
<row id="zotero-restore-to-server">
|
||||
<radio/>
|
||||
<vbox onclick="this.previousSibling.click()">
|
||||
<label value="&zotero.preferences.sync.reset.restoreToServer;"/>
|
||||
<description>&zotero.preferences.sync.reset.restoreToServer.desc;</description>
|
||||
</vbox>
|
||||
</row>
|
||||
-->
|
||||
<row id="zotero-reset-data-sync-history">
|
||||
<radio/>
|
||||
<vbox onclick="this.previousSibling.click()">
|
||||
<label value="&zotero.preferences.sync.reset.resetDataSyncHistory;"/>
|
||||
<description>&zotero.preferences.sync.reset.resetDataSyncHistory.desc;</description>
|
||||
</vbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
|
||||
<hbox>
|
||||
<button label="&zotero.preferences.sync.reset.button;"
|
||||
oncommand="document.getElementById('sync-reset-rows').firstChild.firstChild.click(); Zotero_Preferences.Sync.handleSyncReset('full-sync')"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
<div id="sync-reset-form" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<div id="sync-reset-library-menu-container">
|
||||
<label>Library: <select id="sync-reset-library-menu"/></label>
|
||||
</div>
|
||||
|
||||
<groupbox>
|
||||
<caption label="&zotero.preferences.sync.fileSyncing;"/>
|
||||
<ul id="sync-reset-list">
|
||||
<!--<li>
|
||||
<p>&zotero.preferences.sync.reset.restoreFromServer;</p>
|
||||
<p>&zotero.preferences.sync.reset.restoreFromServer.desc;</p>
|
||||
</li>-->
|
||||
|
||||
<grid>
|
||||
<columns>
|
||||
<column/>
|
||||
<column align="start" pack="start" flex="1"/>
|
||||
</columns>
|
||||
|
||||
<rows id="storage-reset-rows">
|
||||
<row id="zotero-reset-storage-history">
|
||||
<radio/>
|
||||
<vbox onclick="this.previousSibling.click()">
|
||||
<label value="&zotero.preferences.sync.reset.resetFileSyncHistory;"/>
|
||||
<description>&zotero.preferences.sync.reset.resetFileSyncHistory.desc;</description>
|
||||
</vbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<li id="restore-to-server">
|
||||
<label>
|
||||
<input name="sync-reset-radiogroup" value="restore-to-server" type="radio"/>
|
||||
<span class="sync-reset-option-name">&zotero.preferences.sync.reset.restoreToServer;</span>
|
||||
<span class="sync-reset-option-desc">&zotero.preferences.sync.reset.restoreToServer.desc;</span>
|
||||
</label>
|
||||
</li>
|
||||
|
||||
<hbox>
|
||||
<button label="&zotero.preferences.sync.reset.button;"
|
||||
oncommand="document.getElementById('storage-reset-rows').firstChild.firstChild.click(); Zotero_Preferences.Sync.handleSyncReset('reset-storage-history')"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</radiogroup>
|
||||
<!--<li>
|
||||
<h2>&zotero.preferences.sync.reset.resetDataSyncHistory;</h2>
|
||||
<description>&zotero.preferences.sync.reset.resetDataSyncHistory.desc;</p>
|
||||
</li>-->
|
||||
|
||||
<li id="reset-file-sync-history">
|
||||
<label>
|
||||
<input name="sync-reset-radiogroup" value="reset-file-sync-history" type="radio"/>
|
||||
<span class="sync-reset-option-name">&zotero.preferences.sync.reset.resetFileSyncHistory;</span>
|
||||
<span class="sync-reset-option-desc">&zotero.preferences.sync.reset.resetFileSyncHistory.desc;</span>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button id="sync-reset-button"
|
||||
disabled="disabled"
|
||||
onclick="Zotero_Preferences.Sync.reset()">&zotero.preferences.sync.reset.button;</button>
|
||||
</div>
|
||||
</tabpanel>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
|
|
|
@ -45,34 +45,13 @@
|
|||
<script src="preferences.js"/>
|
||||
<script src="preferences_export.js"/>
|
||||
|
||||
<script>
|
||||
<![CDATA[
|
||||
var Zotero_QuickCopySiteEditor = new function () {
|
||||
this.onAccept = onAccept;
|
||||
|
||||
function onAccept() {
|
||||
var io = window.arguments[0];
|
||||
io.domain = document.getElementById('zotero-quickCopy-domain').value;
|
||||
io.format = document.getElementById('zotero-quickCopy-menu').value;
|
||||
|
||||
io.locale = '';
|
||||
if (!document.getElementById('zotero-quickCopy-locale-menu').disabled) {
|
||||
io.locale = document.getElementById('zotero-quickCopy-locale-menu').value;
|
||||
}
|
||||
|
||||
io.ok = true;
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<vbox id="zotero-preferences-quickCopySiteEditor">
|
||||
<label value="&zotero.preferences.quickCopy.siteEditor.domainPath; &zotero.preferences.quickCopy.siteEditor.domainPath.example;" control="zotero-quickCopy-domain"/>
|
||||
<textbox id="zotero-quickCopy-domain"/>
|
||||
<textbox id="zotero-quickCopy-domain" oninput="Zotero_QuickCopySiteEditor.onDomainInput(event)"/>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<label value="&zotero.preferences.quickCopy.siteEditor.outputFormat;" control="zotero-quickCopy-menu"/>
|
||||
<label value="&zotero.preferences.quickCopy.siteEditor.format;" control="zotero-quickCopy-menu"/>
|
||||
<menulist id="zotero-quickCopy-menu"/>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
@ -95,6 +74,31 @@
|
|||
|
||||
<script>
|
||||
<![CDATA[
|
||||
var Zotero_QuickCopySiteEditor = new function () {
|
||||
var menu = document.getElementById('zotero-quickCopy-menu');
|
||||
|
||||
this.onAccept = function () {
|
||||
var io = window.arguments[0];
|
||||
io.domain = document.getElementById('zotero-quickCopy-domain').value;
|
||||
io.format = menu.value;
|
||||
|
||||
io.locale = '';
|
||||
if (!document.getElementById('zotero-quickCopy-locale-menu').disabled) {
|
||||
io.locale = document.getElementById('zotero-quickCopy-locale-menu').value;
|
||||
}
|
||||
|
||||
io.ok = true;
|
||||
}
|
||||
|
||||
this.onDomainInput = function (event) {
|
||||
if (event.target.value == 'wikipedia.org') {
|
||||
Zotero.debug("SETTING TO WIKI");
|
||||
menu.value = 'export=3f50aaac-7acc-4350-acd0-59cb77faf620';
|
||||
Zotero_Preferences.Export.updateQuickCopyUI();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var io = window.arguments[0];
|
||||
var contentType = io.asHTML ? 'html' : '';
|
||||
document.getElementById('zotero-quickCopy-domain').value = io.domain ? io.domain : '';
|
||||
|
|
14
chrome/content/zotero/progressMeterWindow.xul
Normal file
14
chrome/content/zotero/progressMeterWindow.xul
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
|
||||
|
||||
<window id="zotero-progress-meter-window"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
windowtype="alert:alert">
|
||||
|
||||
<vbox id="zotero-progress-text-box" flex="1">
|
||||
<label/>
|
||||
<progressmeter/>
|
||||
</vbox>
|
||||
</window>
|
|
@ -1,943 +0,0 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2009 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileOverview Tools for automatically retrieving a citation for the given PDF
|
||||
*/
|
||||
|
||||
/**
|
||||
* Front end for recognizing PDFs
|
||||
* @namespace
|
||||
*/
|
||||
var Zotero_RecognizePDF = new function() {
|
||||
var _progressWindow, _progressIndicator;
|
||||
|
||||
/**
|
||||
* Checks whether a given PDF could theoretically be recognized
|
||||
* @returns {Boolean} True if the PDF can be recognized, false if it cannot be
|
||||
*/
|
||||
this.canRecognize = function(/**Zotero.Item*/ item) {
|
||||
return item.attachmentMIMEType
|
||||
&& item.attachmentMIMEType == "application/pdf"
|
||||
&& item.isTopLevelItem();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves metadata for the PDF(s) selected in the Zotero Pane, placing the PDFs as a children
|
||||
* of the new items
|
||||
*/
|
||||
this.recognizeSelected = function() {
|
||||
var installed = ZoteroPane_Local.checkPDFConverter();
|
||||
if (!installed) {
|
||||
return;
|
||||
}
|
||||
|
||||
var items = ZoteroPane_Local.getSelectedItems();
|
||||
if (!items) return;
|
||||
var itemRecognizer = new Zotero_RecognizePDF.ItemRecognizer();
|
||||
itemRecognizer.recognizeItems(items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves metadata for a PDF and saves it as an item
|
||||
*
|
||||
* @param {nsIFile} file The PDF file to retrieve metadata for
|
||||
* @param {Integer} libraryID The library in which to save the PDF
|
||||
* @param {Function} stopCheckCallback Function that returns true if the
|
||||
* process is to be interrupted
|
||||
* @return {Promise} A promise resolved when PDF metadata has been retrieved
|
||||
*/
|
||||
this.recognize = Zotero.Promise.coroutine(function* (file, libraryID, stopCheckCallback) {
|
||||
const MAX_PAGES = 15;
|
||||
var me = this;
|
||||
|
||||
var lines = yield _extractText(file, MAX_PAGES);
|
||||
// Look for DOI - Use only first 80 lines to avoid catching article references
|
||||
var allText = lines.join("\n"),
|
||||
firstChunk = lines.slice(0,80).join('\n'),
|
||||
doi = Zotero.Utilities.cleanDOI(firstChunk),
|
||||
promise;
|
||||
Zotero.debug(allText);
|
||||
|
||||
if(!doi) {
|
||||
// Look for a JSTOR stable URL, which can be converted to a DOI by prepending 10.2307
|
||||
doi = firstChunk.match(/www.\jstor\.org\/stable\/(\S+)/i);
|
||||
if(doi) {
|
||||
doi = Zotero.Utilities.cleanDOI(
|
||||
doi[1].indexOf('10.') == 0 ? doi[1] : '10.2307/' + doi[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var newItem;
|
||||
if (doi) {
|
||||
// Look up DOI
|
||||
Zotero.debug("RecognizePDF: Found DOI: "+doi);
|
||||
|
||||
var translateDOI = new Zotero.Translate.Search();
|
||||
translateDOI.setTranslator("11645bd1-0420-45c1-badb-53fb41eeb753");
|
||||
translateDOI.setSearch({"itemType":"journalArticle", "DOI":doi});
|
||||
try {
|
||||
newItem = yield _promiseTranslate(translateDOI, libraryID);
|
||||
return newItem;
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug("RecognizePDF: " + e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Zotero.debug("RecognizePDF: No DOI found in text");
|
||||
}
|
||||
|
||||
// Look for ISBNs if no DOI
|
||||
var isbns = _findISBNs(allText);
|
||||
if (isbns.length) {
|
||||
Zotero.debug("RecognizePDF: Found ISBNs: " + isbns);
|
||||
|
||||
var translate = new Zotero.Translate.Search();
|
||||
translate.setSearch({"itemType":"book", "ISBN":isbns[0]});
|
||||
try {
|
||||
newItem = yield _promiseTranslate(translate, libraryID);
|
||||
return newItem;
|
||||
}
|
||||
catch (e) {
|
||||
// If no DOI or ISBN, query Google Scholar
|
||||
Zotero.debug("RecognizePDF: " + e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Zotero.debug("RecognizePDF: No ISBN found in text");
|
||||
}
|
||||
|
||||
return this.GSFullTextSearch.findItem(lines, libraryID, stopCheckCallback);
|
||||
});
|
||||
|
||||
/**
|
||||
* Get text from a PDF
|
||||
* @param {nsIFile} file PDF
|
||||
* @param {Number} pages Number of pages to extract
|
||||
* @return {Promise}
|
||||
*/
|
||||
function _extractText(file, pages) {
|
||||
var cacheFile = Zotero.File.pathToFile(Zotero.DataDirectory.dir);
|
||||
cacheFile.append("recognizePDFcache.txt");
|
||||
if(cacheFile.exists()) {
|
||||
cacheFile.remove(false);
|
||||
}
|
||||
|
||||
var {exec, args} = Zotero.Fulltext.getPDFConverterExecAndArgs();
|
||||
args.push('-enc', 'UTF-8', '-nopgbrk', '-layout', '-l', pages, file.path, cacheFile.path);
|
||||
|
||||
Zotero.debug("RecognizePDF: Running " + exec.path + " " + args.map(arg => "'" + arg + "'").join(" "));
|
||||
|
||||
return Zotero.Utilities.Internal.exec(exec, args).then(function() {
|
||||
if(!cacheFile.exists()) {
|
||||
throw new Zotero.Exception.Alert("recognizePDF.couldNotRead");
|
||||
}
|
||||
|
||||
try {
|
||||
var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileInputStream);
|
||||
inputStream.init(cacheFile, 0x01, 0o664, 0);
|
||||
try {
|
||||
var intlStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
intlStream.init(inputStream, "UTF-8", 65535,
|
||||
Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
intlStream.QueryInterface(Components.interfaces.nsIUnicharLineInputStream);
|
||||
|
||||
// get the lines in this sample
|
||||
var lines = [], str = {};
|
||||
while(intlStream.readLine(str)) {
|
||||
var line = str.value.trim();
|
||||
if(line) lines.push(line);
|
||||
}
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
} finally {
|
||||
cacheFile.remove(false);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}, function() {
|
||||
throw new Zotero.Exception.Alert("recognizePDF.couldNotRead");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach appropriate handlers to a Zotero.Translate instance and begin translation
|
||||
* @return {Promise}
|
||||
*/
|
||||
var _promiseTranslate = Zotero.Promise.coroutine(function* (translate, libraryID) {
|
||||
translate.setHandler("select", function(translate, items, callback) {
|
||||
for(var i in items) {
|
||||
var obj = {};
|
||||
obj[i] = items[i];
|
||||
callback(obj);
|
||||
return;
|
||||
}
|
||||
});
|
||||
/*translate.setHandler("done", function(translate, success) {
|
||||
if(success && translate.newItems.length) {
|
||||
deferred.resolve(translate.newItems[0]);
|
||||
} else {
|
||||
deferred.reject(translate.translator && translate.translator.length
|
||||
? "Translation with " + translate.translator.map(t => t.label) + " failed"
|
||||
: "Could not find a translator for given search item"
|
||||
);
|
||||
}
|
||||
});*/
|
||||
var newItems = yield translate.translate({
|
||||
libraryID,
|
||||
saveAttachments: false
|
||||
});
|
||||
if (newItems.length) {
|
||||
return newItems[0];
|
||||
}
|
||||
throw new Error("No items found");
|
||||
});
|
||||
|
||||
/**
|
||||
* Search ISBNs in text
|
||||
* @private
|
||||
* @return {String[]} Array of ISBNs
|
||||
*/
|
||||
function _findISBNs(x) {
|
||||
if(typeof(x) != "string") {
|
||||
throw "findISBNs: argument must be a string";
|
||||
}
|
||||
var isbns = [];
|
||||
|
||||
// Match lines saying "isbn: " or "ISBN-10:" or similar, consider m-dashes and n-dashes as well
|
||||
var pattern = /(SBN|sbn)[ \u2014\u2013\u2012-]?(10|13)?[: ]*([0-9X][0-9X \u2014\u2013\u2012-]+)/g;
|
||||
var match;
|
||||
|
||||
while (match = pattern.exec(x)) {
|
||||
var isbn = match[3];
|
||||
isbn = isbn.replace(/[ \u2014\u2013\u2012-]/g, '');
|
||||
if(isbn.length==20 || isbn.length==26) {
|
||||
// Handle the case of two isbns (e.g. paper+hardback) next to each other
|
||||
isbns.push(isbn.slice(0,isbn.length/2), isbn.slice(isbn.length/2));
|
||||
} else if(isbn.length==23) {
|
||||
// Handle the case of two isbns (10+13) next to each other
|
||||
isbns.push(isbn.slice(0,10), isbn.slice(10));
|
||||
} else if(isbn.length==10 || isbn.length==13) {
|
||||
isbns.push(isbn);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate ISBNs
|
||||
var validIsbns = [], cleanISBN;
|
||||
for (var i =0; i < isbns.length; i++) {
|
||||
cleanISBN = Zotero.Utilities.cleanISBN(isbns[i]);
|
||||
if(cleanISBN) validIsbns.push(cleanISBN);
|
||||
}
|
||||
return validIsbns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Handles UI, etc. for recognizing multiple items
|
||||
*/
|
||||
this.ItemRecognizer = function () {
|
||||
this._items = [];
|
||||
}
|
||||
|
||||
this.ItemRecognizer.prototype = {
|
||||
"_stopped": false,
|
||||
"_itemsTotal": 0,
|
||||
"_progressWindow": null,
|
||||
"_progressIndicator": null,
|
||||
|
||||
/**
|
||||
* Retreives metadata for the PDF items passed, displaying a progress dialog during conversion
|
||||
* and placing the PDFs as a children of the new items
|
||||
* @param {Zotero.Item[]} items
|
||||
*/
|
||||
"recognizeItems": function(items) {
|
||||
var me = this;
|
||||
this._items = items.slice();
|
||||
this._itemTotal = items.length;
|
||||
|
||||
_progressWindow = this._progressWindow = window.openDialog("chrome://zotero/content/pdfProgress.xul", "", "chrome,close=yes,resizable=yes,dependent,dialog,centerscreen");
|
||||
this._progressWindow.addEventListener("pageshow", function() { me._onWindowLoaded() }, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Halts recognition of PDFs
|
||||
*/
|
||||
"stop": function() {
|
||||
this._stopped = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Halts recognition and closes window
|
||||
*/
|
||||
"close": function() {
|
||||
this.stop();
|
||||
this._progressWindow.close();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the progress window has been opened; adds items to the tree and begins recognizing
|
||||
* @param
|
||||
*/
|
||||
"_onWindowLoaded": function() {
|
||||
// populate progress window
|
||||
var treechildren = this._progressWindow.document.getElementById("treechildren");
|
||||
this._rowIDs = [];
|
||||
for(var i in this._items) {
|
||||
var treeitem = this._progressWindow.document.createElement('treeitem');
|
||||
var treerow = this._progressWindow.document.createElement('treerow');
|
||||
this._rowIDs.push(this._items[i].id);
|
||||
|
||||
var treecell = this._progressWindow.document.createElement('treecell');
|
||||
treecell.setAttribute("id", "item-"+this._items[i].id+"-icon");
|
||||
treerow.appendChild(treecell);
|
||||
|
||||
treecell = this._progressWindow.document.createElement('treecell');
|
||||
treecell.setAttribute("label", this._items[i].getField("title"));
|
||||
treerow.appendChild(treecell);
|
||||
|
||||
treecell = this._progressWindow.document.createElement('treecell');
|
||||
treecell.setAttribute("id", "item-"+this._items[i].id+"-title");
|
||||
treerow.appendChild(treecell);
|
||||
|
||||
treeitem.appendChild(treerow);
|
||||
treechildren.appendChild(treeitem);
|
||||
}
|
||||
|
||||
var me = this;
|
||||
|
||||
this._progressWindow.document.getElementById("tree").addEventListener(
|
||||
"dblclick", function(event) { me._onDblClick(event, this); });
|
||||
|
||||
this._cancelHandler = function() { me.stop() };
|
||||
this._keypressCancelHandler = function(e) {
|
||||
if(e.keyCode === KeyEvent.DOM_VK_ESCAPE) me.stop();
|
||||
};
|
||||
|
||||
_progressIndicator = this._progressIndicator = this._progressWindow.document.getElementById("progress-indicator");
|
||||
this._progressWindow.document.getElementById("cancel-button")
|
||||
.addEventListener("command", this._cancelHandler, false);
|
||||
// Also cancel if the user presses Esc
|
||||
this._progressWindow.addEventListener("keypress", this._keypressCancelHandler);
|
||||
this._progressWindow.addEventListener("close", this._cancelHandler, false);
|
||||
Zotero_RecognizePDF.GSFullTextSearch.resetQueryLimit();
|
||||
return this._recognizeItem();
|
||||
},
|
||||
|
||||
/**
|
||||
* Shifts an item off of this._items and recognizes it, then calls itself again if there are more
|
||||
* @private
|
||||
*/
|
||||
"_recognizeItem": Zotero.Promise.coroutine(function* () {
|
||||
const SUCCESS_IMAGE = "chrome://zotero/skin/tick.png";
|
||||
const FAILURE_IMAGE = "chrome://zotero/skin/cross.png";
|
||||
const LOADING_IMAGE = "chrome://global/skin/icons/loading_16.png";
|
||||
|
||||
if(!this._items.length) {
|
||||
this._done();
|
||||
return;
|
||||
}
|
||||
|
||||
// Order here matters. Otherwise we may show an incorrect label
|
||||
if(this._stopped) {
|
||||
this._done(true);
|
||||
return;
|
||||
}
|
||||
|
||||
this._progressIndicator.value = (this._itemTotal-this._items.length)/this._itemTotal*100;
|
||||
|
||||
var item = this._items.shift(),
|
||||
itemIcon = this._progressWindow.document.getElementById("item-"+item.id+"-icon"),
|
||||
itemTitle = this._progressWindow.document.getElementById("item-"+item.id+"-title"),
|
||||
rowNumber = this._rowIDs.indexOf(item.id);
|
||||
itemIcon.setAttribute("src", LOADING_IMAGE);
|
||||
itemTitle.setAttribute("label", "");
|
||||
|
||||
var file = item.getFile(), me = this;
|
||||
|
||||
try {
|
||||
if (file) {
|
||||
let newItem = yield Zotero_RecognizePDF.recognize(
|
||||
file,
|
||||
item.libraryID,
|
||||
() => this._stopped
|
||||
);
|
||||
|
||||
// If already stopped, delete
|
||||
if (this._stopped) {
|
||||
yield Zotero.Items.erase(newItem.id);
|
||||
throw new Zotero.Exception.Alert('recognizePDF.stopped');
|
||||
}
|
||||
|
||||
// put new item in same collections as the old one
|
||||
let itemCollections = item.getCollections();
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
for (let i = 0; i < itemCollections.length; i++) {
|
||||
let collection = Zotero.Collections.get(itemCollections[i]);
|
||||
yield collection.addItem(newItem.id);
|
||||
}
|
||||
|
||||
// put old item as a child of the new item
|
||||
item.parentID = newItem.id;
|
||||
yield item.save();
|
||||
});
|
||||
|
||||
itemTitle.setAttribute("label", newItem.getField("title"));
|
||||
itemIcon.setAttribute("src", SUCCESS_IMAGE);
|
||||
this._rowIDs[rowNumber] = newItem.id;
|
||||
|
||||
return this._recognizeItem();
|
||||
}
|
||||
else {
|
||||
throw new Zotero.Exception.Alert("recognizePDF.fileNotFound");
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
|
||||
itemTitle.setAttribute(
|
||||
"label",
|
||||
e instanceof Zotero.Exception.Alert
|
||||
? e.message
|
||||
: Zotero.getString("recognizePDF.error")
|
||||
);
|
||||
itemIcon.setAttribute("src", FAILURE_IMAGE);
|
||||
|
||||
// Don't show "completed" label if stopped on last item
|
||||
if (this._stopped && !this._items.length) {
|
||||
this._done(true);
|
||||
} else {
|
||||
return this._recognizeItem();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// scroll to this item
|
||||
this._progressWindow.document.getElementById("tree").treeBoxObject.scrollToRow(
|
||||
Math.max(0, this._itemTotal - this._items.length - 4)
|
||||
);
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Cleans up after items are recognized, disabling the cancel button and
|
||||
* making the progress window close on blur.
|
||||
* @param {Boolean} cancelled Whether the process was cancelled
|
||||
*/
|
||||
"_done": function(cancelled) {
|
||||
this._progressIndicator.value = 100;
|
||||
// Switch out cancel for close
|
||||
var cancelButton = this._progressWindow.document.getElementById("cancel-button"),
|
||||
me = this;
|
||||
cancelButton.label = Zotero.getString("recognizePDF.close.label");
|
||||
cancelButton.removeEventListener("command", this._cancelHandler, false);
|
||||
cancelButton.addEventListener("command", function() { me.close() }, false);
|
||||
this._progressWindow.removeEventListener("keypress", this._keypressCancelHandler);
|
||||
this._progressWindow.addEventListener("keypress", function() { me.close() });
|
||||
|
||||
if(Zotero.isMac) {
|
||||
// On MacOS X, the windows are not always on top, so we hide them on
|
||||
// blur to avoid clutter
|
||||
this._setCloseTimer();
|
||||
}
|
||||
this._progressWindow.document.getElementById("label").value =
|
||||
cancelled ? Zotero.getString("recognizePDF.cancelled.label")
|
||||
: Zotero.getString("recognizePDF.complete.label");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a timer after which the window will close automatically. If the
|
||||
* window is refocused, clear the timer and do not attempt to auto-close
|
||||
* any more
|
||||
* @private
|
||||
*/
|
||||
"_setCloseTimer": function() {
|
||||
var me = this, win = this._progressWindow;
|
||||
var focusListener = function() {
|
||||
if(!win.zoteroCloseTimeoutID) return;
|
||||
|
||||
win.clearTimeout(win.zoteroCloseTimeoutID);
|
||||
delete win.zoteroCloseTimeoutID;
|
||||
|
||||
win.removeEventListener('blur', blurListener, false);
|
||||
win.removeEventListener('focus', focusListener, false);
|
||||
};
|
||||
var blurListener = function() {
|
||||
// Close window after losing focus for 5 seconds
|
||||
win.zoteroCloseTimeoutID = win.setTimeout(function() { win.close() }, 5000);
|
||||
// Prevent auto-close if we gain focus again
|
||||
win.addEventListener("focus", focusListener, false);
|
||||
};
|
||||
win.addEventListener("blur", blurListener, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Focus items in Zotero library when double-clicking them in the Retrieve
|
||||
* metadata window.
|
||||
* @param {Event} event
|
||||
* @param {tree} tree XUL tree object
|
||||
* @private
|
||||
*/
|
||||
"_onDblClick": function(event, tree) {
|
||||
if (event && tree && event.type == "dblclick") {
|
||||
var itemID = this._rowIDs[tree.treeBoxObject.getRowAt(event.clientX, event.clientY)];
|
||||
if(!itemID) return;
|
||||
|
||||
// Get the right window. In tab mode, it's the container window
|
||||
var lastWin = (window.ZoteroTab ? window.ZoteroTab.containerWindow : window);
|
||||
|
||||
if (lastWin.ZoteroOverlay) {
|
||||
lastWin.ZoteroOverlay.toggleDisplay(true);
|
||||
}
|
||||
|
||||
lastWin.ZoteroPane.selectItem(itemID, false, true);
|
||||
lastWin.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Singleton for querying Google Scholar. Ensures that all queries are
|
||||
* sequential and respect the delay inbetween queries.
|
||||
* @namespace
|
||||
*/
|
||||
this.GSFullTextSearch = new function() {
|
||||
const GOOGLE_SCHOLAR_QUERY_DELAY = 2000; // In ms
|
||||
var queryLimitReached = false,
|
||||
inProgress = false,
|
||||
queue = [],
|
||||
stopCheckCallback; // As long as we process one query at a time, this is ok
|
||||
// Load nsICookieManager2
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
var cookieService = Services.cookies;
|
||||
|
||||
/**
|
||||
* Reset "Query Limit Reached" flag, so that we attempt to query Google again
|
||||
*/
|
||||
this.resetQueryLimit = function() {
|
||||
queryLimitReached = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Queue up item for Google Scholar query
|
||||
* @param {String[]} lines Lines of text to use for full-text query
|
||||
* @param {Integer | null} libraryID Library to save the item to
|
||||
* @param {Function} stopCheckCallback Function that returns true if the
|
||||
* process is to be interrupted
|
||||
* @return {Promise} A promise resolved when PDF metadata has been retrieved
|
||||
*/
|
||||
this.findItem = function(lines, libraryID, stopCheckCallback) {
|
||||
if(!inProgress && queryLimitReached) {
|
||||
// There's no queue, so we can reject immediately
|
||||
return Zotero.Promise.reject(new Zotero.Exception.Alert("recognizePDF.limit"));
|
||||
}
|
||||
|
||||
var deferred = Zotero.Promise.defer();
|
||||
queue.push({
|
||||
deferred: deferred,
|
||||
lines: lines,
|
||||
libraryID: libraryID,
|
||||
stopCheckCallback: stopCheckCallback
|
||||
});
|
||||
_processQueue();
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Process Google Scholar queue
|
||||
* @private
|
||||
* @param {Boolean} proceed Whether we should pop the next item off the queue
|
||||
* This should not be true unless being called after processing
|
||||
* another item
|
||||
*/
|
||||
function _processQueue(proceed) {
|
||||
if(inProgress && !proceed) return; //only one at a time
|
||||
|
||||
if(!queue.length) {
|
||||
inProgress = false;
|
||||
return;
|
||||
}
|
||||
|
||||
inProgress = true;
|
||||
if(queryLimitReached) {
|
||||
// Irreversibly blocked. Reject remaining items in queue
|
||||
var item;
|
||||
while(item = queue.shift()) {
|
||||
item.deferred.reject(new Zotero.Exception.Alert("recognizePDF.limit"));
|
||||
}
|
||||
_processQueue(true); // Wrap it up
|
||||
} else {
|
||||
var item = queue.shift();
|
||||
|
||||
stopCheckCallback = item.stopCheckCallback;
|
||||
if(stopCheckCallback && stopCheckCallback()) {
|
||||
item.deferred.reject(new Zotero.Exception.Alert('recognizePDF.stopped'));
|
||||
_processQueue(true);
|
||||
return;
|
||||
}
|
||||
|
||||
item.deferred.resolve(
|
||||
Zotero.Promise.try(function () {
|
||||
var lines = getGoodLines(item.lines);
|
||||
return queryGoogle(lines, item.libraryID, 3); // Try querying 3 times
|
||||
})
|
||||
.finally(function() { _processQueue(true); })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select lines that are good candidates for Google Scholar query
|
||||
* @private
|
||||
* @param {String[]} lines
|
||||
* @return {String[]}
|
||||
*/
|
||||
function getGoodLines(lines) {
|
||||
// Use only first column from multi-column lines
|
||||
const lineRe = /^[\s_]*([^\s]+(?: [^\s_]+)+)/;
|
||||
var cleanedLines = [], cleanedLineLengths = [];
|
||||
for(var i=0; i<lines.length && cleanedLines.length<100; i++) {
|
||||
var m = lineRe.exec(
|
||||
lines[i]
|
||||
// Replace non-breaking spaces
|
||||
.replace(/\xA0/g, ' ')
|
||||
);
|
||||
if(m && m[1].split(' ').length > 3) {
|
||||
cleanedLines.push(m[1]);
|
||||
cleanedLineLengths.push(m[1].length);
|
||||
}
|
||||
}
|
||||
|
||||
// Get (not quite) median length
|
||||
var lineLengthsLength = cleanedLineLengths.length;
|
||||
if(lineLengthsLength < 20
|
||||
|| cleanedLines[0] === "This is a digital copy of a book that was preserved for generations on library shelves before it was carefully scanned by Google as part of a project") {
|
||||
throw new Zotero.Exception.Alert("recognizePDF.noOCR");
|
||||
}
|
||||
|
||||
var sortedLengths = cleanedLineLengths.sort(),
|
||||
medianLength = sortedLengths[Math.floor(lineLengthsLength/2)];
|
||||
|
||||
// Pick lines within 6 chars of the median (this is completely arbitrary)
|
||||
var goodLines = [],
|
||||
uBound = medianLength + 6,
|
||||
lBound = medianLength - 6;
|
||||
for (var i=0; i<lineLengthsLength; i++) {
|
||||
if(cleanedLineLengths[i] > lBound && cleanedLineLengths[i] < uBound) {
|
||||
// Strip quotation marks so they don't mess up search query quoting
|
||||
var line = cleanedLines[i].replace('"', '');
|
||||
goodLines.push(line);
|
||||
}
|
||||
}
|
||||
return goodLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query Google Scholar
|
||||
* @private
|
||||
* @param {String[]} goodLines
|
||||
* @param {Integer | null} libraryID
|
||||
* @param {Integer} tries Number of queries to attempt before giving up
|
||||
* @return {Promise} A promise resolved when PDF metadata has been retrieved
|
||||
*/
|
||||
var queryGoogle = Zotero.Promise.coroutine(function* (goodLines, libraryID, tries) {
|
||||
if(tries <= 0) throw new Zotero.Exception.Alert("recognizePDF.noMatches");
|
||||
|
||||
// Take the relevant parts of some lines (exclude hyphenated word)
|
||||
var queryString = "", queryStringWords = 0, nextLine = 0;
|
||||
while(queryStringWords < 25) {
|
||||
if(!goodLines.length) throw new Zotero.Exception.Alert("recognizePDF.noMatches");
|
||||
|
||||
var words = goodLines.splice(nextLine, 1)[0].split(/\s+/);
|
||||
// Try to avoid picking adjacent strings so the odds of them appearing in another
|
||||
// document quoting our document is low. Every 7th line is a magic value
|
||||
nextLine = (nextLine + 7) % goodLines.length;
|
||||
|
||||
// Get rid of first and last words
|
||||
words.shift();
|
||||
words.pop();
|
||||
// Make sure there are no long words (probably OCR mistakes)
|
||||
var skipLine = false;
|
||||
for(var i=0; i<words.length; i++) {
|
||||
if(words[i].length > 20) {
|
||||
skipLine = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Add words to query
|
||||
if(!skipLine && words.length) {
|
||||
queryStringWords += words.length;
|
||||
queryString += '"'+words.join(" ")+'" ';
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.debug("RecognizePDF: Query string " + queryString);
|
||||
|
||||
var url = "http://scholar.google.com/scholar?q="+encodeURIComponent(queryString)+"&hl=en&lr=&btnG=Search",
|
||||
delay = GOOGLE_SCHOLAR_QUERY_DELAY - (Date.now() - Zotero.HTTP.lastGoogleScholarQueryTime);
|
||||
|
||||
// Delay
|
||||
if (delay > 0) {
|
||||
yield Zotero.Promise.delay(delay);
|
||||
}
|
||||
Zotero.HTTP.lastGoogleScholarQueryTime = Date.now();
|
||||
try {
|
||||
let xmlhttp = yield Zotero.HTTP.request("GET", url, { "responseType": "document" })
|
||||
.then(
|
||||
function (xmlhttp) {
|
||||
return _checkCaptchaOK(xmlhttp, 3);
|
||||
},
|
||||
function (e) {
|
||||
return _checkCaptchaError(e, 3);
|
||||
}
|
||||
);
|
||||
|
||||
let doc = xmlhttp.response,
|
||||
deferred = Zotero.Promise.defer(),
|
||||
translate = new Zotero.Translate.Web();
|
||||
|
||||
translate.setTranslator("57a00950-f0d1-4b41-b6ba-44ff0fc30289");
|
||||
translate.setDocument(Zotero.HTTP.wrapDocument(doc, url));
|
||||
translate.setHandler("translators", function(translate, detected) {
|
||||
if(detected.length) {
|
||||
deferred.resolve(_promiseTranslate(translate, libraryID));
|
||||
} else {
|
||||
deferred.resolve(Zotero.Promise.try(function() {
|
||||
return queryGoogle(goodLines, libraryID, tries-1);
|
||||
}));
|
||||
}
|
||||
});
|
||||
translate.getTranslators();
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
catch (e) {
|
||||
if(e.name == "recognizePDF.limit") {
|
||||
queryLimitReached = true;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Check for CAPTCHA on a page with HTTP 200 status
|
||||
* @private
|
||||
* @param {XMLHttpRequest} xmlhttp
|
||||
* @param {Integer} tries Number of queries to attempt before giving up
|
||||
* @return {Promise} A promise resolved when PDF metadata has been retrieved
|
||||
*/
|
||||
function _checkCaptchaOK(xmlhttp, tries) {
|
||||
if(stopCheckCallback && stopCheckCallback()) {
|
||||
throw new Zotero.Exception.Alert('recognizePDF.stopped');
|
||||
}
|
||||
|
||||
Zotero.debug("RecognizePDF: (" + xmlhttp.status + ") Got page with title " + xmlhttp.response.title);
|
||||
|
||||
if(Zotero.Utilities.xpath(xmlhttp.response, "//form[@action='Captcha']").length) {
|
||||
Zotero.debug("RecognizePDF: Found CAPTCHA on page.");
|
||||
return _solveCaptcha(xmlhttp, tries);
|
||||
}
|
||||
return xmlhttp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for CAPTCHA on an error page. Handle 403 and 503 pages
|
||||
* @private
|
||||
* @param {Zotero.HTTP.UnexpectedStatusException} e HTTP response error object
|
||||
* @param {Integer} tries Number of queries to attempt before giving up
|
||||
* @param {Boolean} dontClearCookies Whether to attempt to clear cookies in
|
||||
* in order to get CAPTCHA to show up
|
||||
* @return {Promise} A promise resolved when PDF metadata has been retrieved
|
||||
*/
|
||||
var _checkCaptchaError = Zotero.Promise.coroutine(function* (e, tries, dontClearCookies) {
|
||||
if(stopCheckCallback && stopCheckCallback()) {
|
||||
throw new Zotero.Exception.Alert('recognizePDF.stopped');
|
||||
}
|
||||
|
||||
Zotero.debug("RecognizePDF: Checking for CAPTCHA on Google Scholar error page (" + e.status + ")");
|
||||
|
||||
// Check for captcha on error page
|
||||
if(e instanceof Zotero.HTTP.UnexpectedStatusException
|
||||
&& (e.status == 403 || e.status == 503) && e.xmlhttp.response) {
|
||||
if(_extractCaptchaFormData(e.xmlhttp.response)) {
|
||||
Zotero.debug("RecognizePDF: CAPTCHA found");
|
||||
return _solveCaptcha(e.xmlhttp, tries);
|
||||
} else if(!dontClearCookies && e.xmlhttp.channel) { // Make sure we can obtain original URL
|
||||
// AFAICT, for 403 errors, GS just says "sorry, try later",
|
||||
// but if you clear cookies, you get a CAPTCHA
|
||||
Zotero.debug("RecognizePDF: No CAPTCHA detected on page. Clearing cookies.");
|
||||
if(!_clearGSCookies(e.xmlhttp.channel.originalURI.host)) {
|
||||
//user said no or no cookies removed
|
||||
throw new Zotero.Exception.Alert('recognizePDF.limit');
|
||||
}
|
||||
// Redo GET request
|
||||
Zotero.debug("RecognizePDF: Reloading page after clearing cookies.");
|
||||
return Zotero.HTTP.request(
|
||||
"GET", e.xmlhttp.channel.originalURI.spec, { "responseType": "document" }
|
||||
)
|
||||
.then(
|
||||
function (xmlhttp) {
|
||||
return _checkCaptchaOK(xmlhttp, tries);
|
||||
},
|
||||
function (e) {
|
||||
return _checkCaptchaError(e, tries, true); // Don't try this again
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Zotero.debug("RecognizePDF: Google Scholar returned an unexpected page"
|
||||
+ " with status " + e.status);
|
||||
throw new Zotero.Exception.Alert('recognizePDF.limit');
|
||||
}
|
||||
throw e;
|
||||
});
|
||||
|
||||
/**
|
||||
* Prompt user to enter CPATCHA
|
||||
* @private
|
||||
* @param {XMLHttpRequest} xmlhttp
|
||||
* @param {Integer} [tries] Number of queries to attempt before giving up
|
||||
* @return {Promise} A promise resolved when PDF metadata has been retrieved
|
||||
*/
|
||||
function _solveCaptcha(xmlhttp, tries) {
|
||||
var doc = xmlhttp.response;
|
||||
|
||||
if(tries === undefined) tries = 3;
|
||||
|
||||
if(!tries) {
|
||||
Zotero.debug("RecognizePDF: Failed to solve CAPTCHA after multiple attempts.");
|
||||
throw new Zotero.Exception.Alert('recognizePDF.limit');
|
||||
}
|
||||
|
||||
tries--;
|
||||
var formData = doc && _extractCaptchaFormData(doc);
|
||||
if(!formData) {
|
||||
Zotero.debug("RecognizePDF: Could not find CAPTCHA on page.");
|
||||
throw new Zotero.Exception.Alert('recognizePDF.limit');
|
||||
}
|
||||
|
||||
var io = { dataIn: {
|
||||
title: Zotero.getString("recognizePDF.captcha.title"),
|
||||
description: Zotero.getString("recognizePDF.captcha.description"),
|
||||
imgUrl: formData.img
|
||||
}};
|
||||
|
||||
_progressWindow.openDialog("chrome://zotero/content/captcha.xul", "",
|
||||
"chrome,modal,resizable=no,centerscreen", io);
|
||||
|
||||
if(!io.dataOut) {
|
||||
Zotero.debug("RecognizePDF: No CAPTCHA entered");
|
||||
throw new Zotero.Exception.Alert('recognizePDF.limit');
|
||||
}
|
||||
|
||||
Zotero.debug('RecognizePDF: User entered "' + io.dataOut.captcha + '" for CAPTCHA');
|
||||
formData.input.captcha = io.dataOut.captcha;
|
||||
var url = '', prop;
|
||||
for(prop in formData.input) {
|
||||
url += '&' + encodeURIComponent(prop) + '='
|
||||
+ encodeURIComponent(formData.input[prop]);
|
||||
}
|
||||
|
||||
url = formData.action + '?' + url.substr(1);
|
||||
|
||||
return Zotero.HTTP.promise("GET", url, {"responseType":"document"})
|
||||
.then(function(xmlhttp) {
|
||||
return _checkCaptchaOK(xmlhttp, tries);
|
||||
},
|
||||
function(e) {
|
||||
return _checkCaptchaError(e, tries);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract CAPTCHA form-related data from the CAPTCHA page
|
||||
* @private
|
||||
* @param {Document} doc DOM document object for the CAPTCHA page
|
||||
* @return {Object} Object containing data describing CAPTCHA form
|
||||
*/
|
||||
function _extractCaptchaFormData(doc) {
|
||||
var formData = {};
|
||||
|
||||
var img = doc.getElementsByTagName('img')[0];
|
||||
if(!img) return;
|
||||
formData.img = img.src;
|
||||
|
||||
var form = doc.forms[0];
|
||||
if(!form) return;
|
||||
|
||||
formData.action = form.action;
|
||||
formData.input = {};
|
||||
var inputs = form.getElementsByTagName('input');
|
||||
for(var i=0, n=inputs.length; i<n; i++) {
|
||||
if(!inputs[i].name) continue;
|
||||
formData.input[inputs[i].name] = inputs[i].value;
|
||||
}
|
||||
|
||||
formData.continue = "http://scholar.google.com";
|
||||
|
||||
return formData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Google cookies to get the CAPTCHA page to appear
|
||||
* @private
|
||||
* @param {String} host Host of the Google Scholar page (in case it's proxied)
|
||||
* @return {Boolean} Whether any cookies were cleared
|
||||
*/
|
||||
function _clearGSCookies(host) {
|
||||
/* There don't seem to be any negative effects of deleting GDSESS
|
||||
if(!Zotero.isStandalone) {
|
||||
//ask user first
|
||||
var response = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService)
|
||||
.confirm(null, "Clear Google Scholar cookies?",
|
||||
"Google Scholar is attempting to block further queries. We can "
|
||||
+ "clear certain cookies and try again. This may affect some "
|
||||
+ "temporary Google preferences or it may log you out. May we clear"
|
||||
+ " your Google Scholar cookies?");
|
||||
if(!response) return;
|
||||
}*/
|
||||
|
||||
var removed = false, cookies = cookieService.getCookiesFromHost(host);
|
||||
while(cookies.hasMoreElements()) {
|
||||
var cookie = cookies.getNext().QueryInterface(Components.interfaces.nsICookie2);
|
||||
if(["GDSESS", "PREF"].indexOf(cookie.name) !== -1) { // GDSESS doesn't seem to always be enough
|
||||
Zotero.debug("RecognizePDF: Removing cookie " + cookie.name + " for host "
|
||||
+ cookie.host + " and path " + cookie.path);
|
||||
cookieService.remove(cookie.host, cookie.name, cookie.path, false);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!removed) {
|
||||
Zotero.debug("RecognizePDF: No cookies removed");
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
};
|
||||
}
|
219
chrome/content/zotero/recognizePDFDialog.js
Normal file
219
chrome/content/zotero/recognizePDFDialog.js
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2018 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileOverview Tools for automatically retrieving a citation for the given PDF
|
||||
*/
|
||||
|
||||
/**
|
||||
* Front end for recognizing PDFs
|
||||
* @namespace
|
||||
*/
|
||||
|
||||
var Zotero_RecognizePDF_Dialog = new function () {
|
||||
const SUCCESS_IMAGE = 'chrome://zotero/skin/tick.png';
|
||||
const FAILURE_IMAGE = 'chrome://zotero/skin/cross.png';
|
||||
const LOADING_IMAGE = 'chrome://zotero/skin/arrow_refresh.png';
|
||||
|
||||
let _progressWindow = null;
|
||||
let _progressIndicator = null;
|
||||
let _rowIDs = [];
|
||||
|
||||
this.open = function() {
|
||||
if (_progressWindow) {
|
||||
_progressWindow.focus();
|
||||
return;
|
||||
}
|
||||
_progressWindow = window.openDialog('chrome://zotero/content/recognizePDFDialog.xul', '', 'chrome,close=yes,resizable=yes,dependent,dialog,centerscreen');
|
||||
_progressWindow.addEventListener('pageshow', _onWindowLoaded.bind(this), false);
|
||||
};
|
||||
|
||||
function close() {
|
||||
_progressWindow.close();
|
||||
}
|
||||
|
||||
function _getImageByStatus(status) {
|
||||
if (status === Zotero.RecognizePDF.ROW_PROCESSING) {
|
||||
return LOADING_IMAGE;
|
||||
}
|
||||
else if (status === Zotero.RecognizePDF.ROW_FAILED) {
|
||||
return FAILURE_IMAGE;
|
||||
}
|
||||
else if (status === Zotero.RecognizePDF.ROW_SUCCEEDED) {
|
||||
return SUCCESS_IMAGE;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function _rowToTreeItem(row) {
|
||||
let treeitem = _progressWindow.document.createElement('treeitem');
|
||||
treeitem.setAttribute('id', 'item-' + row.id);
|
||||
|
||||
let treerow = _progressWindow.document.createElement('treerow');
|
||||
|
||||
let treecell = _progressWindow.document.createElement('treecell');
|
||||
treecell.setAttribute('id', 'item-' + row.id + '-icon');
|
||||
treecell.setAttribute('src', _getImageByStatus(row.status));
|
||||
|
||||
treerow.appendChild(treecell);
|
||||
|
||||
treecell = _progressWindow.document.createElement('treecell');
|
||||
treecell.setAttribute('label', row.fileName);
|
||||
treerow.appendChild(treecell);
|
||||
|
||||
treecell = _progressWindow.document.createElement('treecell');
|
||||
treecell.setAttribute('id', 'item-' + row.id + '-title');
|
||||
treecell.setAttribute('label', row.message);
|
||||
treerow.appendChild(treecell);
|
||||
|
||||
treeitem.appendChild(treerow);
|
||||
return treeitem;
|
||||
}
|
||||
|
||||
function _onWindowLoaded() {
|
||||
let rows = Zotero.RecognizePDF.getRows();
|
||||
_rowIDs = [];
|
||||
let treechildren = _progressWindow.document.getElementById('treechildren');
|
||||
|
||||
for (let row of rows) {
|
||||
_rowIDs.push(row.id);
|
||||
let treeitem = _rowToTreeItem(row);
|
||||
treechildren.appendChild(treeitem);
|
||||
}
|
||||
|
||||
_progressWindow.document.getElementById('tree').addEventListener('dblclick',
|
||||
function (event) {
|
||||
_onDblClick(event, this);
|
||||
}
|
||||
);
|
||||
|
||||
_progressIndicator = _progressWindow.document.getElementById('progress-indicator');
|
||||
_progressWindow.document.getElementById('cancel-button')
|
||||
.addEventListener('command', function () {
|
||||
close();
|
||||
Zotero.RecognizePDF.cancel();
|
||||
}, false);
|
||||
|
||||
_progressWindow.document.getElementById('minimize-button')
|
||||
.addEventListener('command', function () {
|
||||
close();
|
||||
}, false);
|
||||
|
||||
_progressWindow.document.getElementById('close-button')
|
||||
.addEventListener('command', function () {
|
||||
close();
|
||||
Zotero.RecognizePDF.cancel();
|
||||
}, false);
|
||||
|
||||
_progressWindow.addEventListener('keypress', function (e) {
|
||||
if (e.keyCode === KeyEvent.DOM_VK_ESCAPE) {
|
||||
// If done processing, Esc is equivalent to Close rather than Minimize
|
||||
if (Zotero.RecognizePDF.getTotal() == Zotero.RecognizePDF.getProcessedTotal()) {
|
||||
Zotero.RecognizePDF.cancel();
|
||||
}
|
||||
close();
|
||||
}
|
||||
});
|
||||
|
||||
_progressWindow.addEventListener('unload', function () {
|
||||
Zotero.RecognizePDF.removeListener('rowadded');
|
||||
Zotero.RecognizePDF.removeListener('rowupdated');
|
||||
Zotero.RecognizePDF.removeListener('rowdeleted');
|
||||
_progressWindow = null;
|
||||
_progressIndicator = null;
|
||||
_rowIDs = [];
|
||||
});
|
||||
|
||||
_updateProgress();
|
||||
|
||||
Zotero.RecognizePDF.addListener('rowadded', function (row) {
|
||||
_rowIDs.push(row.id);
|
||||
let treeitem = _rowToTreeItem(row);
|
||||
treechildren.appendChild(treeitem);
|
||||
_updateProgress();
|
||||
});
|
||||
|
||||
Zotero.RecognizePDF.addListener('rowupdated', function (row) {
|
||||
let itemIcon = _progressWindow.document.getElementById('item-' + row.id + '-icon');
|
||||
let itemTitle = _progressWindow.document.getElementById('item-' + row.id + '-title');
|
||||
|
||||
itemIcon.setAttribute('src', _getImageByStatus(row.status));
|
||||
itemTitle.setAttribute('label', row.message);
|
||||
_updateProgress();
|
||||
});
|
||||
|
||||
Zotero.RecognizePDF.addListener('rowdeleted', function (row) {
|
||||
_rowIDs.splice(_rowIDs.indexOf(row.id), 1);
|
||||
let treeitem = _progressWindow.document.getElementById('item-' + row.id);
|
||||
treeitem.parentNode.removeChild(treeitem);
|
||||
_updateProgress();
|
||||
});
|
||||
}
|
||||
|
||||
function _updateProgress() {
|
||||
if (!_progressWindow) return;
|
||||
let total = Zotero.RecognizePDF.getTotal();
|
||||
let processed = Zotero.RecognizePDF.getProcessedTotal();
|
||||
_progressIndicator.value = processed * 100 / total;
|
||||
if (processed === total) {
|
||||
_progressWindow.document.getElementById("cancel-button").hidden = true;
|
||||
_progressWindow.document.getElementById("minimize-button").hidden = true;
|
||||
_progressWindow.document.getElementById("close-button").hidden = false;
|
||||
_progressWindow.document.getElementById("label").value = Zotero.getString('recognizePDF.complete.label');
|
||||
}
|
||||
else {
|
||||
_progressWindow.document.getElementById("cancel-button").hidden = false;
|
||||
_progressWindow.document.getElementById("minimize-button").hidden = false;
|
||||
_progressWindow.document.getElementById("close-button").hidden = true;
|
||||
_progressWindow.document.getElementById("label").value = Zotero.getString('recognizePDF.recognizing.label');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus items in Zotero library when double-clicking them in the Retrieve
|
||||
* metadata window.
|
||||
* @param {Event} event
|
||||
* @param {tree} tree XUL tree object
|
||||
* @private
|
||||
*/
|
||||
async function _onDblClick(event, tree) {
|
||||
if (event && tree && event.type === 'dblclick') {
|
||||
let itemID = _rowIDs[tree.treeBoxObject.getRowAt(event.clientX, event.clientY)];
|
||||
if (!itemID) return;
|
||||
|
||||
let item = await Zotero.Items.getAsync(itemID);
|
||||
if (!item) return;
|
||||
|
||||
if (item.parentItemID) itemID = item.parentItemID;
|
||||
|
||||
if (window.ZoteroOverlay) {
|
||||
window.ZoteroOverlay.toggleDisplay(true);
|
||||
}
|
||||
|
||||
window.ZoteroPane.selectItem(itemID, false, true);
|
||||
window.focus();
|
||||
}
|
||||
}
|
||||
};
|
|
@ -6,10 +6,12 @@
|
|||
title="&zotero.progress.title;" width="550" height="230"
|
||||
id="zotero-progress">
|
||||
<vbox style="padding:10px" flex="1">
|
||||
<label id="label" control="progress-indicator" value="&zotero.recognizePDF.recognizing.label;"/>
|
||||
<label id="label" control="progress-indicator" value=""/>
|
||||
<hbox align="center">
|
||||
<progressmeter id="progress-indicator" mode="determined" flex="1"/>
|
||||
<button id="cancel-button" label="&zotero.recognizePDF.cancel.label;"/>
|
||||
<button id="cancel-button" label="&zotero.general.cancel;"/>
|
||||
<button id="minimize-button" label="&zotero.general.minimize;"/>
|
||||
<button id="close-button" label="&zotero.general.close;"/>
|
||||
</hbox>
|
||||
<tree flex="1" id="tree" hidecolumnpicker="true">
|
||||
<treecols>
|
|
@ -236,14 +236,12 @@
|
|||
id="zotero-items-column-hasAttachment" hidden="true"
|
||||
class="treecol-image"
|
||||
label="&zotero.tabs.attachments.label;"
|
||||
src="chrome://zotero/skin/attach-small.png"
|
||||
zotero-persist="width ordinal hidden sortActive sortDirection"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol
|
||||
id="zotero-items-column-numNotes" hidden="true"
|
||||
class="treecol-image"
|
||||
label="&zotero.tabs.notes.label;"
|
||||
src="chrome://zotero/skin/treeitem-note-small.png"
|
||||
zotero-persist="width ordinal hidden sortActive sortDirection"/>
|
||||
</treecols>
|
||||
<treechildren/>
|
||||
|
|
|
@ -55,3 +55,11 @@ window.addEventListener("keypress", function (event) {
|
|||
browser.reloadWithFlags(browser.webNavigation.LOAD_FLAGS_BYPASS_CACHE);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle <label class="text-link />
|
||||
window.addEventListener("click", function (event) {
|
||||
if (event.originalTarget.localName == 'label'
|
||||
&& event.originalTarget.classList.contains('text-link')) {
|
||||
Zotero.launchURL(event.originalTarget.getAttribute('href'));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
<commandset id="mainCommandSet">
|
||||
<!--FILE-->
|
||||
<command id="cmd_close" oncommand="window.close();"/>
|
||||
<command id="cmd_save" oncommand="saveDocument(window.content.document);"/>
|
||||
<command id="cmd_save" oncommand="saveDocument(browser.contentDocument);"/>
|
||||
<command id="cmd_print" oncommand="browser.contentWindow.print()"/>
|
||||
<command id="cmd_quitApplication" oncommand="goQuitApplication();"/>
|
||||
|
||||
|
|
|
@ -37,24 +37,68 @@
|
|||
]>
|
||||
|
||||
<window id="main-window" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||
<script>
|
||||
// Equivalent to Zotero.openMainWindow()
|
||||
function openMainWindow() {
|
||||
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
var chromeURI = prefService.getCharPref('toolkit.defaultChromeURI');
|
||||
var flags = prefService.getCharPref("toolkit.defaultChromeFeatures", "chrome,dialog=no,all");
|
||||
|
||||
var ww = Components.classes['@mozilla.org/embedcomp/window-watcher;1']
|
||||
.getService(Components.interfaces.nsIWindowWatcher);
|
||||
ww.openWindow(null, chromeURI, '_blank', flags, null);
|
||||
}
|
||||
|
||||
function openAbout() {
|
||||
var ww = Components.classes['@mozilla.org/embedcomp/window-watcher;1']
|
||||
.getService(Components.interfaces.nsIWindowWatcher);
|
||||
ww.openWindow(null, 'chrome://zotero/content/about.xul', 'about', 'chrome,dialog=yes', null);
|
||||
}
|
||||
</script>
|
||||
<commandset id="mainCommandSet">
|
||||
<!--FILE-->
|
||||
<command id="cmd_quitApplication" oncommand="goQuitApplication();"/>
|
||||
<command id="cmd_close" disabled="true"/>
|
||||
<command id="minimizeWindow" disabled="true"/>
|
||||
<command id="zoomWindow" disabled="true"/>
|
||||
<command id="cmd_mainWindow" oncommand="openMainWindow();"/>
|
||||
</commandset>
|
||||
|
||||
<keyset id="mainKeyset">
|
||||
<key id="key_close" key="&closeCmd.key;" command="cmd_close" modifiers="accel"/>
|
||||
<key id="key_mainWindow" key="0" command="cmd_mainWindow" modifiers="accel"/>
|
||||
</keyset>
|
||||
|
||||
<menubar id="main-menubar">
|
||||
<menu id="fileMenu" label="&fileMenu.label;" accesskey="&fileMenu.accesskey;">
|
||||
<menupopup id="menu_FilePopup">
|
||||
<menuitem id="aboutName"
|
||||
accesskey="&aboutProduct.accesskey;"
|
||||
label="&aboutProduct.label;"
|
||||
oncommand="Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('navigator:browser').ZoteroPane.openAboutDialog();"/>
|
||||
</menupopup>
|
||||
<!-- This gets moved to the Application menu automatically -->
|
||||
<menuitem id="aboutName"
|
||||
accesskey="&aboutProduct.accesskey;"
|
||||
label="&aboutProduct.label;"
|
||||
oncommand="openAbout()"/>
|
||||
|
||||
<!-- Disabled Close line in File menu, just to show something -->
|
||||
<menuitem id="menu_close"
|
||||
label="&closeCmd.label;"
|
||||
key="key_close"
|
||||
command="cmd_close"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
||||
<menu id="windowMenu" onpopupshowing="">
|
||||
<menupopup>
|
||||
<menuitem command="minimizeWindow" key="key_minimizeWindow"/>
|
||||
<menuitem command="zoomWindow"/>
|
||||
<menuseparator/>
|
||||
<menuitem command="cmd_mainWindow" label="Zotero" key="key_mainWindow"/>
|
||||
<!--
|
||||
Prevent error from macWindowMenuDidShow(), which is called from a built-in
|
||||
nWindowMenuShowing(), when opening menu
|
||||
-->
|
||||
<menuseparator id="sep-window-list" hidden="true"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
</menubar>
|
||||
</window>
|
||||
|
|
|
@ -33,6 +33,11 @@ const ZoteroStandalone = new function() {
|
|||
* Run when standalone window first opens
|
||||
*/
|
||||
this.onLoad = function() {
|
||||
// Fix window without menubar/titlebar when Zotero is closed in full-screen mode in OS X 10.11+
|
||||
if (Zotero.isMac && window.document.documentElement.getAttribute('sizemode') == 'fullscreen') {
|
||||
window.document.documentElement.setAttribute('sizemode', 'normal');
|
||||
}
|
||||
|
||||
Zotero.Promise.try(function () {
|
||||
if(!Zotero) {
|
||||
throw true;
|
||||
|
@ -47,6 +52,13 @@ const ZoteroStandalone = new function() {
|
|||
document.getElementById('menu_errorConsole').hidden = false;
|
||||
}
|
||||
|
||||
document.getElementById('key_copyCitation')
|
||||
.setAttribute('key', Zotero.Keys.getKeyForCommand('copySelectedItemCitationsToClipboard'));
|
||||
document.getElementById('key_copyBibliography')
|
||||
.setAttribute('key', Zotero.Keys.getKeyForCommand('copySelectedItemsToClipboard'));
|
||||
|
||||
ZoteroStandalone.DebugOutput.init();
|
||||
|
||||
Zotero.hideZoteroPaneOverlays();
|
||||
ZoteroPane.init();
|
||||
ZoteroPane.makeVisible();
|
||||
|
@ -125,6 +137,42 @@ const ZoteroStandalone = new function() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
this.updateQuickCopyOptions = function () {
|
||||
var selected = false;
|
||||
try {
|
||||
selected = Zotero.getActiveZoteroPane()
|
||||
.getSelectedItems()
|
||||
.filter(item => item.isRegularItem())
|
||||
.length;
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
var format = Zotero.QuickCopy.getFormatFromURL(Zotero.QuickCopy.lastActiveURL);
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
|
||||
var copyCitation = document.getElementById('menu_copyCitation');
|
||||
var copyBibliography = document.getElementById('menu_copyBibliography');
|
||||
var copyExport = document.getElementById('menu_copyExport');
|
||||
|
||||
copyCitation.hidden = !selected || format.mode != 'bibliography';
|
||||
copyBibliography.hidden = !selected || format.mode != 'bibliography';
|
||||
copyExport.hidden = !selected || format.mode != 'export';
|
||||
if (format.mode == 'export') {
|
||||
try {
|
||||
let obj = Zotero.Translators.get(format.id);
|
||||
copyExport.label = Zotero.getString('quickCopy.copyAs', obj.label);
|
||||
}
|
||||
catch (e) {
|
||||
if (!(e instanceof Zotero.Exception.UnloadedDataException && e.dataType == 'translators')) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
copyExport.hidden = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.updateAddonsPane = function (doc) {
|
||||
// Hide unsigned add-on verification warnings
|
||||
//
|
||||
|
@ -156,12 +204,23 @@ const ZoteroStandalone = new function() {
|
|||
* Handles help menu requests
|
||||
*/
|
||||
this.openHelp = function(type) {
|
||||
if(type === "troubleshooting") {
|
||||
ZoteroPane.loadURI("http://www.zotero.org/support/getting_help");
|
||||
} else if(type === "feedback") {
|
||||
ZoteroPane.loadURI("http://forums.zotero.org/categories/");
|
||||
} else {
|
||||
ZoteroPane.loadURI("http://www.zotero.org/support/");
|
||||
Components.utils.import("resource://zotero/config.js");
|
||||
|
||||
switch (type) {
|
||||
case "troubleshooting":
|
||||
ZoteroPane.loadURI(ZOTERO_CONFIG.TROUBLESHOOTING_URL);
|
||||
break;
|
||||
|
||||
case "feedback":
|
||||
ZoteroPane.loadURI(ZOTERO_CONFIG.FEEDBACK_URL);
|
||||
break;
|
||||
|
||||
case "connectors":
|
||||
ZoteroPane.loadURI(ZOTERO_CONFIG.CONNECTORS_URL);
|
||||
break;
|
||||
|
||||
default:
|
||||
ZoteroPane.loadURI(ZOTERO_CONFIG.SUPPORT_URL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,10 +236,210 @@ const ZoteroStandalone = new function() {
|
|||
*/
|
||||
this.onUnload = function() {
|
||||
ZoteroPane.destroy();
|
||||
goQuitApplication();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ZoteroStandalone.DebugOutput = {
|
||||
_timer: null,
|
||||
|
||||
init: function () {
|
||||
var storing = Zotero.Debug.storing;
|
||||
this._showMenu();
|
||||
this.update();
|
||||
},
|
||||
|
||||
|
||||
toggleStore: function () {
|
||||
Zotero.Debug.setStore(!Zotero.Debug.storing);
|
||||
},
|
||||
|
||||
|
||||
update: function () {
|
||||
var enabled = Zotero.Debug.storing;
|
||||
var lines = Zotero.Debug.count();
|
||||
var empty = lines == 0;
|
||||
|
||||
// Show "Submit" when enabled, but leave disabled until there's output
|
||||
var menuitem = document.getElementById('debug-output-submit');
|
||||
menuitem.hidden = !enabled && empty;
|
||||
menuitem.disabled = empty;
|
||||
|
||||
// Toggle between "Enable" and "Disable"
|
||||
menuitem = document.getElementById('debug-output-enable-disable');
|
||||
menuitem.label = Zotero.getString('general.' + (enabled ? 'disable' : 'enable'));
|
||||
|
||||
// Update line count
|
||||
var str = Zotero.getString('zotero.debugOutputLogging.linesLogged', lines, lines);
|
||||
document.getElementById('debug-output-status').label = str;
|
||||
|
||||
// Enable "Clear" when there's output
|
||||
document.getElementById('debug-output-clear').disabled = empty;
|
||||
},
|
||||
|
||||
|
||||
submit: function () {
|
||||
// 'Zotero' isn't defined yet when this function is created, so do it inline
|
||||
return Zotero.Promise.coroutine(function* () {
|
||||
Zotero.debug("Submitting debug output");
|
||||
|
||||
Components.utils.import("resource://zotero/config.js");
|
||||
|
||||
var url = ZOTERO_CONFIG.REPOSITORY_URL + "report?debug=1";
|
||||
var output = yield Zotero.Debug.get(
|
||||
Zotero.Prefs.get('debug.store.submitSize'),
|
||||
Zotero.Prefs.get('debug.store.submitLineLength')
|
||||
);
|
||||
Zotero.Debug.setStore(false);
|
||||
|
||||
var ps = Services.prompt;
|
||||
try {
|
||||
var xmlhttp = yield Zotero.HTTP.request(
|
||||
"POST",
|
||||
url,
|
||||
{
|
||||
compressBody: true,
|
||||
body: output,
|
||||
logBodyLength: 30,
|
||||
timeout: 15000,
|
||||
requestObserver: function (req) {
|
||||
// Don't fail during tests, with fake XHR
|
||||
if (!req.channel) {
|
||||
return;
|
||||
}
|
||||
req.channel.notificationCallbacks = {
|
||||
onProgress: function (request, context, progress, progressMax) {},
|
||||
|
||||
// nsIInterfaceRequestor
|
||||
getInterface: function (iid) {
|
||||
try {
|
||||
return this.QueryInterface(iid);
|
||||
}
|
||||
catch (e) {
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Components.interfaces.nsISupports) ||
|
||||
iid.equals(Components.interfaces.nsIInterfaceRequestor) ||
|
||||
iid.equals(Components.interfaces.nsIProgressEventSink)) {
|
||||
return this;
|
||||
}
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
let title = Zotero.getString('general.error');
|
||||
let msg;
|
||||
if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
|
||||
msg = Zotero.getString('general.invalidResponseServer');
|
||||
}
|
||||
else if (e instanceof Zotero.HTTP.BrowserOfflineException) {
|
||||
msg = Zotero.getString('general.browserIsOffline', Zotero.appName);
|
||||
}
|
||||
else {
|
||||
msg = Zotero.getString('zotero.debugOutputLogging.dialog.error');
|
||||
}
|
||||
ps.alert(null, title, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
Zotero.debug(xmlhttp.responseText);
|
||||
|
||||
var reported = xmlhttp.responseXML.getElementsByTagName('reported');
|
||||
if (reported.length != 1) {
|
||||
ps.alert(
|
||||
null,
|
||||
Zotero.getString('general.error'),
|
||||
Zotero.getString('general.serverError')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
var reportID = reported[0].getAttribute('reportID');
|
||||
|
||||
var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
|
||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL;
|
||||
var index = ps.confirmEx(
|
||||
null,
|
||||
Zotero.getString('zotero.debugOutputLogging.dialog.title'),
|
||||
Zotero.getString('zotero.debugOutputLogging.dialog.sent', [ZOTERO_CONFIG.DOMAIN_NAME, reportID]),
|
||||
buttonFlags,
|
||||
Zotero.getString('general.copyToClipboard'),
|
||||
null, null, null, {}
|
||||
);
|
||||
if (index == 0) {
|
||||
const helper = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
|
||||
.getService(Components.interfaces.nsIClipboardHelper);
|
||||
helper.copyString("D" + reportID);
|
||||
}
|
||||
|
||||
Zotero.Debug.clear();
|
||||
return true;
|
||||
}.bind(this))();
|
||||
},
|
||||
|
||||
|
||||
view: function () {
|
||||
Zotero.openInViewer("chrome://zotero/content/debugViewer.html", function (doc) {
|
||||
var submitted = false;
|
||||
doc.querySelector('#submit-button').addEventListener('click', function (event) {
|
||||
submitted = true;
|
||||
});
|
||||
doc.querySelector('#clear-button').addEventListener('click', function (event) {
|
||||
Zotero.Debug.clear();
|
||||
});
|
||||
// If output has been submitted, disable logging when window is closed
|
||||
doc.defaultView.addEventListener('unload', function (event) {
|
||||
if (submitted) {
|
||||
Zotero.Debug.setStore(false);
|
||||
Zotero.Debug.clear();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
clear: function () {
|
||||
Zotero.Debug.clear();
|
||||
},
|
||||
|
||||
|
||||
restartEnabled: function () {
|
||||
var ps = Services.prompt;
|
||||
var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
|
||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL
|
||||
+ ps.BUTTON_POS_2 * ps.BUTTON_TITLE_IS_STRING;
|
||||
var index = ps.confirmEx(
|
||||
null,
|
||||
Zotero.getString('zotero.debugOutputLogging'),
|
||||
Zotero.getString('zotero.debugOutputLogging.enabledAfterRestart', [Zotero.clientName]),
|
||||
buttonFlags,
|
||||
Zotero.getString('general.restartNow'),
|
||||
null, Zotero.getString('general.restartLater'), null, {}
|
||||
);
|
||||
if (index != 1) {
|
||||
Zotero.Prefs.set('debug.store', true);
|
||||
}
|
||||
if (index == 0) {
|
||||
Zotero.Utilities.Internal.quit(true);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
_showMenu: function () {
|
||||
document.getElementById('debug-output-menu').hidden = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Taken from browser.js **/
|
||||
function toJavaScriptConsole() {
|
||||
toOpenWindowByType("global:console", "chrome://global/content/console.xul");
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
windowtype="navigator:browser"
|
||||
title="&brandShortName;"
|
||||
width="915" height="500"
|
||||
width="1000" height="600"
|
||||
persist="screenX screenY width height sizemode">
|
||||
<script type="application/javascript" src="standalone.js"/>
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||
|
@ -60,7 +60,7 @@
|
|||
<!--EDIT-->
|
||||
<commandset id="editMenuCommands"/>
|
||||
<command id="cmd_find"
|
||||
oncommand="document.getElementById('zotero-tb-search').focus();"/>
|
||||
oncommand="document.getElementById('zotero-tb-search').select()"/>
|
||||
</commandset>
|
||||
|
||||
<keyset id="mainKeyset">
|
||||
|
@ -73,6 +73,12 @@
|
|||
key="&importCmd.key;"
|
||||
command="cmd_zotero_importFromClipboard"
|
||||
modifiers="accel shift alt"/>
|
||||
<key id="key_copyCitation"
|
||||
command="cmd_zotero_copyCitation"
|
||||
modifiers="accel shift"/>
|
||||
<key id="key_copyBibliography"
|
||||
command="cmd_zotero_copyBibliography"
|
||||
modifiers="accel shift"/>
|
||||
</keyset>
|
||||
<keyset id="editMenuKeys"/>
|
||||
|
||||
|
@ -136,17 +142,28 @@
|
|||
</menupopup>
|
||||
</menu>
|
||||
|
||||
<menu id="menu_edit">
|
||||
<menu id="menu_edit"
|
||||
onpopupshowing="ZoteroStandalone.updateQuickCopyOptions()">
|
||||
<menupopup id="menu_EditPopup">
|
||||
<menuitem id="menu_undo"/>
|
||||
<menuitem id="menu_redo"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="menu_cut"/>
|
||||
<menuitem id="menu_copy"/>
|
||||
<menuitem id="menu_copyCitation" label="©CitationCmd.label;"
|
||||
command="cmd_zotero_copyCitation"/>
|
||||
<menuitem id="menu_copyBibliography" label="©BibliographyCmd.label;"
|
||||
command="cmd_zotero_copyBibliography"/>
|
||||
<menuitem id="menu_copyCitation"
|
||||
label="©CitationCmd.label;"
|
||||
command="cmd_zotero_copyCitation"
|
||||
key="key_copyCitation"
|
||||
hidden="true"/>
|
||||
<menuitem id="menu_copyBibliography"
|
||||
label="©BibliographyCmd.label;"
|
||||
command="cmd_zotero_copyBibliography"
|
||||
key="key_copyBibliography"
|
||||
hidden="true"/>
|
||||
<menuitem id="menu_copyExport"
|
||||
key="key_copyBibliography"
|
||||
command="cmd_zotero_copyBibliography"
|
||||
hidden="true"/>
|
||||
<menuitem id="menu_paste"/>
|
||||
<menuitem id="menu_delete"/>
|
||||
<menuseparator/>
|
||||
|
@ -173,6 +190,10 @@
|
|||
<menuitem id="menu_rtfScan" label="&zotero.toolbar.rtfScan.label;"
|
||||
command="cmd_zotero_rtfScan"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="installConnector"
|
||||
accessKey="&installConnector.accesskey;"
|
||||
label="&installConnector.label;"
|
||||
oncommand="ZoteroStandalone.openHelp('connectors');"/>
|
||||
<menuitem id="menu_addons" label="&addons.label;"
|
||||
oncommand="Zotero.openInViewer('chrome://mozapps/content/extensions/extensions.xul', ZoteroStandalone.updateAddonsPane)"/>
|
||||
<menuitem id="menu_errorConsole" label="Error Console" oncommand="toJavaScriptConsole()" hidden="true"/>
|
||||
|
@ -203,6 +224,34 @@
|
|||
accesskey="&helpReportErrors.accesskey;"
|
||||
label="&helpReportErrors.label;"
|
||||
command="cmd_zotero_reportErrors"/>
|
||||
<menu id="debug-output-menu"
|
||||
accesskey="&debugOutputLogging.accesskey;"
|
||||
label="&debugOutputLogging.label;"
|
||||
hidden="true">
|
||||
<menupopup id="debug-output-popup"
|
||||
onpopupshowing="ZoteroStandalone.DebugOutput.update()">
|
||||
<menuitem id="debug-output-submit"
|
||||
label="&debugOutputLogging.submit;"
|
||||
oncommand="ZoteroStandalone.DebugOutput.submit()"
|
||||
hidden="true"/>
|
||||
<menuitem id="debug-output-enable-disable"
|
||||
oncommand="ZoteroStandalone.DebugOutput.toggleStore()"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="debug-output-status" disabled="true"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="debug-output-view"
|
||||
label="&debugOutputLogging.view;"
|
||||
oncommand="ZoteroStandalone.DebugOutput.view()"/>
|
||||
<menuitem id="debug-output-clear"
|
||||
label="&debugOutputLogging.clear;"
|
||||
oncommand="ZoteroStandalone.DebugOutput.clear()"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="debug-output-restart-enabled"
|
||||
label="&debugOutputLogging.restartWithLoggingEnabled;"
|
||||
oncommand="ZoteroStandalone.DebugOutput.restartEnabled()"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
<menuseparator/>
|
||||
<menuitem id="checkForUpdates"
|
||||
accesskey="&helpCheckForUpdates.accesskey;"
|
||||
label="&helpCheckForUpdates.label;"
|
||||
|
|
|
@ -52,9 +52,9 @@ var Zotero_Tag_Color_Chooser = new function() {
|
|||
colorPicker.setAttribute('tileWidth', 24);
|
||||
colorPicker.setAttribute('tileHeight', 24);
|
||||
colorPicker.colors = [
|
||||
'#990000', '#CC9933', '#FF9900',
|
||||
'#FFCC00', '#007439', '#1049A9',
|
||||
'#9999FF', '#CC66CC', '#993399'
|
||||
'#FF6666', '#FF8C19', '#999999',
|
||||
'#5FB236', '#009980', '#2EA8E5',
|
||||
'#576DD9', '#A28AE5', '#A6507B'
|
||||
];
|
||||
|
||||
var maxTags = document.getElementById('max-tags');
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
for (let type of types) {
|
||||
var fieldIDs = Zotero.ItemFields.getItemTypeFields(type.id);
|
||||
var baseFields = {};
|
||||
for (let fieldID in fieldIDs) {
|
||||
for (let fieldID of fieldIDs) {
|
||||
if (baseMappedFields.includes(fieldID)) {
|
||||
baseFields[fieldID] = Zotero.ItemFields.getBaseIDFromTypeAndField(type.id, fieldID);
|
||||
}
|
||||
|
|
|
@ -157,6 +157,7 @@ var Zotero_CSL_Editor = new function() {
|
|||
|
||||
this.generateBibliography = function(style) {
|
||||
var iframe = document.getElementById('zotero-csl-preview-box');
|
||||
var editor = document.getElementById('zotero-csl-editor');
|
||||
|
||||
var items = Zotero.getActiveZoteroPane().getSelectedItems();
|
||||
if (items.length == 0) {
|
||||
|
@ -228,6 +229,7 @@ var Zotero_CSL_Editor = new function() {
|
|||
iframe.contentDocument.documentElement.innerHTML = '<div>' + Zotero.getString('styles.editor.warning.renderError') + '</div><div>'+e+'</div>';
|
||||
throw e;
|
||||
}
|
||||
editor.styleEngine = styleEngine;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ var Zotero_TranslatorTesters = new function() {
|
|||
try {
|
||||
for(var i=0; i<translators.length; i++) {
|
||||
if (includeTranslators.length
|
||||
&& !includeTranslators.includes(translators[i].label)) continue;
|
||||
&& !includeTranslators.some(x => translators[i].label.includes(x))) continue;
|
||||
if (skipTranslators && skipTranslators[translators[i].translatorID]) continue;
|
||||
testers.push(new Zotero_TranslatorTester(translators[i], type));
|
||||
};
|
||||
|
@ -298,10 +298,18 @@ Zotero_TranslatorTester._sanitizeItem = function(item, testItem, keepValidFields
|
|||
|
||||
// remove fields to be ignored
|
||||
if(!keepValidFields && "accessDate" in item) delete item.accessDate;
|
||||
|
||||
//sort tags, if they're still there
|
||||
if(item.tags && typeof item.tags === "object" && "sort" in item.tags) {
|
||||
item.tags = Zotero.Utilities.arrayUnique(item.tags).sort();
|
||||
|
||||
// Sort tags
|
||||
if (item.tags && Array.isArray(item.tags)) {
|
||||
// Normalize tags -- necessary until tests are updated for 5.0
|
||||
if (testItem) {
|
||||
item.tags = Zotero.Translate.Base.prototype._cleanTags(item.tags);
|
||||
}
|
||||
item.tags.sort((a, b) => {
|
||||
if (a.tag < b.tag) return -1;
|
||||
if (b.tag < a.tag) return 1;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
return item;
|
||||
|
@ -391,54 +399,25 @@ Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallba
|
|||
|
||||
/**
|
||||
* Fetches the page for a given test and runs it
|
||||
*
|
||||
* This function is only applicable in Firefox; it is overridden in translator_global.js in Chrome
|
||||
* and Safari
|
||||
* @param {Object} test Test to execute
|
||||
* @param {Document} doc DOM document to test against
|
||||
* @param {Function} testDoneCallback A callback to be executed when test is complete
|
||||
* and Safari.
|
||||
*
|
||||
* @param {Object} test - Test to execute
|
||||
* @param {Function} testDoneCallback - A callback to be executed when test is complete
|
||||
*/
|
||||
Zotero_TranslatorTester.prototype.fetchPageAndRunTest = function(test, testDoneCallback) {
|
||||
var timer = Components.classes["@mozilla.org/timer;1"].
|
||||
createInstance(Components.interfaces.nsITimer);
|
||||
timer.initWithCallback({"notify":function() {
|
||||
try {
|
||||
if (hiddenBrowser) Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
||||
} catch(e) {}
|
||||
}}, TEST_RUN_TIMEOUT, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||
|
||||
var me = this;
|
||||
var runTest = function(doc) {
|
||||
me.runTest(test, doc, function(obj, test, status, message) {
|
||||
try {
|
||||
timer.cancel();
|
||||
} catch(e) {};
|
||||
if(hiddenBrowser) Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
||||
testDoneCallback(obj, test, status, message);
|
||||
});
|
||||
};
|
||||
var hiddenBrowser = Zotero.HTTP.processDocuments(test.url,
|
||||
function(doc) {
|
||||
if(test.defer) {
|
||||
me._debug(this, "TranslatorTesting: Waiting "
|
||||
+ (Zotero_TranslatorTester.DEFER_DELAY/1000)
|
||||
+ " second(s) for page content to settle"
|
||||
);
|
||||
Zotero.setTimeout(() => runTest(doc), Zotero_TranslatorTester.DEFER_DELAY);
|
||||
} else {
|
||||
runTest(doc);
|
||||
}
|
||||
},
|
||||
null,
|
||||
function(e) {
|
||||
testDoneCallback(this, test, "failed", "Translation failed to initialize: "+e);
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
// No hidden browser returned from translation-server processDocuments()
|
||||
if (hiddenBrowser) {
|
||||
hiddenBrowser.docShell.allowMetaRedirects = true;
|
||||
}
|
||||
Zotero_TranslatorTester.prototype.fetchPageAndRunTest = function (test, testDoneCallback) {
|
||||
Zotero.HTTP.processDocuments(
|
||||
test.url,
|
||||
(doc) => {
|
||||
this.runTest(test, doc, function (obj, test, status, message) {
|
||||
testDoneCallback(obj, test, status, message);
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(function (e) {
|
||||
testDoneCallback(this, test, "failed", "Translation failed to initialize: " + e);
|
||||
}.bind(this))
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -531,7 +510,9 @@ Zotero_TranslatorTester.prototype._runTestTranslate = function(translate, transl
|
|||
}
|
||||
|
||||
translate.setTranslator(this.translator);
|
||||
translate.translate(false);
|
||||
translate.translate({
|
||||
libraryID: false
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -628,7 +609,9 @@ Zotero_TranslatorTester.prototype.newTest = function(doc, testReadyCallback) {
|
|||
});
|
||||
translate.setHandler("done", function(obj, returnValue) { me._createTest(obj, multipleMode, returnValue, testReadyCallback) });
|
||||
translate.capitalizeTitles = false;
|
||||
translate.translate(false);
|
||||
translate.translate({
|
||||
libraryID: false
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -154,7 +154,7 @@ Zotero.API = {
|
|||
return 'groups/' + Zotero.Groups.getGroupIDFromLibraryID(libraryID);
|
||||
|
||||
default:
|
||||
throw new Error(`Invalid type '${type}`);
|
||||
throw new Error(`Invalid type '${type}'`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
|
||||
Zotero.Attachments = new function(){
|
||||
// Keep in sync with Zotero.Schema.integrityCheck()
|
||||
this.LINK_MODE_IMPORTED_FILE = 0;
|
||||
this.LINK_MODE_IMPORTED_URL = 1;
|
||||
this.LINK_MODE_LINKED_FILE = 2;
|
||||
|
@ -39,6 +40,9 @@ Zotero.Attachments = new function(){
|
|||
* @param {Integer} [options.libraryID]
|
||||
* @param {Integer[]|String[]} [options.parentItemID] - Parent item to add item to
|
||||
* @param {Integer[]} [options.collections] - Collection keys or ids to add new item to
|
||||
* @param {String} [options.fileBaseName]
|
||||
* @param {String} [options.contentType]
|
||||
* @param {String} [options.charset]
|
||||
* @param {Object} [options.saveOptions] - Options to pass to Zotero.Item::save()
|
||||
* @return {Promise<Zotero.Item>}
|
||||
*/
|
||||
|
@ -47,13 +51,24 @@ Zotero.Attachments = new function(){
|
|||
|
||||
var libraryID = options.libraryID;
|
||||
var file = Zotero.File.pathToFile(options.file);
|
||||
var path = file.path;
|
||||
var leafName = file.leafName;
|
||||
var parentItemID = options.parentItemID;
|
||||
var collections = options.collections;
|
||||
var fileBaseName = options.fileBaseName;
|
||||
var contentType = options.contentType;
|
||||
var charset = options.charset;
|
||||
var saveOptions = options.saveOptions;
|
||||
|
||||
var newName = Zotero.File.getValidFileName(file.leafName);
|
||||
if (fileBaseName) {
|
||||
let ext = Zotero.File.getExtension(path);
|
||||
var newName = fileBaseName + (ext != '' ? '.' + ext : '');
|
||||
}
|
||||
else {
|
||||
var newName = Zotero.File.getValidFileName(OS.Path.basename(leafName));
|
||||
}
|
||||
|
||||
if (file.leafName.endsWith(".lnk")) {
|
||||
if (leafName.endsWith(".lnk")) {
|
||||
throw new Error("Cannot add Windows shortcut");
|
||||
}
|
||||
if (parentItemID && collections) {
|
||||
|
@ -90,9 +105,15 @@ Zotero.Attachments = new function(){
|
|||
// Copy file to unique filename, which automatically shortens long filenames
|
||||
newFile = Zotero.File.copyToUnique(file, newFile);
|
||||
|
||||
contentType = yield Zotero.MIME.getMIMETypeFromFile(newFile);
|
||||
yield Zotero.File.setNormalFilePermissions(newFile.path);
|
||||
|
||||
if (!contentType) {
|
||||
contentType = yield Zotero.MIME.getMIMETypeFromFile(newFile);
|
||||
}
|
||||
attachmentItem.attachmentContentType = contentType;
|
||||
if (charset) {
|
||||
attachmentItem.attachmentCharset = charset;
|
||||
}
|
||||
attachmentItem.attachmentPath = newFile.path;
|
||||
yield attachmentItem.save(saveOptions);
|
||||
}.bind(this));
|
||||
|
@ -155,13 +176,18 @@ Zotero.Attachments = new function(){
|
|||
|
||||
|
||||
/**
|
||||
* @param {Object} options - 'file', 'url', 'title', 'contentType', 'charset', 'parentItemID'
|
||||
* @param {Object} options - 'file', 'url', 'title', 'contentType', 'charset', 'parentItemID', 'singleFile'
|
||||
* @return {Promise<Zotero.Item>}
|
||||
*/
|
||||
this.importSnapshotFromFile = Zotero.Promise.coroutine(function* (options) {
|
||||
Zotero.debug('Importing snapshot from file');
|
||||
|
||||
var file = Zotero.File.pathToFile(options.file);
|
||||
// TODO: Fix main filename when copying directory, though in that case it's probably
|
||||
// from our own export and already clean
|
||||
var fileName = options.singleFile
|
||||
? Zotero.File.getValidFileName(file.leafName)
|
||||
: file.leafName;
|
||||
var url = options.url;
|
||||
var title = options.title;
|
||||
var contentType = options.contentType;
|
||||
|
@ -172,7 +198,7 @@ Zotero.Attachments = new function(){
|
|||
throw new Error("parentItemID not provided");
|
||||
}
|
||||
|
||||
var attachmentItem, itemID, destDir, newFile;
|
||||
var attachmentItem, itemID, destDir, newPath;
|
||||
try {
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
// Create a new attachment
|
||||
|
@ -185,6 +211,7 @@ Zotero.Attachments = new function(){
|
|||
attachmentItem.attachmentLinkMode = this.LINK_MODE_IMPORTED_URL;
|
||||
attachmentItem.attachmentContentType = contentType;
|
||||
attachmentItem.attachmentCharset = charset;
|
||||
attachmentItem.attachmentPath = 'storage:' + fileName;
|
||||
|
||||
// DEBUG: this should probably insert access date too so as to
|
||||
// create a proper item, but at the moment this is only called by
|
||||
|
@ -194,16 +221,23 @@ Zotero.Attachments = new function(){
|
|||
var storageDir = Zotero.getStorageDirectory();
|
||||
destDir = this.getStorageDirectory(attachmentItem);
|
||||
yield OS.File.removeDir(destDir.path);
|
||||
file.parent.copyTo(storageDir, destDir.leafName);
|
||||
|
||||
// Point to copied file
|
||||
newFile = destDir.clone();
|
||||
newFile.append(file.leafName);
|
||||
|
||||
attachmentItem.attachmentPath = newFile.path;
|
||||
yield attachmentItem.save();
|
||||
newPath = OS.Path.join(destDir.path, fileName);
|
||||
// Copy single file to new directory
|
||||
if (options.singleFile) {
|
||||
yield this.createDirectoryForItem(attachmentItem);
|
||||
yield OS.File.copy(file.path, newPath);
|
||||
}
|
||||
// Copy entire parent directory (for HTML snapshots)
|
||||
else {
|
||||
file.parent.copyTo(storageDir, destDir.leafName);
|
||||
}
|
||||
}.bind(this));
|
||||
yield _postProcessFile(attachmentItem, newFile, contentType, charset);
|
||||
yield _postProcessFile(
|
||||
attachmentItem,
|
||||
Zotero.File.pathToFile(newPath),
|
||||
contentType,
|
||||
charset
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
|
@ -225,8 +259,18 @@ Zotero.Attachments = new function(){
|
|||
|
||||
|
||||
/**
|
||||
* @param {Object} options - 'libraryID', 'url', 'parentItemID', 'collections', 'title',
|
||||
* 'fileBaseName', 'contentType', 'cookieSandbox', 'saveOptions'
|
||||
* @param {Object} options
|
||||
* @param {Integer} options.libraryID
|
||||
* @param {String} options.url
|
||||
* @param {Integer} [options.parentItemID]
|
||||
* @param {Integer[]} [options.collections]
|
||||
* @param {String} [options.title]
|
||||
* @param {String} [options.fileBaseName]
|
||||
* @param {Boolean} [options.renameIfAllowedType=false]
|
||||
* @param {String} [options.contentType]
|
||||
* @param {String} [options.referrer]
|
||||
* @param {CookieSandbox} [options.cookieSandbox]
|
||||
* @param {Object} [options.saveOptions]
|
||||
* @return {Promise<Zotero.Item>} - A promise for the created attachment item
|
||||
*/
|
||||
this.importFromURL = Zotero.Promise.coroutine(function* (options) {
|
||||
|
@ -236,7 +280,9 @@ Zotero.Attachments = new function(){
|
|||
var collections = options.collections;
|
||||
var title = options.title;
|
||||
var fileBaseName = options.fileBaseName;
|
||||
var renameIfAllowedType = options.renameIfAllowedType;
|
||||
var contentType = options.contentType;
|
||||
var referrer = options.referrer;
|
||||
var cookieSandbox = options.cookieSandbox;
|
||||
var saveOptions = options.saveOptions;
|
||||
|
||||
|
@ -258,7 +304,7 @@ Zotero.Attachments = new function(){
|
|||
// Save using a hidden browser
|
||||
var nativeHandlerImport = function () {
|
||||
return new Zotero.Promise(function (resolve, reject) {
|
||||
var browser = Zotero.HTTP.processDocuments(
|
||||
var browser = Zotero.HTTP.loadDocuments(
|
||||
url,
|
||||
Zotero.Promise.coroutine(function* () {
|
||||
let channel = browser.docShell.currentDocumentChannel;
|
||||
|
@ -266,7 +312,7 @@ Zotero.Attachments = new function(){
|
|||
if (channel.responseStatus < 200 || channel.responseStatus >= 400) {
|
||||
reject(new Error("Invalid response " + channel.responseStatus + " "
|
||||
+ channel.responseStatusText + " for '" + url + "'"));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
@ -298,6 +344,11 @@ Zotero.Attachments = new function(){
|
|||
|
||||
// Save using remote web browser persist
|
||||
var externalHandlerImport = Zotero.Promise.coroutine(function* (contentType) {
|
||||
// Rename attachment
|
||||
if (renameIfAllowedType && !fileBaseName && this.getRenamedFileTypes().includes(contentType)) {
|
||||
let parentItem = Zotero.Items.get(parentItemID);
|
||||
fileBaseName = this.getFileBaseNameFromItem(parentItem);
|
||||
}
|
||||
if (fileBaseName) {
|
||||
let ext = _getExtensionFromURL(url, contentType);
|
||||
var fileName = fileBaseName + (ext != '' ? '.' + ext : '');
|
||||
|
@ -309,16 +360,14 @@ Zotero.Attachments = new function(){
|
|||
const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
|
||||
var wbp = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
|
||||
.createInstance(nsIWBP);
|
||||
wbp.persistFlags = nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
|
||||
if(cookieSandbox) cookieSandbox.attachToInterfaceRequestor(wbp);
|
||||
var encodingFlags = false;
|
||||
|
||||
// Create a temporary directory to save to within the storage directory.
|
||||
// We don't use the normal temp directory because people might have 'storage'
|
||||
// symlinked to another volume, which makes moving complicated.
|
||||
var tmpDir = yield this.createTemporaryStorageDirectory();
|
||||
var tmpFile = tmpDir.clone();
|
||||
tmpFile.append(fileName);
|
||||
var tmpDir = (yield this.createTemporaryStorageDirectory()).path;
|
||||
var tmpFile = OS.Path.join(tmpDir, fileName);
|
||||
|
||||
// Save to temp dir
|
||||
var deferred = Zotero.Promise.defer();
|
||||
|
@ -329,10 +378,15 @@ Zotero.Attachments = new function(){
|
|||
var nsIURL = Components.classes["@mozilla.org/network/standard-url;1"]
|
||||
.createInstance(Components.interfaces.nsIURL);
|
||||
nsIURL.spec = url;
|
||||
Zotero.Utilities.Internal.saveURI(wbp, nsIURL, tmpFile);
|
||||
var headers = {};
|
||||
if (referrer) {
|
||||
headers.Referer = referrer;
|
||||
}
|
||||
Zotero.Utilities.Internal.saveURI(wbp, nsIURL, tmpFile, headers);
|
||||
|
||||
|
||||
yield deferred.promise;
|
||||
let sample = yield Zotero.File.getSample(tmpFile);
|
||||
let sample = yield Zotero.File.getContentsAsync(tmpFile, null, 1000);
|
||||
try {
|
||||
if (contentType == 'application/pdf' &&
|
||||
Zotero.MIME.sniffForMIMEType(sample) != 'application/pdf') {
|
||||
|
@ -366,25 +420,22 @@ Zotero.Attachments = new function(){
|
|||
if (collections) {
|
||||
attachmentItem.setCollections(collections);
|
||||
}
|
||||
attachmentItem.attachmentPath = 'storage:' + fileName;
|
||||
var itemID = yield attachmentItem.save(saveOptions);
|
||||
|
||||
// Create a new folder for this item in the storage directory
|
||||
destDir = this.getStorageDirectory(attachmentItem);
|
||||
yield OS.File.move(tmpDir.path, destDir.path);
|
||||
var destFile = destDir.clone();
|
||||
destFile.append(fileName);
|
||||
|
||||
// Refetch item to update path
|
||||
attachmentItem.attachmentPath = destFile.path;
|
||||
yield attachmentItem.save(saveOptions);
|
||||
|
||||
Zotero.Fulltext.queueItem(attachmentItem);
|
||||
|
||||
// DEBUG: Does this fail if 'storage' is symlinked to another drive?
|
||||
destDir = this.getStorageDirectory(attachmentItem).path;
|
||||
yield OS.File.move(tmpDir, destDir);
|
||||
}.bind(this));
|
||||
} catch (e) {
|
||||
try {
|
||||
if (tmpDir && tmpDir.exists()) {
|
||||
tmpDir.remove(true);
|
||||
if (tmpDir) {
|
||||
yield OS.File.removeDir(tmpDir, { ignoreAbsent: true });
|
||||
}
|
||||
if (destDir && destDir.exists()) {
|
||||
destDir.remove(true);
|
||||
if (destDir) {
|
||||
yield OS.File.removeDir(destDir, { ignoreAbsent: true });
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -393,16 +444,6 @@ Zotero.Attachments = new function(){
|
|||
throw e;
|
||||
}
|
||||
|
||||
// We don't have any way of knowing that the file is flushed to disk,
|
||||
// so we just wait a second before indexing and hope for the best.
|
||||
// We'll index it later if it fails. (This may not be necessary.)
|
||||
//
|
||||
// If this is removed, the afterEach() delay in the server_connector /connector/saveSnapshot
|
||||
// tests can also be removed.
|
||||
setTimeout(function () {
|
||||
Zotero.Fulltext.indexItems([attachmentItem.id]);
|
||||
}, 1000);
|
||||
|
||||
return attachmentItem;
|
||||
}.bind(this));
|
||||
|
||||
|
@ -573,11 +614,10 @@ Zotero.Attachments = new function(){
|
|||
contentType = "application/pdf";
|
||||
}
|
||||
|
||||
var tmpDir = yield this.createTemporaryStorageDirectory();
|
||||
var tmpDir = (yield this.createTemporaryStorageDirectory()).path;
|
||||
try {
|
||||
var tmpFile = tmpDir.clone();
|
||||
var fileName = Zotero.File.truncateFileName(_getFileNameFromURL(url, contentType), 100);
|
||||
tmpFile.append(fileName);
|
||||
var tmpFile = OS.Path.join(tmpDir, fileName);
|
||||
|
||||
// If we're using the title from the document, make some adjustments
|
||||
if (!options.title) {
|
||||
|
@ -592,17 +632,18 @@ Zotero.Attachments = new function(){
|
|||
}
|
||||
}
|
||||
|
||||
if (contentType === 'text/html' || contentType === 'application/xhtml+xml') {
|
||||
if ((contentType === 'text/html' || contentType === 'application/xhtml+xml')
|
||||
// Documents from XHR don't work here
|
||||
&& document instanceof Ci.nsIDOMDocument) {
|
||||
Zotero.debug('Saving document with saveDocument()');
|
||||
yield Zotero.Utilities.Internal.saveDocument(document, tmpFile.path);
|
||||
yield Zotero.Utilities.Internal.saveDocument(document, tmpFile);
|
||||
}
|
||||
else {
|
||||
Zotero.debug("Saving file with saveURI()");
|
||||
const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
|
||||
var wbp = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
|
||||
.createInstance(nsIWBP);
|
||||
wbp.persistFlags = nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION
|
||||
| nsIWBP.PERSIST_FLAGS_FROM_CACHE;
|
||||
wbp.persistFlags = nsIWBP.PERSIST_FLAGS_FROM_CACHE;
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
var nsIURL = ioService.newURI(url, null, null);
|
||||
|
@ -637,16 +678,14 @@ Zotero.Attachments = new function(){
|
|||
if (collections && collections.length) {
|
||||
attachmentItem.setCollections(collections);
|
||||
}
|
||||
attachmentItem.attachmentPath = 'storage:' + fileName;
|
||||
var itemID = yield attachmentItem.save();
|
||||
|
||||
// Create a new folder for this item in the storage directory
|
||||
destDir = this.getStorageDirectory(attachmentItem);
|
||||
yield OS.File.move(tmpDir.path, destDir.path);
|
||||
var destFile = destDir.clone();
|
||||
destFile.append(fileName);
|
||||
Zotero.Fulltext.queueItem(attachmentItem);
|
||||
|
||||
attachmentItem.attachmentPath = destFile.path;
|
||||
yield attachmentItem.save();
|
||||
// DEBUG: Does this fail if 'storage' is symlinked to another drive?
|
||||
destDir = this.getStorageDirectory(attachmentItem).path;
|
||||
yield OS.File.move(tmpDir, destDir);
|
||||
}.bind(this));
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -654,11 +693,11 @@ Zotero.Attachments = new function(){
|
|||
|
||||
// Clean up
|
||||
try {
|
||||
if (tmpDir && tmpDir.exists()) {
|
||||
tmpDir.remove(true);
|
||||
if (tmpDir) {
|
||||
yield OS.File.removeDir(tmpDir, { ignoreAbsent: true });
|
||||
}
|
||||
if (destDir && destDir.exists()) {
|
||||
destDir.remove(true);
|
||||
if (destDir) {
|
||||
yield OS.File.removeDir(destDir, { ignoreAbsent: true });
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -668,21 +707,6 @@ Zotero.Attachments = new function(){
|
|||
throw e;
|
||||
}
|
||||
|
||||
// We don't have any way of knowing that the file is flushed to disk,
|
||||
// so we just wait a second before indexing and hope for the best.
|
||||
// We'll index it later if it fails. (This may not be necessary.)
|
||||
if (contentType == 'application/pdf') {
|
||||
setTimeout(function () {
|
||||
Zotero.Fulltext.indexPDF(attachmentItem.getFilePath(), attachmentItem.id);
|
||||
}, 1000);
|
||||
}
|
||||
else if (Zotero.MIME.isTextType(contentType)) {
|
||||
// wbp.saveDocument consumes the document context (in Zotero.Utilities.Internal.saveDocument)
|
||||
// Seems like a mozilla bug, but nothing on bugtracker.
|
||||
// Either way, we don't rely on Zotero.Fulltext.indexDocument here anymore
|
||||
yield Zotero.Fulltext.indexItems(attachmentItem.id, true, true);
|
||||
}
|
||||
|
||||
return attachmentItem;
|
||||
});
|
||||
|
||||
|
@ -788,6 +812,30 @@ Zotero.Attachments = new function(){
|
|||
}
|
||||
|
||||
|
||||
this.getRenamedFileTypes = function () {
|
||||
try {
|
||||
var types = Zotero.Prefs.get('autoRenameFiles.fileTypes');
|
||||
return types ? types.split(',') : [];
|
||||
}
|
||||
catch (e) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.getRenamedFileBaseNameIfAllowedType = async function (parentItem, file) {
|
||||
var types = this.getRenamedFileTypes();
|
||||
var contentType = file.endsWith('.pdf')
|
||||
// Don't bother reading file if there's a .pdf extension
|
||||
? 'application/pdf'
|
||||
: await Zotero.MIME.getMIMETypeFromFile(file);
|
||||
if (!types.includes(contentType)) {
|
||||
return false;
|
||||
}
|
||||
return this.getFileBaseNameFromItem(parentItem);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create directory for attachment files within storage directory
|
||||
*
|
||||
|
@ -874,14 +922,15 @@ Zotero.Attachments = new function(){
|
|||
}
|
||||
|
||||
if (Zotero.File.directoryContains(basePath, path)) {
|
||||
basePath = OS.Path.normalize(basePath);
|
||||
path = OS.Path.normalize(path);
|
||||
path = this.BASE_PATH_PLACEHOLDER
|
||||
+ path.substr(basePath.length + 1)
|
||||
// Since stored paths can be synced to other platforms, use
|
||||
// forward slashes for consistency. resolveRelativePath() will
|
||||
// convert to the appropriate platform-specific slash on use.
|
||||
.replace(/\\/g, "/");
|
||||
// Since stored paths can be synced to other platforms, use forward slashes for consistency.
|
||||
// resolveRelativePath() will convert to the appropriate platform-specific slash on use.
|
||||
basePath = OS.Path.normalize(basePath).replace(/\\/g, "/");
|
||||
path = OS.Path.normalize(path).replace(/\\/g, "/");
|
||||
// Normalize D:\ vs. D:\foo
|
||||
if (!basePath.endsWith('/')) {
|
||||
basePath += '/';
|
||||
}
|
||||
path = this.BASE_PATH_PLACEHOLDER + path.substr(basePath.length)
|
||||
}
|
||||
|
||||
return path;
|
||||
|
@ -957,11 +1006,13 @@ Zotero.Attachments = new function(){
|
|||
}
|
||||
}
|
||||
catch (e) {
|
||||
iterator.close();
|
||||
if (e != StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
iterator.close();
|
||||
}
|
||||
return numFiles > 1;
|
||||
});
|
||||
|
||||
|
@ -1078,13 +1129,75 @@ Zotero.Attachments = new function(){
|
|||
|
||||
|
||||
/**
|
||||
* Copy attachment item, including files, to another library
|
||||
* Move attachment item, including file, to another library
|
||||
*/
|
||||
this.moveAttachmentToLibrary = async function (attachment, libraryID, parentItemID) {
|
||||
if (attachment.libraryID == libraryID) {
|
||||
throw new Error("Attachment is already in library " + libraryID);
|
||||
}
|
||||
|
||||
Zotero.DB.requireTransaction();
|
||||
|
||||
var newAttachment = attachment.clone(libraryID);
|
||||
if (attachment.isImportedAttachment()) {
|
||||
// Attachment path isn't copied over by clone() if libraryID is different
|
||||
newAttachment.attachmentPath = attachment.attachmentPath;
|
||||
}
|
||||
if (parentItemID) {
|
||||
newAttachment.parentID = parentItemID;
|
||||
}
|
||||
await newAttachment.save();
|
||||
|
||||
// Move files over if they exist
|
||||
var oldDir;
|
||||
var newDir;
|
||||
if (newAttachment.isImportedAttachment()) {
|
||||
oldDir = this.getStorageDirectory(attachment).path;
|
||||
if (await OS.File.exists(oldDir)) {
|
||||
newDir = this.getStorageDirectory(newAttachment).path;
|
||||
// Target directory shouldn't exist, but remove it if it does
|
||||
//
|
||||
// Testing for directories in OS.File, used by removeDir(), is broken on Travis,
|
||||
// so use nsIFile
|
||||
if (Zotero.automatedTest) {
|
||||
let nsIFile = Zotero.File.pathToFile(newDir);
|
||||
if (nsIFile.exists()) {
|
||||
nsIFile.remove(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
await OS.File.removeDir(newDir, { ignoreAbsent: true });
|
||||
}
|
||||
await OS.File.move(oldDir, newDir);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await attachment.erase();
|
||||
}
|
||||
catch (e) {
|
||||
// Move files back if old item can't be deleted
|
||||
if (newAttachment.isImportedAttachment()) {
|
||||
try {
|
||||
await OS.File.move(newDir, oldDir);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
return newAttachment.id;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Copy attachment item, including file, to another library
|
||||
*/
|
||||
this.copyAttachmentToLibrary = Zotero.Promise.coroutine(function* (attachment, libraryID, parentItemID) {
|
||||
var linkMode = attachment.attachmentLinkMode;
|
||||
|
||||
if (attachment.libraryID == libraryID) {
|
||||
throw ("Attachment is already in library " + libraryID);
|
||||
throw new Error("Attachment is already in library " + libraryID);
|
||||
}
|
||||
|
||||
Zotero.DB.requireTransaction();
|
||||
|
|
|
@ -16,13 +16,13 @@ Zotero.Cite = {
|
|||
* Remove specified item IDs in-place from a citeproc-js bibliography object returned
|
||||
* by makeBibliography()
|
||||
* @param {bib} citeproc-js bibliography object
|
||||
* @param {Array} itemsToRemove Array of items to remove
|
||||
* @param {Set} itemsToRemove Set of items to remove
|
||||
*/
|
||||
"removeFromBibliography":function(bib, itemsToRemove) {
|
||||
var removeItems = [];
|
||||
for(let i in bib[0].entry_ids) {
|
||||
for(let j in bib[0].entry_ids[i]) {
|
||||
if(itemsToRemove[bib[0].entry_ids[i][j]]) {
|
||||
if(itemsToRemove.has(`${bib[0].entry_ids[i][j]}`)) {
|
||||
removeItems.push(i);
|
||||
break;
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ Zotero.Cite = {
|
|||
var sessionID = id.substr(0, slashIndex),
|
||||
session = Zotero.Integration.sessions[sessionID],
|
||||
item;
|
||||
if(session) {
|
||||
if (session) {
|
||||
item = session.embeddedZoteroItems[id.substr(slashIndex+1)];
|
||||
}
|
||||
|
||||
|
@ -315,6 +315,104 @@ Zotero.Cite = {
|
|||
} else {
|
||||
return Zotero.Items.get(id);
|
||||
}
|
||||
},
|
||||
|
||||
extraToCSL: function (extra) {
|
||||
return extra.replace(/^([A-Za-z \-]+)(:\s*.+)/gm, function (_, field, value) {
|
||||
var originalField = field;
|
||||
var field = field.toLowerCase().replace(/ /g, '-');
|
||||
// Fields from https://aurimasv.github.io/z2csl/typeMap.xml
|
||||
switch (field) {
|
||||
// Standard fields
|
||||
case 'abstract':
|
||||
case 'accessed':
|
||||
case 'annote':
|
||||
case 'archive':
|
||||
case 'archive-place':
|
||||
case 'author':
|
||||
case 'authority':
|
||||
case 'call-number':
|
||||
case 'chapter-number':
|
||||
case 'citation-label':
|
||||
case 'citation-number':
|
||||
case 'collection-editor':
|
||||
case 'collection-number':
|
||||
case 'collection-title':
|
||||
case 'composer':
|
||||
case 'container':
|
||||
case 'container-author':
|
||||
case 'container-title':
|
||||
case 'container-title-short':
|
||||
case 'dimensions':
|
||||
case 'director':
|
||||
case 'edition':
|
||||
case 'editor':
|
||||
case 'editorial-director':
|
||||
case 'event':
|
||||
case 'event-date':
|
||||
case 'event-place':
|
||||
case 'first-reference-note-number':
|
||||
case 'genre':
|
||||
case 'illustrator':
|
||||
case 'interviewer':
|
||||
case 'issue':
|
||||
case 'issued':
|
||||
case 'jurisdiction':
|
||||
case 'keyword':
|
||||
case 'language':
|
||||
case 'locator':
|
||||
case 'medium':
|
||||
case 'note':
|
||||
case 'number':
|
||||
case 'number-of-pages':
|
||||
case 'number-of-volumes':
|
||||
case 'original-author':
|
||||
case 'original-date':
|
||||
case 'original-publisher':
|
||||
case 'original-publisher-place':
|
||||
case 'original-title':
|
||||
case 'page':
|
||||
case 'page-first':
|
||||
case 'publisher':
|
||||
case 'publisher-place':
|
||||
case 'recipient':
|
||||
case 'references':
|
||||
case 'reviewed-author':
|
||||
case 'reviewed-title':
|
||||
case 'scale':
|
||||
case 'section':
|
||||
case 'source':
|
||||
case 'status':
|
||||
case 'submitted':
|
||||
case 'title':
|
||||
case 'title-short':
|
||||
case 'translator':
|
||||
case 'version':
|
||||
case 'volume':
|
||||
case 'year-suffix':
|
||||
break;
|
||||
|
||||
// Uppercase fields
|
||||
case 'doi':
|
||||
case 'isbn':
|
||||
case 'issn':
|
||||
case 'pmcid':
|
||||
case 'pmid':
|
||||
case 'url':
|
||||
field = field.toUpperCase();
|
||||
break;
|
||||
|
||||
// Weirdo
|
||||
case 'archive-location':
|
||||
field = 'archive_location';
|
||||
break;
|
||||
|
||||
// Don't change other lines
|
||||
default:
|
||||
field = originalField;
|
||||
}
|
||||
return field + value;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -498,7 +596,7 @@ Zotero.Cite.System.prototype = {
|
|||
/**
|
||||
* citeproc-js system function for getting items
|
||||
* See http://gsl-nagoya-u.net/http/pub/citeproc-doc.html#retrieveitem
|
||||
* @param {String|Integer} Item ID, or string item for embedded citations
|
||||
* @param {String|Integer} item - Item ID, or string item for embedded citations
|
||||
* @return {Object} citeproc-js item
|
||||
*/
|
||||
"retrieveItem":function retrieveItem(item) {
|
||||
|
@ -509,10 +607,10 @@ Zotero.Cite.System.prototype = {
|
|||
} else if(typeof item === "string" && (slashIndex = item.indexOf("/")) !== -1) {
|
||||
// is an embedded item
|
||||
var sessionID = item.substr(0, slashIndex);
|
||||
var session = Zotero.Integration.sessions[sessionID]
|
||||
var session = Zotero.Integration.sessions[sessionID];
|
||||
if(session) {
|
||||
var embeddedCitation = session.embeddedItems[item.substr(slashIndex+1)];
|
||||
if(embeddedCitation) {
|
||||
if (embeddedCitation) {
|
||||
embeddedCitation.id = item;
|
||||
return embeddedCitation;
|
||||
}
|
||||
|
@ -526,7 +624,7 @@ Zotero.Cite.System.prototype = {
|
|||
}
|
||||
|
||||
if(!zoteroItem) {
|
||||
throw "Zotero.Cite.System.retrieveItem called on non-item "+item;
|
||||
throw new Error("Zotero.Cite.System.retrieveItem called on non-item "+item);
|
||||
}
|
||||
|
||||
var cslItem = Zotero.Utilities.itemToCSLJSON(zoteroItem);
|
||||
|
@ -556,21 +654,41 @@ Zotero.Cite.System.prototype = {
|
|||
* @return {String|Boolean} The locale as a string if it exists, or false if it doesn't
|
||||
*/
|
||||
"retrieveLocale":function retrieveLocale(lang) {
|
||||
var protHandler = Components.classes["@mozilla.org/network/protocol;1?name=chrome"]
|
||||
.createInstance(Components.interfaces.nsIProtocolHandler);
|
||||
try {
|
||||
var channel = protHandler.newChannel(protHandler.newURI("chrome://zotero/content/locale/csl/locales-"+lang+".xml", "UTF-8", null));
|
||||
var rawStream = channel.open();
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
var converterStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
converterStream.init(rawStream, "UTF-8", 65535,
|
||||
Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
var str = {};
|
||||
converterStream.readString(channel.contentLength, str);
|
||||
converterStream.close();
|
||||
return str.value;
|
||||
return Zotero.Cite.Locale.get(lang);
|
||||
}
|
||||
};
|
||||
|
||||
Zotero.Cite.Locale = {
|
||||
_cache: new Map(),
|
||||
|
||||
get: function (locale) {
|
||||
var str = this._cache.get(locale);
|
||||
if (str) {
|
||||
return str;
|
||||
}
|
||||
var uri = `chrome://zotero/content/locale/csl/locales-${locale}.xml`;
|
||||
try {
|
||||
let protHandler = Components.classes["@mozilla.org/network/protocol;1?name=chrome"]
|
||||
.createInstance(Components.interfaces.nsIProtocolHandler);
|
||||
let channel = protHandler.newChannel(protHandler.newURI(uri));
|
||||
let cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
cstream.init(channel.open(), "UTF-8", 0, 0);
|
||||
let obj = {};
|
||||
let read = 0;
|
||||
let str = "";
|
||||
do {
|
||||
// Read as much as we can and put it in obj.value
|
||||
read = cstream.readString(0xffffffff, obj);
|
||||
str += obj.value;
|
||||
} while (read != 0);
|
||||
cstream.close();
|
||||
this._cache.set(locale, str);
|
||||
return str;
|
||||
}
|
||||
catch (e) {
|
||||
//Zotero.debug(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,390 +0,0 @@
|
|||
var CSL_HOST = {
|
||||
debug: function (str) {
|
||||
Zotero.debug("CSL: " + str);
|
||||
},
|
||||
error: function (str) {
|
||||
Zotero.debug("CSL error: " + str);
|
||||
}
|
||||
};
|
||||
function DOMParser() {
|
||||
return Components.classes["@mozilla.org/xmlextras/domparser;1"]
|
||||
.createInstance(Components.interfaces.nsIDOMParser);
|
||||
};
|
||||
|
||||
var CSL_IS_IE;
|
||||
var CSL_CHROME = function () {
|
||||
if ("undefined" == typeof DOMParser || CSL_IS_IE) {
|
||||
CSL_IS_IE = true;
|
||||
DOMParser = function() {};
|
||||
DOMParser.prototype.parseFromString = function(str, contentType) {
|
||||
if ("undefined" != typeof ActiveXObject) {
|
||||
var xmldata = new ActiveXObject('MSXML.DomDocument');
|
||||
xmldata.async = false;
|
||||
xmldata.loadXML(str);
|
||||
return xmldata;
|
||||
} else if ("undefined" != typeof XMLHttpRequest) {
|
||||
var xmldata = new XMLHttpRequest;
|
||||
if (!contentType) {
|
||||
contentType = 'text/xml';
|
||||
}
|
||||
xmldata.open('GET', 'data:' + contentType + ';charset=utf-8,' + encodeURIComponent(str), false);
|
||||
if(xmldata.overrideMimeType) {
|
||||
xmldata.overrideMimeType(contentType);
|
||||
}
|
||||
xmldata.send(null);
|
||||
return xmldata.responseXML;
|
||||
}
|
||||
};
|
||||
this.hasAttributes = function (node) {
|
||||
var ret;
|
||||
if (node.attributes && node.attributes.length) {
|
||||
ret = true;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
} else {
|
||||
this.hasAttributes = function (node) {
|
||||
var ret;
|
||||
if (node.attributes && node.attributes.length) {
|
||||
ret = true;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
this.importNode = function (doc, srcElement) {
|
||||
if ("undefined" == typeof doc.importNode) {
|
||||
var ret = this._importNode(doc, srcElement, true);
|
||||
} else {
|
||||
var ret = doc.importNode(srcElement, true);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
this._importNode = function(doc, node, allChildren) {
|
||||
switch (node.nodeType) {
|
||||
case 1:
|
||||
var newNode = doc.createElement(node.nodeName);
|
||||
if (node.attributes && node.attributes.length > 0)
|
||||
for (var i = 0, il = node.attributes.length; i < il;)
|
||||
newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i++].nodeName));
|
||||
if (allChildren && node.childNodes && node.childNodes.length > 0)
|
||||
for (var i = 0, il = node.childNodes.length; i < il;)
|
||||
newNode.appendChild(this._importNode(doc, node.childNodes[i++], allChildren));
|
||||
return newNode;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 8:
|
||||
}
|
||||
};
|
||||
this.parser = new DOMParser();
|
||||
var str = "<docco><institution institution-parts=\"long\" delimiter=\", \" substitute-use-first=\"1\" use-last=\"1\"><institution-part name=\"long\"/></institution></docco>";
|
||||
var inst_doc = this.parser.parseFromString(str, "text/xml");
|
||||
var inst_node = inst_doc.getElementsByTagName("institution");
|
||||
this.institution = inst_node.item(0);
|
||||
var inst_part_node = inst_doc.getElementsByTagName("institution-part");
|
||||
this.institutionpart = inst_part_node.item(0);
|
||||
this.ns = "http://purl.org/net/xbiblio/csl";
|
||||
};
|
||||
CSL_CHROME.prototype.clean = function (xml) {
|
||||
xml = xml.replace(/<\?[^?]+\?>/g, "");
|
||||
xml = xml.replace(/<![^>]+>/g, "");
|
||||
xml = xml.replace(/^\s+/, "");
|
||||
xml = xml.replace(/\s+$/, "");
|
||||
xml = xml.replace(/^\n*/, "");
|
||||
return xml;
|
||||
};
|
||||
CSL_CHROME.prototype.getStyleId = function (myxml, styleName) {
|
||||
var text = "";
|
||||
var tagName = "id";
|
||||
if (styleName) {
|
||||
tagName = "title";
|
||||
}
|
||||
var node = myxml.getElementsByTagName(tagName);
|
||||
if (node && node.length) {
|
||||
node = node.item(0);
|
||||
}
|
||||
if (node) {
|
||||
text = node.textContent;
|
||||
}
|
||||
if (!text) {
|
||||
text = node.innerText;
|
||||
}
|
||||
if (!text) {
|
||||
text = node.innerHTML;
|
||||
}
|
||||
return text;
|
||||
};
|
||||
CSL_CHROME.prototype.children = function (myxml) {
|
||||
var children, pos, len, ret;
|
||||
if (myxml) {
|
||||
ret = [];
|
||||
children = myxml.childNodes;
|
||||
for (pos = 0, len = children.length; pos < len; pos += 1) {
|
||||
if (children[pos].nodeName != "#text") {
|
||||
ret.push(children[pos]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
CSL_CHROME.prototype.nodename = function (myxml) {
|
||||
var ret = myxml.nodeName;
|
||||
return ret;
|
||||
};
|
||||
CSL_CHROME.prototype.attributes = function (myxml) {
|
||||
var ret, attrs, attr, key, xml, pos, len;
|
||||
ret = new Object();
|
||||
if (myxml && this.hasAttributes(myxml)) {
|
||||
attrs = myxml.attributes;
|
||||
for (pos = 0, len=attrs.length; pos < len; pos += 1) {
|
||||
attr = attrs[pos];
|
||||
ret["@" + attr.name] = attr.value;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
CSL_CHROME.prototype.content = function (myxml) {
|
||||
var ret;
|
||||
if ("undefined" != typeof myxml.textContent) {
|
||||
ret = myxml.textContent;
|
||||
} else if ("undefined" != typeof myxml.innerText) {
|
||||
ret = myxml.innerText;
|
||||
} else {
|
||||
ret = myxml.txt;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
CSL_CHROME.prototype.namespace = {
|
||||
"xml":"http://www.w3.org/XML/1998/namespace"
|
||||
}
|
||||
CSL_CHROME.prototype.numberofnodes = function (myxml) {
|
||||
if (myxml) {
|
||||
return myxml.length;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
CSL_CHROME.prototype.getAttributeName = function (attr) {
|
||||
var ret = attr.name;
|
||||
return ret;
|
||||
}
|
||||
CSL_CHROME.prototype.getAttributeValue = function (myxml,name,namespace) {
|
||||
var ret = "";
|
||||
if (namespace) {
|
||||
name = namespace+":"+name;
|
||||
}
|
||||
if (myxml && this.hasAttributes(myxml) && myxml.getAttribute(name)) {
|
||||
ret = myxml.getAttribute(name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
CSL_CHROME.prototype.getNodeValue = function (myxml,name) {
|
||||
var ret = null;
|
||||
if (name){
|
||||
var vals = myxml.getElementsByTagName(name);
|
||||
if (vals.length > 0) {
|
||||
if ("undefined" != typeof vals[0].textContent) {
|
||||
ret = vals[0].textContent;
|
||||
} else if ("undefined" != typeof vals[0].innerText) {
|
||||
ret = vals[0].innerText;
|
||||
} else {
|
||||
ret = vals[0].text;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret === null && myxml && myxml.childNodes && (myxml.childNodes.length == 0 || (myxml.childNodes.length == 1 && myxml.firstChild.nodeName == "#text"))) {
|
||||
if ("undefined" != typeof myxml.textContent) {
|
||||
ret = myxml.textContent;
|
||||
} else if ("undefined" != typeof myxml.innerText) {
|
||||
ret = myxml.innerText;
|
||||
} else {
|
||||
ret = myxml.text;
|
||||
}
|
||||
}
|
||||
if (ret === null) {
|
||||
ret = myxml;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
CSL_CHROME.prototype.setAttributeOnNodeIdentifiedByNameAttribute = function (myxml,nodename,partname,attrname,val) {
|
||||
var pos, len, xml, nodes, node;
|
||||
if (attrname.slice(0,1) === '@'){
|
||||
attrname = attrname.slice(1);
|
||||
}
|
||||
nodes = myxml.getElementsByTagName(nodename);
|
||||
for (pos = 0, len = nodes.length; pos < len; pos += 1) {
|
||||
node = nodes[pos];
|
||||
if (node.getAttribute("name") != partname) {
|
||||
continue;
|
||||
}
|
||||
node.setAttribute(attrname, val);
|
||||
}
|
||||
}
|
||||
CSL_CHROME.prototype.deleteNodeByNameAttribute = function (myxml,val) {
|
||||
var pos, len, node, nodes;
|
||||
nodes = myxml.childNodes;
|
||||
for (pos = 0, len = nodes.length; pos < len; pos += 1) {
|
||||
node = nodes[pos];
|
||||
if (!node || node.nodeType == node.TEXT_NODE) {
|
||||
continue;
|
||||
}
|
||||
if (this.hasAttributes(node) && node.getAttribute("name") == val) {
|
||||
myxml.removeChild(nodes[pos]);
|
||||
}
|
||||
}
|
||||
}
|
||||
CSL_CHROME.prototype.deleteAttribute = function (myxml,attr) {
|
||||
myxml.removeAttribute(attr);
|
||||
}
|
||||
CSL_CHROME.prototype.setAttribute = function (myxml,attr,val) {
|
||||
if (!myxml.ownerDocument) {
|
||||
myxml = myxml.firstChild;
|
||||
}
|
||||
if (["function", "unknown"].indexOf(typeof myxml.setAttribute) > -1) {
|
||||
myxml.setAttribute(attr, val);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
CSL_CHROME.prototype.nodeCopy = function (myxml) {
|
||||
var cloned_node = myxml.cloneNode(true);
|
||||
return cloned_node;
|
||||
}
|
||||
CSL_CHROME.prototype.getNodesByName = function (myxml,name,nameattrval) {
|
||||
var ret, nodes, node, pos, len;
|
||||
ret = [];
|
||||
nodes = myxml.getElementsByTagName(name);
|
||||
for (pos = 0, len = nodes.length; pos < len; pos += 1) {
|
||||
node = nodes.item(pos);
|
||||
if (nameattrval && !(this.hasAttributes(node) && node.getAttribute("name") == nameattrval)) {
|
||||
continue;
|
||||
}
|
||||
ret.push(node);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
CSL_CHROME.prototype.nodeNameIs = function (myxml,name) {
|
||||
if (name == myxml.nodeName) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
CSL_CHROME.prototype.makeXml = function (myxml) {
|
||||
var ret, topnode;
|
||||
if (!myxml) {
|
||||
myxml = "<docco><bogus/></docco>";
|
||||
}
|
||||
myxml = myxml.replace(/\s*<\?[^>]*\?>\s*\n*/g, "");
|
||||
var nodetree = this.parser.parseFromString(myxml, "application/xml");
|
||||
return nodetree.firstChild;
|
||||
};
|
||||
CSL_CHROME.prototype.insertChildNodeAfter = function (parent,node,pos,datexml) {
|
||||
var myxml, xml;
|
||||
myxml = this.importNode(node.ownerDocument, datexml);
|
||||
parent.replaceChild(myxml, node);
|
||||
return parent;
|
||||
};
|
||||
CSL_CHROME.prototype.insertPublisherAndPlace = function(myxml) {
|
||||
var group = myxml.getElementsByTagName("group");
|
||||
for (var i = 0, ilen = group.length; i < ilen; i += 1) {
|
||||
var node = group.item(i);
|
||||
var skippers = [];
|
||||
for (var j = 0, jlen = node.childNodes.length; j < jlen; j += 1) {
|
||||
if (node.childNodes.item(j).nodeType !== 1) {
|
||||
skippers.push(j);
|
||||
}
|
||||
}
|
||||
if (node.childNodes.length - skippers.length === 2) {
|
||||
var twovars = [];
|
||||
for (var j = 0, jlen = 2; j < jlen; j += 1) {
|
||||
if (skippers.indexOf(j) > -1) {
|
||||
continue;
|
||||
}
|
||||
var child = node.childNodes.item(j);
|
||||
var subskippers = [];
|
||||
for (var k = 0, klen = child.childNodes.length; k < klen; k += 1) {
|
||||
if (child.childNodes.item(k).nodeType !== 1) {
|
||||
subskippers.push(k);
|
||||
}
|
||||
}
|
||||
if (child.childNodes.length - subskippers.length === 0) {
|
||||
twovars.push(child.getAttribute('variable'));
|
||||
if (child.getAttribute('suffix')
|
||||
|| child.getAttribute('prefix')) {
|
||||
twovars = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (twovars.indexOf("publisher") > -1 && twovars.indexOf("publisher-place") > -1) {
|
||||
node.setAttribute('has-publisher-and-publisher-place', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
CSL_CHROME.prototype.addMissingNameNodes = function(myxml) {
|
||||
var nameslist = myxml.getElementsByTagName("names");
|
||||
for (var i = 0, ilen = nameslist.length; i < ilen; i += 1) {
|
||||
var names = nameslist.item(i);
|
||||
var namelist = names.getElementsByTagName("name");
|
||||
if ((!namelist || namelist.length === 0)
|
||||
&& names.parentNode.tagName.toLowerCase() !== "substitute") {
|
||||
var doc = names.ownerDocument;
|
||||
var name = doc.createElement("name");
|
||||
names.appendChild(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
CSL_CHROME.prototype.addInstitutionNodes = function(myxml) {
|
||||
var names, thenames, institution, theinstitution, name, thename, xml, pos, len;
|
||||
names = myxml.getElementsByTagName("names");
|
||||
for (pos = 0, len = names.length; pos < len; pos += 1) {
|
||||
thenames = names.item(pos);
|
||||
name = thenames.getElementsByTagName("name");
|
||||
if (name.length == 0) {
|
||||
continue;
|
||||
}
|
||||
institution = thenames.getElementsByTagName("institution");
|
||||
if (institution.length == 0) {
|
||||
theinstitution = this.importNode(myxml.ownerDocument, this.institution);
|
||||
theinstitutionpart = theinstitution.getElementsByTagName("institution-part").item(0);
|
||||
thename = name.item(0);
|
||||
thenames.insertBefore(theinstitution, thename.nextSibling);
|
||||
for (var j = 0, jlen = CSL.INSTITUTION_KEYS.length; j < jlen; j += 1) {
|
||||
var attrname = CSL.INSTITUTION_KEYS[j];
|
||||
var attrval = thename.getAttribute(attrname);
|
||||
if (attrval) {
|
||||
theinstitutionpart.setAttribute(attrname, attrval);
|
||||
}
|
||||
}
|
||||
var nameparts = thename.getElementsByTagName("name-part");
|
||||
for (var j = 0, jlen = nameparts.length; j < jlen; j += 1) {
|
||||
if ('family' === nameparts[j].getAttribute('name')) {
|
||||
for (var k = 0, klen = CSL.INSTITUTION_KEYS.length; k < klen; k += 1) {
|
||||
var attrname = CSL.INSTITUTION_KEYS[k];
|
||||
var attrval = nameparts[j].getAttribute(attrname);
|
||||
if (attrval) {
|
||||
theinstitutionpart.setAttribute(attrname, attrval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
CSL_CHROME.prototype.flagDateMacros = function(myxml) {
|
||||
var pos, len, thenode, thedate;
|
||||
nodes = myxml.getElementsByTagName("macro");
|
||||
for (pos = 0, len = nodes.length; pos < len; pos += 1) {
|
||||
thenode = nodes.item(pos);
|
||||
thedate = thenode.getElementsByTagName("date");
|
||||
if (thedate.length) {
|
||||
thenode.setAttribute('macro-has-date', 'true');
|
||||
}
|
||||
}
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -25,12 +25,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
Zotero.CollectionTreeRow = function(type, ref, level, isOpen)
|
||||
{
|
||||
Zotero.CollectionTreeRow = function (collectionTreeView, type, ref, level, isOpen) {
|
||||
this.view = collectionTreeView;
|
||||
this.type = type;
|
||||
this.ref = ref;
|
||||
this.level = level || 0
|
||||
this.isOpen = isOpen || false;
|
||||
this.onUnload = null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -300,6 +301,18 @@ Zotero.CollectionTreeRow.prototype.getSearchObject = Zotero.Promise.coroutine(fu
|
|||
}
|
||||
else if (this.isDuplicates()) {
|
||||
var s = yield this.ref.getSearchObject();
|
||||
let tmpTable;
|
||||
for (let id in s.conditions) {
|
||||
let c = s.conditions[id];
|
||||
if (c.condition == 'tempTable') {
|
||||
tmpTable = c.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Called by ItemTreeView::unregister()
|
||||
this.onUnload = async function () {
|
||||
await Zotero.DB.queryAsync(`DROP TABLE IF EXISTS ${tmpTable}`);
|
||||
};
|
||||
}
|
||||
else {
|
||||
var s = new Zotero.Search();
|
||||
|
@ -330,6 +343,7 @@ Zotero.CollectionTreeRow.prototype.getSearchObject = Zotero.Promise.coroutine(fu
|
|||
|
||||
// Create the outer (filter) search
|
||||
var s2 = new Zotero.Search();
|
||||
s2.addCondition('libraryID', 'is', this.ref.libraryID);
|
||||
|
||||
if (this.isTrash()) {
|
||||
s2.addCondition('deleted', 'true');
|
||||
|
@ -367,8 +381,8 @@ Zotero.CollectionTreeRow.prototype.getChildTags = Zotero.Promise.coroutine(funct
|
|||
case 'bucket':
|
||||
return [];
|
||||
}
|
||||
var results = yield this.getSearchResults();
|
||||
return Zotero.Tags.getAllWithinItemsList(results);
|
||||
var results = yield this.getSearchResults(true);
|
||||
return Zotero.Tags.getAllWithinSearchResults(results);
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ Zotero.CollectionTreeView = function()
|
|||
{
|
||||
Zotero.LibraryTreeView.apply(this);
|
||||
|
||||
this.itemTreeView = null;
|
||||
this.itemToSelect = null;
|
||||
this.hideSources = [];
|
||||
|
||||
|
@ -75,6 +76,14 @@ Object.defineProperty(Zotero.CollectionTreeView.prototype, "selectedTreeRow", {
|
|||
});
|
||||
|
||||
|
||||
Object.defineProperty(Zotero.CollectionTreeView.prototype, 'window', {
|
||||
get: function () {
|
||||
return this._ownerDocument.defaultView;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* Called by the tree itself
|
||||
*/
|
||||
|
@ -86,6 +95,13 @@ Zotero.CollectionTreeView.prototype.setTree = Zotero.Promise.coroutine(function*
|
|||
}
|
||||
this._treebox = treebox;
|
||||
|
||||
if (!this._ownerDocument) {
|
||||
try {
|
||||
this._ownerDocument = treebox.treeBody.ownerDocument;
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
|
||||
// Add a keypress listener for expand/collapse
|
||||
var tree = this._treebox.treeBody.parentNode;
|
||||
tree.addEventListener('keypress', function(event) {
|
||||
|
@ -177,7 +193,7 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
|
|||
//
|
||||
this._addRowToArray(
|
||||
newRows,
|
||||
new Zotero.CollectionTreeRow('library', { libraryID: Zotero.Libraries.userLibraryID }),
|
||||
new Zotero.CollectionTreeRow(this, 'library', { libraryID: Zotero.Libraries.userLibraryID }),
|
||||
added++
|
||||
);
|
||||
added += yield this._expandRow(newRows, 0);
|
||||
|
@ -189,12 +205,12 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
|
|||
if (groups.length) {
|
||||
this._addRowToArray(
|
||||
newRows,
|
||||
new Zotero.CollectionTreeRow('separator', false),
|
||||
new Zotero.CollectionTreeRow(this, 'separator', false),
|
||||
added++
|
||||
);
|
||||
this._addRowToArray(
|
||||
newRows,
|
||||
new Zotero.CollectionTreeRow('header', {
|
||||
new Zotero.CollectionTreeRow(this, 'header', {
|
||||
id: "group-libraries-header",
|
||||
label: Zotero.getString('pane.collections.groupLibraries'),
|
||||
libraryID: -1
|
||||
|
@ -204,7 +220,7 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
|
|||
for (let group of groups) {
|
||||
this._addRowToArray(
|
||||
newRows,
|
||||
new Zotero.CollectionTreeRow('group', group),
|
||||
new Zotero.CollectionTreeRow(this, 'group', group),
|
||||
added++
|
||||
);
|
||||
added += yield this._expandRow(newRows, added - 1);
|
||||
|
@ -224,12 +240,12 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
|
|||
if (feeds.length) {
|
||||
this._addRowToArray(
|
||||
newRows,
|
||||
new Zotero.CollectionTreeRow('separator', false),
|
||||
new Zotero.CollectionTreeRow(this, 'separator', false),
|
||||
added++
|
||||
);
|
||||
this._addRowToArray(
|
||||
newRows,
|
||||
new Zotero.CollectionTreeRow('header', {
|
||||
new Zotero.CollectionTreeRow(this, 'header', {
|
||||
id: "feed-libraries-header",
|
||||
label: Zotero.getString('pane.collections.feedLibraries'),
|
||||
libraryID: -1
|
||||
|
@ -239,7 +255,7 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
|
|||
for (let feed of feeds) {
|
||||
this._addRowToArray(
|
||||
newRows,
|
||||
new Zotero.CollectionTreeRow('feed', feed),
|
||||
new Zotero.CollectionTreeRow(this, 'feed', feed),
|
||||
added++
|
||||
);
|
||||
}
|
||||
|
@ -259,8 +275,10 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
|
|||
});
|
||||
|
||||
|
||||
/*
|
||||
* Redisplay everything
|
||||
/**
|
||||
* Refresh tree and invalidate
|
||||
*
|
||||
* See note for refresh() for requirements of calling code
|
||||
*/
|
||||
Zotero.CollectionTreeView.prototype.reload = function()
|
||||
{
|
||||
|
@ -433,13 +451,11 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
|
|||
}
|
||||
this._removeRow(row);
|
||||
yield this._addSortedRow('collection', id);
|
||||
if (!extraData[id].skipSelect) {
|
||||
yield this.selectByID(currentTreeRow.id);
|
||||
if (reopen) {
|
||||
let newRow = this.getRowIndexByID(rowID);
|
||||
if (!this.isContainerOpen(newRow)) {
|
||||
yield this.toggleOpenState(newRow);
|
||||
}
|
||||
yield this.selectByID(currentTreeRow.id);
|
||||
if (reopen) {
|
||||
let newRow = this.getRowIndexByID(rowID);
|
||||
if (!this.isContainerOpen(newRow)) {
|
||||
yield this.toggleOpenState(newRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -484,17 +500,18 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
|
|||
break;
|
||||
|
||||
case 'group':
|
||||
if (ids.length != 1) {
|
||||
case 'feed':
|
||||
if (type == 'groups' && ids.length != 1) {
|
||||
Zotero.logError("WARNING: Multiple groups shouldn't currently be added "
|
||||
+ "together in collectionTreeView::notify()")
|
||||
}
|
||||
yield this.reload();
|
||||
yield this.selectByID(currentTreeRow.id);
|
||||
break;
|
||||
|
||||
case 'feed':
|
||||
yield this.reload();
|
||||
yield this.selectByID("L" + id);
|
||||
yield this.selectByID(
|
||||
// Groups only come from sync, so they should never be auto-selected
|
||||
(type != 'group' && selectRow)
|
||||
? "L" + id
|
||||
: currentTreeRow.id
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -592,7 +609,7 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
|
|||
}
|
||||
}
|
||||
this._addRow(
|
||||
new Zotero.CollectionTreeRow('collection', collection, level),
|
||||
new Zotero.CollectionTreeRow(this, 'collection', collection, level),
|
||||
beforeRow
|
||||
);
|
||||
}
|
||||
|
@ -632,7 +649,7 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
|
|||
}
|
||||
}
|
||||
this._addRow(
|
||||
new Zotero.CollectionTreeRow('search', search, level),
|
||||
new Zotero.CollectionTreeRow(this, 'search', search, level),
|
||||
beforeRow
|
||||
);
|
||||
}
|
||||
|
@ -655,8 +672,7 @@ Zotero.CollectionTreeView.prototype.setHighlightedRows = Zotero.Promise.coroutin
|
|||
// Make sure all highlighted collections are shown
|
||||
for (let id of ids) {
|
||||
if (id[0] == 'C') {
|
||||
id = id.substr(1);
|
||||
yield this.expandToCollection(id);
|
||||
yield this.expandToCollection(parseInt(id.substr(1)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -768,7 +784,7 @@ Zotero.CollectionTreeView.prototype.getImageSrc = function(row, col)
|
|||
case 'search':
|
||||
// Keep in sync with Zotero.(Collection|Search).prototype.treeViewImage
|
||||
if (Zotero.isMac) {
|
||||
return "chrome://zotero-platform/content/treesource-" + collectionType + ".png";
|
||||
return `chrome://zotero-platform/content/treesource-${collectionType}${Zotero.hiDPISuffix}.png`;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1179,11 +1195,9 @@ Zotero.CollectionTreeView.prototype.selectItem = Zotero.Promise.coroutine(functi
|
|||
yield this.selectLibrary(item.libraryID);
|
||||
}
|
||||
|
||||
var itemsView = this.selectedTreeRow.itemTreeView;
|
||||
yield this.itemTreeView.waitForLoad();
|
||||
|
||||
yield itemsView.waitForLoad();
|
||||
|
||||
var selected = yield itemsView.selectItem(itemID, expand);
|
||||
var selected = yield this.itemTreeView.selectItem(itemID, expand);
|
||||
if (selected) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1197,10 +1211,9 @@ Zotero.CollectionTreeView.prototype.selectItem = Zotero.Promise.coroutine(functi
|
|||
yield this.selectLibrary(item.libraryID);
|
||||
}
|
||||
|
||||
itemsView = this.selectedTreeRow.itemTreeView;
|
||||
yield itemsView.waitForLoad();
|
||||
yield this.itemTreeView.waitForLoad();
|
||||
|
||||
return itemsView.selectItem(itemID, expand);
|
||||
return this.itemTreeView.selectItem(itemID, expand);
|
||||
});
|
||||
|
||||
|
||||
|
@ -1334,7 +1347,7 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
|
|||
let beforeRow = row + 1 + newRows;
|
||||
this._addRowToArray(
|
||||
rows,
|
||||
new Zotero.CollectionTreeRow('collection', collections[i], level + 1),
|
||||
new Zotero.CollectionTreeRow(this, 'collection', collections[i], level + 1),
|
||||
beforeRow
|
||||
);
|
||||
newRows++;
|
||||
|
@ -1350,7 +1363,7 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
|
|||
for (var i = 0, len = savedSearches.length; i < len; i++) {
|
||||
this._addRowToArray(
|
||||
rows,
|
||||
new Zotero.CollectionTreeRow('search', savedSearches[i], level + 1),
|
||||
new Zotero.CollectionTreeRow(this, 'search', savedSearches[i], level + 1),
|
||||
row + 1 + newRows
|
||||
);
|
||||
newRows++;
|
||||
|
@ -1360,7 +1373,7 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
|
|||
// Add "My Publications"
|
||||
this._addRowToArray(
|
||||
rows,
|
||||
new Zotero.CollectionTreeRow(
|
||||
new Zotero.CollectionTreeRow(this,
|
||||
'publications',
|
||||
{
|
||||
libraryID,
|
||||
|
@ -1378,7 +1391,7 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
|
|||
let d = new Zotero.Duplicates(libraryID);
|
||||
this._addRowToArray(
|
||||
rows,
|
||||
new Zotero.CollectionTreeRow('duplicates', d, level + 1),
|
||||
new Zotero.CollectionTreeRow(this, 'duplicates', d, level + 1),
|
||||
row + 1 + newRows
|
||||
);
|
||||
newRows++;
|
||||
|
@ -1393,7 +1406,7 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
|
|||
s.addCondition('unfiled', 'true');
|
||||
this._addRowToArray(
|
||||
rows,
|
||||
new Zotero.CollectionTreeRow('unfiled', s, level + 1),
|
||||
new Zotero.CollectionTreeRow(this, 'unfiled', s, level + 1),
|
||||
row + 1 + newRows
|
||||
);
|
||||
newRows++;
|
||||
|
@ -1407,7 +1420,7 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
|
|||
};
|
||||
this._addRowToArray(
|
||||
rows,
|
||||
new Zotero.CollectionTreeRow('trash', ref, level + 1),
|
||||
new Zotero.CollectionTreeRow(this, 'trash', ref, level + 1),
|
||||
row + 1 + newRows
|
||||
);
|
||||
newRows++;
|
||||
|
@ -1467,7 +1480,7 @@ Zotero.CollectionTreeView.prototype._saveOpenStates = Zotero.Promise.coroutine(f
|
|||
for (var id in state) {
|
||||
var m = id.match(/^C([0-9]+)$/);
|
||||
if (m) {
|
||||
if (!(yield Zotero.Collections.getAsync(m[1]))) {
|
||||
if (!(yield Zotero.Collections.getAsync(parseInt(m[1])))) {
|
||||
delete state[id];
|
||||
}
|
||||
continue;
|
||||
|
@ -1475,7 +1488,7 @@ Zotero.CollectionTreeView.prototype._saveOpenStates = Zotero.Promise.coroutine(f
|
|||
|
||||
var m = id.match(/^G([0-9]+)$/);
|
||||
if (m) {
|
||||
if (!Zotero.Groups.get(m[1])) {
|
||||
if (!Zotero.Groups.get(parseInt(m[1]))) {
|
||||
delete state[id];
|
||||
}
|
||||
continue;
|
||||
|
@ -1608,6 +1621,7 @@ Zotero.CollectionTreeView.prototype.canDropCheck = function (row, orient, dataTr
|
|||
if (dataType == 'zotero/item') {
|
||||
var ids = data;
|
||||
var items = Zotero.Items.get(ids);
|
||||
items = Zotero.Items.keepParents(items);
|
||||
var skip = true;
|
||||
for (let item of items) {
|
||||
// Can only drag top-level items
|
||||
|
@ -1815,6 +1829,7 @@ Zotero.CollectionTreeView.prototype.canDropCheckAsync = Zotero.Promise.coroutine
|
|||
if (treeRow.ref.libraryID != draggedCollection.libraryID) {
|
||||
// Disallow if linked collection already exists
|
||||
if (yield draggedCollection.getLinkedCollection(treeRow.ref.libraryID, true)) {
|
||||
Zotero.debug("Linked collection already exists in library");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1826,6 +1841,7 @@ Zotero.CollectionTreeView.prototype.canDropCheckAsync = Zotero.Promise.coroutine
|
|||
// If this is allowed in the future for the root collection,
|
||||
// need to allow drag only to root
|
||||
if (yield descendent.getLinkedCollection(treeRow.ref.libraryID, true)) {
|
||||
Zotero.debug("Linked subcollection already exists in library");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2117,6 +2133,7 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
}
|
||||
|
||||
if (targetTreeRow.isPublications()) {
|
||||
items = Zotero.Items.keepParents(items);
|
||||
let io = this._treebox.treeBody.ownerDocument.defaultView
|
||||
.ZoteroPane.showPublicationsWizard(items);
|
||||
if (!io) {
|
||||
|
@ -2188,12 +2205,11 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
}
|
||||
*/
|
||||
|
||||
let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
let lastWin = wm.getMostRecentWindow("navigator:browser");
|
||||
let lastWin = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
lastWin.openDialog('chrome://zotero/content/merge.xul', '', 'chrome,modal,centerscreen', io);
|
||||
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
// DEBUG: This probably needs to be updated if this starts being used
|
||||
for (let obj of io.dataOut) {
|
||||
yield obj.ref.save();
|
||||
}
|
||||
|
@ -2228,24 +2244,23 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
}
|
||||
else if (dataType == 'text/x-moz-url' || dataType == 'application/x-moz-file') {
|
||||
var targetLibraryID = targetTreeRow.ref.libraryID;
|
||||
|
||||
if (targetTreeRow.isCollection()) {
|
||||
var parentCollectionID = targetTreeRow.ref.id;
|
||||
}
|
||||
else {
|
||||
var parentCollectionID = false;
|
||||
}
|
||||
var addedItems = [];
|
||||
|
||||
for (var i=0; i<data.length; i++) {
|
||||
var file = data[i];
|
||||
|
||||
if (dataType == 'text/x-moz-url') {
|
||||
var url = data[i];
|
||||
let item;
|
||||
|
||||
if (url.indexOf('file:///') == 0) {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
// If dragging currently loaded page, only convert to
|
||||
// file if not an HTML document
|
||||
if (win.content.location.href != url ||
|
||||
|
@ -2263,9 +2278,7 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
|
||||
// Still string, so remote URL
|
||||
if (typeof file == 'string') {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
win.ZoteroPane.addItemFromURL(url, 'temporaryPDFHack', null, row); // TODO: don't do this
|
||||
continue;
|
||||
}
|
||||
|
@ -2274,13 +2287,13 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
}
|
||||
|
||||
if (dropEffect == 'link') {
|
||||
yield Zotero.Attachments.linkFromFile({
|
||||
item = yield Zotero.Attachments.linkFromFile({
|
||||
file: file,
|
||||
collections: parentCollectionID ? [parentCollectionID] : undefined
|
||||
});
|
||||
}
|
||||
else {
|
||||
yield Zotero.Attachments.importFromFile({
|
||||
item = yield Zotero.Attachments.importFromFile({
|
||||
file: file,
|
||||
libraryID: targetLibraryID,
|
||||
collections: parentCollectionID ? [parentCollectionID] : undefined
|
||||
|
@ -2295,7 +2308,12 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
addedItems.push(item);
|
||||
}
|
||||
|
||||
// Automatically retrieve metadata for PDFs
|
||||
Zotero.RecognizePDF.autoRecognizeItems(addedItems);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2360,11 +2378,12 @@ Zotero.CollectionTreeCache = {
|
|||
"clear": function () {
|
||||
this.lastTreeRow = null;
|
||||
this.lastSearch = null;
|
||||
if(this.lastTempTable) {
|
||||
// Drop the last temp table when we can. We don't wait on this because it can cause a
|
||||
// deadlock: this waits on open transactions, but a transaction could be waiting on
|
||||
// ItemTreeView::notify(), which waits on ItemTreeView::refresh(), which calls this.
|
||||
Zotero.DB.queryTx("DROP TABLE IF EXISTS " + this.lastTempTable).done();
|
||||
if (this.lastTempTable) {
|
||||
let tableName = this.lastTempTable;
|
||||
let id = Zotero.DB.addCallback('commit', async function () {
|
||||
await Zotero.DB.queryAsync("DROP TABLE IF EXISTS " + tableName);
|
||||
Zotero.DB.removeCallback('commit', id);
|
||||
});
|
||||
}
|
||||
this.lastTempTable = null;
|
||||
this.lastResults = null;
|
||||
|
|
192
chrome/content/zotero/xpcom/connector/httpIntegrationClient.js
Normal file
192
chrome/content/zotero/xpcom/connector/httpIntegrationClient.js
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2017 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a HTTP-based integration interface for Zotero. The actual
|
||||
* heavy lifting occurs in the connector and/or wherever the connector delegates the heavy
|
||||
* lifting to.
|
||||
*/
|
||||
Zotero.HTTPIntegrationClient = {
|
||||
deferredResponse: null,
|
||||
sendCommandPromise: Zotero.Promise.resolve(),
|
||||
sendCommand: async function(command, args=[]) {
|
||||
let payload = JSON.stringify({command, arguments: args});
|
||||
function sendCommand() {
|
||||
Zotero.HTTPIntegrationClient.deferredResponse = Zotero.Promise.defer();
|
||||
Zotero.HTTPIntegrationClient.sendResponse.apply(Zotero.HTTPIntegrationClient,
|
||||
[200, 'application/json', payload]);
|
||||
return Zotero.HTTPIntegrationClient.deferredResponse.promise;
|
||||
}
|
||||
// Force issued commands to occur sequentially, since these are really just
|
||||
// a sequence of HTTP requests and responses.
|
||||
// We might want to consider something better later, but this has the advantage of
|
||||
// being easy to interface with as a Client, as you don't need SSE or WS.
|
||||
if (command != 'Document.complete') {
|
||||
Zotero.HTTPIntegrationClient.sendCommandPromise =
|
||||
Zotero.HTTPIntegrationClient.sendCommandPromise.then(sendCommand, sendCommand);
|
||||
} else {
|
||||
await Zotero.HTTPIntegrationClient.sendCommandPromise;
|
||||
sendCommand();
|
||||
}
|
||||
return Zotero.HTTPIntegrationClient.sendCommandPromise;
|
||||
}
|
||||
};
|
||||
|
||||
Zotero.HTTPIntegrationClient.Application = function() {
|
||||
this.primaryFieldType = "Http";
|
||||
this.secondaryFieldType = "Http";
|
||||
this.outputFormat = 'html';
|
||||
this.supportedNotes = ['footnotes'];
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Application.prototype = {
|
||||
getActiveDocument: async function() {
|
||||
let result = await Zotero.HTTPIntegrationClient.sendCommand('Application.getActiveDocument');
|
||||
this.outputFormat = result.outputFormat || this.outputFormat;
|
||||
this.supportedNotes = result.supportedNotes || this.supportedNotes;
|
||||
return new Zotero.HTTPIntegrationClient.Document(result.documentID);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* See integrationTests.js
|
||||
*/
|
||||
Zotero.HTTPIntegrationClient.Document = function(documentID) {
|
||||
this._documentID = documentID;
|
||||
};
|
||||
for (let method of ["activate", "canInsertField", "displayAlert", "getDocumentData",
|
||||
"setDocumentData", "setBibliographyStyle"]) {
|
||||
Zotero.HTTPIntegrationClient.Document.prototype[method] = async function() {
|
||||
return Zotero.HTTPIntegrationClient.sendCommand("Document."+method,
|
||||
[this._documentID].concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
}
|
||||
|
||||
// @NOTE Currently unused, prompts are done using the connector
|
||||
Zotero.HTTPIntegrationClient.Document.prototype._displayAlert = async function(dialogText, icon, buttons) {
|
||||
var ps = Services.prompt;
|
||||
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_OK)
|
||||
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING);
|
||||
|
||||
switch (buttons) {
|
||||
case DIALOG_BUTTONS_OK:
|
||||
buttonFlags = ps.BUTTON_POS_0_DEFAULT + ps.BUTTON_POS_0 * ps.BUTTON_TITLE_OK; break;
|
||||
case DIALOG_BUTTONS_OK_CANCEL:
|
||||
buttonFlags = ps.BUTTON_POS_0_DEFAULT + ps.STD_OK_CANCEL_BUTTONS; break;
|
||||
case DIALOG_BUTTONS_YES_NO:
|
||||
buttonFlags = ps.BUTTON_POS_0_DEFAULT + ps.STD_YES_NO_BUTTONS; break;
|
||||
case DIALOG_BUTTONS_YES_NO_CANCEL:
|
||||
buttonFlags = ps.BUTTON_POS_0_DEFAULT + ps.BUTTON_POS_0 * ps.BUTTON_TITLE_YES +
|
||||
ps.BUTTON_POS_1 * ps.BUTTON_TITLE_NO +
|
||||
ps.BUTTON_POS_2 * ps.BUTTON_TITLE_CANCEL; break;
|
||||
}
|
||||
|
||||
var result = ps.confirmEx(
|
||||
null,
|
||||
"Zotero",
|
||||
dialogText,
|
||||
buttonFlags,
|
||||
null, null, null,
|
||||
null,
|
||||
{}
|
||||
);
|
||||
|
||||
switch (buttons) {
|
||||
default:
|
||||
break;
|
||||
case DIALOG_BUTTONS_OK_CANCEL:
|
||||
case DIALOG_BUTTONS_YES_NO:
|
||||
result = (result+1)%2; break;
|
||||
case DIALOG_BUTTONS_YES_NO_CANCEL:
|
||||
result = result == 0 ? 2 : result == 2 ? 0 : 1; break;
|
||||
}
|
||||
await this.activate();
|
||||
return result;
|
||||
}
|
||||
Zotero.HTTPIntegrationClient.Document.prototype.cleanup = async function() {};
|
||||
Zotero.HTTPIntegrationClient.Document.prototype.cursorInField = async function(fieldType) {
|
||||
var retVal = await Zotero.HTTPIntegrationClient.sendCommand("Document.cursorInField", [this._documentID, fieldType]);
|
||||
if (!retVal) return null;
|
||||
return new Zotero.HTTPIntegrationClient.Field(this._documentID, retVal);
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Document.prototype.insertField = async function(fieldType, noteType) {
|
||||
var retVal = await Zotero.HTTPIntegrationClient.sendCommand("Document.insertField", [this._documentID, fieldType, parseInt(noteType) || 0]);
|
||||
return new Zotero.HTTPIntegrationClient.Field(this._documentID, retVal);
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Document.prototype.getFields = async function(fieldType) {
|
||||
var retVal = await Zotero.HTTPIntegrationClient.sendCommand("Document.getFields", [this._documentID, fieldType]);
|
||||
return retVal.map(field => new Zotero.HTTPIntegrationClient.Field(this._documentID, field));
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Document.prototype.convert = async function(fields, fieldType, noteTypes) {
|
||||
fields = fields.map((f) => f._id);
|
||||
await Zotero.HTTPIntegrationClient.sendCommand("Field.convert", [this._documentID, fields, fieldType, noteTypes]);
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Document.prototype.complete = async function() {
|
||||
Zotero.HTTPIntegrationClient.inProgress = false;
|
||||
Zotero.HTTPIntegrationClient.sendCommand("Document.complete", [this._documentID]);
|
||||
};
|
||||
|
||||
/**
|
||||
* See integrationTests.js
|
||||
*/
|
||||
Zotero.HTTPIntegrationClient.Field = function(documentID, json) {
|
||||
this._documentID = documentID;
|
||||
this._id = json.id;
|
||||
this._code = json.code;
|
||||
this._text = json.text;
|
||||
this._noteIndex = json.noteIndex;
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Field.prototype = {};
|
||||
|
||||
for (let method of ["delete", "select", "removeCode"]) {
|
||||
Zotero.HTTPIntegrationClient.Field.prototype[method] = async function() {
|
||||
return Zotero.HTTPIntegrationClient.sendCommand("Field."+method,
|
||||
[this._documentID, this._id].concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
}
|
||||
Zotero.HTTPIntegrationClient.Field.prototype.getText = async function() {
|
||||
return this._text;
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Field.prototype.setText = async function(text, isRich) {
|
||||
// The HTML will be stripped by Google Docs and and since we're
|
||||
// caching this value, we need to strip it ourselves
|
||||
var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
|
||||
.createInstance(Components.interfaces.nsIDOMParser);
|
||||
var doc = parser.parseFromString(text, "text/html");
|
||||
this._text = doc.documentElement.textContent;
|
||||
return Zotero.HTTPIntegrationClient.sendCommand("Field.setText", [this._documentID, this._id, text, true]);
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Field.prototype.getCode = async function() {
|
||||
return this._code;
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Field.prototype.setCode = async function(code) {
|
||||
this._code = code;
|
||||
return Zotero.HTTPIntegrationClient.sendCommand("Field.setCode", [this._documentID, this._id, code]);
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Field.prototype.getNoteIndex = async function() {
|
||||
return this._noteIndex;
|
||||
};
|
||||
Zotero.HTTPIntegrationClient.Field.prototype.equals = async function(arg) {
|
||||
return this._id === arg._id;
|
||||
};
|
1425
chrome/content/zotero/xpcom/connector/server_connector.js
Normal file
1425
chrome/content/zotero/xpcom/connector/server_connector.js
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2017 Center for History and New Media
|
||||
George Mason University, Fairfax, Virginia, USA
|
||||
http://zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds integration endpoints related to doc integration via HTTP/connector.
|
||||
*
|
||||
* document/execCommand initiates an integration command and responds with the
|
||||
* next request for the http client (e.g. 'Application.getDocument').
|
||||
* The client should respond to document/respond with the payload and expect
|
||||
* another response with the next request, until it receives 'Document.complete'
|
||||
* at which point the integration transaction is considered complete.
|
||||
*/
|
||||
Zotero.Server.Endpoints['/connector/document/execCommand'] = function() {};
|
||||
Zotero.Server.Endpoints['/connector/document/execCommand'].prototype = {
|
||||
supportedMethods: ["POST"],
|
||||
supportedDataTypes: ["application/json"],
|
||||
permitBookmarklet: true,
|
||||
init: function(data, sendResponse) {
|
||||
if (Zotero.HTTPIntegrationClient.inProgress) {
|
||||
// This will focus the last integration window if present
|
||||
Zotero.Integration.execCommand('http', data.command, data.docId);
|
||||
sendResponse(503, 'text/plain', 'Integration transaction is already in progress')
|
||||
return;
|
||||
}
|
||||
Zotero.HTTPIntegrationClient.inProgress = true;
|
||||
Zotero.HTTPIntegrationClient.sendResponse = sendResponse;
|
||||
Zotero.Integration.execCommand('http', data.command, data.docId);
|
||||
},
|
||||
};
|
||||
|
||||
Zotero.Server.Endpoints['/connector/document/respond'] = function() {};
|
||||
Zotero.Server.Endpoints['/connector/document/respond'].prototype = {
|
||||
supportedMethods: ["POST"],
|
||||
supportedDataTypes: ["application/json"],
|
||||
permitBookmarklet: true,
|
||||
|
||||
init: function(data, sendResponse) {
|
||||
data = JSON.parse(data);
|
||||
if (data && data.error) {
|
||||
// Apps Script stack is a JSON object
|
||||
if (typeof data.stack != "string") {
|
||||
data.stack = JSON.stringify(data.stack);
|
||||
}
|
||||
Zotero.HTTPIntegrationClient.deferredResponse.reject(data);
|
||||
} else {
|
||||
Zotero.HTTPIntegrationClient.deferredResponse.resolve(data);
|
||||
}
|
||||
Zotero.HTTPIntegrationClient.sendResponse = sendResponse;
|
||||
}
|
||||
};
|
||||
|
||||
// For managing macOS integration and progress window focus
|
||||
Zotero.Server.Endpoints['/connector/sendToBack'] = function() {};
|
||||
Zotero.Server.Endpoints['/connector/sendToBack'].prototype = {
|
||||
supportedMethods: ["POST"],
|
||||
supportedDataTypes: ["application/json"],
|
||||
permitBookmarklet: true,
|
||||
init: function() {
|
||||
Zotero.Utilities.Internal.sendToBack();
|
||||
},
|
||||
};
|
|
@ -219,7 +219,6 @@ Zotero.CreatorTypes = new function() {
|
|||
Zotero.CachedTypes.apply(this, arguments);
|
||||
this.constructor.prototype = new Zotero.CachedTypes();
|
||||
|
||||
this.getTypesForItemType = getTypesForItemType;
|
||||
this.isValidForItemType = isValidForItemType;
|
||||
|
||||
this._typeDesc = 'creator type';
|
||||
|
@ -237,11 +236,8 @@ Zotero.CreatorTypes = new function() {
|
|||
this.init = Zotero.Promise.coroutine(function* () {
|
||||
yield this.constructor.prototype.init.apply(this);
|
||||
|
||||
var sql = "SELECT itemTypeID, creatorTypeID AS id, creatorType AS name "
|
||||
+ "FROM itemTypeCreatorTypes NATURAL JOIN creatorTypes "
|
||||
// DEBUG: sort needs to be on localized strings in itemPane.js
|
||||
// (though still put primary field at top)
|
||||
+ "ORDER BY primaryField=1 DESC, name";
|
||||
var sql = "SELECT itemTypeID, creatorTypeID AS id, creatorType AS name, primaryField "
|
||||
+ "FROM itemTypeCreatorTypes NATURAL JOIN creatorTypes";
|
||||
var rows = yield Zotero.DB.queryAsync(sql);
|
||||
for (let i=0; i<rows.length; i++) {
|
||||
let row = rows[i];
|
||||
|
@ -251,7 +247,20 @@ Zotero.CreatorTypes = new function() {
|
|||
}
|
||||
_creatorTypesByItemType[itemTypeID].push({
|
||||
id: row.id,
|
||||
name: row.name
|
||||
name: row.name,
|
||||
primaryField: row.primaryField,
|
||||
localizedName: this.getLocalizedString(row.name)
|
||||
});
|
||||
}
|
||||
// Sort primary field first, then by localized name
|
||||
for (let itemTypeID in _creatorTypesByItemType) {
|
||||
_creatorTypesByItemType[itemTypeID].sort((a, b) => {
|
||||
if (a.primaryField != b.primaryField) return b.primaryField - a.primaryField;
|
||||
return Zotero.localeCompare(a.localizedName, b.localizedName);
|
||||
});
|
||||
_creatorTypesByItemType[itemTypeID].forEach((x) => {
|
||||
delete x.primaryField;
|
||||
delete x.localizedName;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -267,11 +276,10 @@ Zotero.CreatorTypes = new function() {
|
|||
});
|
||||
|
||||
|
||||
function getTypesForItemType(itemTypeID) {
|
||||
this.getTypesForItemType = function (itemTypeID) {
|
||||
if (!_creatorTypesByItemType[itemTypeID]) {
|
||||
throw new Error("Creator types not loaded for itemTypeID " + itemTypeID);
|
||||
return [];
|
||||
}
|
||||
|
||||
return _creatorTypesByItemType[itemTypeID];
|
||||
}
|
||||
|
||||
|
@ -451,44 +459,44 @@ Zotero.ItemTypes = new function() {
|
|||
|
||||
// HiDPI images available
|
||||
case 'attachment-link':
|
||||
case 'attachment-pdf':
|
||||
case 'attachment-web-link':
|
||||
case 'artwork':
|
||||
case 'audioRecording':
|
||||
case 'bill':
|
||||
case 'blogPost':
|
||||
case 'book':
|
||||
case 'bookSection':
|
||||
case 'case':
|
||||
case 'computerProgram':
|
||||
case 'dictionaryEntry':
|
||||
case 'email':
|
||||
case 'encyclopediaArticle':
|
||||
case 'film':
|
||||
case 'forumPost':
|
||||
case 'hearing':
|
||||
case 'instantMessage':
|
||||
case 'interview':
|
||||
case 'journalArticle':
|
||||
case 'letter':
|
||||
case 'magazineArticle':
|
||||
case 'manuscript':
|
||||
case 'newspaperArticle':
|
||||
case 'note':
|
||||
case 'patent':
|
||||
case 'presentation':
|
||||
case 'report':
|
||||
case 'statute':
|
||||
case 'thesis':
|
||||
case 'webpage':
|
||||
return "chrome://zotero/skin/treeitem-" + itemType + suffix + ".png";
|
||||
|
||||
// No HiDPI images available
|
||||
case 'attachment-snapshot':
|
||||
case 'attachment-pdf':
|
||||
case 'blogPost':
|
||||
case 'case':
|
||||
case 'conferencePaper':
|
||||
case 'dictionaryEntry':
|
||||
case 'email':
|
||||
case 'encyclopediaArticle':
|
||||
case 'hearing':
|
||||
case 'manuscript':
|
||||
case 'map':
|
||||
case 'patent':
|
||||
case 'podcast':
|
||||
case 'presentation':
|
||||
case 'radioBroadcast':
|
||||
case 'statute':
|
||||
case 'thesis':
|
||||
case 'tvBroadcast':
|
||||
case 'videoRecording':
|
||||
return "chrome://zotero/skin/treeitem-" + itemType + ".png";
|
||||
|
|
|
@ -80,7 +80,8 @@ Zotero.defineProperty(Zotero.Collection.prototype, 'parent', {
|
|||
set: function(val) {
|
||||
Zotero.debug("WARNING: Zotero.Collection.prototype.parent has been deprecated -- use .parentID or .parentKey", 2);
|
||||
this.parentID = val;
|
||||
}
|
||||
},
|
||||
enumerable: false
|
||||
});
|
||||
|
||||
Zotero.defineProperty(Zotero.Collection.prototype, 'treeViewID', {
|
||||
|
@ -91,8 +92,9 @@ Zotero.defineProperty(Zotero.Collection.prototype, 'treeViewID', {
|
|||
|
||||
Zotero.defineProperty(Zotero.Collection.prototype, 'treeViewImage', {
|
||||
get: function () {
|
||||
// Keep in sync with collectionTreeView::getImageSrc()
|
||||
if (Zotero.isMac) {
|
||||
return "chrome://zotero-platform/content/treesource-collection.png";
|
||||
return `chrome://zotero-platform/content/treesource-collection${Zotero.hiDPISuffix}.png`;
|
||||
}
|
||||
return "chrome://zotero/skin/treesource-collection" + Zotero.hiDPISuffix + ".png";
|
||||
}
|
||||
|
@ -286,20 +288,22 @@ Zotero.Collection.prototype._saveData = Zotero.Promise.coroutine(function* (env)
|
|||
env.parent ? env.parent : null
|
||||
);
|
||||
|
||||
if (isNew) {
|
||||
env.sqlColumns.unshift('collectionID');
|
||||
env.sqlValues.unshift(collectionID ? { int: collectionID } : null);
|
||||
|
||||
let placeholders = env.sqlColumns.map(() => '?').join();
|
||||
let sql = "INSERT INTO collections (" + env.sqlColumns.join(', ') + ") "
|
||||
+ "VALUES (" + placeholders + ")";
|
||||
yield Zotero.DB.queryAsync(sql, env.sqlValues);
|
||||
}
|
||||
else {
|
||||
let sql = 'UPDATE collections SET '
|
||||
+ env.sqlColumns.map(x => x + '=?').join(', ') + ' WHERE collectionID=?';
|
||||
env.sqlValues.push(collectionID ? { int: collectionID } : null);
|
||||
yield Zotero.DB.queryAsync(sql, env.sqlValues);
|
||||
if (env.sqlColumns.length) {
|
||||
if (isNew) {
|
||||
env.sqlColumns.unshift('collectionID');
|
||||
env.sqlValues.unshift(collectionID ? { int: collectionID } : null);
|
||||
|
||||
let placeholders = env.sqlColumns.map(() => '?').join();
|
||||
let sql = "INSERT INTO collections (" + env.sqlColumns.join(', ') + ") "
|
||||
+ "VALUES (" + placeholders + ")";
|
||||
yield Zotero.DB.queryAsync(sql, env.sqlValues);
|
||||
}
|
||||
else {
|
||||
let sql = 'UPDATE collections SET '
|
||||
+ env.sqlColumns.map(x => x + '=?').join(', ') + ' WHERE collectionID=?';
|
||||
env.sqlValues.push(collectionID ? { int: collectionID } : null);
|
||||
yield Zotero.DB.queryAsync(sql, env.sqlValues);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._changed.parentKey) {
|
||||
|
@ -425,7 +429,7 @@ Zotero.Collection.prototype.removeItems = Zotero.Promise.coroutine(function* (it
|
|||
return;
|
||||
}
|
||||
|
||||
var current = this.getChildItems(true);
|
||||
var current = this.getChildItems(true, true);
|
||||
|
||||
Zotero.DB.requireTransaction();
|
||||
for (let i=0; i<itemIDs.length; i++) {
|
||||
|
@ -567,6 +571,7 @@ Zotero.Collection.prototype._eraseData = Zotero.Promise.coroutine(function* (env
|
|||
|
||||
var descendents = this.getDescendents(false, null, true);
|
||||
var items = [];
|
||||
var libraryHasTrash = Zotero.Libraries.hasTrash(this.libraryID);
|
||||
|
||||
var del = [];
|
||||
var itemsToUpdate = [];
|
||||
|
@ -584,19 +589,23 @@ Zotero.Collection.prototype._eraseData = Zotero.Promise.coroutine(function* (env
|
|||
}
|
||||
// Descendent items
|
||||
else {
|
||||
// Delete items from DB
|
||||
// Trash/delete items
|
||||
if (env.options.deleteItems) {
|
||||
del.push(descendents[i].id);
|
||||
}
|
||||
else {
|
||||
|
||||
// If item isn't being removed or is just moving to the trash, mark for update
|
||||
if (!env.options.deleteItems || libraryHasTrash) {
|
||||
itemsToUpdate.push(descendents[i].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (del.length) {
|
||||
if (Zotero.Libraries.hasTrash(this.libraryID)) {
|
||||
if (libraryHasTrash) {
|
||||
yield this.ChildObjects.trash(del);
|
||||
} else {
|
||||
}
|
||||
// If library doesn't have trash, just erase
|
||||
else {
|
||||
Zotero.debug(Zotero.Libraries.getName(this.libraryID) + " library does not have trash. "
|
||||
+ this.ChildObjects._ZDO_Objects + " will be erased");
|
||||
let options = {};
|
||||
|
@ -636,7 +645,7 @@ Zotero.Collection.prototype._eraseData = Zotero.Promise.coroutine(function* (env
|
|||
env.deletedObjectIDs = collections;
|
||||
|
||||
// Update collection cache for descendant items
|
||||
if (!env.options.deleteItems) {
|
||||
if (itemsToUpdate.length) {
|
||||
let deletedCollections = new Set(env.deletedObjectIDs);
|
||||
itemsToUpdate.forEach(itemID => {
|
||||
let item = Zotero.Items.get(itemID);
|
||||
|
@ -689,8 +698,7 @@ Zotero.Collection.prototype.fromJSON = function (json) {
|
|||
this.name = json.name;
|
||||
this.parentKey = json.parentCollection ? json.parentCollection : false;
|
||||
|
||||
// TODO
|
||||
//this.setRelations(json.relations);
|
||||
this.setRelations(json.relations || {});
|
||||
}
|
||||
|
||||
|
||||
|
@ -704,7 +712,7 @@ Zotero.Collection.prototype.toJSON = function (options = {}) {
|
|||
|
||||
obj.name = this.name;
|
||||
obj.parentCollection = this.parentKey ? this.parentKey : false;
|
||||
obj.relations = {}; // TEMP
|
||||
obj.relations = this.getRelations();
|
||||
|
||||
return this._postToJSON(env);
|
||||
}
|
||||
|
|
|
@ -31,16 +31,33 @@ Zotero.Creators = new function() {
|
|||
var _cache = {};
|
||||
|
||||
this.init = Zotero.Promise.coroutine(function* () {
|
||||
var repaired = false;
|
||||
var sql = "SELECT * FROM creators";
|
||||
var rows = yield Zotero.DB.queryAsync(sql);
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
let row = rows[i];
|
||||
_cache[row.creatorID] = this.cleanData({
|
||||
// Avoid "DB column 'name' not found" warnings from the DB row Proxy
|
||||
firstName: row.firstName,
|
||||
lastName: row.lastName,
|
||||
fieldMode: row.fieldMode
|
||||
});
|
||||
try {
|
||||
_cache[row.creatorID] = this.cleanData({
|
||||
// Avoid "DB column 'name' not found" warnings from the DB row Proxy
|
||||
firstName: row.firstName,
|
||||
lastName: row.lastName,
|
||||
fieldMode: row.fieldMode
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
// Automatically fix DB errors and try again
|
||||
if (!repaired) {
|
||||
Zotero.logError(e);
|
||||
Zotero.logError("Trying integrity check to fix creator error");
|
||||
yield Zotero.Schema.integrityCheck(true);
|
||||
repaired = true;
|
||||
rows = yield Zotero.DB.queryAsync(sql);
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user