Version Description
- Enhancement: At long last, support for Microsoft Office files (Word, PowerPoint, Publisher, Visio), as well as a boat-load of other formats, has been re-added to Document Gallery by way of integration with the Thumber.co service. For a small fee you can generate images for all of your attachments using a service designed specifically to work well with Document Gallery. For a limited time, Thumber.co is offering a free 7-day trial of the basic subscription. If you don't like it, all you have to do is cancel and you won't pay a penny.
- Enhancement: The pagination footer now includes more than just "prev" and "next", allowing for quicker navigation of long multi-page galleries. Additionally, the pagination footer will no longer be included if pagination is enabled, but there are less than a page-length's worth of attachments in the gallery.
-
Enhancement: Massive rewrite of some core logic that had become unmaintainable. This will mean nothing to most
users, with the noted exception that if you were using the
dg_thumbers
filter you'll need to change some things. If this applies to you then you'll want to hold off on upgrading until you've had a chance to rework your usage of the filter to map to the new expected values.
Download this release
Release Info
Developer | dan.rossiter |
Plugin | Document Gallery |
Version | 4.1 |
Comparing to | |
See all releases |
Code changes from version 4.0 to 4.1
- LICENSE.txt +617 -282
- README.txt +59 -66
- admin/class-admin.php +60 -999
- admin/class-ajax-handler.php +1 -1
- admin/class-feature-pointers.php +117 -0
- admin/tabs/advanced-tab.php +121 -0
- admin/tabs/general-tab.php +375 -0
- admin/tabs/logging-tab.php +128 -0
- admin/tabs/thumber-co-tab.php +126 -0
- admin/tabs/thumbnail-management-tab.php +328 -0
- assets/css/admin.css +8 -4
- assets/css/admin.min.css +1 -1
- assets/css/style.css +4 -0
- assets/css/style.min.css +1 -1
- assets/js/admin.js +8 -7
- assets/js/admin.min.js +18 -19
- assets/js/gallery.js +15 -9
- assets/js/gallery.min.js +3 -3
- document-gallery.php +3 -9
- inc/class-api.php +4 -7
- inc/class-document-gallery.php +8 -8
- inc/class-document.php +1 -1
- inc/class-gallery-sanitization.php +7 -7
- inc/class-gallery.php +41 -47
- inc/class-image-editor-imagick.php +1 -1
- inc/class-logger.php +5 -5
- inc/class-setup.php +55 -11
- inc/class-thumb.php +11 -6
- inc/class-thumber.php +101 -549
- inc/class-util.php +81 -11
- inc/thumbers/class-abstract-thumber.php +150 -0
- inc/thumbers/class-audio-video-thumber.php +88 -0
- inc/thumbers/class-default-thumber.php +121 -0
- inc/thumbers/class-ghostscript-thumber.php +150 -0
- inc/thumbers/class-image-thumber.php +38 -0
- inc/thumbers/class-imagick-thumber.php +88 -0
- inc/thumbers/class-thumber-co-thumber.php +172 -0
- inc/thumbers/thumber-co/class-thumber-client.php +166 -0
- inc/thumbers/thumber-co/thumber-client/LICENSE.txt +13 -0
- inc/thumbers/thumber-co/thumber-client/base-transaction.php +249 -0
- inc/thumbers/thumber-co/thumber-client/client.php +298 -0
- inc/thumbers/thumber-co/thumber-client/thumb-request.php +155 -0
- inc/thumbers/thumber-co/thumber-client/thumb-response.php +80 -0
- inc/thumbers/thumber-co/thumber-client/thumb-transaction.php +87 -0
LICENSE.txt
CHANGED
@@ -1,281 +1,622 @@
|
|
1 |
GNU GENERAL PUBLIC LICENSE
|
2 |
-
Version
|
3 |
|
4 |
-
Copyright (C)
|
5 |
-
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
6 |
Everyone is permitted to copy and distribute verbatim copies
|
7 |
of this license document, but changing it is not allowed.
|
8 |
|
9 |
Preamble
|
10 |
|
11 |
-
The
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
|
|
|
|
19 |
your programs, too.
|
20 |
|
21 |
When we speak of free software, we are referring to freedom, not
|
22 |
price. Our General Public Licenses are designed to make sure that you
|
23 |
have the freedom to distribute copies of free software (and charge for
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
|
28 |
-
To protect your rights, we need to
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
|
33 |
For example, if you distribute copies of such a program, whether
|
34 |
-
gratis or for a fee, you must
|
35 |
-
you
|
36 |
-
source code. And you must show them these terms so they
|
37 |
-
rights.
|
38 |
-
|
39 |
-
|
40 |
-
(
|
41 |
-
distribute and/or modify
|
42 |
-
|
43 |
-
|
44 |
-
that
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
The precise terms and conditions for copying, distribution and
|
57 |
modification follow.
|
58 |
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
this License.
|
196 |
|
197 |
-
|
198 |
-
|
199 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
otherwise) that contradict the conditions of this License, they do not
|
201 |
-
excuse you from the conditions of this License. If you cannot
|
202 |
-
|
203 |
-
License and any other pertinent obligations, then as a consequence you
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
any
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
impose that choice.
|
225 |
-
|
226 |
-
This section is intended to make thoroughly clear what is believed to
|
227 |
-
be a consequence of the rest of this License.
|
228 |
-
|
229 |
-
8. If the distribution and/or use of the Program is restricted in
|
230 |
-
certain countries either by patents or by copyrighted interfaces, the
|
231 |
-
original copyright holder who places the Program under this License
|
232 |
-
may add an explicit geographical distribution limitation excluding
|
233 |
-
those countries, so that distribution is permitted only in or among
|
234 |
-
countries not thus excluded. In such case, this License incorporates
|
235 |
-
the limitation as if written in the body of this License.
|
236 |
-
|
237 |
-
9. The Free Software Foundation may publish revised and/or new versions
|
238 |
-
of the General Public License from time to time. Such new versions will
|
239 |
be similar in spirit to the present version, but may differ in detail to
|
240 |
address new problems or concerns.
|
241 |
|
242 |
-
Each version is given a distinguishing version number. If the
|
243 |
-
specifies a version
|
244 |
-
later version", you have the
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
|
280 |
END OF TERMS AND CONDITIONS
|
281 |
|
@@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms.
|
|
287 |
|
288 |
To do so, attach the following notices to the program. It is safest
|
289 |
to attach them to the start of each source file to most effectively
|
290 |
-
|
291 |
the "copyright" line and a pointer to where the full notice is found.
|
292 |
|
293 |
<one line to give the program's name and a brief idea of what it does.>
|
294 |
Copyright (C) <year> <name of author>
|
295 |
|
296 |
-
This program is free software
|
297 |
it under the terms of the GNU General Public License as published by
|
298 |
-
the Free Software Foundation
|
299 |
(at your option) any later version.
|
300 |
|
301 |
This program is distributed in the hope that it will be useful,
|
@@ -303,37 +644,31 @@ the "copyright" line and a pointer to where the full notice is found.
|
|
303 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
304 |
GNU General Public License for more details.
|
305 |
|
306 |
-
You should have received a copy of the GNU General Public License
|
307 |
-
with this program
|
308 |
-
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
309 |
|
310 |
Also add information on how to contact you by electronic and paper mail.
|
311 |
|
312 |
-
If the program
|
313 |
-
when it starts in an interactive mode:
|
314 |
|
315 |
-
|
316 |
-
|
317 |
This is free software, and you are welcome to redistribute it
|
318 |
under certain conditions; type `show c' for details.
|
319 |
|
320 |
The hypothetical commands `show w' and `show c' should show the appropriate
|
321 |
-
parts of the General Public License. Of course,
|
322 |
-
be
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
This General Public License does not permit incorporating your program into
|
336 |
-
proprietary programs. If your program is a subroutine library, you may
|
337 |
-
consider it more useful to permit linking proprietary applications with the
|
338 |
-
library. If this is what you want to do, use the GNU Lesser General
|
339 |
-
Public License instead of this License.
|
1 |
GNU GENERAL PUBLIC LICENSE
|
2 |
+
Version 3, 29 June 2007
|
3 |
|
4 |
+
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
|
5 |
Everyone is permitted to copy and distribute verbatim copies
|
6 |
of this license document, but changing it is not allowed.
|
7 |
|
8 |
Preamble
|
9 |
|
10 |
+
The GNU General Public License is a free, copyleft license for
|
11 |
+
software and other kinds of works.
|
12 |
+
|
13 |
+
The licenses for most software and other practical works are designed
|
14 |
+
to take away your freedom to share and change the works. By contrast,
|
15 |
+
the GNU General Public License is intended to guarantee your freedom to
|
16 |
+
share and change all versions of a program--to make sure it remains free
|
17 |
+
software for all its users. We, the Free Software Foundation, use the
|
18 |
+
GNU General Public License for most of our software; it applies also to
|
19 |
+
any other work released this way by its authors. You can apply it to
|
20 |
your programs, too.
|
21 |
|
22 |
When we speak of free software, we are referring to freedom, not
|
23 |
price. Our General Public Licenses are designed to make sure that you
|
24 |
have the freedom to distribute copies of free software (and charge for
|
25 |
+
them if you wish), that you receive source code or can get it if you
|
26 |
+
want it, that you can change the software or use pieces of it in new
|
27 |
+
free programs, and that you know you can do these things.
|
28 |
|
29 |
+
To protect your rights, we need to prevent others from denying you
|
30 |
+
these rights or asking you to surrender the rights. Therefore, you have
|
31 |
+
certain responsibilities if you distribute copies of the software, or if
|
32 |
+
you modify it: responsibilities to respect the freedom of others.
|
33 |
|
34 |
For example, if you distribute copies of such a program, whether
|
35 |
+
gratis or for a fee, you must pass on to the recipients the same
|
36 |
+
freedoms that you received. You must make sure that they, too, receive
|
37 |
+
or can get the source code. And you must show them these terms so they
|
38 |
+
know their rights.
|
39 |
+
|
40 |
+
Developers that use the GNU GPL protect your rights with two steps:
|
41 |
+
(1) assert copyright on the software, and (2) offer you this License
|
42 |
+
giving you legal permission to copy, distribute and/or modify it.
|
43 |
+
|
44 |
+
For the developers' and authors' protection, the GPL clearly explains
|
45 |
+
that there is no warranty for this free software. For both users' and
|
46 |
+
authors' sake, the GPL requires that modified versions be marked as
|
47 |
+
changed, so that their problems will not be attributed erroneously to
|
48 |
+
authors of previous versions.
|
49 |
+
|
50 |
+
Some devices are designed to deny users access to install or run
|
51 |
+
modified versions of the software inside them, although the manufacturer
|
52 |
+
can do so. This is fundamentally incompatible with the aim of
|
53 |
+
protecting users' freedom to change the software. The systematic
|
54 |
+
pattern of such abuse occurs in the area of products for individuals to
|
55 |
+
use, which is precisely where it is most unacceptable. Therefore, we
|
56 |
+
have designed this version of the GPL to prohibit the practice for those
|
57 |
+
products. If such problems arise substantially in other domains, we
|
58 |
+
stand ready to extend this provision to those domains in future versions
|
59 |
+
of the GPL, as needed to protect the freedom of users.
|
60 |
+
|
61 |
+
Finally, every program is threatened constantly by software patents.
|
62 |
+
States should not allow patents to restrict development and use of
|
63 |
+
software on general-purpose computers, but in those that do, we wish to
|
64 |
+
avoid the special danger that patents applied to a free program could
|
65 |
+
make it effectively proprietary. To prevent this, the GPL assures that
|
66 |
+
patents cannot be used to render the program non-free.
|
67 |
|
68 |
The precise terms and conditions for copying, distribution and
|
69 |
modification follow.
|
70 |
|
71 |
+
TERMS AND CONDITIONS
|
72 |
+
|
73 |
+
0. Definitions.
|
74 |
+
|
75 |
+
"This License" refers to version 3 of the GNU General Public License.
|
76 |
+
|
77 |
+
"Copyright" also means copyright-like laws that apply to other kinds of
|
78 |
+
works, such as semiconductor masks.
|
79 |
+
|
80 |
+
"The Program" refers to any copyrightable work licensed under this
|
81 |
+
License. Each licensee is addressed as "you". "Licensees" and
|
82 |
+
"recipients" may be individuals or organizations.
|
83 |
+
|
84 |
+
To "modify" a work means to copy from or adapt all or part of the work
|
85 |
+
in a fashion requiring copyright permission, other than the making of an
|
86 |
+
exact copy. The resulting work is called a "modified version" of the
|
87 |
+
earlier work or a work "based on" the earlier work.
|
88 |
+
|
89 |
+
A "covered work" means either the unmodified Program or a work based
|
90 |
+
on the Program.
|
91 |
+
|
92 |
+
To "propagate" a work means to do anything with it that, without
|
93 |
+
permission, would make you directly or secondarily liable for
|
94 |
+
infringement under applicable copyright law, except executing it on a
|
95 |
+
computer or modifying a private copy. Propagation includes copying,
|
96 |
+
distribution (with or without modification), making available to the
|
97 |
+
public, and in some countries other activities as well.
|
98 |
+
|
99 |
+
To "convey" a work means any kind of propagation that enables other
|
100 |
+
parties to make or receive copies. Mere interaction with a user through
|
101 |
+
a computer network, with no transfer of a copy, is not conveying.
|
102 |
+
|
103 |
+
An interactive user interface displays "Appropriate Legal Notices"
|
104 |
+
to the extent that it includes a convenient and prominently visible
|
105 |
+
feature that (1) displays an appropriate copyright notice, and (2)
|
106 |
+
tells the user that there is no warranty for the work (except to the
|
107 |
+
extent that warranties are provided), that licensees may convey the
|
108 |
+
work under this License, and how to view a copy of this License. If
|
109 |
+
the interface presents a list of user commands or options, such as a
|
110 |
+
menu, a prominent item in the list meets this criterion.
|
111 |
+
|
112 |
+
1. Source Code.
|
113 |
+
|
114 |
+
The "source code" for a work means the preferred form of the work
|
115 |
+
for making modifications to it. "Object code" means any non-source
|
116 |
+
form of a work.
|
117 |
+
|
118 |
+
A "Standard Interface" means an interface that either is an official
|
119 |
+
standard defined by a recognized standards body, or, in the case of
|
120 |
+
interfaces specified for a particular programming language, one that
|
121 |
+
is widely used among developers working in that language.
|
122 |
+
|
123 |
+
The "System Libraries" of an executable work include anything, other
|
124 |
+
than the work as a whole, that (a) is included in the normal form of
|
125 |
+
packaging a Major Component, but which is not part of that Major
|
126 |
+
Component, and (b) serves only to enable use of the work with that
|
127 |
+
Major Component, or to implement a Standard Interface for which an
|
128 |
+
implementation is available to the public in source code form. A
|
129 |
+
"Major Component", in this context, means a major essential component
|
130 |
+
(kernel, window system, and so on) of the specific operating system
|
131 |
+
(if any) on which the executable work runs, or a compiler used to
|
132 |
+
produce the work, or an object code interpreter used to run it.
|
133 |
+
|
134 |
+
The "Corresponding Source" for a work in object code form means all
|
135 |
+
the source code needed to generate, install, and (for an executable
|
136 |
+
work) run the object code and to modify the work, including scripts to
|
137 |
+
control those activities. However, it does not include the work's
|
138 |
+
System Libraries, or general-purpose tools or generally available free
|
139 |
+
programs which are used unmodified in performing those activities but
|
140 |
+
which are not part of the work. For example, Corresponding Source
|
141 |
+
includes interface definition files associated with source files for
|
142 |
+
the work, and the source code for shared libraries and dynamically
|
143 |
+
linked subprograms that the work is specifically designed to require,
|
144 |
+
such as by intimate data communication or control flow between those
|
145 |
+
subprograms and other parts of the work.
|
146 |
+
|
147 |
+
The Corresponding Source need not include anything that users
|
148 |
+
can regenerate automatically from other parts of the Corresponding
|
149 |
+
Source.
|
150 |
+
|
151 |
+
The Corresponding Source for a work in source code form is that
|
152 |
+
same work.
|
153 |
+
|
154 |
+
2. Basic Permissions.
|
155 |
+
|
156 |
+
All rights granted under this License are granted for the term of
|
157 |
+
copyright on the Program, and are irrevocable provided the stated
|
158 |
+
conditions are met. This License explicitly affirms your unlimited
|
159 |
+
permission to run the unmodified Program. The output from running a
|
160 |
+
covered work is covered by this License only if the output, given its
|
161 |
+
content, constitutes a covered work. This License acknowledges your
|
162 |
+
rights of fair use or other equivalent, as provided by copyright law.
|
163 |
+
|
164 |
+
You may make, run and propagate covered works that you do not
|
165 |
+
convey, without conditions so long as your license otherwise remains
|
166 |
+
in force. You may convey covered works to others for the sole purpose
|
167 |
+
of having them make modifications exclusively for you, or provide you
|
168 |
+
with facilities for running those works, provided that you comply with
|
169 |
+
the terms of this License in conveying all material for which you do
|
170 |
+
not control copyright. Those thus making or running the covered works
|
171 |
+
for you must do so exclusively on your behalf, under your direction
|
172 |
+
and control, on terms that prohibit them from making any copies of
|
173 |
+
your copyrighted material outside their relationship with you.
|
174 |
+
|
175 |
+
Conveying under any other circumstances is permitted solely under
|
176 |
+
the conditions stated below. Sublicensing is not allowed; section 10
|
177 |
+
makes it unnecessary.
|
178 |
+
|
179 |
+
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
180 |
+
|
181 |
+
No covered work shall be deemed part of an effective technological
|
182 |
+
measure under any applicable law fulfilling obligations under article
|
183 |
+
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
184 |
+
similar laws prohibiting or restricting circumvention of such
|
185 |
+
measures.
|
186 |
+
|
187 |
+
When you convey a covered work, you waive any legal power to forbid
|
188 |
+
circumvention of technological measures to the extent such circumvention
|
189 |
+
is effected by exercising rights under this License with respect to
|
190 |
+
the covered work, and you disclaim any intention to limit operation or
|
191 |
+
modification of the work as a means of enforcing, against the work's
|
192 |
+
users, your or third parties' legal rights to forbid circumvention of
|
193 |
+
technological measures.
|
194 |
+
|
195 |
+
4. Conveying Verbatim Copies.
|
196 |
+
|
197 |
+
You may convey verbatim copies of the Program's source code as you
|
198 |
+
receive it, in any medium, provided that you conspicuously and
|
199 |
+
appropriately publish on each copy an appropriate copyright notice;
|
200 |
+
keep intact all notices stating that this License and any
|
201 |
+
non-permissive terms added in accord with section 7 apply to the code;
|
202 |
+
keep intact all notices of the absence of any warranty; and give all
|
203 |
+
recipients a copy of this License along with the Program.
|
204 |
+
|
205 |
+
You may charge any price or no price for each copy that you convey,
|
206 |
+
and you may offer support or warranty protection for a fee.
|
207 |
+
|
208 |
+
5. Conveying Modified Source Versions.
|
209 |
+
|
210 |
+
You may convey a work based on the Program, or the modifications to
|
211 |
+
produce it from the Program, in the form of source code under the
|
212 |
+
terms of section 4, provided that you also meet all of these conditions:
|
213 |
+
|
214 |
+
a) The work must carry prominent notices stating that you modified
|
215 |
+
it, and giving a relevant date.
|
216 |
+
|
217 |
+
b) The work must carry prominent notices stating that it is
|
218 |
+
released under this License and any conditions added under section
|
219 |
+
7. This requirement modifies the requirement in section 4 to
|
220 |
+
"keep intact all notices".
|
221 |
+
|
222 |
+
c) You must license the entire work, as a whole, under this
|
223 |
+
License to anyone who comes into possession of a copy. This
|
224 |
+
License will therefore apply, along with any applicable section 7
|
225 |
+
additional terms, to the whole of the work, and all its parts,
|
226 |
+
regardless of how they are packaged. This License gives no
|
227 |
+
permission to license the work in any other way, but it does not
|
228 |
+
invalidate such permission if you have separately received it.
|
229 |
+
|
230 |
+
d) If the work has interactive user interfaces, each must display
|
231 |
+
Appropriate Legal Notices; however, if the Program has interactive
|
232 |
+
interfaces that do not display Appropriate Legal Notices, your
|
233 |
+
work need not make them do so.
|
234 |
+
|
235 |
+
A compilation of a covered work with other separate and independent
|
236 |
+
works, which are not by their nature extensions of the covered work,
|
237 |
+
and which are not combined with it such as to form a larger program,
|
238 |
+
in or on a volume of a storage or distribution medium, is called an
|
239 |
+
"aggregate" if the compilation and its resulting copyright are not
|
240 |
+
used to limit the access or legal rights of the compilation's users
|
241 |
+
beyond what the individual works permit. Inclusion of a covered work
|
242 |
+
in an aggregate does not cause this License to apply to the other
|
243 |
+
parts of the aggregate.
|
244 |
+
|
245 |
+
6. Conveying Non-Source Forms.
|
246 |
+
|
247 |
+
You may convey a covered work in object code form under the terms
|
248 |
+
of sections 4 and 5, provided that you also convey the
|
249 |
+
machine-readable Corresponding Source under the terms of this License,
|
250 |
+
in one of these ways:
|
251 |
+
|
252 |
+
a) Convey the object code in, or embodied in, a physical product
|
253 |
+
(including a physical distribution medium), accompanied by the
|
254 |
+
Corresponding Source fixed on a durable physical medium
|
255 |
+
customarily used for software interchange.
|
256 |
+
|
257 |
+
b) Convey the object code in, or embodied in, a physical product
|
258 |
+
(including a physical distribution medium), accompanied by a
|
259 |
+
written offer, valid for at least three years and valid for as
|
260 |
+
long as you offer spare parts or customer support for that product
|
261 |
+
model, to give anyone who possesses the object code either (1) a
|
262 |
+
copy of the Corresponding Source for all the software in the
|
263 |
+
product that is covered by this License, on a durable physical
|
264 |
+
medium customarily used for software interchange, for a price no
|
265 |
+
more than your reasonable cost of physically performing this
|
266 |
+
conveying of source, or (2) access to copy the
|
267 |
+
Corresponding Source from a network server at no charge.
|
268 |
+
|
269 |
+
c) Convey individual copies of the object code with a copy of the
|
270 |
+
written offer to provide the Corresponding Source. This
|
271 |
+
alternative is allowed only occasionally and noncommercially, and
|
272 |
+
only if you received the object code with such an offer, in accord
|
273 |
+
with subsection 6b.
|
274 |
+
|
275 |
+
d) Convey the object code by offering access from a designated
|
276 |
+
place (gratis or for a charge), and offer equivalent access to the
|
277 |
+
Corresponding Source in the same way through the same place at no
|
278 |
+
further charge. You need not require recipients to copy the
|
279 |
+
Corresponding Source along with the object code. If the place to
|
280 |
+
copy the object code is a network server, the Corresponding Source
|
281 |
+
may be on a different server (operated by you or a third party)
|
282 |
+
that supports equivalent copying facilities, provided you maintain
|
283 |
+
clear directions next to the object code saying where to find the
|
284 |
+
Corresponding Source. Regardless of what server hosts the
|
285 |
+
Corresponding Source, you remain obligated to ensure that it is
|
286 |
+
available for as long as needed to satisfy these requirements.
|
287 |
+
|
288 |
+
e) Convey the object code using peer-to-peer transmission, provided
|
289 |
+
you inform other peers where the object code and Corresponding
|
290 |
+
Source of the work are being offered to the general public at no
|
291 |
+
charge under subsection 6d.
|
292 |
+
|
293 |
+
A separable portion of the object code, whose source code is excluded
|
294 |
+
from the Corresponding Source as a System Library, need not be
|
295 |
+
included in conveying the object code work.
|
296 |
+
|
297 |
+
A "User Product" is either (1) a "consumer product", which means any
|
298 |
+
tangible personal property which is normally used for personal, family,
|
299 |
+
or household purposes, or (2) anything designed or sold for incorporation
|
300 |
+
into a dwelling. In determining whether a product is a consumer product,
|
301 |
+
doubtful cases shall be resolved in favor of coverage. For a particular
|
302 |
+
product received by a particular user, "normally used" refers to a
|
303 |
+
typical or common use of that class of product, regardless of the status
|
304 |
+
of the particular user or of the way in which the particular user
|
305 |
+
actually uses, or expects or is expected to use, the product. A product
|
306 |
+
is a consumer product regardless of whether the product has substantial
|
307 |
+
commercial, industrial or non-consumer uses, unless such uses represent
|
308 |
+
the only significant mode of use of the product.
|
309 |
+
|
310 |
+
"Installation Information" for a User Product means any methods,
|
311 |
+
procedures, authorization keys, or other information required to install
|
312 |
+
and execute modified versions of a covered work in that User Product from
|
313 |
+
a modified version of its Corresponding Source. The information must
|
314 |
+
suffice to ensure that the continued functioning of the modified object
|
315 |
+
code is in no case prevented or interfered with solely because
|
316 |
+
modification has been made.
|
317 |
+
|
318 |
+
If you convey an object code work under this section in, or with, or
|
319 |
+
specifically for use in, a User Product, and the conveying occurs as
|
320 |
+
part of a transaction in which the right of possession and use of the
|
321 |
+
User Product is transferred to the recipient in perpetuity or for a
|
322 |
+
fixed term (regardless of how the transaction is characterized), the
|
323 |
+
Corresponding Source conveyed under this section must be accompanied
|
324 |
+
by the Installation Information. But this requirement does not apply
|
325 |
+
if neither you nor any third party retains the ability to install
|
326 |
+
modified object code on the User Product (for example, the work has
|
327 |
+
been installed in ROM).
|
328 |
+
|
329 |
+
The requirement to provide Installation Information does not include a
|
330 |
+
requirement to continue to provide support service, warranty, or updates
|
331 |
+
for a work that has been modified or installed by the recipient, or for
|
332 |
+
the User Product in which it has been modified or installed. Access to a
|
333 |
+
network may be denied when the modification itself materially and
|
334 |
+
adversely affects the operation of the network or violates the rules and
|
335 |
+
protocols for communication across the network.
|
336 |
+
|
337 |
+
Corresponding Source conveyed, and Installation Information provided,
|
338 |
+
in accord with this section must be in a format that is publicly
|
339 |
+
documented (and with an implementation available to the public in
|
340 |
+
source code form), and must require no special password or key for
|
341 |
+
unpacking, reading or copying.
|
342 |
+
|
343 |
+
7. Additional Terms.
|
344 |
+
|
345 |
+
"Additional permissions" are terms that supplement the terms of this
|
346 |
+
License by making exceptions from one or more of its conditions.
|
347 |
+
Additional permissions that are applicable to the entire Program shall
|
348 |
+
be treated as though they were included in this License, to the extent
|
349 |
+
that they are valid under applicable law. If additional permissions
|
350 |
+
apply only to part of the Program, that part may be used separately
|
351 |
+
under those permissions, but the entire Program remains governed by
|
352 |
+
this License without regard to the additional permissions.
|
353 |
+
|
354 |
+
When you convey a copy of a covered work, you may at your option
|
355 |
+
remove any additional permissions from that copy, or from any part of
|
356 |
+
it. (Additional permissions may be written to require their own
|
357 |
+
removal in certain cases when you modify the work.) You may place
|
358 |
+
additional permissions on material, added by you to a covered work,
|
359 |
+
for which you have or can give appropriate copyright permission.
|
360 |
+
|
361 |
+
Notwithstanding any other provision of this License, for material you
|
362 |
+
add to a covered work, you may (if authorized by the copyright holders of
|
363 |
+
that material) supplement the terms of this License with terms:
|
364 |
+
|
365 |
+
a) Disclaiming warranty or limiting liability differently from the
|
366 |
+
terms of sections 15 and 16 of this License; or
|
367 |
+
|
368 |
+
b) Requiring preservation of specified reasonable legal notices or
|
369 |
+
author attributions in that material or in the Appropriate Legal
|
370 |
+
Notices displayed by works containing it; or
|
371 |
+
|
372 |
+
c) Prohibiting misrepresentation of the origin of that material, or
|
373 |
+
requiring that modified versions of such material be marked in
|
374 |
+
reasonable ways as different from the original version; or
|
375 |
+
|
376 |
+
d) Limiting the use for publicity purposes of names of licensors or
|
377 |
+
authors of the material; or
|
378 |
+
|
379 |
+
e) Declining to grant rights under trademark law for use of some
|
380 |
+
trade names, trademarks, or service marks; or
|
381 |
+
|
382 |
+
f) Requiring indemnification of licensors and authors of that
|
383 |
+
material by anyone who conveys the material (or modified versions of
|
384 |
+
it) with contractual assumptions of liability to the recipient, for
|
385 |
+
any liability that these contractual assumptions directly impose on
|
386 |
+
those licensors and authors.
|
387 |
+
|
388 |
+
All other non-permissive additional terms are considered "further
|
389 |
+
restrictions" within the meaning of section 10. If the Program as you
|
390 |
+
received it, or any part of it, contains a notice stating that it is
|
391 |
+
governed by this License along with a term that is a further
|
392 |
+
restriction, you may remove that term. If a license document contains
|
393 |
+
a further restriction but permits relicensing or conveying under this
|
394 |
+
License, you may add to a covered work material governed by the terms
|
395 |
+
of that license document, provided that the further restriction does
|
396 |
+
not survive such relicensing or conveying.
|
397 |
+
|
398 |
+
If you add terms to a covered work in accord with this section, you
|
399 |
+
must place, in the relevant source files, a statement of the
|
400 |
+
additional terms that apply to those files, or a notice indicating
|
401 |
+
where to find the applicable terms.
|
402 |
+
|
403 |
+
Additional terms, permissive or non-permissive, may be stated in the
|
404 |
+
form of a separately written license, or stated as exceptions;
|
405 |
+
the above requirements apply either way.
|
406 |
+
|
407 |
+
8. Termination.
|
408 |
+
|
409 |
+
You may not propagate or modify a covered work except as expressly
|
410 |
+
provided under this License. Any attempt otherwise to propagate or
|
411 |
+
modify it is void, and will automatically terminate your rights under
|
412 |
+
this License (including any patent licenses granted under the third
|
413 |
+
paragraph of section 11).
|
414 |
+
|
415 |
+
However, if you cease all violation of this License, then your
|
416 |
+
license from a particular copyright holder is reinstated (a)
|
417 |
+
provisionally, unless and until the copyright holder explicitly and
|
418 |
+
finally terminates your license, and (b) permanently, if the copyright
|
419 |
+
holder fails to notify you of the violation by some reasonable means
|
420 |
+
prior to 60 days after the cessation.
|
421 |
+
|
422 |
+
Moreover, your license from a particular copyright holder is
|
423 |
+
reinstated permanently if the copyright holder notifies you of the
|
424 |
+
violation by some reasonable means, this is the first time you have
|
425 |
+
received notice of violation of this License (for any work) from that
|
426 |
+
copyright holder, and you cure the violation prior to 30 days after
|
427 |
+
your receipt of the notice.
|
428 |
+
|
429 |
+
Termination of your rights under this section does not terminate the
|
430 |
+
licenses of parties who have received copies or rights from you under
|
431 |
+
this License. If your rights have been terminated and not permanently
|
432 |
+
reinstated, you do not qualify to receive new licenses for the same
|
433 |
+
material under section 10.
|
434 |
+
|
435 |
+
9. Acceptance Not Required for Having Copies.
|
436 |
+
|
437 |
+
You are not required to accept this License in order to receive or
|
438 |
+
run a copy of the Program. Ancillary propagation of a covered work
|
439 |
+
occurring solely as a consequence of using peer-to-peer transmission
|
440 |
+
to receive a copy likewise does not require acceptance. However,
|
441 |
+
nothing other than this License grants you permission to propagate or
|
442 |
+
modify any covered work. These actions infringe copyright if you do
|
443 |
+
not accept this License. Therefore, by modifying or propagating a
|
444 |
+
covered work, you indicate your acceptance of this License to do so.
|
445 |
+
|
446 |
+
10. Automatic Licensing of Downstream Recipients.
|
447 |
+
|
448 |
+
Each time you convey a covered work, the recipient automatically
|
449 |
+
receives a license from the original licensors, to run, modify and
|
450 |
+
propagate that work, subject to this License. You are not responsible
|
451 |
+
for enforcing compliance by third parties with this License.
|
452 |
+
|
453 |
+
An "entity transaction" is a transaction transferring control of an
|
454 |
+
organization, or substantially all assets of one, or subdividing an
|
455 |
+
organization, or merging organizations. If propagation of a covered
|
456 |
+
work results from an entity transaction, each party to that
|
457 |
+
transaction who receives a copy of the work also receives whatever
|
458 |
+
licenses to the work the party's predecessor in interest had or could
|
459 |
+
give under the previous paragraph, plus a right to possession of the
|
460 |
+
Corresponding Source of the work from the predecessor in interest, if
|
461 |
+
the predecessor has it or can get it with reasonable efforts.
|
462 |
+
|
463 |
+
You may not impose any further restrictions on the exercise of the
|
464 |
+
rights granted or affirmed under this License. For example, you may
|
465 |
+
not impose a license fee, royalty, or other charge for exercise of
|
466 |
+
rights granted under this License, and you may not initiate litigation
|
467 |
+
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
468 |
+
any patent claim is infringed by making, using, selling, offering for
|
469 |
+
sale, or importing the Program or any portion of it.
|
470 |
+
|
471 |
+
11. Patents.
|
472 |
+
|
473 |
+
A "contributor" is a copyright holder who authorizes use under this
|
474 |
+
License of the Program or a work on which the Program is based. The
|
475 |
+
work thus licensed is called the contributor's "contributor version".
|
476 |
+
|
477 |
+
A contributor's "essential patent claims" are all patent claims
|
478 |
+
owned or controlled by the contributor, whether already acquired or
|
479 |
+
hereafter acquired, that would be infringed by some manner, permitted
|
480 |
+
by this License, of making, using, or selling its contributor version,
|
481 |
+
but do not include claims that would be infringed only as a
|
482 |
+
consequence of further modification of the contributor version. For
|
483 |
+
purposes of this definition, "control" includes the right to grant
|
484 |
+
patent sublicenses in a manner consistent with the requirements of
|
485 |
this License.
|
486 |
|
487 |
+
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
488 |
+
patent license under the contributor's essential patent claims, to
|
489 |
+
make, use, sell, offer for sale, import and otherwise run, modify and
|
490 |
+
propagate the contents of its contributor version.
|
491 |
+
|
492 |
+
In the following three paragraphs, a "patent license" is any express
|
493 |
+
agreement or commitment, however denominated, not to enforce a patent
|
494 |
+
(such as an express permission to practice a patent or covenant not to
|
495 |
+
sue for patent infringement). To "grant" such a patent license to a
|
496 |
+
party means to make such an agreement or commitment not to enforce a
|
497 |
+
patent against the party.
|
498 |
+
|
499 |
+
If you convey a covered work, knowingly relying on a patent license,
|
500 |
+
and the Corresponding Source of the work is not available for anyone
|
501 |
+
to copy, free of charge and under the terms of this License, through a
|
502 |
+
publicly available network server or other readily accessible means,
|
503 |
+
then you must either (1) cause the Corresponding Source to be so
|
504 |
+
available, or (2) arrange to deprive yourself of the benefit of the
|
505 |
+
patent license for this particular work, or (3) arrange, in a manner
|
506 |
+
consistent with the requirements of this License, to extend the patent
|
507 |
+
license to downstream recipients. "Knowingly relying" means you have
|
508 |
+
actual knowledge that, but for the patent license, your conveying the
|
509 |
+
covered work in a country, or your recipient's use of the covered work
|
510 |
+
in a country, would infringe one or more identifiable patents in that
|
511 |
+
country that you have reason to believe are valid.
|
512 |
+
|
513 |
+
If, pursuant to or in connection with a single transaction or
|
514 |
+
arrangement, you convey, or propagate by procuring conveyance of, a
|
515 |
+
covered work, and grant a patent license to some of the parties
|
516 |
+
receiving the covered work authorizing them to use, propagate, modify
|
517 |
+
or convey a specific copy of the covered work, then the patent license
|
518 |
+
you grant is automatically extended to all recipients of the covered
|
519 |
+
work and works based on it.
|
520 |
+
|
521 |
+
A patent license is "discriminatory" if it does not include within
|
522 |
+
the scope of its coverage, prohibits the exercise of, or is
|
523 |
+
conditioned on the non-exercise of one or more of the rights that are
|
524 |
+
specifically granted under this License. You may not convey a covered
|
525 |
+
work if you are a party to an arrangement with a third party that is
|
526 |
+
in the business of distributing software, under which you make payment
|
527 |
+
to the third party based on the extent of your activity of conveying
|
528 |
+
the work, and under which the third party grants, to any of the
|
529 |
+
parties who would receive the covered work from you, a discriminatory
|
530 |
+
patent license (a) in connection with copies of the covered work
|
531 |
+
conveyed by you (or copies made from those copies), or (b) primarily
|
532 |
+
for and in connection with specific products or compilations that
|
533 |
+
contain the covered work, unless you entered into that arrangement,
|
534 |
+
or that patent license was granted, prior to 28 March 2007.
|
535 |
+
|
536 |
+
Nothing in this License shall be construed as excluding or limiting
|
537 |
+
any implied license or other defenses to infringement that may
|
538 |
+
otherwise be available to you under applicable patent law.
|
539 |
+
|
540 |
+
12. No Surrender of Others' Freedom.
|
541 |
+
|
542 |
+
If conditions are imposed on you (whether by court order, agreement or
|
543 |
otherwise) that contradict the conditions of this License, they do not
|
544 |
+
excuse you from the conditions of this License. If you cannot convey a
|
545 |
+
covered work so as to satisfy simultaneously your obligations under this
|
546 |
+
License and any other pertinent obligations, then as a consequence you may
|
547 |
+
not convey it at all. For example, if you agree to terms that obligate you
|
548 |
+
to collect a royalty for further conveying from those to whom you convey
|
549 |
+
the Program, the only way you could satisfy both those terms and this
|
550 |
+
License would be to refrain entirely from conveying the Program.
|
551 |
+
|
552 |
+
13. Use with the GNU Affero General Public License.
|
553 |
+
|
554 |
+
Notwithstanding any other provision of this License, you have
|
555 |
+
permission to link or combine any covered work with a work licensed
|
556 |
+
under version 3 of the GNU Affero General Public License into a single
|
557 |
+
combined work, and to convey the resulting work. The terms of this
|
558 |
+
License will continue to apply to the part which is the covered work,
|
559 |
+
but the special requirements of the GNU Affero General Public License,
|
560 |
+
section 13, concerning interaction through a network will apply to the
|
561 |
+
combination as such.
|
562 |
+
|
563 |
+
14. Revised Versions of this License.
|
564 |
+
|
565 |
+
The Free Software Foundation may publish revised and/or new versions of
|
566 |
+
the GNU General Public License from time to time. Such new versions will
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
567 |
be similar in spirit to the present version, but may differ in detail to
|
568 |
address new problems or concerns.
|
569 |
|
570 |
+
Each version is given a distinguishing version number. If the
|
571 |
+
Program specifies that a certain numbered version of the GNU General
|
572 |
+
Public License "or any later version" applies to it, you have the
|
573 |
+
option of following the terms and conditions either of that numbered
|
574 |
+
version or of any later version published by the Free Software
|
575 |
+
Foundation. If the Program does not specify a version number of the
|
576 |
+
GNU General Public License, you may choose any version ever published
|
577 |
+
by the Free Software Foundation.
|
578 |
+
|
579 |
+
If the Program specifies that a proxy can decide which future
|
580 |
+
versions of the GNU General Public License can be used, that proxy's
|
581 |
+
public statement of acceptance of a version permanently authorizes you
|
582 |
+
to choose that version for the Program.
|
583 |
+
|
584 |
+
Later license versions may give you additional or different
|
585 |
+
permissions. However, no additional obligations are imposed on any
|
586 |
+
author or copyright holder as a result of your choosing to follow a
|
587 |
+
later version.
|
588 |
+
|
589 |
+
15. Disclaimer of Warranty.
|
590 |
+
|
591 |
+
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
592 |
+
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
593 |
+
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
594 |
+
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
595 |
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
596 |
+
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
597 |
+
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
598 |
+
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
599 |
+
|
600 |
+
16. Limitation of Liability.
|
601 |
+
|
602 |
+
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
603 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
604 |
+
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
605 |
+
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
606 |
+
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
607 |
+
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
608 |
+
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
609 |
+
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
610 |
+
SUCH DAMAGES.
|
611 |
+
|
612 |
+
17. Interpretation of Sections 15 and 16.
|
613 |
+
|
614 |
+
If the disclaimer of warranty and limitation of liability provided
|
615 |
+
above cannot be given local legal effect according to their terms,
|
616 |
+
reviewing courts shall apply local law that most closely approximates
|
617 |
+
an absolute waiver of all civil liability in connection with the
|
618 |
+
Program, unless a warranty or assumption of liability accompanies a
|
619 |
+
copy of the Program in return for a fee.
|
620 |
|
621 |
END OF TERMS AND CONDITIONS
|
622 |
|
628 |
|
629 |
To do so, attach the following notices to the program. It is safest
|
630 |
to attach them to the start of each source file to most effectively
|
631 |
+
state the exclusion of warranty; and each file should have at least
|
632 |
the "copyright" line and a pointer to where the full notice is found.
|
633 |
|
634 |
<one line to give the program's name and a brief idea of what it does.>
|
635 |
Copyright (C) <year> <name of author>
|
636 |
|
637 |
+
This program is free software: you can redistribute it and/or modify
|
638 |
it under the terms of the GNU General Public License as published by
|
639 |
+
the Free Software Foundation, either version 3 of the License, or
|
640 |
(at your option) any later version.
|
641 |
|
642 |
This program is distributed in the hope that it will be useful,
|
644 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
645 |
GNU General Public License for more details.
|
646 |
|
647 |
+
You should have received a copy of the GNU General Public License
|
648 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
649 |
|
650 |
Also add information on how to contact you by electronic and paper mail.
|
651 |
|
652 |
+
If the program does terminal interaction, make it output a short
|
653 |
+
notice like this when it starts in an interactive mode:
|
654 |
|
655 |
+
<program> Copyright (C) <year> <name of author>
|
656 |
+
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
657 |
This is free software, and you are welcome to redistribute it
|
658 |
under certain conditions; type `show c' for details.
|
659 |
|
660 |
The hypothetical commands `show w' and `show c' should show the appropriate
|
661 |
+
parts of the General Public License. Of course, your program's commands
|
662 |
+
might be different; for a GUI interface, you would use an "about box".
|
663 |
+
|
664 |
+
You should also get your employer (if you work as a programmer) or school,
|
665 |
+
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
666 |
+
For more information on this, and how to apply and follow the GNU GPL, see
|
667 |
+
<http://www.gnu.org/licenses/>.
|
668 |
+
|
669 |
+
The GNU General Public License does not permit incorporating your program
|
670 |
+
into proprietary programs. If your program is a subroutine library, you
|
671 |
+
may consider it more useful to permit linking proprietary applications with
|
672 |
+
the library. If this is what you want to do, use the GNU Lesser General
|
673 |
+
Public License instead of this License. But first, please read
|
674 |
+
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
|
|
|
|
|
|
|
|
README.txt
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
=== Document Gallery ===
|
2 |
Contributors: dan.rossiter, demur
|
3 |
-
Tags: attachments, thumbnail, documents, gallery,
|
4 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=EE5LWRLG933EN&lc=US&item_name=Document%20Gallery%20Plugin&item_number=document%2dgallery¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted
|
5 |
Requires at least: 4.1
|
6 |
Tested up to: 4.4
|
7 |
-
Stable tag: 4.
|
8 |
License: GPLv2
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
@@ -18,7 +18,7 @@ other attached media, much like the gallery option already available for image
|
|
18 |
attachments.
|
19 |
|
20 |
Watch the following video for a brief demonstration of Document Gallery in action:
|
21 |
-
[youtube http://www.youtube.com/watch?v=
|
22 |
|
23 |
Read more in the **Installation** tab!
|
24 |
|
@@ -295,74 +295,52 @@ Document Gallery provides the `dg_thumbers` filter, which allows developers to
|
|
295 |
add, remove, or even re-order which methods are used to generate a thumbnail
|
296 |
for a given attachment.
|
297 |
|
298 |
-
The value being filtered is an
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
a system path to a **temporary** copy of the generated image if generation
|
305 |
-
succeeds. The caller will manipulate the file at the returned path so **do not** pass
|
306 |
-
in a file path to the original copy of anything as it will be destroyed. Also, do not
|
307 |
-
worry about any image resizing or giving the file a sensible name as the caller
|
308 |
-
of your method will resize and rename the file before returning.
|
309 |
|
310 |
The following is an example taken from the Document Gallery source (with a few
|
311 |
modifications for ease of readability), where we add thumbnail generation for
|
312 |
all Audio/Video filetypes supported by WordPress:
|
313 |
|
314 |
-
`
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
function
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
$tmp_dir = untrailingslashit(get_temp_dir());
|
351 |
-
$temp_file = $tmp_dir . DIRECTORY_SEPARATOR . wp_unique_filename($tmp_dir, md5(time()) . ".$ext");
|
352 |
-
|
353 |
-
if (!$fp = @fopen($temp_file, 'wb')) {
|
354 |
-
return false;
|
355 |
-
}
|
356 |
-
|
357 |
-
if (!@fwrite($fp, $metadata['image']['data'])) {
|
358 |
-
fclose($fp);
|
359 |
-
return false;
|
360 |
-
}
|
361 |
-
|
362 |
-
fclose($fp);
|
363 |
-
|
364 |
-
return $temp_file;
|
365 |
-
}`
|
366 |
|
367 |
**Filter Inclusion of Default Document Gallery CSS**
|
368 |
|
@@ -443,6 +421,21 @@ To see a list of features planned for the future as well as to propose your own
|
|
443 |
ideas for future Document Gallery development, take a look at our
|
444 |
[issue tracker](https://github.com/thenadz/document-gallery/issues).
|
445 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
446 |
= 4.0 =
|
447 |
* **Enhancement:** The WordPress visual editor now displays a full gallery preview.
|
448 |
* **Enhancement:** You can now paginate your galleries. This is especially useful in large multi-hundred item galleries.
|
1 |
=== Document Gallery ===
|
2 |
Contributors: dan.rossiter, demur
|
3 |
+
Tags: attachments, library, thumbnail, documents, gallery, word, pdf
|
4 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=EE5LWRLG933EN&lc=US&item_name=Document%20Gallery%20Plugin&item_number=document%2dgallery¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted
|
5 |
Requires at least: 4.1
|
6 |
Tested up to: 4.4
|
7 |
+
Stable tag: 4.1
|
8 |
License: GPLv2
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
18 |
attachments.
|
19 |
|
20 |
Watch the following video for a brief demonstration of Document Gallery in action:
|
21 |
+
[youtube http://www.youtube.com/watch?v=Xb7RVzfeUUg]
|
22 |
|
23 |
Read more in the **Installation** tab!
|
24 |
|
295 |
add, remove, or even re-order which methods are used to generate a thumbnail
|
296 |
for a given attachment.
|
297 |
|
298 |
+
The value being filtered is an array of `DG_AbstractThumber` objects. You will want to look at this abstract class,
|
299 |
+
located in the DG source under `inc/thumbers` to see how to correctly implement the abstract methods. You'll notice
|
300 |
+
that `DG_AbstractThumber::init()` will handle creating a singleton instance of your class (though you can opt not
|
301 |
+
to use this logic if you prefer). To register your implementation of `DG_AbstractThumber` using `init()`, you would
|
302 |
+
simply call YourThumberClass::init() and all of the work setting up the `dg_thumbers` filter to include your thumber
|
303 |
+
will be done for you.
|
|
|
|
|
|
|
|
|
|
|
304 |
|
305 |
The following is an example taken from the Document Gallery source (with a few
|
306 |
modifications for ease of readability), where we add thumbnail generation for
|
307 |
all Audio/Video filetypes supported by WordPress:
|
308 |
|
309 |
+
`DG_ImageThumber::init();
|
310 |
+
|
311 |
+
class DG_ImageThumber extends DG_AbstractThumber {
|
312 |
+
|
313 |
+
/**
|
314 |
+
* @return string[] The extensions supported by this thumber.
|
315 |
+
*/
|
316 |
+
protected function getThumberExtensions() {
|
317 |
+
return array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
|
318 |
+
}
|
319 |
+
|
320 |
+
/**
|
321 |
+
* @param string $ID The attachment ID to retrieve thumbnail from.
|
322 |
+
* @param int $pg Unused.
|
323 |
+
*
|
324 |
+
* @return bool|string False on failure, URL to thumb on success.
|
325 |
+
*/
|
326 |
+
public function getThumbnail( $ID, $pg = 1 ) {
|
327 |
+
$options = DG_Thumber::getOptions();
|
328 |
+
$ret = false;
|
329 |
+
|
330 |
+
if ( $icon = image_downsize( $ID, array( $options['width'], $options['height'] ) ) ) {
|
331 |
+
$ret = $icon[0];
|
332 |
+
}
|
333 |
+
|
334 |
+
return $ret;
|
335 |
+
}
|
336 |
+
|
337 |
+
/**
|
338 |
+
* @return int An integer from 0 to 100. Higher priorities will be attempted before lower priority thumbers.
|
339 |
+
*/
|
340 |
+
public function getPriority() {
|
341 |
+
return 100;
|
342 |
+
}
|
343 |
+
}`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
|
345 |
**Filter Inclusion of Default Document Gallery CSS**
|
346 |
|
421 |
ideas for future Document Gallery development, take a look at our
|
422 |
[issue tracker](https://github.com/thenadz/document-gallery/issues).
|
423 |
|
424 |
+
= 4.1 =
|
425 |
+
* **Enhancement:** At long last, support for Microsoft Office files (Word, PowerPoint, Publisher, Visio), as well as a
|
426 |
+
boat-load of [other formats](https://www.thumber.co/about#filetypes), has been re-added to Document Gallery by way of
|
427 |
+
integration with the [Thumber.co](https://thumber.co) service. For a small fee you can generate images for all of your
|
428 |
+
attachments using a service designed specifically to work well with Document Gallery. **For a limited time,
|
429 |
+
Thumber.co is offering a free 7-day trial of the basic subscription. If you don't like it, all you have to do is
|
430 |
+
cancel and you won't pay a penny.**
|
431 |
+
* **Enhancement:** The pagination footer now includes more than just "prev" and "next", allowing for quicker navigation
|
432 |
+
of long multi-page galleries. Additionally, the pagination footer will no longer be included if pagination is enabled,
|
433 |
+
but there are less than a page-length's worth of attachments in the gallery.
|
434 |
+
* **Enhancement:** Massive rewrite of some core logic that had become unmaintainable. This will mean nothing to most
|
435 |
+
users, with the noted exception that if you were using the `dg_thumbers` filter you'll need to change some things.
|
436 |
+
If this applies to you then you'll want to hold off on upgrading until you've had a chance to rework your usage of the
|
437 |
+
filter to map to the new expected values.
|
438 |
+
|
439 |
= 4.0 =
|
440 |
* **Enhancement:** The WordPress visual editor now displays a full gallery preview.
|
441 |
* **Enhancement:** You can now paginate your galleries. This is especially useful in large multi-hundred item galleries.
|
admin/class-admin.php
CHANGED
@@ -15,15 +15,10 @@ class DG_Admin {
|
|
15 |
/**
|
16 |
* NOTE: This should only ever be accessed through getTabs().
|
17 |
*
|
18 |
-
* @var
|
19 |
*/
|
20 |
private static $tabs;
|
21 |
|
22 |
-
/**
|
23 |
-
* @var array The URL parameters. Currently only used in the thumbnail mgmt tab.
|
24 |
-
*/
|
25 |
-
private static $URL_params;
|
26 |
-
|
27 |
/**
|
28 |
* Returns reference to tabs array, initializing if needed.
|
29 |
*
|
@@ -32,10 +27,11 @@ class DG_Admin {
|
|
32 |
public static function &getTabs() {
|
33 |
if ( ! isset( self::$tabs ) ) {
|
34 |
self::$tabs = array(
|
35 |
-
'
|
36 |
-
'
|
37 |
-
'
|
38 |
-
'
|
|
|
39 |
);
|
40 |
}
|
41 |
|
@@ -51,29 +47,27 @@ class DG_Admin {
|
|
51 |
|
52 |
<h2 class="nav-tab-wrapper">
|
53 |
<?php foreach ( self::getTabs() as $tab => $name ) {
|
54 |
-
$class = ( $tab
|
55 |
-
echo '<a
|
56 |
} ?>
|
57 |
</h2>
|
58 |
|
59 |
-
<form method="post" action="options.php" id="
|
60 |
-
<input type="hidden" name="<?php echo DG_OPTION_NAME; ?>[tab]" value="<?php echo self::$current; ?>"/>
|
61 |
<?php
|
62 |
settings_fields( DG_OPTION_NAME );
|
63 |
do_settings_sections( DG_OPTION_NAME );
|
64 |
-
if ( self::$current
|
65 |
submit_button();
|
66 |
}
|
67 |
?>
|
68 |
</form>
|
69 |
-
|
70 |
</div>
|
71 |
<?php }
|
72 |
|
73 |
/**
|
74 |
* Adds settings link to main plugin view.
|
75 |
-
* @param $links
|
76 |
-
* @return
|
77 |
*/
|
78 |
public static function addSettingsLink( $links ) {
|
79 |
$settings = '<a href="options-general.php?page=' . DG_OPTION_NAME . '">' .
|
@@ -85,9 +79,9 @@ class DG_Admin {
|
|
85 |
|
86 |
/**
|
87 |
* Adds donate link to main plugin view.
|
88 |
-
* @param $links
|
89 |
* @param $file string The file.
|
90 |
-
* @return
|
91 |
*/
|
92 |
public static function addDonateLink( $links, $file ) {
|
93 |
if ( $file === DG_BASENAME ) {
|
@@ -118,6 +112,9 @@ class DG_Admin {
|
|
118 |
* @param $hook string The hook.
|
119 |
*/
|
120 |
public static function enqueueScriptsAndStyles( $hook ) {
|
|
|
|
|
|
|
121 |
if ( in_array( $hook, array( DG_Admin::$hook, 'post.php', 'post-new.php' ), true ) ) {
|
122 |
// Settings Page
|
123 |
DG_Util::enqueueAsset( 'document-gallery-admin', 'assets/css/admin.css' );
|
@@ -125,10 +122,14 @@ class DG_Admin {
|
|
125 |
DG_Util::enqueueAsset( 'document-gallery-admin', 'assets/js/admin.js', array( 'jquery' ) );
|
126 |
wp_localize_script( 'document-gallery-admin', 'dg_admin_vars', array( 'upload_limit' => wp_max_upload_size() ) );
|
127 |
if ( $hook !== self::$hook ) { //if $hook is 'post.php' or 'post-new.php'
|
128 |
-
wp_localize_script( 'document-gallery-admin', 'ajax_object', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
|
129 |
-
|
130 |
-
// Media Manager
|
131 |
global $dg_options;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
DG_Util::enqueueAsset( 'dg-media-manager', 'assets/js/media_manager.js', array( 'media-views' ) );
|
133 |
wp_localize_script( 'dg-media-manager', 'DGl10n', array(
|
134 |
'dgMenuTitle' => __( 'Create Document Gallery', 'document-gallery' ),
|
@@ -155,30 +156,30 @@ class DG_Admin {
|
|
155 |
/**
|
156 |
* Adds assets/js/gallery.js as registered TinyMCE plugin
|
157 |
*
|
158 |
-
* @param
|
159 |
*
|
160 |
-
* @return
|
161 |
*/
|
162 |
-
public static function mce_external_plugins( $
|
163 |
-
$
|
164 |
|
165 |
-
return $
|
166 |
}
|
167 |
|
168 |
/**
|
169 |
* Adds assets/css/style.css as registered TinyMCE CSS
|
170 |
*
|
171 |
-
* @param
|
172 |
*
|
173 |
-
* @return
|
174 |
*/
|
175 |
-
public static function dg_plugin_mce_css( $
|
176 |
-
if ( ! empty( $
|
177 |
-
$
|
178 |
}
|
179 |
-
$
|
180 |
|
181 |
-
return $
|
182 |
}
|
183 |
|
184 |
/**
|
@@ -192,352 +193,19 @@ class DG_Admin {
|
|
192 |
* Registers settings for the Document Gallery options page.
|
193 |
*/
|
194 |
public static function registerSettings() {
|
195 |
-
|
196 |
-
reset( self::getTabs() );
|
197 |
-
self::$current = key( self::getTabs() );
|
198 |
-
} else {
|
199 |
-
self::$current = $_REQUEST['tab'];
|
200 |
-
}
|
201 |
|
202 |
register_setting( DG_OPTION_NAME, DG_OPTION_NAME, array( __CLASS__, 'validateSettings' ) );
|
203 |
|
204 |
-
|
205 |
-
|
206 |
-
}
|
207 |
-
|
208 |
-
/**
|
209 |
-
* Registers settings for the general tab.
|
210 |
-
*/
|
211 |
-
private static function registerGeneralSettings() {
|
212 |
-
global $dg_options;
|
213 |
-
|
214 |
-
include_once DG_PATH . 'inc/class-gallery.php';
|
215 |
-
include_once DG_PATH . 'inc/class-gallery-sanitization.php';
|
216 |
-
include_once DG_PATH . 'inc/class-thumber.php';
|
217 |
-
|
218 |
-
$defaults = $dg_options['gallery'];
|
219 |
-
$active = $dg_options['thumber']['active'];
|
220 |
-
|
221 |
-
add_settings_section(
|
222 |
-
'gallery_defaults', __( 'Default Settings', 'document-gallery' ),
|
223 |
-
array( __CLASS__, 'renderDefaultSettingsSection' ), DG_OPTION_NAME );
|
224 |
-
|
225 |
-
add_settings_section(
|
226 |
-
'thumbnail_generation', __( 'Thumbnail Generation', 'document-gallery' ),
|
227 |
-
array( __CLASS__, 'renderThumberSection' ), DG_OPTION_NAME );
|
228 |
-
|
229 |
-
add_settings_section(
|
230 |
-
'css', __( 'Custom CSS', 'document-gallery' ),
|
231 |
-
array( __CLASS__, 'renderCssSection' ), DG_OPTION_NAME );
|
232 |
-
|
233 |
-
add_settings_field(
|
234 |
-
'gallery_defaults_attachment_pg', 'attachment_pg',
|
235 |
-
array( __CLASS__, 'renderCheckboxField' ),
|
236 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
237 |
-
array(
|
238 |
-
'label_for' => 'label_gallery_defaults_attachment_pg',
|
239 |
-
'name' => 'gallery_defaults][attachment_pg',
|
240 |
-
'value' => esc_attr( $defaults['attachment_pg'] ),
|
241 |
-
'option_name' => DG_OPTION_NAME,
|
242 |
-
'description' => __( 'Link to attachment page rather than to file.', 'document-gallery' )
|
243 |
-
) );
|
244 |
-
|
245 |
-
add_settings_field(
|
246 |
-
'gallery_defaults_columns', 'columns',
|
247 |
-
array( __CLASS__, 'renderTextField' ),
|
248 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
249 |
-
array(
|
250 |
-
'label_for' => 'label_gallery_defaults_columns',
|
251 |
-
'name' => 'gallery_defaults][columns',
|
252 |
-
'value' => esc_attr( $defaults['columns'] ),
|
253 |
-
'type' => 'number" min="1" step="1',
|
254 |
-
'option_name' => DG_OPTION_NAME,
|
255 |
-
'description' => __( 'The number of columns to display when not rendering descriptions.', 'document-gallery' )
|
256 |
-
) );
|
257 |
-
|
258 |
-
add_settings_field(
|
259 |
-
'gallery_defaults_descriptions', 'descriptions',
|
260 |
-
array( __CLASS__, 'renderCheckboxField' ),
|
261 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
262 |
-
array(
|
263 |
-
'label_for' => 'label_gallery_defaults_descriptions',
|
264 |
-
'name' => 'gallery_defaults][descriptions',
|
265 |
-
'value' => esc_attr( $defaults['descriptions'] ),
|
266 |
-
'option_name' => DG_OPTION_NAME,
|
267 |
-
'description' => __( 'Include document descriptions.', 'document-gallery' )
|
268 |
-
) );
|
269 |
-
|
270 |
-
add_settings_field(
|
271 |
-
'gallery_defaults_fancy', 'fancy',
|
272 |
-
array( __CLASS__, 'renderCheckboxField' ),
|
273 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
274 |
-
array(
|
275 |
-
'label_for' => 'label_gallery_defaults_fancy',
|
276 |
-
'name' => 'gallery_defaults][fancy',
|
277 |
-
'value' => esc_attr( $defaults['fancy'] ),
|
278 |
-
'option_name' => DG_OPTION_NAME,
|
279 |
-
'description' => __( 'Use auto-generated document thumbnails.', 'document-gallery' )
|
280 |
-
) );
|
281 |
-
|
282 |
-
add_settings_field(
|
283 |
-
'gallery_defaults_order', 'order',
|
284 |
-
array( __CLASS__, 'renderSelectField' ),
|
285 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
286 |
-
array(
|
287 |
-
'label_for' => 'label_gallery_defaults_order',
|
288 |
-
'name' => 'gallery_defaults][order',
|
289 |
-
'value' => esc_attr( $defaults['order'] ),
|
290 |
-
'options' => DG_GallerySanitization::getOrderOptions(),
|
291 |
-
'option_name' => DG_OPTION_NAME,
|
292 |
-
'description' => __( 'Ascending or descending sorting of documents.', 'document-gallery' )
|
293 |
-
) );
|
294 |
-
|
295 |
-
add_settings_field(
|
296 |
-
'gallery_defaults_orderby', 'orderby',
|
297 |
-
array( __CLASS__, 'renderSelectField' ),
|
298 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
299 |
-
array(
|
300 |
-
'label_for' => 'label_gallery_defaults_orderby',
|
301 |
-
'name' => 'gallery_defaults][orderby',
|
302 |
-
'value' => esc_attr( $defaults['orderby'] ),
|
303 |
-
'options' => DG_GallerySanitization::getOrderbyOptions(),
|
304 |
-
'option_name' => DG_OPTION_NAME,
|
305 |
-
'description' => __( 'Which field to order documents by.', 'document-gallery' )
|
306 |
-
) );
|
307 |
-
|
308 |
-
add_settings_field(
|
309 |
-
'gallery_defaults_relation', 'relation',
|
310 |
-
array( __CLASS__, 'renderSelectField' ),
|
311 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
312 |
-
array(
|
313 |
-
'label_for' => 'label_gallery_defaults_relation',
|
314 |
-
'name' => 'gallery_defaults][relation',
|
315 |
-
'value' => esc_attr( $defaults['relation'] ),
|
316 |
-
'options' => DG_GallerySanitization::getRelationOptions(),
|
317 |
-
'option_name' => DG_OPTION_NAME,
|
318 |
-
'description' => __( 'Whether matched documents must have all taxa_names (AND) or at least one (OR).', 'document-gallery' )
|
319 |
-
) );
|
320 |
-
|
321 |
-
add_settings_field(
|
322 |
-
'gallery_defaults_limit', 'limit',
|
323 |
-
array( __CLASS__, 'renderTextField' ),
|
324 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
325 |
-
array(
|
326 |
-
'label_for' => 'label_gallery_defaults_limit',
|
327 |
-
'name' => 'gallery_defaults][limit',
|
328 |
-
'value' => esc_attr( $defaults['limit'] ),
|
329 |
-
'type' => 'number" min="-1" step="1',
|
330 |
-
'option_name' => DG_OPTION_NAME,
|
331 |
-
'description' => __( 'Limit the number of documents included. -1 means no limit.', 'document-gallery' )
|
332 |
-
) );
|
333 |
-
|
334 |
-
add_settings_field(
|
335 |
-
'gallery_defaults_mime_types', 'mime_types',
|
336 |
-
array( __CLASS__, 'renderTextField' ),
|
337 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
338 |
-
array(
|
339 |
-
'label_for' => 'label_gallery_defaults_mime_types',
|
340 |
-
'name' => 'gallery_defaults][mime_types',
|
341 |
-
'value' => esc_attr( $defaults['mime_types'] ),
|
342 |
-
'type' => 'text',
|
343 |
-
'option_name' => DG_OPTION_NAME,
|
344 |
-
'description' => __( 'Comma-delimited list of <a href="http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types">MIME types</a>.', 'document-gallery' )
|
345 |
-
) );
|
346 |
-
|
347 |
-
add_settings_field(
|
348 |
-
'gallery_defaults_new_window', 'new_window',
|
349 |
-
array( __CLASS__, 'renderCheckboxField' ),
|
350 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
351 |
-
array(
|
352 |
-
'label_for' => 'label_gallery_defaults_new_window',
|
353 |
-
'name' => 'gallery_defaults][new_window',
|
354 |
-
'value' => esc_attr( $defaults['new_window'] ),
|
355 |
-
'option_name' => DG_OPTION_NAME,
|
356 |
-
'description' => __( 'Open thumbnail links in new window.', 'document-gallery' )
|
357 |
-
) );
|
358 |
-
|
359 |
-
add_settings_field(
|
360 |
-
'gallery_defaults_paginate', 'paginate',
|
361 |
-
array( __CLASS__, 'renderCheckboxField' ),
|
362 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
363 |
-
array(
|
364 |
-
'label_for' => 'label_gallery_defaults_paginate',
|
365 |
-
'name' => 'gallery_defaults][paginate',
|
366 |
-
'value' => esc_attr( $defaults['paginate'] ),
|
367 |
-
'option_name' => DG_OPTION_NAME,
|
368 |
-
'description' => __( 'When a limit exists, paginate rather than truncating gallery.', 'document-gallery' )
|
369 |
-
) );
|
370 |
-
|
371 |
-
add_settings_field(
|
372 |
-
'gallery_defaults_post_status', 'post_status',
|
373 |
-
array( __CLASS__, 'renderSelectField' ),
|
374 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
375 |
-
array(
|
376 |
-
'label_for' => 'label_gallery_defaults_post_status',
|
377 |
-
'name' => 'gallery_defaults][post_status',
|
378 |
-
'value' => esc_attr( $defaults['post_status'] ),
|
379 |
-
'options' => DG_GallerySanitization::getPostStatuses(),
|
380 |
-
'option_name' => DG_OPTION_NAME,
|
381 |
-
'description' => __( 'Which post status to look for when querying documents.', 'document-gallery' )
|
382 |
-
) );
|
383 |
-
|
384 |
-
add_settings_field(
|
385 |
-
'gallery_defaults_post_type', 'post_type',
|
386 |
-
array( __CLASS__, 'renderSelectField' ),
|
387 |
-
DG_OPTION_NAME, 'gallery_defaults',
|
388 |
-
array(
|
389 |
-
'label_for' => 'label_gallery_defaults_post_type',
|
390 |
-
'name' => 'gallery_defaults][post_type',
|
391 |
-
'value' => esc_attr( $defaults['post_type'] ),
|
392 |
-
'options' => DG_GallerySanitization::getPostTypes(),
|
393 |
-
'option_name' => DG_OPTION_NAME,
|
394 |
-
'description' => __( 'Which post type to look for when querying documents.', 'document-gallery' )
|
395 |
-
) );
|
396 |
-
|
397 |
-
add_settings_field(
|
398 |
-
'thumbnail_generation_av', __( 'Audio/Video', 'document-gallery' ),
|
399 |
-
array( __CLASS__, 'renderCheckboxField' ),
|
400 |
-
DG_OPTION_NAME, 'thumbnail_generation',
|
401 |
-
array(
|
402 |
-
'label_for' => 'label_thumbnail_generation_av',
|
403 |
-
'name' => 'thumbnail_generation][av',
|
404 |
-
'value' => esc_attr( $active['av'] ),
|
405 |
-
'option_name' => DG_OPTION_NAME,
|
406 |
-
'description' => esc_html__( 'Locally generate thumbnails for audio & video files.', 'document-gallery' )
|
407 |
-
) );
|
408 |
-
|
409 |
-
add_settings_field(
|
410 |
-
'thumbnail_generation_gs', 'Ghostscript',
|
411 |
-
array( __CLASS__, 'renderCheckboxField' ),
|
412 |
-
DG_OPTION_NAME, 'thumbnail_generation',
|
413 |
-
array(
|
414 |
-
'label_for' => 'label_thumbnail_generation_gs',
|
415 |
-
'name' => 'thumbnail_generation][gs',
|
416 |
-
'value' => esc_attr( $active['gs'] ),
|
417 |
-
'option_name' => DG_OPTION_NAME,
|
418 |
-
'description' => DG_Thumber::isGhostscriptAvailable()
|
419 |
-
? __( 'Use <a href="http://www.ghostscript.com/" target="_blank">Ghostscript</a> for faster local PDF processing (compared to Imagick).', 'document-gallery' )
|
420 |
-
: __( 'Your server is not configured to run <a href="http://www.ghostscript.com/" target="_blank">Ghostscript</a>.', 'document-gallery' ),
|
421 |
-
'disabled' => ! DG_Thumber::isGhostscriptAvailable()
|
422 |
-
) );
|
423 |
-
|
424 |
-
add_settings_field(
|
425 |
-
'thumbnail_generation_imagick', 'Imagick',
|
426 |
-
array( __CLASS__, 'renderCheckboxField' ),
|
427 |
-
DG_OPTION_NAME, 'thumbnail_generation',
|
428 |
-
array(
|
429 |
-
'label_for' => 'label_thumbnail_generation_imagick',
|
430 |
-
'name' => 'thumbnail_generation][imagick',
|
431 |
-
'value' => esc_attr( $active['imagick'] ),
|
432 |
-
'option_name' => DG_OPTION_NAME,
|
433 |
-
'description' => DG_Thumber::isImagickAvailable()
|
434 |
-
? __( 'Use <a href="http://www.php.net/manual/en/book.imagick.php" target="_blank">Imagick</a> to handle lots of filetypes locally.', 'document-gallery' )
|
435 |
-
: __( 'Your server is not configured to run <a href="http://www.php.net/manual/en/book.imagick.php" target="_blank">Imagick</a>.', 'document-gallery' ),
|
436 |
-
'disabled' => ! DG_Thumber::isImagickAvailable()
|
437 |
-
) );
|
438 |
-
|
439 |
-
add_settings_field(
|
440 |
-
'thumbnail_generation_width', __( 'Max Thumbnail Dimensions', 'document-gallery' ),
|
441 |
-
array( __CLASS__, 'renderMultiTextField' ),
|
442 |
-
DG_OPTION_NAME, 'thumbnail_generation',
|
443 |
-
array(
|
444 |
-
array(
|
445 |
-
'label_for' => 'label_advanced_width',
|
446 |
-
'name' => 'thumbnail_generation][width',
|
447 |
-
'value' => esc_attr( $dg_options['thumber']['width'] ),
|
448 |
-
'type' => 'number" min="1" step="1',
|
449 |
-
'option_name' => DG_OPTION_NAME,
|
450 |
-
'description' => ' x '
|
451 |
-
),
|
452 |
-
array(
|
453 |
-
'label_for' => 'label_advanced_height',
|
454 |
-
'name' => 'thumbnail_generation][height',
|
455 |
-
'value' => esc_attr( $dg_options['thumber']['height'] ),
|
456 |
-
'type' => 'number" min="1" step="1',
|
457 |
-
'option_name' => DG_OPTION_NAME,
|
458 |
-
'description' => __( 'The max width and height (in pixels) that thumbnails will be generated.', 'document-gallery' )
|
459 |
-
)
|
460 |
-
) );
|
461 |
-
}
|
462 |
-
|
463 |
-
/**
|
464 |
-
* Registers settings for the thumbnail management tab.
|
465 |
-
*/
|
466 |
-
private static function registerThumbnailSettings() {
|
467 |
-
add_settings_section(
|
468 |
-
'thumbnail_table', '',
|
469 |
-
array( __CLASS__, 'renderThumbnailSection' ), DG_OPTION_NAME );
|
470 |
-
}
|
471 |
-
|
472 |
-
/**
|
473 |
-
* Registers settings for the logging tab.
|
474 |
-
*/
|
475 |
-
private static function registerLoggingSettings() {
|
476 |
-
add_settings_section(
|
477 |
-
'logging_table', '',
|
478 |
-
array( __CLASS__, 'renderLoggingSection' ), DG_OPTION_NAME );
|
479 |
-
}
|
480 |
-
|
481 |
-
/**
|
482 |
-
* Registers settings for the advanced tab.
|
483 |
-
*/
|
484 |
-
private static function registerAdvancedSettings() {
|
485 |
-
global $dg_options;
|
486 |
-
|
487 |
-
add_settings_section(
|
488 |
-
'advanced', __( 'Advanced Thumbnail Generation', 'document-gallery' ),
|
489 |
-
array( __CLASS__, 'renderAdvancedSection' ), DG_OPTION_NAME );
|
490 |
-
|
491 |
-
add_settings_field(
|
492 |
-
'advanced_logging_enabled', __( 'Logging Enabled', 'document-gallery' ),
|
493 |
-
array( __CLASS__, 'renderCheckboxField' ),
|
494 |
-
DG_OPTION_NAME, 'advanced',
|
495 |
-
array(
|
496 |
-
'label_for' => 'label_advanced_logging_enabled',
|
497 |
-
'name' => 'logging_enabled',
|
498 |
-
'value' => esc_attr( $dg_options['logging']['enabled'] ),
|
499 |
-
'option_name' => DG_OPTION_NAME,
|
500 |
-
'description' => __( 'Whether to log debug and error information related to Document Gallery.', 'document-gallery' )
|
501 |
-
) );
|
502 |
-
|
503 |
-
add_settings_field(
|
504 |
-
'advanced_logging_purge_interval', __( 'Logging Purge Interval', 'document-gallery' ),
|
505 |
-
array( __CLASS__, 'renderTextField' ),
|
506 |
-
DG_OPTION_NAME, 'advanced',
|
507 |
-
array(
|
508 |
-
'label_for' => 'label_advanced_logging_purge_interval',
|
509 |
-
'name' => 'logging_purge_interval',
|
510 |
-
'value' => esc_attr( $dg_options['logging']['purge_interval'] ),
|
511 |
-
'type' => 'number" min="0" step="1',
|
512 |
-
'option_name' => DG_OPTION_NAME,
|
513 |
-
'description' => __( 'Number of days to keep old log entries (0 disables purging).', 'document-gallery' )
|
514 |
-
) );
|
515 |
-
|
516 |
-
add_settings_field(
|
517 |
-
'advanced_gs', __( 'Ghostscript Absolute Path', 'document-gallery' ),
|
518 |
-
array( __CLASS__, 'renderTextField' ),
|
519 |
-
DG_OPTION_NAME, 'advanced',
|
520 |
-
array(
|
521 |
-
'label_for' => 'label_advanced_gs',
|
522 |
-
'name' => 'gs',
|
523 |
-
'value' => esc_attr( $dg_options['thumber']['gs'] ),
|
524 |
-
'option_name' => DG_OPTION_NAME,
|
525 |
-
'description' => $dg_options['thumber']['gs']
|
526 |
-
? __( 'Successfully auto-detected the location of Ghostscript.', 'document-gallery' )
|
527 |
-
: __( 'Failed to auto-detect the location of Ghostscript.', 'document-gallery' )
|
528 |
-
) );
|
529 |
-
|
530 |
-
add_settings_section(
|
531 |
-
'advanced_options_dump', __( 'Options Array Dump', 'document-gallery' ),
|
532 |
-
array( __CLASS__, 'renderOptionsDumpSection' ), DG_OPTION_NAME );
|
533 |
}
|
534 |
|
535 |
/**
|
536 |
* Validates submitted options, sanitizing any invalid options.
|
537 |
*
|
538 |
-
* @param
|
539 |
-
*
|
540 |
-
* @return array Sanitized new options.
|
541 |
*/
|
542 |
public static function validateSettings( $values ) {
|
543 |
// NOTE: WP double-calls this function -- below logic prevents potential
|
@@ -546,162 +214,16 @@ class DG_Admin {
|
|
546 |
// subsequent calls.
|
547 |
static $ret = null;
|
548 |
if ( is_null( $ret ) ) {
|
549 |
-
|
550 |
-
global $dg_options;
|
551 |
-
return $dg_options;
|
552 |
-
} else {
|
553 |
-
if ( isset( $values['ajax'] ) ) {
|
554 |
-
unset( $values['ajax'] );
|
555 |
-
define( 'DOING_AJAX', true );
|
556 |
-
}
|
557 |
|
558 |
-
|
559 |
-
unset( $values['
|
560 |
-
|
561 |
}
|
562 |
-
}
|
563 |
-
|
564 |
-
return $ret;
|
565 |
-
}
|
566 |
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
* @param array $values User-submitted new options.
|
571 |
-
*
|
572 |
-
* @return array Sanitized new options.
|
573 |
-
*/
|
574 |
-
private static function validateGeneralSettings( $values ) {
|
575 |
-
global $dg_options;
|
576 |
-
$ret = $dg_options;
|
577 |
-
|
578 |
-
include_once DG_PATH . 'inc/class-gallery.php';
|
579 |
-
|
580 |
-
$thumbs_cleared = false;
|
581 |
-
|
582 |
-
// handle gallery shortcode defaults
|
583 |
-
$errs = array();
|
584 |
-
$ret['gallery'] = DG_Gallery::sanitizeDefaults( null, $values['gallery_defaults'], $errs );
|
585 |
-
|
586 |
-
foreach ( $errs as $k => $v ) {
|
587 |
-
add_settings_error( DG_OPTION_NAME, str_replace( '_', '-', $k ), $v );
|
588 |
-
}
|
589 |
-
|
590 |
-
// handle setting width
|
591 |
-
if ( isset( $values['thumbnail_generation']['width'] ) ) {
|
592 |
-
$width = (int) $values['thumbnail_generation']['width'];
|
593 |
-
if ( $width > 0 ) {
|
594 |
-
$ret['thumber']['width'] = $width;
|
595 |
-
} else {
|
596 |
-
add_settings_error( DG_OPTION_NAME, 'thumber-width',
|
597 |
-
__( 'Invalid width given: ', 'document-gallery' ) . $values['thumbnail_generation']['width'] );
|
598 |
-
}
|
599 |
-
|
600 |
-
unset( $values['thumbnail_generation']['width'] );
|
601 |
-
}
|
602 |
-
|
603 |
-
// handle setting height
|
604 |
-
if ( isset( $values['thumbnail_generation']['height'] ) ) {
|
605 |
-
$height = (int) $values['thumbnail_generation']['height'];
|
606 |
-
if ( $height > 0 ) {
|
607 |
-
$ret['thumber']['height'] = $height;
|
608 |
-
} else {
|
609 |
-
add_settings_error( DG_OPTION_NAME, 'thumber-height',
|
610 |
-
__( 'Invalid height given: ', 'document-gallery' ) . $values['thumbnail_generation']['height'] );
|
611 |
-
}
|
612 |
-
|
613 |
-
unset( $values['thumbnail_generation']['width'] );
|
614 |
-
}
|
615 |
-
|
616 |
-
// delete thumb cache to force regeneration if max dimensions changed
|
617 |
-
if ( $ret['thumber']['width'] !== $dg_options['thumber']['width'] ||
|
618 |
-
$ret['thumber']['height'] !== $dg_options['thumber']['height'] ) {
|
619 |
-
DG_Thumb::purgeThumbs();
|
620 |
-
}
|
621 |
-
|
622 |
-
// handle setting the active thumbers
|
623 |
-
foreach ( array_keys( $ret['thumber']['active'] ) as $k ) {
|
624 |
-
$ret['thumber']['active'][ $k ] = isset( $values['thumbnail_generation'][ $k ] );
|
625 |
-
}
|
626 |
-
|
627 |
-
// if new thumbers available, clear failed thumbnails for retry
|
628 |
-
if ( ! $thumbs_cleared ) {
|
629 |
-
DG_Thumb::purgeFailedThumbs();
|
630 |
-
}
|
631 |
-
|
632 |
-
// handle modified CSS
|
633 |
-
if ( trim( $ret['css']['text'] ) !== trim( $values['css'] ) ) {
|
634 |
-
$ret['css']['text'] = trim( $values['css'] );
|
635 |
-
}
|
636 |
-
|
637 |
-
return $ret;
|
638 |
-
}
|
639 |
-
|
640 |
-
/**
|
641 |
-
* Validates thumbnail management settings, sanitizing any invalid options.
|
642 |
-
*
|
643 |
-
* @param array $values User-submitted new options.
|
644 |
-
*
|
645 |
-
* @return array Sanitized new options.
|
646 |
-
*/
|
647 |
-
private static function validateThumbnailSettings( $values ) {
|
648 |
-
global $dg_options;
|
649 |
-
$ret = $dg_options;
|
650 |
-
$responseArr = array( 'result' => false );
|
651 |
-
|
652 |
-
if ( isset( $values['entry'] ) ) {
|
653 |
-
$ID = intval( $values['entry'] );
|
654 |
-
} else {
|
655 |
-
$ID = - 1;
|
656 |
-
}
|
657 |
-
|
658 |
-
// Thumbnail(s) cleanup;
|
659 |
-
// cleanup value is a marker
|
660 |
-
if ( isset( $values['cleanup'] ) && isset( $values['ids'] ) ) {
|
661 |
-
$deleted = array_values( array_intersect( array_keys( DG_Thumb::getThumbs() ), $values['ids'] ) );
|
662 |
-
DG_Thumb::purgeThumbs( $deleted );
|
663 |
-
$responseArr['result'] = true;
|
664 |
-
$responseArr['deleted'] = $deleted;
|
665 |
-
}
|
666 |
-
|
667 |
-
// Attachment title update
|
668 |
-
// title value is a marker
|
669 |
-
elseif ( isset( $values['title'] ) && $ID != - 1 ) {
|
670 |
-
$attachment = array(
|
671 |
-
'ID' => $ID,
|
672 |
-
'post_title' => rawurldecode( addslashes( $values['title'] ) )
|
673 |
-
);
|
674 |
-
if ( wp_update_post( $attachment ) ) {
|
675 |
-
$responseArr['result'] = true;
|
676 |
-
}
|
677 |
-
}
|
678 |
-
|
679 |
-
// Attachment description update
|
680 |
-
// description value is a marker
|
681 |
-
elseif ( isset( $values['description'] ) && $ID != - 1 ) {
|
682 |
-
$attachment = array(
|
683 |
-
'ID' => $ID,
|
684 |
-
'post_content' => rawurldecode( addslashes( $values['description'] ) )
|
685 |
-
);
|
686 |
-
if ( wp_update_post( $attachment ) ) {
|
687 |
-
$responseArr['result'] = true;
|
688 |
-
}
|
689 |
-
}
|
690 |
-
|
691 |
-
// Thumbnail file manual refresh (one at a time)
|
692 |
-
// upload value is a marker
|
693 |
-
elseif ( isset( $values['upload'] ) && isset( $_FILES['file'] ) && array_key_exists( $ID, DG_Thumb::getThumbs() ) ) {
|
694 |
-
$uploaded_filename = self::validateUploadedFile();
|
695 |
-
if ( $uploaded_filename && ( $thumb = DG_Thumber::setThumbnail( $ID, $uploaded_filename ) ) ) {
|
696 |
-
$responseArr['result'] = true;
|
697 |
-
$responseArr['url'] = $thumb->getUrl();
|
698 |
-
}
|
699 |
-
}
|
700 |
-
|
701 |
-
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
|
702 |
-
@header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
|
703 |
-
echo wp_json_encode( $responseArr );
|
704 |
-
add_filter( 'wp_redirect', array( __CLASS__, '_exit' ), 1, 0 );
|
705 |
}
|
706 |
|
707 |
return $ret;
|
@@ -771,58 +293,6 @@ class DG_Admin {
|
|
771 |
return $temp_file;
|
772 |
}
|
773 |
|
774 |
-
/**
|
775 |
-
* Validates logging settings, sanitizing any invalid options.
|
776 |
-
*
|
777 |
-
* @param array $values User-submitted new options.
|
778 |
-
*
|
779 |
-
* @return array Sanitized new options.
|
780 |
-
*/
|
781 |
-
private static function validateLoggingSettings( $values ) {
|
782 |
-
global $dg_options;
|
783 |
-
if ( isset( $values['clearLog'] ) ) {
|
784 |
-
DG_Logger::clearLog();
|
785 |
-
}
|
786 |
-
|
787 |
-
return $dg_options;
|
788 |
-
}
|
789 |
-
|
790 |
-
/**
|
791 |
-
* Validates advanced settings, sanitizing any invalid options.
|
792 |
-
*
|
793 |
-
* @param array $values User-submitted new options.
|
794 |
-
*
|
795 |
-
* @return array Sanitized new options.
|
796 |
-
*/
|
797 |
-
private static function validateAdvancedSettings( $values ) {
|
798 |
-
global $dg_options;
|
799 |
-
$ret = $dg_options;
|
800 |
-
|
801 |
-
// handle setting the Ghostscript path
|
802 |
-
if ( isset( $values['gs'] ) && 0 != strcmp( $values['gs'], $ret['thumber']['gs'] ) ) {
|
803 |
-
if ( false === strpos( $values['gs'], ';' ) ) {
|
804 |
-
$ret['thumber']['gs'] = $values['gs'];
|
805 |
-
} else {
|
806 |
-
add_settings_error( DG_OPTION_NAME, 'thumber-gs',
|
807 |
-
__( 'Invalid Ghostscript path given: ', 'document-gallery' ) . $values['gs'] );
|
808 |
-
}
|
809 |
-
}
|
810 |
-
|
811 |
-
// logging settings
|
812 |
-
$ret['logging']['enabled'] = isset( $values['logging_enabled'] );
|
813 |
-
if ( isset( $values['logging_purge_interval'] ) ) {
|
814 |
-
$purge_interval = (int) $values['logging_purge_interval'];
|
815 |
-
if ( $purge_interval >= 0 ) {
|
816 |
-
$ret['logging']['purge_interval'] = $purge_interval;
|
817 |
-
} else {
|
818 |
-
add_settings_error( DG_OPTION_NAME, 'thumber-logging-purge-interval',
|
819 |
-
__( 'Invalid logging purge interval given: ', 'document-gallery' ) . $values['logging_purge_interval'] );
|
820 |
-
}
|
821 |
-
}
|
822 |
-
|
823 |
-
return $ret;
|
824 |
-
}
|
825 |
-
|
826 |
/**
|
827 |
* @return bool Whether to register settings.
|
828 |
*/
|
@@ -837,282 +307,6 @@ class DG_Admin {
|
|
837 |
return ! empty( $script ) && ( 'options-general.php' === $script || 'options.php' === $script );
|
838 |
}
|
839 |
|
840 |
-
/**
|
841 |
-
* Render the Default Settings section.
|
842 |
-
*/
|
843 |
-
public static function renderDefaultSettingsSection() { ?>
|
844 |
-
<p><?php _e( 'The following values will be used by default in the shortcode. You can still manually set each of these values in each individual shortcode.', 'document-gallery' ); ?></p>
|
845 |
-
<?php }
|
846 |
-
|
847 |
-
/**
|
848 |
-
* Render the Thumber section.
|
849 |
-
*/
|
850 |
-
public static function renderThumberSection() { ?>
|
851 |
-
<p><?php _e( 'Select which tools to use when generating thumbnails.', 'document-gallery' ); ?></p>
|
852 |
-
<?php }
|
853 |
-
|
854 |
-
/**
|
855 |
-
* Renders a text field for use when modifying the CSS to be printed in addition to the default CSS.
|
856 |
-
*/
|
857 |
-
public static function renderCssSection() {
|
858 |
-
global $dg_options; ?>
|
859 |
-
<p><?php printf(
|
860 |
-
__( 'Enter custom CSS styling for use with document galleries. To see which ids and classes you can style, take a look at <a href="%s" target="_blank">style.css</a>.', 'document-gallery' ),
|
861 |
-
DG_URL . 'assets/css/style.css' ); ?></p>
|
862 |
-
<table class="form-table">
|
863 |
-
<tbody>
|
864 |
-
<tr valign="top">
|
865 |
-
<td>
|
866 |
-
<textarea name="<?php echo DG_OPTION_NAME; ?>[css]" rows="10" cols="50"
|
867 |
-
class="large-text code"><?php echo $dg_options['css']['text']; ?></textarea>
|
868 |
-
</td>
|
869 |
-
</tr>
|
870 |
-
</tbody>
|
871 |
-
</table>
|
872 |
-
<?php }
|
873 |
-
|
874 |
-
/**
|
875 |
-
* Render the Thumber Advanced section.
|
876 |
-
*/
|
877 |
-
public static function renderAdvancedSection() {
|
878 |
-
include_once DG_PATH . 'inc/class-thumber.php'; ?>
|
879 |
-
<p><?php _e( 'Unless you <em>really</em> know what you\'re doing, you should not touch these values.', 'document-gallery' ); ?></p>
|
880 |
-
<?php if ( ! DG_Thumber::isExecAvailable() ) : ?>
|
881 |
-
<p>
|
882 |
-
<em><?php _e( 'NOTE: <code>exec()</code> is not accessible. Ghostscript will not function.', 'document-gallery' ); ?></em>
|
883 |
-
</p>
|
884 |
-
<?php endif; ?>
|
885 |
-
<?php }
|
886 |
-
|
887 |
-
/**
|
888 |
-
* Renders a readonly textfield containing a dump of current DG options.
|
889 |
-
*/
|
890 |
-
public static function renderOptionsDumpSection() {
|
891 |
-
global $dg_options; ?>
|
892 |
-
<p><?php
|
893 |
-
_e( 'The following <em>readonly text</em> should be provided when <a href="http://wordpress.org/support/plugin/document-gallery" target="_blank">reporting a bug</a>:', 'documet-gallery' );
|
894 |
-
?></p>
|
895 |
-
<table class="form-table">
|
896 |
-
<tbody>
|
897 |
-
<tr valign="top">
|
898 |
-
<td>
|
899 |
-
<textarea readonly="true" rows="10" cols="50" id="options-dump"
|
900 |
-
class="large-text code"><?php print_r( $dg_options ); ?></textarea>
|
901 |
-
</td>
|
902 |
-
</tr>
|
903 |
-
</tbody>
|
904 |
-
</table>
|
905 |
-
<?php }
|
906 |
-
|
907 |
-
/**
|
908 |
-
* Render the Thumbnail table.
|
909 |
-
*/
|
910 |
-
public static function renderThumbnailSection() {
|
911 |
-
include_once DG_PATH . 'inc/class-thumber.php';
|
912 |
-
static $limit_options = array( 10, 25, 75 );
|
913 |
-
static $order_options = array( 'asc', 'desc' );
|
914 |
-
static $orderby_options = array( 'date', 'title' );
|
915 |
-
$options = DG_Thumber::getOptions();
|
916 |
-
|
917 |
-
// find subset of thumbs to be included
|
918 |
-
self::$URL_params = array( 'page' => DG_OPTION_NAME, 'tab' => 'Thumbnail' );
|
919 |
-
$orderby = self::$URL_params['orderby'] = self::getOrderbyParam($orderby_options);
|
920 |
-
$order = self::$URL_params['order'] = self::getOrderParam($order_options);
|
921 |
-
$limit = self::$URL_params['limit'] = self::getLimitParam();
|
922 |
-
|
923 |
-
$thumbs = DG_Thumb::getThumbs( $options['width'] . 'x' . $options['height'] );
|
924 |
-
uasort( $thumbs, array( __CLASS__, 'cmpThumb' ) );
|
925 |
-
$thumbs_number = count( $thumbs );
|
926 |
-
$lastsheet = ceil( $thumbs_number / $limit );
|
927 |
-
$sheet = isset( $_REQUEST['sheet'] ) ? absint( $_REQUEST['sheet'] ) : 1;
|
928 |
-
if ( $sheet === 0 || $sheet > $lastsheet ) {
|
929 |
-
$sheet = 1;
|
930 |
-
}
|
931 |
-
|
932 |
-
$offset = ( $sheet - 1 ) * $limit;
|
933 |
-
$thumbs = array_slice( $thumbs, $offset, $limit, true );
|
934 |
-
|
935 |
-
// https://core.trac.wordpress.org/ticket/12212
|
936 |
-
$posts = array();
|
937 |
-
if ( ! empty( $thumbs ) ) {
|
938 |
-
$posts = get_posts(
|
939 |
-
array(
|
940 |
-
'post_type' => 'any',
|
941 |
-
'post_status' => 'any',
|
942 |
-
'numberposts' => - 1,
|
943 |
-
'post__in' => array_keys( $thumbs ),
|
944 |
-
'orderby' => 'post__in'
|
945 |
-
) );
|
946 |
-
}
|
947 |
-
|
948 |
-
foreach ( $posts as $post ) {
|
949 |
-
$path_parts = pathinfo( $post->guid );
|
950 |
-
|
951 |
-
$thumb = $thumbs[$post->ID];
|
952 |
-
$thumbs[$post->ID] = array();
|
953 |
-
$t = &$thumbs[$post->ID];
|
954 |
-
$t['timestamp'] = $thumb->getTimestamp();
|
955 |
-
$t['title'] = self::getTitle( $post );
|
956 |
-
$t['ext'] = isset( $path_parts['extension'] ) ? $path_parts['extension'] : '';
|
957 |
-
$t['description'] = $post->post_content;
|
958 |
-
$t['icon'] = $thumb->isSuccess() ? $thumb->getUrl() : DG_Thumber::getDefaultThumbnail( $post->ID );
|
959 |
-
}
|
960 |
-
unset( $posts );
|
961 |
-
|
962 |
-
$select_limit = '';
|
963 |
-
foreach ( $limit_options as $l_o ) {
|
964 |
-
$select_limit .= '<option value="' . $l_o . '"' . selected( $limit, $l_o, false ) . '>' . $l_o . '</option>' . PHP_EOL;
|
965 |
-
}
|
966 |
-
|
967 |
-
$thead = '<tr>' .
|
968 |
-
'<th scope="col" class="manage-column column-cb check-column">' .
|
969 |
-
'<label class="screen-reader-text" for="cb-select-all-%1$d">' . __( 'Select All', 'document-gallery' ) . '</label>' .
|
970 |
-
'<input id="cb-select-all-%1$d" type="checkbox">' .
|
971 |
-
'</th>' .
|
972 |
-
'<th scope="col" class="manage-column column-icon">' . __( 'Thumbnail', 'document-gallery' ) . '</th>' .
|
973 |
-
'<th scope="col" class="manage-column column-title ' . ( ( $orderby != 'title' ) ? 'sortable desc' : 'sorted ' . $order ) . '"><a href="?' . http_build_query( array_merge( self::$URL_params, array(
|
974 |
-
'orderby' => 'title',
|
975 |
-
'order' => ( ( $orderby != 'title' ) ? 'asc' : ( ( $order == 'asc' ) ? 'desc' : 'asc' ) )
|
976 |
-
) ) ) . '"><span>' . __( 'File name', 'document-gallery' ) . '</span><span class="sorting-indicator"></span></th>' .
|
977 |
-
'<th scope="col" class="manage-column column-description">' . __( 'Description', 'document-gallery' ) . '</th>' .
|
978 |
-
'<th scope="col" class="manage-column column-thumbupload"></th>' .
|
979 |
-
'<th scope="col" class="manage-column column-date ' . ( ( $orderby != 'date' ) ? 'sortable asc' : 'sorted ' . $order ) . '"><a href="?' . http_build_query( array_merge( self::$URL_params, array(
|
980 |
-
'orderby' => 'date',
|
981 |
-
'order' => ( ( $orderby != 'date' ) ? 'desc' : ( ( $order == 'asc' ) ? 'desc' : 'asc' ) )
|
982 |
-
) ) ) . '"><span>' . __( 'Date', 'document-gallery' ) . '</span><span class="sorting-indicator"></span></th>' .
|
983 |
-
'</tr>';
|
984 |
-
|
985 |
-
$pagination = '<div class="alignleft bulkactions"><button class="button action deleteSelected">' . __( 'Delete Selected', 'document-gallery' ) . '</button></div><div class="tablenav-pages">' .
|
986 |
-
'<span class="displaying-num">' .
|
987 |
-
$thumbs_number . ' ' . _n( 'item', 'items', $thumbs_number, 'document-gallery' ) .
|
988 |
-
'</span>' . ( $lastsheet > 1 ?
|
989 |
-
'<span class="pagination-links">' .
|
990 |
-
'<a class="first-page' . ( $sheet == 1 ? ' disabled' : '' ) . '" title="' . __( 'Go to the first page', 'document-gallery' ) . '"' . ( $sheet == 1 ? '' : ' href="?' . http_build_query( self::$URL_params ) . '"' ) . '>«</a>' .
|
991 |
-
'<a class="prev-page' . ( $sheet == 1 ? ' disabled' : '' ) . '" title="' . __( 'Go to the previous page', 'document-gallery' ) . '"' . ( $sheet == 1 ? '' : ' href="?' . http_build_query( array_merge( self::$URL_params, array( 'sheet' => $sheet - 1 ) ) ) . '"' ) . '>‹</a>' .
|
992 |
-
'<span class="paging-input">' .
|
993 |
-
'<input class="current-page" title="' . __( 'Current page', 'document-gallery' ) . '" type="text" name="paged" value="' . $sheet . '" size="' . strlen( $sheet ) . '" maxlength="' . strlen( $sheet ) . '"> ' . __( 'of', 'document-gallery' ) . ' <span class="total-pages">' . $lastsheet . '</span></span>' .
|
994 |
-
'<a class="next-page' . ( $sheet == $lastsheet ? ' disabled' : '' ) . '" title="' . __( 'Go to the next page', 'document-gallery' ) . '"' . ( $sheet == $lastsheet ? '' : ' href="?' . http_build_query( array_merge( self::$URL_params, array( 'sheet' => $sheet + 1 ) ) ) . '"' ) . '>›</a>' .
|
995 |
-
'<a class="last-page' . ( $sheet == $lastsheet ? ' disabled' : '' ) . '" title="' . __( 'Go to the last page', 'document-gallery' ) . '"' . ( $sheet == $lastsheet ? '' : ' href="?' . http_build_query( array_merge( self::$URL_params, array( 'sheet' => $lastsheet ) ) ) . '"' ) . '>»</a>' .
|
996 |
-
'</span>' : ' <b>|</b> ' ) .
|
997 |
-
'<span class="displaying-num"><select dir="rtl" class="limit_per_page">' . $select_limit . '</select> ' . __( 'items per page', 'document-gallery' ) . '</span>' .
|
998 |
-
'</div>' .
|
999 |
-
'<br class="clear" />';
|
1000 |
-
?>
|
1001 |
-
|
1002 |
-
<script type="text/javascript">
|
1003 |
-
var URL_params = <?php echo wp_json_encode( self::$URL_params ); ?>;
|
1004 |
-
</script>
|
1005 |
-
<div class="thumbs-list-wrapper">
|
1006 |
-
<div>
|
1007 |
-
<div class="tablenav top"><?php echo $pagination; ?></div>
|
1008 |
-
<table id="ThumbsTable" class="wp-list-table widefat fixed media"
|
1009 |
-
cellpadding="0" cellspacing="0">
|
1010 |
-
<thead>
|
1011 |
-
<?php printf( $thead, 1 ); ?>
|
1012 |
-
</thead>
|
1013 |
-
<tfoot>
|
1014 |
-
<?php printf( $thead, 2 ); ?>
|
1015 |
-
</tfoot>
|
1016 |
-
<tbody><?php
|
1017 |
-
foreach ( $thumbs as $tid => $thumb ) {
|
1018 |
-
$icon = $thumb['icon'];
|
1019 |
-
$title = $thumb['title'];
|
1020 |
-
$ext = $thumb['ext'];
|
1021 |
-
$description = $thumb['description'];
|
1022 |
-
$date = DocumentGallery::localDateTimeFromTimestamp( $thumb['timestamp'] );
|
1023 |
-
?>
|
1024 |
-
<tr data-entry="<?php echo $tid; ?>">
|
1025 |
-
<td scope="row" class="check-column">
|
1026 |
-
<input
|
1027 |
-
type="checkbox"
|
1028 |
-
class="cb-ids"
|
1029 |
-
name="<?php echo DG_OPTION_NAME; ?>[ids][]"
|
1030 |
-
value="<?php echo $tid; ?>">
|
1031 |
-
</td>
|
1032 |
-
<td class="column-icon media-icon"><img src="<?php echo $icon; ?>" /></td>
|
1033 |
-
<td class="title column-title">
|
1034 |
-
<strong>
|
1035 |
-
<a
|
1036 |
-
href="<?php echo home_url( '/?attachment_id=' . $tid ); ?>"
|
1037 |
-
target="_blank"
|
1038 |
-
title="<?php sprintf( __( "View '%s' attachment page", 'document-gallery' ), $title ); ?>">
|
1039 |
-
<span class="editable-title"><?php echo $title; ?></span>
|
1040 |
-
<sup><?php echo $ext; ?></sup>
|
1041 |
-
</a>
|
1042 |
-
</strong>
|
1043 |
-
<span class="dashicons dashicons-edit"></span>
|
1044 |
-
<span class="edit-controls">
|
1045 |
-
<span class="dashicons dashicons-yes"></span>
|
1046 |
-
<span class="dashicons dashicons-no"></span>
|
1047 |
-
</span>
|
1048 |
-
</td>
|
1049 |
-
<td class="column-description">
|
1050 |
-
<div class="editable-description"><?php echo $description; ?></div>
|
1051 |
-
<span class="dashicons dashicons-edit"></span>
|
1052 |
-
<span class="edit-controls">
|
1053 |
-
<span class="dashicons dashicons-yes"></span>
|
1054 |
-
<span class="dashicons dashicons-no"></span>
|
1055 |
-
<span class="dashicons dashicons-update"></span>
|
1056 |
-
</span>
|
1057 |
-
</td>
|
1058 |
-
<td class="column-thumbupload">
|
1059 |
-
<span class="manual-download">
|
1060 |
-
<span class="dashicons dashicons-upload"></span>
|
1061 |
-
<span class="html5dndmarker">Drop file here<span> or </span></span>
|
1062 |
-
<span class="buttons-area">
|
1063 |
-
<input id="upload-button<?php echo $tid; ?>" type="file" />
|
1064 |
-
<input id="trigger-button<?php echo $tid; ?>" type="button" value="Select File" class="button" />
|
1065 |
-
</span>
|
1066 |
-
</span>
|
1067 |
-
<div class="progress animate invis">
|
1068 |
-
<span><span></span></span>
|
1069 |
-
</div>
|
1070 |
-
</td>
|
1071 |
-
<td class="date column-date"><?php echo $date; ?></td>
|
1072 |
-
</tr>
|
1073 |
-
<?php
|
1074 |
-
} ?>
|
1075 |
-
</tbody>
|
1076 |
-
</table>
|
1077 |
-
<div class="tablenav bottom"><?php echo $pagination; ?></div>
|
1078 |
-
</div>
|
1079 |
-
</div>
|
1080 |
-
<?php }
|
1081 |
-
|
1082 |
-
/**
|
1083 |
-
* @return int The limit, which may or may not be a member of $limit_options.
|
1084 |
-
*/
|
1085 |
-
private static function getLimitParam() {
|
1086 |
-
global $dg_options;
|
1087 |
-
$limit = isset( $_REQUEST['limit'] ) ? DG_Util::posint( $_REQUEST['limit'] ) : $dg_options['meta']['items_per_page'];
|
1088 |
-
if ( $limit !== $dg_options['meta']['items_per_page'] ) {
|
1089 |
-
$dg_options['meta']['items_per_page'] = $limit;
|
1090 |
-
DocumentGallery::setOptions( $dg_options );
|
1091 |
-
}
|
1092 |
-
|
1093 |
-
return $limit;
|
1094 |
-
}
|
1095 |
-
|
1096 |
-
/**
|
1097 |
-
* @param $order_options array The possible options for order.
|
1098 |
-
*
|
1099 |
-
* @return string The order value.
|
1100 |
-
*/
|
1101 |
-
private static function getOrderParam($order_options) {
|
1102 |
-
$ret = isset( $_REQUEST['order'] ) ? strtolower( $_REQUEST['order'] ) : '';
|
1103 |
-
return in_array($ret, $order_options) ? $ret : $order_options[0];
|
1104 |
-
}
|
1105 |
-
|
1106 |
-
/**
|
1107 |
-
* @param $orderby_options array The possible options for orderby.
|
1108 |
-
*
|
1109 |
-
* @return string The orderby value.
|
1110 |
-
*/
|
1111 |
-
private static function getOrderbyParam($orderby_options) {
|
1112 |
-
$ret = isset( $_REQUEST['orderby'] ) ? strtolower( $_REQUEST['orderby'] ) : '';
|
1113 |
-
return in_array( $ret, $orderby_options ) ? $ret : $orderby_options[0];
|
1114 |
-
}
|
1115 |
-
|
1116 |
/**
|
1117 |
* Adds meta box to the attchements' edit pages.
|
1118 |
*/
|
@@ -1141,7 +335,7 @@ class DG_Admin {
|
|
1141 |
$thumb = DG_Thumb::getThumb( $ID, $options['width'] . 'x' . $options['height'] );
|
1142 |
$icon = ! is_null( $thumb ) && $thumb->isSuccess()
|
1143 |
? $thumb->getUrl()
|
1144 |
-
:
|
1145 |
|
1146 |
echo '<table id="ThumbsTable" class="wp-list-table widefat fixed media" cellpadding="0" cellspacing="0">' .
|
1147 |
'<tbody><tr data-entry="' . $ID . '"><td class="column-icon media-icon"><img src="' .
|
@@ -1190,115 +384,10 @@ class DG_Admin {
|
|
1190 |
}
|
1191 |
}
|
1192 |
|
1193 |
-
/**
|
1194 |
-
* Render the Logging table.
|
1195 |
-
*/
|
1196 |
-
public static function renderLoggingSection() {
|
1197 |
-
$log_list = DG_Logger::readLog();
|
1198 |
-
if ( $log_list ) {
|
1199 |
-
$levels = array_map( array( __CLASS__, 'getLogLabelSpan' ), array_keys( DG_LogLevel::getLogLevels() ) );
|
1200 |
-
|
1201 |
-
$fmt =
|
1202 |
-
'<tr>' .
|
1203 |
-
'<th scope="col" class="manage-column column-date sorted desc"><a href="javascript:void(0);">' .
|
1204 |
-
'<span>%s</span><span class="sorting-indicator"></span></a>' .
|
1205 |
-
'</th>' .
|
1206 |
-
'<th scope="col" class="manage-column column-level"><span>%s</span></th>' .
|
1207 |
-
'<th scope="col" class="manage-column column-message"><span>%s</span></th>' .
|
1208 |
-
'</tr>';
|
1209 |
-
|
1210 |
-
$thead = sprintf( $fmt,
|
1211 |
-
__( 'Date', 'document-gallery' ),
|
1212 |
-
__( 'Level', 'document-gallery' ),
|
1213 |
-
__( 'Message', 'document-gallery' ) );
|
1214 |
-
|
1215 |
-
?>
|
1216 |
-
<div class="log-list-wrapper">
|
1217 |
-
<div>
|
1218 |
-
<div class="tablenav top">
|
1219 |
-
<div class="alignleft bulkactions">
|
1220 |
-
<button class="action expandAll">
|
1221 |
-
<?php echo __( 'Expand All', 'document-gallery' ); ?>
|
1222 |
-
</button>
|
1223 |
-
<button class="action collapseAll">
|
1224 |
-
<?php echo __( 'Collapse All', 'document-gallery' ); ?>
|
1225 |
-
</button>
|
1226 |
-
</div>
|
1227 |
-
<div class="levelSelector">
|
1228 |
-
<input type="checkbox" id="allLevels" name="lswitch" value="all" checked/>
|
1229 |
-
<label for="allLevels" class="allLevels">ALL</label>
|
1230 |
-
<?php
|
1231 |
-
foreach ( array_keys( DG_LogLevel::getLogLevels() ) as $k ) { ?>
|
1232 |
-
<?php
|
1233 |
-
$lower = strtolower( $k );
|
1234 |
-
$upper = strtoupper( $k );
|
1235 |
-
?>
|
1236 |
-
<input type="checkbox" id="<?php echo $lower; ?>Level" name="lswitch"
|
1237 |
-
value="<?php echo $lower; ?>" checked/>
|
1238 |
-
<label for="<?php echo $lower; ?>Level"
|
1239 |
-
class="<?php echo $lower; ?>Level"><?php echo $upper; ?></label>
|
1240 |
-
<?php }
|
1241 |
-
?>
|
1242 |
-
</div>
|
1243 |
-
</div>
|
1244 |
-
<table id="LogTable" class="wp-list-table widefat fixed media" cellpadding="0" cellspacing="0">
|
1245 |
-
<thead>
|
1246 |
-
<?php echo $thead; ?>
|
1247 |
-
</thead>
|
1248 |
-
<tfoot>
|
1249 |
-
<?php echo $thead; ?>
|
1250 |
-
</tfoot>
|
1251 |
-
<tbody><?php
|
1252 |
-
for ( $i = count( $log_list ); $i > 0; $i-- ) {
|
1253 |
-
$log_entry = $log_list[ $i - 1 ];
|
1254 |
-
$date = DocumentGallery::localDateTimeFromTimestamp( $log_entry[0] );
|
1255 |
-
|
1256 |
-
// convert attachment names to links
|
1257 |
-
$log_entry[2] = preg_replace( '/[ ^](attachment #)(\d+)[.,: ]/i', ' <a href="' . home_url() . '/?attachment_id=\2" target="_blank">\1<strong>\2</strong></a> ', $log_entry[2] );
|
1258 |
-
|
1259 |
-
// bold the place where log entry was submitted
|
1260 |
-
$log_entry[2] = preg_replace( '/^(\((?:\w+(?:::|->))?\w+\)) /', '<strong>\1</strong> ', $log_entry[2] );
|
1261 |
-
|
1262 |
-
// italicize any function references within log entry
|
1263 |
-
$log_entry[2] = preg_replace( '/(\(?\w+(?:::|->)\w+\)?)/m', '<i>\1</i>', $log_entry[2] );
|
1264 |
-
|
1265 |
-
echo '<tr><td class="date column-date" data-sort-value="' . $log_entry[0] . '"><span class="logLabel date">' . $date . '</span></td>' .
|
1266 |
-
'<td class="column-level">' . $levels[ $log_entry[1] ] . '</td>' .
|
1267 |
-
'<td class="column-entry">' . ( empty( $log_entry[3] ) ? '<pre>' . $log_entry[2] . '</pre>' : '<div class="expander" title="Click to Expand"><pre>' . $log_entry[2] . '</pre><div><span class="dashicons dashicons-arrow-down-alt2"></span></div></div><div class="spoiler-body"><pre>' . $log_entry[3] . '</pre></div>' ) . '</td>' .
|
1268 |
-
'</tr>' . PHP_EOL;
|
1269 |
-
} ?>
|
1270 |
-
</tbody>
|
1271 |
-
</table>
|
1272 |
-
<div class="tablenav bottom">
|
1273 |
-
<div class="alignright bulkactions">
|
1274 |
-
<button class="button action clearLog" name='<?php echo DG_OPTION_NAME; ?>[clearLog]'
|
1275 |
-
value='true'>
|
1276 |
-
<?php echo __( 'Clear Log', 'document-gallery' ); ?>
|
1277 |
-
</button>
|
1278 |
-
</div>
|
1279 |
-
</div>
|
1280 |
-
</div>
|
1281 |
-
</div>
|
1282 |
-
<?php } else {
|
1283 |
-
echo '<div class="noLog">' . __( 'There are no log entries at this time.', 'document-gallery' ) . '<br />' . __( 'For Your information:', 'document-gallery' ) . ' <strong><i>' . __( 'Logging', 'document-gallery' ) . '</i></strong> ' . ( DG_Logger::logEnabled() ? '<span class="loggingON">' . __( 'is turned ON', 'document-gallery' ) . '!</span>' : '<span class="loggingOFF">' . __( 'is turned OFF', 'document-gallery' ) . '!</span>' ) . '</div>';
|
1284 |
-
}
|
1285 |
-
}
|
1286 |
-
|
1287 |
-
/**
|
1288 |
-
* Takes label name and returns SPAN tag.
|
1289 |
-
*
|
1290 |
-
* @param string $e label name.
|
1291 |
-
*
|
1292 |
-
* @return string SPAN tag
|
1293 |
-
*/
|
1294 |
-
private static function getLogLabelSpan( $e ) {
|
1295 |
-
return '<span class="logLabel ' . strtolower( $e ) . '">' . strtoupper( $e ) . '</span>';
|
1296 |
-
}
|
1297 |
-
|
1298 |
/**
|
1299 |
* Render a checkbox field.
|
1300 |
*
|
1301 |
-
* @param
|
1302 |
*/
|
1303 |
public static function renderCheckboxField( $args ) {
|
1304 |
$args['disabled'] = isset( $args['disabled'] ) ? $args['disabled'] : false;
|
@@ -1314,7 +403,7 @@ class DG_Admin {
|
|
1314 |
/**
|
1315 |
* Render a text field.
|
1316 |
*
|
1317 |
-
* @param
|
1318 |
*/
|
1319 |
public static function renderTextField( $args ) {
|
1320 |
printf( '<input type="%1$s" value="%2$s" name="%3$s[%4$s]" id="%5$s" /> %6$s',
|
@@ -1329,7 +418,7 @@ class DG_Admin {
|
|
1329 |
/**
|
1330 |
* Accepts a two-dimensional array where each inner array consists of valid arguments for renderTextField.
|
1331 |
*
|
1332 |
-
* @param
|
1333 |
*/
|
1334 |
public static function renderMultiTextField( $args ) {
|
1335 |
foreach ( $args as $arg ) {
|
@@ -1340,7 +429,7 @@ class DG_Admin {
|
|
1340 |
/**
|
1341 |
* Render a select field.
|
1342 |
*
|
1343 |
-
* @param
|
1344 |
*/
|
1345 |
public static function renderSelectField( $args ) {
|
1346 |
printf( '<select name="%1$s[%2$s]" id="%3$s">',
|
@@ -1360,43 +449,15 @@ class DG_Admin {
|
|
1360 |
}
|
1361 |
|
1362 |
/**
|
1363 |
-
*
|
1364 |
-
* @param $t2 DG_Thumb Thumbnail #2
|
1365 |
-
*
|
1366 |
-
* @return int The result of comparing the two thumbs using arguments in $URL_params.
|
1367 |
-
*/
|
1368 |
-
public static function cmpThumb($t1, $t2) {
|
1369 |
-
$ret = 0;
|
1370 |
-
switch (self::$URL_params['orderby']) {
|
1371 |
-
case 'date':
|
1372 |
-
$ret = $t1->getTimestamp() - $t2->getTimestamp();
|
1373 |
-
break;
|
1374 |
-
|
1375 |
-
case 'title':
|
1376 |
-
$ret = strcmp( self::getTitle( $t1->getPostId() ), self::getTitle( $t2->getPostId() ) );
|
1377 |
-
break;
|
1378 |
-
}
|
1379 |
-
|
1380 |
-
return 'asc' === self::$URL_params['order'] ? $ret : -$ret;
|
1381 |
-
}
|
1382 |
-
|
1383 |
-
/**
|
1384 |
-
* @param $post int|WP_Post The post to get title of.
|
1385 |
-
* @return string The title.
|
1386 |
*/
|
1387 |
-
private static function
|
1388 |
-
if (
|
1389 |
-
|
|
|
|
|
|
|
1390 |
}
|
1391 |
-
|
1392 |
-
return ! empty( $post->post_title ) ? $post->post_title : pathinfo( $post->guid, PATHINFO_FILENAME );
|
1393 |
-
}
|
1394 |
-
|
1395 |
-
/**
|
1396 |
-
* Wraps the PHP exit language construct.
|
1397 |
-
*/
|
1398 |
-
public static function _exit() {
|
1399 |
-
exit;
|
1400 |
}
|
1401 |
|
1402 |
/**
|
15 |
/**
|
16 |
* NOTE: This should only ever be accessed through getTabs().
|
17 |
*
|
18 |
+
* @var string[] Associative array containing all tab names, keyed by tab slug.
|
19 |
*/
|
20 |
private static $tabs;
|
21 |
|
|
|
|
|
|
|
|
|
|
|
22 |
/**
|
23 |
* Returns reference to tabs array, initializing if needed.
|
24 |
*
|
27 |
public static function &getTabs() {
|
28 |
if ( ! isset( self::$tabs ) ) {
|
29 |
self::$tabs = array(
|
30 |
+
'general-tab' => __( 'General', 'document-gallery' ),
|
31 |
+
'thumber-co-tab' => __( 'Thumber.co', 'document-gallery' ),
|
32 |
+
'thumbnail-management-tab' => __( 'Thumbnail Management', 'document-gallery' ),
|
33 |
+
'logging-tab' => __( 'Logging', 'document-gallery' ),
|
34 |
+
'advanced-tab' => __( 'Advanced', 'document-gallery' )
|
35 |
);
|
36 |
}
|
37 |
|
47 |
|
48 |
<h2 class="nav-tab-wrapper">
|
49 |
<?php foreach ( self::getTabs() as $tab => $name ) {
|
50 |
+
$class = ( $tab === self::$current ) ? ' nav-tab-active' : '';
|
51 |
+
echo '<a id="' . $tab . '-header" class="nav-tab' . $class . '" href="?page=' . DG_OPTION_NAME . '&tab=' . $tab . '">' . $name . '</a>';
|
52 |
} ?>
|
53 |
</h2>
|
54 |
|
55 |
+
<form method="post" action="options.php?tab=<?php echo self::$current; ?>" id="<?php echo self::$current ?>">
|
|
|
56 |
<?php
|
57 |
settings_fields( DG_OPTION_NAME );
|
58 |
do_settings_sections( DG_OPTION_NAME );
|
59 |
+
if ( self::$current !== 'thumbnail-management-tab' && self::$current != 'logging-tab' ) {
|
60 |
submit_button();
|
61 |
}
|
62 |
?>
|
63 |
</form>
|
|
|
64 |
</div>
|
65 |
<?php }
|
66 |
|
67 |
/**
|
68 |
* Adds settings link to main plugin view.
|
69 |
+
* @param $links string[] The links being prepended.
|
70 |
+
* @return string[] The given array with settings link prepended.
|
71 |
*/
|
72 |
public static function addSettingsLink( $links ) {
|
73 |
$settings = '<a href="options-general.php?page=' . DG_OPTION_NAME . '">' .
|
79 |
|
80 |
/**
|
81 |
* Adds donate link to main plugin view.
|
82 |
+
* @param $links string[] The links.
|
83 |
* @param $file string The file.
|
84 |
+
* @return string[] The given array with donate link appended.
|
85 |
*/
|
86 |
public static function addDonateLink( $links, $file ) {
|
87 |
if ( $file === DG_BASENAME ) {
|
112 |
* @param $hook string The hook.
|
113 |
*/
|
114 |
public static function enqueueScriptsAndStyles( $hook ) {
|
115 |
+
include_once DG_PATH . 'admin/class-feature-pointers.php';
|
116 |
+
DG_FeaturePointers::enqueueScripts();
|
117 |
+
|
118 |
if ( in_array( $hook, array( DG_Admin::$hook, 'post.php', 'post-new.php' ), true ) ) {
|
119 |
// Settings Page
|
120 |
DG_Util::enqueueAsset( 'document-gallery-admin', 'assets/css/admin.css' );
|
122 |
DG_Util::enqueueAsset( 'document-gallery-admin', 'assets/js/admin.js', array( 'jquery' ) );
|
123 |
wp_localize_script( 'document-gallery-admin', 'dg_admin_vars', array( 'upload_limit' => wp_max_upload_size() ) );
|
124 |
if ( $hook !== self::$hook ) { //if $hook is 'post.php' or 'post-new.php'
|
|
|
|
|
|
|
125 |
global $dg_options;
|
126 |
+
|
127 |
+
// Media Manager integration
|
128 |
+
add_action( 'admin_print_footer_scripts', array(
|
129 |
+
'DG_Admin',
|
130 |
+
'loadCustomTemplates'
|
131 |
+
) ); //wp_print_scripts || wp_footer
|
132 |
+
|
133 |
DG_Util::enqueueAsset( 'dg-media-manager', 'assets/js/media_manager.js', array( 'media-views' ) );
|
134 |
wp_localize_script( 'dg-media-manager', 'DGl10n', array(
|
135 |
'dgMenuTitle' => __( 'Create Document Gallery', 'document-gallery' ),
|
156 |
/**
|
157 |
* Adds assets/js/gallery.js as registered TinyMCE plugin
|
158 |
*
|
159 |
+
* @param string[] $plugins An array of default TinyMCE plugins.
|
160 |
*
|
161 |
+
* @return string[] Default TinyMCE plugins plus custom DG plugin.
|
162 |
*/
|
163 |
+
public static function mce_external_plugins( $plugins ) {
|
164 |
+
$plugins['dg'] = DG_Util::getAssetPath( 'assets/js/gallery.js' );
|
165 |
|
166 |
+
return $plugins;
|
167 |
}
|
168 |
|
169 |
/**
|
170 |
* Adds assets/css/style.css as registered TinyMCE CSS
|
171 |
*
|
172 |
+
* @param string $stylesheets Comma-delimited list of stylesheets.
|
173 |
*
|
174 |
+
* @return string Comma-delimited list of stylesheets.
|
175 |
*/
|
176 |
+
public static function dg_plugin_mce_css( $stylesheets ) {
|
177 |
+
if ( ! empty( $stylesheets ) ) {
|
178 |
+
$stylesheets .= ',';
|
179 |
}
|
180 |
+
$stylesheets .= str_replace( ',', '%2C', DG_Util::getAssetPath( 'assets/css/style.css' ) );
|
181 |
|
182 |
+
return $stylesheets;
|
183 |
}
|
184 |
|
185 |
/**
|
193 |
* Registers settings for the Document Gallery options page.
|
194 |
*/
|
195 |
public static function registerSettings() {
|
196 |
+
self::initCurrentTab();
|
|
|
|
|
|
|
|
|
|
|
197 |
|
198 |
register_setting( DG_OPTION_NAME, DG_OPTION_NAME, array( __CLASS__, 'validateSettings' ) );
|
199 |
|
200 |
+
include_once DG_PATH . 'admin/tabs/' . self::$current . '.php';
|
201 |
+
dg_register_settings();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
202 |
}
|
203 |
|
204 |
/**
|
205 |
* Validates submitted options, sanitizing any invalid options.
|
206 |
*
|
207 |
+
* @param mixed[] $values User-submitted new options.
|
208 |
+
* @return mixed[] Sanitized new options.
|
|
|
209 |
*/
|
210 |
public static function validateSettings( $values ) {
|
211 |
// NOTE: WP double-calls this function -- below logic prevents potential
|
214 |
// subsequent calls.
|
215 |
static $ret = null;
|
216 |
if ( is_null( $ret ) ) {
|
217 |
+
self::initCurrentTab();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
218 |
|
219 |
+
if ( isset( $values['ajax'] ) ) {
|
220 |
+
unset( $values['ajax'] );
|
221 |
+
define( 'DOING_AJAX', true );
|
222 |
}
|
|
|
|
|
|
|
|
|
223 |
|
224 |
+
DG_Logger::writeLog( DG_LogLevel::Detail, 'Validating ' . self::$current . ' tab.' );
|
225 |
+
include_once DG_PATH . 'admin/tabs/' . self::$current . '.php';
|
226 |
+
$ret = dg_validate_settings( $values );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
227 |
}
|
228 |
|
229 |
return $ret;
|
293 |
return $temp_file;
|
294 |
}
|
295 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
296 |
/**
|
297 |
* @return bool Whether to register settings.
|
298 |
*/
|
307 |
return ! empty( $script ) && ( 'options-general.php' === $script || 'options.php' === $script );
|
308 |
}
|
309 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
310 |
/**
|
311 |
* Adds meta box to the attchements' edit pages.
|
312 |
*/
|
335 |
$thumb = DG_Thumb::getThumb( $ID, $options['width'] . 'x' . $options['height'] );
|
336 |
$icon = ! is_null( $thumb ) && $thumb->isSuccess()
|
337 |
? $thumb->getUrl()
|
338 |
+
: DG_DefaultThumber::getInstance()->getThumbnail( $ID );
|
339 |
|
340 |
echo '<table id="ThumbsTable" class="wp-list-table widefat fixed media" cellpadding="0" cellspacing="0">' .
|
341 |
'<tbody><tr data-entry="' . $ID . '"><td class="column-icon media-icon"><img src="' .
|
384 |
}
|
385 |
}
|
386 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
387 |
/**
|
388 |
* Render a checkbox field.
|
389 |
*
|
390 |
+
* @param mixed[] $args
|
391 |
*/
|
392 |
public static function renderCheckboxField( $args ) {
|
393 |
$args['disabled'] = isset( $args['disabled'] ) ? $args['disabled'] : false;
|
403 |
/**
|
404 |
* Render a text field.
|
405 |
*
|
406 |
+
* @param mixed[] $args
|
407 |
*/
|
408 |
public static function renderTextField( $args ) {
|
409 |
printf( '<input type="%1$s" value="%2$s" name="%3$s[%4$s]" id="%5$s" /> %6$s',
|
418 |
/**
|
419 |
* Accepts a two-dimensional array where each inner array consists of valid arguments for renderTextField.
|
420 |
*
|
421 |
+
* @param mixed[] $args
|
422 |
*/
|
423 |
public static function renderMultiTextField( $args ) {
|
424 |
foreach ( $args as $arg ) {
|
429 |
/**
|
430 |
* Render a select field.
|
431 |
*
|
432 |
+
* @param mixed[] $args
|
433 |
*/
|
434 |
public static function renderSelectField( $args ) {
|
435 |
printf( '<select name="%1$s[%2$s]" id="%3$s">',
|
449 |
}
|
450 |
|
451 |
/**
|
452 |
+
* Initializes the current tab value.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
453 |
*/
|
454 |
+
private static function initCurrentTab() {
|
455 |
+
if ( empty( $_GET['tab'] ) || ! array_key_exists( $_GET['tab'], self::getTabs() ) ) {
|
456 |
+
reset( self::getTabs() );
|
457 |
+
self::$current = key( self::getTabs() );
|
458 |
+
} else {
|
459 |
+
self::$current = $_GET['tab'];
|
460 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
461 |
}
|
462 |
|
463 |
/**
|
admin/class-ajax-handler.php
CHANGED
@@ -26,7 +26,7 @@ class DG_AjaxHandler {
|
|
26 |
if ( isset( $_REQUEST['ids'] ) ) {
|
27 |
foreach ( $_REQUEST['ids'] as $id ) {
|
28 |
// only return URL if different from default -- default image is already displayed on the client side
|
29 |
-
$url = DG_Thumber::getThumbnail( $id, 1, true, $is_default );
|
30 |
if ( ! $is_default ) {
|
31 |
$ret[$id] = $url;
|
32 |
}
|
26 |
if ( isset( $_REQUEST['ids'] ) ) {
|
27 |
foreach ( $_REQUEST['ids'] as $id ) {
|
28 |
// only return URL if different from default -- default image is already displayed on the client side
|
29 |
+
$url = DG_Thumber::getInstance()->getThumbnail( $id, 1, true, $is_default );
|
30 |
if ( ! $is_default ) {
|
31 |
$ret[$id] = $url;
|
32 |
}
|
admin/class-feature-pointers.php
ADDED
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
class DG_FeaturePointers {
|
5 |
+
/**
|
6 |
+
* @var string Each method used to output a feature pointer must end in this suffix.
|
7 |
+
*/
|
8 |
+
private static $feature_pointer_method_suffix = 'FeaturePointer';
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var string[] The cached pointer methods to avoid reflecting multiple times in a given session.
|
12 |
+
*/
|
13 |
+
private static $feature_pointer_methods;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Enqueues the wp-pointer CSS/JS along with any specific feature pointers.
|
17 |
+
*/
|
18 |
+
public static function enqueueScripts() {
|
19 |
+
$seen = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
|
20 |
+
|
21 |
+
$do_add_script = false;
|
22 |
+
foreach ( self::getFeaturePointerMethods() as $method ) {
|
23 |
+
$fp_id = self::getFeaturePointerIdFromMethodName( $method );
|
24 |
+
if ( ! in_array( $fp_id, $seen ) ) {
|
25 |
+
$do_add_script = true;
|
26 |
+
add_action( 'admin_print_footer_scripts', array( __CLASS__, $method ) );
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
// enqueue WP core CSS/JS if we've got pointers
|
31 |
+
if ( $do_add_script ) {
|
32 |
+
wp_enqueue_script( 'wp-pointer' );
|
33 |
+
wp_enqueue_style( 'wp-pointer' );
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Feature pointer for DG settings.
|
39 |
+
*/
|
40 |
+
public static function dg41_1FeaturePointer() {
|
41 |
+
$title = '<h3>' . __( 'Configure Document Gallery', 'document-gallery' ) . '</h3>';
|
42 |
+
$body = '<p>' . __( 'Did you know Document Gallery has lots of configurable settings allowing you to fine tune ' .
|
43 |
+
'what your users experience when viewing a gallery? <em>Click the <strong>Settings</strong> ' .
|
44 |
+
'link above to see for yourself!</em>', 'document-gallery' ) . '</p>';
|
45 |
+
self::printFeaturePointer( '#the-list #document-gallery .row-actions', array( 'content' => $title . $body, 'position' => 'top' ) );
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Feature pointer for Thumber.co tab in DG settings.
|
50 |
+
*/
|
51 |
+
public static function dg41_2FeaturePointer() {
|
52 |
+
$title = '<h3>' . __( 'More Thumbnails!', 'document-gallery' ) . '</h3>';
|
53 |
+
$body = '<p>' . __( 'If you need to generate thumbnails for Word documents, PowerPoints, and more then you ' .
|
54 |
+
'need to check out Thumber.co. Free 1-week trial for a limited time! <em>Click the ' .
|
55 |
+
'<strong>Thumber.co</strong> tab above to get started.</em>', 'document-gallery' ) . '</p>';
|
56 |
+
self::printFeaturePointer( '#thumber-co-tab-header', array( 'content' => $title . $body, 'position' => 'top' ) );
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Print the pointer JavaScript data.
|
61 |
+
* NOTE: Taken from WP_Internal_Pointers.
|
62 |
+
*
|
63 |
+
* @param string $selector The HTML elements, on which the pointer should be attached.
|
64 |
+
* @param mixed[] $args Arguments to be passed to the pointer JS (see wp-pointer.js).
|
65 |
+
*/
|
66 |
+
private static function printFeaturePointer( $selector, $args ) {
|
67 |
+
if ( empty( $selector ) || empty( $args ) || empty( $args['content'] ) )
|
68 |
+
return;
|
69 |
+
|
70 |
+
$trace = debug_backtrace();
|
71 |
+
$pointer_id = self::getFeaturePointerIdFromMethodName( $trace[1]['function'] );
|
72 |
+
?>
|
73 |
+
<script>(function(b){var a=<?php echo wp_json_encode( $args ); ?>,c;a&&(a=b.extend(a,{close:function(){b.post(ajaxurl,{pointer:"<?php echo $pointer_id; ?>",action:"dismiss-wp-pointer"})}}),c=function(){b("<?php echo $selector; ?>").first().pointer(a).pointer("open")},a.position&&a.position.defer_loading?b(window).bind("load.wp-pointers",c):b(document).ready(c))})(jQuery);</script>
|
74 |
+
<?php
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* @param string $method The method name.
|
79 |
+
* @return string The feature pointer ID.
|
80 |
+
*/
|
81 |
+
private static function getFeaturePointerIdFromMethodName( $method ) {
|
82 |
+
return substr( $method, 0, strlen( $method ) - strlen( self::$feature_pointer_method_suffix ) );
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Reflectively retrieves all of the feature pointer methods, which must end with the feature pointer method suffix.
|
87 |
+
* @return string[] The names of all public class methods matching the feature pointer pattern.
|
88 |
+
*/
|
89 |
+
private static function getFeaturePointerMethods() {
|
90 |
+
if ( ! isset( self::$feature_pointer_methods ) ) {
|
91 |
+
$reflect = new ReflectionClass( __CLASS__ );
|
92 |
+
$methods = $reflect->getMethods( ReflectionMethod::IS_STATIC | ReflectionMethod::IS_PUBLIC );
|
93 |
+
self::$feature_pointer_methods =
|
94 |
+
array_map(
|
95 |
+
array( __CLASS__, 'getNameFromMethod' ),
|
96 |
+
array_filter( $methods, array( __CLASS__, 'isFilterPointerMethod' ) ) );
|
97 |
+
}
|
98 |
+
|
99 |
+
return self::$feature_pointer_methods;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* @param $method ReflectionMethod The method to extract name from.
|
104 |
+
*/
|
105 |
+
private static function getNameFromMethod( $method ) {
|
106 |
+
return $method->name;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* @param $method ReflectionMethod The method name.
|
111 |
+
* @return bool Whether the method name matches the filter pointer pattern.
|
112 |
+
*/
|
113 |
+
private static function isFilterPointerMethod( $method ) {
|
114 |
+
// NOTE: ReflectionClass returns methods that are static OR public -- must reduce to an AND
|
115 |
+
return $method->isPublic() && $method->isStatic() && DG_Util::endsWith( $method->name, self::$feature_pointer_method_suffix );
|
116 |
+
}
|
117 |
+
}
|
admin/tabs/advanced-tab.php
ADDED
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Register settings for the tab.
|
6 |
+
*/
|
7 |
+
function dg_register_settings() {
|
8 |
+
global $dg_options;
|
9 |
+
|
10 |
+
add_settings_section(
|
11 |
+
'advanced', __( 'Advanced Thumbnail Generation', 'document-gallery' ),
|
12 |
+
'dg_render_advanced_section', DG_OPTION_NAME );
|
13 |
+
|
14 |
+
add_settings_field(
|
15 |
+
'advanced_logging_enabled', __( 'Logging Enabled', 'document-gallery' ),
|
16 |
+
array( 'DG_Admin', 'renderCheckboxField' ),
|
17 |
+
DG_OPTION_NAME, 'advanced',
|
18 |
+
array(
|
19 |
+
'label_for' => 'label_advanced_logging_enabled',
|
20 |
+
'name' => 'logging_enabled',
|
21 |
+
'value' => esc_attr( $dg_options['logging']['enabled'] ),
|
22 |
+
'option_name' => DG_OPTION_NAME,
|
23 |
+
'description' => __( 'Whether to log debug and error information related to Document Gallery.', 'document-gallery' )
|
24 |
+
) );
|
25 |
+
|
26 |
+
add_settings_field(
|
27 |
+
'advanced_logging_purge_interval', __( 'Logging Purge Interval', 'document-gallery' ),
|
28 |
+
array( 'DG_Admin', 'renderTextField' ),
|
29 |
+
DG_OPTION_NAME, 'advanced',
|
30 |
+
array(
|
31 |
+
'label_for' => 'label_advanced_logging_purge_interval',
|
32 |
+
'name' => 'logging_purge_interval',
|
33 |
+
'value' => esc_attr( $dg_options['logging']['purge_interval'] ),
|
34 |
+
'type' => 'number" min="0" step="1',
|
35 |
+
'option_name' => DG_OPTION_NAME,
|
36 |
+
'description' => __( 'Number of days to keep old log entries (0 disables purging).', 'document-gallery' )
|
37 |
+
) );
|
38 |
+
|
39 |
+
add_settings_field(
|
40 |
+
'advanced_gs', __( 'Ghostscript Absolute Path', 'document-gallery' ),
|
41 |
+
array( 'DG_Admin', 'renderTextField' ),
|
42 |
+
DG_OPTION_NAME, 'advanced',
|
43 |
+
array(
|
44 |
+
'label_for' => 'label_advanced_gs',
|
45 |
+
'name' => 'gs',
|
46 |
+
'value' => esc_attr( $dg_options['thumber']['gs'] ),
|
47 |
+
'option_name' => DG_OPTION_NAME,
|
48 |
+
'description' => $dg_options['thumber']['gs']
|
49 |
+
? __( 'Successfully auto-detected the location of Ghostscript.', 'document-gallery' )
|
50 |
+
: __( 'Failed to auto-detect the location of Ghostscript.', 'document-gallery' )
|
51 |
+
) );
|
52 |
+
|
53 |
+
add_settings_section(
|
54 |
+
'advanced_options_dump', __( 'Options Array Dump', 'document-gallery' ),
|
55 |
+
'dg_render_options_dump_section', DG_OPTION_NAME );
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Validate settings for the tab.
|
60 |
+
*/
|
61 |
+
function dg_validate_settings( $values ) {
|
62 |
+
global $dg_options;
|
63 |
+
$ret = $dg_options;
|
64 |
+
|
65 |
+
// handle setting the Ghostscript path
|
66 |
+
if ( isset( $values['gs'] ) && 0 != strcmp( $values['gs'], $ret['thumber']['gs'] ) ) {
|
67 |
+
if ( false === strpos( $values['gs'], ';' ) ) {
|
68 |
+
$ret['thumber']['gs'] = $values['gs'];
|
69 |
+
} else {
|
70 |
+
add_settings_error( DG_OPTION_NAME, 'thumber-gs',
|
71 |
+
__( 'Invalid Ghostscript path given: ', 'document-gallery' ) . $values['gs'] );
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
// logging settings
|
76 |
+
$ret['logging']['enabled'] = isset( $values['logging_enabled'] );
|
77 |
+
if ( isset( $values['logging_purge_interval'] ) ) {
|
78 |
+
$purge_interval = (int) $values['logging_purge_interval'];
|
79 |
+
if ( $purge_interval >= 0 ) {
|
80 |
+
$ret['logging']['purge_interval'] = $purge_interval;
|
81 |
+
} else {
|
82 |
+
add_settings_error( DG_OPTION_NAME, 'thumber-logging-purge-interval',
|
83 |
+
__( 'Invalid logging purge interval given: ', 'document-gallery' ) . $values['logging_purge_interval'] );
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
return $ret;
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Render the Thumber Advanced section.
|
92 |
+
*/
|
93 |
+
function dg_render_advanced_section() {
|
94 |
+
include_once DG_PATH . 'inc/class-thumber.php'; ?>
|
95 |
+
<p><?php _e( 'Unless you <em>really</em> know what you\'re doing, you should not touch these values.', 'document-gallery' ); ?></p>
|
96 |
+
<?php if ( ! DG_AbstractThumber::isExecAvailable() ) : ?>
|
97 |
+
<p>
|
98 |
+
<em><?php _e( 'NOTE: <code>exec()</code> is not accessible. Ghostscript will not function.', 'document-gallery' ); ?></em>
|
99 |
+
</p>
|
100 |
+
<?php endif; ?>
|
101 |
+
<?php }
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Renders a readonly textfield containing a dump of current DG options.
|
105 |
+
*/
|
106 |
+
function dg_render_options_dump_section() {
|
107 |
+
global $dg_options; ?>
|
108 |
+
<p><?php
|
109 |
+
_e( 'The following <em>readonly text</em> should be provided when <a href="http://wordpress.org/support/plugin/document-gallery" target="_blank">reporting a bug</a>:', 'documet-gallery' );
|
110 |
+
?></p>
|
111 |
+
<table class="form-table">
|
112 |
+
<tbody>
|
113 |
+
<tr valign="top">
|
114 |
+
<td>
|
115 |
+
<textarea readonly="true" rows="10" cols="50" id="options-dump"
|
116 |
+
class="large-text code"><?php print_r( $dg_options ); ?></textarea>
|
117 |
+
</td>
|
118 |
+
</tr>
|
119 |
+
</tbody>
|
120 |
+
</table>
|
121 |
+
<?php }
|
admin/tabs/general-tab.php
ADDED
@@ -0,0 +1,375 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Register settings for the tab.
|
6 |
+
*/
|
7 |
+
function dg_register_settings() {
|
8 |
+
global $dg_options;
|
9 |
+
|
10 |
+
include_once DG_PATH . 'inc/class-gallery.php';
|
11 |
+
include_once DG_PATH . 'inc/class-gallery-sanitization.php';
|
12 |
+
include_once DG_PATH . 'inc/class-thumber.php';
|
13 |
+
|
14 |
+
$defaults = $dg_options['gallery'];
|
15 |
+
$active = $dg_options['thumber']['active'];
|
16 |
+
|
17 |
+
add_settings_section(
|
18 |
+
'gallery_defaults', __( 'Default Settings', 'document-gallery' ),
|
19 |
+
'dg_render_default_settings_section', DG_OPTION_NAME );
|
20 |
+
|
21 |
+
add_settings_section(
|
22 |
+
'thumbnail_generation', __( 'Thumbnail Generation', 'document-gallery' ),
|
23 |
+
'dg_render_thumber_section', DG_OPTION_NAME );
|
24 |
+
|
25 |
+
add_settings_section(
|
26 |
+
'css', __( 'Custom CSS', 'document-gallery' ),
|
27 |
+
'dg_render_css_section', DG_OPTION_NAME );
|
28 |
+
|
29 |
+
add_settings_field(
|
30 |
+
'gallery_defaults_attachment_pg', 'attachment_pg',
|
31 |
+
array( 'DG_Admin', 'renderCheckboxField' ),
|
32 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
33 |
+
array(
|
34 |
+
'label_for' => 'label_gallery_defaults_attachment_pg',
|
35 |
+
'name' => 'gallery_defaults][attachment_pg',
|
36 |
+
'value' => esc_attr( $defaults['attachment_pg'] ),
|
37 |
+
'option_name' => DG_OPTION_NAME,
|
38 |
+
'description' => __( 'Link to attachment page rather than to file.', 'document-gallery' )
|
39 |
+
) );
|
40 |
+
|
41 |
+
add_settings_field(
|
42 |
+
'gallery_defaults_columns', 'columns',
|
43 |
+
array( 'DG_Admin', 'renderTextField' ),
|
44 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
45 |
+
array(
|
46 |
+
'label_for' => 'label_gallery_defaults_columns',
|
47 |
+
'name' => 'gallery_defaults][columns',
|
48 |
+
'value' => esc_attr( $defaults['columns'] ),
|
49 |
+
'type' => 'number" min="1" step="1',
|
50 |
+
'option_name' => DG_OPTION_NAME,
|
51 |
+
'description' => __( 'The number of columns to display when not rendering descriptions.', 'document-gallery' )
|
52 |
+
) );
|
53 |
+
|
54 |
+
add_settings_field(
|
55 |
+
'gallery_defaults_descriptions', 'descriptions',
|
56 |
+
array( 'DG_Admin', 'renderCheckboxField' ),
|
57 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
58 |
+
array(
|
59 |
+
'label_for' => 'label_gallery_defaults_descriptions',
|
60 |
+
'name' => 'gallery_defaults][descriptions',
|
61 |
+
'value' => esc_attr( $defaults['descriptions'] ),
|
62 |
+
'option_name' => DG_OPTION_NAME,
|
63 |
+
'description' => __( 'Include document descriptions.', 'document-gallery' )
|
64 |
+
) );
|
65 |
+
|
66 |
+
add_settings_field(
|
67 |
+
'gallery_defaults_fancy', 'fancy',
|
68 |
+
array( 'DG_Admin', 'renderCheckboxField' ),
|
69 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
70 |
+
array(
|
71 |
+
'label_for' => 'label_gallery_defaults_fancy',
|
72 |
+
'name' => 'gallery_defaults][fancy',
|
73 |
+
'value' => esc_attr( $defaults['fancy'] ),
|
74 |
+
'option_name' => DG_OPTION_NAME,
|
75 |
+
'description' => __( 'Use auto-generated document thumbnails.', 'document-gallery' )
|
76 |
+
) );
|
77 |
+
|
78 |
+
add_settings_field(
|
79 |
+
'gallery_defaults_order', 'order',
|
80 |
+
array( 'DG_Admin', 'renderSelectField' ),
|
81 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
82 |
+
array(
|
83 |
+
'label_for' => 'label_gallery_defaults_order',
|
84 |
+
'name' => 'gallery_defaults][order',
|
85 |
+
'value' => esc_attr( $defaults['order'] ),
|
86 |
+
'options' => DG_GallerySanitization::getOrderOptions(),
|
87 |
+
'option_name' => DG_OPTION_NAME,
|
88 |
+
'description' => __( 'Ascending or descending sorting of documents.', 'document-gallery' )
|
89 |
+
) );
|
90 |
+
|
91 |
+
add_settings_field(
|
92 |
+
'gallery_defaults_orderby', 'orderby',
|
93 |
+
array( 'DG_Admin', 'renderSelectField' ),
|
94 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
95 |
+
array(
|
96 |
+
'label_for' => 'label_gallery_defaults_orderby',
|
97 |
+
'name' => 'gallery_defaults][orderby',
|
98 |
+
'value' => esc_attr( $defaults['orderby'] ),
|
99 |
+
'options' => DG_GallerySanitization::getOrderbyOptions(),
|
100 |
+
'option_name' => DG_OPTION_NAME,
|
101 |
+
'description' => __( 'Which field to order documents by.', 'document-gallery' )
|
102 |
+
) );
|
103 |
+
|
104 |
+
add_settings_field(
|
105 |
+
'gallery_defaults_relation', 'relation',
|
106 |
+
array( 'DG_Admin', 'renderSelectField' ),
|
107 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
108 |
+
array(
|
109 |
+
'label_for' => 'label_gallery_defaults_relation',
|
110 |
+
'name' => 'gallery_defaults][relation',
|
111 |
+
'value' => esc_attr( $defaults['relation'] ),
|
112 |
+
'options' => DG_GallerySanitization::getRelationOptions(),
|
113 |
+
'option_name' => DG_OPTION_NAME,
|
114 |
+
'description' => __( 'Whether matched documents must have all taxa_names (AND) or at least one (OR).', 'document-gallery' )
|
115 |
+
) );
|
116 |
+
|
117 |
+
add_settings_field(
|
118 |
+
'gallery_defaults_limit', 'limit',
|
119 |
+
array( 'DG_Admin', 'renderTextField' ),
|
120 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
121 |
+
array(
|
122 |
+
'label_for' => 'label_gallery_defaults_limit',
|
123 |
+
'name' => 'gallery_defaults][limit',
|
124 |
+
'value' => esc_attr( $defaults['limit'] ),
|
125 |
+
'type' => 'number" min="-1" step="1',
|
126 |
+
'option_name' => DG_OPTION_NAME,
|
127 |
+
'description' => __( 'Limit the number of documents included. -1 means no limit.', 'document-gallery' )
|
128 |
+
) );
|
129 |
+
|
130 |
+
add_settings_field(
|
131 |
+
'gallery_defaults_mime_types', 'mime_types',
|
132 |
+
array( 'DG_Admin', 'renderTextField' ),
|
133 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
134 |
+
array(
|
135 |
+
'label_for' => 'label_gallery_defaults_mime_types',
|
136 |
+
'name' => 'gallery_defaults][mime_types',
|
137 |
+
'value' => esc_attr( $defaults['mime_types'] ),
|
138 |
+
'type' => 'text',
|
139 |
+
'option_name' => DG_OPTION_NAME,
|
140 |
+
'description' => __( 'Comma-delimited list of <a href="http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types">MIME types</a>.', 'document-gallery' )
|
141 |
+
) );
|
142 |
+
|
143 |
+
add_settings_field(
|
144 |
+
'gallery_defaults_new_window', 'new_window',
|
145 |
+
array( 'DG_Admin', 'renderCheckboxField' ),
|
146 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
147 |
+
array(
|
148 |
+
'label_for' => 'label_gallery_defaults_new_window',
|
149 |
+
'name' => 'gallery_defaults][new_window',
|
150 |
+
'value' => esc_attr( $defaults['new_window'] ),
|
151 |
+
'option_name' => DG_OPTION_NAME,
|
152 |
+
'description' => __( 'Open thumbnail links in new window.', 'document-gallery' )
|
153 |
+
) );
|
154 |
+
|
155 |
+
add_settings_field(
|
156 |
+
'gallery_defaults_paginate', 'paginate',
|
157 |
+
array( 'DG_Admin', 'renderCheckboxField' ),
|
158 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
159 |
+
array(
|
160 |
+
'label_for' => 'label_gallery_defaults_paginate',
|
161 |
+
'name' => 'gallery_defaults][paginate',
|
162 |
+
'value' => esc_attr( $defaults['paginate'] ),
|
163 |
+
'option_name' => DG_OPTION_NAME,
|
164 |
+
'description' => __( 'When a limit exists, paginate rather than truncating gallery.', 'document-gallery' )
|
165 |
+
) );
|
166 |
+
|
167 |
+
add_settings_field(
|
168 |
+
'gallery_defaults_post_status', 'post_status',
|
169 |
+
array( 'DG_Admin', 'renderSelectField' ),
|
170 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
171 |
+
array(
|
172 |
+
'label_for' => 'label_gallery_defaults_post_status',
|
173 |
+
'name' => 'gallery_defaults][post_status',
|
174 |
+
'value' => esc_attr( $defaults['post_status'] ),
|
175 |
+
'options' => DG_GallerySanitization::getPostStatuses(),
|
176 |
+
'option_name' => DG_OPTION_NAME,
|
177 |
+
'description' => __( 'Which post status to look for when querying documents.', 'document-gallery' )
|
178 |
+
) );
|
179 |
+
|
180 |
+
add_settings_field(
|
181 |
+
'gallery_defaults_post_type', 'post_type',
|
182 |
+
array( 'DG_Admin', 'renderSelectField' ),
|
183 |
+
DG_OPTION_NAME, 'gallery_defaults',
|
184 |
+
array(
|
185 |
+
'label_for' => 'label_gallery_defaults_post_type',
|
186 |
+
'name' => 'gallery_defaults][post_type',
|
187 |
+
'value' => esc_attr( $defaults['post_type'] ),
|
188 |
+
'options' => DG_GallerySanitization::getPostTypes(),
|
189 |
+
'option_name' => DG_OPTION_NAME,
|
190 |
+
'description' => __( 'Which post type to look for when querying documents.', 'document-gallery' )
|
191 |
+
) );
|
192 |
+
|
193 |
+
add_settings_field(
|
194 |
+
'thumbnail_generation_thumber-co', __( 'Thumber.co', 'document-gallery' ),
|
195 |
+
array( 'DG_Admin', 'renderCheckboxField' ),
|
196 |
+
DG_OPTION_NAME, 'thumbnail_generation',
|
197 |
+
array(
|
198 |
+
'label_for' => 'label_thumbnail_generation_thumber-co',
|
199 |
+
'name' => 'thumbnail_generation][thumber-co',
|
200 |
+
'value' => esc_attr( $active['thumber-co'] ),
|
201 |
+
'option_name' => DG_OPTION_NAME,
|
202 |
+
'description' => __( 'Use your <a href="http://thumber.co" target="_blank">Thumber.co</a> subscription to remotely generate document thumbnails.' , 'document-gallery' ),
|
203 |
+
'disabled' => ! DG_ThumberCoThumber::isThumberCoAvailable()
|
204 |
+
) );
|
205 |
+
|
206 |
+
add_settings_field(
|
207 |
+
'thumbnail_generation_av', __( 'Audio/Video', 'document-gallery' ),
|
208 |
+
array( 'DG_Admin', 'renderCheckboxField' ),
|
209 |
+
DG_OPTION_NAME, 'thumbnail_generation',
|
210 |
+
array(
|
211 |
+
'label_for' => 'label_thumbnail_generation_av',
|
212 |
+
'name' => 'thumbnail_generation][av',
|
213 |
+
'value' => esc_attr( $active['av'] ),
|
214 |
+
'option_name' => DG_OPTION_NAME,
|
215 |
+
'description' => esc_html__( 'Locally generate thumbnails for audio & video files.', 'document-gallery' )
|
216 |
+
) );
|
217 |
+
|
218 |
+
add_settings_field(
|
219 |
+
'thumbnail_generation_gs', 'Ghostscript',
|
220 |
+
array( 'DG_Admin', 'renderCheckboxField' ),
|
221 |
+
DG_OPTION_NAME, 'thumbnail_generation',
|
222 |
+
array(
|
223 |
+
'label_for' => 'label_thumbnail_generation_gs',
|
224 |
+
'name' => 'thumbnail_generation][gs',
|
225 |
+
'value' => esc_attr( $active['gs'] ),
|
226 |
+
'option_name' => DG_OPTION_NAME,
|
227 |
+
'description' => DG_GhostscriptThumber::isGhostscriptAvailable()
|
228 |
+
? __( 'Use <a href="http://www.ghostscript.com/" target="_blank">Ghostscript</a> for faster local PDF processing (compared to Imagick).', 'document-gallery' )
|
229 |
+
: __( 'Your server is not configured to run <a href="http://www.ghostscript.com/" target="_blank">Ghostscript</a>.', 'document-gallery' ),
|
230 |
+
'disabled' => ! DG_GhostscriptThumber::isGhostscriptAvailable()
|
231 |
+
) );
|
232 |
+
|
233 |
+
add_settings_field(
|
234 |
+
'thumbnail_generation_imagick', 'Imagick',
|
235 |
+
array( 'DG_Admin', 'renderCheckboxField' ),
|
236 |
+
DG_OPTION_NAME, 'thumbnail_generation',
|
237 |
+
array(
|
238 |
+
'label_for' => 'label_thumbnail_generation_imagick',
|
239 |
+
'name' => 'thumbnail_generation][imagick',
|
240 |
+
'value' => esc_attr( $active['imagick'] ),
|
241 |
+
'option_name' => DG_OPTION_NAME,
|
242 |
+
'description' => DG_ImagickThumber::isImagickAvailable()
|
243 |
+
? __( 'Use <a href="http://www.php.net/manual/en/book.imagick.php" target="_blank">Imagick</a> to handle lots of filetypes locally.', 'document-gallery' )
|
244 |
+
: __( 'Your server is not configured to run <a href="http://www.php.net/manual/en/book.imagick.php" target="_blank">Imagick</a>.', 'document-gallery' ),
|
245 |
+
'disabled' => ! DG_ImagickThumber::isImagickAvailable()
|
246 |
+
) );
|
247 |
+
|
248 |
+
add_settings_field(
|
249 |
+
'thumbnail_generation_width', __( 'Max Thumbnail Dimensions', 'document-gallery' ),
|
250 |
+
array( 'DG_Admin', 'renderMultiTextField' ),
|
251 |
+
DG_OPTION_NAME, 'thumbnail_generation',
|
252 |
+
array(
|
253 |
+
array(
|
254 |
+
'label_for' => 'label_advanced_width',
|
255 |
+
'name' => 'thumbnail_generation][width',
|
256 |
+
'value' => esc_attr( $dg_options['thumber']['width'] ),
|
257 |
+
'type' => 'number" min="1" step="1',
|
258 |
+
'option_name' => DG_OPTION_NAME,
|
259 |
+
'description' => ' x '
|
260 |
+
),
|
261 |
+
array(
|
262 |
+
'label_for' => 'label_advanced_height',
|
263 |
+
'name' => 'thumbnail_generation][height',
|
264 |
+
'value' => esc_attr( $dg_options['thumber']['height'] ),
|
265 |
+
'type' => 'number" min="1" step="1',
|
266 |
+
'option_name' => DG_OPTION_NAME,
|
267 |
+
'description' => __( 'The max width and height (in pixels) that thumbnails will be generated.', 'document-gallery' )
|
268 |
+
)
|
269 |
+
) );
|
270 |
+
}
|
271 |
+
|
272 |
+
/**
|
273 |
+
* Validate settings for the tab.
|
274 |
+
*/
|
275 |
+
function dg_validate_settings( $values ) {
|
276 |
+
global $dg_options;
|
277 |
+
$ret = $dg_options;
|
278 |
+
|
279 |
+
include_once DG_PATH . 'inc/class-gallery.php';
|
280 |
+
|
281 |
+
$thumbs_cleared = false;
|
282 |
+
|
283 |
+
// handle gallery shortcode defaults
|
284 |
+
$errs = array();
|
285 |
+
$ret['gallery'] = DG_Gallery::sanitizeDefaults( null, $values['gallery_defaults'], $errs );
|
286 |
+
|
287 |
+
foreach ( $errs as $k => $v ) {
|
288 |
+
add_settings_error( DG_OPTION_NAME, str_replace( '_', '-', $k ), $v );
|
289 |
+
}
|
290 |
+
|
291 |
+
// handle setting width
|
292 |
+
if ( isset( $values['thumbnail_generation']['width'] ) ) {
|
293 |
+
$width = (int) $values['thumbnail_generation']['width'];
|
294 |
+
if ( $width > 0 ) {
|
295 |
+
$ret['thumber']['width'] = $width;
|
296 |
+
} else {
|
297 |
+
add_settings_error( DG_OPTION_NAME, 'thumber-width',
|
298 |
+
__( 'Invalid width given: ', 'document-gallery' ) . $values['thumbnail_generation']['width'] );
|
299 |
+
}
|
300 |
+
|
301 |
+
unset( $values['thumbnail_generation']['width'] );
|
302 |
+
}
|
303 |
+
|
304 |
+
// handle setting height
|
305 |
+
if ( isset( $values['thumbnail_generation']['height'] ) ) {
|
306 |
+
$height = (int) $values['thumbnail_generation']['height'];
|
307 |
+
if ( $height > 0 ) {
|
308 |
+
$ret['thumber']['height'] = $height;
|
309 |
+
} else {
|
310 |
+
add_settings_error( DG_OPTION_NAME, 'thumber-height',
|
311 |
+
__( 'Invalid height given: ', 'document-gallery' ) . $values['thumbnail_generation']['height'] );
|
312 |
+
}
|
313 |
+
|
314 |
+
unset( $values['thumbnail_generation']['width'] );
|
315 |
+
}
|
316 |
+
|
317 |
+
// delete thumb cache to force regeneration if max dimensions changed
|
318 |
+
if ( $ret['thumber']['width'] !== $dg_options['thumber']['width'] ||
|
319 |
+
$ret['thumber']['height'] !== $dg_options['thumber']['height'] ) {
|
320 |
+
DG_Thumb::purgeThumbs();
|
321 |
+
}
|
322 |
+
|
323 |
+
// handle setting the active thumbers
|
324 |
+
foreach ( array_keys( $ret['thumber']['active'] ) as $k ) {
|
325 |
+
$ret['thumber']['active'][ $k ] = isset( $values['thumbnail_generation'][ $k ] );
|
326 |
+
}
|
327 |
+
|
328 |
+
// if new thumbers available, clear failed thumbnails for retry
|
329 |
+
if ( ! $thumbs_cleared ) {
|
330 |
+
DG_Thumb::purgeFailedThumbs();
|
331 |
+
}
|
332 |
+
|
333 |
+
// handle modified CSS
|
334 |
+
if ( trim( $ret['css']['text'] ) !== trim( $values['css'] ) ) {
|
335 |
+
$ret['css']['text'] = trim( $values['css'] );
|
336 |
+
}
|
337 |
+
|
338 |
+
return $ret;
|
339 |
+
}
|
340 |
+
|
341 |
+
/**
|
342 |
+
* Render the Default Settings section.
|
343 |
+
*/
|
344 |
+
function dg_render_default_settings_section() { ?>
|
345 |
+
<p><?php _e( 'The following values will be used by default in the shortcode. You can still manually set each of these values in each individual shortcode.', 'document-gallery' ); ?></p>
|
346 |
+
<?php }
|
347 |
+
|
348 |
+
|
349 |
+
/**
|
350 |
+
* Render the Thumber section.
|
351 |
+
*/
|
352 |
+
function dg_render_thumber_section() { ?>
|
353 |
+
<p><?php _e( 'Select which tools to use when generating thumbnails.', 'document-gallery' ); ?></p>
|
354 |
+
<?php }
|
355 |
+
|
356 |
+
|
357 |
+
/**
|
358 |
+
* Renders a text field for use when modifying the CSS to be printed in addition to the default CSS.
|
359 |
+
*/
|
360 |
+
function dg_render_css_section() {
|
361 |
+
global $dg_options; ?>
|
362 |
+
<p><?php printf(
|
363 |
+
__( 'Enter custom CSS styling for use with document galleries. To see which ids and classes you can style, take a look at <a href="%s" target="_blank">style.css</a>.', 'document-gallery' ),
|
364 |
+
DG_URL . 'assets/css/style.css' ); ?></p>
|
365 |
+
<table class="form-table">
|
366 |
+
<tbody>
|
367 |
+
<tr valign="top">
|
368 |
+
<td>
|
369 |
+
<textarea name="<?php echo DG_OPTION_NAME; ?>[css]" rows="10" cols="50"
|
370 |
+
class="large-text code"><?php echo $dg_options['css']['text']; ?></textarea>
|
371 |
+
</td>
|
372 |
+
</tr>
|
373 |
+
</tbody>
|
374 |
+
</table>
|
375 |
+
<?php }
|
admin/tabs/logging-tab.php
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Register settings for the tab.
|
6 |
+
*/
|
7 |
+
function dg_register_settings() {
|
8 |
+
add_settings_section(
|
9 |
+
'logging_table', '',
|
10 |
+
'dg_render_logging_section', DG_OPTION_NAME );
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Validate settings for the tab.
|
15 |
+
*/
|
16 |
+
function dg_validate_settings( $values ) {
|
17 |
+
global $dg_options;
|
18 |
+
if (isset($values['clearLog'])) {
|
19 |
+
DG_Logger::clearLog();
|
20 |
+
}
|
21 |
+
|
22 |
+
return $dg_options;
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Render the Logging table.
|
27 |
+
*/
|
28 |
+
function dg_render_logging_section() {
|
29 |
+
$log_list = DG_Logger::readLog();
|
30 |
+
if ( $log_list ) {
|
31 |
+
$levels = array_map( 'dg_get_log_label_span', array_keys( DG_LogLevel::getLogLevels() ) );
|
32 |
+
|
33 |
+
$fmt =
|
34 |
+
'<tr>' .
|
35 |
+
'<th scope="col" class="manage-column column-date sorted desc"><a href="javascript:void(0);">' .
|
36 |
+
'<span>%s</span><span class="sorting-indicator"></span></a>' .
|
37 |
+
'</th>' .
|
38 |
+
'<th scope="col" class="manage-column column-level"><span>%s</span></th>' .
|
39 |
+
'<th scope="col" class="manage-column column-message"><span>%s</span></th>' .
|
40 |
+
'</tr>';
|
41 |
+
|
42 |
+
$thead = sprintf( $fmt,
|
43 |
+
__( 'Date', 'document-gallery' ),
|
44 |
+
__( 'Level', 'document-gallery' ),
|
45 |
+
__( 'Message', 'document-gallery' ) );
|
46 |
+
|
47 |
+
?>
|
48 |
+
<div class="log-list-wrapper">
|
49 |
+
<div>
|
50 |
+
<div class="tablenav top">
|
51 |
+
<div class="alignleft bulkactions">
|
52 |
+
<button class="action expandAll">
|
53 |
+
<?php echo __( 'Expand All', 'document-gallery' ); ?>
|
54 |
+
</button>
|
55 |
+
<button class="action collapseAll">
|
56 |
+
<?php echo __( 'Collapse All', 'document-gallery' ); ?>
|
57 |
+
</button>
|
58 |
+
</div>
|
59 |
+
<div class="levelSelector">
|
60 |
+
<input type="checkbox" id="allLevels" name="lswitch" value="all" checked/>
|
61 |
+
<label for="allLevels" class="allLevels">ALL</label>
|
62 |
+
<?php
|
63 |
+
foreach ( array_keys( DG_LogLevel::getLogLevels() ) as $k ) { ?>
|
64 |
+
<?php
|
65 |
+
$lower = strtolower( $k );
|
66 |
+
$upper = strtoupper( $k );
|
67 |
+
?>
|
68 |
+
<input type="checkbox" id="<?php echo $lower; ?>Level" name="lswitch"
|
69 |
+
value="<?php echo $lower; ?>" checked/>
|
70 |
+
<label for="<?php echo $lower; ?>Level"
|
71 |
+
class="<?php echo $lower; ?>Level"><?php echo $upper; ?></label>
|
72 |
+
<?php }
|
73 |
+
?>
|
74 |
+
</div>
|
75 |
+
</div>
|
76 |
+
<table id="LogTable" class="wp-list-table widefat fixed media" cellpadding="0" cellspacing="0">
|
77 |
+
<thead>
|
78 |
+
<?php echo $thead; ?>
|
79 |
+
</thead>
|
80 |
+
<tfoot>
|
81 |
+
<?php echo $thead; ?>
|
82 |
+
</tfoot>
|
83 |
+
<tbody><?php
|
84 |
+
for ( $i = count( $log_list ); $i > 0; $i-- ) {
|
85 |
+
$log_entry = $log_list[ $i - 1 ];
|
86 |
+
$date = DocumentGallery::localDateTimeFromTimestamp( $log_entry[0] );
|
87 |
+
|
88 |
+
// convert attachment names to links
|
89 |
+
$log_entry[2] = preg_replace( '/[ ^](attachment #)(\d+)[.,: ]/i', ' <a href="' . home_url() . '/?attachment_id=\2" target="_blank">\1<strong>\2</strong></a> ', $log_entry[2] );
|
90 |
+
|
91 |
+
// bold the place where log entry was submitted
|
92 |
+
$log_entry[2] = preg_replace( '/^(\((?:\w+(?:::|->))?\w+\)) /', '<strong>\1</strong> ', $log_entry[2] );
|
93 |
+
|
94 |
+
// italicize any function references within log entry
|
95 |
+
$log_entry[2] = preg_replace( '/(\(?\w+(?:::|->)\w+\)?)/m', '<i>\1</i>', $log_entry[2] );
|
96 |
+
|
97 |
+
echo '<tr><td class="date column-date" data-sort-value="' . $log_entry[0] . '"><span class="logLabel date">' . $date . '</span></td>' .
|
98 |
+
'<td class="column-level">' . $levels[ $log_entry[1] ] . '</td>' .
|
99 |
+
'<td class="column-entry">' . ( empty( $log_entry[3] ) ? '<pre>' . $log_entry[2] . '</pre>' : '<div class="expander" title="Click to Expand"><pre>' . $log_entry[2] . '</pre><div><span class="dashicons dashicons-arrow-down-alt2"></span></div></div><div class="spoiler-body"><pre>' . $log_entry[3] . '</pre></div>' ) . '</td>' .
|
100 |
+
'</tr>' . PHP_EOL;
|
101 |
+
} ?>
|
102 |
+
</tbody>
|
103 |
+
</table>
|
104 |
+
<div class="tablenav bottom">
|
105 |
+
<div class="alignright bulkactions">
|
106 |
+
<button class="button action clearLog" name='<?php echo DG_OPTION_NAME; ?>[clearLog]'
|
107 |
+
value='true'>
|
108 |
+
<?php echo __( 'Clear Log', 'document-gallery' ); ?>
|
109 |
+
</button>
|
110 |
+
</div>
|
111 |
+
</div>
|
112 |
+
</div>
|
113 |
+
</div>
|
114 |
+
<?php } else {
|
115 |
+
echo '<div class="noLog">' . __( 'There are no log entries at this time.', 'document-gallery' ) . '<br />' . __( 'For Your information:', 'document-gallery' ) . ' <strong><i>' . __( 'Logging', 'document-gallery' ) . '</i></strong> ' . ( DG_Logger::logEnabled() ? '<span class="loggingON">' . __( 'is turned ON', 'document-gallery' ) . '!</span>' : '<span class="loggingOFF">' . __( 'is turned OFF', 'document-gallery' ) . '!</span>' ) . '</div>';
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Takes label name and returns SPAN tag.
|
121 |
+
*
|
122 |
+
* @param string $e label name.
|
123 |
+
*
|
124 |
+
* @return string SPAN tag
|
125 |
+
*/
|
126 |
+
function dg_get_log_label_span( $e ) {
|
127 |
+
return '<span class="logLabel ' . strtolower( $e ) . '">' . strtoupper( $e ) . '</span>';
|
128 |
+
}
|
admin/tabs/thumber-co-tab.php
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Register settings for the tab.
|
6 |
+
*/
|
7 |
+
function dg_register_settings() {
|
8 |
+
global $dg_options;
|
9 |
+
|
10 |
+
add_settings_section(
|
11 |
+
'thumber-co', __( 'Thumber.co Subscription', 'document-gallery' ),
|
12 |
+
'dg_render_thumber_co_section', DG_OPTION_NAME );
|
13 |
+
|
14 |
+
add_settings_field(
|
15 |
+
'thumber-co_uid', __( 'User ID', 'document-gallery' ),
|
16 |
+
array( 'DG_Admin', 'renderTextField' ),
|
17 |
+
DG_OPTION_NAME, 'thumber-co',
|
18 |
+
array(
|
19 |
+
'label_for' => 'label_thumber-co_uid',
|
20 |
+
'name' => 'uid',
|
21 |
+
'value' => esc_attr( $dg_options['thumber-co']['uid'] ),
|
22 |
+
'option_name' => DG_OPTION_NAME,
|
23 |
+
'description' => __( 'User ID assigned by Thumber.co', 'document-gallery' )
|
24 |
+
) );
|
25 |
+
|
26 |
+
add_settings_field(
|
27 |
+
'thumber-co_secret', __( 'User Secret', 'document-gallery' ),
|
28 |
+
array( 'DG_Admin', 'renderTextField' ),
|
29 |
+
DG_OPTION_NAME, 'thumber-co',
|
30 |
+
array(
|
31 |
+
'label_for' => 'label_thumber-co_secret',
|
32 |
+
'name' => 'secret',
|
33 |
+
'value' => esc_attr( $dg_options['thumber-co']['secret'] ),
|
34 |
+
'option_name' => DG_OPTION_NAME,
|
35 |
+
'description' => __( 'User secret assigned by Thumber.co', 'document-gallery' )
|
36 |
+
) );
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Validate settings for the tab.
|
41 |
+
*/
|
42 |
+
function dg_validate_settings( $values ) {
|
43 |
+
global $dg_options;
|
44 |
+
$ret = $dg_options;
|
45 |
+
|
46 |
+
$has_changed = $has_error = false;
|
47 |
+
$old_uid = $dg_options['thumber-co']['uid'];
|
48 |
+
$old_secret = $dg_options['thumber-co']['secret'];
|
49 |
+
$old_subscription = $dg_options['thumber-co']['subscription'];
|
50 |
+
|
51 |
+
// handle setting the UID
|
52 |
+
if ( isset( $values['uid'] ) && 0 !== strcmp( $values['uid'], $ret['thumber-co']['uid'] ) ) {
|
53 |
+
static $guid_regex = '/^[^\W_]{8}-[^\W_]{4}-[^\W_]{4}-[^\W_]{4}-[^\W_]{12}$/';
|
54 |
+
if ( '' === $values['uid'] || preg_match( $guid_regex, $values['uid'] ) ) {
|
55 |
+
$ret['thumber-co']['uid'] = ( '' !== $values['uid'] ) ? $values['uid'] : null;
|
56 |
+
$has_changed = true;
|
57 |
+
} else {
|
58 |
+
add_settings_error( DG_OPTION_NAME, 'thumber-co-uid',
|
59 |
+
__( 'Invalid user ID given: ', 'document-gallery' ) . $values['uid'] );
|
60 |
+
$has_error = true;
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
// handle setting the user secret
|
65 |
+
if ( isset( $values['secret'] ) && 0 !== strcmp( $values['secret'], $ret['thumber-co']['secret'] ) ) {
|
66 |
+
static $secret_regex = '/^[-A-Z\d]+$/i';
|
67 |
+
if ( '' === $values['secret'] || preg_match( $secret_regex, $values['secret'] ) ) {
|
68 |
+
$ret['thumber-co']['secret'] = ( '' !== $values['secret'] ) ? $values['secret'] : null;
|
69 |
+
$has_changed = true;
|
70 |
+
} else {
|
71 |
+
add_settings_error( DG_OPTION_NAME, 'thumber-co-secret',
|
72 |
+
__( 'Invalid user secret given: ', 'document-gallery' ) . $values['secret'] );
|
73 |
+
$has_error = true;
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
// test whether we can actually auth w/ given credentials
|
78 |
+
if ( $has_changed && ! $has_error ) {
|
79 |
+
if ( isset( $ret['thumber-co']['uid'] ) && isset( $ret['thumber-co']['secret'] ) ) {
|
80 |
+
include_once DG_PATH . 'inc/thumbers/thumber-co/class-thumber-co-thumber.php';
|
81 |
+
|
82 |
+
// NOTE: We're tricking getSubscription to re-query subscription w/ new credentials
|
83 |
+
$dg_options['thumber-co']['subscription'] = null;
|
84 |
+
|
85 |
+
$client = DG_ThumberClient::getInstance();
|
86 |
+
$client->setUid( $ret['thumber-co']['uid'] );
|
87 |
+
$client->setUserSecret( $ret['thumber-co']['secret'] );
|
88 |
+
$ret['thumber-co']['subscription'] = $client->getSubscription( false );
|
89 |
+
if ( ! isset( $ret['thumber-co']['subscription'] ) ) {
|
90 |
+
$ret['thumber-co']['uid'] = $old_uid;
|
91 |
+
$ret['thumber-co']['secret'] = $old_secret;
|
92 |
+
$ret['thumber-co']['subscription'] = $old_subscription;
|
93 |
+
|
94 |
+
add_settings_error( DG_OPTION_NAME, 'thumber-co-authenticate',
|
95 |
+
__( 'Failed to authenticate with given user ID and secret.', 'document-gallery' ) );
|
96 |
+
} else {
|
97 |
+
// auto-enable if we've got newly-working credentials
|
98 |
+
$ret['thumber']['active']['thumber-co'] = true;
|
99 |
+
}
|
100 |
+
} else {
|
101 |
+
// auto-disable if we've got newly-broken credentials
|
102 |
+
$ret['thumber']['active']['thumber-co'] = false;
|
103 |
+
}
|
104 |
+
}
|
105 |
+
|
106 |
+
return $ret;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Render the Thumber Advanced section.
|
111 |
+
*/
|
112 |
+
function dg_render_thumber_co_section() { ?>
|
113 |
+
<p><?php _e( '<em>Thumber.co</em> is an external service capable of generating ' .
|
114 |
+
'thumbnails for the tricky file types that Document Gallery can\'t handle on its own. Files such as ' .
|
115 |
+
'Word, PowerPoint, and PDFs can all be processed, allowing you to provide a more complete experience ' .
|
116 |
+
'to your users. Further information, including a complete list of supported file types is available '.
|
117 |
+
'<a href="http://thumber.co/about" target="_blank">here</a>.', 'document-gallery' ); ?></p>
|
118 |
+
|
119 |
+
<p><?php _e( 'Once you <a href="http://thumber.co/subscriptions">register for a Thumber.co subscription</a>, simply enter your credentials below to get started!' ); ?></p>
|
120 |
+
<?php if ( ! DG_Util::isPublicSite() ) : ?>
|
121 |
+
<p>
|
122 |
+
<em><?php _e( 'NOTE: It appears that you are on a private server not accessible from outside your local network. ' .
|
123 |
+
'Thumber.co must be able to access your site in order for thumbnail conversions to work properly.', 'document-gallery' ); ?></em>
|
124 |
+
</p>
|
125 |
+
<?php endif; ?>
|
126 |
+
<?php }
|
admin/tabs/thumbnail-management-tab.php
ADDED
@@ -0,0 +1,328 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
$dg_url_params = array( 'page' => DG_OPTION_NAME, 'tab' => 'thumbnail-management-tab' );
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Register settings for the tab.
|
8 |
+
*/
|
9 |
+
function dg_register_settings() {
|
10 |
+
add_settings_section(
|
11 |
+
'thumbnail_table', '',
|
12 |
+
'dg_render_thumbnail_section', DG_OPTION_NAME );
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Validate settings for the tab.
|
17 |
+
*/
|
18 |
+
function dg_validate_settings( $values ) {
|
19 |
+
global $dg_options;
|
20 |
+
$ret = $dg_options;
|
21 |
+
$responseArr = array( 'result' => false );
|
22 |
+
|
23 |
+
if ( isset( $values['entry'] ) ) {
|
24 |
+
$ID = intval( $values['entry'] );
|
25 |
+
} else {
|
26 |
+
$ID = - 1;
|
27 |
+
}
|
28 |
+
|
29 |
+
// Thumbnail(s) cleanup;
|
30 |
+
// cleanup value is a marker
|
31 |
+
if ( isset( $values['cleanup'] ) && isset( $values['ids'] ) ) {
|
32 |
+
$deleted = array_values( array_intersect( array_keys( DG_Thumb::getThumbs() ), $values['ids'] ) );
|
33 |
+
DG_Thumb::purgeThumbs( $deleted );
|
34 |
+
$responseArr['result'] = true;
|
35 |
+
$responseArr['deleted'] = $deleted;
|
36 |
+
}
|
37 |
+
|
38 |
+
// Attachment title update
|
39 |
+
// title value is a marker
|
40 |
+
elseif ( isset( $values['title'] ) && $ID != - 1 ) {
|
41 |
+
$attachment = array(
|
42 |
+
'ID' => $ID,
|
43 |
+
'post_title' => rawurldecode( addslashes( $values['title'] ) )
|
44 |
+
);
|
45 |
+
if ( wp_update_post( $attachment ) ) {
|
46 |
+
$responseArr['result'] = true;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
// Attachment description update
|
51 |
+
// description value is a marker
|
52 |
+
elseif ( isset( $values['description'] ) && $ID != - 1 ) {
|
53 |
+
$attachment = array(
|
54 |
+
'ID' => $ID,
|
55 |
+
'post_content' => rawurldecode( addslashes( $values['description'] ) )
|
56 |
+
);
|
57 |
+
if ( wp_update_post( $attachment ) ) {
|
58 |
+
$responseArr['result'] = true;
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
// Thumbnail file manual refresh (one at a time)
|
63 |
+
// upload value is a marker
|
64 |
+
elseif ( isset( $values['upload'] ) && isset( $_FILES['file'] ) && array_key_exists( $ID, DG_Thumb::getThumbs() ) ) {
|
65 |
+
$uploaded_filename = DG_Admin::validateUploadedFile();
|
66 |
+
if ( $uploaded_filename && ( $thumb = DG_Thumber::setThumbnail( $ID, $uploaded_filename ) ) ) {
|
67 |
+
$responseArr['result'] = true;
|
68 |
+
$responseArr['url'] = $thumb->getUrl();
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
|
73 |
+
@header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
|
74 |
+
echo wp_json_encode( $responseArr );
|
75 |
+
add_filter( 'wp_redirect', 'dg_exit', 1, 0 );
|
76 |
+
}
|
77 |
+
|
78 |
+
return $ret;
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Render the Thumbnail table.
|
83 |
+
*/
|
84 |
+
function dg_render_thumbnail_section() {
|
85 |
+
global $dg_url_params;
|
86 |
+
|
87 |
+
include_once DG_PATH . 'inc/class-thumber.php';
|
88 |
+
static $limit_options = array( 10, 25, 75 );
|
89 |
+
static $order_options = array( 'asc', 'desc' );
|
90 |
+
static $orderby_options = array( 'date', 'title' );
|
91 |
+
$options = DG_Thumber::getOptions();
|
92 |
+
|
93 |
+
// find subset of thumbs to be included
|
94 |
+
$orderby = $dg_url_params['orderby'] = dg_get_orderby_param( $orderby_options );
|
95 |
+
$order = $dg_url_params['order'] = dg_get_order_param( $order_options );
|
96 |
+
$limit = $dg_url_params['limit'] = dg_get_limit_param();
|
97 |
+
|
98 |
+
$thumbs = DG_Thumb::getThumbs( $options['width'] . 'x' . $options['height'] );
|
99 |
+
uasort( $thumbs, 'dg_cmp_thumb' );
|
100 |
+
$thumbs_number = count( $thumbs );
|
101 |
+
$lastsheet = ceil( $thumbs_number / $limit );
|
102 |
+
$sheet = isset( $_REQUEST['sheet'] ) ? absint( $_REQUEST['sheet'] ) : 1;
|
103 |
+
if ( $sheet === 0 || $sheet > $lastsheet ) {
|
104 |
+
$sheet = 1;
|
105 |
+
}
|
106 |
+
|
107 |
+
$offset = ( $sheet - 1 ) * $limit;
|
108 |
+
$thumbs = array_slice( $thumbs, $offset, $limit, true );
|
109 |
+
|
110 |
+
// https://core.trac.wordpress.org/ticket/12212
|
111 |
+
$posts = array();
|
112 |
+
if ( ! empty( $thumbs ) ) {
|
113 |
+
$posts = get_posts(
|
114 |
+
array(
|
115 |
+
'post_type' => 'any',
|
116 |
+
'post_status' => 'any',
|
117 |
+
'numberposts' => - 1,
|
118 |
+
'post__in' => array_keys( $thumbs ),
|
119 |
+
'orderby' => 'post__in'
|
120 |
+
) );
|
121 |
+
}
|
122 |
+
|
123 |
+
foreach ( $posts as $post ) {
|
124 |
+
$path_parts = pathinfo( $post->guid );
|
125 |
+
|
126 |
+
$thumb = $thumbs[$post->ID];
|
127 |
+
$thumbs[$post->ID] = array();
|
128 |
+
$t = &$thumbs[$post->ID];
|
129 |
+
$t['timestamp'] = $thumb->getTimestamp();
|
130 |
+
$t['title'] = dg_get_thumb_title( $post );
|
131 |
+
$t['ext'] = isset( $path_parts['extension'] ) ? $path_parts['extension'] : '';
|
132 |
+
$t['description'] = $post->post_content;
|
133 |
+
$t['icon'] = $thumb->isSuccess() ? $thumb->getUrl() : DG_DefaultThumber::getInstance()->getThumbnail( $post->ID );
|
134 |
+
}
|
135 |
+
unset( $posts );
|
136 |
+
|
137 |
+
$select_limit = '';
|
138 |
+
foreach ( $limit_options as $l_o ) {
|
139 |
+
$select_limit .= '<option value="' . $l_o . '"' . selected( $limit, $l_o, false ) . '>' . $l_o . '</option>' . PHP_EOL;
|
140 |
+
}
|
141 |
+
|
142 |
+
$thead = '<tr>' .
|
143 |
+
'<th scope="col" class="manage-column column-cb check-column">' .
|
144 |
+
'<label class="screen-reader-text" for="cb-select-all-%1$d">' . __( 'Select All', 'document-gallery' ) . '</label>' .
|
145 |
+
'<input id="cb-select-all-%1$d" type="checkbox">' .
|
146 |
+
'</th>' .
|
147 |
+
'<th scope="col" class="manage-column column-icon">' . __( 'Thumbnail', 'document-gallery' ) . '</th>' .
|
148 |
+
'<th scope="col" class="manage-column column-title ' . ( ( $orderby != 'title' ) ? 'sortable desc' : 'sorted ' . $order ) . '"><a href="?' . http_build_query( array_merge( $dg_url_params, array(
|
149 |
+
'orderby' => 'title',
|
150 |
+
'order' => ( ( $orderby != 'title' ) ? 'asc' : ( ( $order == 'asc' ) ? 'desc' : 'asc' ) )
|
151 |
+
) ) ) . '"><span>' . __( 'File name', 'document-gallery' ) . '</span><span class="sorting-indicator"></span></th>' .
|
152 |
+
'<th scope="col" class="manage-column column-description">' . __( 'Description', 'document-gallery' ) . '</th>' .
|
153 |
+
'<th scope="col" class="manage-column column-thumbupload"></th>' .
|
154 |
+
'<th scope="col" class="manage-column column-date ' . ( ( $orderby != 'date' ) ? 'sortable asc' : 'sorted ' . $order ) . '"><a href="?' . http_build_query( array_merge( $dg_url_params, array(
|
155 |
+
'orderby' => 'date',
|
156 |
+
'order' => ( ( $orderby != 'date' ) ? 'desc' : ( ( $order == 'asc' ) ? 'desc' : 'asc' ) )
|
157 |
+
) ) ) . '"><span>' . __( 'Date', 'document-gallery' ) . '</span><span class="sorting-indicator"></span></th>' .
|
158 |
+
'</tr>';
|
159 |
+
|
160 |
+
$pagination = '<div class="alignleft bulkactions"><button class="button action deleteSelected">' . __( 'Delete Selected', 'document-gallery' ) . '</button></div><div class="tablenav-pages">' .
|
161 |
+
'<span class="displaying-num">' .
|
162 |
+
$thumbs_number . ' ' . _n( 'item', 'items', $thumbs_number, 'document-gallery' ) .
|
163 |
+
'</span>' . ( $lastsheet > 1 ?
|
164 |
+
'<span class="pagination-links">' .
|
165 |
+
'<a class="first-page' . ( $sheet == 1 ? ' disabled' : '' ) . '" title="' . __( 'Go to the first page', 'document-gallery' ) . '"' . ( $sheet == 1 ? '' : ' href="?' . http_build_query( $dg_url_params ) . '"' ) . '>«</a>' .
|
166 |
+
'<a class="prev-page' . ( $sheet == 1 ? ' disabled' : '' ) . '" title="' . __( 'Go to the previous page', 'document-gallery' ) . '"' . ( $sheet == 1 ? '' : ' href="?' . http_build_query( array_merge( $dg_url_params, array( 'sheet' => $sheet - 1 ) ) ) . '"' ) . '>‹</a>' .
|
167 |
+
'<span class="paging-input">' .
|
168 |
+
'<input class="current-page" title="' . __( 'Current page', 'document-gallery' ) . '" type="text" name="paged" value="' . $sheet . '" size="' . strlen( $sheet ) . '" maxlength="' . strlen( $sheet ) . '"> ' . __( 'of', 'document-gallery' ) . ' <span class="total-pages">' . $lastsheet . '</span></span>' .
|
169 |
+
'<a class="next-page' . ( $sheet == $lastsheet ? ' disabled' : '' ) . '" title="' . __( 'Go to the next page', 'document-gallery' ) . '"' . ( $sheet == $lastsheet ? '' : ' href="?' . http_build_query( array_merge( $dg_url_params, array( 'sheet' => $sheet + 1 ) ) ) . '"' ) . '>›</a>' .
|
170 |
+
'<a class="last-page' . ( $sheet == $lastsheet ? ' disabled' : '' ) . '" title="' . __( 'Go to the last page', 'document-gallery' ) . '"' . ( $sheet == $lastsheet ? '' : ' href="?' . http_build_query( array_merge( $dg_url_params, array( 'sheet' => $lastsheet ) ) ) . '"' ) . '>»</a>' .
|
171 |
+
'</span>' : ' <b>|</b> ' ) .
|
172 |
+
'<span class="displaying-num"><select dir="rtl" class="limit_per_page">' . $select_limit . '</select> ' . __( 'items per page', 'document-gallery' ) . '</span>' .
|
173 |
+
'</div>' .
|
174 |
+
'<br class="clear" />';
|
175 |
+
?>
|
176 |
+
|
177 |
+
<script type="text/javascript">
|
178 |
+
var URL_params = <?php echo wp_json_encode( $dg_url_params ); ?>;
|
179 |
+
</script>
|
180 |
+
<div class="thumbs-list-wrapper">
|
181 |
+
<div>
|
182 |
+
<div class="tablenav top"><?php echo $pagination; ?></div>
|
183 |
+
<table id="ThumbsTable" class="wp-list-table widefat fixed media"
|
184 |
+
cellpadding="0" cellspacing="0">
|
185 |
+
<thead>
|
186 |
+
<?php printf( $thead, 1 ); ?>
|
187 |
+
</thead>
|
188 |
+
<tfoot>
|
189 |
+
<?php printf( $thead, 2 ); ?>
|
190 |
+
</tfoot>
|
191 |
+
<tbody><?php
|
192 |
+
foreach ( $thumbs as $tid => $thumb ) {
|
193 |
+
$icon = $thumb['icon'];
|
194 |
+
$title = $thumb['title'];
|
195 |
+
$ext = $thumb['ext'];
|
196 |
+
$description = $thumb['description'];
|
197 |
+
$date = DocumentGallery::localDateTimeFromTimestamp( $thumb['timestamp'] );
|
198 |
+
?>
|
199 |
+
<tr data-entry="<?php echo $tid; ?>">
|
200 |
+
<td scope="row" class="check-column">
|
201 |
+
<input
|
202 |
+
type="checkbox"
|
203 |
+
class="cb-ids"
|
204 |
+
name="<?php echo DG_OPTION_NAME; ?>[ids][]"
|
205 |
+
value="<?php echo $tid; ?>">
|
206 |
+
</td>
|
207 |
+
<td class="column-icon media-icon"><img src="<?php echo $icon; ?>" /></td>
|
208 |
+
<td class="title column-title">
|
209 |
+
<strong>
|
210 |
+
<a
|
211 |
+
href="<?php echo home_url( '/?attachment_id=' . $tid ); ?>"
|
212 |
+
target="_blank"
|
213 |
+
title="<?php sprintf( __( "View '%s' attachment page", 'document-gallery' ), $title ); ?>">
|
214 |
+
<span class="editable-title"><?php echo $title; ?></span>
|
215 |
+
<sup><?php echo $ext; ?></sup>
|
216 |
+
</a>
|
217 |
+
</strong>
|
218 |
+
<span class="dashicons dashicons-edit"></span>
|
219 |
+
<span class="edit-controls">
|
220 |
+
<span class="dashicons dashicons-yes"></span>
|
221 |
+
<span class="dashicons dashicons-no"></span>
|
222 |
+
</span>
|
223 |
+
</td>
|
224 |
+
<td class="column-description">
|
225 |
+
<div class="editable-description"><?php echo $description; ?></div>
|
226 |
+
<span class="dashicons dashicons-edit"></span>
|
227 |
+
<span class="edit-controls">
|
228 |
+
<span class="dashicons dashicons-yes"></span>
|
229 |
+
<span class="dashicons dashicons-no"></span>
|
230 |
+
<span class="dashicons dashicons-update"></span>
|
231 |
+
</span>
|
232 |
+
</td>
|
233 |
+
<td class="column-thumbupload">
|
234 |
+
<span class="manual-download">
|
235 |
+
<span class="dashicons dashicons-upload"></span>
|
236 |
+
<span class="html5dndmarker">Drop file here<span> or </span></span>
|
237 |
+
<span class="buttons-area">
|
238 |
+
<input id="upload-button<?php echo $tid; ?>" type="file" />
|
239 |
+
<input id="trigger-button<?php echo $tid; ?>" type="button" value="Select File" class="button" />
|
240 |
+
</span>
|
241 |
+
</span>
|
242 |
+
<div class="progress animate invis">
|
243 |
+
<span><span></span></span>
|
244 |
+
</div>
|
245 |
+
</td>
|
246 |
+
<td class="date column-date"><?php echo $date; ?></td>
|
247 |
+
</tr>
|
248 |
+
<?php
|
249 |
+
} ?>
|
250 |
+
</tbody>
|
251 |
+
</table>
|
252 |
+
<div class="tablenav bottom"><?php echo $pagination; ?></div>
|
253 |
+
</div>
|
254 |
+
</div>
|
255 |
+
<?php }
|
256 |
+
|
257 |
+
/**
|
258 |
+
* @param $t1 DG_Thumb Thumbnail #1.
|
259 |
+
* @param $t2 DG_Thumb Thumbnail #2
|
260 |
+
*
|
261 |
+
* @return int The result of comparing the two thumbs using arguments in $URL_params.
|
262 |
+
*/
|
263 |
+
function dg_cmp_thumb($t1, $t2) {
|
264 |
+
global $dg_url_params;
|
265 |
+
$ret = 0;
|
266 |
+
switch ( $dg_url_params['orderby'] ) {
|
267 |
+
case 'date':
|
268 |
+
$ret = $t1->getTimestamp() - $t2->getTimestamp();
|
269 |
+
break;
|
270 |
+
|
271 |
+
case 'title':
|
272 |
+
$ret = strcmp( dg_get_thumb_title( $t1->getPostId() ), dg_get_thumb_title( $t2->getPostId() ) );
|
273 |
+
break;
|
274 |
+
}
|
275 |
+
|
276 |
+
return 'asc' === $dg_url_params['order'] ? $ret : -$ret;
|
277 |
+
}
|
278 |
+
|
279 |
+
/**
|
280 |
+
* @return int The limit, which may or may not be a member of $limit_options.
|
281 |
+
*/
|
282 |
+
function dg_get_limit_param() {
|
283 |
+
global $dg_options;
|
284 |
+
$limit = isset( $_REQUEST['limit'] ) ? DG_Util::posint( $_REQUEST['limit'] ) : $dg_options['meta']['items_per_page'];
|
285 |
+
if ( $limit !== $dg_options['meta']['items_per_page'] ) {
|
286 |
+
$dg_options['meta']['items_per_page'] = $limit;
|
287 |
+
DocumentGallery::setOptions( $dg_options );
|
288 |
+
}
|
289 |
+
|
290 |
+
return $limit;
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* @param $order_options string[] The possible options for order.
|
295 |
+
* @return string The order value.
|
296 |
+
*/
|
297 |
+
function dg_get_order_param($order_options) {
|
298 |
+
$ret = isset( $_REQUEST['order'] ) ? strtolower( $_REQUEST['order'] ) : '';
|
299 |
+
return in_array($ret, $order_options) ? $ret : $order_options[0];
|
300 |
+
}
|
301 |
+
|
302 |
+
/**
|
303 |
+
* @param $orderby_options string[] The possible options for orderby.
|
304 |
+
* @return string The orderby value.
|
305 |
+
*/
|
306 |
+
function dg_get_orderby_param($orderby_options) {
|
307 |
+
$ret = isset( $_REQUEST['orderby'] ) ? strtolower( $_REQUEST['orderby'] ) : '';
|
308 |
+
return in_array( $ret, $orderby_options ) ? $ret : $orderby_options[0];
|
309 |
+
}
|
310 |
+
|
311 |
+
/**
|
312 |
+
* @param $post int|WP_Post The post to get title of.
|
313 |
+
* @return string The title.
|
314 |
+
*/
|
315 |
+
function dg_get_thumb_title( $post ) {
|
316 |
+
if ( is_numeric( $post ) ) {
|
317 |
+
$post = get_post( $post );
|
318 |
+
}
|
319 |
+
|
320 |
+
return ! empty( $post->post_title ) ? $post->post_title : pathinfo( $post->guid, PATHINFO_FILENAME );
|
321 |
+
}
|
322 |
+
|
323 |
+
/**
|
324 |
+
* Wraps the PHP exit language construct.
|
325 |
+
*/
|
326 |
+
function dg_exit() {
|
327 |
+
exit;
|
328 |
+
}
|
assets/css/admin.css
CHANGED
@@ -147,19 +147,23 @@ tr.selected:hover {
|
|
147 |
padding-right: 5px;
|
148 |
}
|
149 |
|
150 |
-
|
151 |
content: '\f108';
|
152 |
}
|
153 |
|
154 |
-
|
|
|
|
|
|
|
|
|
155 |
content: '\f233';
|
156 |
}
|
157 |
|
158 |
-
|
159 |
content: '\f163';
|
160 |
}
|
161 |
|
162 |
-
|
163 |
content: '\f332';
|
164 |
}
|
165 |
|
147 |
padding-right: 5px;
|
148 |
}
|
149 |
|
150 |
+
#general-tab-header:before {
|
151 |
content: '\f108';
|
152 |
}
|
153 |
|
154 |
+
#thumber-co-tab-header:before {
|
155 |
+
content: '\f529';
|
156 |
+
}
|
157 |
+
|
158 |
+
#thumbnail-management-tab-header:before {
|
159 |
content: '\f233';
|
160 |
}
|
161 |
|
162 |
+
#logging-tab-header:before {
|
163 |
content: '\f163';
|
164 |
}
|
165 |
|
166 |
+
#advanced-tab-header:before {
|
167 |
content: '\f332';
|
168 |
}
|
169 |
|
assets/css/admin.min.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
@media screen and (max-width:782px){.column-title{width:150px}.column-date{display:table-cell !important;width:auto !important}.nav-tab-wrapper{padding-left:5px !important;padding-right:5px !important}.top .tablenav-pages{display:none}.bottom .tablenav-pages{width:auto !important;margin-top:0 !important}.bottom .displaying-num{position:inherit !important}}@media screen and (max-width:979px){.column-thumbupload{display:none}.thumbs-list-wrapper{margin-top:0 !important}}div.thumbs-list-wrapper,div.log-list-wrapper{text-align:center;margin-top:1.5em}div.thumbs-list-wrapper>div,div.log-list-wrapper>div{margin:0 auto;display:inline-block}#ThumbsTable,#LogTable{border:0;box-shadow:none;-webkit-box-shadow:none;-moz-box-shadow:none;border-radius:10px;-webkit-border-radius:10px;-moz-border-radius:10px;background:#b9c9fe;color:#039;width:100%;margin:10px auto}#ThumbsTable tbody,#LogTable tbody{background:#e8edff;color:#669}#ThumbsTable>tbody>tr:hover,#LogTable>tbody>tr:hover{background:#d0dafd}#ThumbsTable>tbody>tr:not(:last-child) td,#LogTable>tbody>tr:not(:last-child) td{border-bottom:1px solid #b9c9fe}#ThumbsTable td,#ThumbsTable th,#LogTable td,#LogTable th{text-align:center;vertical-align:middle;margin:0;padding:4px}#LogTable td{text-align:left}td.title.column-title,.column-thumbupload{text-align:left !important}td.column-icon.media-icon{height:70px}td.media-icon img{width:auto;height:auto;max-width:80px;max-height:60px;border:0}#ThumbsTable img{display:block;margin:5px auto}#LogTable td>pre,.spoiler-body>pre,.expander pre,.collapser pre{margin:0;display:inline-block;white-space:pre-line}tr.selected{background:#b6adce}tr.selected:hover{background:#d8d3e5 !important}.check-column,.column-icon{white-space:nowrap;width:80px}.column-thumbupload{white-space:nowrap;width:35%}#document_gallery_gen_box .column-thumbupload{width:auto;padding-left:7em}.nav-tab:before,.deleteSelected:before,.clearLog:before,.expandAll:before,.collapseAll:before,.logLabel.date:before,.collapser:after,.expander:after{display:inline-block;-webkit-font-smoothing:antialiased;font:normal 20px/1 'dashicons';vertical-align:text-bottom;padding-right:5px}.General-tab:before{content:'\f108'}.Thumbnail-tab:before{content:'\f233'}.Logging-tab:before{content:'\f163'}.Advanced-tab:before{content:'\f332'}.deleteSelected:before,.clearLog:before{content:'\f182'}.expandAll:before{content:'\f211'}.collapseAll:before{content:'\f506'}.expandAll,.collapseAll{display:none}#ThumbsTable .title a:after,#LogTable>tbody a:after{content:'\f504';display:inline-block;-webkit-font-smoothing:antialiased;font-family:'dashicons';font-size:inherit;font-style:normal;font-variant:normal;font-weight:normal;line-height:1;vertical-align:inherit;padding-left:5px}#LogTable>tbody a{-webkit-transition:none;transition:none;text-decoration:none;outline:0}#LogTable>tbody pre strong{font-weight:bolder}#LogTable>tbody a:active,#LogTable>tbody a:hover{color:#2ea2cc}.levelSelector{float:right}.logLabel{padding:0 10px;color:#fff !important;text-decoration:none;font-weight:bolder;border:none !important;float:left;margin-left:1px;margin-top:1px;-webkit-border-radius:100px;-moz-border-radius:100px;border-radius:100px;cursor:context-menu}.logLabel.warning{background:#f89406}.logLabel.detail{background:#3a87ad}.logLabel.error{background:#c00}.logLabel.date{background:#999;font-weight:inherit}.logLabel.date:before{font-size:inherit;vertical-align:middle;padding-bottom:.2em;content:'\f469'}.spoiler-body{padding:1px 6px 2px;display:none;border-top:1px solid #c3cbd1;background:#f5f5f5}.column-entry{text-align:left !important}.expander pre,.collapser pre{vertical-align:middle;float:left;white-space:pre-wrap}.expander,.collapser{display:table;vertical-align:middle;width:100%;cursor:pointer}.expander>div,.collapser>div{display:table-cell;vertical-align:middle;height:100%}.dashicons.dashicons-arrow-down-alt2,.dashicons.dashicons-arrow-up-alt2{float:right;padding-right:15px}.levelSelector>*,.dashicons{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.levelSelector>input[type=checkbox]{display:none}.levelSelector>input[type=checkbox]+label{color:#6b6b6b;font-weight:bolder;margin:4px 0;overflow:auto;text-align:center;padding:3px 8px;display:table-cell;background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#FFF,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#FFF),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#FFF,#e6e6e6);background-image:-o-linear-gradient(top,#FFF,#e6e6e6);background-image:linear-gradient(to bottom,#FFF,#e6e6e6);background-repeat:repeat-x;border:1px solid #CCC;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF',endColorstr='#FFE6E6E6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.levelSelector>input[type=checkbox]+label:first-of-type{border-top-left-radius:4px;border-bottom-left-radius:4px}.levelSelector>input[type=checkbox]+label:last-of-type{border-top-right-radius:4px;border-bottom-right-radius:4px}.levelSelector>input[type=checkbox]:checked+label{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.levelSelector>input[type=checkbox]+label.errorLevel{color:#c00}.levelSelector>input[type=checkbox]:checked+label.errorLevel{background-color:#c00;color:#FFF}.levelSelector>input[type=checkbox]+label.warningLevel{color:#f89406}.levelSelector>input[type=checkbox]:checked+label.warningLevel{background-color:#f89406;color:#FFF}.levelSelector>input[type=checkbox]+label.detailLevel{color:#3a87ad}.levelSelector>input[type=checkbox]:checked+label.detailLevel{background-color:#3a87ad;color:#FFF}.noLog{font-size:x-large;display:block;width:100%;text-align:center;margin-top:20ex;line-height:150%}.loggingON,.loggingOFF{font-weight:bolder}.loggingON{color:green}.loggingOFF{color:red}th input{margin-left:0 !important;margin-top:1px !important}td input{margin-right:0 !important}textarea[readonly],input[readonly],select[readonly]{background-color:#dcdcdc}.nowrap{white-space:nowrap}.column-level{white-space:nowrap;width:6em}.column-date{width:16em !important}.column-thumbupload{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.column-thumbupload>*{visibility:hidden}.column-thumbupload .dashicons{font-size:x-large;padding-top:2px;padding-left:16px;padding-right:10px;vertical-align:text-bottom}#ThumbsTable tr:hover .column-thumbupload>*,#document_gallery_gen_box #ThumbsTable tr .column-thumbupload>*{visibility:visible}.dragover{outline:3px dashed #83b4d8}.html5dndmarker span{padding:0 10px}.buttons-area input:first-child,.invis{display:none !important}#document_gallery_gen_box h3 span{font-weight:100}#document_gallery_gen_box h3 span i b{font-weight:500}th.column-description{text-align:left !important}.editable-description{max-height:70px;overflow-y:auto;text-align:justify}.column-description textarea{height:65px;width:100%}td.column-title,td.column-description{position:relative}td.column-title.trans,td.column-description.trans{background-color:inherit;transition:background-color 1s linear;-o-transition:background-color 1s linear;-moz-transition:background-color 1s linear;-webkit-transition:background-color 1s linear}td .dashicons-edit,td .edit-controls{display:none;position:absolute;top:5px;right:12px}td .dashicons-edit,.edit-controls .dashicons-yes,.edit-controls .dashicons-no,.edit-controls .dashicons-update{z-index:100;font-size:x-large;cursor:pointer;width:auto;height:auto}td .dashicons-edit,.edit-controls .dashicons-update{color:#0074a2}.edit-controls:hover,.edit-controls.waiting{opacity:1}.edit-controls{opacity:.1}.edit-controls .dashicons-yes{color:green}.edit-controls .dashicons-no{color:red}.edit-controls.waiting .dashicons-yes,.edit-controls.waiting .dashicons-no{display:none}.edit-controls .dashicons-update{display:none;cursor:default}.edit-controls.waiting .dashicons-update,.deleteSelected.waiting:before{display:block;-webkit-animation:spin 1s linear infinite;-moz-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.deleteSelected.waiting:before{content:'\f463';width:auto;height:auto;display:inline-block;padding:0}@-moz-keyframes spin{100%{-moz-transform:rotate(360deg)}}@-webkit-keyframes spin{100%{-webkit-transform:rotate(360deg)}}@keyframes spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.responseSuccess{background-color:greenyellow !important}.responseFail{background-color:crimson !important}td.column-title .dashicons-edit,td.column-description .dashicons-edit{height:0;opacity:0;display:block;overflow:hidden;transition:opacity 1s ease-out;-o-transition:opacity 1s ease-out;-moz-transition:opacity 1s ease-out;-webkit-transition:opacity 1s ease-out}td.column-title:hover .dashicons-edit,td.column-description:hover .dashicons-edit{opacity:1;height:auto}td.column-title input{width:75%}.manual-download{display:block;text-align:center}.editable-description::-webkit-scrollbar,.column-description textarea::-webkit-scrollbar{width:5px;height:5px}.editable-description::-webkit-scrollbar-track-piece,.column-description textarea::-webkit-scrollbar-track-piece{background-color:#fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.editable-description::-webkit-scrollbar-thumb:vertical,.column-description textarea::-webkit-scrollbar-thumb:vertical{height:5px;background-color:#9b9b9b;-webkit-border-radius:5px}.dg-settings label.setting{margin:2px 0}.dg-settings label.setting table{width:100%;padding-right:8px}.dg-settings label.setting table tr td:last-of-type,.dg-settings label.setting table tr td:last-of-type *{text-align:right !important;float:none !important;margin:auto 0 !important}.dg-settings label.setting table tr td:last-of-type select{max-width:none !important}.dg-settings label.setting table tr td span{text-align:left !important;float:none !important}.progress{border:0;width:100%;height:18px;position:relative;background-color:#f1f1f1;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;-webkit-box-shadow:inset 0 -1px 1px rgba(255,255,255,0.3);-moz-box-shadow:inset 0 -1px 1px rgba(255,255,255,0.3);box-shadow:inset 0 -1px 1px rgba(255,255,255,0.3)}.column-thumbupload .progress{visibility:visible !important}.progress>span{border:0;height:100%;display:block;overflow:hidden;position:relative;-webkit-transition:width .5s linear;-moz-transition:width .5s linear;-o-transition:width .5s linear;transition:width .5s linear;background-color:#7ad03a;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;background-image:linear-gradient(90deg,#2bc253 37%,#54f054 69%);background-image:-moz-linear-gradient(90deg,#2bc253 37%,#54f054 69%);background-image:-o-linear-gradient(90deg,#2bc253 37%,#54f054 69%);background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0,#2bc253),color-stop(1,#54f054));-webkit-box-shadow:inset 0 2px 9px rgba(255,255,255,0.3),inset 0 -2px 6px rgba(0,0,0,0.4);-moz-box-shadow:inset 0 2px 9px rgba(255,255,255,0.3),inset 0 -2px 6px rgba(0,0,0,0.4);box-shadow:inset 0 2px 9px rgba(255,255,255,0.3),inset 0 -2px 6px rgba(0,0,0,0.4)}.progress>span:after,.progress.animate>span>span{top:0;left:0;right:0;bottom:0;z-index:1;content:'';overflow:hidden;position:absolute;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;background-image:-webkit-gradient(linear,0 0,100% 100%,color-stop(.25,rgba(255,255,255,.2)),color-stop(.25,transparent),color-stop(.5,transparent),color-stop(.5,rgba(255,255,255,.2)),color-stop(.75,rgba(255,255,255,.2)),color-stop(.75,transparent),to(transparent));background-image:-moz-linear-gradient(315deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(315deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);background-image:linear-gradient(315deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);-webkit-background-size:50px 50px;-moz-background-size:50px 50px;background-size:50px 50px;-webkit-animation:move 2s linear infinite;-moz-animation:move 2s linear infinite;-ms-animation:move 2s linear infinite;animation:move 2s linear infinite}@-webkit-keyframes move{0{background-position:0 0}100%{background-position:50px 50px}}@-moz-keyframes move{0{background-position:0 0}100%{background-position:50px 50px}}@-ms-keyframes move{0{background-position:0 0}100%{background-position:50px 50px}}@keyframes move{0{background-position:0 0}100%{background-position:50px 50px}}.progress.animate>span:after{display:none}.progress.success>span{background-color:green;width:100% !important;background-image:none !important}.progress.fail>span{background-color:red;background-image:none !important}.progress.nostripes>span>span,.progress.nostripes>span:after,.progress.success>span>span,.progress.success>span:after,.progress.fail>span>span,.progress.fail>span:after{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none;background-image:none}
|
1 |
+
@media screen and (max-width:782px){.column-title{width:150px}.column-date{display:table-cell !important;width:auto !important}.nav-tab-wrapper{padding-left:5px !important;padding-right:5px !important}.top .tablenav-pages{display:none}.bottom .tablenav-pages{width:auto !important;margin-top:0 !important}.bottom .displaying-num{position:inherit !important}}@media screen and (max-width:979px){.column-thumbupload{display:none}.thumbs-list-wrapper{margin-top:0 !important}}div.thumbs-list-wrapper,div.log-list-wrapper{text-align:center;margin-top:1.5em}div.thumbs-list-wrapper>div,div.log-list-wrapper>div{margin:0 auto;display:inline-block}#ThumbsTable,#LogTable{border:0;box-shadow:none;-webkit-box-shadow:none;-moz-box-shadow:none;border-radius:10px;-webkit-border-radius:10px;-moz-border-radius:10px;background:#b9c9fe;color:#039;width:100%;margin:10px auto}#ThumbsTable tbody,#LogTable tbody{background:#e8edff;color:#669}#ThumbsTable>tbody>tr:hover,#LogTable>tbody>tr:hover{background:#d0dafd}#ThumbsTable>tbody>tr:not(:last-child) td,#LogTable>tbody>tr:not(:last-child) td{border-bottom:1px solid #b9c9fe}#ThumbsTable td,#ThumbsTable th,#LogTable td,#LogTable th{text-align:center;vertical-align:middle;margin:0;padding:4px}#LogTable td{text-align:left}td.title.column-title,.column-thumbupload{text-align:left !important}td.column-icon.media-icon{height:70px}td.media-icon img{width:auto;height:auto;max-width:80px;max-height:60px;border:0}#ThumbsTable img{display:block;margin:5px auto}#LogTable td>pre,.spoiler-body>pre,.expander pre,.collapser pre{margin:0;display:inline-block;white-space:pre-line}tr.selected{background:#b6adce}tr.selected:hover{background:#d8d3e5 !important}.check-column,.column-icon{white-space:nowrap;width:80px}.column-thumbupload{white-space:nowrap;width:35%}#document_gallery_gen_box .column-thumbupload{width:auto;padding-left:7em}.nav-tab:before,.deleteSelected:before,.clearLog:before,.expandAll:before,.collapseAll:before,.logLabel.date:before,.collapser:after,.expander:after{display:inline-block;-webkit-font-smoothing:antialiased;font:normal 20px/1 'dashicons';vertical-align:text-bottom;padding-right:5px}#general-tab-header:before{content:'\f108'}#thumber-co-tab-header:before{content:'\f529'}#thumbnail-management-tab-header:before{content:'\f233'}#logging-tab-header:before{content:'\f163'}#advanced-tab-header:before{content:'\f332'}.deleteSelected:before,.clearLog:before{content:'\f182'}.expandAll:before{content:'\f211'}.collapseAll:before{content:'\f506'}.expandAll,.collapseAll{display:none}#ThumbsTable .title a:after,#LogTable>tbody a:after{content:'\f504';display:inline-block;-webkit-font-smoothing:antialiased;font-family:'dashicons';font-size:inherit;font-style:normal;font-variant:normal;font-weight:normal;line-height:1;vertical-align:inherit;padding-left:5px}#LogTable>tbody a{-webkit-transition:none;transition:none;text-decoration:none;outline:0}#LogTable>tbody pre strong{font-weight:bolder}#LogTable>tbody a:active,#LogTable>tbody a:hover{color:#2ea2cc}.levelSelector{float:right}.logLabel{padding:0 10px;color:#fff !important;text-decoration:none;font-weight:bolder;border:none !important;float:left;margin-left:1px;margin-top:1px;-webkit-border-radius:100px;-moz-border-radius:100px;border-radius:100px;cursor:context-menu}.logLabel.warning{background:#f89406}.logLabel.detail{background:#3a87ad}.logLabel.error{background:#c00}.logLabel.date{background:#999;font-weight:inherit}.logLabel.date:before{font-size:inherit;vertical-align:middle;padding-bottom:.2em;content:'\f469'}.spoiler-body{padding:1px 6px 2px;display:none;border-top:1px solid #c3cbd1;background:#f5f5f5}.column-entry{text-align:left !important}.expander pre,.collapser pre{vertical-align:middle;float:left;white-space:pre-wrap}.expander,.collapser{display:table;vertical-align:middle;width:100%;cursor:pointer}.expander>div,.collapser>div{display:table-cell;vertical-align:middle;height:100%}.dashicons.dashicons-arrow-down-alt2,.dashicons.dashicons-arrow-up-alt2{float:right;padding-right:15px}.levelSelector>*,.dashicons{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.levelSelector>input[type=checkbox]{display:none}.levelSelector>input[type=checkbox]+label{color:#6b6b6b;font-weight:bolder;margin:4px 0;overflow:auto;text-align:center;padding:3px 8px;display:table-cell;background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#FFF,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#FFF),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#FFF,#e6e6e6);background-image:-o-linear-gradient(top,#FFF,#e6e6e6);background-image:linear-gradient(to bottom,#FFF,#e6e6e6);background-repeat:repeat-x;border:1px solid #CCC;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF',endColorstr='#FFE6E6E6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.levelSelector>input[type=checkbox]+label:first-of-type{border-top-left-radius:4px;border-bottom-left-radius:4px}.levelSelector>input[type=checkbox]+label:last-of-type{border-top-right-radius:4px;border-bottom-right-radius:4px}.levelSelector>input[type=checkbox]:checked+label{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.levelSelector>input[type=checkbox]+label.errorLevel{color:#c00}.levelSelector>input[type=checkbox]:checked+label.errorLevel{background-color:#c00;color:#FFF}.levelSelector>input[type=checkbox]+label.warningLevel{color:#f89406}.levelSelector>input[type=checkbox]:checked+label.warningLevel{background-color:#f89406;color:#FFF}.levelSelector>input[type=checkbox]+label.detailLevel{color:#3a87ad}.levelSelector>input[type=checkbox]:checked+label.detailLevel{background-color:#3a87ad;color:#FFF}.noLog{font-size:x-large;display:block;width:100%;text-align:center;margin-top:20ex;line-height:150%}.loggingON,.loggingOFF{font-weight:bolder}.loggingON{color:green}.loggingOFF{color:red}th input{margin-left:0 !important;margin-top:1px !important}td input{margin-right:0 !important}textarea[readonly],input[readonly],select[readonly]{background-color:#dcdcdc}.nowrap{white-space:nowrap}.column-level{white-space:nowrap;width:6em}.column-date{width:16em !important}.column-thumbupload{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.column-thumbupload>*{visibility:hidden}.column-thumbupload .dashicons{font-size:x-large;padding-top:2px;padding-left:16px;padding-right:10px;vertical-align:text-bottom}#ThumbsTable tr:hover .column-thumbupload>*,#document_gallery_gen_box #ThumbsTable tr .column-thumbupload>*{visibility:visible}.dragover{outline:3px dashed #83b4d8}.html5dndmarker span{padding:0 10px}.buttons-area input:first-child,.invis{display:none !important}#document_gallery_gen_box h3 span{font-weight:100}#document_gallery_gen_box h3 span i b{font-weight:500}th.column-description{text-align:left !important}.editable-description{max-height:70px;overflow-y:auto;text-align:justify}.column-description textarea{height:65px;width:100%}td.column-title,td.column-description{position:relative}td.column-title.trans,td.column-description.trans{background-color:inherit;transition:background-color 1s linear;-o-transition:background-color 1s linear;-moz-transition:background-color 1s linear;-webkit-transition:background-color 1s linear}td .dashicons-edit,td .edit-controls{display:none;position:absolute;top:5px;right:12px}td .dashicons-edit,.edit-controls .dashicons-yes,.edit-controls .dashicons-no,.edit-controls .dashicons-update{z-index:100;font-size:x-large;cursor:pointer;width:auto;height:auto}td .dashicons-edit,.edit-controls .dashicons-update{color:#0074a2}.edit-controls:hover,.edit-controls.waiting{opacity:1}.edit-controls{opacity:.1}.edit-controls .dashicons-yes{color:green}.edit-controls .dashicons-no{color:red}.edit-controls.waiting .dashicons-yes,.edit-controls.waiting .dashicons-no{display:none}.edit-controls .dashicons-update{display:none;cursor:default}.edit-controls.waiting .dashicons-update,.deleteSelected.waiting:before{display:block;-webkit-animation:spin 1s linear infinite;-moz-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.deleteSelected.waiting:before{content:'\f463';width:auto;height:auto;display:inline-block;padding:0}@-moz-keyframes spin{100%{-moz-transform:rotate(360deg)}}@-webkit-keyframes spin{100%{-webkit-transform:rotate(360deg)}}@keyframes spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.responseSuccess{background-color:greenyellow !important}.responseFail{background-color:crimson !important}td.column-title .dashicons-edit,td.column-description .dashicons-edit{height:0;opacity:0;display:block;overflow:hidden;transition:opacity 1s ease-out;-o-transition:opacity 1s ease-out;-moz-transition:opacity 1s ease-out;-webkit-transition:opacity 1s ease-out}td.column-title:hover .dashicons-edit,td.column-description:hover .dashicons-edit{opacity:1;height:auto}td.column-title input{width:75%}.manual-download{display:block;text-align:center}.editable-description::-webkit-scrollbar,.column-description textarea::-webkit-scrollbar{width:5px;height:5px}.editable-description::-webkit-scrollbar-track-piece,.column-description textarea::-webkit-scrollbar-track-piece{background-color:#fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.editable-description::-webkit-scrollbar-thumb:vertical,.column-description textarea::-webkit-scrollbar-thumb:vertical{height:5px;background-color:#9b9b9b;-webkit-border-radius:5px}.dg-settings label.setting{margin:2px 0}.dg-settings label.setting table{width:100%;padding-right:8px}.dg-settings label.setting table tr td:last-of-type,.dg-settings label.setting table tr td:last-of-type *{text-align:right !important;float:none !important;margin:auto 0 !important}.dg-settings label.setting table tr td:last-of-type select{max-width:none !important}.dg-settings label.setting table tr td span{text-align:left !important;float:none !important}.progress{border:0;width:100%;height:18px;position:relative;background-color:#f1f1f1;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;-webkit-box-shadow:inset 0 -1px 1px rgba(255,255,255,0.3);-moz-box-shadow:inset 0 -1px 1px rgba(255,255,255,0.3);box-shadow:inset 0 -1px 1px rgba(255,255,255,0.3)}.column-thumbupload .progress{visibility:visible !important}.progress>span{border:0;height:100%;display:block;overflow:hidden;position:relative;-webkit-transition:width .5s linear;-moz-transition:width .5s linear;-o-transition:width .5s linear;transition:width .5s linear;background-color:#7ad03a;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;background-image:linear-gradient(90deg,#2bc253 37%,#54f054 69%);background-image:-moz-linear-gradient(90deg,#2bc253 37%,#54f054 69%);background-image:-o-linear-gradient(90deg,#2bc253 37%,#54f054 69%);background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0,#2bc253),color-stop(1,#54f054));-webkit-box-shadow:inset 0 2px 9px rgba(255,255,255,0.3),inset 0 -2px 6px rgba(0,0,0,0.4);-moz-box-shadow:inset 0 2px 9px rgba(255,255,255,0.3),inset 0 -2px 6px rgba(0,0,0,0.4);box-shadow:inset 0 2px 9px rgba(255,255,255,0.3),inset 0 -2px 6px rgba(0,0,0,0.4)}.progress>span:after,.progress.animate>span>span{top:0;left:0;right:0;bottom:0;z-index:1;content:'';overflow:hidden;position:absolute;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;background-image:-webkit-gradient(linear,0 0,100% 100%,color-stop(.25,rgba(255,255,255,.2)),color-stop(.25,transparent),color-stop(.5,transparent),color-stop(.5,rgba(255,255,255,.2)),color-stop(.75,rgba(255,255,255,.2)),color-stop(.75,transparent),to(transparent));background-image:-moz-linear-gradient(315deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(315deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);background-image:linear-gradient(315deg,rgba(255,255,255,.2) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.2) 50%,rgba(255,255,255,.2) 75%,transparent 75%,transparent);-webkit-background-size:50px 50px;-moz-background-size:50px 50px;background-size:50px 50px;-webkit-animation:move 2s linear infinite;-moz-animation:move 2s linear infinite;-ms-animation:move 2s linear infinite;animation:move 2s linear infinite}@-webkit-keyframes move{0{background-position:0 0}100%{background-position:50px 50px}}@-moz-keyframes move{0{background-position:0 0}100%{background-position:50px 50px}}@-ms-keyframes move{0{background-position:0 0}100%{background-position:50px 50px}}@keyframes move{0{background-position:0 0}100%{background-position:50px 50px}}.progress.animate>span:after{display:none}.progress.success>span{background-color:green;width:100% !important;background-image:none !important}.progress.fail>span{background-color:red;background-image:none !important}.progress.nostripes>span>span,.progress.nostripes>span:after,.progress.success>span>span,.progress.success>span:after,.progress.fail>span>span,.progress.fail>span:after{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none;background-image:none}
|
assets/css/style.css
CHANGED
@@ -23,6 +23,10 @@
|
|
23 |
text-align: center;
|
24 |
}
|
25 |
|
|
|
|
|
|
|
|
|
26 |
/* WITHOUT DESCRIPTION */
|
27 |
.document-gallery .document-icon {
|
28 |
display: inline-block;
|
23 |
text-align: center;
|
24 |
}
|
25 |
|
26 |
+
.dg-paginate-wrapper .paginate {
|
27 |
+
text-align: center;
|
28 |
+
}
|
29 |
+
|
30 |
/* WITHOUT DESCRIPTION */
|
31 |
.document-gallery .document-icon {
|
32 |
display: inline-block;
|
assets/css/style.min.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
.document-gallery .document-icon{text-align:center}.document-gallery .document-icon img{width:89px;max-width:100%;border:0;margin:0 auto}.document-gallery .document-icon a{font-size:10px;line-height:12px}.document-gallery .document-icon{margin:5px 0 0}.document-gallery .document-icon .title{display:block;text-align:center}.document-gallery .document-icon{display:inline-block;vertical-align:top;overflow:hidden}.document-gallery .document-icon-row{width:100%;padding:0;text-align:left}.document-gallery .descriptions.document-icon-row .document-icon{max-width:115px;padding:0 3px 0 0;float:left}.document-gallery .descriptions.document-icon-row{vertical-align:middle;text-align:inherit}.document-gallery .descriptions.document-icon-row img{width:65px;max-width:100%}.document-gallery .descriptions.document-icon-row:before,.document-gallery .descriptions.document-icon-row:after{content:"";display:table}.document-gallery .descriptions.document-icon-row:after{clear:both}.document-gallery .descriptions.document-icon-row{zoom:1}
|
1 |
+
.document-gallery .document-icon{text-align:center}.document-gallery .document-icon img{width:89px;max-width:100%;border:0;margin:0 auto}.document-gallery .document-icon a{font-size:10px;line-height:12px}.document-gallery .document-icon{margin:5px 0 0}.document-gallery .document-icon .title{display:block;text-align:center}.dg-paginate-wrapper .paginate{text-align:center}.document-gallery .document-icon{display:inline-block;vertical-align:top;overflow:hidden}.document-gallery .document-icon-row{width:100%;padding:0;text-align:left}.document-gallery .descriptions.document-icon-row .document-icon{max-width:115px;padding:0 3px 0 0;float:left}.document-gallery .descriptions.document-icon-row{vertical-align:middle;text-align:inherit}.document-gallery .descriptions.document-icon-row img{width:65px;max-width:100%}.document-gallery .descriptions.document-icon-row:before,.document-gallery .descriptions.document-icon-row:after{content:"";display:table}.document-gallery .descriptions.document-icon-row:after{clear:both}.document-gallery .descriptions.document-icon-row{zoom:1}
|
assets/js/admin.js
CHANGED
@@ -25,7 +25,7 @@ jQuery(document).ready(function () {
|
|
25 |
jQuery('select.limit_per_page').change(function () {
|
26 |
jQuery(location).attr('href', '?' + jQuery.param(jQuery.extend(URL_params, {limit: this.value})));
|
27 |
});
|
28 |
-
jQuery('#tab
|
29 |
event.preventDefault();
|
30 |
if (jQuery('.cb-ids:checked').length > 0) {
|
31 |
var a = jQuery(this).attr('action');
|
@@ -53,7 +53,7 @@ jQuery(document).ready(function () {
|
|
53 |
return false;
|
54 |
});
|
55 |
|
56 |
-
jQuery('#tab
|
57 |
jQuery(this).select();
|
58 |
});
|
59 |
|
@@ -209,11 +209,12 @@ jQuery(document).ready(function () {
|
|
209 |
if (f.type.indexOf('image/') == 0 && typeof dg_admin_vars.upload_limit != 'undefined' && f.size <= parseInt(dg_admin_vars.upload_limit)) {
|
210 |
var target, theRow = jQuery('[data-entry=' + entry + ']');
|
211 |
var formData = new FormData(theRow.closest('form')[0]);
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
} else {
|
216 |
-
target =
|
|
|
217 |
}
|
218 |
formData.append('document_gallery[entry]', entry);
|
219 |
formData.append('document_gallery[ajax]', 'true');
|
@@ -342,7 +343,7 @@ jQuery(document).ready(function () {
|
|
342 |
jQuery('.edit-controls .dashicons-yes').click(function () {
|
343 |
var cell = jQuery(this).closest('td');
|
344 |
var entry = jQuery(this).closest('tr').data('entry');
|
345 |
-
var target = jQuery('#tab
|
346 |
var formData = new FormData(jQuery('[data-entry=' + entry + ']').closest('form')[0]);
|
347 |
formData.append('document_gallery[entry]', entry);
|
348 |
formData.append('document_gallery[ajax]', 'true');
|
25 |
jQuery('select.limit_per_page').change(function () {
|
26 |
jQuery(location).attr('href', '?' + jQuery.param(jQuery.extend(URL_params, {limit: this.value})));
|
27 |
});
|
28 |
+
jQuery('#thumbnail-management-tab').submit(function (event) {
|
29 |
event.preventDefault();
|
30 |
if (jQuery('.cb-ids:checked').length > 0) {
|
31 |
var a = jQuery(this).attr('action');
|
53 |
return false;
|
54 |
});
|
55 |
|
56 |
+
jQuery('#advanced-tab #options-dump').click(function () {
|
57 |
jQuery(this).select();
|
58 |
});
|
59 |
|
209 |
if (f.type.indexOf('image/') == 0 && typeof dg_admin_vars.upload_limit != 'undefined' && f.size <= parseInt(dg_admin_vars.upload_limit)) {
|
210 |
var target, theRow = jQuery('[data-entry=' + entry + ']');
|
211 |
var formData = new FormData(theRow.closest('form')[0]);
|
212 |
+
var thumbMgmtTab = jQuery('#thumbnail-management-tab');
|
213 |
+
if (thumbMgmtTab.length) {
|
214 |
+
target = thumbMgmtTab.attr('action');
|
215 |
} else {
|
216 |
+
target = ajaxurl;
|
217 |
+
formData.append('action', 'dg_upload_thumb');
|
218 |
}
|
219 |
formData.append('document_gallery[entry]', entry);
|
220 |
formData.append('document_gallery[ajax]', 'true');
|
343 |
jQuery('.edit-controls .dashicons-yes').click(function () {
|
344 |
var cell = jQuery(this).closest('td');
|
345 |
var entry = jQuery(this).closest('tr').data('entry');
|
346 |
+
var target = jQuery('#thumbnail-management-tab').attr('action');
|
347 |
var formData = new FormData(jQuery('[data-entry=' + entry + ']').closest('form')[0]);
|
348 |
formData.append('document_gallery[entry]', entry);
|
349 |
formData.append('document_gallery[ajax]', 'true');
|
assets/js/admin.min.js
CHANGED
@@ -1,20 +1,19 @@
|
|
1 |
jQuery(document).ready(function(){function l(a){a=a||event;if(a.dataTransfer.types)for(var b=0;b<a.dataTransfer.types.length;b++)if("Files"==a.dataTransfer.types[b]){a.stopPropagation();a.preventDefault();a.dataTransfer.dropEffect="none";break}}function p(a){a=a||event;if(a.originalEvent.dataTransfer.types)for(var b=0;b<a.originalEvent.dataTransfer.types.length;b++)if("Files"==a.originalEvent.dataTransfer.types[b])return a.stopPropagation(),a.preventDefault(),a.originalEvent.dataTransfer.dropEffect=
|
2 |
-
"move",!1}function q(a){a=a||event;if(a.originalEvent.dataTransfer.types)for(var b=0;b<a.originalEvent.dataTransfer.types.length;b++)if("Files"==a.originalEvent.dataTransfer.types[b]){this.classList.add("dragover");
|
3 |
-
|
4 |
-
a||event;m(a.target.files,jQuery(this).closest("tr").data("entry"))}function m(a,b){for(var
|
5 |
-
|
6 |
-
console.log(
|
7 |
-
|
8 |
-
jQuery("
|
9 |
-
|
10 |
-
|
11 |
-
jQuery(
|
12 |
-
|
13 |
-
|
14 |
-
jQuery(
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
(n(
|
20 |
-
c.send(e)}})});
|
1 |
jQuery(document).ready(function(){function l(a){a=a||event;if(a.dataTransfer.types)for(var b=0;b<a.dataTransfer.types.length;b++)if("Files"==a.dataTransfer.types[b]){a.stopPropagation();a.preventDefault();a.dataTransfer.dropEffect="none";break}}function p(a){a=a||event;if(a.originalEvent.dataTransfer.types)for(var b=0;b<a.originalEvent.dataTransfer.types.length;b++)if("Files"==a.originalEvent.dataTransfer.types[b])return a.stopPropagation(),a.preventDefault(),a.originalEvent.dataTransfer.dropEffect=
|
2 |
+
"move",!1}function q(a){a=a||event;if(a.originalEvent.dataTransfer.types)for(var b=0;b<a.originalEvent.dataTransfer.types.length;b++)if("Files"==a.originalEvent.dataTransfer.types[b]){this.classList.add("dragover");c[jQuery(this).data("entry")]=c[jQuery(this).data("entry")].add(jQuery(a.target));break}}function r(a){a=a||event;if(a.originalEvent.dataTransfer.types)for(var b=0;b<a.originalEvent.dataTransfer.types.length;b++)if("Files"==a.originalEvent.dataTransfer.types[b]){c[jQuery(this).data("entry")]=
|
3 |
+
c[jQuery(this).data("entry")].not(a.target);0===c[jQuery(this).data("entry")].length&&this.classList.remove("dragover");break}}function t(a){a=a||event;if(a.originalEvent.dataTransfer.types)for(var b=0;b<a.originalEvent.dataTransfer.types.length;b++)if("Files"==a.originalEvent.dataTransfer.types[b]){a.stopPropagation();a.preventDefault();m(a.originalEvent.dataTransfer.files,jQuery(this).data("entry"));c[jQuery(this).data("entry")]=jQuery();this.classList.remove("dragover");break}}function u(a){a=
|
4 |
+
a||event;m(a.target.files,jQuery(this).closest("tr").data("entry"))}function m(a,b){for(var g=0,f;f=a[g];g++)if(0==f.type.indexOf("image/")&&"undefined"!=typeof dg_admin_vars.upload_limit&&f.size<=parseInt(dg_admin_vars.upload_limit)){var e,k=jQuery("[data-entry="+b+"]"),g=new FormData(k.closest("form")[0]);e=jQuery("#thumbnail-management-tab");e.length?e=e.attr("action"):(e=ajaxurl,g.append("action","dg_upload_thumb"));g.append("document_gallery[entry]",b);g.append("document_gallery[ajax]","true");
|
5 |
+
g.append("document_gallery[upload]","true");g.append("file",f);var d=new XMLHttpRequest;d.open("POST",e);var c=k.find(".column-icon img"),h=k.find(".progress > *:first");d.onreadystatechange=function(){if(4==d.readyState){if(200==d.status&&-1==d.responseText.indexOf("\n")){jQuery(h).parent().addClass("success");var a=jQuery.parseJSON(d.responseText);a.result&&(a.url===c.attr("src")?c.attr("src",c.attr("src")+"?"+(new Date).getTime()):c.attr("src",a.url))}else jQuery(h).parent().addClass("fail"),console.log("Invalid response from server:"),
|
6 |
+
console.log(d.responseText);setTimeout(function(){k.find(".column-thumbupload > *").toggleClass("invis");jQuery(h).parent().removeClass("success fail")},5E3)}};d.onload=function(){h.width("100%")};d.upload.onprogress=function(a){a.lengthComputable&&h.width((a.loaded/a.total*100|0)+"%")};h.width(0);k.find(".column-thumbupload > *").toggleClass("invis");d.send(g);break}else console.log("Attempt to upload improper file %c"+f.name+":","font-weight:bold;"),0!=f.type.indexOf("image/")&&console.log("\tIs not an image - "+
|
7 |
+
f.type),"undefined"!=typeof dg_admin_vars.upload_limit&&f.size>parseInt(dg_admin_vars.upload_limit)&&console.log("\tIs too big - "+f.size+"b; (Limit is "+dg_admin_vars.upload_limit+"b)")}function n(a){for(var b=4,g=0;6>g;g++)a.animate({"margin-left":"+="+(b=-b)+"px"},50)}jQuery(".cb-ids").change(function(){jQuery(this).is(":checked")?jQuery(this).closest("tr").addClass("selected"):jQuery(this).closest("tr").removeClass("selected")});jQuery("th input:checkbox").change(function(){jQuery(this).is(":checked")?
|
8 |
+
jQuery("#ThumbsTable tbody tr").addClass("selected"):jQuery("#ThumbsTable tbody tr").removeClass("selected")});jQuery("input.current-page").bind("keypress",{},function(a){13==(a.keyCode?a.keyCode:a.which)&&(a.preventDefault(),jQuery(location).attr("href","?"+jQuery.param(jQuery.extend(URL_params,{sheet:this.value}))))});jQuery("select.limit_per_page").change(function(){jQuery(location).attr("href","?"+jQuery.param(jQuery.extend(URL_params,{limit:this.value})))});jQuery("#thumbnail-management-tab").submit(function(a){a.preventDefault();
|
9 |
+
if(0<jQuery(".cb-ids:checked").length){a=jQuery(this).attr("action");var b=jQuery(this).serialize()+"&document_gallery%5Bajax%5D=true&document_gallery%5Bcleanup%5D=true";jQuery(".deleteSelected").addClass("waiting").attr("disabled","disabled");jQuery.post(a,b,function(a){if(a.result){a=a.deleted;for(var b in a)jQuery("input[type=checkbox][value="+a[b]+"]").closest("tr").fadeOut("slow",0,function(){jQuery(this).slideUp("slow",function(){jQuery(this).remove()})})}jQuery(".deleteSelected").removeClass("waiting").removeAttr("disabled")}).fail(function(){console.log("Problem in reaching the server");
|
10 |
+
jQuery(".deleteSelected").removeClass("waiting").removeAttr("disabled")})}return!1});jQuery("#advanced-tab #options-dump").click(function(){jQuery(this).select()});jQuery(".expander").click(function(){getSelection().toString()||(jQuery(this).next().slideToggle("slow"),jQuery(this).find(".dashicons").toggleClass("dashicons-arrow-down-alt2 dashicons-arrow-up-alt2"),jQuery(this).toggleClass("expander collapser"),jQuery(this).attr("title",jQuery(this).hasClass("expander")?"Click to Expand":"Click to Collapse"))});
|
11 |
+
jQuery(".spoiler-body").length&&(jQuery(".expandAll, .collapseAll").addClass("button"),jQuery(".expandAll").click(function(a){a.preventDefault();jQuery(".expander").trigger("click")}),jQuery(".collapseAll").click(function(a){a.preventDefault();jQuery(".collapser").trigger("click")}));jQuery(".levelSelector input").change(function(){"all"==jQuery(this).val()?(jQuery(".levelSelector input").not("[value='all']").prop("checked",jQuery(this).is(":checked")),jQuery(this).is(":checked")?jQuery("#LogTable tbody tr").show():
|
12 |
+
jQuery("#LogTable tbody tr").hide()):(jQuery(this).is(":checked")?jQuery("#LogTable tbody tr:has(span."+jQuery(this).val()+")").show():jQuery("#LogTable tbody tr:has(span."+jQuery(this).val()+")").hide(),jQuery(".levelSelector input:checked").not("[value='all']").length+1==jQuery('.levelSelector input[type="checkbox"]').length?jQuery('.levelSelector input[value="all"]').prop("checked",!0):jQuery('.levelSelector input[value="all"]').prop("checked",!1))});jQuery("#LogTable .manage-column.column-date").click(function(){jQuery(this).toggleClass("asc desc");
|
13 |
+
var a=jQuery("#LogTable > tbody"),b=a.children("tr");a.append(b.get().reverse())});window.addEventListener("dragover",l,!1);window.addEventListener("drop",l,!1);var c={};jQuery("#ThumbsTable tbody tr").each(function(){jQuery(this).on("dragenter",q).on("dragover",p).on("dragleave",r).on("drop",t);c[jQuery(this).data("entry")]=jQuery();jQuery(this).find("input:button").on("click",function(){jQuery(this).prevAll("input:file").click()});jQuery(this).find("input:file").on("change",u)});"draggable"in document.createElement("span")||
|
14 |
+
jQuery(".html5dndmarker").hide();jQuery("td .dashicons-edit").click(function(){var a=jQuery(this).closest("td");if(a.hasClass("column-title")){if("none"==a.find("a").css("display"))return;a.find("a").hide().after('<input type="text" value="'+a.find(".editable-title").text()+'">');a.find("input").focus()}else if(a.hasClass("column-description")){if("none"==a.find(".editable-description").css("display"))return;a.find(".editable-description").hide().after("<textarea>"+a.find(".editable-description").html()+
|
15 |
+
"</textarea>");a.find("textarea").focus()}else return;jQuery(this).css("visibility","hidden");a.find(".edit-controls").show()});jQuery(".edit-controls .dashicons-no").click(function(){var a=jQuery(this).closest("td");if(a.hasClass("column-title")){if("none"!=a.find("a").css("display"))return;a.find("input").fadeOut("fast",function(){jQuery(this).remove();a.find("a").fadeIn("fast")})}else if(a.hasClass("column-description")){if("none"!=a.find(".editable-description").css("display"))return;a.find("textarea").fadeOut("fast",
|
16 |
+
function(){jQuery(this).remove();a.find(".editable-description").fadeIn("fast")})}else return;jQuery(this).closest(".edit-controls").hide();a.find(".dashicons-edit").css("visibility","visible")});jQuery(".edit-controls .dashicons-yes").click(function(){var a=jQuery(this).closest("td"),b=jQuery(this).closest("tr").data("entry"),g=jQuery("#thumbnail-management-tab").attr("action"),f=new FormData(jQuery("[data-entry="+b+"]").closest("form")[0]);f.append("document_gallery[entry]",b);f.append("document_gallery[ajax]",
|
17 |
+
"true");var e,c;if(a.hasClass("column-title"))e=a.find("input"),c=a.find(".editable-title"),f.append("document_gallery[title]",encodeURIComponent(e.val()));else if(a.hasClass("column-description"))e=a.find("textarea"),c=a.find(".editable-description"),f.append("document_gallery[description]",encodeURIComponent(e.val()));else return;if(e.val()==c.text()||a.hasClass("column-description")&&e.val()==c.html())jQuery(this).next(".dashicons-no").click();else{var d=new XMLHttpRequest;d.open("POST",g);d.onreadystatechange=
|
18 |
+
function(){4==d.readyState&&(a.addClass("trans"),a.find(".edit-controls").removeClass("waiting"),-1==d.responseText.indexOf("\n")?jQuery.parseJSON(d.responseText).result?(a.hasClass("column-description")?c.html(e.val()):c.text(e.val()),a.find(".dashicons-no").click(),a.addClass("responseSuccess").delay(2E3).queue(function(){jQuery(this).removeClass("responseSuccess").dequeue()}).delay(1100).queue(function(){jQuery(this).removeClass("trans").dequeue()})):(n(e),a.addClass("responseFail").delay(1100).queue(function(){jQuery(this).removeClass("responseFail").dequeue()}).delay(1100).queue(function(){jQuery(this).removeClass("trans").dequeue()})):
|
19 |
+
(n(e),a.addClass("responseFail").delay(1100).queue(function(){jQuery(this).removeClass("responseFail").dequeue()}).delay(1100).queue(function(){jQuery(this).removeClass("trans").dequeue()}),console.log("Invalid response from server:"),console.log(d.responseText)))};jQuery(this).closest(".edit-controls").addClass("waiting");d.send(f)}})});
|
|
assets/js/gallery.js
CHANGED
@@ -43,14 +43,13 @@
|
|
43 |
* Listen for all pagination clicks in current DOM and any future DOM elements.
|
44 |
*/
|
45 |
function registerPaginationHandler() {
|
46 |
-
$('body').delegate('.dg-paginate-wrapper
|
47 |
var target = $(this).closest('.dg-paginate-wrapper');
|
48 |
var atts = target.data('shortcode');
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
atts['skip'] += atts['limit'];
|
54 |
}
|
55 |
|
56 |
retrieveGallery(atts, target);
|
@@ -87,7 +86,7 @@
|
|
87 |
// TODO: Cache already-retrieved gallery pages. Need to be careful not to keep too many at a time
|
88 |
// (could consume a lot of memory) & handle caching pages for multiple galleries on a single pages.
|
89 |
$.post(ajaxurl, { action: 'dg_generate_gallery', atts: atts }, function(html) {
|
90 |
-
var jobj = $(html);
|
91 |
target.replaceWith(jobj);
|
92 |
sizeGalleryIcons(jobj);
|
93 |
resetPendingIcons();
|
@@ -99,7 +98,7 @@
|
|
99 |
*/
|
100 |
function retrieveNextIcons() {
|
101 |
// max number of icons to retrieve per AJAX request
|
102 |
-
var batchLimit =
|
103 |
|
104 |
// IDs already retrieved
|
105 |
var idBatch = [];
|
@@ -114,7 +113,14 @@
|
|
114 |
|
115 |
if (idBatch.length != 0) {
|
116 |
// request the next batch of icons
|
117 |
-
$.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
}
|
119 |
}
|
120 |
|
43 |
* Listen for all pagination clicks in current DOM and any future DOM elements.
|
44 |
*/
|
45 |
function registerPaginationHandler() {
|
46 |
+
$('body').delegate('.dg-paginate-wrapper .paginate a', 'click', function (e) {
|
47 |
var target = $(this).closest('.dg-paginate-wrapper');
|
48 |
var atts = target.data('shortcode');
|
49 |
+
atts['skip'] = 0;
|
50 |
+
var split = $(this).attr('href').split('#')[1].split('=');
|
51 |
+
if ( split.length >= 2 ) {
|
52 |
+
atts['skip'] = atts['limit'] * (split.pop() - 1);
|
|
|
53 |
}
|
54 |
|
55 |
retrieveGallery(atts, target);
|
86 |
// TODO: Cache already-retrieved gallery pages. Need to be careful not to keep too many at a time
|
87 |
// (could consume a lot of memory) & handle caching pages for multiple galleries on a single pages.
|
88 |
$.post(ajaxurl, { action: 'dg_generate_gallery', atts: atts }, function(html) {
|
89 |
+
var jobj = $($.parseHTML(html));
|
90 |
target.replaceWith(jobj);
|
91 |
sizeGalleryIcons(jobj);
|
92 |
resetPendingIcons();
|
98 |
*/
|
99 |
function retrieveNextIcons() {
|
100 |
// max number of icons to retrieve per AJAX request
|
101 |
+
var batchLimit = 4;
|
102 |
|
103 |
// IDs already retrieved
|
104 |
var idBatch = [];
|
113 |
|
114 |
if (idBatch.length != 0) {
|
115 |
// request the next batch of icons
|
116 |
+
$.ajax({
|
117 |
+
type: 'POST',
|
118 |
+
url: ajaxurl,
|
119 |
+
dataType: 'json',
|
120 |
+
data: { action: 'dg_generate_icons', ids: idBatch },
|
121 |
+
success: processRetrievedThumbnails,
|
122 |
+
error: function(xhr) { console.error(xhr.responseText); }
|
123 |
+
});
|
124 |
}
|
125 |
}
|
126 |
|
assets/js/gallery.min.js
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
-
(function(b){function g(a){(a||b(".document-gallery[data-icon-width]")).each(function(){var a=b(this).data("icon-width")+"%";b(this).find(".document-icon").width(a)})}function m(){"undefined"!==typeof tinymce&&tinymce.PluginManager.add("dg",function(a,d){a.on("LoadContent dgUpdate undo",function(a){b(a.target.contentDocument).find(".wpview-type-dg > [data-shortcode]").each(function(){h(b.parseJSON(decodeURIComponent(b(this).data("shortcode"))),b(this))})})})}function n(){b("body").delegate(".dg-paginate-wrapper
|
2 |
-
"click",function(a){var d=b(this).closest(".dg-paginate-wrapper"),
|
3 |
-
b.
|
1 |
+
(function(b){function g(a){(a||b(".document-gallery[data-icon-width]")).each(function(){var a=b(this).data("icon-width")+"%";b(this).find(".document-icon").width(a)})}function m(){"undefined"!==typeof tinymce&&tinymce.PluginManager.add("dg",function(a,d){a.on("LoadContent dgUpdate undo",function(a){b(a.target.contentDocument).find(".wpview-type-dg > [data-shortcode]").each(function(){h(b.parseJSON(decodeURIComponent(b(this).data("shortcode"))),b(this))})})})}function n(){b("body").delegate(".dg-paginate-wrapper .paginate a",
|
2 |
+
"click",function(a){var d=b(this).closest(".dg-paginate-wrapper"),e=d.data("shortcode");e.skip=0;var c=b(this).attr("href").split("#")[1].split("=");2<=c.length&&(e.skip=e.limit*(c.pop()-1));h(e,d);a.preventDefault()})}function k(){c=[];f=0;b(".document-gallery img[data-id]").each(function(){var a=b(this).data("id");-1===b.inArray(a,c)&&c.push(a)});l()}function h(a,d){b.post(ajaxurl,{action:"dg_generate_gallery",atts:a},function(a){a=b(b.parseHTML(a));d.replaceWith(a);g(a);k()})}function l(){for(var a=
|
3 |
+
[];f<c.length&&4!==a.length;f++)a.push(c[f]);0!=a.length&&b.ajax({type:"POST",url:ajaxurl,dataType:"json",data:{action:"dg_generate_icons",ids:a},success:p,error:function(a){console.error(a.responseText)}})}function p(a){for(var d in a)if(a.hasOwnProperty(d)){var c=b('.document-gallery img[data-id="'+d+'"]');c.removeAttr("data-id");(function(c,d){d.fadeOut("fast",function(){b(this).attr("src",a[c]);b(this).fadeIn("fast")})})(d,c)}l()}var c,f;b(document).ready(function(){g();k();m();n()})})(jQuery);
|
document-gallery.php
CHANGED
@@ -5,14 +5,14 @@ defined( 'WPINC' ) OR exit;
|
|
5 |
Plugin Name: Document Gallery
|
6 |
Plugin URI: http://wordpress.org/extend/plugins/document-gallery/
|
7 |
Description: Display non-images (and images) in gallery format on a page or post with the [dg] shortcode.
|
8 |
-
Version: 4.
|
9 |
Author: Dan Rossiter
|
10 |
Author URI: http://danrossiter.org/
|
11 |
-
License:
|
12 |
Text Domain: document-gallery
|
13 |
*/
|
14 |
|
15 |
-
define( 'DG_VERSION', '4.
|
16 |
|
17 |
// define helper paths & URLs
|
18 |
define( 'DG_BASENAME', plugin_basename( __FILE__ ) );
|
@@ -70,12 +70,6 @@ if ( is_admin() ) {
|
|
70 |
add_action( 'add_meta_boxes', array( 'DG_Admin', 'addMetaBox' ) );
|
71 |
add_action( 'wp_ajax_dg_upload_thumb', array( 'DG_Admin', 'saveMetaBox' ) );
|
72 |
|
73 |
-
// Media Manager integration
|
74 |
-
add_action( 'admin_print_footer_scripts', array(
|
75 |
-
'DG_Admin',
|
76 |
-
'loadCustomTemplates'
|
77 |
-
) ); //wp_print_scripts || wp_footer
|
78 |
-
|
79 |
if ( DG_Admin::doRegisterSettings() ) {
|
80 |
add_action( 'admin_init', array( 'DG_Admin', 'registerSettings' ) );
|
81 |
}
|
5 |
Plugin Name: Document Gallery
|
6 |
Plugin URI: http://wordpress.org/extend/plugins/document-gallery/
|
7 |
Description: Display non-images (and images) in gallery format on a page or post with the [dg] shortcode.
|
8 |
+
Version: 4.1
|
9 |
Author: Dan Rossiter
|
10 |
Author URI: http://danrossiter.org/
|
11 |
+
License: GPLv3
|
12 |
Text Domain: document-gallery
|
13 |
*/
|
14 |
|
15 |
+
define( 'DG_VERSION', '4.1' );
|
16 |
|
17 |
// define helper paths & URLs
|
18 |
define( 'DG_BASENAME', plugin_basename( __FILE__ ) );
|
70 |
add_action( 'add_meta_boxes', array( 'DG_Admin', 'addMetaBox' ) );
|
71 |
add_action( 'wp_ajax_dg_upload_thumb', array( 'DG_Admin', 'saveMetaBox' ) );
|
72 |
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
if ( DG_Admin::doRegisterSettings() ) {
|
74 |
add_action( 'admin_init', array( 'DG_Admin', 'registerSettings' ) );
|
75 |
}
|
inc/class-api.php
CHANGED
@@ -40,6 +40,7 @@ class DG_API {
|
|
40 |
* plugin in the future.
|
41 |
*
|
42 |
* @param int $ID The attachment ID.
|
|
|
43 |
*/
|
44 |
public static function setThumbnailFailed( $ID ) {
|
45 |
include_once DG_PATH . 'inc/class-thumber.php';
|
@@ -59,7 +60,7 @@ class DG_API {
|
|
59 |
public static function getThumbnail( $ID, $pg = 1, $generate_if_missing = false ) {
|
60 |
include_once DG_PATH . 'inc/class-thumber.php';
|
61 |
|
62 |
-
return DG_Thumber::getThumbnail( $ID, $pg, $generate_if_missing );
|
63 |
}
|
64 |
|
65 |
/**
|
@@ -67,13 +68,9 @@ class DG_API {
|
|
67 |
* the plugin to attempt to re-generate the thumbnail for this attachment next time it
|
68 |
* is requested in a gallery or through some other means.
|
69 |
*
|
70 |
-
* @param int|
|
71 |
-
*
|
72 |
-
* @return array All IDs that were deleted -- some subset of IDs requested to be deleted.
|
73 |
*/
|
74 |
public static function deleteThumbnails( $ids ) {
|
75 |
-
|
76 |
-
|
77 |
-
return DG_Thumber::deleteThumbMeta( $ids );
|
78 |
}
|
79 |
}
|
40 |
* plugin in the future.
|
41 |
*
|
42 |
* @param int $ID The attachment ID.
|
43 |
+
* @return DG_Thumb The failed thumb.
|
44 |
*/
|
45 |
public static function setThumbnailFailed( $ID ) {
|
46 |
include_once DG_PATH . 'inc/class-thumber.php';
|
60 |
public static function getThumbnail( $ID, $pg = 1, $generate_if_missing = false ) {
|
61 |
include_once DG_PATH . 'inc/class-thumber.php';
|
62 |
|
63 |
+
return DG_Thumber::getInstance()->getThumbnail( $ID, $pg, $generate_if_missing );
|
64 |
}
|
65 |
|
66 |
/**
|
68 |
* the plugin to attempt to re-generate the thumbnail for this attachment next time it
|
69 |
* is requested in a gallery or through some other means.
|
70 |
*
|
71 |
+
* @param int|int[] $ids Which thumbnails to delete.
|
|
|
|
|
72 |
*/
|
73 |
public static function deleteThumbnails( $ids ) {
|
74 |
+
DG_Thumb::purgeThumbs( $ids );
|
|
|
|
|
75 |
}
|
76 |
}
|
inc/class-document-gallery.php
CHANGED
@@ -15,7 +15,7 @@ class DocumentGallery {
|
|
15 |
* Takes values passed from attributes and returns suitable HTML to represent
|
16 |
* all valid attachments requested.
|
17 |
*
|
18 |
-
* @param
|
19 |
*
|
20 |
* @return string HTML for the Document Gallery.
|
21 |
*/
|
@@ -79,7 +79,7 @@ class DocumentGallery {
|
|
79 |
/**
|
80 |
* @param int $blog ID of the blog to be retrieved in multisite env.
|
81 |
*
|
82 |
-
* @return
|
83 |
*/
|
84 |
public static function getOptions( $blog = null ) {
|
85 |
global $dg_options;
|
@@ -90,7 +90,7 @@ class DocumentGallery {
|
|
90 |
}
|
91 |
|
92 |
/**
|
93 |
-
* @param
|
94 |
* @param int $blog ID of the blog to be set in multisite env.
|
95 |
*/
|
96 |
public static function setOptions( $options, $blog = null ) {
|
@@ -127,10 +127,10 @@ class DocumentGallery {
|
|
127 |
/**
|
128 |
* Checks whether the given options match the option schema.
|
129 |
*
|
130 |
-
* @param
|
131 |
-
* @param
|
132 |
*
|
133 |
-
* @return
|
134 |
*/
|
135 |
public static function validateOptionsStructure( $new, $old ) {
|
136 |
if ( self::isValidOptionsStructure( $new ) ) {
|
@@ -148,8 +148,8 @@ class DocumentGallery {
|
|
148 |
}
|
149 |
|
150 |
/**
|
151 |
-
* @param
|
152 |
-
* @param
|
153 |
*
|
154 |
* @return bool Whether the given options structure matches the schema.
|
155 |
*/
|
15 |
* Takes values passed from attributes and returns suitable HTML to represent
|
16 |
* all valid attachments requested.
|
17 |
*
|
18 |
+
* @param mixed[] $atts Arguments from the user.
|
19 |
*
|
20 |
* @return string HTML for the Document Gallery.
|
21 |
*/
|
79 |
/**
|
80 |
* @param int $blog ID of the blog to be retrieved in multisite env.
|
81 |
*
|
82 |
+
* @return mixed[] Options for the blog.
|
83 |
*/
|
84 |
public static function getOptions( $blog = null ) {
|
85 |
global $dg_options;
|
90 |
}
|
91 |
|
92 |
/**
|
93 |
+
* @param mixed[] $options
|
94 |
* @param int $blog ID of the blog to be set in multisite env.
|
95 |
*/
|
96 |
public static function setOptions( $options, $blog = null ) {
|
127 |
/**
|
128 |
* Checks whether the given options match the option schema.
|
129 |
*
|
130 |
+
* @param mixed[] $new The new options to be validated.
|
131 |
+
* @param mixed[] $old The old options.
|
132 |
*
|
133 |
+
* @return mixed[] The options to be saved.
|
134 |
*/
|
135 |
public static function validateOptionsStructure( $new, $old ) {
|
136 |
if ( self::isValidOptionsStructure( $new ) ) {
|
148 |
}
|
149 |
|
150 |
/**
|
151 |
+
* @param mixed[]|mixed $o The options structure to validate.
|
152 |
+
* @param mixed[] $schema The schema to validate against (note that only keys matter -- non-array values are ignored).
|
153 |
*
|
154 |
* @return bool Whether the given options structure matches the schema.
|
155 |
*/
|
inc/class-document.php
CHANGED
@@ -81,7 +81,7 @@ class DG_Document {
|
|
81 |
}
|
82 |
|
83 |
if ( ! isset( $thumb ) ) {
|
84 |
-
$thumb =
|
85 |
}
|
86 |
|
87 |
$repl = array( $this->link, $thumb, $this->title_attribute, $this->title, $target, $this->extension, $this->size, $this->path, $data );
|
81 |
}
|
82 |
|
83 |
if ( ! isset( $thumb ) ) {
|
84 |
+
$thumb = DG_DefaultThumber::init()->getThumbnail( $this->ID );
|
85 |
}
|
86 |
|
87 |
$repl = array( $this->link, $thumb, $this->title_attribute, $this->title, $target, $this->extension, $this->size, $this->path, $data );
|
inc/class-gallery-sanitization.php
CHANGED
@@ -53,7 +53,7 @@ class DG_GallerySanitization {
|
|
53 |
*
|
54 |
* @param string $key The key to reference the current value in the defaults array.
|
55 |
* @param mixed $value The value to be sanitized.
|
56 |
-
* @param
|
57 |
*
|
58 |
* @return mixed The sanitized value, falling back to the current default value when invalid value given.
|
59 |
*/
|
@@ -283,7 +283,7 @@ class DG_GallerySanitization {
|
|
283 |
}
|
284 |
|
285 |
/**
|
286 |
-
* @return
|
287 |
*/
|
288 |
public static function getOrderOptions() {
|
289 |
return array( 'ASC', 'DESC' );
|
@@ -309,7 +309,7 @@ class DG_GallerySanitization {
|
|
309 |
}
|
310 |
|
311 |
/**
|
312 |
-
* @return
|
313 |
*/
|
314 |
public static function getOrderbyOptions() {
|
315 |
return array(
|
@@ -366,7 +366,7 @@ class DG_GallerySanitization {
|
|
366 |
}
|
367 |
|
368 |
/**
|
369 |
-
* @return
|
370 |
*/
|
371 |
public static function getPostStatuses() {
|
372 |
static $statuses;
|
@@ -399,7 +399,7 @@ class DG_GallerySanitization {
|
|
399 |
}
|
400 |
|
401 |
/**
|
402 |
-
* @return
|
403 |
*/
|
404 |
public static function getPostTypes() {
|
405 |
static $types;
|
@@ -432,7 +432,7 @@ class DG_GallerySanitization {
|
|
432 |
}
|
433 |
|
434 |
/**
|
435 |
-
* @return
|
436 |
*/
|
437 |
public static function getRelationOptions() {
|
438 |
return array( 'AND', 'OR' );
|
@@ -479,7 +479,7 @@ class DG_GallerySanitization {
|
|
479 |
}
|
480 |
|
481 |
/**
|
482 |
-
* @return
|
483 |
*/
|
484 |
public static function getOperatorOptions() {
|
485 |
return array( 'IN', 'NOT IN', 'AND', 'OR' );
|
53 |
*
|
54 |
* @param string $key The key to reference the current value in the defaults array.
|
55 |
* @param mixed $value The value to be sanitized.
|
56 |
+
* @param string[] $errs The array of errors, which will be appended with any errors found.
|
57 |
*
|
58 |
* @return mixed The sanitized value, falling back to the current default value when invalid value given.
|
59 |
*/
|
283 |
}
|
284 |
|
285 |
/**
|
286 |
+
* @return string[] The valid options for order parameter.
|
287 |
*/
|
288 |
public static function getOrderOptions() {
|
289 |
return array( 'ASC', 'DESC' );
|
309 |
}
|
310 |
|
311 |
/**
|
312 |
+
* @return string[] The valid options for orderby parameter.
|
313 |
*/
|
314 |
public static function getOrderbyOptions() {
|
315 |
return array(
|
366 |
}
|
367 |
|
368 |
/**
|
369 |
+
* @return string[] All registered post statuses.
|
370 |
*/
|
371 |
public static function getPostStatuses() {
|
372 |
static $statuses;
|
399 |
}
|
400 |
|
401 |
/**
|
402 |
+
* @return string[] All registered post types.
|
403 |
*/
|
404 |
public static function getPostTypes() {
|
405 |
static $types;
|
432 |
}
|
433 |
|
434 |
/**
|
435 |
+
* @return string[] The valid options for relation parameter.
|
436 |
*/
|
437 |
public static function getRelationOptions() {
|
438 |
return array( 'AND', 'OR' );
|
479 |
}
|
480 |
|
481 |
/**
|
482 |
+
* @return string[] The valid options for *_relation/*_operator parameter.
|
483 |
*/
|
484 |
public static function getOperatorOptions() {
|
485 |
return array( 'IN', 'NOT IN', 'AND', 'OR' );
|
inc/class-gallery.php
CHANGED
@@ -20,8 +20,9 @@ class DG_Gallery {
|
|
20 |
private $docs = array();
|
21 |
private $errs = array();
|
22 |
|
23 |
-
private $
|
24 |
-
|
|
|
25 |
|
26 |
// templates for HTML output
|
27 |
private static $no_docs, $comment, $defaults;
|
@@ -65,7 +66,7 @@ class DG_Gallery {
|
|
65 |
/**
|
66 |
* @param int $blog The blog we're retrieving options for (null => current blog).
|
67 |
*
|
68 |
-
* @return
|
69 |
*/
|
70 |
public static function getOptions( $blog = null ) {
|
71 |
$options = DocumentGallery::getOptions( $blog );
|
@@ -74,7 +75,7 @@ class DG_Gallery {
|
|
74 |
}
|
75 |
|
76 |
/**
|
77 |
-
* @param
|
78 |
* @param int $blog The blog we're retrieving options for (null => current blog).
|
79 |
*/
|
80 |
public static function setOptions( $options, $blog = null ) {
|
@@ -103,9 +104,12 @@ class DG_Gallery {
|
|
103 |
/**
|
104 |
* Builds a gallery object with attributes passed.
|
105 |
*
|
106 |
-
* @param
|
107 |
*/
|
108 |
public function __construct( $atts ) {
|
|
|
|
|
|
|
109 |
include_once DG_PATH . 'inc/class-document.php';
|
110 |
|
111 |
// empty string is passed when no arguments are given, but constructor expects an array
|
@@ -175,11 +179,11 @@ class DG_Gallery {
|
|
175 |
/**
|
176 |
* Cleans up user input, making sure we don't pass crap on to WP core.
|
177 |
*
|
178 |
-
* @param
|
179 |
-
* @param
|
180 |
-
* @param
|
181 |
*
|
182 |
-
* @return
|
183 |
*/
|
184 |
public static function sanitizeDefaults( $old_defaults, $defaults, &$errs ) {
|
185 |
if ( is_null( $old_defaults ) ) {
|
@@ -213,7 +217,7 @@ class DG_Gallery {
|
|
213 |
/**
|
214 |
* Gets all valid Documents based on the attributes passed by the user.
|
215 |
* NOTE: Keys in returned array are arbitrary and will vary. They should be ignored.
|
216 |
-
* @return
|
217 |
* @throws InvalidArgumentException Thrown when $this->errs is not empty.
|
218 |
*/
|
219 |
private function getDocuments() {
|
@@ -247,8 +251,10 @@ class DG_Gallery {
|
|
247 |
|
248 |
$wpq = new WP_Query();
|
249 |
$attachments = $wpq->query( $query );
|
250 |
-
$this->
|
251 |
-
$this->
|
|
|
|
|
252 |
|
253 |
return $attachments;
|
254 |
}
|
@@ -258,7 +264,7 @@ class DG_Gallery {
|
|
258 |
* self::$defaults. If they are the name of a taxonomy, they are plugged
|
259 |
* into the query, otherwise $this->errs is appended with an error string.
|
260 |
*
|
261 |
-
* @param
|
262 |
*/
|
263 |
private function setTaxa( &$query ) {
|
264 |
if ( ! empty( $this->taxa ) ) {
|
@@ -298,17 +304,17 @@ class DG_Gallery {
|
|
298 |
}
|
299 |
|
300 |
/*==========================================================================
|
301 |
-
|
302 |
-
|
303 |
|
304 |
/**
|
305 |
* Returns an array of term ids when provided with a list of term names.
|
306 |
* Also appends an entry onto $errs if any invalid names are found.
|
307 |
*
|
308 |
* @param string $taxon The taxon these terms are a member of.
|
309 |
-
* @param
|
310 |
*
|
311 |
-
* @return
|
312 |
*/
|
313 |
private function getTermIdsByNames( $taxon, $term_names ) {
|
314 |
return $this->getTermXByNames( 'term_id', $taxon, $term_names );
|
@@ -319,9 +325,9 @@ class DG_Gallery {
|
|
319 |
* Also appends an entry onto $errs if any invalid names are found.
|
320 |
*
|
321 |
* @param string $taxon The taxon these terms are a member of.
|
322 |
-
* @param
|
323 |
*
|
324 |
-
* @return
|
325 |
*/
|
326 |
private function getTermSlugsByNames( $taxon, $term_names ) {
|
327 |
return $this->getTermXByNames( 'slug', $taxon, $term_names );
|
@@ -336,9 +342,9 @@ class DG_Gallery {
|
|
336 |
*
|
337 |
* @param string $x Field to retrieve from matched term.
|
338 |
* @param string $taxon The taxon these terms are a member of.
|
339 |
-
* @param
|
340 |
*
|
341 |
-
* @return
|
342 |
*/
|
343 |
private function getTermXByNames( $x, $taxon, $term_idents ) {
|
344 |
$ret = array();
|
@@ -347,8 +353,7 @@ class DG_Gallery {
|
|
347 |
// taxons may optionally be prefixed by 'tax_' --
|
348 |
// this is only useful when avoiding collisions with other attributes
|
349 |
if ( ! taxonomy_exists( $taxon ) ) {
|
350 |
-
|
351 |
-
if ( $count > 0 && taxonomy_exists( $tmp ) ) {
|
352 |
$taxon = $tmp;
|
353 |
} else {
|
354 |
$this->errs[] = sprintf( DG_GallerySanitization::getUnaryErr(), 'taxon', $taxon );
|
@@ -394,7 +399,7 @@ class DG_Gallery {
|
|
394 |
*=========================================================================*/
|
395 |
|
396 |
/**
|
397 |
-
* @return
|
398 |
*/
|
399 |
private function getShortcodeData() {
|
400 |
$ret = array_merge( $this->atts, $this->taxa );
|
@@ -414,8 +419,6 @@ class DG_Gallery {
|
|
414 |
* @return string HTML representing this Gallery.
|
415 |
*/
|
416 |
public function __toString() {
|
417 |
-
static $instance = 0;
|
418 |
-
|
419 |
if ( ! empty( $this->errs ) ) {
|
420 |
return '<p>' . implode( '</p><p>', $this->errs ) . '</p>';
|
421 |
}
|
@@ -424,13 +427,11 @@ class DG_Gallery {
|
|
424 |
return self::$no_docs;
|
425 |
}
|
426 |
|
427 |
-
$instance++;
|
428 |
-
|
429 |
$icon_find = array( '%class%', '%icons%' );
|
430 |
$icon_repl = array();
|
431 |
$icon_classes = array( 'document-icon-row' );
|
432 |
$gallery_find = array( '%id%', '%data%', '%rows%', '%class%' );
|
433 |
-
$gallery_repl = array( "document-gallery-$instance", ( "data-shortcode='" . wp_json_encode( self::getShortcodeData() ) . "'" ), '' );
|
434 |
$gallery_classes = array( 'document-gallery' );
|
435 |
|
436 |
if ( $this->useDescriptions() ) {
|
@@ -462,7 +463,7 @@ class DG_Gallery {
|
|
462 |
$icon_repl[1] = '';
|
463 |
|
464 |
$min = min( $i + $cols, $count );
|
465 |
-
for ( $x = $i; $x < $min; $x
|
466 |
$icon_repl[1] .= $this->docs[ $x ];
|
467 |
}
|
468 |
|
@@ -474,23 +475,16 @@ class DG_Gallery {
|
|
474 |
$gallery = apply_filters( 'dg_gallery_template', '<div id="%id%" class="%class%" %data%>' . PHP_EOL . '%rows%</div>', $this->useDescriptions() );
|
475 |
|
476 |
// build pagination section
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
$right_href = '';
|
488 |
-
$right_tag = 'span';
|
489 |
-
}
|
490 |
-
|
491 |
-
$prev = __( 'Prev', 'document-gallery' );
|
492 |
-
$next = __( 'Next', 'document-gallery' );
|
493 |
-
$gallery_repl[2] .= "<span class='pagination'><$left_tag$left_href class='paginate left'>$prev</$left_tag> | <$right_tag$right_href class='paginate right'>$next</$right_tag></span>";
|
494 |
$gallery_classes[] = 'dg-paginate-wrapper';
|
495 |
}
|
496 |
|
20 |
private $docs = array();
|
21 |
private $errs = array();
|
22 |
|
23 |
+
private $instance;
|
24 |
+
|
25 |
+
private $pg_count = 1, $cur_pg = 1;
|
26 |
|
27 |
// templates for HTML output
|
28 |
private static $no_docs, $comment, $defaults;
|
66 |
/**
|
67 |
* @param int $blog The blog we're retrieving options for (null => current blog).
|
68 |
*
|
69 |
+
* @return mixed[] Gets gallery branch of DG options array.
|
70 |
*/
|
71 |
public static function getOptions( $blog = null ) {
|
72 |
$options = DocumentGallery::getOptions( $blog );
|
75 |
}
|
76 |
|
77 |
/**
|
78 |
+
* @param mixed[] $options New value for gallery branch of DG options array.
|
79 |
* @param int $blog The blog we're retrieving options for (null => current blog).
|
80 |
*/
|
81 |
public static function setOptions( $options, $blog = null ) {
|
104 |
/**
|
105 |
* Builds a gallery object with attributes passed.
|
106 |
*
|
107 |
+
* @param mixed[] $atts Array of attributes used in shortcode.
|
108 |
*/
|
109 |
public function __construct( $atts ) {
|
110 |
+
static $instance = 0;
|
111 |
+
$this->instance = ++$instance;
|
112 |
+
|
113 |
include_once DG_PATH . 'inc/class-document.php';
|
114 |
|
115 |
// empty string is passed when no arguments are given, but constructor expects an array
|
179 |
/**
|
180 |
* Cleans up user input, making sure we don't pass crap on to WP core.
|
181 |
*
|
182 |
+
* @param mixed[] $old_defaults The previous set of defaults.
|
183 |
+
* @param mixed[] $defaults The defaults array to sanitize.
|
184 |
+
* @param string[] &$errs The array of errors, which will be appended with any errors found.
|
185 |
*
|
186 |
+
* @return mixed[] The sanitized defaults.
|
187 |
*/
|
188 |
public static function sanitizeDefaults( $old_defaults, $defaults, &$errs ) {
|
189 |
if ( is_null( $old_defaults ) ) {
|
217 |
/**
|
218 |
* Gets all valid Documents based on the attributes passed by the user.
|
219 |
* NOTE: Keys in returned array are arbitrary and will vary. They should be ignored.
|
220 |
+
* @return WP_Post[] Contains all documents matching the query.
|
221 |
* @throws InvalidArgumentException Thrown when $this->errs is not empty.
|
222 |
*/
|
223 |
private function getDocuments() {
|
251 |
|
252 |
$wpq = new WP_Query();
|
253 |
$attachments = $wpq->query( $query );
|
254 |
+
$this->pg_count = $wpq->max_num_pages;
|
255 |
+
if ( $this->atts['skip'] >= 0 && $this->atts['limit'] > 0 ) {
|
256 |
+
$this->cur_pg = min( $this->atts['skip'] / $this->atts['limit'] + 1, $wpq->max_num_pages );
|
257 |
+
}
|
258 |
|
259 |
return $attachments;
|
260 |
}
|
264 |
* self::$defaults. If they are the name of a taxonomy, they are plugged
|
265 |
* into the query, otherwise $this->errs is appended with an error string.
|
266 |
*
|
267 |
+
* @param mixed[] $query Query to insert tax query into.
|
268 |
*/
|
269 |
private function setTaxa( &$query ) {
|
270 |
if ( ! empty( $this->taxa ) ) {
|
304 |
}
|
305 |
|
306 |
/*==========================================================================
|
307 |
+
* HELPER FUNCTIONS
|
308 |
+
*=========================================================================*/
|
309 |
|
310 |
/**
|
311 |
* Returns an array of term ids when provided with a list of term names.
|
312 |
* Also appends an entry onto $errs if any invalid names are found.
|
313 |
*
|
314 |
* @param string $taxon The taxon these terms are a member of.
|
315 |
+
* @param string[] $term_names Terms to retrieve.
|
316 |
*
|
317 |
+
* @return WP_Term[] All matched terms.
|
318 |
*/
|
319 |
private function getTermIdsByNames( $taxon, $term_names ) {
|
320 |
return $this->getTermXByNames( 'term_id', $taxon, $term_names );
|
325 |
* Also appends an entry onto $errs if any invalid names are found.
|
326 |
*
|
327 |
* @param string $taxon The taxon these terms are a member of.
|
328 |
+
* @param string[] $term_names Terms to retrieve.
|
329 |
*
|
330 |
+
* @return WP_Term[] All matched terms.
|
331 |
*/
|
332 |
private function getTermSlugsByNames( $taxon, $term_names ) {
|
333 |
return $this->getTermXByNames( 'slug', $taxon, $term_names );
|
342 |
*
|
343 |
* @param string $x Field to retrieve from matched term.
|
344 |
* @param string $taxon The taxon these terms are a member of.
|
345 |
+
* @param string[] $term_idents Terms to retrieve, identified by either slug or name.
|
346 |
*
|
347 |
+
* @return WP_Term[] All matched terms.
|
348 |
*/
|
349 |
private function getTermXByNames( $x, $taxon, $term_idents ) {
|
350 |
$ret = array();
|
353 |
// taxons may optionally be prefixed by 'tax_' --
|
354 |
// this is only useful when avoiding collisions with other attributes
|
355 |
if ( ! taxonomy_exists( $taxon ) ) {
|
356 |
+
if ( DG_Util::startsWith( $taxon, 'tax_' ) && ( $tmp = substr( $taxon, 4 ) ) && taxonomy_exists( $tmp ) ) {
|
|
|
357 |
$taxon = $tmp;
|
358 |
} else {
|
359 |
$this->errs[] = sprintf( DG_GallerySanitization::getUnaryErr(), 'taxon', $taxon );
|
399 |
*=========================================================================*/
|
400 |
|
401 |
/**
|
402 |
+
* @return mixed[] The data to be used in the data-shortcode attribute.
|
403 |
*/
|
404 |
private function getShortcodeData() {
|
405 |
$ret = array_merge( $this->atts, $this->taxa );
|
419 |
* @return string HTML representing this Gallery.
|
420 |
*/
|
421 |
public function __toString() {
|
|
|
|
|
422 |
if ( ! empty( $this->errs ) ) {
|
423 |
return '<p>' . implode( '</p><p>', $this->errs ) . '</p>';
|
424 |
}
|
427 |
return self::$no_docs;
|
428 |
}
|
429 |
|
|
|
|
|
430 |
$icon_find = array( '%class%', '%icons%' );
|
431 |
$icon_repl = array();
|
432 |
$icon_classes = array( 'document-icon-row' );
|
433 |
$gallery_find = array( '%id%', '%data%', '%rows%', '%class%' );
|
434 |
+
$gallery_repl = array( "document-gallery-$this->instance", ( "data-shortcode='" . wp_json_encode( self::getShortcodeData() ) . "'" ), '' );
|
435 |
$gallery_classes = array( 'document-gallery' );
|
436 |
|
437 |
if ( $this->useDescriptions() ) {
|
463 |
$icon_repl[1] = '';
|
464 |
|
465 |
$min = min( $i + $cols, $count );
|
466 |
+
for ( $x = $i; $x < $min; $x++ ) {
|
467 |
$icon_repl[1] .= $this->docs[ $x ];
|
468 |
}
|
469 |
|
475 |
$gallery = apply_filters( 'dg_gallery_template', '<div id="%id%" class="%class%" %data%>' . PHP_EOL . '%rows%</div>', $this->useDescriptions() );
|
476 |
|
477 |
// build pagination section
|
478 |
+
if ( $this->atts['paginate'] && $this->atts['limit'] > 0 && $this->pg_count > 1 ) {
|
479 |
+
$args = array(
|
480 |
+
'base' => '#%_%',
|
481 |
+
'format' => 'dg_page=%#%',
|
482 |
+
'total' => $this->pg_count,
|
483 |
+
'current' => $this->cur_pg,
|
484 |
+
'prev_text' => __( '«' ),
|
485 |
+
'next_text' => __( '»' )
|
486 |
+
);
|
487 |
+
$gallery_repl[2] .= '<div class="paginate">' . paginate_links( $args ) . '</div>';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
488 |
$gallery_classes[] = 'dg-paginate-wrapper';
|
489 |
}
|
490 |
|
inc/class-image-editor-imagick.php
CHANGED
@@ -53,7 +53,7 @@ class DG_Image_Editor_Imagick extends WP_Image_Editor_Imagick {
|
|
53 |
}
|
54 |
|
55 |
/**
|
56 |
-
* @return
|
57 |
*/
|
58 |
public static function query_formats() {
|
59 |
try {
|
53 |
}
|
54 |
|
55 |
/**
|
56 |
+
* @return string[]|bool The formats supported by Imagick, or false
|
57 |
*/
|
58 |
public static function query_formats() {
|
59 |
try {
|
inc/class-logger.php
CHANGED
@@ -53,7 +53,7 @@ class DG_Logger {
|
|
53 |
* @param int $skip How many lines to skip before returning rows.
|
54 |
* @param int $limit Max number of lines to read.
|
55 |
*
|
56 |
-
* @return
|
57 |
*/
|
58 |
public static function readLog( $skip = 0, $limit = PHP_INT_MAX ) {
|
59 |
$ret = null;
|
@@ -176,7 +176,7 @@ class DG_Logger {
|
|
176 |
*
|
177 |
* @param int $blog ID of the blog to be retrieved in multisite env.
|
178 |
*
|
179 |
-
* @return
|
180 |
*/
|
181 |
public static function getOptions( $blog = null ) {
|
182 |
$options = DocumentGallery::getOptions( $blog );
|
@@ -196,7 +196,7 @@ class DG_Logger {
|
|
196 |
}
|
197 |
|
198 |
/**
|
199 |
-
* @param
|
200 |
*
|
201 |
* @return string The stack trace in human-readable form.
|
202 |
*/
|
@@ -295,12 +295,12 @@ class DG_LogLevel {
|
|
295 |
}
|
296 |
|
297 |
/**
|
298 |
-
* @var
|
299 |
*/
|
300 |
private static $levels = null;
|
301 |
|
302 |
/**
|
303 |
-
* @return
|
304 |
*/
|
305 |
public static function getLogLevels() {
|
306 |
if ( is_null( self::$levels ) ) {
|
53 |
* @param int $skip How many lines to skip before returning rows.
|
54 |
* @param int $limit Max number of lines to read.
|
55 |
*
|
56 |
+
* @return string[][]|null The rows from the log file or null if failed to open log.
|
57 |
*/
|
58 |
public static function readLog( $skip = 0, $limit = PHP_INT_MAX ) {
|
59 |
$ret = null;
|
176 |
*
|
177 |
* @param int $blog ID of the blog to be retrieved in multisite env.
|
178 |
*
|
179 |
+
* @return mixed[] Logger options for the blog.
|
180 |
*/
|
181 |
public static function getOptions( $blog = null ) {
|
182 |
$options = DocumentGallery::getOptions( $blog );
|
196 |
}
|
197 |
|
198 |
/**
|
199 |
+
* @param mixed[][] $trace Array containing stack trace to be converted to string.
|
200 |
*
|
201 |
* @return string The stack trace in human-readable form.
|
202 |
*/
|
295 |
}
|
296 |
|
297 |
/**
|
298 |
+
* @var int[] Backs the getter.
|
299 |
*/
|
300 |
private static $levels = null;
|
301 |
|
302 |
/**
|
303 |
+
* @return int[] Associative array containing all log level names mapped to their int value.
|
304 |
*/
|
305 |
public static function getLogLevels() {
|
306 |
if ( is_null( self::$levels ) ) {
|
inc/class-setup.php
CHANGED
@@ -13,7 +13,7 @@ class DG_Setup {
|
|
13 |
*
|
14 |
* @param $skeleton bool When true, expensive values are not calculated. Only keys may be trusted when returning skeleton.
|
15 |
*
|
16 |
-
* @return
|
17 |
*/
|
18 |
public static function getDefaultOptions( $skeleton = false ) {
|
19 |
include_once DG_PATH . 'inc/class-thumber.php';
|
@@ -35,6 +35,13 @@ class DG_Setup {
|
|
35 |
// max height to generate thumbnails
|
36 |
'height' => 200
|
37 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
'gallery' => array(
|
39 |
// default: link directly to file (true to link to attachment pg)
|
40 |
'attachment_pg' => false,
|
@@ -88,7 +95,7 @@ class DG_Setup {
|
|
88 |
}
|
89 |
|
90 |
/**
|
91 |
-
* @return
|
92 |
*/
|
93 |
public static function getDefaultMimeTypes() {
|
94 |
return array( 'application', 'video', 'text', 'audio', 'image' );
|
@@ -142,6 +149,7 @@ class DG_Setup {
|
|
142 |
self::threePointFour( $options );
|
143 |
self::threePointFive( $options );
|
144 |
self::fourPointZero( $options );
|
|
|
145 |
|
146 |
// update plugin meta data
|
147 |
$options['meta']['version'] = DG_VERSION;
|
@@ -160,7 +168,7 @@ class DG_Setup {
|
|
160 |
*
|
161 |
* The defaults sub-branch in the gallery branch is being flattened into its parent.
|
162 |
*
|
163 |
-
* @param
|
164 |
*/
|
165 |
private static function twoPointTwo( &$options ) {
|
166 |
if ( isset( $options['version'] ) && version_compare( $options['version'], '2.2', '<' ) ) {
|
@@ -199,7 +207,7 @@ class DG_Setup {
|
|
199 |
/**
|
200 |
* Some of the data previously stored along with custom CSS is no longer needed.
|
201 |
*
|
202 |
-
* @param
|
203 |
*/
|
204 |
private static function twoPointThree( &$options ) {
|
205 |
if ( isset( $options['version'] ) && version_compare( $options['version'], '2.3', '<' ) ) {
|
@@ -237,7 +245,7 @@ class DG_Setup {
|
|
237 |
* Added "columns" attribute.
|
238 |
* Added "mime_types" attribute.
|
239 |
*
|
240 |
-
* @param
|
241 |
*/
|
242 |
private static function threePointZeroBeta( &$options ) {
|
243 |
if ( isset( $options['version'] ) /*&& version_compare($options['version'], '3.0.0-beta', '<')*/ ) {
|
@@ -266,7 +274,7 @@ class DG_Setup {
|
|
266 |
*
|
267 |
* Added scheduled log purge event to handle rollovers.
|
268 |
*
|
269 |
-
* @param
|
270 |
*/
|
271 |
private static function threePointOne( &$options ) {
|
272 |
if ( version_compare( $options['meta']['version'], '3.1', '<' ) ) {
|
@@ -284,7 +292,7 @@ class DG_Setup {
|
|
284 |
/**
|
285 |
* Adds 'new_window' under gallery options.
|
286 |
*
|
287 |
-
* @param
|
288 |
*/
|
289 |
private static function threePointTwo( &$options ) {
|
290 |
if ( version_compare( $options['meta']['version'], '3.2', '<' ) ) {
|
@@ -295,7 +303,7 @@ class DG_Setup {
|
|
295 |
/**
|
296 |
* Removes minified CSS. Fixing corrupt data for boolean fields that may have gotten strings.
|
297 |
*
|
298 |
-
* @param
|
299 |
*/
|
300 |
private static function threePointThree( &$options ) {
|
301 |
if ( version_compare( $options['meta']['version'], '3.3', '<' ) ) {
|
@@ -319,7 +327,7 @@ class DG_Setup {
|
|
319 |
/**
|
320 |
* Removes the validation option. Validation is now non-optional.
|
321 |
*
|
322 |
-
* @param
|
323 |
*/
|
324 |
private static function threePointFour( &$options ) {
|
325 |
if ( version_compare( $options['meta']['version'], '3.4', '<' ) ) {
|
@@ -340,7 +348,7 @@ class DG_Setup {
|
|
340 |
* There is no longer a concept of gallery load timeout. Missing thumbnails are asynchronously generated after
|
341 |
* a gallery is first rendered via AJAX requests.
|
342 |
*
|
343 |
-
* @param
|
344 |
*/
|
345 |
private static function threePointFive( &$options ) {
|
346 |
if ( version_compare( $options['meta']['version'], '3.5', '<' ) ) {
|
@@ -353,7 +361,7 @@ class DG_Setup {
|
|
353 |
* Paginate & skip options were added.
|
354 |
* Moving cached thumbs into postmeta table.
|
355 |
*
|
356 |
-
* @param
|
357 |
*/
|
358 |
private static function fourPointZero( &$options ) {
|
359 |
if ( version_compare( $options['meta']['version'], '4.0', '<' ) ) {
|
@@ -381,6 +389,42 @@ class DG_Setup {
|
|
381 |
}
|
382 |
}
|
383 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
384 |
/**
|
385 |
* Sets up Document Gallery on all blog(s) activated.
|
386 |
*
|
13 |
*
|
14 |
* @param $skeleton bool When true, expensive values are not calculated. Only keys may be trusted when returning skeleton.
|
15 |
*
|
16 |
+
* @return mixed[][] Contains default options for DG.
|
17 |
*/
|
18 |
public static function getDefaultOptions( $skeleton = false ) {
|
19 |
include_once DG_PATH . 'inc/class-thumber.php';
|
35 |
// max height to generate thumbnails
|
36 |
'height' => 200
|
37 |
),
|
38 |
+
'thumber-co' => array(
|
39 |
+
'uid' => null,
|
40 |
+
'secret' => null,
|
41 |
+
'subscription' => array(),
|
42 |
+
'direct_upload' => false,
|
43 |
+
'mime_types' => array()
|
44 |
+
),
|
45 |
'gallery' => array(
|
46 |
// default: link directly to file (true to link to attachment pg)
|
47 |
'attachment_pg' => false,
|
95 |
}
|
96 |
|
97 |
/**
|
98 |
+
* @return string[] The default MIME types to include in gallery.
|
99 |
*/
|
100 |
public static function getDefaultMimeTypes() {
|
101 |
return array( 'application', 'video', 'text', 'audio', 'image' );
|
149 |
self::threePointFour( $options );
|
150 |
self::threePointFive( $options );
|
151 |
self::fourPointZero( $options );
|
152 |
+
self::fourPointOne( $options );
|
153 |
|
154 |
// update plugin meta data
|
155 |
$options['meta']['version'] = DG_VERSION;
|
168 |
*
|
169 |
* The defaults sub-branch in the gallery branch is being flattened into its parent.
|
170 |
*
|
171 |
+
* @param mixed[][] $options The options to be modified.
|
172 |
*/
|
173 |
private static function twoPointTwo( &$options ) {
|
174 |
if ( isset( $options['version'] ) && version_compare( $options['version'], '2.2', '<' ) ) {
|
207 |
/**
|
208 |
* Some of the data previously stored along with custom CSS is no longer needed.
|
209 |
*
|
210 |
+
* @param mixed[][] $options The options to be modified.
|
211 |
*/
|
212 |
private static function twoPointThree( &$options ) {
|
213 |
if ( isset( $options['version'] ) && version_compare( $options['version'], '2.3', '<' ) ) {
|
245 |
* Added "columns" attribute.
|
246 |
* Added "mime_types" attribute.
|
247 |
*
|
248 |
+
* @param mixed[][] $options The options to be modified.
|
249 |
*/
|
250 |
private static function threePointZeroBeta( &$options ) {
|
251 |
if ( isset( $options['version'] ) /*&& version_compare($options['version'], '3.0.0-beta', '<')*/ ) {
|
274 |
*
|
275 |
* Added scheduled log purge event to handle rollovers.
|
276 |
*
|
277 |
+
* @param mixed[][] $options The options to be modified.
|
278 |
*/
|
279 |
private static function threePointOne( &$options ) {
|
280 |
if ( version_compare( $options['meta']['version'], '3.1', '<' ) ) {
|
292 |
/**
|
293 |
* Adds 'new_window' under gallery options.
|
294 |
*
|
295 |
+
* @param mixed[][] $options The options to be modified.
|
296 |
*/
|
297 |
private static function threePointTwo( &$options ) {
|
298 |
if ( version_compare( $options['meta']['version'], '3.2', '<' ) ) {
|
303 |
/**
|
304 |
* Removes minified CSS. Fixing corrupt data for boolean fields that may have gotten strings.
|
305 |
*
|
306 |
+
* @param mixed[][] $options The options to be modified.
|
307 |
*/
|
308 |
private static function threePointThree( &$options ) {
|
309 |
if ( version_compare( $options['meta']['version'], '3.3', '<' ) ) {
|
327 |
/**
|
328 |
* Removes the validation option. Validation is now non-optional.
|
329 |
*
|
330 |
+
* @param mixed[][] $options The options to be modified.
|
331 |
*/
|
332 |
private static function threePointFour( &$options ) {
|
333 |
if ( version_compare( $options['meta']['version'], '3.4', '<' ) ) {
|
348 |
* There is no longer a concept of gallery load timeout. Missing thumbnails are asynchronously generated after
|
349 |
* a gallery is first rendered via AJAX requests.
|
350 |
*
|
351 |
+
* @param mixed[][] $options The options to be modified.
|
352 |
*/
|
353 |
private static function threePointFive( &$options ) {
|
354 |
if ( version_compare( $options['meta']['version'], '3.5', '<' ) ) {
|
361 |
* Paginate & skip options were added.
|
362 |
* Moving cached thumbs into postmeta table.
|
363 |
*
|
364 |
+
* @param mixed[][] $options The options to be modified.
|
365 |
*/
|
366 |
private static function fourPointZero( &$options ) {
|
367 |
if ( version_compare( $options['meta']['version'], '4.0', '<' ) ) {
|
389 |
}
|
390 |
}
|
391 |
|
392 |
+
/**
|
393 |
+
* Adds integration w/ Thumber.co service.
|
394 |
+
* Update existing thumbs to match new thumbnail generation architecture.
|
395 |
+
*
|
396 |
+
* @param mixed[][] $options The options to be modified.
|
397 |
+
*/
|
398 |
+
private static function fourPointOne( &$options ) {
|
399 |
+
if ( version_compare( $options['meta']['version'], '4.1', '<' ) ) {
|
400 |
+
$options['thumber']['active']['thumber-co'] = false;
|
401 |
+
$options['thumber-co'] = array(
|
402 |
+
'uid' => null,
|
403 |
+
'secret' => null,
|
404 |
+
'subscription' => array(),
|
405 |
+
'direct_upload' => false,
|
406 |
+
'mime_types' => array()
|
407 |
+
);
|
408 |
+
|
409 |
+
$old_thumbs = DG_Thumb::getThumbs();
|
410 |
+
DG_Thumb::purgeThumbs();
|
411 |
+
foreach ( $old_thumbs as $thumb ) {
|
412 |
+
if ( $thumb->isSuccess() ) {
|
413 |
+
$generator = $thumb->getGenerator();
|
414 |
+
if ( $generator == 'DG_Thumber::getGhostscriptThumbnail' ) {
|
415 |
+
$thumb->setGenerator( 'DG_GhostscriptThumber' );
|
416 |
+
} elseif ( $generator == 'DG_Thumber::getImagickThumbnail' ) {
|
417 |
+
$thumb->setGenerator( 'DG_ImagickThumber' );
|
418 |
+
} elseif ( $generator == 'DG_Thumber::getAudioVideoThumbnail' ) {
|
419 |
+
$thumb->setGenerator( 'DG_AudioVideoThumber' );
|
420 |
+
}
|
421 |
+
|
422 |
+
$thumb->save();
|
423 |
+
}
|
424 |
+
}
|
425 |
+
}
|
426 |
+
}
|
427 |
+
|
428 |
/**
|
429 |
* Sets up Document Gallery on all blog(s) activated.
|
430 |
*
|
inc/class-thumb.php
CHANGED
@@ -9,7 +9,7 @@ class DG_Thumb {
|
|
9 |
|
10 |
/**
|
11 |
* TODO: Replace w/ https://codex.wordpress.org/Class_Reference/WP_Object_Cache
|
12 |
-
* @var
|
13 |
*/
|
14 |
private static $thumbs = null;
|
15 |
|
@@ -189,7 +189,7 @@ class DG_Thumb {
|
|
189 |
* @return bool Whether this instance represents a successful thumb generation.
|
190 |
*/
|
191 |
public function isSuccess() {
|
192 |
-
return ! empty( $this->relative_path );
|
193 |
}
|
194 |
|
195 |
/**
|
@@ -202,8 +202,13 @@ class DG_Thumb {
|
|
202 |
// thumbs are immutable -- once created they can only be read or deleted
|
203 |
if ( isset( $this->meta_id ) ) return;
|
204 |
|
|
|
|
|
|
|
|
|
|
|
205 |
// post_id + dimensions must be unique so purge the old entry if one exists
|
206 |
-
$old_thumb = self::getThumb( $this->post_id, $this->
|
207 |
if ( ! is_null( $old_thumb ) ) {
|
208 |
$old_thumb->delete();
|
209 |
}
|
@@ -309,7 +314,7 @@ class DG_Thumb {
|
|
309 |
* Gets either a nested associative array mapping ID to dimension to thumb or an associative array mapping ID to thumb.
|
310 |
*
|
311 |
* @param $dimensions string WIDTHxHEIGHT
|
312 |
-
* @return
|
313 |
*/
|
314 |
public static function getThumbs($dimensions = null) {
|
315 |
self::initThumbs();
|
@@ -330,7 +335,7 @@ class DG_Thumb {
|
|
330 |
|
331 |
/**
|
332 |
* Removes thumbs from the DB.
|
333 |
-
* @param $ids
|
334 |
* @param $blog_id null|int Optional. The blog to purge from. Defaults to active blog.
|
335 |
*/
|
336 |
public static function purgeThumbs($ids = null, $blog_id = null) {
|
@@ -396,7 +401,7 @@ class DG_Thumb {
|
|
396 |
}
|
397 |
|
398 |
/**
|
399 |
-
* @param $thumbs
|
400 |
*/
|
401 |
private static function cleanupThumbFiles($thumbs) {
|
402 |
if ( is_a( $thumbs, __CLASS__ ) ) {
|
9 |
|
10 |
/**
|
11 |
* TODO: Replace w/ https://codex.wordpress.org/Class_Reference/WP_Object_Cache
|
12 |
+
* @var DG_Thumb[] The cached copy of thumbs.
|
13 |
*/
|
14 |
private static $thumbs = null;
|
15 |
|
189 |
* @return bool Whether this instance represents a successful thumb generation.
|
190 |
*/
|
191 |
public function isSuccess() {
|
192 |
+
return ! empty( $this->relative_path ) && ! DG_Util::startsWith( $this->getPath(), DG_PATH );
|
193 |
}
|
194 |
|
195 |
/**
|
202 |
// thumbs are immutable -- once created they can only be read or deleted
|
203 |
if ( isset( $this->meta_id ) ) return;
|
204 |
|
205 |
+
// don't re-save identical thumb
|
206 |
+
if ( isset( self::$thumbs[$this->post_id][$this->dimensions] ) &&
|
207 |
+
$this == self::$thumbs[$this->post_id][$this->dimensions] ) return;
|
208 |
+
|
209 |
+
|
210 |
// post_id + dimensions must be unique so purge the old entry if one exists
|
211 |
+
$old_thumb = self::getThumb( $this->post_id, $this->dimensions );
|
212 |
if ( ! is_null( $old_thumb ) ) {
|
213 |
$old_thumb->delete();
|
214 |
}
|
314 |
* Gets either a nested associative array mapping ID to dimension to thumb or an associative array mapping ID to thumb.
|
315 |
*
|
316 |
* @param $dimensions string WIDTHxHEIGHT
|
317 |
+
* @return DG_Thumb[] The matched thumbs.
|
318 |
*/
|
319 |
public static function getThumbs($dimensions = null) {
|
320 |
self::initThumbs();
|
335 |
|
336 |
/**
|
337 |
* Removes thumbs from the DB.
|
338 |
+
* @param $ids int[]|int|null Optional. The post IDs to be purged. If not given then all are purged.
|
339 |
* @param $blog_id null|int Optional. The blog to purge from. Defaults to active blog.
|
340 |
*/
|
341 |
public static function purgeThumbs($ids = null, $blog_id = null) {
|
401 |
}
|
402 |
|
403 |
/**
|
404 |
+
* @param $thumbs DG_Thumb[]|DG_Thumb Removes files associated with given thumb(s).
|
405 |
*/
|
406 |
private static function cleanupThumbFiles($thumbs) {
|
407 |
if ( is_a( $thumbs, __CLASS__ ) ) {
|
inc/class-thumber.php
CHANGED
@@ -1,61 +1,27 @@
|
|
1 |
<?php
|
2 |
defined( 'WPINC' ) OR exit;
|
3 |
|
|
|
|
|
|
|
4 |
/**
|
5 |
* Thumber wraps the functionality required to
|
6 |
* generate thumbnails for arbitrary documents.
|
7 |
*
|
8 |
* @author drossiter
|
9 |
*/
|
10 |
-
class DG_Thumber {
|
11 |
|
12 |
/**
|
13 |
-
*
|
14 |
-
*
|
15 |
-
* @param $skeleton bool When true, values that require computation will be
|
16 |
-
* skipped. Useful when only structure of options is needed.
|
17 |
-
*
|
18 |
-
* @return array The default thumbnail generation methods.
|
19 |
*/
|
20 |
-
|
21 |
-
$gs_active = $imagick_active = null;
|
22 |
-
if ( ! $skeleton ) {
|
23 |
-
$gs_active = (bool) self::getGhostscriptExecutable();
|
24 |
-
$imagick_active = self::isImagickAvailable();
|
25 |
-
}
|
26 |
-
|
27 |
-
return array(
|
28 |
-
'av' => true,
|
29 |
-
'gs' => $gs_active,
|
30 |
-
'imagick' => $imagick_active
|
31 |
-
);
|
32 |
-
}
|
33 |
|
34 |
/**
|
35 |
-
*
|
36 |
-
*
|
37 |
-
* @param int $ID Document ID.
|
38 |
-
* @param string $path System path to thumbnail.
|
39 |
-
* @param string $generator Descriptor for generation method -- usually method name.
|
40 |
-
*
|
41 |
-
* @return DG_Thumb|bool Thumb on success, false on failure.
|
42 |
*/
|
43 |
-
public static function
|
44 |
-
return self
|
45 |
-
}
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Sets the thumbnail for the given attachment ID to a failed state.
|
49 |
-
*
|
50 |
-
* @param int $ID Document ID.
|
51 |
-
*/
|
52 |
-
public static function setThumbnailFailed( $ID ) {
|
53 |
-
$options = self::getOptions();
|
54 |
-
$thumb = new DG_Thumb();
|
55 |
-
$thumb->setPostId( $ID );
|
56 |
-
$thumb->setTimestamp( time() );
|
57 |
-
$thumb->setDimensions( $options['width'] . 'x' . $options['height'] );
|
58 |
-
$thumb->save();
|
59 |
}
|
60 |
|
61 |
/**
|
@@ -68,7 +34,7 @@ class DG_Thumber {
|
|
68 |
*
|
69 |
* @return string URL to the thumbnail.
|
70 |
*/
|
71 |
-
public
|
72 |
$options = self::getOptions();
|
73 |
$dimensions = $options['width'] . 'x' . $options['height'];
|
74 |
|
@@ -79,403 +45,112 @@ class DG_Thumber {
|
|
79 |
return null;
|
80 |
}
|
81 |
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
foreach ( self::getThumbers() as $ext_preg => $thumber ) {
|
86 |
-
$ext_preg = '!\.(?:' . $ext_preg . ')$!i';
|
87 |
-
|
88 |
-
if ( preg_match( $ext_preg, $file ) ) {
|
89 |
if ( DG_Logger::logEnabled() ) {
|
90 |
$toLog = sprintf( __( 'Attempting to generate thumbnail for attachment #%d with (%s)',
|
91 |
-
|
92 |
DG_Logger::writeLog( DG_LogLevel::Detail, $toLog );
|
93 |
}
|
94 |
|
95 |
-
if ( self::thumbnailGenerationHarness( $thumber, $ID, $pg ) ) {
|
96 |
break;
|
97 |
}
|
98 |
}
|
99 |
}
|
100 |
}
|
101 |
|
102 |
-
$thumb = DG_Thumb::getThumb( $ID, $dimensions );
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
}
|
107 |
-
|
108 |
-
// fallback to default thumb for attachment type
|
109 |
-
$url = self::getDefaultThumbnail( $ID, $pg );
|
110 |
-
$is_default = true;
|
111 |
-
} else {
|
112 |
-
$url = $thumb->getUrl();
|
113 |
-
$is_default = false;
|
114 |
}
|
115 |
|
116 |
-
return $
|
117 |
}
|
118 |
|
119 |
-
/*==========================================================================
|
120 |
-
* AUDIO VIDEO THUMBNAILS
|
121 |
-
*=========================================================================*/
|
122 |
-
|
123 |
/**
|
124 |
-
*
|
125 |
-
* an embedded image to use as a thumbnail.
|
126 |
-
*
|
127 |
-
* @param string $ID The attachment ID to retrieve thumbnail from.
|
128 |
-
* @param int $pg Unused.
|
129 |
-
*
|
130 |
-
* @return bool|string False on failure, URL to thumb on success.
|
131 |
*/
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
$attachment = get_post( $ID );
|
136 |
-
$doc_path = get_attached_file( $ID );
|
137 |
-
|
138 |
-
if ( preg_match( '#^video/#', get_post_mime_type( $attachment ) ) ) {
|
139 |
-
$metadata = wp_read_video_metadata( $doc_path );
|
140 |
-
} elseif ( preg_match( '#^audio/#', get_post_mime_type( $attachment ) ) ) {
|
141 |
-
$metadata = wp_read_audio_metadata( $doc_path );
|
142 |
-
}
|
143 |
-
|
144 |
-
// unsupported mime type || no embedded image present
|
145 |
-
if ( ! isset( $metadata ) || empty( $metadata['image']['data'] ) ) {
|
146 |
-
return false;
|
147 |
-
}
|
148 |
-
|
149 |
-
$ext = 'jpg';
|
150 |
-
switch ( $metadata['image']['mime'] ) {
|
151 |
-
case 'image/gif':
|
152 |
-
$ext = 'gif';
|
153 |
-
break;
|
154 |
-
case 'image/png':
|
155 |
-
$ext = 'png';
|
156 |
-
break;
|
157 |
-
}
|
158 |
-
|
159 |
-
$temp_file = self::getTempFile( $ext );
|
160 |
-
|
161 |
-
if ( ! $fp = @fopen( $temp_file, 'wb' ) ) {
|
162 |
-
DG_Logger::writeLog( DG_LogLevel::Error, __( 'Could not open file: ', 'document-gallery' ) . $temp_file );
|
163 |
-
|
164 |
-
return false;
|
165 |
-
}
|
166 |
-
|
167 |
-
if ( ! @fwrite( $fp, $metadata['image']['data'] ) ) {
|
168 |
-
DG_Logger::writeLog( DG_LogLevel::Error, __( 'Could not write file: ', 'document-gallery' ) . $temp_file );
|
169 |
-
fclose( $fp );
|
170 |
-
|
171 |
-
return false;
|
172 |
-
}
|
173 |
-
|
174 |
-
fclose( $fp );
|
175 |
-
|
176 |
-
return $temp_file;
|
177 |
}
|
178 |
|
179 |
/**
|
180 |
-
* @return
|
181 |
*/
|
182 |
-
|
183 |
-
|
184 |
}
|
185 |
|
186 |
-
/*==========================================================================
|
187 |
-
* IMAGICK THUMBNAILS
|
188 |
-
*=========================================================================*/
|
189 |
-
|
190 |
/**
|
191 |
-
*
|
192 |
*
|
193 |
-
* @param
|
194 |
-
*
|
195 |
*
|
196 |
-
* @return bool
|
197 |
*/
|
198 |
-
public static function
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
$err = $img->load();
|
204 |
-
if ( is_wp_error( $err ) ) {
|
205 |
-
DG_Logger::writeLog(
|
206 |
-
DG_LogLevel::Error,
|
207 |
-
__( 'Failed to open file in Imagick: ', 'document-gallery' ) .
|
208 |
-
$err->get_error_message() );
|
209 |
-
|
210 |
-
return false;
|
211 |
-
}
|
212 |
-
|
213 |
-
$temp_file = self::getTempFile();
|
214 |
-
|
215 |
-
$err = $img->save( $temp_file, 'image/png' );
|
216 |
-
if ( is_wp_error( $err ) ) {
|
217 |
-
DG_Logger::writeLog(
|
218 |
-
DG_LogLevel::Error,
|
219 |
-
__( 'Failed to save image in Imagick: ', 'document-gallery' ) .
|
220 |
-
$err->get_error_message() );
|
221 |
-
|
222 |
-
return false;
|
223 |
-
}
|
224 |
-
|
225 |
-
return $temp_file;
|
226 |
-
}
|
227 |
-
|
228 |
-
/**
|
229 |
-
* @return bool Whether WP_Image_Editor_Imagick can be used on this system.
|
230 |
-
*/
|
231 |
-
public static function isImagickAvailable() {
|
232 |
-
static $ret = null;
|
233 |
-
|
234 |
-
if ( is_null( $ret ) ) {
|
235 |
-
include_once DG_WPINC_PATH . 'class-wp-image-editor.php';
|
236 |
-
include_once DG_WPINC_PATH . 'class-wp-image-editor-imagick.php';
|
237 |
-
$ret = WP_Image_Editor_Imagick::test();
|
238 |
}
|
239 |
|
240 |
-
return
|
|
|
|
|
|
|
|
|
|
|
241 |
}
|
242 |
|
243 |
-
/*==========================================================================
|
244 |
-
* GHOSTSCRIPT THUMBNAILS
|
245 |
-
*=========================================================================*/
|
246 |
-
|
247 |
/**
|
248 |
-
*
|
249 |
-
* also handle this, but is *much* slower.
|
250 |
*
|
251 |
-
* @param int $ID
|
252 |
-
* @param
|
|
|
253 |
*
|
254 |
-
* @return bool
|
255 |
-
*/
|
256 |
-
public static function getGhostscriptThumbnail( $ID, $pg = 1 ) {
|
257 |
-
static $gs = null;
|
258 |
-
|
259 |
-
if ( is_null( $gs ) ) {
|
260 |
-
$options = self::getOptions();
|
261 |
-
$gs = $options['gs'];
|
262 |
-
|
263 |
-
if ( false !== $gs ) {
|
264 |
-
$gs = escapeshellarg( $gs ) . ' -sDEVICE=png16m -dFirstPage=%1$d'
|
265 |
-
. ' -dLastPage=%1$d -dBATCH -dNOPAUSE -dPDFFitPage -sOutputFile=%2$s %3$s 2>&1';
|
266 |
-
}
|
267 |
-
}
|
268 |
-
|
269 |
-
if ( false === $gs ) {
|
270 |
-
return false;
|
271 |
-
}
|
272 |
-
|
273 |
-
$doc_path = get_attached_file( $ID );
|
274 |
-
$temp_path = self::getTempFile();
|
275 |
-
|
276 |
-
exec( sprintf( $gs, $pg, $temp_path, $doc_path ), $out, $ret );
|
277 |
-
|
278 |
-
if ( $ret != 0 ) {
|
279 |
-
DG_Logger::writeLog( DG_LogLevel::Error, __( 'Ghostscript failed: ', 'document-gallery' ) . print_r( $out ) );
|
280 |
-
@unlink( $temp_path );
|
281 |
-
|
282 |
-
return false;
|
283 |
-
}
|
284 |
-
|
285 |
-
return $temp_path;
|
286 |
-
}
|
287 |
-
|
288 |
-
/**
|
289 |
-
* @return array All extensions supported by Ghostscript.
|
290 |
*/
|
291 |
-
|
292 |
-
return
|
293 |
}
|
294 |
|
295 |
/**
|
296 |
-
*
|
297 |
-
*
|
298 |
-
* NOTE: This does not check the options for gs path. Don't use in
|
299 |
-
* thumbnail generation as it's slow and not configurable.
|
300 |
*
|
301 |
-
* @
|
302 |
-
|
303 |
-
public static function getGhostscriptExecutable() {
|
304 |
-
static $executable = null;
|
305 |
-
|
306 |
-
if ( is_null( $executable ) ) {
|
307 |
-
// we must be able to exec()
|
308 |
-
$executable = self::isExecAvailable();
|
309 |
-
if ( ! $executable ) {
|
310 |
-
return $executable;
|
311 |
-
}
|
312 |
-
|
313 |
-
// find on Windows system
|
314 |
-
if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) ) {
|
315 |
-
// look for environment variable
|
316 |
-
$executable = getenv( 'GSC' );
|
317 |
-
if ( $executable ) {
|
318 |
-
return $executable;
|
319 |
-
}
|
320 |
-
|
321 |
-
// hope GS in the path
|
322 |
-
$executable = exec( 'where gswin*c.exe' );
|
323 |
-
if ( ! empty( $executable ) ) {
|
324 |
-
return $executable;
|
325 |
-
}
|
326 |
-
|
327 |
-
// look directly in filesystem
|
328 |
-
// 64- or 32-bit binary
|
329 |
-
$executable = exec( 'dir /o:n/s/b "C:\Program Files\gs\*gswin*c.exe"' );
|
330 |
-
if ( ! empty( $executable ) ) {
|
331 |
-
return $executable;
|
332 |
-
}
|
333 |
-
|
334 |
-
// 32-bit binary on 64-bit OS
|
335 |
-
$executable = exec( 'dir /o:n/s/b "C:\Program Files (x86)\gs\*gswin32c.exe"' );
|
336 |
-
$executable = empty( $executable ) ? false : $executable;
|
337 |
-
|
338 |
-
return $executable;
|
339 |
-
}
|
340 |
-
|
341 |
-
// handle Linux systems
|
342 |
-
$executable = exec( 'which gs' );
|
343 |
-
if ( ! empty( $executable ) ) {
|
344 |
-
return $executable;
|
345 |
-
}
|
346 |
-
|
347 |
-
// GoDaddy and others aren't setup in such a way that
|
348 |
-
// the above works so we need to fallback to a direct
|
349 |
-
// filesystem check in most common location
|
350 |
-
exec( 'test -e /usr/bin/gs', $dummy, $ret );
|
351 |
-
$executable = ( $ret === 0 ) ? '/usr/bin/gs' : false;
|
352 |
-
|
353 |
-
return $executable;
|
354 |
-
}
|
355 |
-
|
356 |
-
return $executable;
|
357 |
-
}
|
358 |
-
|
359 |
-
/**
|
360 |
-
* @return bool Whether we can use the GS executable.
|
361 |
*/
|
362 |
-
public static function
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
|
370 |
-
return $
|
371 |
}
|
372 |
|
373 |
/*==========================================================================
|
374 |
-
*
|
375 |
*=========================================================================*/
|
376 |
|
377 |
/**
|
378 |
-
*
|
379 |
-
*
|
380 |
-
* @param string $ID The attachment ID to retrieve thumbnail from.
|
381 |
-
* @param int $pg Unused.
|
382 |
-
*
|
383 |
-
* @return string URL to thumbnail.
|
384 |
-
*/
|
385 |
-
public static function getDefaultThumbnail( $ID, $pg = 1 ) {
|
386 |
-
$options = self::getOptions();
|
387 |
-
$width = $options['width'];
|
388 |
-
$height = $options['height'];
|
389 |
-
$icon_url = DG_URL . 'assets/icons/';
|
390 |
-
|
391 |
-
// handle images
|
392 |
-
if ( $icon = image_downsize( $ID, array( $width, $height ) ) ) {
|
393 |
-
$icon = $icon[0];
|
394 |
-
} // default extension icon
|
395 |
-
elseif ( $name = self::getDefaultIcon( self::getExt( wp_get_attachment_url( $ID ) ) ) ) {
|
396 |
-
$icon = $icon_url . $name;
|
397 |
-
} // fallback to standard WP icons
|
398 |
-
elseif ( ! $icon = wp_mime_type_icon( $ID ) ) {
|
399 |
-
// everything failed. This is bad...
|
400 |
-
$icon = $icon_url . 'missing.png';
|
401 |
-
}
|
402 |
-
|
403 |
-
return $icon;
|
404 |
-
}
|
405 |
-
|
406 |
-
/**
|
407 |
-
* Returns the name of the image to represent the filetype given.
|
408 |
-
*
|
409 |
-
* @param string $ext
|
410 |
-
*
|
411 |
-
* @return string Default icon based on extension.
|
412 |
*/
|
413 |
-
|
414 |
-
|
415 |
-
static $exts = array(
|
416 |
-
// Most Common First
|
417 |
-
'pdf' => 'pdf.png',
|
418 |
-
// MS Office
|
419 |
-
'doc|docx|docm|dotx|dotm' => 'msdoc.png',
|
420 |
-
'ppt|pot|pps|pptx|pptm|ppsx|ppsm|potx|potm|ppam|sldx|sldm' => 'msppt.png',
|
421 |
-
'xla|xls|xlt|xlw|xlsx|xlsm|xlsb|xltx|xltm|xlam' => 'msxls.png',
|
422 |
-
'mdb' => 'msaccess.png',
|
423 |
-
// iWork
|
424 |
-
'key' => 'key.png',
|
425 |
-
'numbers' => 'numbers.png',
|
426 |
-
'pages' => 'pages.png',
|
427 |
-
// Images
|
428 |
-
'jpg|jpeg|jpe|gif|png|bmp|tif|tiff|ico' => 'image.png',
|
429 |
-
// Video formats
|
430 |
-
'asf|asx|wmv|wmx|wm|avi|divx|flv|mov' => 'video.png',
|
431 |
-
'qt|mpeg|mpg|mpe|mp4|m4v|ogv|webm|mkv' => 'video.png',
|
432 |
-
// Audio formats
|
433 |
-
'mp3|m4a|m4b|ra|ram|wav|ogg|oga|wma|wax|mka' => 'audio.png',
|
434 |
-
'midi|mid' => 'midi.png',
|
435 |
-
// Text formats
|
436 |
-
'txt|tsv|csv' => 'text.png',
|
437 |
-
'rtx' => 'rtx.png',
|
438 |
-
'rtf' => 'rtf.png',
|
439 |
-
'ics' => 'ics.png',
|
440 |
-
'wp|wpd' => 'wordperfect.png',
|
441 |
-
// Programming
|
442 |
-
'html|htm' => 'html.png',
|
443 |
-
'css' => 'css.png',
|
444 |
-
'js' => 'javascript.png',
|
445 |
-
'class' => 'java.png',
|
446 |
-
'asc' => 'asc.png',
|
447 |
-
'c' => 'c.png',
|
448 |
-
'cc|cpp' => 'cpp.png',
|
449 |
-
'h' => 'h.png',
|
450 |
-
// Msc application formats
|
451 |
-
'zip|tar|gzip|gz|bz2|tgz|7z|rar' => 'compressed.png',
|
452 |
-
'exe' => 'exec.png',
|
453 |
-
'swf' => 'shockwave.png',
|
454 |
-
// OpenDocument formats
|
455 |
-
'odt' => 'opendocument-text.png',
|
456 |
-
'odp' => 'opendocument-presentation.png',
|
457 |
-
'ods' => 'opendocument-spreadsheet.png',
|
458 |
-
'odg' => 'opendocument-graphics.png',
|
459 |
-
'odb' => 'opendocument-database.png',
|
460 |
-
'odf' => 'opendocument-formula.png'
|
461 |
-
);
|
462 |
-
|
463 |
-
foreach ( $exts as $ext_preg => $icon ) {
|
464 |
-
$ext_preg = '!(' . $ext_preg . ')$!i';
|
465 |
-
if ( preg_match( $ext_preg, $ext ) ) {
|
466 |
-
return $icon;
|
467 |
-
}
|
468 |
-
}
|
469 |
|
470 |
-
return
|
471 |
}
|
472 |
|
473 |
-
/*==========================================================================
|
474 |
-
* GENERAL THUMBNAIL HELPER FUNCTIONS
|
475 |
-
*=========================================================================*/
|
476 |
-
|
477 |
/**
|
478 |
-
* @return
|
479 |
*/
|
480 |
public static function getThumbed() {
|
481 |
$thumbs = DG_Thumb::getThumbs();
|
@@ -491,37 +166,6 @@ class DG_Thumber {
|
|
491 |
return get_posts( $args );
|
492 |
}
|
493 |
|
494 |
-
/**
|
495 |
-
* Key: Attachment ID
|
496 |
-
* Val: array
|
497 |
-
* + timestamp - When the thumbnail was generated (or generation failed).
|
498 |
-
* + thumb_path - System path to thumbnail image.
|
499 |
-
* + thumb_url - URL pointing to the thumbnail for this document.
|
500 |
-
* + thumber - Generator used to create thumb OR false if failed to gen.
|
501 |
-
* @return array|null Thumber options from DB or null if options not initialized.
|
502 |
-
*/
|
503 |
-
public static function getOptions( $blog = null ) {
|
504 |
-
$options = DocumentGallery::getOptions( $blog );
|
505 |
-
|
506 |
-
return $options['thumber'];
|
507 |
-
}
|
508 |
-
|
509 |
-
/**
|
510 |
-
* Key: Attachment ID
|
511 |
-
* Val: array
|
512 |
-
* + timestamp - When the thumbnail was generated (or generation failed).
|
513 |
-
* + thumb_path - System path to thumbnail image.
|
514 |
-
* + thumb_url - URL pointing to the thumbnail for this document.
|
515 |
-
* + thumber - Generator used to create thumb OR false if failed to gen.
|
516 |
-
*
|
517 |
-
* @param array $options Thumber options to store in DB
|
518 |
-
*/
|
519 |
-
private static function setOptions( $options, $blog = null ) {
|
520 |
-
$dg_options = DocumentGallery::getOptions( $blog );
|
521 |
-
$dg_options['thumber'] = $options;
|
522 |
-
DocumentGallery::setOptions( $dg_options, $blog );
|
523 |
-
}
|
524 |
-
|
525 |
/**
|
526 |
* @filter dg_thumbers Allows developers to filter the Thumbers used
|
527 |
* for specific filetypes. Index is the regex to match file extensions
|
@@ -530,59 +174,26 @@ class DG_Thumber {
|
|
530 |
* to get a thumbnail for, 2nd is the page to take a thumbnail of
|
531 |
* (may not be relevant for some filetypes).
|
532 |
*
|
533 |
-
* @return
|
534 |
*/
|
535 |
private static function getThumbers() {
|
536 |
static $thumbers = null;
|
537 |
|
538 |
if ( is_null( $thumbers ) ) {
|
539 |
-
$options = self::getOptions();
|
540 |
-
$active = $options['active'];
|
541 |
-
$thumbers = array();
|
542 |
-
|
543 |
-
// Audio/Video embedded images
|
544 |
-
if ( $active['av'] ) {
|
545 |
-
$exts = implode( '|', self::getAudioVideoExts() );
|
546 |
-
$thumbers[ $exts ] = array( __CLASS__, 'getAudioVideoThumbnail' );
|
547 |
-
}
|
548 |
-
|
549 |
-
// Ghostscript
|
550 |
-
if ( $active['gs'] && self::isGhostscriptAvailable() ) {
|
551 |
-
$exts = implode( '|', self::getGhostscriptExts() );
|
552 |
-
$thumbers[ $exts ] = array( __CLASS__, 'getGhostscriptThumbnail' );
|
553 |
-
}
|
554 |
-
|
555 |
-
// Imagick
|
556 |
-
if ( $active['imagick'] && self::isImagickAvailable() ) {
|
557 |
-
include_once DG_PATH . 'inc/class-image-editor-imagick.php';
|
558 |
-
if ( $exts = DG_Image_Editor_Imagick::query_formats() ) {
|
559 |
-
$exts = implode( '|', $exts );
|
560 |
-
$thumbers[ $exts ] = array( __CLASS__, 'getImagickThumbnail' );
|
561 |
-
}
|
562 |
-
}
|
563 |
-
|
564 |
// allow users to filter thumbers used
|
565 |
-
$thumbers = apply_filters( 'dg_thumbers',
|
566 |
-
|
567 |
-
|
568 |
-
$thumbers = array_filter( $thumbers, 'is_callable' );
|
569 |
|
570 |
// log which thumbers are being used
|
571 |
if ( DG_Logger::logEnabled() ) {
|
572 |
if ( count( $thumbers ) > 0 ) {
|
573 |
-
$
|
574 |
-
|
575 |
-
$thumber = DG_Util::callableToString($v);
|
576 |
-
|
577 |
-
// TODO: The following works for all internal regexes, but may have unpredictable
|
578 |
-
// results if developer adds additional thumbnail generators using different regexes
|
579 |
-
$filetypes = str_replace( '|', ', ', $k );
|
580 |
-
|
581 |
-
$entry .= PHP_EOL . "$thumber: $filetypes";
|
582 |
-
}
|
583 |
} else {
|
584 |
$entry = __( 'No thumbnail generators enabled.', 'document-gallery' );
|
585 |
}
|
|
|
586 |
DG_Logger::writeLog( DG_LogLevel::Detail, $entry );
|
587 |
}
|
588 |
}
|
@@ -590,13 +201,28 @@ class DG_Thumber {
|
|
590 |
return $thumbers;
|
591 |
}
|
592 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
593 |
/**
|
594 |
* Template that handles generating a thumbnail.
|
595 |
*
|
596 |
* If image has already been generated through other means, $pg may be set to the system path where the
|
597 |
* thumbnail is located. In this case, $generator will not be invoked, but *will* be kept for historical purposes.
|
598 |
*
|
599 |
-
* @param
|
600 |
* @param int $ID ID for the attachment that we need a thumbnail for.
|
601 |
* @param int|string $pg Page number of the attachment to get a thumbnail for or the system path to the image to be used.
|
602 |
*
|
@@ -606,8 +232,15 @@ class DG_Thumber {
|
|
606 |
// handle system page in $pg variable
|
607 |
if ( is_string( $pg ) && ! is_numeric( $pg ) ) {
|
608 |
$temp_path = $pg;
|
609 |
-
}
|
610 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
611 |
return false;
|
612 |
}
|
613 |
|
@@ -659,31 +292,12 @@ class DG_Thumber {
|
|
659 |
$thumb->setDimensions( $options['width'] . 'x' . $options['height'] );
|
660 |
$thumb->setTimestamp( time() );
|
661 |
$thumb->setRelativePath( substr( $thumb_path, strlen( $upload['basedir'] ) + 1 ) );
|
662 |
-
$thumb->setGenerator(
|
663 |
$thumb->save();
|
664 |
|
665 |
return $thumb;
|
666 |
}
|
667 |
|
668 |
-
/**
|
669 |
-
* Caller should handle removal of the temp file when finished.
|
670 |
-
*
|
671 |
-
* @param string $ext The extension to be given to the temp file.
|
672 |
-
*
|
673 |
-
* @return string A temp file with the given extension.
|
674 |
-
*/
|
675 |
-
private static function getTempFile( $ext = 'png' ) {
|
676 |
-
static $base = null;
|
677 |
-
static $tmp;
|
678 |
-
|
679 |
-
if ( is_null( $base ) ) {
|
680 |
-
$base = md5( time() );
|
681 |
-
$tmp = untrailingslashit( get_temp_dir() );
|
682 |
-
}
|
683 |
-
|
684 |
-
return $tmp . DIRECTORY_SEPARATOR . wp_unique_filename( $tmp, $base . '.' . $ext );
|
685 |
-
}
|
686 |
-
|
687 |
/**
|
688 |
* Constructs name for file's thumbnail, ensuring that it does not conflict
|
689 |
* with any existing file.
|
@@ -697,71 +311,9 @@ class DG_Thumber {
|
|
697 |
private static function getUniqueThumbName( $dirname, $extless, $ext = 'png' ) {
|
698 |
return wp_unique_filename( $dirname, str_replace( '.', '-', $extless ) . '-thumb.' . $ext );
|
699 |
}
|
|
|
700 |
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
*
|
705 |
-
* @return bool Whether exec() is available.
|
706 |
-
*/
|
707 |
-
public static function isExecAvailable() {
|
708 |
-
static $available = null;
|
709 |
-
|
710 |
-
if ( is_null( $available ) ) {
|
711 |
-
$available = true;
|
712 |
-
|
713 |
-
if ( ini_get( 'safe_mode' ) ) {
|
714 |
-
$available = false;
|
715 |
-
} else {
|
716 |
-
$d = ini_get( 'disable_functions' );
|
717 |
-
$s = ini_get( 'suhosin.executor.func.blacklist' );
|
718 |
-
if ( "$d$s" ) {
|
719 |
-
$array = preg_split( '/,\s*/', "$d,$s" );
|
720 |
-
$available = ! in_array( 'exec', $array );
|
721 |
-
}
|
722 |
-
}
|
723 |
-
}
|
724 |
-
|
725 |
-
return $available;
|
726 |
-
}
|
727 |
-
|
728 |
-
/**
|
729 |
-
* Formerly achieved with wp_check_filetype(), but it was only returning
|
730 |
-
* valid results if the active user had permission to upload the given filetype.
|
731 |
-
*
|
732 |
-
* @param string $filename Name of the file to get extension from.
|
733 |
-
*
|
734 |
-
* @return bool|string Returns the file extension on success, false on failure.
|
735 |
-
*/
|
736 |
-
private static function getExt( $filename ) {
|
737 |
-
if ( $ext = pathinfo( $filename, PATHINFO_EXTENSION ) ) {
|
738 |
-
$res = preg_grep( '/^(?:.*\|)?' . $ext . '(?:\|.*)?$/i', self::getAllExts() );
|
739 |
-
$res = reset( $res );
|
740 |
-
if ( $res === false ) {
|
741 |
-
$ext = false;
|
742 |
-
}
|
743 |
-
}
|
744 |
-
|
745 |
-
if ( ! $ext && ( $info = getimagesize( $filename ) ) && ( $ext = image_type_to_extension( $info[2], false ) ) ) {
|
746 |
-
return $ext;
|
747 |
-
}
|
748 |
-
|
749 |
-
return $ext;
|
750 |
-
}
|
751 |
-
|
752 |
-
/**
|
753 |
-
* Addresses issues with getting a complete list of supported MIME types as
|
754 |
-
* described in this issue: https://core.trac.wordpress.org/ticket/32544
|
755 |
-
* @return array Contains all MIME types supported by WordPress, including custom types added by plugins.
|
756 |
-
*/
|
757 |
-
private static function getAllExts() {
|
758 |
-
return array_keys( array_merge( wp_get_mime_types(), get_allowed_mime_types() ) );
|
759 |
-
}
|
760 |
-
|
761 |
-
/**
|
762 |
-
* Blocks instantiation. All functions are static.
|
763 |
-
*/
|
764 |
-
private function __construct() {
|
765 |
-
|
766 |
-
}
|
767 |
}
|
1 |
<?php
|
2 |
defined( 'WPINC' ) OR exit;
|
3 |
|
4 |
+
// NOTE: Child thumbers are included at bottom of this file
|
5 |
+
include_once DG_PATH . 'inc/thumbers/class-abstract-thumber.php';
|
6 |
+
|
7 |
/**
|
8 |
* Thumber wraps the functionality required to
|
9 |
* generate thumbnails for arbitrary documents.
|
10 |
*
|
11 |
* @author drossiter
|
12 |
*/
|
13 |
+
class DG_Thumber extends DG_AbstractThumber {
|
14 |
|
15 |
/**
|
16 |
+
* @var DG_Thumber The singleton instance.
|
|
|
|
|
|
|
|
|
|
|
17 |
*/
|
18 |
+
private static $instance;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
/**
|
21 |
+
* @return DG_Thumber The singleton instance.
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
*/
|
23 |
+
public static function getInstance() {
|
24 |
+
return isset( self::$instance ) ? self::$instance : ( self::$instance = new DG_Thumber() );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
}
|
26 |
|
27 |
/**
|
34 |
*
|
35 |
* @return string URL to the thumbnail.
|
36 |
*/
|
37 |
+
public function getThumbnail( $ID, $pg = 1, $generate_if_missing = true, &$is_default = null ) {
|
38 |
$options = self::getOptions();
|
39 |
$dimensions = $options['width'] . 'x' . $options['height'];
|
40 |
|
45 |
return null;
|
46 |
}
|
47 |
|
48 |
+
foreach ( self::getThumbers() as $thumber ) {
|
49 |
+
if ( $thumber->supportsAttachment( $ID ) ) {
|
|
|
|
|
|
|
|
|
|
|
50 |
if ( DG_Logger::logEnabled() ) {
|
51 |
$toLog = sprintf( __( 'Attempting to generate thumbnail for attachment #%d with (%s)',
|
52 |
+
'document-gallery' ), $ID, get_class( $thumber ) );
|
53 |
DG_Logger::writeLog( DG_LogLevel::Detail, $toLog );
|
54 |
}
|
55 |
|
56 |
+
if ( $generated = self::thumbnailGenerationHarness( $thumber, $ID, $pg ) ) {
|
57 |
break;
|
58 |
}
|
59 |
}
|
60 |
}
|
61 |
}
|
62 |
|
63 |
+
$thumb = isset( $generated ) ? $generated : DG_Thumb::getThumb( $ID, $dimensions );
|
64 |
+
$is_default = ! isset( $thumb ) || ! $thumb->isSuccess();
|
65 |
+
if ( ! isset( $thumb ) ) {
|
66 |
+
$thumb = self::setThumbnailFailed( $ID );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
}
|
68 |
|
69 |
+
return $thumb->isSuccess() ? $thumb->getUrl() : DG_DefaultThumber::getInstance()->getThumbnail( $ID, $pg );
|
70 |
}
|
71 |
|
|
|
|
|
|
|
|
|
72 |
/**
|
73 |
+
* @return string[] The extensions supported by this thumber.
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
*/
|
75 |
+
protected function getThumberExtensions() {
|
76 |
+
throw new BadFunctionCallException( 'Not implemented.' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
}
|
78 |
|
79 |
/**
|
80 |
+
* @return int An integer from 0 to 100. Higher priorities will be attempted before lower priority thumbers.
|
81 |
*/
|
82 |
+
public function getPriority() {
|
83 |
+
throw new BadFunctionCallException( 'Not implemented.' );
|
84 |
}
|
85 |
|
|
|
|
|
|
|
|
|
86 |
/**
|
87 |
+
* Returns the default mapping of thumber slug to whether it is active or not.
|
88 |
*
|
89 |
+
* @param $skeleton bool When true, values that require computation will be
|
90 |
+
* skipped. Useful when only structure of options is needed.
|
91 |
*
|
92 |
+
* @return bool[] The default thumbnail generation methods.
|
93 |
*/
|
94 |
+
public static function getDefaultThumbers( $skeleton = false ) {
|
95 |
+
$gs_active = $imagick_active = null;
|
96 |
+
if ( ! $skeleton ) {
|
97 |
+
$gs_active = (bool) DG_GhostscriptThumber::getGhostscriptExecutable();
|
98 |
+
$imagick_active = DG_ImagickThumber::isImagickAvailable();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
}
|
100 |
|
101 |
+
return array(
|
102 |
+
'av' => true,
|
103 |
+
'gs' => $gs_active,
|
104 |
+
'imagick' => $imagick_active,
|
105 |
+
'thumber-co' => false
|
106 |
+
);
|
107 |
}
|
108 |
|
|
|
|
|
|
|
|
|
109 |
/**
|
110 |
+
* Sets the thumbnail for the given attachment ID.
|
|
|
111 |
*
|
112 |
+
* @param int $ID Document ID.
|
113 |
+
* @param string $path System path to thumbnail.
|
114 |
+
* @param string $generator Descriptor for generation method -- usually method name.
|
115 |
*
|
116 |
+
* @return DG_Thumb|bool Thumb on success, false on failure.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
*/
|
118 |
+
public static function setThumbnail( $ID, $path, $generator = 'unknown' ) {
|
119 |
+
return self::thumbnailGenerationHarness( $generator, $ID, $path );
|
120 |
}
|
121 |
|
122 |
/**
|
123 |
+
* Sets the thumbnail for the given attachment ID to a failed state.
|
|
|
|
|
|
|
124 |
*
|
125 |
+
* @param int $ID Document ID.
|
126 |
+
* @return DG_Thumb The failed thumbnail.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
*/
|
128 |
+
public static function setThumbnailFailed( $ID ) {
|
129 |
+
$options = self::getOptions();
|
130 |
+
$thumb = new DG_Thumb();
|
131 |
+
$thumb->setPostId( $ID );
|
132 |
+
$thumb->setTimestamp( time() );
|
133 |
+
$thumb->setDimensions( $options['width'] . 'x' . $options['height'] );
|
134 |
+
$thumb->save();
|
135 |
|
136 |
+
return $thumb;
|
137 |
}
|
138 |
|
139 |
/*==========================================================================
|
140 |
+
* GENERAL THUMBNAIL HELPER FUNCTIONS
|
141 |
*=========================================================================*/
|
142 |
|
143 |
/**
|
144 |
+
* @return mixed[]|null Thumber options from DB or null if options not initialized.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
*/
|
146 |
+
public static function getOptions( $blog = null ) {
|
147 |
+
$options = DocumentGallery::getOptions( $blog );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
148 |
|
149 |
+
return $options['thumber'];
|
150 |
}
|
151 |
|
|
|
|
|
|
|
|
|
152 |
/**
|
153 |
+
* @return WP_Post[] Each attachment that has been processed.
|
154 |
*/
|
155 |
public static function getThumbed() {
|
156 |
$thumbs = DG_Thumb::getThumbs();
|
166 |
return get_posts( $args );
|
167 |
}
|
168 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
/**
|
170 |
* @filter dg_thumbers Allows developers to filter the Thumbers used
|
171 |
* for specific filetypes. Index is the regex to match file extensions
|
174 |
* to get a thumbnail for, 2nd is the page to take a thumbnail of
|
175 |
* (may not be relevant for some filetypes).
|
176 |
*
|
177 |
+
* @return DG_AbstractThumber[]
|
178 |
*/
|
179 |
private static function getThumbers() {
|
180 |
static $thumbers = null;
|
181 |
|
182 |
if ( is_null( $thumbers ) ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
// allow users to filter thumbers used
|
184 |
+
$thumbers = apply_filters( 'dg_thumbers', array() );
|
185 |
+
$thumbers = array_filter( $thumbers, array( __CLASS__, 'isThumber' ) );
|
186 |
+
usort( $thumbers, array( 'DG_AbstractThumber', 'cmpThumberByPriority' ) );
|
|
|
187 |
|
188 |
// log which thumbers are being used
|
189 |
if ( DG_Logger::logEnabled() ) {
|
190 |
if ( count( $thumbers ) > 0 ) {
|
191 |
+
$names = array_map( 'get_class', $thumbers );
|
192 |
+
$entry = __( 'Thumbnail Generators: ', 'document-gallery' ) . implode( ', ', $names );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
} else {
|
194 |
$entry = __( 'No thumbnail generators enabled.', 'document-gallery' );
|
195 |
}
|
196 |
+
|
197 |
DG_Logger::writeLog( DG_LogLevel::Detail, $entry );
|
198 |
}
|
199 |
}
|
201 |
return $thumbers;
|
202 |
}
|
203 |
|
204 |
+
/**
|
205 |
+
* @param $maybe_thumber mixed Variable to be tested.
|
206 |
+
* @return bool Whether given variable is a thumber.
|
207 |
+
*/
|
208 |
+
private static function isThumber( $maybe_thumber ) {
|
209 |
+
$ret = is_a( $maybe_thumber, 'DG_AbstractThumber' );
|
210 |
+
if ( !$ret ) {
|
211 |
+
DG_Logger::writeLog(
|
212 |
+
DG_LogLevel::Error,
|
213 |
+
'Attempted to add non-DG_AbstractThumber in thumbnail generation: ' . print_r( $maybe_thumber, true ) );
|
214 |
+
}
|
215 |
+
|
216 |
+
return $ret;
|
217 |
+
}
|
218 |
+
|
219 |
/**
|
220 |
* Template that handles generating a thumbnail.
|
221 |
*
|
222 |
* If image has already been generated through other means, $pg may be set to the system path where the
|
223 |
* thumbnail is located. In this case, $generator will not be invoked, but *will* be kept for historical purposes.
|
224 |
*
|
225 |
+
* @param DG_AbstractThumber|string $generator Takes ID and pg and returns path to temp file or false.
|
226 |
* @param int $ID ID for the attachment that we need a thumbnail for.
|
227 |
* @param int|string $pg Page number of the attachment to get a thumbnail for or the system path to the image to be used.
|
228 |
*
|
232 |
// handle system page in $pg variable
|
233 |
if ( is_string( $pg ) && ! is_numeric( $pg ) ) {
|
234 |
$temp_path = $pg;
|
235 |
+
} elseif ( is_a( $generator, 'DG_AbstractThumber' ) ) {
|
236 |
+
// delegate thumbnail generation to $generator
|
237 |
+
if ( false === ( $temp_path = $generator->getThumbnail( $ID, $pg ) ) ) {
|
238 |
+
return false;
|
239 |
+
}
|
240 |
+
} else {
|
241 |
+
DG_Logger::writeLog(
|
242 |
+
DG_LogLevel::Error,
|
243 |
+
'Attempted to call thumbnailGenerationHarness with invalid generator: ' . print_r( $generator, true ) );
|
244 |
return false;
|
245 |
}
|
246 |
|
292 |
$thumb->setDimensions( $options['width'] . 'x' . $options['height'] );
|
293 |
$thumb->setTimestamp( time() );
|
294 |
$thumb->setRelativePath( substr( $thumb_path, strlen( $upload['basedir'] ) + 1 ) );
|
295 |
+
$thumb->setGenerator( get_class( $generator ) );
|
296 |
$thumb->save();
|
297 |
|
298 |
return $thumb;
|
299 |
}
|
300 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
301 |
/**
|
302 |
* Constructs name for file's thumbnail, ensuring that it does not conflict
|
303 |
* with any existing file.
|
311 |
private static function getUniqueThumbName( $dirname, $extless, $ext = 'png' ) {
|
312 |
return wp_unique_filename( $dirname, str_replace( '.', '-', $extless ) . '-thumb.' . $ext );
|
313 |
}
|
314 |
+
}
|
315 |
|
316 |
+
// include all internal DG thumbers
|
317 |
+
foreach ( glob( DG_PATH . 'inc/thumbers/*.php' ) as $path ) {
|
318 |
+
include_once $path;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
}
|
inc/class-util.php
CHANGED
@@ -28,7 +28,7 @@ class DG_Util {
|
|
28 |
}
|
29 |
|
30 |
/**
|
31 |
-
* @return
|
32 |
*/
|
33 |
public static function getBlogIds() {
|
34 |
global $wpdb;
|
@@ -36,12 +36,30 @@ class DG_Util {
|
|
36 |
}
|
37 |
|
38 |
/**
|
39 |
-
*
|
|
|
|
|
40 |
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
* @return int A positive integer.
|
42 |
*/
|
43 |
-
public static function posint($maybeint) {
|
44 |
-
return max(absint($maybeint), 1);
|
45 |
}
|
46 |
|
47 |
/**
|
@@ -49,7 +67,6 @@ class DG_Util {
|
|
49 |
*
|
50 |
* @param mixed $val To be converted.
|
51 |
* @param bool|NULL $default The value to return if unable to parse $val.
|
52 |
-
*
|
53 |
* @return bool|NULL Bool value if can be parsed, else NULL.
|
54 |
*/
|
55 |
public static function toBool( $val, $default = null ) {
|
@@ -87,16 +104,16 @@ class DG_Util {
|
|
87 |
|
88 |
/**
|
89 |
* Wrapper method which handles deciding whether to include minified assets. Minified files are not used
|
90 |
-
* in
|
91 |
*
|
92 |
* @param $handle string Unique identifier for the script/style.
|
93 |
* @param $src string Relative path to asset from DG_URL.
|
94 |
-
* @param
|
95 |
* @param bool $in_footer For scripts, dictates whether to put in footer.
|
96 |
*/
|
97 |
public static function enqueueAsset( $handle, $src, $deps = array(), $in_footer = true ) {
|
98 |
$src = self::getAssetPath( $src );
|
99 |
-
if (
|
100 |
wp_enqueue_script( $handle, $src, $deps, DG_VERSION, $in_footer );
|
101 |
} else {
|
102 |
wp_enqueue_style( $handle, $src, $deps, DG_VERSION );
|
@@ -106,13 +123,66 @@ class DG_Util {
|
|
106 |
/**
|
107 |
* Converts path to min version when WP is not running in debug mode and fully-qualifies path.
|
108 |
*
|
109 |
-
* @param $src string Relative path to asset from DG_URL.
|
110 |
* @return string The fully-qualified, potentially min version of the given path.
|
111 |
*/
|
112 |
public static function getAssetPath( $src ) {
|
113 |
-
if ( !defined('
|
114 |
-
$
|
|
|
115 |
}
|
116 |
return DG_URL . $src;
|
117 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
}
|
28 |
}
|
29 |
|
30 |
/**
|
31 |
+
* @return int[] All blog IDs.
|
32 |
*/
|
33 |
public static function getBlogIds() {
|
34 |
global $wpdb;
|
36 |
}
|
37 |
|
38 |
/**
|
39 |
+
* Caller should handle removal of the temp file when finished.
|
40 |
+
*
|
41 |
+
* @param string $ext The extension to be given to the temp file.
|
42 |
*
|
43 |
+
* @return string A temp file with the given extension.
|
44 |
+
*/
|
45 |
+
public static function getTempFile( $ext = 'png' ) {
|
46 |
+
static $base = null;
|
47 |
+
static $tmp;
|
48 |
+
|
49 |
+
if ( is_null( $base ) ) {
|
50 |
+
$base = md5( time() );
|
51 |
+
$tmp = untrailingslashit( get_temp_dir() );
|
52 |
+
}
|
53 |
+
|
54 |
+
return $tmp . DIRECTORY_SEPARATOR . wp_unique_filename( $tmp, $base . '.' . $ext );
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* @param mixed $maybeint Data you wish to have converted to a positive integer.
|
59 |
* @return int A positive integer.
|
60 |
*/
|
61 |
+
public static function posint( $maybeint ) {
|
62 |
+
return max( absint( $maybeint ), 1 );
|
63 |
}
|
64 |
|
65 |
/**
|
67 |
*
|
68 |
* @param mixed $val To be converted.
|
69 |
* @param bool|NULL $default The value to return if unable to parse $val.
|
|
|
70 |
* @return bool|NULL Bool value if can be parsed, else NULL.
|
71 |
*/
|
72 |
public static function toBool( $val, $default = null ) {
|
104 |
|
105 |
/**
|
106 |
* Wrapper method which handles deciding whether to include minified assets. Minified files are not used
|
107 |
+
* in SCRIPT_DEBUG mode to make troubleshooting easier.
|
108 |
*
|
109 |
* @param $handle string Unique identifier for the script/style.
|
110 |
* @param $src string Relative path to asset from DG_URL.
|
111 |
+
* @param string[] $deps Any assets depended on by asset to be enqueued.
|
112 |
* @param bool $in_footer For scripts, dictates whether to put in footer.
|
113 |
*/
|
114 |
public static function enqueueAsset( $handle, $src, $deps = array(), $in_footer = true ) {
|
115 |
$src = self::getAssetPath( $src );
|
116 |
+
if ( self::endsWith( $src, '.js' ) ) {
|
117 |
wp_enqueue_script( $handle, $src, $deps, DG_VERSION, $in_footer );
|
118 |
} else {
|
119 |
wp_enqueue_style( $handle, $src, $deps, DG_VERSION );
|
123 |
/**
|
124 |
* Converts path to min version when WP is not running in debug mode and fully-qualifies path.
|
125 |
*
|
126 |
+
* @param $src string Relative path to non-minified asset from DG_URL.
|
127 |
* @return string The fully-qualified, potentially min version of the given path.
|
128 |
*/
|
129 |
public static function getAssetPath( $src ) {
|
130 |
+
if ( ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG ) {
|
131 |
+
$parts = explode( '.', $src );
|
132 |
+
$src = $parts[0] . '.min.' . $parts[1];
|
133 |
}
|
134 |
return DG_URL . $src;
|
135 |
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* @param $haystack string The string to be tested.
|
139 |
+
* @param $needle string The value to be tested against.
|
140 |
+
* @return bool Whether $haystack starts with $needle.
|
141 |
+
*/
|
142 |
+
public static function startsWith( $haystack, $needle ) {
|
143 |
+
return substr( $haystack, 0, strlen( $needle ) ) === $needle;
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* @param $haystack string The string to be tested.
|
148 |
+
* @param $needle string The value to be tested against.
|
149 |
+
* @return bool Whether $haystack ends with $needle.
|
150 |
+
*/
|
151 |
+
public static function endsWith( $haystack, $needle ) {
|
152 |
+
return substr( $haystack, -strlen( $needle ) ) === $needle;
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* @return bool Whether the WP host is a public site accessible from the Internet.
|
157 |
+
*/
|
158 |
+
public static function isPublicSite() {
|
159 |
+
$host = parse_url( site_url(), PHP_URL_HOST );
|
160 |
+
$is_ip = filter_var( $host, FILTER_VALIDATE_IP );
|
161 |
+
return $is_ip ? self::isPublicIp( $host ) : self::isPublicHostname( $host );
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* @param $ip string The IP address.
|
166 |
+
* @return bool Whether the given IP is public.
|
167 |
+
*/
|
168 |
+
private static function isPublicIp( $ip ) {
|
169 |
+
return false !== filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE )
|
170 |
+
&& '127.0.0.1' !== $ip && '::1' !== $ip;
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* @param $hostname string The hostname to test.
|
175 |
+
* @return bool Whether the given hostname has at least one public IP address associated.
|
176 |
+
*/
|
177 |
+
private static function isPublicHostname( $hostname ) {
|
178 |
+
$ret = false;
|
179 |
+
foreach ( gethostbynamel( $hostname ) as $ip ) {
|
180 |
+
if ( self::isPublicIp( $ip ) ) {
|
181 |
+
$ret = true;
|
182 |
+
break;
|
183 |
+
}
|
184 |
+
}
|
185 |
+
|
186 |
+
return $ret;
|
187 |
+
}
|
188 |
}
|
inc/thumbers/class-abstract-thumber.php
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
abstract class DG_AbstractThumber {
|
5 |
+
|
6 |
+
/**
|
7 |
+
* @var DG_AbstractThumber[] The singleton instances, keyed by class name.
|
8 |
+
*/
|
9 |
+
protected static $instances = array();
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Blocks external instantiation. Thumbers only require a singleton instance.
|
13 |
+
*/
|
14 |
+
protected function __construct() {
|
15 |
+
}
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Initialize the thumber class for use in thumbnail generation.
|
19 |
+
*
|
20 |
+
* @return DG_AbstractThumber The instance for the calling class.
|
21 |
+
*/
|
22 |
+
public static function init() {
|
23 |
+
$class = get_called_class();
|
24 |
+
if ( ! isset( self::$instances[$class] ) ) {
|
25 |
+
try {
|
26 |
+
self::$instances[$class] = new static();
|
27 |
+
add_action( 'dg_thumbers', array( $class, 'thumbersFilter' ), 0 );
|
28 |
+
} catch ( Exception $e ) {
|
29 |
+
DG_Logger::writeLog( DG_LogLevel::Error, "Failed to construct thumber of type $class." );
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
return isset( self::$instances[$class] ) ? self::$instances[$class] : null;
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Adds the singleton instance for the calling class as a thumber.
|
38 |
+
*
|
39 |
+
* @param $thumbers DG_AbstractThumber[] The thumbers being filtered.
|
40 |
+
* @return DG_AbstractThumber[] The filtered thumbers.
|
41 |
+
*/
|
42 |
+
public static function thumbersFilter( $thumbers ) {
|
43 |
+
$thumbers[] = static::$instances[get_called_class()];
|
44 |
+
return $thumbers;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* @return string[] The extensions supported by this thumber.
|
49 |
+
*/
|
50 |
+
protected abstract function getThumberExtensions();
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @param int $ID The attachment ID to retrieve thumbnail from.
|
54 |
+
* @param int $pg Unused.
|
55 |
+
* @return bool|string False on failure, URL to thumb on success.
|
56 |
+
*/
|
57 |
+
public abstract function getThumbnail( $ID, $pg = 1 );
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @return int An integer from 0 to 100. Higher priorities will be attempted before lower priority thumbers.
|
61 |
+
*/
|
62 |
+
public abstract function getPriority();
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @param int $ID The attachment ID to retrieve thumbnail from.
|
66 |
+
* @return bool Whether the attachment is supported by this thumber.
|
67 |
+
*/
|
68 |
+
public function supportsAttachment( $ID ) {
|
69 |
+
return in_array( self::getAttachmentExt( $ID ), $this->getThumberExtensions() );
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Used in sorting an array of thumbers.
|
74 |
+
*
|
75 |
+
* @param $t1 DG_AbstractThumber First thumber.
|
76 |
+
* @param $t2 DG_AbstractThumber Second thumber.
|
77 |
+
* @return int Negative if $t1 has a higher priority, positive if $t1 has a lower priority.
|
78 |
+
*/
|
79 |
+
public static function cmpThumberByPriority( $t1, $t2 ) {
|
80 |
+
return $t2->getPriority() - $t1->getPriority();
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Checks whether exec() may be used.
|
85 |
+
* Source: http://stackoverflow.com/a/12980534/866618
|
86 |
+
*
|
87 |
+
* @return bool Whether exec() is available.
|
88 |
+
*/
|
89 |
+
public static function isExecAvailable() {
|
90 |
+
static $available = null;
|
91 |
+
|
92 |
+
if ( is_null( $available ) ) {
|
93 |
+
$available = true;
|
94 |
+
|
95 |
+
if ( ini_get( 'safe_mode' ) ) {
|
96 |
+
$available = false;
|
97 |
+
} else {
|
98 |
+
$d = ini_get( 'disable_functions' );
|
99 |
+
$s = ini_get( 'suhosin.executor.func.blacklist' );
|
100 |
+
if ( "$d$s" ) {
|
101 |
+
$array = preg_split( '/,\s*/', "$d,$s" );
|
102 |
+
$available = ! in_array( 'exec', $array );
|
103 |
+
}
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
return $available;
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* @param $ID int The attachment ID.
|
112 |
+
* @return bool|string The attachment extension on success, false on failure.
|
113 |
+
*/
|
114 |
+
protected static function getAttachmentExt( $ID ) {
|
115 |
+
return self::getExt( get_attached_file( $ID ) );
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Formerly achieved with wp_check_filetype(), but it was only returning
|
120 |
+
* valid results if the active user had permission to upload the given filetype.
|
121 |
+
*
|
122 |
+
* @param string $filename Name of the file to get extension from.
|
123 |
+
*
|
124 |
+
* @return bool|string Returns the file extension on success, false on failure.
|
125 |
+
*/
|
126 |
+
protected static function getExt( $filename ) {
|
127 |
+
if ( $ext = pathinfo( $filename, PATHINFO_EXTENSION ) ) {
|
128 |
+
$res = preg_grep( '/^(?:.*\|)?' . $ext . '(?:\|.*)?$/i', self::getAllExts() );
|
129 |
+
$res = reset( $res );
|
130 |
+
if ( $res === false ) {
|
131 |
+
$ext = false;
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
if ( ! $ext && ( $info = getimagesize( $filename ) ) && ( $ext = image_type_to_extension( $info[2], false ) ) ) {
|
136 |
+
return $ext;
|
137 |
+
}
|
138 |
+
|
139 |
+
return $ext;
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Addresses issues with getting a complete list of supported MIME types as
|
144 |
+
* described in this issue: https://core.trac.wordpress.org/ticket/32544
|
145 |
+
* @return string[] Contains all MIME types supported by WordPress, including custom types added by plugins.
|
146 |
+
*/
|
147 |
+
protected static function getAllExts() {
|
148 |
+
return array_keys( array_merge( wp_get_mime_types(), get_allowed_mime_types() ) );
|
149 |
+
}
|
150 |
+
}
|
inc/thumbers/class-audio-video-thumber.php
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
DG_AudioVideoThumber::init();
|
5 |
+
|
6 |
+
class DG_AudioVideoThumber extends DG_AbstractThumber {
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Initialize the thumber class for use in thumbnail generation.
|
10 |
+
*/
|
11 |
+
public static function init() {
|
12 |
+
$options = DG_Thumber::getOptions();
|
13 |
+
$active = $options['active'];
|
14 |
+
if ( $active['av'] ) {
|
15 |
+
parent::init();
|
16 |
+
}
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Uses wp_read_video_metadata() and wp_read_audio_metadata() to retrieve
|
21 |
+
* an embedded image to use as a thumbnail.
|
22 |
+
*
|
23 |
+
* @param string $ID The attachment ID to retrieve thumbnail from.
|
24 |
+
* @param int $pg Unused.
|
25 |
+
*
|
26 |
+
* @return bool|string False on failure, URL to thumb on success.
|
27 |
+
*/
|
28 |
+
public function getThumbnail( $ID, $pg = 1 ) {
|
29 |
+
include_once DG_WPADMIN_PATH . 'includes/media.php';
|
30 |
+
|
31 |
+
$doc_path = get_attached_file( $ID );
|
32 |
+
$mime_type = get_post_mime_type( $ID );
|
33 |
+
|
34 |
+
if ( DG_Util::startsWith( $mime_type, 'video/' ) ) {
|
35 |
+
$metadata = wp_read_video_metadata( $doc_path );
|
36 |
+
} elseif ( DG_Util::startsWith( $mime_type, 'audio/' ) ) {
|
37 |
+
$metadata = wp_read_audio_metadata( $doc_path );
|
38 |
+
}
|
39 |
+
|
40 |
+
// unsupported mime type || no embedded image present
|
41 |
+
if ( ! isset( $metadata ) || empty( $metadata['image']['data'] ) ) {
|
42 |
+
return false;
|
43 |
+
}
|
44 |
+
|
45 |
+
$ext = 'jpg';
|
46 |
+
switch ( $metadata['image']['mime'] ) {
|
47 |
+
case 'image/gif':
|
48 |
+
$ext = 'gif';
|
49 |
+
break;
|
50 |
+
case 'image/png':
|
51 |
+
$ext = 'png';
|
52 |
+
break;
|
53 |
+
}
|
54 |
+
|
55 |
+
$temp_file = DG_Util::getTempFile( $ext );
|
56 |
+
|
57 |
+
if ( ! $fp = @fopen( $temp_file, 'wb' ) ) {
|
58 |
+
DG_Logger::writeLog( DG_LogLevel::Error, __( 'Could not open file: ', 'document-gallery' ) . $temp_file );
|
59 |
+
|
60 |
+
return false;
|
61 |
+
}
|
62 |
+
|
63 |
+
if ( ! @fwrite( $fp, $metadata['image']['data'] ) ) {
|
64 |
+
DG_Logger::writeLog( DG_LogLevel::Error, __( 'Could not write file: ', 'document-gallery' ) . $temp_file );
|
65 |
+
fclose( $fp );
|
66 |
+
|
67 |
+
return false;
|
68 |
+
}
|
69 |
+
|
70 |
+
fclose( $fp );
|
71 |
+
|
72 |
+
return $temp_file;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* @return string[] The extensions supported by this thumber.
|
77 |
+
*/
|
78 |
+
protected function getThumberExtensions() {
|
79 |
+
return array_merge( wp_get_audio_extensions(), wp_get_video_extensions() );
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* @return int An integer from 0 to 100. Higher priorities will be attempted before lower priority thumbers.
|
84 |
+
*/
|
85 |
+
public function getPriority() {
|
86 |
+
return 95;
|
87 |
+
}
|
88 |
+
}
|
inc/thumbers/class-default-thumber.php
ADDED
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
class DG_DefaultThumber extends DG_AbstractThumber {
|
5 |
+
|
6 |
+
/**
|
7 |
+
* @var DG_DefaultThumber The singleton instance.
|
8 |
+
*/
|
9 |
+
private static $instance;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @return DG_DefaultThumber The singleton instance.
|
13 |
+
*/
|
14 |
+
public static function getInstance() {
|
15 |
+
return isset( self::$instance ) ? self::$instance : ( self::$instance = new DG_DefaultThumber() );
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Get thumbnail for document with given ID from default images.
|
20 |
+
*
|
21 |
+
* @param string $ID The attachment ID to retrieve thumbnail from.
|
22 |
+
* @param int $pg Unused.
|
23 |
+
*
|
24 |
+
* @return string URL to thumbnail.
|
25 |
+
*/
|
26 |
+
public function getThumbnail( $ID, $pg = 1 ) {
|
27 |
+
$icon_url = DG_URL . 'assets/icons/';
|
28 |
+
|
29 |
+
// handle images
|
30 |
+
if ( $name = self::getDefaultIcon( self::getExt( wp_get_attachment_url( $ID ) ) ) ) {
|
31 |
+
$icon = $icon_url . $name;
|
32 |
+
} // fallback to standard WP icons
|
33 |
+
elseif ( ! $icon = wp_mime_type_icon( $ID ) ) {
|
34 |
+
// everything failed. This is bad...
|
35 |
+
$icon = $icon_url . 'missing.png';
|
36 |
+
}
|
37 |
+
|
38 |
+
return $icon;
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @return string[] The extensions supported by this thumber.
|
43 |
+
*/
|
44 |
+
protected function getThumberExtensions() {
|
45 |
+
return self::getAllExts();
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @return int An integer from 0 to 100. Higher priorities will be attempted before lower priority thumbers.
|
50 |
+
*/
|
51 |
+
public function getPriority() {
|
52 |
+
return 0;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Returns the name of the image to represent the filetype given.
|
57 |
+
*
|
58 |
+
* @param string $ext
|
59 |
+
*
|
60 |
+
* @return string Default icon based on extension.
|
61 |
+
*/
|
62 |
+
private static function getDefaultIcon( $ext ) {
|
63 |
+
// Maps file ext to default image name.
|
64 |
+
static $exts = array(
|
65 |
+
// Most Common First
|
66 |
+
'pdf' => 'pdf.png',
|
67 |
+
// MS Office
|
68 |
+
'doc|docx|docm|dotx|dotm' => 'msdoc.png',
|
69 |
+
'ppt|pot|pps|pptx|pptm|ppsx|ppsm|potx|potm|ppam|sldx|sldm' => 'msppt.png',
|
70 |
+
'xla|xls|xlt|xlw|xlsx|xlsm|xlsb|xltx|xltm|xlam' => 'msxls.png',
|
71 |
+
'mdb' => 'msaccess.png',
|
72 |
+
// iWork
|
73 |
+
'key' => 'key.png',
|
74 |
+
'numbers' => 'numbers.png',
|
75 |
+
'pages' => 'pages.png',
|
76 |
+
// Images
|
77 |
+
'jpg|jpeg|jpe|gif|png|bmp|tif|tiff|ico' => 'image.png',
|
78 |
+
// Video formats
|
79 |
+
'asf|asx|wmv|wmx|wm|avi|divx|flv|mov' => 'video.png',
|
80 |
+
'qt|mpeg|mpg|mpe|mp4|m4v|ogv|webm|mkv' => 'video.png',
|
81 |
+
// Audio formats
|
82 |
+
'mp3|m4a|m4b|ra|ram|wav|ogg|oga|wma|wax|mka' => 'audio.png',
|
83 |
+
'midi|mid' => 'midi.png',
|
84 |
+
// Text formats
|
85 |
+
'txt|tsv|csv' => 'text.png',
|
86 |
+
'rtx' => 'rtx.png',
|
87 |
+
'rtf' => 'rtf.png',
|
88 |
+
'ics' => 'ics.png',
|
89 |
+
'wp|wpd' => 'wordperfect.png',
|
90 |
+
// Programming
|
91 |
+
'html|htm' => 'html.png',
|
92 |
+
'css' => 'css.png',
|
93 |
+
'js' => 'javascript.png',
|
94 |
+
'class' => 'java.png',
|
95 |
+
'asc' => 'asc.png',
|
96 |
+
'c' => 'c.png',
|
97 |
+
'cc|cpp' => 'cpp.png',
|
98 |
+
'h' => 'h.png',
|
99 |
+
// Msc application formats
|
100 |
+
'zip|tar|gzip|gz|bz2|tgz|7z|rar' => 'compressed.png',
|
101 |
+
'exe' => 'exec.png',
|
102 |
+
'swf' => 'shockwave.png',
|
103 |
+
// OpenDocument formats
|
104 |
+
'odt' => 'opendocument-text.png',
|
105 |
+
'odp' => 'opendocument-presentation.png',
|
106 |
+
'ods' => 'opendocument-spreadsheet.png',
|
107 |
+
'odg' => 'opendocument-graphics.png',
|
108 |
+
'odb' => 'opendocument-database.png',
|
109 |
+
'odf' => 'opendocument-formula.png'
|
110 |
+
);
|
111 |
+
|
112 |
+
foreach ( $exts as $ext_preg => $icon ) {
|
113 |
+
$ext_preg = '!(' . $ext_preg . ')$!i';
|
114 |
+
if ( preg_match( $ext_preg, $ext ) ) {
|
115 |
+
return $icon;
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
return false;
|
120 |
+
}
|
121 |
+
}
|
inc/thumbers/class-ghostscript-thumber.php
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
DG_GhostscriptThumber::init();
|
5 |
+
|
6 |
+
class DG_GhostscriptThumber extends DG_AbstractThumber {
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Initialize the thumber class for use in thumbnail generation.
|
10 |
+
*/
|
11 |
+
public static function init() {
|
12 |
+
$options = DG_Thumber::getOptions();
|
13 |
+
$active = $options['active'];
|
14 |
+
if ( $active['gs'] && self::isGhostscriptAvailable() ) {
|
15 |
+
parent::init();
|
16 |
+
}
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Get thumbnail for document with given ID using Ghostscript. Imagick could
|
21 |
+
* also handle this, but is *much* slower.
|
22 |
+
*
|
23 |
+
* @param int $ID The attachment ID to retrieve thumbnail from.
|
24 |
+
* @param int $pg The page number to make thumbnail of -- index starts at 1.
|
25 |
+
*
|
26 |
+
* @return bool|string False on failure, URL to thumb on success.
|
27 |
+
*/
|
28 |
+
public function getThumbnail($ID, $pg = 1) {
|
29 |
+
static $gs = null;
|
30 |
+
|
31 |
+
if ( is_null( $gs ) ) {
|
32 |
+
$options = DG_Thumber::getOptions();
|
33 |
+
$gs = $options['gs'];
|
34 |
+
|
35 |
+
if ( false !== $gs ) {
|
36 |
+
$gs = escapeshellarg( $gs ) . ' -sDEVICE=png16m -dFirstPage=%1$d'
|
37 |
+
. ' -dLastPage=%1$d -dBATCH -dNOPAUSE -dPDFFitPage -sOutputFile=%2$s %3$s 2>&1';
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
if ( false === $gs ) {
|
42 |
+
return false;
|
43 |
+
}
|
44 |
+
|
45 |
+
$doc_path = get_attached_file( $ID );
|
46 |
+
$temp_path = DG_Util::getTempFile();
|
47 |
+
|
48 |
+
exec( sprintf( $gs, $pg, $temp_path, $doc_path ), $out, $ret );
|
49 |
+
|
50 |
+
if ( $ret != 0 ) {
|
51 |
+
DG_Logger::writeLog( DG_LogLevel::Error, __( 'Ghostscript failed: ', 'document-gallery' ) . print_r( $out ) );
|
52 |
+
@unlink( $temp_path );
|
53 |
+
|
54 |
+
return false;
|
55 |
+
}
|
56 |
+
|
57 |
+
return $temp_path;
|
58 |
+
}
|
59 |
+
/**
|
60 |
+
* @return string[] The extensions supported by this thumber.
|
61 |
+
*/
|
62 |
+
protected function getThumberExtensions() {
|
63 |
+
return array( 'pdf', 'ps', 'eps' );
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Dynamically determines whether we may call gs through exec().
|
68 |
+
*
|
69 |
+
* NOTE: This does not check the options for gs path. Don't use in
|
70 |
+
* thumbnail generation as it's slow and not configurable.
|
71 |
+
*
|
72 |
+
* @return bool|string If available, returns exe path. False otherwise.
|
73 |
+
*/
|
74 |
+
public static function getGhostscriptExecutable() {
|
75 |
+
static $executable = null;
|
76 |
+
|
77 |
+
if ( is_null( $executable ) ) {
|
78 |
+
// we must be able to exec()
|
79 |
+
$executable = self::isExecAvailable();
|
80 |
+
if ( ! $executable ) {
|
81 |
+
return $executable;
|
82 |
+
}
|
83 |
+
|
84 |
+
// find on Windows system
|
85 |
+
if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) ) {
|
86 |
+
// look for environment variable
|
87 |
+
$executable = getenv( 'GSC' );
|
88 |
+
if ( $executable ) {
|
89 |
+
return $executable;
|
90 |
+
}
|
91 |
+
|
92 |
+
// hope GS in the path
|
93 |
+
$executable = exec( 'where gswin*c.exe' );
|
94 |
+
if ( ! empty( $executable ) ) {
|
95 |
+
return $executable;
|
96 |
+
}
|
97 |
+
|
98 |
+
// look directly in filesystem
|
99 |
+
// 64- or 32-bit binary
|
100 |
+
$executable = exec( 'dir /o:n/s/b "C:\Program Files\gs\*gswin*c.exe"' );
|
101 |
+
if ( ! empty( $executable ) ) {
|
102 |
+
return $executable;
|
103 |
+
}
|
104 |
+
|
105 |
+
// 32-bit binary on 64-bit OS
|
106 |
+
$executable = exec( 'dir /o:n/s/b "C:\Program Files (x86)\gs\*gswin32c.exe"' );
|
107 |
+
$executable = empty( $executable ) ? false : $executable;
|
108 |
+
|
109 |
+
return $executable;
|
110 |
+
}
|
111 |
+
|
112 |
+
// handle Linux systems
|
113 |
+
$executable = exec( 'which gs' );
|
114 |
+
if ( ! empty( $executable ) ) {
|
115 |
+
return $executable;
|
116 |
+
}
|
117 |
+
|
118 |
+
// GoDaddy and others aren't setup in such a way that
|
119 |
+
// the above works so we need to fallback to a direct
|
120 |
+
// filesystem check in most common location
|
121 |
+
exec( 'test -e /usr/bin/gs', $dummy, $ret );
|
122 |
+
$executable = ( $ret === 0 ) ? '/usr/bin/gs' : false;
|
123 |
+
|
124 |
+
return $executable;
|
125 |
+
}
|
126 |
+
|
127 |
+
return $executable;
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* @return bool Whether we can use the GS executable.
|
132 |
+
*/
|
133 |
+
public static function isGhostscriptAvailable() {
|
134 |
+
static $ret = null;
|
135 |
+
|
136 |
+
if ( is_null( $ret ) ) {
|
137 |
+
$options = DG_Thumber::getOptions();
|
138 |
+
$ret = $options['gs'] && self::isExecAvailable();
|
139 |
+
}
|
140 |
+
|
141 |
+
return $ret;
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* @return int An integer from 0 to 100. Higher priorities will be attempted before lower priority thumbers.
|
146 |
+
*/
|
147 |
+
public function getPriority() {
|
148 |
+
return 75;
|
149 |
+
}
|
150 |
+
}
|
inc/thumbers/class-image-thumber.php
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
DG_ImageThumber::init();
|
5 |
+
|
6 |
+
class DG_ImageThumber extends DG_AbstractThumber {
|
7 |
+
|
8 |
+
/**
|
9 |
+
* @return string[] The extensions supported by this thumber.
|
10 |
+
*/
|
11 |
+
protected function getThumberExtensions() {
|
12 |
+
return array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @param string $ID The attachment ID to retrieve thumbnail from.
|
17 |
+
* @param int $pg Unused.
|
18 |
+
*
|
19 |
+
* @return bool|string False on failure, URL to thumb on success.
|
20 |
+
*/
|
21 |
+
public function getThumbnail( $ID, $pg = 1 ) {
|
22 |
+
$options = DG_Thumber::getOptions();
|
23 |
+
$ret = false;
|
24 |
+
|
25 |
+
if ( $icon = image_downsize( $ID, array( $options['width'], $options['height'] ) ) ) {
|
26 |
+
$ret = $icon[0];
|
27 |
+
}
|
28 |
+
|
29 |
+
return $ret;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @return int An integer from 0 to 100. Higher priorities will be attempted before lower priority thumbers.
|
34 |
+
*/
|
35 |
+
public function getPriority() {
|
36 |
+
return 100;
|
37 |
+
}
|
38 |
+
}
|
inc/thumbers/class-imagick-thumber.php
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
include_once DG_PATH . 'inc/class-image-editor-imagick.php';
|
5 |
+
|
6 |
+
DG_ImagickThumber::init();
|
7 |
+
|
8 |
+
class DG_ImagickThumber extends DG_AbstractThumber {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Initialize the thumber class for use in thumbnail generation.
|
12 |
+
*/
|
13 |
+
public static function init() {
|
14 |
+
$options = DG_Thumber::getOptions();
|
15 |
+
$active = $options['active'];
|
16 |
+
if ( $active['imagick'] && self::isImagickAvailable() ) {
|
17 |
+
parent::init();
|
18 |
+
}
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @return string[] The extensions supported by this thumber.
|
23 |
+
*/
|
24 |
+
protected function getThumberExtensions() {
|
25 |
+
if ( ! ($ret = DG_Image_Editor_Imagick::query_formats()) ) {
|
26 |
+
$ret = array();
|
27 |
+
}
|
28 |
+
|
29 |
+
return $ret;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Uses WP_Image_Editor_Imagick to generate thumbnails.
|
34 |
+
*
|
35 |
+
* @param int $ID The attachment ID to retrieve thumbnail from.
|
36 |
+
* @param int $pg The page to get the thumbnail of.
|
37 |
+
*
|
38 |
+
* @return bool|string False on failure, URL to thumb on success.
|
39 |
+
*/
|
40 |
+
public function getThumbnail($ID, $pg = 1) {
|
41 |
+
$doc_path = get_attached_file( $ID );
|
42 |
+
$img = new DG_Image_Editor_Imagick( $doc_path, $pg - 1 );
|
43 |
+
$err = $img->load();
|
44 |
+
if ( is_wp_error( $err ) ) {
|
45 |
+
DG_Logger::writeLog(
|
46 |
+
DG_LogLevel::Error,
|
47 |
+
__( 'Failed to open file in Imagick: ', 'document-gallery' ) .
|
48 |
+
$err->get_error_message() );
|
49 |
+
|
50 |
+
return false;
|
51 |
+
}
|
52 |
+
|
53 |
+
$temp_file = DG_Util::getTempFile();
|
54 |
+
|
55 |
+
$err = $img->save( $temp_file, 'image/png' );
|
56 |
+
if ( is_wp_error( $err ) ) {
|
57 |
+
DG_Logger::writeLog(
|
58 |
+
DG_LogLevel::Error,
|
59 |
+
__( 'Failed to save image in Imagick: ', 'document-gallery' ) .
|
60 |
+
$err->get_error_message() );
|
61 |
+
|
62 |
+
return false;
|
63 |
+
}
|
64 |
+
|
65 |
+
return $temp_file;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @return bool Whether WP_Image_Editor_Imagick can be used on this system.
|
70 |
+
*/
|
71 |
+
public static function isImagickAvailable() {
|
72 |
+
static $ret = null;
|
73 |
+
|
74 |
+
if ( is_null( $ret ) ) {
|
75 |
+
$ret = WP_Image_Editor_Imagick::test();
|
76 |
+
}
|
77 |
+
|
78 |
+
return $ret;
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* @return int An integer from 0 to 100. Higher priorities will be attempted before lower priority thumbers.
|
83 |
+
*/
|
84 |
+
public function getPriority()
|
85 |
+
{
|
86 |
+
return 50;
|
87 |
+
}
|
88 |
+
}
|
inc/thumbers/class-thumber-co-thumber.php
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
include_once DG_PATH . 'inc/thumbers/thumber-co/thumber-client/client.php';
|
5 |
+
include_once DG_PATH . 'inc/thumbers/thumber-co/class-thumber-client.php';
|
6 |
+
|
7 |
+
add_filter( 'allowed_http_origin', array( 'DG_ThumberCoThumber', 'allowThumberWebhooks' ), 10, 2);
|
8 |
+
add_filter( 'upload_mimes', array( 'DG_ThumberCoThumber', 'customMimeTypes' ) );
|
9 |
+
add_action( 'admin_post_nopriv_' . DG_ThumberCoThumber::ThumberAction, array( DG_ThumberClient::getInstance(), 'receiveThumbResponse' ), 5, 0);
|
10 |
+
|
11 |
+
DG_ThumberCoThumber::init();
|
12 |
+
|
13 |
+
class DG_ThumberCoThumber extends DG_AbstractThumber {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @const string Name of the action performed in the webhook.
|
17 |
+
*/
|
18 |
+
const ThumberAction = 'dg_thumber_webhook';
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @const string Used in nonce to separate the attachment ID from the "random" segment.
|
22 |
+
*/
|
23 |
+
const NonceSeparator = '_';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @var string URL to webhook.
|
27 |
+
*/
|
28 |
+
private static $webhook;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @var DG_ThumberClient The thumber client instance.
|
32 |
+
*/
|
33 |
+
private static $client;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Initializes the static values for this class.
|
37 |
+
*/
|
38 |
+
public static function init() {
|
39 |
+
$options = DG_Thumber::getOptions();
|
40 |
+
$active = $options['active'];
|
41 |
+
if ( $active['thumber-co'] ) {
|
42 |
+
parent::init();
|
43 |
+
self::$webhook = admin_url( 'admin-post.php?action=' . self::ThumberAction );
|
44 |
+
self::$client = DG_ThumberClient::getInstance();
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @param int $ID The attachment ID.
|
50 |
+
* @param int $pg The page to thumbnail.
|
51 |
+
*
|
52 |
+
* @return bool Always false. Asynchronously set the thumbnail in webhook later.
|
53 |
+
*/
|
54 |
+
public function getThumbnail( $ID, $pg = 1 ) {
|
55 |
+
global $dg_options;
|
56 |
+
|
57 |
+
include_once DG_PATH . 'inc/thumbers/thumber-co/thumber-client/client.php';
|
58 |
+
include_once DG_PATH . 'inc/thumbers/thumber-co/thumber-client/thumb-request.php';
|
59 |
+
|
60 |
+
$options = DG_Thumber::getOptions();
|
61 |
+
$url_or_path = get_attached_file( $ID );
|
62 |
+
|
63 |
+
if ( ! self::checkGeometry( $options['width'], $options['height'] ) ) {
|
64 |
+
DG_Logger::writeLog( DG_LogLevel::Detail, "Skipping attachment #$ID as it exceeds Thumber.co subscription geometry limit." );
|
65 |
+
return false;
|
66 |
+
}
|
67 |
+
|
68 |
+
if ( ! self::checkFileSize( $url_or_path ) ) {
|
69 |
+
DG_Logger::writeLog( DG_LogLevel::Detail, "Skipping attachment #$ID as it exceeds Thumber.co subscription file size limit." );
|
70 |
+
return false;
|
71 |
+
}
|
72 |
+
|
73 |
+
$mime_type = get_post_mime_type( $ID );
|
74 |
+
if ( ! $dg_options['thumber-co']['direct_upload'] ) {
|
75 |
+
$url_or_path = wp_get_attachment_url( $ID );
|
76 |
+
}
|
77 |
+
|
78 |
+
if ( ! $url_or_path || ! $mime_type ) {
|
79 |
+
return false;
|
80 |
+
}
|
81 |
+
|
82 |
+
$req = new ThumberThumbReq();
|
83 |
+
$req->setCallback( self::$webhook );
|
84 |
+
$req->setMimeType( $mime_type );
|
85 |
+
$req->setNonce( $ID . self::NonceSeparator . md5( microtime() ) );
|
86 |
+
$req->setPg( $pg );
|
87 |
+
$req->setGeometry( $options['width'] . 'x' . $options['height'] );
|
88 |
+
|
89 |
+
if ( $dg_options['thumber-co']['direct_upload'] ) {
|
90 |
+
$req->setDecodedData( file_get_contents( $url_or_path ) );
|
91 |
+
} else {
|
92 |
+
$req->setUrl( $url_or_path );
|
93 |
+
}
|
94 |
+
|
95 |
+
$resp = self::$client->sendThumbRequest( $req );
|
96 |
+
|
97 |
+
if ( $resp['http_code'] < 200 || $resp['http_code'] > 399 ) {
|
98 |
+
DG_Logger::writeLog( DG_LogLevel::Error, 'Failed to transmit to server: ' . $resp['body'] );
|
99 |
+
}
|
100 |
+
|
101 |
+
// always returns false -- we set the thumbnail later when webhook is hit
|
102 |
+
return false;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* @return string[] The extensions supported by this thumber.
|
107 |
+
*/
|
108 |
+
protected function getThumberExtensions() {
|
109 |
+
return self::$client->getMimeTypes();
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* @return int An integer from 0 to 100. Higher priorities will be attempted before lower priority thumbers.
|
114 |
+
*/
|
115 |
+
public function getPriority() {
|
116 |
+
return 5;
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* @return bool Whether Thumber.co may be used in thumbnail generation.
|
121 |
+
*/
|
122 |
+
public static function isThumberCoAvailable() {
|
123 |
+
global $dg_options;
|
124 |
+
return isset( $dg_options['thumber-co']['uid'] ) && isset( $dg_options['thumber-co']['secret'] );
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* TODO: This should be a configurable option and should include all Thumber types not default WP-supported.
|
129 |
+
* @param $mimes string[] The MIME types WP knows about.
|
130 |
+
* @return string[] Modified MIME types -- adding additional supported types.
|
131 |
+
*/
|
132 |
+
public static function customMimeTypes($mimes) {
|
133 |
+
$mimes['pub'] = 'application/mspublisher';
|
134 |
+
return $mimes;
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* WP by default will not handle POSTs from Thumber so add a special case for the action we want to handle.
|
139 |
+
* @param $origin
|
140 |
+
* @param $origin_arg
|
141 |
+
*
|
142 |
+
* @return bool Whether WP will handle the action.
|
143 |
+
*/
|
144 |
+
public static function allowThumberWebhooks($origin, $origin_arg) {
|
145 |
+
return $origin || ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] === self::ThumberAction );
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* @param string $filename File to be tested.
|
150 |
+
* @return bool Whether file is acceptable to be sent to Thumber.
|
151 |
+
*/
|
152 |
+
private static function checkFileSize($filename ) {
|
153 |
+
$ret = true;
|
154 |
+
$size = @filesize( $filename );
|
155 |
+
if ( $size !== false ) {
|
156 |
+
$sub = self::$client->getSubscription();
|
157 |
+
$ret = ( ! $sub || empty( $sub['file_size_limit'] ) ) || ( $size > 0 && $size <= $sub['file_size_limit'] );
|
158 |
+
}
|
159 |
+
|
160 |
+
return $ret;
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* @param $width int The requested thumb width.
|
165 |
+
* @param $height int The requested thumb height.
|
166 |
+
* @return bool Whether the requested geometry meets subscription limitations.
|
167 |
+
*/
|
168 |
+
private static function checkGeometry( $width, $height ) {
|
169 |
+
$sub = self::$client->getSubscription();
|
170 |
+
return ( ! $sub || empty( $sub['thumb_size_limit'] ) ) || ( $width <= $sub['thumb_size_limit'] && $height <= $sub['thumb_size_limit'] );
|
171 |
+
}
|
172 |
+
}
|
inc/thumbers/thumber-co/class-thumber-client.php
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
defined( 'WPINC' ) OR exit;
|
3 |
+
|
4 |
+
class DG_ThumberClient extends ThumberClient {
|
5 |
+
|
6 |
+
/**
|
7 |
+
* @var DG_ThumberClient Backs the getter.
|
8 |
+
*/
|
9 |
+
private static $instance;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @return DG_ThumberClient The singleton instance.
|
13 |
+
*/
|
14 |
+
public static function getInstance() {
|
15 |
+
return isset( self::$instance ) ? self::$instance : ( self::$instance = new DG_ThumberClient() );
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Enforce singleton.
|
20 |
+
*/
|
21 |
+
protected function __construct() {
|
22 |
+
parent::__construct();
|
23 |
+
|
24 |
+
global $dg_options;
|
25 |
+
|
26 |
+
$this->uid = $dg_options['thumber-co']['uid'];
|
27 |
+
$this->userSecret = $dg_options['thumber-co']['secret'];
|
28 |
+
$this->thumberUserAgent = 'Document Gallery Thumber Client 1.0 (PHP ' . phpversion() . '; ' . php_uname() . ')';
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Sends HTTP request to Thumber server.
|
33 |
+
* @param $type string GET or POST
|
34 |
+
* @param $url string The URL endpoint being targeted.
|
35 |
+
* @param $httpHeaders string[] The headers to be sent.
|
36 |
+
* @param $body string The POST body. Ignored if type is GET.
|
37 |
+
* @return mixed[] The result of the request.
|
38 |
+
*/
|
39 |
+
protected function sendToThumber($type, $url, $httpHeaders, $body = '') {
|
40 |
+
$headers = array();
|
41 |
+
foreach ( $httpHeaders as $v ) {
|
42 |
+
$kvp = explode( ':', $v );
|
43 |
+
$headers[trim( $kvp[0] )] = trim( $kvp[1] );
|
44 |
+
}
|
45 |
+
|
46 |
+
// NOTE: Failure was local so not actual HTTP error, but makes error checking much
|
47 |
+
// simpler if we set the value to something above the success range
|
48 |
+
$result = array (
|
49 |
+
'http_code' => 600,
|
50 |
+
'header' => '',
|
51 |
+
'body' => '',
|
52 |
+
'last_url' => ''
|
53 |
+
);
|
54 |
+
$args = array(
|
55 |
+
'headers' => $headers,
|
56 |
+
'user-agent' => $this->thumberUserAgent
|
57 |
+
);
|
58 |
+
|
59 |
+
switch ( $type ) {
|
60 |
+
case 'GET':
|
61 |
+
if ( ! empty( $body ) ) {
|
62 |
+
$args['body'] = $body;
|
63 |
+
}
|
64 |
+
|
65 |
+
$resp = wp_remote_get( $url, $args );
|
66 |
+
break;
|
67 |
+
|
68 |
+
case 'POST':
|
69 |
+
if (!empty($body)) {
|
70 |
+
$args['body'] = $body;
|
71 |
+
}
|
72 |
+
|
73 |
+
$resp = wp_remote_post( $url, $args );
|
74 |
+
break;
|
75 |
+
|
76 |
+
default:
|
77 |
+
$err = 'Invalid HTTP type given: ' . $type;
|
78 |
+
self::handleError( $err );
|
79 |
+
$result['error'] = 'Invalid HTTP type given: ' . $type;
|
80 |
+
}
|
81 |
+
|
82 |
+
if ( isset( $resp ) ) {
|
83 |
+
if ( ! is_wp_error( $resp ) ) {
|
84 |
+
$result['http_code'] = $resp['response']['code'];
|
85 |
+
$result['body'] = $resp['body'];
|
86 |
+
} else {
|
87 |
+
$result['body'] = $resp->get_error_message();
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
return $result;
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Processes the POST request, generating a ThumberResponse, validating, and passing the result to $callback.
|
96 |
+
* If not using client.php as the webhook, whoever receives webhook response should first invoke this method to
|
97 |
+
* validate response.
|
98 |
+
*/
|
99 |
+
public function receiveThumbResponse() {
|
100 |
+
$resp = parent::receiveThumbResponse();
|
101 |
+
if ( is_null( $resp ) ) {
|
102 |
+
return;
|
103 |
+
}
|
104 |
+
|
105 |
+
$nonce = $resp->getNonce();
|
106 |
+
$split = explode( DG_ThumberCoThumber::NonceSeparator, $nonce );
|
107 |
+
if ( $resp->getSuccess() && count( $split ) === 2 ) {
|
108 |
+
$ID = absint( $split[0] );
|
109 |
+
$tmpfile = DG_Util::getTempFile();
|
110 |
+
|
111 |
+
file_put_contents( $tmpfile, $resp->getDecodedData() );
|
112 |
+
|
113 |
+
DG_Thumber::setThumbnail( $ID, $tmpfile, array( __CLASS__, 'getThumberThumbnail' ) );
|
114 |
+
DG_Logger::writeLog( DG_LogLevel::Detail, "Received thumbnail from Thumber for attachment #{$split[0]}." );
|
115 |
+
} else {
|
116 |
+
$ID = ( count( $split ) > 0) ? $split[0] : $nonce;
|
117 |
+
DG_Logger::writeLog( DG_LogLevel::Warning, "Thumber was unable to process attachment #$ID: " . $resp->getError() );
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* @param $update_options bool Optional. Whether the returned value should be updated in options array.
|
123 |
+
* @return object|null Returns an object with subscription information. Object includes the following:
|
124 |
+
* name, monthly_cost, watermark, direct_upload, thumbs_per_hr_limit, file_size_limit, and thumb_size_limit.
|
125 |
+
*/
|
126 |
+
public function getSubscription($update_options = true) {
|
127 |
+
global $dg_options;
|
128 |
+
$ret = $dg_options['thumber-co']['subscription'];
|
129 |
+
if ( empty( $dg_options['thumber-co']['subscription'] ) ) {
|
130 |
+
static $whitelist = array( 'direct_upload', 'file_size_limit', 'thumb_size_limit' );
|
131 |
+
$ret = array_intersect_key( (array)parent::getSubscription(), array_flip( $whitelist ) );
|
132 |
+
if ( $update_options ) {
|
133 |
+
$dg_options['thumber-co']['subscription'] = $ret;
|
134 |
+
DocumentGallery::setOptions( $dg_options );
|
135 |
+
}
|
136 |
+
}
|
137 |
+
|
138 |
+
return $ret;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Retrieves the supported MIME types from Thumber that are also compatible with WordPress.
|
143 |
+
* @return string[] The supported MIME types reported by the Thumber server.
|
144 |
+
*/
|
145 |
+
public function getMimeTypes() {
|
146 |
+
global $dg_options;
|
147 |
+
if ( empty( $dg_options['thumber-co']['mime_types'] ) ) {
|
148 |
+
// avoid values being removed as a result of current user but also include any MIME types
|
149 |
+
// that are added outside of the default WP values
|
150 |
+
$wp_types = array_merge( wp_get_mime_types(), get_allowed_mime_types() );
|
151 |
+
|
152 |
+
$allowed = array_intersect( $wp_types, parent::getMimeTypes() );
|
153 |
+
$dg_options['thumber-co']['mime_types'] = array_keys( $allowed );
|
154 |
+
DocumentGallery::setOptions( $dg_options );
|
155 |
+
}
|
156 |
+
|
157 |
+
return $dg_options['thumber-co']['mime_types'];
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* @param $err string Fires on fatal error.
|
162 |
+
*/
|
163 |
+
protected function handleError($err) {
|
164 |
+
DG_Logger::writeLog( DG_LogLevel::Error, $err );
|
165 |
+
}
|
166 |
+
}
|
inc/thumbers/thumber-co/thumber-client/LICENSE.txt
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Copyright 2015 Lambda Services
|
2 |
+
|
3 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4 |
+
you may not use this file except in compliance with the License.
|
5 |
+
You may obtain a copy of the License at
|
6 |
+
|
7 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
8 |
+
|
9 |
+
Unless required by applicable law or agreed to in writing, software
|
10 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 |
+
See the License for the specific language governing permissions and
|
13 |
+
limitations under the License.
|
inc/thumbers/thumber-co/thumber-client/base-transaction.php
ADDED
@@ -0,0 +1,249 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class ThumberBaseTransaction The base transaction class which performs all necessary cryptographic work in addition
|
5 |
+
* to reflectively (de)serializing JSON for all transactions.
|
6 |
+
*
|
7 |
+
* Any request with no fields other than those required for authentication may be sent directly using this class,
|
8 |
+
* other requests with custom parameters will need to extend this class.
|
9 |
+
*/
|
10 |
+
class ThumberBaseTransaction {
|
11 |
+
/**
|
12 |
+
* Constructs new ThumberTransaction instance.
|
13 |
+
*
|
14 |
+
* @param string $json JSON string to for populating instance.
|
15 |
+
*/
|
16 |
+
public function __construct($json = null) {
|
17 |
+
if (!is_null($json)) {
|
18 |
+
$this->fromJson($json);
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var string The UID for API user. Note that only requests will set this value.
|
24 |
+
*/
|
25 |
+
protected $uid;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Sets the UID.
|
29 |
+
*
|
30 |
+
* @param string $uid The UID.
|
31 |
+
*/
|
32 |
+
public function setUid($uid) {
|
33 |
+
$this->uid = $uid;
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Gets the UID.
|
38 |
+
*
|
39 |
+
* @return string The UID.
|
40 |
+
*/
|
41 |
+
public function getUid() {
|
42 |
+
return $this->uid;
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @var string The unique identifier for this transaction set (same used in both req & resultant resp).
|
47 |
+
*/
|
48 |
+
protected $nonce;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Sets the NONCE. Generates the NONCE from microtime() if none is given.
|
52 |
+
*
|
53 |
+
* @param string $nonce The NONCE.
|
54 |
+
*/
|
55 |
+
public function setNonce($nonce = null) {
|
56 |
+
if (is_null($nonce)) {
|
57 |
+
$nonce = md5(microtime());
|
58 |
+
}
|
59 |
+
|
60 |
+
$this->nonce = $nonce;
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Gets the NONCE.
|
65 |
+
*
|
66 |
+
* @return string The NONCE.
|
67 |
+
*/
|
68 |
+
public function getNonce() {
|
69 |
+
return $this->nonce;
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* @var int The UTC timestamp representing when this transaction was sent.
|
74 |
+
*/
|
75 |
+
protected $timestamp;
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Sets the timestamp.
|
79 |
+
*
|
80 |
+
* @param int $timestamp The timestamp.
|
81 |
+
*/
|
82 |
+
public function setTimestamp($timestamp) {
|
83 |
+
$this->timestamp = $timestamp;
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Gets the timestamp.
|
88 |
+
*
|
89 |
+
* @return int The timestamp.
|
90 |
+
*/
|
91 |
+
public function getTimestamp() {
|
92 |
+
return $this->timestamp;
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* @var string The checksum which is calculated with the contents of the
|
97 |
+
* transaction (minus the checksum) and the user's secret with the HMAC-SHA256 algorithm.
|
98 |
+
*/
|
99 |
+
protected $checksum;
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Sets the checksum.
|
103 |
+
*
|
104 |
+
* @param string $checksum The checksum.
|
105 |
+
*/
|
106 |
+
public function setChecksum($checksum) {
|
107 |
+
$this->checksum = $checksum;
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Gets the checksum.
|
112 |
+
*
|
113 |
+
* @return string The checksum.
|
114 |
+
*/
|
115 |
+
public function getChecksum() {
|
116 |
+
return $this->checksum;
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Whether this instance is valid. If secret is provided, then validity will include checksum validation.
|
121 |
+
*
|
122 |
+
* @param string $secret The user secret.
|
123 |
+
* @return bool Whether this instance is valid.
|
124 |
+
*/
|
125 |
+
public function isValid($secret = null) {
|
126 |
+
// NOTE: Doesn't check UID because this class is used in representing req & resp. Not ideal solution.
|
127 |
+
return isset($this->nonce) &&
|
128 |
+
isset($this->timestamp) &&
|
129 |
+
isset($this->checksum) &&
|
130 |
+
(is_null($secret) || $this->isValidChecksum($secret));
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Computes checksum for this instance and compares against the value set as the instance checksum.
|
135 |
+
*
|
136 |
+
* @param string $secret The user secret.
|
137 |
+
* @return bool Whether this instance's checksum value is valid for this instance's contents.
|
138 |
+
*/
|
139 |
+
public function isValidChecksum($secret) {
|
140 |
+
return $this->checksum === $this->computeChecksum($secret);
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Computes checksum based on instance variables.
|
145 |
+
*
|
146 |
+
* @param string $secret The user secret.
|
147 |
+
* @return string The checksum representing this instance.
|
148 |
+
*/
|
149 |
+
public function computeChecksum($secret) {
|
150 |
+
$arr = $this->toArray();
|
151 |
+
unset($arr['checksum']);
|
152 |
+
|
153 |
+
// only use up to the first 1024 characters of each value in computing checksum
|
154 |
+
foreach ($arr as &$v) {
|
155 |
+
if (is_bool($v)) {
|
156 |
+
$v = $v ? 'true' : 'false';
|
157 |
+
} else {
|
158 |
+
$v = substr((string)$v, 0, 1024);
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
ksort($arr, SORT_STRING);
|
163 |
+
|
164 |
+
return hash_hmac('sha256', $this->toQuery($arr), $secret, false);
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Gets array representation of this instance reflectively. Any public/protected instance variables in this
|
169 |
+
* or any extending classes will be included.
|
170 |
+
*
|
171 |
+
* @return array Array representation of this instance.
|
172 |
+
*/
|
173 |
+
public function toArray() {
|
174 |
+
$ret = array();
|
175 |
+
|
176 |
+
foreach($this as $k => $v) {
|
177 |
+
if (is_null($v)) continue;
|
178 |
+
|
179 |
+
// camel case to underscore word delineation
|
180 |
+
$k = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $k));
|
181 |
+
$ret[$k] = $v;
|
182 |
+
}
|
183 |
+
|
184 |
+
return $ret;
|
185 |
+
}
|
186 |
+
|
187 |
+
/**
|
188 |
+
* @param array|NULL $arr The array to be converted. If null, $this->toArray() is used.
|
189 |
+
* @return string The resultant query string.
|
190 |
+
*/
|
191 |
+
public function toQuery($arr = null) {
|
192 |
+
return self::implode('=', '&', !is_null($arr) ? $arr : $this->toArray());
|
193 |
+
}
|
194 |
+
|
195 |
+
/**
|
196 |
+
* Creates JSON string with class fields, renaming field names to underscore rather than camel.
|
197 |
+
*
|
198 |
+
* @return string JSON representation of defined object accessible non-static properties.
|
199 |
+
*/
|
200 |
+
public function toJson() {
|
201 |
+
return json_encode($this->toArray());
|
202 |
+
}
|
203 |
+
|
204 |
+
/**
|
205 |
+
* Populates instance with values from JSON.
|
206 |
+
*
|
207 |
+
* @param string $json The JSON string to populate this instance with.
|
208 |
+
*/
|
209 |
+
public function fromJson($json) {
|
210 |
+
$json = json_decode($json, true);
|
211 |
+
if (is_null($json)) {
|
212 |
+
throw new InvalidArgumentException("Provided JSON string is invalid: $json");
|
213 |
+
}
|
214 |
+
|
215 |
+
foreach ($json as $k => $v) {
|
216 |
+
// underscore word delineation to camel case
|
217 |
+
$k = preg_replace_callback('/_([a-z])/', array (__CLASS__, 'secondCharToUpper'), $k);
|
218 |
+
if (property_exists($this, $k)) {
|
219 |
+
$this->$k = $v;
|
220 |
+
}
|
221 |
+
}
|
222 |
+
}
|
223 |
+
|
224 |
+
/**
|
225 |
+
* @param string $string To take second char from.
|
226 |
+
* @return char Capitalized second char of given string.
|
227 |
+
*/
|
228 |
+
private static function secondCharToUpper($string) {
|
229 |
+
return strtoupper($string[1]);
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Implodes associative array.
|
234 |
+
* @param string $inner Glue between key and value.
|
235 |
+
* @param string $outer Glue between key-value pairs.
|
236 |
+
* @param array $arr The array to be imploded.
|
237 |
+
* @return string The implosion.
|
238 |
+
*/
|
239 |
+
private static function implode($inner, $outer, $arr) {
|
240 |
+
if (count($arr) == 0) return '';
|
241 |
+
$ret = '';
|
242 |
+
|
243 |
+
foreach ($arr as $k => $v) {
|
244 |
+
$ret .= "$k$inner$v$outer";
|
245 |
+
}
|
246 |
+
|
247 |
+
return substr($ret , 0, -strlen($outer));
|
248 |
+
}
|
249 |
+
}
|
inc/thumbers/thumber-co/thumber-client/client.php
ADDED
@@ -0,0 +1,298 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class to process sending requests and receiving responses.
|
5 |
+
*/
|
6 |
+
class ThumberClient {
|
7 |
+
/**
|
8 |
+
* The Thumber.co API subdomain.
|
9 |
+
*/
|
10 |
+
const ThumberServerHost = 'api.thumber.co';
|
11 |
+
|
12 |
+
/**
|
13 |
+
* The path for creating a new thumbnail.
|
14 |
+
*/
|
15 |
+
const ThumberServerCreatePath = '/create.json';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* The path for GETting the user's current subscription info.
|
19 |
+
*/
|
20 |
+
const ThumberSubscriptionPath = '/subscription.json';
|
21 |
+
|
22 |
+
/**
|
23 |
+
* The path for GETting the supported MIME types.
|
24 |
+
*/
|
25 |
+
const ThumberServerMimeTypesPath = '/mime_types.json';
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @var string The user agent to send HTTP requests as.
|
29 |
+
*/
|
30 |
+
protected $thumberUserAgent;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @var string UID for the user accessing the Thumber API.
|
34 |
+
*/
|
35 |
+
protected $uid;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @param $uid string UID for the user accessing the Thumber API.
|
39 |
+
*/
|
40 |
+
public function setUid($uid) {
|
41 |
+
$this->uid = $uid;
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* @var string The user secret assoicataed with the UID for the user
|
46 |
+
* accessing the Thumber API.
|
47 |
+
*/
|
48 |
+
protected $userSecret;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* @param $userSecret string The user secret assoicataed with the UID for the user
|
52 |
+
* accessing the Thumber API.
|
53 |
+
*/
|
54 |
+
public function setUserSecret($userSecret) {
|
55 |
+
$this->userSecret = $userSecret;
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* @var string Fully-qualified system path to this file.
|
60 |
+
*/
|
61 |
+
private $thumberClientPath;
|
62 |
+
|
63 |
+
/**
|
64 |
+
* @var object The subscription object.
|
65 |
+
*/
|
66 |
+
private static $subscription;
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @var array The supported MIME types.
|
70 |
+
*/
|
71 |
+
private static $mime_types;
|
72 |
+
|
73 |
+
/**
|
74 |
+
* @var ThumberClient Backs the getter.
|
75 |
+
*/
|
76 |
+
private static $instance;
|
77 |
+
|
78 |
+
/**
|
79 |
+
* @return ThumberClient The singleton instance.
|
80 |
+
*/
|
81 |
+
public static function getInstance() {
|
82 |
+
return isset( self::$instance ) ? self::$instance : ( self::$instance = new ThumberClient() );
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Initialized class members.
|
87 |
+
*/
|
88 |
+
protected function __construct() {
|
89 |
+
$this->thumberUserAgent = 'Thumber Client 1.0 (PHP ' . phpversion() . '; ' . php_uname() . ')';
|
90 |
+
$this->thumberClientPath = dirname( __FILE__ ) . '/';
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Sends the provided request to Thumber for processing.
|
95 |
+
*
|
96 |
+
* NOTE: Caller should consider testing file size against getSubscription()->file_size_limit to avoid unnecessary
|
97 |
+
* HTTP requests when the file will be rejected.
|
98 |
+
*
|
99 |
+
* @param ThumberThumbReq $req The request to be sent.
|
100 |
+
* @return array The results of sending the request.
|
101 |
+
*/
|
102 |
+
public function sendThumbRequest($req) {
|
103 |
+
if (!($req instanceof ThumberThumbReq)) {
|
104 |
+
$err = 'Request must be of type ThumberThumbReq.';
|
105 |
+
$this->handleError($err);
|
106 |
+
return array('error' => $err);
|
107 |
+
}
|
108 |
+
|
109 |
+
return $this->sendRequest($req, 'POST', self::ThumberServerCreatePath);
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Processes the POST request, generating a ThumberResponse, validating, and passing the result to $callback.
|
114 |
+
* If not using client.php as the webhook, whoever receives webhook response should first invoke this method to
|
115 |
+
* validate response.
|
116 |
+
*/
|
117 |
+
public function receiveThumbResponse() {
|
118 |
+
include_once $this->thumberClientPath . 'thumb-response.php';
|
119 |
+
|
120 |
+
$json = stream_get_contents(fopen('php://input', 'r'));
|
121 |
+
$resp = ThumberThumbResp::parseJson($json);
|
122 |
+
|
123 |
+
if (is_null($resp)) {
|
124 |
+
$this->handleError('Failed to parse JSON in POST body: ' . $json);
|
125 |
+
return null;
|
126 |
+
}
|
127 |
+
|
128 |
+
if (!$resp->isValid($this->userSecret)) {
|
129 |
+
$this->handleError('Received invalid response: ' . $json);
|
130 |
+
return null;
|
131 |
+
}
|
132 |
+
|
133 |
+
// This method should be overridden in order to use response
|
134 |
+
return $resp;
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* @return object|null Returns an object with subscription information. Object includes the following:
|
139 |
+
* name, monthly_cost, watermark, direct_upload, thumbs_per_hr_limit, file_size_limit, and thumb_size_limit.
|
140 |
+
*/
|
141 |
+
public function getSubscription() {
|
142 |
+
include_once $this->thumberClientPath . 'base-transaction.php';
|
143 |
+
|
144 |
+
if (isset(self::$subscription)) {
|
145 |
+
return self::$subscription;
|
146 |
+
} else {
|
147 |
+
$resp = $this->sendRequest(new ThumberBaseTransaction(), 'GET', self::ThumberSubscriptionPath);
|
148 |
+
if (!array_key_exists('error', $resp)) {
|
149 |
+
self::$subscription = json_decode($resp['body']);
|
150 |
+
return self::$subscription;
|
151 |
+
} else {
|
152 |
+
$this->handleError('Failed to retrieve subscription: ' . $resp['body']);
|
153 |
+
return null;
|
154 |
+
}
|
155 |
+
}
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Retrieves the supported MIME types from Thumber.
|
160 |
+
* @return array The supported MIME types reported by the Thumber server.
|
161 |
+
*/
|
162 |
+
public function getMimeTypes() {
|
163 |
+
if (!isset(self::$mime_types)) {
|
164 |
+
$headers = array('Content-Type: application/json', 'Content-Length: 0');
|
165 |
+
$result = $this->sendToThumber('GET', self::getThumberUrl(self::ThumberServerMimeTypesPath), $headers);
|
166 |
+
self::$mime_types = !array_key_exists('error', $result) ? json_decode($result['body'], true) : array();
|
167 |
+
}
|
168 |
+
|
169 |
+
return self::$mime_types;
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Sends the provided request to the API endpoint.
|
174 |
+
*
|
175 |
+
* @param ThumberBaseTransaction $req The request to be sent. UID, callback, and timestamp
|
176 |
+
* will be written by client. Additionally, nonce will be set if not already set.
|
177 |
+
* @param string $type The type of HTTP request (GET/POST/etc.)
|
178 |
+
* @param string $path The relative path on Thumber server to contact.
|
179 |
+
* @return array containing data about success of the cURL request.
|
180 |
+
*/
|
181 |
+
public function sendRequest($req, $type, $path) {
|
182 |
+
include_once $this->thumberClientPath . 'base-transaction.php';
|
183 |
+
|
184 |
+
if (!is_a($req, 'ThumberBaseTransaction')) {
|
185 |
+
$err = 'Request must be of type ThumberBaseTransaction.';
|
186 |
+
$this->handleError($err);
|
187 |
+
return array('error' => $err);
|
188 |
+
}
|
189 |
+
|
190 |
+
// whether we've changed any field, requiring recompute of checksum
|
191 |
+
$changed = false;
|
192 |
+
|
193 |
+
$timestamp = $req->getTimestamp();
|
194 |
+
if (empty($timestamp)) {
|
195 |
+
$req->setTimestamp(time());
|
196 |
+
$changed = true;
|
197 |
+
}
|
198 |
+
|
199 |
+
$uid = $req->getUid();
|
200 |
+
if (empty($uid)) {
|
201 |
+
$req->setUid($this->uid);
|
202 |
+
$changed = true;
|
203 |
+
}
|
204 |
+
|
205 |
+
$nonce = $req->getNonce();
|
206 |
+
if (empty($nonce)) {
|
207 |
+
$req->setNonce();
|
208 |
+
$changed = true;
|
209 |
+
}
|
210 |
+
|
211 |
+
$checksum = $req->getChecksum();
|
212 |
+
if ($changed || empty($checksum)) {
|
213 |
+
$req->setChecksum($req->computeChecksum($this->userSecret));
|
214 |
+
}
|
215 |
+
|
216 |
+
if (!$req->isValid($this->userSecret)) {
|
217 |
+
$err = 'Invalid request provided.';
|
218 |
+
$this->handleError($err);
|
219 |
+
return array('error' => $err);
|
220 |
+
}
|
221 |
+
|
222 |
+
$body = '';
|
223 |
+
if ($type == 'GET') {
|
224 |
+
$path .= '?' . $req->toQuery();
|
225 |
+
} else {
|
226 |
+
$body = $req->toJson();
|
227 |
+
}
|
228 |
+
|
229 |
+
$headers = array('Content-Type: application/json', 'Content-Length: ' . strlen($body));
|
230 |
+
$result = $this->sendToThumber($type, self::getThumberUrl($path), $headers, $body);
|
231 |
+
$result['nonce'] = !array_key_exists('error', $result) ? $req->getNonce() : '';
|
232 |
+
|
233 |
+
// caller should handle errors sensibly
|
234 |
+
return $result;
|
235 |
+
}
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Sends cURL request to Thumber server.
|
239 |
+
* @param $type string GET or POST
|
240 |
+
* @param $url string The URL endpoint being targeted.
|
241 |
+
* @param $httpHeaders array The headers to be sent.
|
242 |
+
* @param $body string The POST body. Ignored if type is GET.
|
243 |
+
* @return array The result of the request.
|
244 |
+
*/
|
245 |
+
protected function sendToThumber($type, $url, $httpHeaders, $body = '') {
|
246 |
+
// open connection
|
247 |
+
$ch = curl_init();
|
248 |
+
|
249 |
+
curl_setopt($ch, CURLOPT_USERAGENT, $this->thumberUserAgent);
|
250 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
251 |
+
curl_setopt($ch, CURLOPT_URL, $url);
|
252 |
+
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeaders);
|
253 |
+
if ($type == 'POST') {
|
254 |
+
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
|
255 |
+
}
|
256 |
+
|
257 |
+
// execute post, storing useful information about result
|
258 |
+
$response = curl_exec($ch);
|
259 |
+
$error = curl_error($ch);
|
260 |
+
$result = array (
|
261 |
+
'header' => '',
|
262 |
+
'body' => '',
|
263 |
+
'error' => '',
|
264 |
+
'http_code' => '',
|
265 |
+
'last_url' => ''
|
266 |
+
);
|
267 |
+
|
268 |
+
if ($error === '') {
|
269 |
+
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
270 |
+
|
271 |
+
$result['header'] = substr($response, 0, $header_size);
|
272 |
+
$result['body'] = substr($response, $header_size);
|
273 |
+
$result['http_code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
274 |
+
$result['last_url'] = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
|
275 |
+
} else {
|
276 |
+
$result ['error'] = $error;
|
277 |
+
}
|
278 |
+
|
279 |
+
curl_close($ch);
|
280 |
+
|
281 |
+
return $result;
|
282 |
+
}
|
283 |
+
|
284 |
+
/**
|
285 |
+
* @param string $path The path at Thumber to generate URL from.
|
286 |
+
* @return string The full URL to the given relative path.
|
287 |
+
*/
|
288 |
+
private static function getThumberUrl($path) {
|
289 |
+
return 'http://' . self::ThumberServerHost . $path;
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* @param $err string Fires on fatal error.
|
294 |
+
*/
|
295 |
+
protected function handleError($err) {
|
296 |
+
echo $err;
|
297 |
+
}
|
298 |
+
}
|
inc/thumbers/thumber-co/thumber-client/thumb-request.php
ADDED
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
include_once 'thumb-transaction.php';
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class ThumberThumbReq Object representation of request sent to Thumber in order to get thumbnail for a file.
|
7 |
+
*/
|
8 |
+
class ThumberThumbReq extends ThumberThumbTransaction {
|
9 |
+
/**
|
10 |
+
* @var string The local URL that will be POSTed to with generated thumbnail.
|
11 |
+
*/
|
12 |
+
protected $callback;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Sets the callback URL.
|
16 |
+
*
|
17 |
+
* @param string $callback The callback URL.
|
18 |
+
*/
|
19 |
+
public function setCallback($callback) {
|
20 |
+
$this->callback = $callback;
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Gets the callback URL.
|
25 |
+
*
|
26 |
+
* @return string The callback URL.
|
27 |
+
*/
|
28 |
+
public function getCallback() {
|
29 |
+
return $this->callback;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @var string URL pointing to the file to be thumbed.
|
34 |
+
*/
|
35 |
+
protected $url;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Sets the URL pointing to the file to be thumbed.
|
39 |
+
*
|
40 |
+
* @param string $url The URL.
|
41 |
+
*/
|
42 |
+
public function setUrl($url) {
|
43 |
+
$this->url = $url;
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Gets the URL pointing to the file to be thumbed.
|
48 |
+
*
|
49 |
+
* @return string The URL.
|
50 |
+
*/
|
51 |
+
public function getUrl() {
|
52 |
+
return $this->url;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* The geometry string to use when thumbnail is being sized.
|
57 |
+
* Geometry string should be a valid ImageMagick geometry string
|
58 |
+
* (http://www.imagemagick.org/script/command-line-processing.php#geometry).
|
59 |
+
*
|
60 |
+
* @var string Geometry string for sizing thumbnail.
|
61 |
+
*/
|
62 |
+
protected $geometry;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Sets the geometry string.
|
66 |
+
*
|
67 |
+
* @param string $geometry The geometry string.
|
68 |
+
*/
|
69 |
+
public function setGeometry($geometry) {
|
70 |
+
$this->geometry = $geometry;
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Gets the geometry string.
|
75 |
+
*
|
76 |
+
* @return string The geometry string.
|
77 |
+
*/
|
78 |
+
public function getGeometry() {
|
79 |
+
return $this->geometry;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* 1-indexed page number to be used for generated thumbnail.
|
84 |
+
*
|
85 |
+
* @var int Page number to be used for generated thumbnail.
|
86 |
+
*/
|
87 |
+
protected $pg;
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Sets the page number to be used for generated thumbnail.
|
91 |
+
*
|
92 |
+
* @param int $pg Page number.
|
93 |
+
*/
|
94 |
+
public function setPg($pg) {
|
95 |
+
$this->pg = $pg;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Gets the page number to be used for generated thumbnail.
|
100 |
+
*
|
101 |
+
* @return int Page number.
|
102 |
+
*/
|
103 |
+
public function getPg() {
|
104 |
+
return $this->pg;
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* @var string The mime type of the file being thumbed.
|
109 |
+
*/
|
110 |
+
protected $mimeType;
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Sets the mime type.
|
114 |
+
*
|
115 |
+
* @param string $mimeType The mime type.
|
116 |
+
*/
|
117 |
+
public function setMimeType($mimeType) {
|
118 |
+
$this->mimeType = $mimeType;
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Gets the mime type.
|
123 |
+
*
|
124 |
+
* @return string The mime type.
|
125 |
+
*/
|
126 |
+
public function getMimeType() {
|
127 |
+
return $this->mimeType;
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* (non-PHPdoc)
|
132 |
+
* @see ThumberBaseTransaction::isValid()
|
133 |
+
*/
|
134 |
+
public function isValid($secret = null) {
|
135 |
+
$data = $this->getEncodedData();
|
136 |
+
return parent::isValid($secret) &&
|
137 |
+
isset($this->uid) &&
|
138 |
+
isset($this->callback) &&
|
139 |
+
(isset($this->url) || !empty($data)) &&
|
140 |
+
isset($this->mimeType);
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Creates a ThumberThumbReq instance from the given JSON.
|
145 |
+
* @param string $json The JSON to create instance from.
|
146 |
+
* @return ThumberThumbReq|NULL The resultant object from parsing the JSON.
|
147 |
+
*/
|
148 |
+
public static function parseJson($json) {
|
149 |
+
try {
|
150 |
+
return new ThumberThumbReq($json);
|
151 |
+
} catch (InvalidArgumentException $e) {
|
152 |
+
return null;
|
153 |
+
}
|
154 |
+
}
|
155 |
+
}
|
inc/thumbers/thumber-co/thumber-client/thumb-response.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
include_once 'thumb-transaction.php';
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class ThumberThumbResp Object representation of response from Thumber following thumbnail generation.
|
7 |
+
*/
|
8 |
+
class ThumberThumbResp extends ThumberThumbTransaction {
|
9 |
+
/**
|
10 |
+
* @var bool Whether the related ThumberReq was successful.
|
11 |
+
*/
|
12 |
+
protected $success;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Sets whether the related ThumberReq was successful.
|
16 |
+
*
|
17 |
+
* @param bool $success Whether the related ThumberReq was successful.
|
18 |
+
*/
|
19 |
+
public function setSuccess($success) {
|
20 |
+
$this->success = $success;
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Gets whether the related ThumberReq was successful.
|
25 |
+
*
|
26 |
+
* @return bool Whether the related ThumberReq was successful.
|
27 |
+
*/
|
28 |
+
public function getSuccess() {
|
29 |
+
return $this->success;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* The error string indicating what went wrong.
|
34 |
+
*
|
35 |
+
* @var string The error string.
|
36 |
+
*/
|
37 |
+
protected $error;
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Sets the error string indicating what went wrong.
|
41 |
+
*
|
42 |
+
* @param string $error The error string.
|
43 |
+
*/
|
44 |
+
public function setError($error) {
|
45 |
+
$this->error = $error;
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Gets the error string indicating what went wrong.
|
50 |
+
*
|
51 |
+
* @return string The error string.
|
52 |
+
*/
|
53 |
+
public function getError() {
|
54 |
+
return $this->error;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* (non-PHPdoc)
|
59 |
+
* @see ThumberTransaction::isValid()
|
60 |
+
*/
|
61 |
+
public function isValid($secret = null) {
|
62 |
+
$data = $this->getEncodedData();
|
63 |
+
return parent::isValid($secret) &&
|
64 |
+
is_bool($this->success) &&
|
65 |
+
($this->success ? (!empty($data)) : isset($this->error));
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Creates a ThumberResp instance from the given JSON.
|
70 |
+
* @param string $json The JSON to create instance from.
|
71 |
+
* @return ThumberThumbResp|NULL The resultant object from parsing the JSON.
|
72 |
+
*/
|
73 |
+
public static function parseJson($json) {
|
74 |
+
try {
|
75 |
+
return new ThumberThumbResp($json);
|
76 |
+
} catch (InvalidArgumentException $e) {
|
77 |
+
return null;
|
78 |
+
}
|
79 |
+
}
|
80 |
+
}
|
inc/thumbers/thumber-co/thumber-client/thumb-transaction.php
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
include_once 'base-transaction.php';
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class ThumberThumbTransaction Adds support for a binary "data" field, which is transmitted in base64-encoded format.
|
7 |
+
* This class handles conversion to and from base64 encoding as needed in a lazy manner that avoids more compute than
|
8 |
+
* is necessary only *when* it's necessary.
|
9 |
+
*/
|
10 |
+
abstract class ThumberThumbTransaction extends ThumberBaseTransaction {
|
11 |
+
/**
|
12 |
+
* The base64-encoded data.
|
13 |
+
*
|
14 |
+
* @var string base64-encoded data.
|
15 |
+
*/
|
16 |
+
protected $data;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Sets the base64-encoded data.
|
20 |
+
*
|
21 |
+
* @param string $data The base64-encoded data.
|
22 |
+
*/
|
23 |
+
public function setEncodedData($data) {
|
24 |
+
$this->data = $data;
|
25 |
+
$this->decodedData = null;
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Gets the base64-encoded data.
|
30 |
+
*
|
31 |
+
* NOTE: If only raw data is initialized, this method will populate the base64-encoded data from that value.
|
32 |
+
*
|
33 |
+
* @return string The base64-encoded data.
|
34 |
+
*/
|
35 |
+
public function getEncodedData() {
|
36 |
+
if (empty($this->data) && !empty($this->decodedData)) {
|
37 |
+
$this->data = base64_encode($this->decodedData);
|
38 |
+
}
|
39 |
+
|
40 |
+
return $this->data;
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* The raw file data. Private as opposed to protected to avoid being included in JSON by ThumberBaseTransaction
|
45 |
+
* reflection.
|
46 |
+
*
|
47 |
+
* @var data Raw data read from file.
|
48 |
+
*/
|
49 |
+
private $decodedData;
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Gets the raw file data.
|
53 |
+
*
|
54 |
+
* @param data $decodedData The raw file data.
|
55 |
+
*/
|
56 |
+
public function setDecodedData($decodedData) {
|
57 |
+
$this->decodedData = $decodedData;
|
58 |
+
$this->data = null;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Gets the raw file data.
|
63 |
+
*
|
64 |
+
* NOTE: If only base64 data is initialized, this method will populate the raw data from that value.
|
65 |
+
*
|
66 |
+
* @return data The raw file data.
|
67 |
+
*/
|
68 |
+
public function getDecodedData() {
|
69 |
+
if (empty($this->decodedData) && !empty($this->data)) {
|
70 |
+
$this->decodedData = base64_decode($this->data);
|
71 |
+
}
|
72 |
+
|
73 |
+
return $this->decodedData;
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Gets array representation of this instance.
|
78 |
+
*
|
79 |
+
* @return array Array representation of this instance.
|
80 |
+
*/
|
81 |
+
public function toArray() {
|
82 |
+
// force generation of Base64 data if not yet generated
|
83 |
+
$this->getEncodedData();
|
84 |
+
|
85 |
+
return parent::toArray();
|
86 |
+
}
|
87 |
+
}
|