Version Description
- Add: Support WebP image format
- Add: Support AVIF image format
- Add: Documentation link to readme file
- Optimize: Code cleanup/refactoring
- Optimize: WPCS validation (Phase 1)
- Optimize: Activate links after all other filters
- Optimize: Plugin metadata retrieval
- Update: Confirm WordPress 6.0 compatibility
- Update: Build dependencies
- Update: GitHub issue templates
Download this release
Release Info
Developer | Archetyped |
Plugin | Simple Lightbox |
Version | 2.9.0 |
Comparing to | |
See all releases |
Code changes from version 2.8.1 to 2.9.0
- .gitignore +4 -3
- CONTRIBUTING.md +28 -28
- COPYING +339 -339
- Gruntfile.js +49 -49
- README.md +11 -11
- changelog.txt +356 -343
- client/css/admin.css +1 -1
- client/css/app.css +1 -1
- client/js/dev/lib.admin.js +26 -26
- client/js/dev/lib.core.js +933 -933
- client/js/dev/lib.view.js +4740 -4740
- client/js/prod/lib.admin.js +1 -1
- client/js/prod/lib.core.js +1 -1
- client/js/prod/lib.view.js +1 -1
- client/sass/admin.scss +53 -53
- client/sass/app.scss +9 -9
- composer.json +8 -8
- composer.lock +342 -340
- content-handlers/image/js/dev/handler.image.js +32 -32
- content-handlers/image/js/prod/handler.image.js +1 -1
- controller.php +1891 -1705
- functions.php +24 -24
- grunt/jshint.js +37 -37
- grunt/phplint.js +13 -13
- grunt/sass.js +36 -36
- grunt/uglify.js +20 -20
- grunt/watch.js +56 -56
- includes/class-requirements-check.php +168 -168
- includes/class.admin.php +686 -661
- includes/class.admin_action.php +110 -109
- includes/class.admin_menu.php +41 -40
- includes/class.admin_page.php +188 -187
- includes/class.admin_section.php +53 -51
- includes/class.admin_view.php +553 -529
- includes/class.base.php +561 -555
- includes/class.base_collection.php +369 -369
- includes/class.base_object.php +343 -337
- includes/class.collection_controller.php +57 -57
- includes/class.component.php +135 -135
- includes/class.content_handler.php +82 -82
- includes/class.content_handlers.php +280 -277
- includes/class.field.php +2 -2
- includes/class.field_base.php +1202 -1118
- includes/class.field_collection.php +842 -768
- includes/class.field_type.php +462 -445
- includes/class.fields.php +518 -446
- includes/class.option.php +185 -179
- includes/class.options.php +696 -679
- includes/class.template_tag.php +9 -9
- includes/class.template_tags.php +122 -122
- includes/class.theme.php +0 -54
.gitignore
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
-
.
|
2 |
-
.
|
3 |
-
|
|
|
4 |
vendor/
|
1 |
+
.ds_store
|
2 |
+
.vscode
|
3 |
+
.sass-cache
|
4 |
+
node_modules/
|
5 |
vendor/
|
CONTRIBUTING.md
CHANGED
@@ -1,28 +1,28 @@
|
|
1 |
-
# How to contribute
|
2 |
-
|
3 |
-
User feedback is huge. You're experiencing an issue, want a new feature, or just want to shout to the mountains about how much you love Simple Lightbox? Here's how to do it and get the best outcome.
|
4 |
-
|
5 |
-
## Getting Started
|
6 |
-
|
7 |
-
* Install the [latest version of SLB][latest]
|
8 |
-
* Get a [GitHub account][gh] if you don't already have one.
|
9 |
-
|
10 |
-
Now you're ready to contribute!
|
11 |
-
|
12 |
-
## Reporting Issues
|
13 |
-
|
14 |
-
Because of the vast number and variety of sites WordPress powers, your reports are essential to making sure that SLB works everywhere. Sometimes an issue may be particular to your site's setup and sometimes it might be universal to all users. Either way, you can report your issue here.
|
15 |
-
|
16 |
-
Before reporting an issue, please read [Reporting Issues][report-issue] to ensure that you've provided the necessary information for your issue to be properly investigated.
|
17 |
-
|
18 |
-
|
19 |
-
## Additional Resources
|
20 |
-
|
21 |
-
* [Simple Lightbox's Official Page][slb]
|
22 |
-
* [Simple Lightbox on WordPress.org][slb-wp]
|
23 |
-
|
24 |
-
[slb]: http://archetyped.com/tools/simple-lightbox/ "Simple Lightbox"
|
25 |
-
[slb-wp]: http://wordpress.org/plugins/simple-lightbox
|
26 |
-
[latest]: https://github.com/archetyped/simple-lightbox "Simple Lightbox"
|
27 |
-
[gh]: https://github.com/signup/free "GitHub Signup"
|
28 |
-
[report-issue]: https://github.com/archetyped/simple-lightbox/wiki/Reporting-Issues "Reporting Issues"
|
1 |
+
# How to contribute
|
2 |
+
|
3 |
+
User feedback is huge. You're experiencing an issue, want a new feature, or just want to shout to the mountains about how much you love Simple Lightbox? Here's how to do it and get the best outcome.
|
4 |
+
|
5 |
+
## Getting Started
|
6 |
+
|
7 |
+
* Install the [latest version of SLB][latest]
|
8 |
+
* Get a [GitHub account][gh] if you don't already have one.
|
9 |
+
|
10 |
+
Now you're ready to contribute!
|
11 |
+
|
12 |
+
## Reporting Issues
|
13 |
+
|
14 |
+
Because of the vast number and variety of sites WordPress powers, your reports are essential to making sure that SLB works everywhere. Sometimes an issue may be particular to your site's setup and sometimes it might be universal to all users. Either way, you can report your issue here.
|
15 |
+
|
16 |
+
Before reporting an issue, please read [Reporting Issues][report-issue] to ensure that you've provided the necessary information for your issue to be properly investigated.
|
17 |
+
|
18 |
+
|
19 |
+
## Additional Resources
|
20 |
+
|
21 |
+
* [Simple Lightbox's Official Page][slb]
|
22 |
+
* [Simple Lightbox on WordPress.org][slb-wp]
|
23 |
+
|
24 |
+
[slb]: http://archetyped.com/tools/simple-lightbox/ "Simple Lightbox"
|
25 |
+
[slb-wp]: http://wordpress.org/plugins/simple-lightbox
|
26 |
+
[latest]: https://github.com/archetyped/simple-lightbox "Simple Lightbox"
|
27 |
+
[gh]: https://github.com/signup/free "GitHub Signup"
|
28 |
+
[report-issue]: https://github.com/archetyped/simple-lightbox/wiki/Reporting-Issues "Reporting Issues"
|
COPYING
CHANGED
@@ -1,339 +1,339 @@
|
|
1 |
-
GNU GENERAL PUBLIC LICENSE
|
2 |
-
Version 2, June 1991
|
3 |
-
|
4 |
-
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
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 licenses for most software are designed to take away your
|
12 |
-
freedom to share and change it. By contrast, the GNU General Public
|
13 |
-
License is intended to guarantee your freedom to share and change free
|
14 |
-
software--to make sure the software is free for all its users. This
|
15 |
-
General Public License applies to most of the Free Software
|
16 |
-
Foundation's software and to any other program whose authors commit to
|
17 |
-
using it. (Some other Free Software Foundation software is covered by
|
18 |
-
the GNU Lesser General Public License instead.) You can apply it to
|
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 |
-
this service if you wish), that you receive source code or can get it
|
25 |
-
if you want it, that you can change the software or use pieces of it
|
26 |
-
in new free programs; and that you know you can do these things.
|
27 |
-
|
28 |
-
To protect your rights, we need to make restrictions that forbid
|
29 |
-
anyone to deny you these rights or to ask you to surrender the rights.
|
30 |
-
These restrictions translate to certain responsibilities for you if you
|
31 |
-
distribute copies of the software, or if you modify it.
|
32 |
-
|
33 |
-
For example, if you distribute copies of such a program, whether
|
34 |
-
gratis or for a fee, you must give the recipients all the rights that
|
35 |
-
you have. You must make sure that they, too, receive or can get the
|
36 |
-
source code. And you must show them these terms so they know their
|
37 |
-
rights.
|
38 |
-
|
39 |
-
We protect your rights with two steps: (1) copyright the software, and
|
40 |
-
(2) offer you this license which gives you legal permission to copy,
|
41 |
-
distribute and/or modify the software.
|
42 |
-
|
43 |
-
Also, for each author's protection and ours, we want to make certain
|
44 |
-
that everyone understands that there is no warranty for this free
|
45 |
-
software. If the software is modified by someone else and passed on, we
|
46 |
-
want its recipients to know that what they have is not the original, so
|
47 |
-
that any problems introduced by others will not reflect on the original
|
48 |
-
authors' reputations.
|
49 |
-
|
50 |
-
Finally, any free program is threatened constantly by software
|
51 |
-
patents. We wish to avoid the danger that redistributors of a free
|
52 |
-
program will individually obtain patent licenses, in effect making the
|
53 |
-
program proprietary. To prevent this, we have made it clear that any
|
54 |
-
patent must be licensed for everyone's free use or not licensed at all.
|
55 |
-
|
56 |
-
The precise terms and conditions for copying, distribution and
|
57 |
-
modification follow.
|
58 |
-
|
59 |
-
GNU GENERAL PUBLIC LICENSE
|
60 |
-
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
61 |
-
|
62 |
-
0. This License applies to any program or other work which contains
|
63 |
-
a notice placed by the copyright holder saying it may be distributed
|
64 |
-
under the terms of this General Public License. The "Program", below,
|
65 |
-
refers to any such program or work, and a "work based on the Program"
|
66 |
-
means either the Program or any derivative work under copyright law:
|
67 |
-
that is to say, a work containing the Program or a portion of it,
|
68 |
-
either verbatim or with modifications and/or translated into another
|
69 |
-
language. (Hereinafter, translation is included without limitation in
|
70 |
-
the term "modification".) Each licensee is addressed as "you".
|
71 |
-
|
72 |
-
Activities other than copying, distribution and modification are not
|
73 |
-
covered by this License; they are outside its scope. The act of
|
74 |
-
running the Program is not restricted, and the output from the Program
|
75 |
-
is covered only if its contents constitute a work based on the
|
76 |
-
Program (independent of having been made by running the Program).
|
77 |
-
Whether that is true depends on what the Program does.
|
78 |
-
|
79 |
-
1. You may copy and distribute verbatim copies of the Program's
|
80 |
-
source code as you receive it, in any medium, provided that you
|
81 |
-
conspicuously and appropriately publish on each copy an appropriate
|
82 |
-
copyright notice and disclaimer of warranty; keep intact all the
|
83 |
-
notices that refer to this License and to the absence of any warranty;
|
84 |
-
and give any other recipients of the Program a copy of this License
|
85 |
-
along with the Program.
|
86 |
-
|
87 |
-
You may charge a fee for the physical act of transferring a copy, and
|
88 |
-
you may at your option offer warranty protection in exchange for a fee.
|
89 |
-
|
90 |
-
2. You may modify your copy or copies of the Program or any portion
|
91 |
-
of it, thus forming a work based on the Program, and copy and
|
92 |
-
distribute such modifications or work under the terms of Section 1
|
93 |
-
above, provided that you also meet all of these conditions:
|
94 |
-
|
95 |
-
a) You must cause the modified files to carry prominent notices
|
96 |
-
stating that you changed the files and the date of any change.
|
97 |
-
|
98 |
-
b) You must cause any work that you distribute or publish, that in
|
99 |
-
whole or in part contains or is derived from the Program or any
|
100 |
-
part thereof, to be licensed as a whole at no charge to all third
|
101 |
-
parties under the terms of this License.
|
102 |
-
|
103 |
-
c) If the modified program normally reads commands interactively
|
104 |
-
when run, you must cause it, when started running for such
|
105 |
-
interactive use in the most ordinary way, to print or display an
|
106 |
-
announcement including an appropriate copyright notice and a
|
107 |
-
notice that there is no warranty (or else, saying that you provide
|
108 |
-
a warranty) and that users may redistribute the program under
|
109 |
-
these conditions, and telling the user how to view a copy of this
|
110 |
-
License. (Exception: if the Program itself is interactive but
|
111 |
-
does not normally print such an announcement, your work based on
|
112 |
-
the Program is not required to print an announcement.)
|
113 |
-
|
114 |
-
These requirements apply to the modified work as a whole. If
|
115 |
-
identifiable sections of that work are not derived from the Program,
|
116 |
-
and can be reasonably considered independent and separate works in
|
117 |
-
themselves, then this License, and its terms, do not apply to those
|
118 |
-
sections when you distribute them as separate works. But when you
|
119 |
-
distribute the same sections as part of a whole which is a work based
|
120 |
-
on the Program, the distribution of the whole must be on the terms of
|
121 |
-
this License, whose permissions for other licensees extend to the
|
122 |
-
entire whole, and thus to each and every part regardless of who wrote it.
|
123 |
-
|
124 |
-
Thus, it is not the intent of this section to claim rights or contest
|
125 |
-
your rights to work written entirely by you; rather, the intent is to
|
126 |
-
exercise the right to control the distribution of derivative or
|
127 |
-
collective works based on the Program.
|
128 |
-
|
129 |
-
In addition, mere aggregation of another work not based on the Program
|
130 |
-
with the Program (or with a work based on the Program) on a volume of
|
131 |
-
a storage or distribution medium does not bring the other work under
|
132 |
-
the scope of this License.
|
133 |
-
|
134 |
-
3. You may copy and distribute the Program (or a work based on it,
|
135 |
-
under Section 2) in object code or executable form under the terms of
|
136 |
-
Sections 1 and 2 above provided that you also do one of the following:
|
137 |
-
|
138 |
-
a) Accompany it with the complete corresponding machine-readable
|
139 |
-
source code, which must be distributed under the terms of Sections
|
140 |
-
1 and 2 above on a medium customarily used for software interchange; or,
|
141 |
-
|
142 |
-
b) Accompany it with a written offer, valid for at least three
|
143 |
-
years, to give any third party, for a charge no more than your
|
144 |
-
cost of physically performing source distribution, a complete
|
145 |
-
machine-readable copy of the corresponding source code, to be
|
146 |
-
distributed under the terms of Sections 1 and 2 above on a medium
|
147 |
-
customarily used for software interchange; or,
|
148 |
-
|
149 |
-
c) Accompany it with the information you received as to the offer
|
150 |
-
to distribute corresponding source code. (This alternative is
|
151 |
-
allowed only for noncommercial distribution and only if you
|
152 |
-
received the program in object code or executable form with such
|
153 |
-
an offer, in accord with Subsection b above.)
|
154 |
-
|
155 |
-
The source code for a work means the preferred form of the work for
|
156 |
-
making modifications to it. For an executable work, complete source
|
157 |
-
code means all the source code for all modules it contains, plus any
|
158 |
-
associated interface definition files, plus the scripts used to
|
159 |
-
control compilation and installation of the executable. However, as a
|
160 |
-
special exception, the source code distributed need not include
|
161 |
-
anything that is normally distributed (in either source or binary
|
162 |
-
form) with the major components (compiler, kernel, and so on) of the
|
163 |
-
operating system on which the executable runs, unless that component
|
164 |
-
itself accompanies the executable.
|
165 |
-
|
166 |
-
If distribution of executable or object code is made by offering
|
167 |
-
access to copy from a designated place, then offering equivalent
|
168 |
-
access to copy the source code from the same place counts as
|
169 |
-
distribution of the source code, even though third parties are not
|
170 |
-
compelled to copy the source along with the object code.
|
171 |
-
|
172 |
-
4. You may not copy, modify, sublicense, or distribute the Program
|
173 |
-
except as expressly provided under this License. Any attempt
|
174 |
-
otherwise to copy, modify, sublicense or distribute the Program is
|
175 |
-
void, and will automatically terminate your rights under this License.
|
176 |
-
However, parties who have received copies, or rights, from you under
|
177 |
-
this License will not have their licenses terminated so long as such
|
178 |
-
parties remain in full compliance.
|
179 |
-
|
180 |
-
5. You are not required to accept this License, since you have not
|
181 |
-
signed it. However, nothing else grants you permission to modify or
|
182 |
-
distribute the Program or its derivative works. These actions are
|
183 |
-
prohibited by law if you do not accept this License. Therefore, by
|
184 |
-
modifying or distributing the Program (or any work based on the
|
185 |
-
Program), you indicate your acceptance of this License to do so, and
|
186 |
-
all its terms and conditions for copying, distributing or modifying
|
187 |
-
the Program or works based on it.
|
188 |
-
|
189 |
-
6. Each time you redistribute the Program (or any work based on the
|
190 |
-
Program), the recipient automatically receives a license from the
|
191 |
-
original licensor to copy, distribute or modify the Program subject to
|
192 |
-
these terms and conditions. You may not impose any further
|
193 |
-
restrictions on the recipients' exercise of the rights granted herein.
|
194 |
-
You are not responsible for enforcing compliance by third parties to
|
195 |
-
this License.
|
196 |
-
|
197 |
-
7. If, as a consequence of a court judgment or allegation of patent
|
198 |
-
infringement or for any other reason (not limited to patent issues),
|
199 |
-
conditions are imposed on you (whether by court order, agreement or
|
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 |
-
distribute so as to satisfy simultaneously your obligations under this
|
203 |
-
License and any other pertinent obligations, then as a consequence you
|
204 |
-
may not distribute the Program at all. For example, if a patent
|
205 |
-
license would not permit royalty-free redistribution of the Program by
|
206 |
-
all those who receive copies directly or indirectly through you, then
|
207 |
-
the only way you could satisfy both it and this License would be to
|
208 |
-
refrain entirely from distribution of the Program.
|
209 |
-
|
210 |
-
If any portion of this section is held invalid or unenforceable under
|
211 |
-
any particular circumstance, the balance of the section is intended to
|
212 |
-
apply and the section as a whole is intended to apply in other
|
213 |
-
circumstances.
|
214 |
-
|
215 |
-
It is not the purpose of this section to induce you to infringe any
|
216 |
-
patents or other property right claims or to contest validity of any
|
217 |
-
such claims; this section has the sole purpose of protecting the
|
218 |
-
integrity of the free software distribution system, which is
|
219 |
-
implemented by public license practices. Many people have made
|
220 |
-
generous contributions to the wide range of software distributed
|
221 |
-
through that system in reliance on consistent application of that
|
222 |
-
system; it is up to the author/donor to decide if he or she is willing
|
223 |
-
to distribute software through any other system and a licensee cannot
|
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 Program
|
243 |
-
specifies a version number of this License which applies to it and "any
|
244 |
-
later version", you have the option of following the terms and conditions
|
245 |
-
either of that version or of any later version published by the Free
|
246 |
-
Software Foundation. If the Program does not specify a version number of
|
247 |
-
this License, you may choose any version ever published by the Free Software
|
248 |
-
Foundation.
|
249 |
-
|
250 |
-
10. If you wish to incorporate parts of the Program into other free
|
251 |
-
programs whose distribution conditions are different, write to the author
|
252 |
-
to ask for permission. For software which is copyrighted by the Free
|
253 |
-
Software Foundation, write to the Free Software Foundation; we sometimes
|
254 |
-
make exceptions for this. Our decision will be guided by the two goals
|
255 |
-
of preserving the free status of all derivatives of our free software and
|
256 |
-
of promoting the sharing and reuse of software generally.
|
257 |
-
|
258 |
-
NO WARRANTY
|
259 |
-
|
260 |
-
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
261 |
-
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
262 |
-
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
263 |
-
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
264 |
-
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
265 |
-
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
266 |
-
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
267 |
-
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
268 |
-
REPAIR OR CORRECTION.
|
269 |
-
|
270 |
-
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
271 |
-
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
272 |
-
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
273 |
-
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
274 |
-
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
275 |
-
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
276 |
-
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
277 |
-
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
278 |
-
POSSIBILITY OF SUCH DAMAGES.
|
279 |
-
|
280 |
-
END OF TERMS AND CONDITIONS
|
281 |
-
|
282 |
-
How to Apply These Terms to Your New Programs
|
283 |
-
|
284 |
-
If you develop a new program, and you want it to be of the greatest
|
285 |
-
possible use to the public, the best way to achieve this is to make it
|
286 |
-
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 |
-
convey the exclusion of warranty; and each file should have at least
|
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; you can redistribute it and/or modify
|
297 |
-
it under the terms of the GNU General Public License as published by
|
298 |
-
the Free Software Foundation; either version 2 of the License, or
|
299 |
-
(at your option) any later version.
|
300 |
-
|
301 |
-
This program is distributed in the hope that it will be useful,
|
302 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
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 along
|
307 |
-
with this program; if not, write to the Free Software Foundation, Inc.,
|
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 is interactive, make it output a short notice like this
|
313 |
-
when it starts in an interactive mode:
|
314 |
-
|
315 |
-
Gnomovision version 69, Copyright (C) year name of author
|
316 |
-
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
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, the commands you use may
|
322 |
-
be called something other than `show w' and `show c'; they could even be
|
323 |
-
mouse-clicks or menu items--whatever suits your program.
|
324 |
-
|
325 |
-
You should also get your employer (if you work as a programmer) or your
|
326 |
-
school, if any, to sign a "copyright disclaimer" for the program, if
|
327 |
-
necessary. Here is a sample; alter the names:
|
328 |
-
|
329 |
-
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
330 |
-
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
331 |
-
|
332 |
-
<signature of Ty Coon>, 1 April 1989
|
333 |
-
Ty Coon, President of Vice
|
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 2, June 1991
|
3 |
+
|
4 |
+
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
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 licenses for most software are designed to take away your
|
12 |
+
freedom to share and change it. By contrast, the GNU General Public
|
13 |
+
License is intended to guarantee your freedom to share and change free
|
14 |
+
software--to make sure the software is free for all its users. This
|
15 |
+
General Public License applies to most of the Free Software
|
16 |
+
Foundation's software and to any other program whose authors commit to
|
17 |
+
using it. (Some other Free Software Foundation software is covered by
|
18 |
+
the GNU Lesser General Public License instead.) You can apply it to
|
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 |
+
this service if you wish), that you receive source code or can get it
|
25 |
+
if you want it, that you can change the software or use pieces of it
|
26 |
+
in new free programs; and that you know you can do these things.
|
27 |
+
|
28 |
+
To protect your rights, we need to make restrictions that forbid
|
29 |
+
anyone to deny you these rights or to ask you to surrender the rights.
|
30 |
+
These restrictions translate to certain responsibilities for you if you
|
31 |
+
distribute copies of the software, or if you modify it.
|
32 |
+
|
33 |
+
For example, if you distribute copies of such a program, whether
|
34 |
+
gratis or for a fee, you must give the recipients all the rights that
|
35 |
+
you have. You must make sure that they, too, receive or can get the
|
36 |
+
source code. And you must show them these terms so they know their
|
37 |
+
rights.
|
38 |
+
|
39 |
+
We protect your rights with two steps: (1) copyright the software, and
|
40 |
+
(2) offer you this license which gives you legal permission to copy,
|
41 |
+
distribute and/or modify the software.
|
42 |
+
|
43 |
+
Also, for each author's protection and ours, we want to make certain
|
44 |
+
that everyone understands that there is no warranty for this free
|
45 |
+
software. If the software is modified by someone else and passed on, we
|
46 |
+
want its recipients to know that what they have is not the original, so
|
47 |
+
that any problems introduced by others will not reflect on the original
|
48 |
+
authors' reputations.
|
49 |
+
|
50 |
+
Finally, any free program is threatened constantly by software
|
51 |
+
patents. We wish to avoid the danger that redistributors of a free
|
52 |
+
program will individually obtain patent licenses, in effect making the
|
53 |
+
program proprietary. To prevent this, we have made it clear that any
|
54 |
+
patent must be licensed for everyone's free use or not licensed at all.
|
55 |
+
|
56 |
+
The precise terms and conditions for copying, distribution and
|
57 |
+
modification follow.
|
58 |
+
|
59 |
+
GNU GENERAL PUBLIC LICENSE
|
60 |
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
61 |
+
|
62 |
+
0. This License applies to any program or other work which contains
|
63 |
+
a notice placed by the copyright holder saying it may be distributed
|
64 |
+
under the terms of this General Public License. The "Program", below,
|
65 |
+
refers to any such program or work, and a "work based on the Program"
|
66 |
+
means either the Program or any derivative work under copyright law:
|
67 |
+
that is to say, a work containing the Program or a portion of it,
|
68 |
+
either verbatim or with modifications and/or translated into another
|
69 |
+
language. (Hereinafter, translation is included without limitation in
|
70 |
+
the term "modification".) Each licensee is addressed as "you".
|
71 |
+
|
72 |
+
Activities other than copying, distribution and modification are not
|
73 |
+
covered by this License; they are outside its scope. The act of
|
74 |
+
running the Program is not restricted, and the output from the Program
|
75 |
+
is covered only if its contents constitute a work based on the
|
76 |
+
Program (independent of having been made by running the Program).
|
77 |
+
Whether that is true depends on what the Program does.
|
78 |
+
|
79 |
+
1. You may copy and distribute verbatim copies of the Program's
|
80 |
+
source code as you receive it, in any medium, provided that you
|
81 |
+
conspicuously and appropriately publish on each copy an appropriate
|
82 |
+
copyright notice and disclaimer of warranty; keep intact all the
|
83 |
+
notices that refer to this License and to the absence of any warranty;
|
84 |
+
and give any other recipients of the Program a copy of this License
|
85 |
+
along with the Program.
|
86 |
+
|
87 |
+
You may charge a fee for the physical act of transferring a copy, and
|
88 |
+
you may at your option offer warranty protection in exchange for a fee.
|
89 |
+
|
90 |
+
2. You may modify your copy or copies of the Program or any portion
|
91 |
+
of it, thus forming a work based on the Program, and copy and
|
92 |
+
distribute such modifications or work under the terms of Section 1
|
93 |
+
above, provided that you also meet all of these conditions:
|
94 |
+
|
95 |
+
a) You must cause the modified files to carry prominent notices
|
96 |
+
stating that you changed the files and the date of any change.
|
97 |
+
|
98 |
+
b) You must cause any work that you distribute or publish, that in
|
99 |
+
whole or in part contains or is derived from the Program or any
|
100 |
+
part thereof, to be licensed as a whole at no charge to all third
|
101 |
+
parties under the terms of this License.
|
102 |
+
|
103 |
+
c) If the modified program normally reads commands interactively
|
104 |
+
when run, you must cause it, when started running for such
|
105 |
+
interactive use in the most ordinary way, to print or display an
|
106 |
+
announcement including an appropriate copyright notice and a
|
107 |
+
notice that there is no warranty (or else, saying that you provide
|
108 |
+
a warranty) and that users may redistribute the program under
|
109 |
+
these conditions, and telling the user how to view a copy of this
|
110 |
+
License. (Exception: if the Program itself is interactive but
|
111 |
+
does not normally print such an announcement, your work based on
|
112 |
+
the Program is not required to print an announcement.)
|
113 |
+
|
114 |
+
These requirements apply to the modified work as a whole. If
|
115 |
+
identifiable sections of that work are not derived from the Program,
|
116 |
+
and can be reasonably considered independent and separate works in
|
117 |
+
themselves, then this License, and its terms, do not apply to those
|
118 |
+
sections when you distribute them as separate works. But when you
|
119 |
+
distribute the same sections as part of a whole which is a work based
|
120 |
+
on the Program, the distribution of the whole must be on the terms of
|
121 |
+
this License, whose permissions for other licensees extend to the
|
122 |
+
entire whole, and thus to each and every part regardless of who wrote it.
|
123 |
+
|
124 |
+
Thus, it is not the intent of this section to claim rights or contest
|
125 |
+
your rights to work written entirely by you; rather, the intent is to
|
126 |
+
exercise the right to control the distribution of derivative or
|
127 |
+
collective works based on the Program.
|
128 |
+
|
129 |
+
In addition, mere aggregation of another work not based on the Program
|
130 |
+
with the Program (or with a work based on the Program) on a volume of
|
131 |
+
a storage or distribution medium does not bring the other work under
|
132 |
+
the scope of this License.
|
133 |
+
|
134 |
+
3. You may copy and distribute the Program (or a work based on it,
|
135 |
+
under Section 2) in object code or executable form under the terms of
|
136 |
+
Sections 1 and 2 above provided that you also do one of the following:
|
137 |
+
|
138 |
+
a) Accompany it with the complete corresponding machine-readable
|
139 |
+
source code, which must be distributed under the terms of Sections
|
140 |
+
1 and 2 above on a medium customarily used for software interchange; or,
|
141 |
+
|
142 |
+
b) Accompany it with a written offer, valid for at least three
|
143 |
+
years, to give any third party, for a charge no more than your
|
144 |
+
cost of physically performing source distribution, a complete
|
145 |
+
machine-readable copy of the corresponding source code, to be
|
146 |
+
distributed under the terms of Sections 1 and 2 above on a medium
|
147 |
+
customarily used for software interchange; or,
|
148 |
+
|
149 |
+
c) Accompany it with the information you received as to the offer
|
150 |
+
to distribute corresponding source code. (This alternative is
|
151 |
+
allowed only for noncommercial distribution and only if you
|
152 |
+
received the program in object code or executable form with such
|
153 |
+
an offer, in accord with Subsection b above.)
|
154 |
+
|
155 |
+
The source code for a work means the preferred form of the work for
|
156 |
+
making modifications to it. For an executable work, complete source
|
157 |
+
code means all the source code for all modules it contains, plus any
|
158 |
+
associated interface definition files, plus the scripts used to
|
159 |
+
control compilation and installation of the executable. However, as a
|
160 |
+
special exception, the source code distributed need not include
|
161 |
+
anything that is normally distributed (in either source or binary
|
162 |
+
form) with the major components (compiler, kernel, and so on) of the
|
163 |
+
operating system on which the executable runs, unless that component
|
164 |
+
itself accompanies the executable.
|
165 |
+
|
166 |
+
If distribution of executable or object code is made by offering
|
167 |
+
access to copy from a designated place, then offering equivalent
|
168 |
+
access to copy the source code from the same place counts as
|
169 |
+
distribution of the source code, even though third parties are not
|
170 |
+
compelled to copy the source along with the object code.
|
171 |
+
|
172 |
+
4. You may not copy, modify, sublicense, or distribute the Program
|
173 |
+
except as expressly provided under this License. Any attempt
|
174 |
+
otherwise to copy, modify, sublicense or distribute the Program is
|
175 |
+
void, and will automatically terminate your rights under this License.
|
176 |
+
However, parties who have received copies, or rights, from you under
|
177 |
+
this License will not have their licenses terminated so long as such
|
178 |
+
parties remain in full compliance.
|
179 |
+
|
180 |
+
5. You are not required to accept this License, since you have not
|
181 |
+
signed it. However, nothing else grants you permission to modify or
|
182 |
+
distribute the Program or its derivative works. These actions are
|
183 |
+
prohibited by law if you do not accept this License. Therefore, by
|
184 |
+
modifying or distributing the Program (or any work based on the
|
185 |
+
Program), you indicate your acceptance of this License to do so, and
|
186 |
+
all its terms and conditions for copying, distributing or modifying
|
187 |
+
the Program or works based on it.
|
188 |
+
|
189 |
+
6. Each time you redistribute the Program (or any work based on the
|
190 |
+
Program), the recipient automatically receives a license from the
|
191 |
+
original licensor to copy, distribute or modify the Program subject to
|
192 |
+
these terms and conditions. You may not impose any further
|
193 |
+
restrictions on the recipients' exercise of the rights granted herein.
|
194 |
+
You are not responsible for enforcing compliance by third parties to
|
195 |
+
this License.
|
196 |
+
|
197 |
+
7. If, as a consequence of a court judgment or allegation of patent
|
198 |
+
infringement or for any other reason (not limited to patent issues),
|
199 |
+
conditions are imposed on you (whether by court order, agreement or
|
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 |
+
distribute so as to satisfy simultaneously your obligations under this
|
203 |
+
License and any other pertinent obligations, then as a consequence you
|
204 |
+
may not distribute the Program at all. For example, if a patent
|
205 |
+
license would not permit royalty-free redistribution of the Program by
|
206 |
+
all those who receive copies directly or indirectly through you, then
|
207 |
+
the only way you could satisfy both it and this License would be to
|
208 |
+
refrain entirely from distribution of the Program.
|
209 |
+
|
210 |
+
If any portion of this section is held invalid or unenforceable under
|
211 |
+
any particular circumstance, the balance of the section is intended to
|
212 |
+
apply and the section as a whole is intended to apply in other
|
213 |
+
circumstances.
|
214 |
+
|
215 |
+
It is not the purpose of this section to induce you to infringe any
|
216 |
+
patents or other property right claims or to contest validity of any
|
217 |
+
such claims; this section has the sole purpose of protecting the
|
218 |
+
integrity of the free software distribution system, which is
|
219 |
+
implemented by public license practices. Many people have made
|
220 |
+
generous contributions to the wide range of software distributed
|
221 |
+
through that system in reliance on consistent application of that
|
222 |
+
system; it is up to the author/donor to decide if he or she is willing
|
223 |
+
to distribute software through any other system and a licensee cannot
|
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 Program
|
243 |
+
specifies a version number of this License which applies to it and "any
|
244 |
+
later version", you have the option of following the terms and conditions
|
245 |
+
either of that version or of any later version published by the Free
|
246 |
+
Software Foundation. If the Program does not specify a version number of
|
247 |
+
this License, you may choose any version ever published by the Free Software
|
248 |
+
Foundation.
|
249 |
+
|
250 |
+
10. If you wish to incorporate parts of the Program into other free
|
251 |
+
programs whose distribution conditions are different, write to the author
|
252 |
+
to ask for permission. For software which is copyrighted by the Free
|
253 |
+
Software Foundation, write to the Free Software Foundation; we sometimes
|
254 |
+
make exceptions for this. Our decision will be guided by the two goals
|
255 |
+
of preserving the free status of all derivatives of our free software and
|
256 |
+
of promoting the sharing and reuse of software generally.
|
257 |
+
|
258 |
+
NO WARRANTY
|
259 |
+
|
260 |
+
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
261 |
+
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
262 |
+
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
263 |
+
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
264 |
+
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
265 |
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
266 |
+
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
267 |
+
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
268 |
+
REPAIR OR CORRECTION.
|
269 |
+
|
270 |
+
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
271 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
272 |
+
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
273 |
+
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
274 |
+
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
275 |
+
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
276 |
+
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
277 |
+
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
278 |
+
POSSIBILITY OF SUCH DAMAGES.
|
279 |
+
|
280 |
+
END OF TERMS AND CONDITIONS
|
281 |
+
|
282 |
+
How to Apply These Terms to Your New Programs
|
283 |
+
|
284 |
+
If you develop a new program, and you want it to be of the greatest
|
285 |
+
possible use to the public, the best way to achieve this is to make it
|
286 |
+
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 |
+
convey the exclusion of warranty; and each file should have at least
|
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; you can redistribute it and/or modify
|
297 |
+
it under the terms of the GNU General Public License as published by
|
298 |
+
the Free Software Foundation; either version 2 of the License, or
|
299 |
+
(at your option) any later version.
|
300 |
+
|
301 |
+
This program is distributed in the hope that it will be useful,
|
302 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
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 along
|
307 |
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
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 is interactive, make it output a short notice like this
|
313 |
+
when it starts in an interactive mode:
|
314 |
+
|
315 |
+
Gnomovision version 69, Copyright (C) year name of author
|
316 |
+
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
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, the commands you use may
|
322 |
+
be called something other than `show w' and `show c'; they could even be
|
323 |
+
mouse-clicks or menu items--whatever suits your program.
|
324 |
+
|
325 |
+
You should also get your employer (if you work as a programmer) or your
|
326 |
+
school, if any, to sign a "copyright disclaimer" for the program, if
|
327 |
+
necessary. Here is a sample; alter the names:
|
328 |
+
|
329 |
+
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
330 |
+
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
331 |
+
|
332 |
+
<signature of Ty Coon>, 1 April 1989
|
333 |
+
Ty Coon, President of Vice
|
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.
|
Gruntfile.js
CHANGED
@@ -1,49 +1,49 @@
|
|
1 |
-
module.exports = function(grunt) {
|
2 |
-
// Load tasks
|
3 |
-
require('load-grunt-tasks')(grunt);
|
4 |
-
// Display task timing
|
5 |
-
require('time-grunt')(grunt);
|
6 |
-
// Project configuration.
|
7 |
-
grunt.initConfig({
|
8 |
-
// Metadata
|
9 |
-
pkg : grunt.file.readJSON('package.json'),
|
10 |
-
// Variables
|
11 |
-
paths : {
|
12 |
-
// Base dir assets dir
|
13 |
-
base : 'client',
|
14 |
-
|
15 |
-
// PHP assets
|
16 |
-
php : {
|
17 |
-
files_std : ['*.php', '**/*.php', '!node_modules/**/*.php'], // Standard file match
|
18 |
-
files : '<%= paths.php.files_std %>' // Dynamic file match
|
19 |
-
},
|
20 |
-
|
21 |
-
// JavaScript assets
|
22 |
-
js : {
|
23 |
-
base : 'js', // Base dir
|
24 |
-
src : '<%= paths.js.base %>/dev', // Development code
|
25 |
-
dest : '<%= paths.js.base %>/prod', // Production code
|
26 |
-
files_std : '**/<%= paths.js.src %>/**/*.js', // Standard file match
|
27 |
-
files : '<%= paths.js.files_std %>' // Dynamic file match
|
28 |
-
},
|
29 |
-
|
30 |
-
// Sass assets
|
31 |
-
sass : {
|
32 |
-
src : 'sass', // Source files dir
|
33 |
-
dest : 'css', // Compiled files dir
|
34 |
-
ext : '.css', // Compiled extension
|
35 |
-
target : '*.scss', // Only Sass files in CWD
|
36 |
-
exclude : '!_*.scss', // Do not process partials
|
37 |
-
base_src : '<%= paths.base %>/<%= paths.sass.src %>', // Base source dir
|
38 |
-
base_dest : '<%= paths.base %>/<%= paths.sass.dest %>', // Base compile dir
|
39 |
-
}
|
40 |
-
},
|
41 |
-
});
|
42 |
-
|
43 |
-
// Load task configurations
|
44 |
-
grunt.loadTasks('grunt');
|
45 |
-
|
46 |
-
// Default Tasks
|
47 |
-
grunt.registerTask('build', ['
|
48 |
-
grunt.registerTask('watch_all', ['watch:js', 'watch:sass']);
|
49 |
-
};
|
1 |
+
module.exports = function(grunt) {
|
2 |
+
// Load tasks
|
3 |
+
require('load-grunt-tasks')(grunt);
|
4 |
+
// Display task timing
|
5 |
+
require('time-grunt')(grunt);
|
6 |
+
// Project configuration.
|
7 |
+
grunt.initConfig({
|
8 |
+
// Metadata
|
9 |
+
pkg : grunt.file.readJSON('package.json'),
|
10 |
+
// Variables
|
11 |
+
paths : {
|
12 |
+
// Base dir assets dir
|
13 |
+
base : 'client',
|
14 |
+
|
15 |
+
// PHP assets
|
16 |
+
php : {
|
17 |
+
files_std : ['*.php', '**/*.php', '!node_modules/**/*.php'], // Standard file match
|
18 |
+
files : '<%= paths.php.files_std %>' // Dynamic file match
|
19 |
+
},
|
20 |
+
|
21 |
+
// JavaScript assets
|
22 |
+
js : {
|
23 |
+
base : 'js', // Base dir
|
24 |
+
src : '<%= paths.js.base %>/dev', // Development code
|
25 |
+
dest : '<%= paths.js.base %>/prod', // Production code
|
26 |
+
files_std : '**/<%= paths.js.src %>/**/*.js', // Standard file match
|
27 |
+
files : '<%= paths.js.files_std %>' // Dynamic file match
|
28 |
+
},
|
29 |
+
|
30 |
+
// Sass assets
|
31 |
+
sass : {
|
32 |
+
src : 'sass', // Source files dir
|
33 |
+
dest : 'css', // Compiled files dir
|
34 |
+
ext : '.css', // Compiled extension
|
35 |
+
target : '*.scss', // Only Sass files in CWD
|
36 |
+
exclude : '!_*.scss', // Do not process partials
|
37 |
+
base_src : '<%= paths.base %>/<%= paths.sass.src %>', // Base source dir
|
38 |
+
base_dest : '<%= paths.base %>/<%= paths.sass.dest %>', // Base compile dir
|
39 |
+
}
|
40 |
+
},
|
41 |
+
});
|
42 |
+
|
43 |
+
// Load task configurations
|
44 |
+
grunt.loadTasks('grunt');
|
45 |
+
|
46 |
+
// Default Tasks
|
47 |
+
grunt.registerTask('build', ['jshint:all', 'uglify', 'sass']);
|
48 |
+
grunt.registerTask('watch_all', ['watch:js', 'watch:sass']);
|
49 |
+
};
|
README.md
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
-
Simple Lightbox
|
2 |
-
===============
|
3 |
-
|
4 |
-
The highly customizable lightbox for WordPress
|
5 |
-
|
6 |
-
http://archetyped.com/tools/simple-lightbox/
|
7 |
-
|
8 |
-
## Support
|
9 |
-
Found a bug or otherwise experiencing an issue with Simple Lightbox? [Report the issue here][issue-report]
|
10 |
-
|
11 |
-
[issue-report]: https://github.com/archetyped/simple-lightbox/wiki/Reporting-Issues "Report an issue"
|
1 |
+
Simple Lightbox
|
2 |
+
===============
|
3 |
+
|
4 |
+
The highly customizable lightbox for WordPress
|
5 |
+
|
6 |
+
http://archetyped.com/tools/simple-lightbox/
|
7 |
+
|
8 |
+
## Support
|
9 |
+
Found a bug or otherwise experiencing an issue with Simple Lightbox? [Report the issue here][issue-report]
|
10 |
+
|
11 |
+
[issue-report]: https://github.com/archetyped/simple-lightbox/wiki/Reporting-Issues "Report an issue"
|
changelog.txt
CHANGED
@@ -1,344 +1,357 @@
|
|
1 |
-
= 2.
|
2 |
-
|
3 |
-
*
|
4 |
-
* Add:
|
5 |
-
* Add:
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
*
|
10 |
-
* Update:
|
11 |
-
*
|
12 |
-
*
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
*
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
* Update:
|
24 |
-
* Optimize:
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
*
|
29 |
-
*
|
30 |
-
*
|
31 |
-
*
|
32 |
-
*
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
* Fix:
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
*
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
*
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
*
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
*
|
68 |
-
* Optimize:
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
*
|
75 |
-
* Optimize:
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
*
|
80 |
-
*
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
*
|
91 |
-
*
|
92 |
-
* Add:
|
93 |
-
* Add:
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
*
|
98 |
-
*
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
*
|
104 |
-
*
|
105 |
-
* Add:
|
106 |
-
*
|
107 |
-
*
|
108 |
-
*
|
109 |
-
*
|
110 |
-
*
|
111 |
-
*
|
112 |
-
*
|
113 |
-
*
|
114 |
-
*
|
115 |
-
*
|
116 |
-
*
|
117 |
-
*
|
118 |
-
*
|
119 |
-
* Optimize:
|
120 |
-
* Optimize:
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
* Optimize:
|
125 |
-
* Optimize:
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
*
|
130 |
-
*
|
131 |
-
* Optimize:
|
132 |
-
* Optimize:
|
133 |
-
* Optimize:
|
134 |
-
|
135 |
-
= 2.2.
|
136 |
-
|
137 |
-
*
|
138 |
-
*
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
*
|
143 |
-
*
|
144 |
-
* Optimize: Client-side
|
145 |
-
* Optimize:
|
146 |
-
* Optimize:
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
*
|
154 |
-
*
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
*
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
*
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
*
|
167 |
-
* Optimize:
|
168 |
-
|
169 |
-
= 2.1 =
|
170 |
-
|
171 |
-
*
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
*
|
176 |
-
*
|
177 |
-
* Optimize:
|
178 |
-
* Optimize:
|
179 |
-
* Optimize:
|
180 |
-
* Optimize:
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
*
|
187 |
-
*
|
188 |
-
* Add:
|
189 |
-
* Add:
|
190 |
-
*
|
191 |
-
*
|
192 |
-
* Optimize:
|
193 |
-
* Optimize:
|
194 |
-
*
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
*
|
200 |
-
* Add:
|
201 |
-
* Add:
|
202 |
-
* Add:
|
203 |
-
*
|
204 |
-
*
|
205 |
-
* Optimize:
|
206 |
-
* Optimize:
|
207 |
-
* Optimize:
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
*
|
212 |
-
*
|
213 |
-
*
|
214 |
-
*
|
215 |
-
*
|
216 |
-
*
|
217 |
-
*
|
218 |
-
*
|
219 |
-
*
|
220 |
-
*
|
221 |
-
*
|
222 |
-
*
|
223 |
-
*
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
*
|
228 |
-
*
|
229 |
-
*
|
230 |
-
*
|
231 |
-
*
|
232 |
-
*
|
233 |
-
*
|
234 |
-
*
|
235 |
-
*
|
236 |
-
*
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
*
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
*
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
*
|
249 |
-
*
|
250 |
-
*
|
251 |
-
*
|
252 |
-
*
|
253 |
-
*
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
*
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
*
|
262 |
-
*
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
* Add:
|
267 |
-
*
|
268 |
-
*
|
269 |
-
*
|
270 |
-
*
|
271 |
-
*
|
272 |
-
*
|
273 |
-
*
|
274 |
-
* Fix:
|
275 |
-
*
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
*
|
282 |
-
*
|
283 |
-
*
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
* Fix:
|
288 |
-
*
|
289 |
-
*
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
* Fix:
|
295 |
-
* Fix:
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
*
|
301 |
-
*
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
*
|
307 |
-
*
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
*
|
320 |
-
* Add:
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
*
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
*
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
* Initial release
|
1 |
+
= 2.9.0 =
|
2 |
+
|
3 |
+
* Add: Support WebP image format
|
4 |
+
* Add: Support AVIF image format
|
5 |
+
* Add: Documentation link to readme file
|
6 |
+
* Optimize: Code cleanup/refactoring
|
7 |
+
* Optimize: WPCS validation (Phase 1)
|
8 |
+
* Optimize: Activate links after all other filters
|
9 |
+
* Optimize: Plugin metadata retrieval
|
10 |
+
* Update: Confirm WordPress 6.0 compatibility
|
11 |
+
* Update: Build dependencies
|
12 |
+
* Update: GitHub issue templates
|
13 |
+
|
14 |
+
= 2.8.1 =
|
15 |
+
|
16 |
+
* Update: PHP 5.6 Compatibility
|
17 |
+
* Add: PHPCS configuration
|
18 |
+
* Add: GitHub Issue templates
|
19 |
+
|
20 |
+
= 2.8.0 =
|
21 |
+
|
22 |
+
* Update: WordPress 5.3+ required.
|
23 |
+
* Update: PHP 7.2+ required.
|
24 |
+
* Optimize: Link detection up to 2x faster.
|
25 |
+
* Optimize: Options data handling.
|
26 |
+
* Optimize: Default title filtering.
|
27 |
+
* Optimize: Standardize media item data structure to avoid conflicts with third-party data.
|
28 |
+
* Optimize: Load only necessary media item properties in browser.
|
29 |
+
* Optimize: Filter all media items (instead of each individual item).
|
30 |
+
* Filter Removed: `media_item_properties` (single item).
|
31 |
+
* Filter Added: `media_items` (all items).
|
32 |
+
* Fix: `area` elements included in link detection (This is Jim's Area).
|
33 |
+
|
34 |
+
= 2.7.1 =
|
35 |
+
|
36 |
+
* Update: Confirm compatibility with WordPress 5.0+
|
37 |
+
* Optimize: Improved support for captions generated by Block Editor.
|
38 |
+
|
39 |
+
= 2.7.0 =
|
40 |
+
|
41 |
+
* Fix: Remove reference to deprecated `screen_icon()` function (The Icon of Finnegan Island)
|
42 |
+
* Add: Validate requirements before initialization.
|
43 |
+
* Optimize: PHP 7.2+ Compatibility
|
44 |
+
* Optimize: Internal code optimizations
|
45 |
+
* Themes
|
46 |
+
* Add: RTL Support
|
47 |
+
* Update: Load font locally
|
48 |
+
|
49 |
+
= 2.6.0 =
|
50 |
+
|
51 |
+
* Add: Activate links in native WordPress navigation menus (enable in admin settings)
|
52 |
+
* Add: Group menu links separately (enable in admin settings)
|
53 |
+
* Optimize: Fallback lightbox title text retrieval (link text)
|
54 |
+
* Fix: Undefined variable in `Utilities::get_plugin_base_file()` (The Lost Temple of Xavivars)
|
55 |
+
|
56 |
+
= 2.5.3 =
|
57 |
+
|
58 |
+
* Optimize: Entity handling in URIs for different server environments
|
59 |
+
|
60 |
+
= 2.5.2 =
|
61 |
+
|
62 |
+
* Fix: Activation when Home page set to static page (Lyra's Static Cling)
|
63 |
+
* Optimize: Prep for WordPress language packs
|
64 |
+
|
65 |
+
= 2.5.1 =
|
66 |
+
|
67 |
+
* Update: Client-side Utilities library
|
68 |
+
* Optimize: Request processing
|
69 |
+
|
70 |
+
= 2.5.0 =
|
71 |
+
|
72 |
+
* Fix: Query string removed from URI (A Stern Query)
|
73 |
+
* Optimize: Key-based asset data storage/retrieval
|
74 |
+
* Optimize: Improved cache usage when processing links
|
75 |
+
* Optimize: Refactor image URI detection
|
76 |
+
|
77 |
+
= 2.4.1 =
|
78 |
+
|
79 |
+
* Fix: Ungrouped items in empty group (Robert & The Lost Group)
|
80 |
+
* Fix: IE8 Support (S.Franzis' Legacy)
|
81 |
+
* Optimize: Widget support
|
82 |
+
* Optimize: Relative and internal URI handling
|
83 |
+
* Optimize: Link activation performance
|
84 |
+
|
85 |
+
= 2.4.0 =
|
86 |
+
|
87 |
+
* Update: WordPress version compatibility (v4.2.1)
|
88 |
+
* Optimize: Standardize code
|
89 |
+
* Optimize: Do not process excerpt content
|
90 |
+
* Optimize: Client-side libraries (Phase 1)
|
91 |
+
* Add: Set group via `slb_activate()`
|
92 |
+
* Add: Set group via `activate_links()`
|
93 |
+
* Add: `slb_is_enabled` filter
|
94 |
+
|
95 |
+
= 2.3.1 =
|
96 |
+
|
97 |
+
* Fix: WordPress version requirement
|
98 |
+
* Optimize: Field collection group parsing
|
99 |
+
|
100 |
+
= 2.3.0 =
|
101 |
+
[Full Release Notes](http://archetyped.com/lab/slb-2-3-0 "Simple Lightbox 2.3.0")
|
102 |
+
|
103 |
+
* Update: WordPress 3.9 support
|
104 |
+
* Update: Support URI, content
|
105 |
+
* Add: Enhanced grouping support
|
106 |
+
* Add: Shortcode: `[slb_group]`
|
107 |
+
* Add: Shortcode: `[slb_exclude]`
|
108 |
+
* Add: Filter: `slb_pre_process_links`
|
109 |
+
* Add: Filter: `slb_post_process_links`
|
110 |
+
* Add: Filter: `slb_process_link_attributes`
|
111 |
+
* Add: Filter: `slb_media_item_properties`
|
112 |
+
* Add: Filter: `slb_pre_exclude_content`
|
113 |
+
* Add: Filter: `slb_exclude_shortcodes`
|
114 |
+
* Add: Filter: `slb_group_shortcodes`
|
115 |
+
* Add: Template Tag: `slb_activate()` - Manually activate content
|
116 |
+
* Add: Option to enable/disable usage of WordPress-generated media title
|
117 |
+
* Add: Dev mode
|
118 |
+
* Add: Theme breakpoints
|
119 |
+
* Optimize: Remove deprecated code
|
120 |
+
* Optimize: Remove deprecated legacy support
|
121 |
+
* Optimize: Content exclusion performance
|
122 |
+
* Optimize: Content grouping performance
|
123 |
+
* Optimize: Harden code against third-party post query modifications
|
124 |
+
* Optimize: Utility code
|
125 |
+
* Optimize: Loading process
|
126 |
+
* Optimize: Client-side code
|
127 |
+
* Optimize: Client-side: Code loading
|
128 |
+
* Optimize: Client-side: Simplified dependency detection
|
129 |
+
* Optimize: Client-side: Default Theme transitions
|
130 |
+
* Optimize: Grunt: Cleanup
|
131 |
+
* Optimize: Grunt: Path abstraction
|
132 |
+
* Optimize: Grunt: Task loading
|
133 |
+
* Optimize: Grunt: Selective file compilation
|
134 |
+
|
135 |
+
= 2.2.2 =
|
136 |
+
|
137 |
+
* Optimize: Widget processing
|
138 |
+
* Optimize: Remove call-time-pass-by-references
|
139 |
+
|
140 |
+
= 2.2.1 =
|
141 |
+
|
142 |
+
* Fix: Enable/Disable lightbox on certain requests (Danny the Enabler)
|
143 |
+
* Fix: Widget links grouped with post links (Rafa's Widgetarian Adventure)
|
144 |
+
* Optimize: Client-side loading
|
145 |
+
* Optimize: Theme validation
|
146 |
+
* Optimize: Widget processing
|
147 |
+
|
148 |
+
= 2.2.0 =
|
149 |
+
|
150 |
+
* Update: WordPress 3.8 support
|
151 |
+
* Add: Add-on support
|
152 |
+
* Add: Load external data for item
|
153 |
+
* Add: Unloading process for viewer
|
154 |
+
* Add: Relative links marked as "internal"
|
155 |
+
* Add: Grunt build workflow
|
156 |
+
* Optimize: Initialization process
|
157 |
+
* Optimize: Client-side output (JavaScript, CSS)
|
158 |
+
* Optimize: Improved URI handling (variants, query strings, etc.)
|
159 |
+
* Optimize: Improved support for content types (video, etc.)
|
160 |
+
* Optimize: Improved File contents retrieval
|
161 |
+
* Optimize: Plugin metadata cleanup
|
162 |
+
* Optimize: Use absolute paths for file includes (props k3davis)
|
163 |
+
|
164 |
+
= 2.1.3 =
|
165 |
+
|
166 |
+
* Fix: PHP configuration issue on some web hosts (Tim's got (config) issues)
|
167 |
+
* Optimize: Hide overlapping elements when lightbox is displayed (e.g. Flash, etc.)
|
168 |
+
|
169 |
+
= 2.1.2 =
|
170 |
+
|
171 |
+
* Fix: Incorrect paths when WP in subdirectory (Kim's Van Repair)
|
172 |
+
|
173 |
+
= 2.1.1 =
|
174 |
+
|
175 |
+
* Fix: Automatic resizing
|
176 |
+
* Fix: Compatibility with non-standard wp-content location (On the Path of the Wijdemans)
|
177 |
+
* Optimize: jQuery dependency handling
|
178 |
+
* Optimize: Plugin initialization
|
179 |
+
* Optimize: Deferred component stylesheet loading
|
180 |
+
* Optimize: Code cleanup
|
181 |
+
|
182 |
+
= 2.1 =
|
183 |
+
|
184 |
+
* Update: Finalized Theme API
|
185 |
+
* Update: Finalized Content Handler API
|
186 |
+
* Update: Finalized Template Tag API
|
187 |
+
* Update: Administration framework
|
188 |
+
* Add: Baseline theme
|
189 |
+
* Add: Hook for extending image link matching
|
190 |
+
* Optimize: Link validation
|
191 |
+
* Optimize: Intelligent client-side loading
|
192 |
+
* Optimize: Server-side processing
|
193 |
+
* Optimize: Default theme display
|
194 |
+
* Fix: False positive link activation (What's eating Gilbert's links?)
|
195 |
+
* Fix: Gallery post format compatibility (Just Juan problem with galleries)
|
196 |
+
|
197 |
+
= 2.0 =
|
198 |
+
|
199 |
+
* Completely rewritten lightbox code
|
200 |
+
* Add: Automatically resize lightbox to fit window
|
201 |
+
* Add: APIs for third-party add-ons
|
202 |
+
* Add: Flexible theme support
|
203 |
+
* Add: Flexible content handler support
|
204 |
+
* Add: Mobile-optimized responsive themes (2)
|
205 |
+
* Optimize: PHP class autoloading
|
206 |
+
* Optimize: Improved performance and compatibility
|
207 |
+
* Optimize: Full internationalization support
|
208 |
+
|
209 |
+
= 1.6 =
|
210 |
+
|
211 |
+
* Add: Widget support
|
212 |
+
* Add: WordPress 3.3 support
|
213 |
+
* Add: Localization support
|
214 |
+
* Add: Option to group gallery links separately (supports WordPress & NextGen galleries)
|
215 |
+
* Add: Upgrade notice
|
216 |
+
* Optimize: WP 3.3 compatibility
|
217 |
+
* Optimize: Improved compatibility with URI case-sensitivity
|
218 |
+
* Optimize: Activation processing
|
219 |
+
* Optimize: Image grouping
|
220 |
+
* Optimize: Image metadata loading performance
|
221 |
+
* Optimize: File loading
|
222 |
+
* Optimize: Improved safeguards against interference by bugs in other plugins
|
223 |
+
* Optimize: Link processing performance
|
224 |
+
* Optimize: Lightbox styling isolated from site styles
|
225 |
+
* Optimize: Improved link processing performance
|
226 |
+
* Optimize: Improved image metadata support
|
227 |
+
* Optimize: Improved support for HTTP/HTTPS requests
|
228 |
+
* Fix: SLB is not defined in JS (Jezz Hands)
|
229 |
+
* Fix: Boolean case-sensitivity (78 Truths)
|
230 |
+
* Fix: YouTube embed using iFrame overlaps lightbox (Elena in Hiding)
|
231 |
+
* Fix: Issue when scanning links without valid URLs (McCloskey Iteration)
|
232 |
+
* Fix: Image activation is case-sensitive (Sensitive Tanya)
|
233 |
+
* Fix: Visible lightbox overlay edges when image larger than browser window (Chibi Overlay)
|
234 |
+
* Fix: Options availability for some users
|
235 |
+
* Fix: Inconsistent loading of image metadata
|
236 |
+
* Fix: Links not fully processed when group is set manually
|
237 |
+
|
238 |
+
= 1.5.6 =
|
239 |
+
|
240 |
+
* Add: Display image description in lightbox (with HTML support)
|
241 |
+
* Add: Support for W3 Total Cache plugin
|
242 |
+
* Add: Initial support for NextGEN galleries
|
243 |
+
* Update: **Important:** [System Requirements](http://wordpress.org/about/requirements/) aligned with WP 3.2.1
|
244 |
+
* Optimize: Improved support for small images in default template
|
245 |
+
* Optimize: Support for non-English text in user options
|
246 |
+
* Optimize: Improved IE compatibility
|
247 |
+
* Optimize: Improved data handling
|
248 |
+
* Optimize: Skin loading performance
|
249 |
+
* Optimize: Skin CSS Cleanup
|
250 |
+
* Optimize: Caption support for galleries
|
251 |
+
* Optimize: Options code cleanup (Juga Sweep)
|
252 |
+
* Fix: User-defined UI text not used (Ivan gets Even (cooler))
|
253 |
+
* Fix: Options reset after update (KRazy Donna)
|
254 |
+
|
255 |
+
= 1.5.5.1 =
|
256 |
+
|
257 |
+
* Fix: Disabled links not being disabled (Disabling Sascha)
|
258 |
+
|
259 |
+
= 1.5.5 =
|
260 |
+
|
261 |
+
* Add: Distinct link activation (will not affect other lightboxes)
|
262 |
+
* Add: Backwards compatibility with legacy lightbox links (optional)
|
263 |
+
* Add: Support for WordPress 3.2
|
264 |
+
* Add: Support for links added after page load (e.g. via AJAX, etc.)
|
265 |
+
* Add: Admin option to enable/disable attachment links
|
266 |
+
* Add: Support for image attachment links
|
267 |
+
* Update: Options management overhaul
|
268 |
+
* Update: Additional WordPress 3.2 support (Gallery)
|
269 |
+
* Update: Cache-management for enqueued files
|
270 |
+
* Update: Improved UI consistency
|
271 |
+
* Update: Improved compatibility for older versions of PHP
|
272 |
+
* Update: Internal optimizations
|
273 |
+
* Update: Improved URL handling
|
274 |
+
* Fix: Improved options migration from old versions (Hutchison Migration)
|
275 |
+
* Fix: XHTML Validation (Hajo Validation)
|
276 |
+
|
277 |
+
= 1.5.4 =
|
278 |
+
|
279 |
+
* Add: Optional Link validation
|
280 |
+
* Add: Keyboard Navigation
|
281 |
+
* Add: Option to enable/disable image caption
|
282 |
+
* Add: `rel` attribute supported again
|
283 |
+
* Add: Use `slb_off` in link's `rel` attribute to disable automatic activation for link
|
284 |
+
* Fix: HTTPS compatibility (Jürgen Protocol)
|
285 |
+
* Fix: Enabling SLB on Pages issue
|
286 |
+
* Fix: Zmanu is_single
|
287 |
+
* Fix: Image order is sometimes incorrect
|
288 |
+
* Optimize: Filter double clicks
|
289 |
+
* Optimize: Separate options to enable/disable SLB on Posts and Pages
|
290 |
+
* Optimize: Better grouping support
|
291 |
+
|
292 |
+
= 1.5.3 =
|
293 |
+
|
294 |
+
* Fix: Caption may not display under certain circumstances (Caption Erin)
|
295 |
+
* Fix: Images not grouped when "separate by post" option is activated (Logical Ross)
|
296 |
+
* Update: Lightbox will not be activated for links that already have `rel` attribute set
|
297 |
+
|
298 |
+
= 1.5.2 =
|
299 |
+
|
300 |
+
* Fix: Slideshow loops out of control (Mirage of Wallentin)
|
301 |
+
* Fix: Lightbox fails when group by posts disabled (Lange Find)
|
302 |
+
* Add: Option to use the image's URI as caption when link title not set (Under UI options)
|
303 |
+
|
304 |
+
= 1.5.1 =
|
305 |
+
|
306 |
+
* Add: WP Gallery support
|
307 |
+
* Fix: Navigation hidden when only one image
|
308 |
+
* Fix: Use user-defined UI text
|
309 |
+
|
310 |
+
= 1.5 =
|
311 |
+
|
312 |
+
* Add: Theme support
|
313 |
+
* Optimize: JavaScript cleanup and file size reductions
|
314 |
+
* Optimize: CSS cleanup
|
315 |
+
|
316 |
+
= 1.4 =
|
317 |
+
|
318 |
+
* Update: Integrated with jQuery
|
319 |
+
* Optimize: JavaScript file size 9x smaller
|
320 |
+
* Add: Close lightbox by clicking to left/right outside of image (an oft-requested feature)
|
321 |
+
|
322 |
+
= 1.3.2 =
|
323 |
+
|
324 |
+
* Add: Option to enable/disable lightbox resizing animation (thanks Maria!)
|
325 |
+
|
326 |
+
= 1.3.1 =
|
327 |
+
|
328 |
+
* Update: Utilities code (internal)
|
329 |
+
|
330 |
+
= 1.3 =
|
331 |
+
|
332 |
+
* Add: Customizable UI label text (close, next, and previous button images can be replaced in `images` directory)
|
333 |
+
* Add: Group image links by Post (separate slideshow for each post)
|
334 |
+
* Add: Reset settings link on plugin listings page
|
335 |
+
* Optimize: Organized settings page
|
336 |
+
|
337 |
+
= 1.2.1 =
|
338 |
+
|
339 |
+
* Fixed: Image title given higher precedence than Image alt (more compatible w/WP workflow)
|
340 |
+
|
341 |
+
= 1.2 =
|
342 |
+
|
343 |
+
* Added: Option to group automatically activated links
|
344 |
+
* Optimized: Lightbox caption retrieval
|
345 |
+
|
346 |
+
= 1.1 =
|
347 |
+
|
348 |
+
* Added: Enable/disable lightbox functionality by page type (Home, Pages/Posts, Archive, etc.)
|
349 |
+
* Added: Automatically activate lightbox functionality for image links
|
350 |
+
* Added: Link to settings menu on plugin listing page
|
351 |
+
* Optimized: Options menu field building
|
352 |
+
* Optimized: Loading of default values for plugin options
|
353 |
+
* Optimized: General code optimizations
|
354 |
+
|
355 |
+
= 1.0 =
|
356 |
+
|
357 |
* Initial release
|
client/css/admin.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
.slb_section_head{display:block;padding:2em 0 0}.slb_option_item .block{display:inline-block}.slb_option_item label.title{width:200px;padding:10px}.slb_option_item .input{font-size:11px;line-height:20px;margin-bottom:9px;padding:8px 10px}.slb_option_item .input select{min-width:12em}.slb_notice{color:#f00;font-weight:bold}.slb .columns-2{margin-right:300px}.slb .columns-2 .postbox-container{float:left;width:100%}.slb .columns-2 .content-secondary{margin-right:-300px;width:280px;float:right}.slb_admin_action_reset{color:#a00}.slb_admin_action_reset:hover{color:#dc3232;border:none}
|
1 |
+
.slb_section_head{display:block;padding:2em 0 0}.slb_option_item .block{display:inline-block}.slb_option_item label.title{width:200px;padding:10px}.slb_option_item .input{font-size:11px;line-height:20px;margin-bottom:9px;padding:8px 10px}.slb_option_item .input select{min-width:12em}.slb_notice{color:#f00;font-weight:bold}.slb .columns-2{margin-right:300px}.slb .columns-2 .postbox-container{float:left;width:100%}.slb .columns-2 .content-secondary{margin-right:-300px;width:280px;float:right}.slb_admin_action_reset{color:#a00}.slb_admin_action_reset:hover{color:#dc3232;border:none}
|
client/css/app.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
html.slb_overlay object,html.slb_overlay embed,html.slb_overlay iframe{visibility:hidden}html.slb_overlay #slb_viewer_wrap object,html.slb_overlay #slb_viewer_wrap embed,html.slb_overlay #slb_viewer_wrap iframe{visibility:visible}
|
1 |
+
html.slb_overlay object,html.slb_overlay embed,html.slb_overlay iframe{visibility:hidden}html.slb_overlay #slb_viewer_wrap object,html.slb_overlay #slb_viewer_wrap embed,html.slb_overlay #slb_viewer_wrap iframe{visibility:visible}
|
client/js/dev/lib.admin.js
CHANGED
@@ -1,27 +1,27 @@
|
|
1 |
-
/**
|
2 |
-
* Admin
|
3 |
-
* @package Simple Lightbox
|
4 |
-
* @subpackage Admin
|
5 |
-
* @author Archetyped
|
6 |
-
*/
|
7 |
-
|
8 |
-
/* global SLB, postboxes, pagenow */
|
9 |
-
|
10 |
-
if ( !!window.SLB && !!SLB.attach ) { (function ($) {
|
11 |
-
|
12 |
-
SLB.attach('Admin', {
|
13 |
-
/**
|
14 |
-
* Initialization routines
|
15 |
-
*/
|
16 |
-
init: function() {
|
17 |
-
if ( postboxes ) {
|
18 |
-
postboxes.add_postbox_toggles(pagenow);
|
19 |
-
}
|
20 |
-
},
|
21 |
-
});
|
22 |
-
|
23 |
-
$(document).ready(function() {
|
24 |
-
SLB.Admin.init();
|
25 |
-
});
|
26 |
-
|
27 |
})(jQuery);}
|
1 |
+
/**
|
2 |
+
* Admin
|
3 |
+
* @package Simple Lightbox
|
4 |
+
* @subpackage Admin
|
5 |
+
* @author Archetyped
|
6 |
+
*/
|
7 |
+
|
8 |
+
/* global SLB, postboxes, pagenow */
|
9 |
+
|
10 |
+
if ( !!window.SLB && !!SLB.attach ) { (function ($) {
|
11 |
+
|
12 |
+
SLB.attach('Admin', {
|
13 |
+
/**
|
14 |
+
* Initialization routines
|
15 |
+
*/
|
16 |
+
init: function() {
|
17 |
+
if ( postboxes ) {
|
18 |
+
postboxes.add_postbox_toggles(pagenow);
|
19 |
+
}
|
20 |
+
},
|
21 |
+
});
|
22 |
+
|
23 |
+
$(document).ready(function() {
|
24 |
+
SLB.Admin.init();
|
25 |
+
});
|
26 |
+
|
27 |
})(jQuery);}
|
client/js/dev/lib.core.js
CHANGED
@@ -1,934 +1,934 @@
|
|
1 |
-
/**
|
2 |
-
* Core
|
3 |
-
* @package SLB
|
4 |
-
* @author Archetyped
|
5 |
-
*/
|
6 |
-
if ( window.jQuery ){(function($) {
|
7 |
-
'use strict';
|
8 |
-
|
9 |
-
/**
|
10 |
-
* Extendible class
|
11 |
-
* Adapted from John Resig
|
12 |
-
* @link http://ejohn.org/blog/simple-javascript-inheritance/
|
13 |
-
*/
|
14 |
-
var c_init = false;
|
15 |
-
var Class = function() {};
|
16 |
-
|
17 |
-
/**
|
18 |
-
* Create class that extends another class
|
19 |
-
* @param object members Child class' properties
|
20 |
-
* @return function New class
|
21 |
-
*/
|
22 |
-
Class.extend = function(members) {
|
23 |
-
var _super = this.prototype;
|
24 |
-
|
25 |
-
// Copy instance to prototype
|
26 |
-
c_init = true;
|
27 |
-
var proto = new this();
|
28 |
-
c_init = false;
|
29 |
-
|
30 |
-
var val, name;
|
31 |
-
// Scrub prototype objects (Decouple from super class)
|
32 |
-
for ( name in proto ) {
|
33 |
-
if ( $.isPlainObject(proto[name]) ) {
|
34 |
-
val = $.extend({}, proto[name]);
|
35 |
-
proto[name] = val;
|
36 |
-
}
|
37 |
-
}
|
38 |
-
|
39 |
-
/**
|
40 |
-
* Create class method with access to super class method
|
41 |
-
* @param string nm Method name
|
42 |
-
* @param function fn Class method
|
43 |
-
* @return function Class method with access to super class method
|
44 |
-
*/
|
45 |
-
var make_handler = function(nm, fn) {
|
46 |
-
return function() {
|
47 |
-
// Cache super variable
|
48 |
-
var tmp = this._super;
|
49 |
-
// Set variable to super class method
|
50 |
-
this._super = _super[nm];
|
51 |
-
// Call method
|
52 |
-
var ret = fn.apply(this, arguments);
|
53 |
-
// Restore super variable
|
54 |
-
this._super = tmp;
|
55 |
-
// Return value
|
56 |
-
return ret;
|
57 |
-
};
|
58 |
-
};
|
59 |
-
// Copy properties to Class
|
60 |
-
for ( name in members ) {
|
61 |
-
// Add access to super class method to methods
|
62 |
-
if ( 'function' === typeof members[name] && 'function' === typeof _super[name] ) {
|
63 |
-
proto[name] = make_handler(name, members[name]);
|
64 |
-
} else {
|
65 |
-
// Transfer properties
|
66 |
-
// Objects are copied, not referenced
|
67 |
-
proto[name] = ( $.isPlainObject(members[name]) ) ? $.extend({}, members[name]) : members[name];
|
68 |
-
}
|
69 |
-
}
|
70 |
-
|
71 |
-
/**
|
72 |
-
* Class constructor
|
73 |
-
* Supports pre-construction initilization (`Class._init()`)
|
74 |
-
* Supports passing constructor for new classes (`Class._c()`)
|
75 |
-
*/
|
76 |
-
function Class() {
|
77 |
-
if ( !c_init ) {
|
78 |
-
// Private initialization
|
79 |
-
if ( 'function' === typeof this._init ) {
|
80 |
-
this._init.apply(this, arguments);
|
81 |
-
}
|
82 |
-
// Main Constructor
|
83 |
-
if ( 'function' === typeof this._c ) {
|
84 |
-
this._c.apply(this, arguments);
|
85 |
-
}
|
86 |
-
}
|
87 |
-
}
|
88 |
-
|
89 |
-
|
90 |
-
// Populate new prototype
|
91 |
-
Class.prototype = proto;
|
92 |
-
|
93 |
-
// Set constructor
|
94 |
-
Class.prototype.constructor = Class;
|
95 |
-
|
96 |
-
// Set extender
|
97 |
-
Class.extend = this.extend;
|
98 |
-
|
99 |
-
// Return function
|
100 |
-
return Class;
|
101 |
-
};
|
102 |
-
|
103 |
-
/**
|
104 |
-
* Base Class
|
105 |
-
*/
|
106 |
-
var Base = {
|
107 |
-
/* Properties */
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Base object flag
|
111 |
-
* @var bool
|
112 |
-
*/
|
113 |
-
base: false,
|
114 |
-
/**
|
115 |
-
* Instance parent
|
116 |
-
* @var object
|
117 |
-
*/
|
118 |
-
_parent: null,
|
119 |
-
/**
|
120 |
-
* Class prefix
|
121 |
-
* @var string
|
122 |
-
*/
|
123 |
-
prefix: 'slb',
|
124 |
-
|
125 |
-
/* Methods */
|
126 |
-
|
127 |
-
/**
|
128 |
-
* Constructor
|
129 |
-
* Sets instance parent
|
130 |
-
*/
|
131 |
-
_init: function() {
|
132 |
-
this._set_parent();
|
133 |
-
},
|
134 |
-
|
135 |
-
/**
|
136 |
-
* Set instance parent
|
137 |
-
* Set utilities parent to current instance
|
138 |
-
* @param obj p Parent instance
|
139 |
-
*/
|
140 |
-
_set_parent: function(p) {
|
141 |
-
if ( this.util.is_set(p) ) {
|
142 |
-
this._parent = p;
|
143 |
-
}
|
144 |
-
this.util._parent = this;
|
145 |
-
},
|
146 |
-
|
147 |
-
/**
|
148 |
-
* Attach new member to instance
|
149 |
-
* Member can be property (value) or method
|
150 |
-
* @param string name Member name
|
151 |
-
* @param object data Member data
|
152 |
-
* @param bool simple (optional) Save new member as data object or new class instance (Default: new instance)
|
153 |
-
* @return obj Attached object
|
154 |
-
*/
|
155 |
-
attach: function(member, data, simple) {
|
156 |
-
var ret = data;
|
157 |
-
// Validate
|
158 |
-
simple = ( typeof simple === 'undefined' ) ? false : !!simple;
|
159 |
-
// Add member to instance
|
160 |
-
if ( 'string' === $.type(member) ) {
|
161 |
-
// Prepare member value
|
162 |
-
if ( $.isPlainObject(data) && !simple ) {
|
163 |
-
// Set parent reference for attached instance
|
164 |
-
data['_parent'] = this;
|
165 |
-
// Define new class
|
166 |
-
data = this.Class.extend(data);
|
167 |
-
}
|
168 |
-
// Save member to current instance
|
169 |
-
// Initialize new instance if data is a class
|
170 |
-
this[member] = ( 'function' === $.type(data) ) ? new data() : data;
|
171 |
-
ret = this[member];
|
172 |
-
}
|
173 |
-
return ret;
|
174 |
-
},
|
175 |
-
|
176 |
-
/**
|
177 |
-
* Check for child object
|
178 |
-
* Child object can be multi-level (e.g. Child.Level2child.Level3child)
|
179 |
-
*
|
180 |
-
* @param string child Name of child object
|
181 |
-
*/
|
182 |
-
has_child: function(child) {
|
183 |
-
// Validate
|
184 |
-
if ( !this.util.is_string(child) ) {
|
185 |
-
return false;
|
186 |
-
}
|
187 |
-
|
188 |
-
var children = child.split('.');
|
189 |
-
child = null;
|
190 |
-
var o = this;
|
191 |
-
var x;
|
192 |
-
for ( x = 0; x < children.length; x++ ) {
|
193 |
-
child = children[x];
|
194 |
-
if ( "" === child ) {
|
195 |
-
continue;
|
196 |
-
}
|
197 |
-
if ( this.util.is_obj(o) && o[child] ) {
|
198 |
-
o = o[child];
|
199 |
-
} else {
|
200 |
-
return false;
|
201 |
-
}
|
202 |
-
}
|
203 |
-
return true;
|
204 |
-
},
|
205 |
-
|
206 |
-
/**
|
207 |
-
* Check if instance is set as a base
|
208 |
-
* @uses base
|
209 |
-
* @return bool TRUE if object is set as a base
|
210 |
-
*/
|
211 |
-
is_base: function() {
|
212 |
-
return !!this.base;
|
213 |
-
},
|
214 |
-
|
215 |
-
/**
|
216 |
-
* Get parent instance
|
217 |
-
* @uses `Base._parent` property
|
218 |
-
* @return obj Parent instance
|
219 |
-
*/
|
220 |
-
get_parent: function() {
|
221 |
-
var p = this._parent;
|
222 |
-
// Validate
|
223 |
-
if ( !p ) {
|
224 |
-
this._parent = {};
|
225 |
-
}
|
226 |
-
return this._parent;
|
227 |
-
}
|
228 |
-
};
|
229 |
-
|
230 |
-
/**
|
231 |
-
* Utility methods
|
232 |
-
*/
|
233 |
-
var Utilities = {
|
234 |
-
/* Properties */
|
235 |
-
|
236 |
-
_base: null,
|
237 |
-
_parent: null,
|
238 |
-
|
239 |
-
/* Methods */
|
240 |
-
|
241 |
-
/* Connections */
|
242 |
-
|
243 |
-
/**
|
244 |
-
* Get base ancestor
|
245 |
-
* @return obj Base ancestor
|
246 |
-
*/
|
247 |
-
get_base: function() {
|
248 |
-
if ( !this._base ) {
|
249 |
-
var p = this.get_parent();
|
250 |
-
var p_prev = null;
|
251 |
-
var methods = ['is_base', 'get_parent'];
|
252 |
-
// Find base ancestor
|
253 |
-
// Either oldest ancestor or object explicitly set as a base
|
254 |
-
while ( ( p_prev !== p ) && this.is_method(p, methods) && !p.is_base() ) {
|
255 |
-
// Save previous parent
|
256 |
-
p_prev = p;
|
257 |
-
// Get new parent
|
258 |
-
p = p.get_parent();
|
259 |
-
}
|
260 |
-
// Set base
|
261 |
-
this._base = p;
|
262 |
-
}
|
263 |
-
return this._base;
|
264 |
-
},
|
265 |
-
|
266 |
-
/**
|
267 |
-
* Get parent object or parent property value
|
268 |
-
* @param string prop (optional) Property to retrieve
|
269 |
-
* @return obj Parent object or property value
|
270 |
-
*/
|
271 |
-
get_parent: function(prop) {
|
272 |
-
var ret = this._parent;
|
273 |
-
// Validate
|
274 |
-
if ( !ret ) {
|
275 |
-
// Set default parent value
|
276 |
-
ret = this._parent = {};
|
277 |
-
}
|
278 |
-
// Get parent property
|
279 |
-
if ( this.is_string(prop) ) {
|
280 |
-
ret = ( this.in_obj(ret, prop) ) ? ret[prop] : null;
|
281 |
-
}
|
282 |
-
return ret;
|
283 |
-
},
|
284 |
-
|
285 |
-
/* Prefix */
|
286 |
-
|
287 |
-
/**
|
288 |
-
* Retrieve valid separator
|
289 |
-
* If supplied argument is not a valid separator, use default separator
|
290 |
-
* @param string (optional) sep Separator text
|
291 |
-
* @return string Separator text
|
292 |
-
*/
|
293 |
-
get_sep: function(sep) {
|
294 |
-
var sep_default = '_';
|
295 |
-
return ( this.is_string(sep, false) ) ? sep : sep_default;
|
296 |
-
},
|
297 |
-
|
298 |
-
/**
|
299 |
-
* Retrieve prefix
|
300 |
-
* @return string Prefix
|
301 |
-
*/
|
302 |
-
get_prefix: function() {
|
303 |
-
var p = this.get_parent('prefix');
|
304 |
-
return ( this.is_string(p, false) ) ? p : '';
|
305 |
-
},
|
306 |
-
|
307 |
-
/**
|
308 |
-
* Check if string is prefixed
|
309 |
-
*/
|
310 |
-
has_prefix: function(val, sep) {
|
311 |
-
return ( this.is_string(val) && 0 === val.indexOf(this.get_prefix() + this.get_sep(sep)) );
|
312 |
-
},
|
313 |
-
|
314 |
-
/**
|
315 |
-
* Add Prefix to a string
|
316 |
-
* @param string val Value to add prefix to
|
317 |
-
* @param string sep (optional) Separator (Default: `_`)
|
318 |
-
* @param bool (optional) once If text should only be prefixed once (Default: TRUE)
|
319 |
-
*/
|
320 |
-
add_prefix: function(val, sep, once) {
|
321 |
-
// Validate
|
322 |
-
if ( !this.is_string(val) ) {
|
323 |
-
// Return prefix if value to add prefix to is empty
|
324 |
-
return this.get_prefix();
|
325 |
-
}
|
326 |
-
sep = this.get_sep(sep);
|
327 |
-
if ( !this.is_bool(once) ) {
|
328 |
-
once = true;
|
329 |
-
}
|
330 |
-
|
331 |
-
return ( once && this.has_prefix(val, sep) ) ? val : [this.get_prefix(), val].join(sep);
|
332 |
-
},
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Remove Prefix from a string
|
336 |
-
* @param string val Value to add prefix to
|
337 |
-
* @param string sep (optional) Separator (Default: `_`)
|
338 |
-
* @param bool (optional) once If text should only be prefixed once (Default: true)
|
339 |
-
* @return string Original value with prefix removed
|
340 |
-
*/
|
341 |
-
remove_prefix: function(val, sep, once) {
|
342 |
-
// Validate parameters
|
343 |
-
if ( !this.is_string(val, true) ) {
|
344 |
-
return '';
|
345 |
-
}
|
346 |
-
// Default values
|
347 |
-
sep = this.get_sep(sep);
|
348 |
-
if ( !this.is_bool(once) ) {
|
349 |
-
once = true;
|
350 |
-
}
|
351 |
-
// Check if string is prefixed
|
352 |
-
if ( this.has_prefix(val, sep) ) {
|
353 |
-
// Remove prefix
|
354 |
-
var prfx = this.get_prefix() + sep;
|
355 |
-
do {
|
356 |
-
val = val.substr(prfx.length);
|
357 |
-
} while ( !once && this.has_prefix(val, sep) );
|
358 |
-
}
|
359 |
-
return val;
|
360 |
-
},
|
361 |
-
|
362 |
-
/* Attributes */
|
363 |
-
|
364 |
-
/*
|
365 |
-
* Get attribute name
|
366 |
-
* @param string attr_base Attribute's base name
|
367 |
-
* @return string Fully-formed attribute name
|
368 |
-
*/
|
369 |
-
get_attribute: function(attr_base) {
|
370 |
-
// Setup
|
371 |
-
var sep = '-';
|
372 |
-
var top = 'data';
|
373 |
-
// Validate
|
374 |
-
var attr = [top, this.get_prefix()].join(sep);
|
375 |
-
// Process
|
376 |
-
if ( this.is_string(attr_base) && 0 !== attr_base.indexOf(attr + sep) ) {
|
377 |
-
attr = [attr, attr_base].join(sep);
|
378 |
-
}
|
379 |
-
return attr;
|
380 |
-
},
|
381 |
-
|
382 |
-
/* Request */
|
383 |
-
|
384 |
-
/**
|
385 |
-
* Retrieve valid context
|
386 |
-
* @return array Context
|
387 |
-
*/
|
388 |
-
get_context: function() {
|
389 |
-
// Validate
|
390 |
-
var b = this.get_base();
|
391 |
-
if ( !$.isArray(b.context) ) {
|
392 |
-
b.context = [];
|
393 |
-
}
|
394 |
-
// Return context
|
395 |
-
return b.context;
|
396 |
-
},
|
397 |
-
|
398 |
-
/**
|
399 |
-
* Check if a context exists in current request
|
400 |
-
* If multiple contexts are supplied, result will be TRUE if at least ONE context exists
|
401 |
-
*
|
402 |
-
* @param string|array ctx Context to check for
|
403 |
-
* @return bool TRUE if context exists, FALSE otherwise
|
404 |
-
*/
|
405 |
-
is_context: function(ctx) {
|
406 |
-
// Validate context
|
407 |
-
if ( this.is_string(ctx) ) {
|
408 |
-
ctx = [ctx];
|
409 |
-
}
|
410 |
-
return ( this.is_array(ctx) && this.arr_intersect(this.get_context(), ctx).length > 0 );
|
411 |
-
},
|
412 |
-
|
413 |
-
/* Helpers */
|
414 |
-
|
415 |
-
/**
|
416 |
-
* Check if value is set/defined
|
417 |
-
* @param mixed val Value to check
|
418 |
-
* @return bool TRUE if value is defined
|
419 |
-
*/
|
420 |
-
is_set: function(val) {
|
421 |
-
return ( typeof val !== 'undefined' );
|
422 |
-
},
|
423 |
-
|
424 |
-
/**
|
425 |
-
* Validate data type
|
426 |
-
* @param mixed val Value to validate
|
427 |
-
* @param mixed type Data type to compare with (function gets for instance, string checks data type)
|
428 |
-
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
429 |
-
* @return bool TRUE if Value matches specified data type
|
430 |
-
*/
|
431 |
-
is_type: function(val, type, nonempty) {
|
432 |
-
var ret = false;
|
433 |
-
if ( this.is_set(val) && null !== val && this.is_set(type) ) {
|
434 |
-
switch ( $.type(type) ) {
|
435 |
-
case 'function':
|
436 |
-
ret = ( val instanceof type ) ? true : false;
|
437 |
-
break;
|
438 |
-
case 'string':
|
439 |
-
ret = ( $.type(val) === type ) ? true : false;
|
440 |
-
break;
|
441 |
-
default:
|
442 |
-
ret = false;
|
443 |
-
break;
|
444 |
-
}
|
445 |
-
}
|
446 |
-
|
447 |
-
// Validate empty values
|
448 |
-
if ( ret && ( !this.is_set(nonempty) || !!nonempty ) ) {
|
449 |
-
ret = !this.is_empty(val);
|
450 |
-
}
|
451 |
-
return ret;
|
452 |
-
},
|
453 |
-
|
454 |
-
/**
|
455 |
-
* Check if value is a string
|
456 |
-
* @uses is_type()
|
457 |
-
* @param mixed value Value to check
|
458 |
-
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
459 |
-
* @return bool TRUE if value is a valid string
|
460 |
-
*/
|
461 |
-
is_string: function(value, nonempty) {
|
462 |
-
return this.is_type(value, 'string', nonempty);
|
463 |
-
},
|
464 |
-
|
465 |
-
/**
|
466 |
-
* Check if value is an array
|
467 |
-
* @uses is_type()
|
468 |
-
* @param mixed value Value to check
|
469 |
-
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
470 |
-
* @return bool TRUE if value is a valid array
|
471 |
-
*/
|
472 |
-
is_array: function(value, nonempty) {
|
473 |
-
return ( this.is_type(value, 'array', nonempty) );
|
474 |
-
},
|
475 |
-
|
476 |
-
/**
|
477 |
-
* Check if value is a boolean
|
478 |
-
* @uses is_type()
|
479 |
-
* @param mixed value Value to check
|
480 |
-
* @return bool TRUE if value is a valid boolean
|
481 |
-
*/
|
482 |
-
is_bool: function(value) {
|
483 |
-
return this.is_type(value, 'boolean', false);
|
484 |
-
},
|
485 |
-
|
486 |
-
/**
|
487 |
-
* Check if value is an object
|
488 |
-
* @uses is_type()
|
489 |
-
* @param mixed value Value to check
|
490 |
-
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
491 |
-
* @return bool TRUE if value is a valid object
|
492 |
-
*/
|
493 |
-
is_obj: function(value, nonempty) {
|
494 |
-
return this.is_type(value, 'object', nonempty);
|
495 |
-
},
|
496 |
-
|
497 |
-
/**
|
498 |
-
* Check if value is a function
|
499 |
-
* @uses is_type()
|
500 |
-
* @param mixed value Value to check
|
501 |
-
* @return bool TRUE if value is a valid function
|
502 |
-
*/
|
503 |
-
is_func: function(value) {
|
504 |
-
return this.is_type(value, 'function', false);
|
505 |
-
},
|
506 |
-
|
507 |
-
/**
|
508 |
-
* Checks if an object has a method
|
509 |
-
* @param obj obj Object to check
|
510 |
-
* @param string|array key Name(s) of methods to check for
|
511 |
-
* @return bool TRUE if method(s) exist, FALSE otherwise
|
512 |
-
*/
|
513 |
-
is_method: function(obj, key) {
|
514 |
-
var ret = false;
|
515 |
-
if ( this.is_string(key) ) {
|
516 |
-
key = [key];
|
517 |
-
}
|
518 |
-
if ( this.in_obj(obj, key) ) {
|
519 |
-
ret = true;
|
520 |
-
var x = 0;
|
521 |
-
while ( ret && x < key.length ) {
|
522 |
-
ret = this.is_func(obj[key[x]]);
|
523 |
-
x++;
|
524 |
-
}
|
525 |
-
}
|
526 |
-
return ret;
|
527 |
-
},
|
528 |
-
|
529 |
-
/**
|
530 |
-
* Check if object is instance of a class
|
531 |
-
* @param obj obj Instance object
|
532 |
-
* @param obj parent Class to compare with
|
533 |
-
* @return bool TRUE if object is instance of class
|
534 |
-
*/
|
535 |
-
is_instance: function(obj, parent) {
|
536 |
-
if ( !this.is_func(parent) ) {
|
537 |
-
return false;
|
538 |
-
}
|
539 |
-
return ( this.is_obj(obj) && ( obj instanceof parent ) );
|
540 |
-
},
|
541 |
-
|
542 |
-
/**
|
543 |
-
* Check if object is class
|
544 |
-
* Optionally check if class is sub-class of another class
|
545 |
-
* @param func cls Class to check
|
546 |
-
* @param func parent (optional) parent class
|
547 |
-
* @return bool TRUE if object is valid class (and sub-class if parent is specified)
|
548 |
-
*/
|
549 |
-
is_class: function(cls, parent) {
|
550 |
-
// Validate class
|
551 |
-
var ret = ( this.is_func(cls) && ( 'prototype' in cls ) );
|
552 |
-
// Check parent class
|
553 |
-
if ( ret && this.is_set(parent) ) {
|
554 |
-
ret = this.is_instance(cls.prototype, parent);
|
555 |
-
}
|
556 |
-
return ret;
|
557 |
-
},
|
558 |
-
|
559 |
-
/**
|
560 |
-
* Check if value is a number
|
561 |
-
* @uses is_type()
|
562 |
-
* @param mixed value Value to check
|
563 |
-
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
564 |
-
* @return bool TRUE if value is a valid number
|
565 |
-
*/
|
566 |
-
is_num: function(value, nonempty) {
|
567 |
-
var f = {
|
568 |
-
'nan': ( Number.isNaN ) ? Number.isNaN : isNaN,
|
569 |
-
'finite': ( Number.isFinite ) ? Number.isFinite : isFinite
|
570 |
-
};
|
571 |
-
return ( this.is_type(value, 'number', nonempty) && !f.nan(value) && f.finite(value) );
|
572 |
-
},
|
573 |
-
|
574 |
-
/**
|
575 |
-
* Check if value is a integer
|
576 |
-
* @uses is_type()
|
577 |
-
* @param mixed value Value to check
|
578 |
-
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
579 |
-
* @return bool TRUE if value is a valid integer
|
580 |
-
*/
|
581 |
-
is_int: function(value, nonempty) {
|
582 |
-
return ( this.is_num(value, nonempty) && Math.floor(value) === value );
|
583 |
-
},
|
584 |
-
|
585 |
-
/**
|
586 |
-
* Check if value is scalar (string, number, boolean)
|
587 |
-
* @uses is_type()
|
588 |
-
* @param mixed value Value to check
|
589 |
-
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
590 |
-
* @return bool TRUE if value is scalar
|
591 |
-
*/
|
592 |
-
is_scalar: function(value, nonempty) {
|
593 |
-
return ( this.is_num(value, nonempty) || this.is_string(value, nonempty) || this.is_bool(value) );
|
594 |
-
},
|
595 |
-
|
596 |
-
/**
|
597 |
-
* Checks if value is empty
|
598 |
-
* @param mixed value Value to check
|
599 |
-
* @param string type (optional) Data type
|
600 |
-
* @return bool TRUE if value is empty
|
601 |
-
*/
|
602 |
-
is_empty: function(value, type) {
|
603 |
-
var ret = false;
|
604 |
-
// Check Undefined
|
605 |
-
if ( !this.is_set(value) ) {
|
606 |
-
ret = true;
|
607 |
-
} else {
|
608 |
-
// Check standard values
|
609 |
-
var empties = [null, "", false, 0];
|
610 |
-
var x = 0;
|
611 |
-
while ( !ret && x < empties.length ) {
|
612 |
-
ret = ( empties[x] === value );
|
613 |
-
x++;
|
614 |
-
}
|
615 |
-
}
|
616 |
-
|
617 |
-
// Advanced check
|
618 |
-
if ( !ret ) {
|
619 |
-
// Validate type
|
620 |
-
if ( !this.is_set(type) ) {
|
621 |
-
type = $.type(value);
|
622 |
-
}
|
623 |
-
// Type-based check
|
624 |
-
if ( this.is_type(value, type, false) ) {
|
625 |
-
switch ( type ) {
|
626 |
-
case 'string':
|
627 |
-
case 'array':
|
628 |
-
ret = ( value.length === 0 );
|
629 |
-
break;
|
630 |
-
case 'number':
|
631 |
-
ret = ( value == 0 ); // jshint ignore:line
|
632 |
-
break;
|
633 |
-
case 'object':
|
634 |
-
if ( !$.isPlainObject(value) ) {
|
635 |
-
// Custom object. Unable to evaluate emptiness further
|
636 |
-
ret = false;
|
637 |
-
} else {
|
638 |
-
// Evaluate plain object
|
639 |
-
if ( Object.getOwnPropertyNames ) {
|
640 |
-
// Modern browser check
|
641 |
-
ret = ( Object.getOwnPropertyNames(value).length === 0 );
|
642 |
-
} else if ( value.hasOwnProperty ) {
|
643 |
-
// Legacy browser check
|
644 |
-
ret = true;
|
645 |
-
for ( var key in value ) {
|
646 |
-
if ( value.hasOwnProperty(key) ) {
|
647 |
-
ret = false;
|
648 |
-
break;
|
649 |
-
}
|
650 |
-
}
|
651 |
-
}
|
652 |
-
}
|
653 |
-
break;
|
654 |
-
}
|
655 |
-
} else {
|
656 |
-
ret = true;
|
657 |
-
}
|
658 |
-
}
|
659 |
-
return ret;
|
660 |
-
},
|
661 |
-
|
662 |
-
/**
|
663 |
-
* Check if object is a jQuery.Promise instance
|
664 |
-
* Will also match (but not guarantee) jQuery.Deferred instances
|
665 |
-
* @uses is_method()
|
666 |
-
* @param obj obj Object to check
|
667 |
-
* @return bool TRUE if object is Promise/Deferred
|
668 |
-
*/
|
669 |
-
is_promise: function(obj) {
|
670 |
-
return ( this.is_method(obj, ['then', 'done', 'always', 'fail', 'pipe']) );
|
671 |
-
},
|
672 |
-
|
673 |
-
/**
|
674 |
-
* Return formatted string
|
675 |
-
* @param string fmt Format template
|
676 |
-
* @param string val Replacement value (Multiple parameters may be set)
|
677 |
-
* @return string Formatted string
|
678 |
-
*/
|
679 |
-
format: function(fmt, val) {
|
680 |
-
// Validate format
|
681 |
-
if ( !this.is_string(fmt) ) {
|
682 |
-
return '';
|
683 |
-
}
|
684 |
-
var params = [];
|
685 |
-
var ph = '%s';
|
686 |
-
/**
|
687 |
-
* Clean string (remove placeholders)
|
688 |
-
*/
|
689 |
-
var strip = function(txt) {
|
690 |
-
return ( txt.indexOf(ph) !== -1 ) ? txt.replace(ph, '') : txt;
|
691 |
-
};
|
692 |
-
// Stop processing if no replacement values specified or format string contains no placeholders
|
693 |
-
if ( arguments.length < 2 || fmt.indexOf(ph) === -1 ) {
|
694 |
-
return strip(fmt);
|
695 |
-
}
|
696 |
-
// Get replacement values
|
697 |
-
params = Array.prototype.slice.call(arguments, 1);
|
698 |
-
val = null;
|
699 |
-
// Clean parameters
|
700 |
-
for ( var x = 0; x < params.length; x++ ) {
|
701 |
-
if ( !this.is_scalar(params[x], false) ) {
|
702 |
-
params[x] = '';
|
703 |
-
}
|
704 |
-
}
|
705 |
-
|
706 |
-
// Replace all placeholders at once if single parameter set
|
707 |
-
if ( params.length === 1 ) {
|
708 |
-
fmt = fmt.replace(ph, params[0].toString());
|
709 |
-
} else {
|
710 |
-
var idx = 0; // Current replacement index
|
711 |
-
var len = params.length; // Number of replacements
|
712 |
-
var rlen = ph.length; // Placeholder length
|
713 |
-
var pos = 0; // Current placeholder position (in format template)
|
714 |
-
while ( ( pos = fmt.indexOf(ph) ) && pos !== -1 && idx < len ) {
|
715 |
-
// Replace current placeholder with respective parameter
|
716 |
-
fmt = fmt.substr(0, pos) + params[idx].toString() + fmt.substr(pos + rlen);
|
717 |
-
idx++;
|
718 |
-
}
|
719 |
-
// Remove any remaining placeholders
|
720 |
-
fmt = strip(fmt);
|
721 |
-
}
|
722 |
-
return fmt;
|
723 |
-
},
|
724 |
-
|
725 |
-
/**
|
726 |
-
* Checks if key(s) exist in an object
|
727 |
-
* @param object obj Object to check
|
728 |
-
* @param string|array key Key(s) to check for in object
|
729 |
-
* @param bool all (optional) All keys must exist in object? (Default: TRUE)
|
730 |
-
* @return bool TRUE if key(s) exist in object
|
731 |
-
*/
|
732 |
-
in_obj: function(obj, key, all) {
|
733 |
-
// Validate
|
734 |
-
if ( !this.is_bool(all) ) {
|
735 |
-
all = true;
|
736 |
-
}
|
737 |
-
if ( this.is_string(key) ) {
|
738 |
-
key = [key];
|
739 |
-
}
|
740 |
-
// Check for keys
|
741 |
-
var ret = false;
|
742 |
-
if ( this.is_obj(obj) && this.is_array(key) ) {
|
743 |
-
var val;
|
744 |
-
for ( var x = 0; x < key.length; x++ ) {
|
745 |
-
val = key[x];
|
746 |
-
ret = ( this.is_string(val) && ( val in obj ) ) ? true : false;
|
747 |
-
// Stop processing if conditions have been met
|
748 |
-
if ( ( !all && ret ) || ( all && !ret ) ) {
|
749 |
-
break;
|
750 |
-
}
|
751 |
-
}
|
752 |
-
}
|
753 |
-
return ret;
|
754 |
-
},
|
755 |
-
|
756 |
-
/**
|
757 |
-
* Retrieve an object's keys
|
758 |
-
* @param obj Object to parse
|
759 |
-
* @return array List of object's keys
|
760 |
-
*/
|
761 |
-
obj_keys: function(obj) {
|
762 |
-
var keys = [];
|
763 |
-
// Validation
|
764 |
-
if ( !this.is_obj(obj) ) {
|
765 |
-
return keys;
|
766 |
-
}
|
767 |
-
if ( Object.keys ) {
|
768 |
-
keys = Object.keys(obj);
|
769 |
-
} else {
|
770 |
-
var prop;
|
771 |
-
for ( prop in obj ) {
|
772 |
-
if ( obj.hasOwnProperty(prop) ) {
|
773 |
-
keys.push(prop);
|
774 |
-
}
|
775 |
-
}
|
776 |
-
}
|
777 |
-
return keys;
|
778 |
-
},
|
779 |
-
|
780 |
-
/**
|
781 |
-
* Find common elements of 2 or more arrays
|
782 |
-
* @param array arr1 First array
|
783 |
-
* @param array arr2 Second array (additional arrays can be passed as well)
|
784 |
-
* @return array Elements common to all
|
785 |
-
*/
|
786 |
-
arr_intersect: function(arr1, arr2) {
|
787 |
-
var ret = [];
|
788 |
-
// Get arrays
|
789 |
-
var params = Array.prototype.slice.call(arguments);
|
790 |
-
// Clean arrays
|
791 |
-
var arrs = [];
|
792 |
-
var x;
|
793 |
-
for ( x = 0; x < params.length; x++ ) {
|
794 |
-
if ( this.is_array(params[x], false) ) {
|
795 |
-
arrs.push(params[x]);
|
796 |
-
}
|
797 |
-
}
|
798 |
-
// Stop processing if no valid arrays to compare
|
799 |
-
if ( arrs.length < 2 ) {
|
800 |
-
return ret;
|
801 |
-
}
|
802 |
-
params = arr1 = arr2 = null;
|
803 |
-
// Find common elements in arrays
|
804 |
-
var base = arrs.shift();
|
805 |
-
var add;
|
806 |
-
var sub;
|
807 |
-
for ( x = 0; x < base.length; x++ ) {
|
808 |
-
add = true;
|
809 |
-
// Check other arrays for element match
|
810 |
-
for ( sub = 0; sub < arrs.length; sub++ ) {
|
811 |
-
if ( arrs[sub].indexOf(base[x]) === -1 ) {
|
812 |
-
add = false;
|
813 |
-
break;
|
814 |
-
}
|
815 |
-
}
|
816 |
-
if ( add ) {
|
817 |
-
ret.push(base[x]);
|
818 |
-
}
|
819 |
-
}
|
820 |
-
// Return intersection results
|
821 |
-
return ret;
|
822 |
-
},
|
823 |
-
|
824 |
-
/**
|
825 |
-
* Generates a GUID string.
|
826 |
-
* @returns string The generated GUID.
|
827 |
-
* @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
|
828 |
-
* @author Slavik Meltser (slavik@meltser.info).
|
829 |
-
* @link http://slavik.meltser.info/?p=142
|
830 |
-
*/
|
831 |
-
guid: function() {
|
832 |
-
function _p8(s) {
|
833 |
-
var p = (Math.random().toString(16)+"000000000").substr(2,8);
|
834 |
-
return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
|
835 |
-
}
|
836 |
-
return _p8() + _p8(true) + _p8(true) + _p8();
|
837 |
-
},
|
838 |
-
|
839 |
-
/**
|
840 |
-
* Parse URI
|
841 |
-
* @param string uri URI to parse
|
842 |
-
* @return obj URI components (DOM anchor element)
|
843 |
-
*/
|
844 |
-
parse_uri: function(uri) {
|
845 |
-
return $('<a href="' + uri + '"/>').get(0);
|
846 |
-
},
|
847 |
-
/**
|
848 |
-
* Parse URI query string
|
849 |
-
* @param string uri URI with query string to parse
|
850 |
-
* @return obj Query variables and values (empty if no query string)
|
851 |
-
*/
|
852 |
-
parse_query: function(uri) {
|
853 |
-
var delim = {
|
854 |
-
'vars': '&',
|
855 |
-
'val': '='
|
856 |
-
};
|
857 |
-
var query = {
|
858 |
-
'raw': [],
|
859 |
-
'parsed': {},
|
860 |
-
'string': ''
|
861 |
-
};
|
862 |
-
uri = this.parse_uri(uri);
|
863 |
-
if ( 0 === uri.search.indexOf('?') ) {
|
864 |
-
// Extract query string
|
865 |
-
query.raw = uri.search.substr(1).split(delim.vars);
|
866 |
-
var i, temp, key, val;
|
867 |
-
// Build query object
|
868 |
-
for ( i = 0; i < query.raw.length; i++ ) {
|
869 |
-
// Split var and value
|
870 |
-
temp = query.raw[i].split(delim.val);
|
871 |
-
key = temp.shift();
|
872 |
-
val = ( temp.length > 0 ) ? temp.join(delim.val) : null;
|
873 |
-
query.parsed[key] = val;
|
874 |
-
}
|
875 |
-
}
|
876 |
-
return query.parsed;
|
877 |
-
},
|
878 |
-
/**
|
879 |
-
* Build query string from object
|
880 |
-
* @param obj query Query data
|
881 |
-
* @return string Query data formatted as HTTP query string
|
882 |
-
*/
|
883 |
-
build_query: function(query) {
|
884 |
-
var q = [];
|
885 |
-
var delim = {
|
886 |
-
'vars': '&',
|
887 |
-
'val': '='
|
888 |
-
};
|
889 |
-
var val;
|
890 |
-
for ( var key in query ) {
|
891 |
-
val = ( null !== query[key] ) ? delim.val + query[key] : '';
|
892 |
-
q.push(key + val);
|
893 |
-
}
|
894 |
-
return q.join(delim.vars);
|
895 |
-
}
|
896 |
-
};
|
897 |
-
|
898 |
-
// Attach Utilities
|
899 |
-
Base.attach('util', Utilities, true);
|
900 |
-
|
901 |
-
/**
|
902 |
-
* SLB Base Class
|
903 |
-
*/
|
904 |
-
var SLB_Base = Class.extend(Base);
|
905 |
-
|
906 |
-
/**
|
907 |
-
* Core
|
908 |
-
*/
|
909 |
-
var Core = {
|
910 |
-
/* Properties */
|
911 |
-
|
912 |
-
base: true,
|
913 |
-
context: [],
|
914 |
-
|
915 |
-
/**
|
916 |
-
* New object initializer
|
917 |
-
* @var obj
|
918 |
-
*/
|
919 |
-
Class: SLB_Base,
|
920 |
-
|
921 |
-
/* Methods */
|
922 |
-
|
923 |
-
/**
|
924 |
-
* Init
|
925 |
-
* Set variables, DOM, etc.
|
926 |
-
*/
|
927 |
-
_init: function() {
|
928 |
-
this._super();
|
929 |
-
$('html').addClass(this.util.get_prefix());
|
930 |
-
}
|
931 |
-
};
|
932 |
-
var SLB_Core = SLB_Base.extend(Core);
|
933 |
-
window.SLB = new SLB_Core();
|
934 |
})(jQuery);}
|
1 |
+
/**
|
2 |
+
* Core
|
3 |
+
* @package SLB
|
4 |
+
* @author Archetyped
|
5 |
+
*/
|
6 |
+
if ( window.jQuery ){(function($) {
|
7 |
+
'use strict';
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Extendible class
|
11 |
+
* Adapted from John Resig
|
12 |
+
* @link http://ejohn.org/blog/simple-javascript-inheritance/
|
13 |
+
*/
|
14 |
+
var c_init = false;
|
15 |
+
var Class = function() {};
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Create class that extends another class
|
19 |
+
* @param object members Child class' properties
|
20 |
+
* @return function New class
|
21 |
+
*/
|
22 |
+
Class.extend = function(members) {
|
23 |
+
var _super = this.prototype;
|
24 |
+
|
25 |
+
// Copy instance to prototype
|
26 |
+
c_init = true;
|
27 |
+
var proto = new this();
|
28 |
+
c_init = false;
|
29 |
+
|
30 |
+
var val, name;
|
31 |
+
// Scrub prototype objects (Decouple from super class)
|
32 |
+
for ( name in proto ) {
|
33 |
+
if ( $.isPlainObject(proto[name]) ) {
|
34 |
+
val = $.extend({}, proto[name]);
|
35 |
+
proto[name] = val;
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Create class method with access to super class method
|
41 |
+
* @param string nm Method name
|
42 |
+
* @param function fn Class method
|
43 |
+
* @return function Class method with access to super class method
|
44 |
+
*/
|
45 |
+
var make_handler = function(nm, fn) {
|
46 |
+
return function() {
|
47 |
+
// Cache super variable
|
48 |
+
var tmp = this._super;
|
49 |
+
// Set variable to super class method
|
50 |
+
this._super = _super[nm];
|
51 |
+
// Call method
|
52 |
+
var ret = fn.apply(this, arguments);
|
53 |
+
// Restore super variable
|
54 |
+
this._super = tmp;
|
55 |
+
// Return value
|
56 |
+
return ret;
|
57 |
+
};
|
58 |
+
};
|
59 |
+
// Copy properties to Class
|
60 |
+
for ( name in members ) {
|
61 |
+
// Add access to super class method to methods
|
62 |
+
if ( 'function' === typeof members[name] && 'function' === typeof _super[name] ) {
|
63 |
+
proto[name] = make_handler(name, members[name]);
|
64 |
+
} else {
|
65 |
+
// Transfer properties
|
66 |
+
// Objects are copied, not referenced
|
67 |
+
proto[name] = ( $.isPlainObject(members[name]) ) ? $.extend({}, members[name]) : members[name];
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Class constructor
|
73 |
+
* Supports pre-construction initilization (`Class._init()`)
|
74 |
+
* Supports passing constructor for new classes (`Class._c()`)
|
75 |
+
*/
|
76 |
+
function Class() {
|
77 |
+
if ( !c_init ) {
|
78 |
+
// Private initialization
|
79 |
+
if ( 'function' === typeof this._init ) {
|
80 |
+
this._init.apply(this, arguments);
|
81 |
+
}
|
82 |
+
// Main Constructor
|
83 |
+
if ( 'function' === typeof this._c ) {
|
84 |
+
this._c.apply(this, arguments);
|
85 |
+
}
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
|
90 |
+
// Populate new prototype
|
91 |
+
Class.prototype = proto;
|
92 |
+
|
93 |
+
// Set constructor
|
94 |
+
Class.prototype.constructor = Class;
|
95 |
+
|
96 |
+
// Set extender
|
97 |
+
Class.extend = this.extend;
|
98 |
+
|
99 |
+
// Return function
|
100 |
+
return Class;
|
101 |
+
};
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Base Class
|
105 |
+
*/
|
106 |
+
var Base = {
|
107 |
+
/* Properties */
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Base object flag
|
111 |
+
* @var bool
|
112 |
+
*/
|
113 |
+
base: false,
|
114 |
+
/**
|
115 |
+
* Instance parent
|
116 |
+
* @var object
|
117 |
+
*/
|
118 |
+
_parent: null,
|
119 |
+
/**
|
120 |
+
* Class prefix
|
121 |
+
* @var string
|
122 |
+
*/
|
123 |
+
prefix: 'slb',
|
124 |
+
|
125 |
+
/* Methods */
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Constructor
|
129 |
+
* Sets instance parent
|
130 |
+
*/
|
131 |
+
_init: function() {
|
132 |
+
this._set_parent();
|
133 |
+
},
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Set instance parent
|
137 |
+
* Set utilities parent to current instance
|
138 |
+
* @param obj p Parent instance
|
139 |
+
*/
|
140 |
+
_set_parent: function(p) {
|
141 |
+
if ( this.util.is_set(p) ) {
|
142 |
+
this._parent = p;
|
143 |
+
}
|
144 |
+
this.util._parent = this;
|
145 |
+
},
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Attach new member to instance
|
149 |
+
* Member can be property (value) or method
|
150 |
+
* @param string name Member name
|
151 |
+
* @param object data Member data
|
152 |
+
* @param bool simple (optional) Save new member as data object or new class instance (Default: new instance)
|
153 |
+
* @return obj Attached object
|
154 |
+
*/
|
155 |
+
attach: function(member, data, simple) {
|
156 |
+
var ret = data;
|
157 |
+
// Validate
|
158 |
+
simple = ( typeof simple === 'undefined' ) ? false : !!simple;
|
159 |
+
// Add member to instance
|
160 |
+
if ( 'string' === $.type(member) ) {
|
161 |
+
// Prepare member value
|
162 |
+
if ( $.isPlainObject(data) && !simple ) {
|
163 |
+
// Set parent reference for attached instance
|
164 |
+
data['_parent'] = this;
|
165 |
+
// Define new class
|
166 |
+
data = this.Class.extend(data);
|
167 |
+
}
|
168 |
+
// Save member to current instance
|
169 |
+
// Initialize new instance if data is a class
|
170 |
+
this[member] = ( 'function' === $.type(data) ) ? new data() : data;
|
171 |
+
ret = this[member];
|
172 |
+
}
|
173 |
+
return ret;
|
174 |
+
},
|
175 |
+
|
176 |
+
/**
|
177 |
+
* Check for child object
|
178 |
+
* Child object can be multi-level (e.g. Child.Level2child.Level3child)
|
179 |
+
*
|
180 |
+
* @param string child Name of child object
|
181 |
+
*/
|
182 |
+
has_child: function(child) {
|
183 |
+
// Validate
|
184 |
+
if ( !this.util.is_string(child) ) {
|
185 |
+
return false;
|
186 |
+
}
|
187 |
+
|
188 |
+
var children = child.split('.');
|
189 |
+
child = null;
|
190 |
+
var o = this;
|
191 |
+
var x;
|
192 |
+
for ( x = 0; x < children.length; x++ ) {
|
193 |
+
child = children[x];
|
194 |
+
if ( "" === child ) {
|
195 |
+
continue;
|
196 |
+
}
|
197 |
+
if ( this.util.is_obj(o) && o[child] ) {
|
198 |
+
o = o[child];
|
199 |
+
} else {
|
200 |
+
return false;
|
201 |
+
}
|
202 |
+
}
|
203 |
+
return true;
|
204 |
+
},
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Check if instance is set as a base
|
208 |
+
* @uses base
|
209 |
+
* @return bool TRUE if object is set as a base
|
210 |
+
*/
|
211 |
+
is_base: function() {
|
212 |
+
return !!this.base;
|
213 |
+
},
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Get parent instance
|
217 |
+
* @uses `Base._parent` property
|
218 |
+
* @return obj Parent instance
|
219 |
+
*/
|
220 |
+
get_parent: function() {
|
221 |
+
var p = this._parent;
|
222 |
+
// Validate
|
223 |
+
if ( !p ) {
|
224 |
+
this._parent = {};
|
225 |
+
}
|
226 |
+
return this._parent;
|
227 |
+
}
|
228 |
+
};
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Utility methods
|
232 |
+
*/
|
233 |
+
var Utilities = {
|
234 |
+
/* Properties */
|
235 |
+
|
236 |
+
_base: null,
|
237 |
+
_parent: null,
|
238 |
+
|
239 |
+
/* Methods */
|
240 |
+
|
241 |
+
/* Connections */
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Get base ancestor
|
245 |
+
* @return obj Base ancestor
|
246 |
+
*/
|
247 |
+
get_base: function() {
|
248 |
+
if ( !this._base ) {
|
249 |
+
var p = this.get_parent();
|
250 |
+
var p_prev = null;
|
251 |
+
var methods = ['is_base', 'get_parent'];
|
252 |
+
// Find base ancestor
|
253 |
+
// Either oldest ancestor or object explicitly set as a base
|
254 |
+
while ( ( p_prev !== p ) && this.is_method(p, methods) && !p.is_base() ) {
|
255 |
+
// Save previous parent
|
256 |
+
p_prev = p;
|
257 |
+
// Get new parent
|
258 |
+
p = p.get_parent();
|
259 |
+
}
|
260 |
+
// Set base
|
261 |
+
this._base = p;
|
262 |
+
}
|
263 |
+
return this._base;
|
264 |
+
},
|
265 |
+
|
266 |
+
/**
|
267 |
+
* Get parent object or parent property value
|
268 |
+
* @param string prop (optional) Property to retrieve
|
269 |
+
* @return obj Parent object or property value
|
270 |
+
*/
|
271 |
+
get_parent: function(prop) {
|
272 |
+
var ret = this._parent;
|
273 |
+
// Validate
|
274 |
+
if ( !ret ) {
|
275 |
+
// Set default parent value
|
276 |
+
ret = this._parent = {};
|
277 |
+
}
|
278 |
+
// Get parent property
|
279 |
+
if ( this.is_string(prop) ) {
|
280 |
+
ret = ( this.in_obj(ret, prop) ) ? ret[prop] : null;
|
281 |
+
}
|
282 |
+
return ret;
|
283 |
+
},
|
284 |
+
|
285 |
+
/* Prefix */
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Retrieve valid separator
|
289 |
+
* If supplied argument is not a valid separator, use default separator
|
290 |
+
* @param string (optional) sep Separator text
|
291 |
+
* @return string Separator text
|
292 |
+
*/
|
293 |
+
get_sep: function(sep) {
|
294 |
+
var sep_default = '_';
|
295 |
+
return ( this.is_string(sep, false) ) ? sep : sep_default;
|
296 |
+
},
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Retrieve prefix
|
300 |
+
* @return string Prefix
|
301 |
+
*/
|
302 |
+
get_prefix: function() {
|
303 |
+
var p = this.get_parent('prefix');
|
304 |
+
return ( this.is_string(p, false) ) ? p : '';
|
305 |
+
},
|
306 |
+
|
307 |
+
/**
|
308 |
+
* Check if string is prefixed
|
309 |
+
*/
|
310 |
+
has_prefix: function(val, sep) {
|
311 |
+
return ( this.is_string(val) && 0 === val.indexOf(this.get_prefix() + this.get_sep(sep)) );
|
312 |
+
},
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Add Prefix to a string
|
316 |
+
* @param string val Value to add prefix to
|
317 |
+
* @param string sep (optional) Separator (Default: `_`)
|
318 |
+
* @param bool (optional) once If text should only be prefixed once (Default: TRUE)
|
319 |
+
*/
|
320 |
+
add_prefix: function(val, sep, once) {
|
321 |
+
// Validate
|
322 |
+
if ( !this.is_string(val) ) {
|
323 |
+
// Return prefix if value to add prefix to is empty
|
324 |
+
return this.get_prefix();
|
325 |
+
}
|
326 |
+
sep = this.get_sep(sep);
|
327 |
+
if ( !this.is_bool(once) ) {
|
328 |
+
once = true;
|
329 |
+
}
|
330 |
+
|
331 |
+
return ( once && this.has_prefix(val, sep) ) ? val : [this.get_prefix(), val].join(sep);
|
332 |
+
},
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Remove Prefix from a string
|
336 |
+
* @param string val Value to add prefix to
|
337 |
+
* @param string sep (optional) Separator (Default: `_`)
|
338 |
+
* @param bool (optional) once If text should only be prefixed once (Default: true)
|
339 |
+
* @return string Original value with prefix removed
|
340 |
+
*/
|
341 |
+
remove_prefix: function(val, sep, once) {
|
342 |
+
// Validate parameters
|
343 |
+
if ( !this.is_string(val, true) ) {
|
344 |
+
return '';
|
345 |
+
}
|
346 |
+
// Default values
|
347 |
+
sep = this.get_sep(sep);
|
348 |
+
if ( !this.is_bool(once) ) {
|
349 |
+
once = true;
|
350 |
+
}
|
351 |
+
// Check if string is prefixed
|
352 |
+
if ( this.has_prefix(val, sep) ) {
|
353 |
+
// Remove prefix
|
354 |
+
var prfx = this.get_prefix() + sep;
|
355 |
+
do {
|
356 |
+
val = val.substr(prfx.length);
|
357 |
+
} while ( !once && this.has_prefix(val, sep) );
|
358 |
+
}
|
359 |
+
return val;
|
360 |
+
},
|
361 |
+
|
362 |
+
/* Attributes */
|
363 |
+
|
364 |
+
/*
|
365 |
+
* Get attribute name
|
366 |
+
* @param string attr_base Attribute's base name
|
367 |
+
* @return string Fully-formed attribute name
|
368 |
+
*/
|
369 |
+
get_attribute: function(attr_base) {
|
370 |
+
// Setup
|
371 |
+
var sep = '-';
|
372 |
+
var top = 'data';
|
373 |
+
// Validate
|
374 |
+
var attr = [top, this.get_prefix()].join(sep);
|
375 |
+
// Process
|
376 |
+
if ( this.is_string(attr_base) && 0 !== attr_base.indexOf(attr + sep) ) {
|
377 |
+
attr = [attr, attr_base].join(sep);
|
378 |
+
}
|
379 |
+
return attr;
|
380 |
+
},
|
381 |
+
|
382 |
+
/* Request */
|
383 |
+
|
384 |
+
/**
|
385 |
+
* Retrieve valid context
|
386 |
+
* @return array Context
|
387 |
+
*/
|
388 |
+
get_context: function() {
|
389 |
+
// Validate
|
390 |
+
var b = this.get_base();
|
391 |
+
if ( !$.isArray(b.context) ) {
|
392 |
+
b.context = [];
|
393 |
+
}
|
394 |
+
// Return context
|
395 |
+
return b.context;
|
396 |
+
},
|
397 |
+
|
398 |
+
/**
|
399 |
+
* Check if a context exists in current request
|
400 |
+
* If multiple contexts are supplied, result will be TRUE if at least ONE context exists
|
401 |
+
*
|
402 |
+
* @param string|array ctx Context to check for
|
403 |
+
* @return bool TRUE if context exists, FALSE otherwise
|
404 |
+
*/
|
405 |
+
is_context: function(ctx) {
|
406 |
+
// Validate context
|
407 |
+
if ( this.is_string(ctx) ) {
|
408 |
+
ctx = [ctx];
|
409 |
+
}
|
410 |
+
return ( this.is_array(ctx) && this.arr_intersect(this.get_context(), ctx).length > 0 );
|
411 |
+
},
|
412 |
+
|
413 |
+
/* Helpers */
|
414 |
+
|
415 |
+
/**
|
416 |
+
* Check if value is set/defined
|
417 |
+
* @param mixed val Value to check
|
418 |
+
* @return bool TRUE if value is defined
|
419 |
+
*/
|
420 |
+
is_set: function(val) {
|
421 |
+
return ( typeof val !== 'undefined' );
|
422 |
+
},
|
423 |
+
|
424 |
+
/**
|
425 |
+
* Validate data type
|
426 |
+
* @param mixed val Value to validate
|
427 |
+
* @param mixed type Data type to compare with (function gets for instance, string checks data type)
|
428 |
+
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
429 |
+
* @return bool TRUE if Value matches specified data type
|
430 |
+
*/
|
431 |
+
is_type: function(val, type, nonempty) {
|
432 |
+
var ret = false;
|
433 |
+
if ( this.is_set(val) && null !== val && this.is_set(type) ) {
|
434 |
+
switch ( $.type(type) ) {
|
435 |
+
case 'function':
|
436 |
+
ret = ( val instanceof type ) ? true : false;
|
437 |
+
break;
|
438 |
+
case 'string':
|
439 |
+
ret = ( $.type(val) === type ) ? true : false;
|
440 |
+
break;
|
441 |
+
default:
|
442 |
+
ret = false;
|
443 |
+
break;
|
444 |
+
}
|
445 |
+
}
|
446 |
+
|
447 |
+
// Validate empty values
|
448 |
+
if ( ret && ( !this.is_set(nonempty) || !!nonempty ) ) {
|
449 |
+
ret = !this.is_empty(val);
|
450 |
+
}
|
451 |
+
return ret;
|
452 |
+
},
|
453 |
+
|
454 |
+
/**
|
455 |
+
* Check if value is a string
|
456 |
+
* @uses is_type()
|
457 |
+
* @param mixed value Value to check
|
458 |
+
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
459 |
+
* @return bool TRUE if value is a valid string
|
460 |
+
*/
|
461 |
+
is_string: function(value, nonempty) {
|
462 |
+
return this.is_type(value, 'string', nonempty);
|
463 |
+
},
|
464 |
+
|
465 |
+
/**
|
466 |
+
* Check if value is an array
|
467 |
+
* @uses is_type()
|
468 |
+
* @param mixed value Value to check
|
469 |
+
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
470 |
+
* @return bool TRUE if value is a valid array
|
471 |
+
*/
|
472 |
+
is_array: function(value, nonempty) {
|
473 |
+
return ( this.is_type(value, 'array', nonempty) );
|
474 |
+
},
|
475 |
+
|
476 |
+
/**
|
477 |
+
* Check if value is a boolean
|
478 |
+
* @uses is_type()
|
479 |
+
* @param mixed value Value to check
|
480 |
+
* @return bool TRUE if value is a valid boolean
|
481 |
+
*/
|
482 |
+
is_bool: function(value) {
|
483 |
+
return this.is_type(value, 'boolean', false);
|
484 |
+
},
|
485 |
+
|
486 |
+
/**
|
487 |
+
* Check if value is an object
|
488 |
+
* @uses is_type()
|
489 |
+
* @param mixed value Value to check
|
490 |
+
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
491 |
+
* @return bool TRUE if value is a valid object
|
492 |
+
*/
|
493 |
+
is_obj: function(value, nonempty) {
|
494 |
+
return this.is_type(value, 'object', nonempty);
|
495 |
+
},
|
496 |
+
|
497 |
+
/**
|
498 |
+
* Check if value is a function
|
499 |
+
* @uses is_type()
|
500 |
+
* @param mixed value Value to check
|
501 |
+
* @return bool TRUE if value is a valid function
|
502 |
+
*/
|
503 |
+
is_func: function(value) {
|
504 |
+
return this.is_type(value, 'function', false);
|
505 |
+
},
|
506 |
+
|
507 |
+
/**
|
508 |
+
* Checks if an object has a method
|
509 |
+
* @param obj obj Object to check
|
510 |
+
* @param string|array key Name(s) of methods to check for
|
511 |
+
* @return bool TRUE if method(s) exist, FALSE otherwise
|
512 |
+
*/
|
513 |
+
is_method: function(obj, key) {
|
514 |
+
var ret = false;
|
515 |
+
if ( this.is_string(key) ) {
|
516 |
+
key = [key];
|
517 |
+
}
|
518 |
+
if ( this.in_obj(obj, key) ) {
|
519 |
+
ret = true;
|
520 |
+
var x = 0;
|
521 |
+
while ( ret && x < key.length ) {
|
522 |
+
ret = this.is_func(obj[key[x]]);
|
523 |
+
x++;
|
524 |
+
}
|
525 |
+
}
|
526 |
+
return ret;
|
527 |
+
},
|
528 |
+
|
529 |
+
/**
|
530 |
+
* Check if object is instance of a class
|
531 |
+
* @param obj obj Instance object
|
532 |
+
* @param obj parent Class to compare with
|
533 |
+
* @return bool TRUE if object is instance of class
|
534 |
+
*/
|
535 |
+
is_instance: function(obj, parent) {
|
536 |
+
if ( !this.is_func(parent) ) {
|
537 |
+
return false;
|
538 |
+
}
|
539 |
+
return ( this.is_obj(obj) && ( obj instanceof parent ) );
|
540 |
+
},
|
541 |
+
|
542 |
+
/**
|
543 |
+
* Check if object is class
|
544 |
+
* Optionally check if class is sub-class of another class
|
545 |
+
* @param func cls Class to check
|
546 |
+
* @param func parent (optional) parent class
|
547 |
+
* @return bool TRUE if object is valid class (and sub-class if parent is specified)
|
548 |
+
*/
|
549 |
+
is_class: function(cls, parent) {
|
550 |
+
// Validate class
|
551 |
+
var ret = ( this.is_func(cls) && ( 'prototype' in cls ) );
|
552 |
+
// Check parent class
|
553 |
+
if ( ret && this.is_set(parent) ) {
|
554 |
+
ret = this.is_instance(cls.prototype, parent);
|
555 |
+
}
|
556 |
+
return ret;
|
557 |
+
},
|
558 |
+
|
559 |
+
/**
|
560 |
+
* Check if value is a number
|
561 |
+
* @uses is_type()
|
562 |
+
* @param mixed value Value to check
|
563 |
+
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
564 |
+
* @return bool TRUE if value is a valid number
|
565 |
+
*/
|
566 |
+
is_num: function(value, nonempty) {
|
567 |
+
var f = {
|
568 |
+
'nan': ( Number.isNaN ) ? Number.isNaN : isNaN,
|
569 |
+
'finite': ( Number.isFinite ) ? Number.isFinite : isFinite
|
570 |
+
};
|
571 |
+
return ( this.is_type(value, 'number', nonempty) && !f.nan(value) && f.finite(value) );
|
572 |
+
},
|
573 |
+
|
574 |
+
/**
|
575 |
+
* Check if value is a integer
|
576 |
+
* @uses is_type()
|
577 |
+
* @param mixed value Value to check
|
578 |
+
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
579 |
+
* @return bool TRUE if value is a valid integer
|
580 |
+
*/
|
581 |
+
is_int: function(value, nonempty) {
|
582 |
+
return ( this.is_num(value, nonempty) && Math.floor(value) === value );
|
583 |
+
},
|
584 |
+
|
585 |
+
/**
|
586 |
+
* Check if value is scalar (string, number, boolean)
|
587 |
+
* @uses is_type()
|
588 |
+
* @param mixed value Value to check
|
589 |
+
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
|
590 |
+
* @return bool TRUE if value is scalar
|
591 |
+
*/
|
592 |
+
is_scalar: function(value, nonempty) {
|
593 |
+
return ( this.is_num(value, nonempty) || this.is_string(value, nonempty) || this.is_bool(value) );
|
594 |
+
},
|
595 |
+
|
596 |
+
/**
|
597 |
+
* Checks if value is empty
|
598 |
+
* @param mixed value Value to check
|
599 |
+
* @param string type (optional) Data type
|
600 |
+
* @return bool TRUE if value is empty
|
601 |
+
*/
|
602 |
+
is_empty: function(value, type) {
|
603 |
+
var ret = false;
|
604 |
+
// Check Undefined
|
605 |
+
if ( !this.is_set(value) ) {
|
606 |
+
ret = true;
|
607 |
+
} else {
|
608 |
+
// Check standard values
|
609 |
+
var empties = [null, "", false, 0];
|
610 |
+
var x = 0;
|
611 |
+
while ( !ret && x < empties.length ) {
|
612 |
+
ret = ( empties[x] === value );
|
613 |
+
x++;
|
614 |
+
}
|
615 |
+
}
|
616 |
+
|
617 |
+
// Advanced check
|
618 |
+
if ( !ret ) {
|
619 |
+
// Validate type
|
620 |
+
if ( !this.is_set(type) ) {
|
621 |
+
type = $.type(value);
|
622 |
+
}
|
623 |
+
// Type-based check
|
624 |
+
if ( this.is_type(value, type, false) ) {
|
625 |
+
switch ( type ) {
|
626 |
+
case 'string':
|
627 |
+
case 'array':
|
628 |
+
ret = ( value.length === 0 );
|
629 |
+
break;
|
630 |
+
case 'number':
|
631 |
+
ret = ( value == 0 ); // jshint ignore:line
|
632 |
+
break;
|
633 |
+
case 'object':
|
634 |
+
if ( !$.isPlainObject(value) ) {
|
635 |
+
// Custom object. Unable to evaluate emptiness further
|
636 |
+
ret = false;
|
637 |
+
} else {
|
638 |
+
// Evaluate plain object
|
639 |
+
if ( Object.getOwnPropertyNames ) {
|
640 |
+
// Modern browser check
|
641 |
+
ret = ( Object.getOwnPropertyNames(value).length === 0 );
|
642 |
+
} else if ( value.hasOwnProperty ) {
|
643 |
+
// Legacy browser check
|
644 |
+
ret = true;
|
645 |
+
for ( var key in value ) {
|
646 |
+
if ( value.hasOwnProperty(key) ) {
|
647 |
+
ret = false;
|
648 |
+
break;
|
649 |
+
}
|
650 |
+
}
|
651 |
+
}
|
652 |
+
}
|
653 |
+
break;
|
654 |
+
}
|
655 |
+
} else {
|
656 |
+
ret = true;
|
657 |
+
}
|
658 |
+
}
|
659 |
+
return ret;
|
660 |
+
},
|
661 |
+
|
662 |
+
/**
|
663 |
+
* Check if object is a jQuery.Promise instance
|
664 |
+
* Will also match (but not guarantee) jQuery.Deferred instances
|
665 |
+
* @uses is_method()
|
666 |
+
* @param obj obj Object to check
|
667 |
+
* @return bool TRUE if object is Promise/Deferred
|
668 |
+
*/
|
669 |
+
is_promise: function(obj) {
|
670 |
+
return ( this.is_method(obj, ['then', 'done', 'always', 'fail', 'pipe']) );
|
671 |
+
},
|
672 |
+
|
673 |
+
/**
|
674 |
+
* Return formatted string
|
675 |
+
* @param string fmt Format template
|
676 |
+
* @param string val Replacement value (Multiple parameters may be set)
|
677 |
+
* @return string Formatted string
|
678 |
+
*/
|
679 |
+
format: function(fmt, val) {
|
680 |
+
// Validate format
|
681 |
+
if ( !this.is_string(fmt) ) {
|
682 |
+
return '';
|
683 |
+
}
|
684 |
+
var params = [];
|
685 |
+
var ph = '%s';
|
686 |
+
/**
|
687 |
+
* Clean string (remove placeholders)
|
688 |
+
*/
|
689 |
+
var strip = function(txt) {
|
690 |
+
return ( txt.indexOf(ph) !== -1 ) ? txt.replace(ph, '') : txt;
|
691 |
+
};
|
692 |
+
// Stop processing if no replacement values specified or format string contains no placeholders
|
693 |
+
if ( arguments.length < 2 || fmt.indexOf(ph) === -1 ) {
|
694 |
+
return strip(fmt);
|
695 |
+
}
|
696 |
+
// Get replacement values
|
697 |
+
params = Array.prototype.slice.call(arguments, 1);
|
698 |
+
val = null;
|
699 |
+
// Clean parameters
|
700 |
+
for ( var x = 0; x < params.length; x++ ) {
|
701 |
+
if ( !this.is_scalar(params[x], false) ) {
|
702 |
+
params[x] = '';
|
703 |
+
}
|
704 |
+
}
|
705 |
+
|
706 |
+
// Replace all placeholders at once if single parameter set
|
707 |
+
if ( params.length === 1 ) {
|
708 |
+
fmt = fmt.replace(ph, params[0].toString());
|
709 |
+
} else {
|
710 |
+
var idx = 0; // Current replacement index
|
711 |
+
var len = params.length; // Number of replacements
|
712 |
+
var rlen = ph.length; // Placeholder length
|
713 |
+
var pos = 0; // Current placeholder position (in format template)
|
714 |
+
while ( ( pos = fmt.indexOf(ph) ) && pos !== -1 && idx < len ) {
|
715 |
+
// Replace current placeholder with respective parameter
|
716 |
+
fmt = fmt.substr(0, pos) + params[idx].toString() + fmt.substr(pos + rlen);
|
717 |
+
idx++;
|
718 |
+
}
|
719 |
+
// Remove any remaining placeholders
|
720 |
+
fmt = strip(fmt);
|
721 |
+
}
|
722 |
+
return fmt;
|
723 |
+
},
|
724 |
+
|
725 |
+
/**
|
726 |
+
* Checks if key(s) exist in an object
|
727 |
+
* @param object obj Object to check
|
728 |
+
* @param string|array key Key(s) to check for in object
|
729 |
+
* @param bool all (optional) All keys must exist in object? (Default: TRUE)
|
730 |
+
* @return bool TRUE if key(s) exist in object
|
731 |
+
*/
|
732 |
+
in_obj: function(obj, key, all) {
|
733 |
+
// Validate
|
734 |
+
if ( !this.is_bool(all) ) {
|
735 |
+
all = true;
|
736 |
+
}
|
737 |
+
if ( this.is_string(key) ) {
|
738 |
+
key = [key];
|
739 |
+
}
|
740 |
+
// Check for keys
|
741 |
+
var ret = false;
|
742 |
+
if ( this.is_obj(obj) && this.is_array(key) ) {
|
743 |
+
var val;
|
744 |
+
for ( var x = 0; x < key.length; x++ ) {
|
745 |
+
val = key[x];
|
746 |
+
ret = ( this.is_string(val) && ( val in obj ) ) ? true : false;
|
747 |
+
// Stop processing if conditions have been met
|
748 |
+
if ( ( !all && ret ) || ( all && !ret ) ) {
|
749 |
+
break;
|
750 |
+
}
|
751 |
+
}
|
752 |
+
}
|
753 |
+
return ret;
|
754 |
+
},
|
755 |
+
|
756 |
+
/**
|
757 |
+
* Retrieve an object's keys
|
758 |
+
* @param obj Object to parse
|
759 |
+
* @return array List of object's keys
|
760 |
+
*/
|
761 |
+
obj_keys: function(obj) {
|
762 |
+
var keys = [];
|
763 |
+
// Validation
|
764 |
+
if ( !this.is_obj(obj) ) {
|
765 |
+
return keys;
|
766 |
+
}
|
767 |
+
if ( Object.keys ) {
|
768 |
+
keys = Object.keys(obj);
|
769 |
+
} else {
|
770 |
+
var prop;
|
771 |
+
for ( prop in obj ) {
|
772 |
+
if ( obj.hasOwnProperty(prop) ) {
|
773 |
+
keys.push(prop);
|
774 |
+
}
|
775 |
+
}
|
776 |
+
}
|
777 |
+
return keys;
|
778 |
+
},
|
779 |
+
|
780 |
+
/**
|
781 |
+
* Find common elements of 2 or more arrays
|
782 |
+
* @param array arr1 First array
|
783 |
+
* @param array arr2 Second array (additional arrays can be passed as well)
|
784 |
+
* @return array Elements common to all
|
785 |
+
*/
|
786 |
+
arr_intersect: function(arr1, arr2) {
|
787 |
+
var ret = [];
|
788 |
+
// Get arrays
|
789 |
+
var params = Array.prototype.slice.call(arguments);
|
790 |
+
// Clean arrays
|
791 |
+
var arrs = [];
|
792 |
+
var x;
|
793 |
+
for ( x = 0; x < params.length; x++ ) {
|
794 |
+
if ( this.is_array(params[x], false) ) {
|
795 |
+
arrs.push(params[x]);
|
796 |
+
}
|
797 |
+
}
|
798 |
+
// Stop processing if no valid arrays to compare
|
799 |
+
if ( arrs.length < 2 ) {
|
800 |
+
return ret;
|
801 |
+
}
|
802 |
+
params = arr1 = arr2 = null;
|
803 |
+
// Find common elements in arrays
|
804 |
+
var base = arrs.shift();
|
805 |
+
var add;
|
806 |
+
var sub;
|
807 |
+
for ( x = 0; x < base.length; x++ ) {
|
808 |
+
add = true;
|
809 |
+
// Check other arrays for element match
|
810 |
+
for ( sub = 0; sub < arrs.length; sub++ ) {
|
811 |
+
if ( arrs[sub].indexOf(base[x]) === -1 ) {
|
812 |
+
add = false;
|
813 |
+
break;
|
814 |
+
}
|
815 |
+
}
|
816 |
+
if ( add ) {
|
817 |
+
ret.push(base[x]);
|
818 |
+
}
|
819 |
+
}
|
820 |
+
// Return intersection results
|
821 |
+
return ret;
|
822 |
+
},
|
823 |
+
|
824 |
+
/**
|
825 |
+
* Generates a GUID string.
|
826 |
+
* @returns string The generated GUID.
|
827 |
+
* @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
|
828 |
+
* @author Slavik Meltser (slavik@meltser.info).
|
829 |
+
* @link http://slavik.meltser.info/?p=142
|
830 |
+
*/
|
831 |
+
guid: function() {
|
832 |
+
function _p8(s) {
|
833 |
+
var p = (Math.random().toString(16)+"000000000").substr(2,8);
|
834 |
+
return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
|
835 |
+
}
|
836 |
+
return _p8() + _p8(true) + _p8(true) + _p8();
|
837 |
+
},
|
838 |
+
|
839 |
+
/**
|
840 |
+
* Parse URI
|
841 |
+
* @param string uri URI to parse
|
842 |
+
* @return obj URI components (DOM anchor element)
|
843 |
+
*/
|
844 |
+
parse_uri: function(uri) {
|
845 |
+
return $('<a href="' + uri + '"/>').get(0);
|
846 |
+
},
|
847 |
+
/**
|
848 |
+
* Parse URI query string
|
849 |
+
* @param string uri URI with query string to parse
|
850 |
+
* @return obj Query variables and values (empty if no query string)
|
851 |
+
*/
|
852 |
+
parse_query: function(uri) {
|
853 |
+
var delim = {
|
854 |
+
'vars': '&',
|
855 |
+
'val': '='
|
856 |
+
};
|
857 |
+
var query = {
|
858 |
+
'raw': [],
|
859 |
+
'parsed': {},
|
860 |
+
'string': ''
|
861 |
+
};
|
862 |
+
uri = this.parse_uri(uri);
|
863 |
+
if ( 0 === uri.search.indexOf('?') ) {
|
864 |
+
// Extract query string
|
865 |
+
query.raw = uri.search.substr(1).split(delim.vars);
|
866 |
+
var i, temp, key, val;
|
867 |
+
// Build query object
|
868 |
+
for ( i = 0; i < query.raw.length; i++ ) {
|
869 |
+
// Split var and value
|
870 |
+
temp = query.raw[i].split(delim.val);
|
871 |
+
key = temp.shift();
|
872 |
+
val = ( temp.length > 0 ) ? temp.join(delim.val) : null;
|
873 |
+
query.parsed[key] = val;
|
874 |
+
}
|
875 |
+
}
|
876 |
+
return query.parsed;
|
877 |
+
},
|
878 |
+
/**
|
879 |
+
* Build query string from object
|
880 |
+
* @param obj query Query data
|
881 |
+
* @return string Query data formatted as HTTP query string
|
882 |
+
*/
|
883 |
+
build_query: function(query) {
|
884 |
+
var q = [];
|
885 |
+
var delim = {
|
886 |
+
'vars': '&',
|
887 |
+
'val': '='
|
888 |
+
};
|
889 |
+
var val;
|
890 |
+
for ( var key in query ) {
|
891 |
+
val = ( null !== query[key] ) ? delim.val + query[key] : '';
|
892 |
+
q.push(key + val);
|
893 |
+
}
|
894 |
+
return q.join(delim.vars);
|
895 |
+
}
|
896 |
+
};
|
897 |
+
|
898 |
+
// Attach Utilities
|
899 |
+
Base.attach('util', Utilities, true);
|
900 |
+
|
901 |
+
/**
|
902 |
+
* SLB Base Class
|
903 |
+
*/
|
904 |
+
var SLB_Base = Class.extend(Base);
|
905 |
+
|
906 |
+
/**
|
907 |
+
* Core
|
908 |
+
*/
|
909 |
+
var Core = {
|
910 |
+
/* Properties */
|
911 |
+
|
912 |
+
base: true,
|
913 |
+
context: [],
|
914 |
+
|
915 |
+
/**
|
916 |
+
* New object initializer
|
917 |
+
* @var obj
|
918 |
+
*/
|
919 |
+
Class: SLB_Base,
|
920 |
+
|
921 |
+
/* Methods */
|
922 |
+
|
923 |
+
/**
|
924 |
+
* Init
|
925 |
+
* Set variables, DOM, etc.
|
926 |
+
*/
|
927 |
+
_init: function() {
|
928 |
+
this._super();
|
929 |
+
$('html').addClass(this.util.get_prefix());
|
930 |
+
}
|
931 |
+
};
|
932 |
+
var SLB_Core = SLB_Base.extend(Core);
|
933 |
+
window.SLB = new SLB_Core();
|
934 |
})(jQuery);}
|
client/js/dev/lib.view.js
CHANGED
@@ -1,4741 +1,4741 @@
|
|
1 |
-
/**
|
2 |
-
* View (Lightbox) functionality
|
3 |
-
* @package Simple Lightbox
|
4 |
-
* @subpackage View
|
5 |
-
* @author Archetyped
|
6 |
-
*/
|
7 |
-
/* global SLB */
|
8 |
-
if ( !!window.SLB && !!SLB.attach ) { (function ($) {
|
9 |
-
|
10 |
-
/*-** Controller **-*/
|
11 |
-
|
12 |
-
var View = {
|
13 |
-
|
14 |
-
/* Properties */
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Media item properties
|
18 |
-
* > Item key: Link URI
|
19 |
-
* > Base properties
|
20 |
-
* > id: WP Attachment ID
|
21 |
-
* > source: Source URI
|
22 |
-
* > title: Media title (generally WP attachment title)
|
23 |
-
* > desc: Media description (generally WP Attachment content)
|
24 |
-
* > type: Asset type (attachment, image, etc.)
|
25 |
-
*/
|
26 |
-
assets: {},
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Component types that can have default instances
|
30 |
-
* @var array
|
31 |
-
*/
|
32 |
-
component_defaults: [],
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Collection of jQuery.Deferred instances added during loading routine
|
36 |
-
* @var array
|
37 |
-
*/
|
38 |
-
loading: [],
|
39 |
-
|
40 |
-
/**
|
41 |
-
* Cache
|
42 |
-
* @var object
|
43 |
-
*/
|
44 |
-
cache: {},
|
45 |
-
|
46 |
-
/**
|
47 |
-
* Temporary component instances
|
48 |
-
* For use by controller when no component instance is available
|
49 |
-
* > Key: Component slug
|
50 |
-
* > Value: Component instance
|
51 |
-
*/
|
52 |
-
component_temps: {},
|
53 |
-
|
54 |
-
/* Options */
|
55 |
-
options: {},
|
56 |
-
|
57 |
-
/* Methods */
|
58 |
-
|
59 |
-
/* Init */
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Instance initialization
|
63 |
-
*/
|
64 |
-
_init: function() {
|
65 |
-
this._super();
|
66 |
-
// Component References
|
67 |
-
this.init_refs();
|
68 |
-
// Components
|
69 |
-
this.init_components();
|
70 |
-
},
|
71 |
-
|
72 |
-
/**
|
73 |
-
* Update component references in component definitions
|
74 |
-
*/
|
75 |
-
init_refs: function() {
|
76 |
-
var r;
|
77 |
-
var ref;
|
78 |
-
var prop;
|
79 |
-
for ( prop in this ) {
|
80 |
-
prop = this[prop];
|
81 |
-
// Process only components
|
82 |
-
if ( !this.is_component(prop) ) {
|
83 |
-
continue;
|
84 |
-
}
|
85 |
-
// Update component references
|
86 |
-
if ( !this.util.is_empty(prop.prototype._refs) ) {
|
87 |
-
for ( r in prop.prototype._refs ) {
|
88 |
-
ref = prop.prototype._refs[r];
|
89 |
-
if ( this.util.is_string(ref) && ref in this ) {
|
90 |
-
ref = prop.prototype._refs[r] = this[ref];
|
91 |
-
}
|
92 |
-
if ( !this.util.is_class(ref) ) {
|
93 |
-
delete prop.prototype_refs[r];
|
94 |
-
}
|
95 |
-
}
|
96 |
-
}
|
97 |
-
}
|
98 |
-
},
|
99 |
-
|
100 |
-
/**
|
101 |
-
* Initialize Components
|
102 |
-
*/
|
103 |
-
init_components: function() {
|
104 |
-
this.component_defaults = [
|
105 |
-
this.Viewer
|
106 |
-
];
|
107 |
-
},
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Client Initialization
|
111 |
-
* @param obj options Global options
|
112 |
-
*/
|
113 |
-
init: function(options) {
|
114 |
-
var t = this;
|
115 |
-
// Defer initialization until all components loaded
|
116 |
-
$.when.apply($, this.loading).always(function() {
|
117 |
-
// Set options
|
118 |
-
$.extend(true, t.options, options);
|
119 |
-
|
120 |
-
/* Event handlers */
|
121 |
-
|
122 |
-
// History
|
123 |
-
$(window).on('popstate', function(e) {
|
124 |
-
var state = e.originalEvent.state;
|
125 |
-
if ( t.util.in_obj(state, ['item', 'viewer']) ) {
|
126 |
-
var v = t.get_viewer(state.viewer);
|
127 |
-
v.history_handle(e);
|
128 |
-
return e.preventDefault();
|
129 |
-
}
|
130 |
-
});
|
131 |
-
|
132 |
-
/* Set defaults */
|
133 |
-
|
134 |
-
// Items
|
135 |
-
t.init_items();
|
136 |
-
});
|
137 |
-
},
|
138 |
-
|
139 |
-
/* Components */
|
140 |
-
|
141 |
-
/**
|
142 |
-
* Check if default component instance can be created
|
143 |
-
* @uses View.component_defaults
|
144 |
-
* @param func type Component type to check
|
145 |
-
* @return bool TRUE if default component instance creation is allowed
|
146 |
-
*/
|
147 |
-
can_make_default_component: function(type) {
|
148 |
-
return ( -1 !== $.inArray(type, this.component_defaults) );
|
149 |
-
},
|
150 |
-
|
151 |
-
/**
|
152 |
-
* Check if object is valid component class
|
153 |
-
* @param func comp Component to check
|
154 |
-
* @return bool TRUE if object is valid component class
|
155 |
-
*/
|
156 |
-
is_component: function(comp) {
|
157 |
-
return ( this.util.is_class(comp, this.Component) );
|
158 |
-
},
|
159 |
-
|
160 |
-
/**
|
161 |
-
* Retrieve collection of components of specified type
|
162 |
-
* @param func type Component type
|
163 |
-
* @return object Component collection (Default: Empty object)
|
164 |
-
*/
|
165 |
-
get_components: function(type) {
|
166 |
-
var ret = {};
|
167 |
-
if ( this.is_component(type) ) {
|
168 |
-
// Determine collection based on component slug
|
169 |
-
var coll = type.prototype._slug + 's';
|
170 |
-
// Create default collection
|
171 |
-
if ( ! ( coll in this.cache ) ) {
|
172 |
-
this.cache[coll] = {};
|
173 |
-
}
|
174 |
-
ret = this.cache[coll];
|
175 |
-
}
|
176 |
-
return ret;
|
177 |
-
},
|
178 |
-
|
179 |
-
/**
|
180 |
-
* Retrieve component from specific collection
|
181 |
-
* @param function type Component type
|
182 |
-
* @param string id Component ID
|
183 |
-
* @return object|null Component reference (NULL if invalid)
|
184 |
-
*/
|
185 |
-
get_component: function(type, id) {
|
186 |
-
var ret = null;
|
187 |
-
// Validate parameters
|
188 |
-
if ( !this.util.is_func(type) ) {
|
189 |
-
return ret;
|
190 |
-
}
|
191 |
-
// Sanitize id
|
192 |
-
if ( !this.util.is_string(id) ) {
|
193 |
-
id = null;
|
194 |
-
}
|
195 |
-
|
196 |
-
// Get component from collection
|
197 |
-
var coll = this.get_components(type);
|
198 |
-
if ( this.util.is_obj(coll) ) {
|
199 |
-
var tid = ( this.util.is_string(id) ) ? id : this.util.add_prefix('default');
|
200 |
-
if ( tid in coll ) {
|
201 |
-
ret = coll[tid];
|
202 |
-
}
|
203 |
-
}
|
204 |
-
|
205 |
-
// Default: Create default component
|
206 |
-
if ( this.util.is_empty(ret) ) {
|
207 |
-
if ( this.util.is_string(id) || this.can_make_default_component(type) ) {
|
208 |
-
ret = this.add_component(type, id);
|
209 |
-
}
|
210 |
-
}
|
211 |
-
// Return component
|
212 |
-
return ret;
|
213 |
-
},
|
214 |
-
|
215 |
-
/**
|
216 |
-
* Create new component instance and save to appropriate collection
|
217 |
-
* @param function type Component type to create
|
218 |
-
* @param string id ID of component
|
219 |
-
* @param object options Component initialization options (Default options used if default component is allowed)
|
220 |
-
* @return object|null New component (NULL if invalid)
|
221 |
-
*/
|
222 |
-
add_component: function(type, id, options) {
|
223 |
-
// Validate type
|
224 |
-
if ( !this.util.is_func(type) ) {
|
225 |
-
return false;
|
226 |
-
}
|
227 |
-
// Validate request
|
228 |
-
if ( this.util.is_empty(id) && !this.can_make_default_component(type) ) {
|
229 |
-
return false;
|
230 |
-
}
|
231 |
-
// Defaults
|
232 |
-
var ret = null;
|
233 |
-
if ( this.util.is_empty(id) ) {
|
234 |
-
id = this.util.add_prefix('default');
|
235 |
-
}
|
236 |
-
if ( !this.util.is_obj(options) ) {
|
237 |
-
options = {};
|
238 |
-
}
|
239 |
-
// Check if specialized method exists for component type
|
240 |
-
var m = ( 'component' !== type.prototype._slug ) ? 'add_' + type.prototype._slug : null;
|
241 |
-
if ( !this.util.is_empty(m) && ( m in this ) && this.util.is_func(this[m]) ) {
|
242 |
-
ret = this[m](id, options);
|
243 |
-
}
|
244 |
-
// Default process
|
245 |
-
else {
|
246 |
-
ret = new type(id, options);
|
247 |
-
}
|
248 |
-
|
249 |
-
// Add new component to collection
|
250 |
-
if ( this.util.is_type(ret, type) ) {
|
251 |
-
// Get collection
|
252 |
-
var coll = this.get_components(type);
|
253 |
-
// Add to collection
|
254 |
-
switch ( $.type(coll) ) {
|
255 |
-
case 'object' :
|
256 |
-
coll[id] = ret;
|
257 |
-
break;
|
258 |
-
case 'array' :
|
259 |
-
coll.push(ret);
|
260 |
-
break;
|
261 |
-
}
|
262 |
-
} else {
|
263 |
-
ret = null;
|
264 |
-
}
|
265 |
-
// Return new component
|
266 |
-
return ret;
|
267 |
-
},
|
268 |
-
|
269 |
-
/**
|
270 |
-
* Create new temporary component instance
|
271 |
-
* @param function type Component type
|
272 |
-
* @return New temporary instance
|
273 |
-
*/
|
274 |
-
add_component_temp: function(type) {
|
275 |
-
var ret = null;
|
276 |
-
if ( this.is_component(type) ) {
|
277 |
-
// Create new instance
|
278 |
-
ret = new type('');
|
279 |
-
// Save to collection
|
280 |
-
this.component_temps[ret._slug] = ret;
|
281 |
-
}
|
282 |
-
return ret;
|
283 |
-
},
|
284 |
-
|
285 |
-
/**
|
286 |
-
* Retrieve temporary component instance
|
287 |
-
* Creates new temp component instance for type if not previously created
|
288 |
-
* @param function type Component type to retrieve temp instance for
|
289 |
-
* @return obj Temporary component instance
|
290 |
-
*/
|
291 |
-
get_component_temp: function(type) {
|
292 |
-
return ( this.has_component_temp(type) ) ? this.component_temps[type.prototype._slug] : this.add_component_temp(type);
|
293 |
-
},
|
294 |
-
|
295 |
-
/**
|
296 |
-
* Check if temporary component instance exists
|
297 |
-
* @param function type Component type to check for
|
298 |
-
* @return bool TRUE if temp instance exists, FALSE otherwise
|
299 |
-
*/
|
300 |
-
has_component_temp: function(type) {
|
301 |
-
return ( this.is_component(type) && ( type.prototype._slug in this.component_temps ) ) ? true : false;
|
302 |
-
},
|
303 |
-
|
304 |
-
/* Properties */
|
305 |
-
|
306 |
-
/**
|
307 |
-
* Retrieve specified options
|
308 |
-
* @param array opts Array of option names
|
309 |
-
* @return object Specified options (Default: empty object)
|
310 |
-
*/
|
311 |
-
get_options: function(opts) {
|
312 |
-
var ret = {};
|
313 |
-
// Validate
|
314 |
-
if ( this.util.is_string(opts) ) {
|
315 |
-
opts = [opts];
|
316 |
-
}
|
317 |
-
if ( !this.util.is_array(opts) ) {
|
318 |
-
return ret;
|
319 |
-
}
|
320 |
-
// Get specified options
|
321 |
-
for ( var x = 0; x < opts.length; x++ ) {
|
322 |
-
// Skip if option not set
|
323 |
-
if ( !( opts[x] in this.options ) ) {
|
324 |
-
continue;
|
325 |
-
}
|
326 |
-
ret[ opts[x] ] = this.options[ opts[x] ];
|
327 |
-
}
|
328 |
-
return ret;
|
329 |
-
},
|
330 |
-
|
331 |
-
/**
|
332 |
-
* Retrieve option
|
333 |
-
* @uses View.options
|
334 |
-
* @param string opt Option to retrieve
|
335 |
-
* @param mixed def (optional) Default value if option does not exist (Default: NULL)
|
336 |
-
* @return mixed Option value
|
337 |
-
*/
|
338 |
-
get_option: function(opt, def) {
|
339 |
-
var ret = this.get_options(opt);
|
340 |
-
if ( this.util.is_obj(ret) && ( opt in ret ) ) {
|
341 |
-
ret = ret[opt];
|
342 |
-
} else {
|
343 |
-
ret = ( this.util.is_set(def) ) ? def : null;
|
344 |
-
}
|
345 |
-
return ret;
|
346 |
-
},
|
347 |
-
|
348 |
-
/* Viewers */
|
349 |
-
|
350 |
-
/**
|
351 |
-
* Add viewer instance to collection
|
352 |
-
* @param string id Viewer ID
|
353 |
-
* @param obj options Viewer options
|
354 |
-
* @return Viewer New viewer instance
|
355 |
-
*/
|
356 |
-
add_viewer: function(id, options) {
|
357 |
-
// Create viewer
|
358 |
-
var v = new this.Viewer(id, options);
|
359 |
-
// Save viewer
|
360 |
-
this.get_viewers()[v.get_id()] = v;
|
361 |
-
// Return viewer
|
362 |
-
return v;
|
363 |
-
},
|
364 |
-
|
365 |
-
/**
|
366 |
-
* Retrieve all viewer instances
|
367 |
-
* @return obj Viewer instances
|
368 |
-
*/
|
369 |
-
get_viewers: function() {
|
370 |
-
return this.get_components(this.Viewer);
|
371 |
-
},
|
372 |
-
|
373 |
-
/**
|
374 |
-
* Check if viewer exists
|
375 |
-
* @param string v Viewer ID
|
376 |
-
* @return bool TRUE if viewer exists, FALSE otherwise
|
377 |
-
*/
|
378 |
-
has_viewer: function(v) {
|
379 |
-
return ( this.util.is_string(v) && v in this.get_viewers() ) ? true : false;
|
380 |
-
},
|
381 |
-
|
382 |
-
/**
|
383 |
-
* Retrieve Viewer instance
|
384 |
-
* Default viewer retrieved if specified viewer does not exist
|
385 |
-
* > Default viewer created if necessary
|
386 |
-
* @param string v Viewer ID to retrieve
|
387 |
-
* @return Viewer Viewer instance
|
388 |
-
*/
|
389 |
-
get_viewer: function(v) {
|
390 |
-
// Retrieve default viewer if specified viewer not set
|
391 |
-
if ( !this.has_viewer(v) ) {
|
392 |
-
v = this.util.add_prefix('default');
|
393 |
-
// Create default viewer if necessary
|
394 |
-
if ( !this.has_viewer(v) ) {
|
395 |
-
v = this.add_viewer(v);
|
396 |
-
v = v.get_id();
|
397 |
-
}
|
398 |
-
}
|
399 |
-
return this.get_viewers()[v];
|
400 |
-
},
|
401 |
-
|
402 |
-
/* Items */
|
403 |
-
|
404 |
-
/**
|
405 |
-
* Set event handlers
|
406 |
-
*/
|
407 |
-
init_items: function() {
|
408 |
-
// Define handler
|
409 |
-
var t = this;
|
410 |
-
var handler = function() {
|
411 |
-
var ret = t.show_item(this);
|
412 |
-
if ( !t.util.is_bool(ret) ) {
|
413 |
-
ret = true;
|
414 |
-
}
|
415 |
-
return !ret;
|
416 |
-
};
|
417 |
-
|
418 |
-
// Get activated links
|
419 |
-
var sel = this.util.format('a[href][%s="%s"]', this.util.get_attribute('active'), 1);
|
420 |
-
// Add event handler
|
421 |
-
$(document).on('click', sel, null, handler);
|
422 |
-
},
|
423 |
-
|
424 |
-
/**
|
425 |
-
* Retrieve cached items
|
426 |
-
* @return obj Items collection
|
427 |
-
*/
|
428 |
-
get_items: function() {
|
429 |
-
return this.get_components(this.Content_Item);
|
430 |
-
},
|
431 |
-
|
432 |
-
/**
|
433 |
-
* Retrieve specific Content_Item instance
|
434 |
-
* @param mixed Item reference
|
435 |
-
* > Content_Item: Item instance (returned immediately)
|
436 |
-
* > DOM element: DOM element to get item for
|
437 |
-
* > int: Index of cached item
|
438 |
-
* @return Content_Item Item instance for DOM node
|
439 |
-
*/
|
440 |
-
get_item: function(ref) {
|
441 |
-
// Evaluate reference type
|
442 |
-
|
443 |
-
// Content Item instance
|
444 |
-
if ( this.util.is_type(ref, this.Content_Item) ) {
|
445 |
-
return ref;
|
446 |
-
}
|
447 |
-
// Retrieve item instance
|
448 |
-
var item = null;
|
449 |
-
|
450 |
-
// DOM element
|
451 |
-
if ( this.util.in_obj(ref, 'nodeType') ) {
|
452 |
-
// Check if item instance attached to element
|
453 |
-
var key = this.get_component_temp(this.Content_Item).get_data_key();
|
454 |
-
item = $(ref).data(key);
|
455 |
-
}
|
456 |
-
// Cached item (index)
|
457 |
-
else if ( this.util.is_string(ref, false) ) {
|
458 |
-
var items = this.get_items();
|
459 |
-
if ( ref in items ) {
|
460 |
-
item = items[ref];
|
461 |
-
}
|
462 |
-
}
|
463 |
-
// Create default item instance
|
464 |
-
if ( !this.util.is_instance(item, this.Content_Item) ) {
|
465 |
-
item = this.add_item(ref);
|
466 |
-
}
|
467 |
-
return item;
|
468 |
-
},
|
469 |
-
|
470 |
-
/**
|
471 |
-
* Create new item instance
|
472 |
-
* @param obj el DOM element representing item
|
473 |
-
* @return Content_Item New item instance
|
474 |
-
*/
|
475 |
-
add_item: function(el) {
|
476 |
-
return ( new this.Content_Item(el) );
|
477 |
-
},
|
478 |
-
|
479 |
-
/**
|
480 |
-
* Display item in viewer
|
481 |
-
* @param obj el DOM element representing item
|
482 |
-
* @return bool Display result (TRUE if item displayed without issues)
|
483 |
-
*/
|
484 |
-
show_item: function(el) {
|
485 |
-
return this.get_item(el).show();
|
486 |
-
},
|
487 |
-
|
488 |
-
/**
|
489 |
-
* Cache item instance
|
490 |
-
* @uses View.get_items() to retrieve item cache
|
491 |
-
* @param Content_Item item Item to cache
|
492 |
-
* @return Content_item Item instance
|
493 |
-
*/
|
494 |
-
save_item: function(item) {
|
495 |
-
if ( !this.util.is_instance(item, this.Content_Item) ) {
|
496 |
-
return item;
|
497 |
-
}
|
498 |
-
// Save item
|
499 |
-
this.get_items()[item.get_id()] = item;
|
500 |
-
// Return item instance
|
501 |
-
return item;
|
502 |
-
},
|
503 |
-
|
504 |
-
/* Content Handler */
|
505 |
-
|
506 |
-
/**
|
507 |
-
* Retrieve content handlers
|
508 |
-
* @return object Content handlers
|
509 |
-
*/
|
510 |
-
get_content_handlers: function() {
|
511 |
-
return this.get_components(this.Content_Handler);
|
512 |
-
},
|
513 |
-
|
514 |
-
/**
|
515 |
-
* Find matching content handler for item
|
516 |
-
* @param Content_Item|string item Item to find handler for (or ID of Handler)
|
517 |
-
* @return Content_Handler|null Matching content handler (NULL if no matching handler found)
|
518 |
-
*/
|
519 |
-
get_content_handler: function(item) {
|
520 |
-
// Determine handler to retrieve
|
521 |
-
var type = ( this.util.is_instance(item, this.Content_Item) ) ? item.get_attribute('type', '') : item.toString();
|
522 |
-
// Retrieve handler
|
523 |
-
var types = this.get_content_handlers();
|
524 |
-
return ( type in types ) ? types[type] : null;
|
525 |
-
},
|
526 |
-
|
527 |
-
/**
|
528 |
-
* Add/Update Content Handler
|
529 |
-
* @param string id Handler ID
|
530 |
-
* @param obj attr Handler attributes
|
531 |
-
* @return obj|null Handler instance (NULL on failure)
|
532 |
-
*/
|
533 |
-
extend_content_handler: function(id, attr) {
|
534 |
-
var hdl = null;
|
535 |
-
if ( !this.util.is_string(id) || !this.util.is_obj(attr) ) {
|
536 |
-
return hdl;
|
537 |
-
}
|
538 |
-
hdl = this.get_content_handler(id);
|
539 |
-
// Add new content handler
|
540 |
-
if ( null === hdl ) {
|
541 |
-
var hdls = this.get_content_handlers();
|
542 |
-
hdls[id] = hdl = new this.Content_Handler(id, attr);
|
543 |
-
}
|
544 |
-
// Update existing handler
|
545 |
-
else {
|
546 |
-
hdl.set_attributes(attr);
|
547 |
-
}
|
548 |
-
// Load styles
|
549 |
-
if ( this.util.in_obj(attr, 'styles') ) {
|
550 |
-
this.load_styles(attr.styles);
|
551 |
-
}
|
552 |
-
return hdl;
|
553 |
-
},
|
554 |
-
|
555 |
-
/* Group */
|
556 |
-
|
557 |
-
/**
|
558 |
-
* Add new group
|
559 |
-
* @param string g Group ID
|
560 |
-
* > If group with same ID already set, new group replaces existing one
|
561 |
-
* @param object attrs (optional) Group attributes
|
562 |
-
* @return Group New group
|
563 |
-
*/
|
564 |
-
add_group: function(g, attrs) {
|
565 |
-
// Create new group
|
566 |
-
g = new this.Group(g, attrs);
|
567 |
-
// Cache group
|
568 |
-
this.get_groups()[g.get_id()] = g;
|
569 |
-
|
570 |
-
return g;
|
571 |
-
},
|
572 |
-
|
573 |
-
/**
|
574 |
-
* Retrieve groups
|
575 |
-
* @uses groups property
|
576 |
-
* @return object Registered groups
|
577 |
-
*/
|
578 |
-
get_groups: function() {
|
579 |
-
return this.get_components(this.Group);
|
580 |
-
},
|
581 |
-
|
582 |
-
/**
|
583 |
-
* Retrieve specified group
|
584 |
-
* New group created if not yet set
|
585 |
-
* @uses View.has_group()
|
586 |
-
* @uses View.add_group()
|
587 |
-
* @uses View.get_groups()
|
588 |
-
* @param string g Group ID
|
589 |
-
* @return Group Group instance
|
590 |
-
*/
|
591 |
-
get_group: function(g) {
|
592 |
-
return ( !this.has_group(g) ) ? this.add_group(g) : this.get_groups()[g];
|
593 |
-
},
|
594 |
-
|
595 |
-
/**
|
596 |
-
* Checks if group is registered
|
597 |
-
* @uses get_groups() to retrieve registered groups
|
598 |
-
* @return bool TRUE if group exists, FALSE otherwise
|
599 |
-
*/
|
600 |
-
has_group: function(g) {
|
601 |
-
return ( this.util.is_string(g) && ( g in this.get_groups() ) );
|
602 |
-
},
|
603 |
-
|
604 |
-
/* Theme */
|
605 |
-
|
606 |
-
/**
|
607 |
-
* Add/Update theme
|
608 |
-
* @param string name Theme name
|
609 |
-
* @param obj attr (optional) Theme options
|
610 |
-
* @return obj|bool Theme model
|
611 |
-
*/
|
612 |
-
extend_theme: function(id, attr) {
|
613 |
-
// Validate
|
614 |
-
if ( !this.util.is_string(id) ) {
|
615 |
-
return false;
|
616 |
-
}
|
617 |
-
var dfr = $.Deferred();
|
618 |
-
this.loading.push(dfr);
|
619 |
-
|
620 |
-
// Get model if it already exists
|
621 |
-
var model = this.get_theme_model(id);
|
622 |
-
|
623 |
-
// Create default attributes for new theme
|
624 |
-
if ( this.util.is_empty(model) ) {
|
625 |
-
// Save default model
|
626 |
-
model = this.save_theme_model( {'parent': null, 'id': id} );
|
627 |
-
}
|
628 |
-
|
629 |
-
// Add custom attributes
|
630 |
-
if ( this.util.is_obj(attr) ) {
|
631 |
-
// Sanitize
|
632 |
-
if ( 'id' in attr ) {
|
633 |
-
delete(attr['id']);
|
634 |
-
}
|
635 |
-
$.extend(model, attr);
|
636 |
-
}
|
637 |
-
|
638 |
-
// Load styles
|
639 |
-
if ( this.util.in_obj(attr, 'styles') ) {
|
640 |
-
this.load_styles(attr.styles);
|
641 |
-
}
|
642 |
-
|
643 |
-
// Link parent model
|
644 |
-
if ( !this.util.is_obj(model.parent) ) {
|
645 |
-
model.parent = this.get_theme_model(model.parent);
|
646 |
-
}
|
647 |
-
|
648 |
-
// Complete loading when all components loaded
|
649 |
-
dfr.resolve();
|
650 |
-
return model;
|
651 |
-
},
|
652 |
-
|
653 |
-
/**
|
654 |
-
* Retrieve theme models
|
655 |
-
* @return obj Theme models
|
656 |
-
*/
|
657 |
-
get_theme_models: function() {
|
658 |
-
// Retrieve matching theme model
|
659 |
-
return this.Theme.prototype._models;
|
660 |
-
},
|
661 |
-
|
662 |
-
/**
|
663 |
-
* Retrieve theme model
|
664 |
-
* @param string id Theme to retrieve
|
665 |
-
* @return obj Theme model (Default: empty object)
|
666 |
-
*/
|
667 |
-
get_theme_model: function(id) {
|
668 |
-
var ms = this.get_theme_models();
|
669 |
-
return ( this.util.in_obj(ms, id) ) ? ms[id] : {};
|
670 |
-
},
|
671 |
-
|
672 |
-
/**
|
673 |
-
* Save theme model
|
674 |
-
* @uses View.get_theme_models() to retrieve Theme model collection
|
675 |
-
* @param obj Theme model to save
|
676 |
-
* @return obj Saved model
|
677 |
-
*/
|
678 |
-
save_theme_model: function(model) {
|
679 |
-
if ( this.util.in_obj(model, 'id') && this.util.is_string(model.id) ) {
|
680 |
-
// Save model
|
681 |
-
this.get_theme_models()[model.id] = model;
|
682 |
-
}
|
683 |
-
return model;
|
684 |
-
},
|
685 |
-
|
686 |
-
/**
|
687 |
-
* Add/Update Template Tag Handler
|
688 |
-
* @param string id Handler ID
|
689 |
-
* @param obj attr Handler attributes
|
690 |
-
* @return obj|bool Handler instance (FALSE on failure)
|
691 |
-
*/
|
692 |
-
extend_template_tag_handler: function(id, attr) {
|
693 |
-
if ( !this.util.is_string(id) || !this.util.is_obj(attr) ) {
|
694 |
-
return false;
|
695 |
-
}
|
696 |
-
var hdl;
|
697 |
-
var hdls = this.get_template_tag_handlers();
|
698 |
-
if ( this.util.in_obj(hdls, id) ) {
|
699 |
-
// Update existing handler
|
700 |
-
hdl = hdls[id];
|
701 |
-
hdl.set_attributes(attr);
|
702 |
-
} else {
|
703 |
-
// Add new content handler
|
704 |
-
hdl = new this.Template_Tag_Handler(id, attr);
|
705 |
-
hdls[hdl.get_id()] = hdl;
|
706 |
-
}
|
707 |
-
// Load styles
|
708 |
-
if ( this.util.in_obj(attr, 'styles') ) {
|
709 |
-
this.load_styles(attr.styles);
|
710 |
-
}
|
711 |
-
// Set hooks
|
712 |
-
if ( this.util.in_obj(attr, '_hooks') ) {
|
713 |
-
attr._hooks.call(hdl);
|
714 |
-
}
|
715 |
-
return hdl;
|
716 |
-
},
|
717 |
-
|
718 |
-
/**
|
719 |
-
* Retrieve Template Tag Handler collection
|
720 |
-
* @return obj Template_Tag_Handler objects
|
721 |
-
*/
|
722 |
-
get_template_tag_handlers: function() {
|
723 |
-
return this.Template_Tag.prototype.handlers;
|
724 |
-
},
|
725 |
-
|
726 |
-
/**
|
727 |
-
* Retrieve template tag handler
|
728 |
-
* @param string id ID of tag handler to retrieve
|
729 |
-
* @return Template_Tag_Handler|null Tag Handler instance (NULL for invalid ID)
|
730 |
-
*/
|
731 |
-
get_template_tag_handler: function(id) {
|
732 |
-
var handlers = this.get_template_tag_handlers();
|
733 |
-
// Retrieve existing handler or return new handler
|
734 |
-
return ( this.util.in_obj(handlers, id) ) ? handlers[id] : null;
|
735 |
-
},
|
736 |
-
|
737 |
-
/**
|
738 |
-
* Load styles
|
739 |
-
* @param array styles Styles to load
|
740 |
-
*/
|
741 |
-
load_styles: function(styles) {
|
742 |
-
if ( this.util.is_array(styles) ) {
|
743 |
-
var out = [];
|
744 |
-
var style;
|
745 |
-
for ( var x = 0; x < styles.length; x++ ) {
|
746 |
-
style = styles[x];
|
747 |
-
if ( !this.util.in_obj(style, 'uri') || !this.util.is_string(style.uri) ) {
|
748 |
-
continue;
|
749 |
-
}
|
750 |
-
out.push('<link rel="stylesheet" type="text/css" href="' + style.uri + '" />');
|
751 |
-
}
|
752 |
-
$('head').append(out.join(''));
|
753 |
-
}
|
754 |
-
}
|
755 |
-
};
|
756 |
-
|
757 |
-
/* Components */
|
758 |
-
var Component = {
|
759 |
-
/*-** Properties **-*/
|
760 |
-
|
761 |
-
/* Internal/Configuration */
|
762 |
-
|
763 |
-
/**
|
764 |
-
* Base name of component type
|
765 |
-
* @var string
|
766 |
-
*/
|
767 |
-
_slug: 'component',
|
768 |
-
|
769 |
-
/**
|
770 |
-
* Component namespace
|
771 |
-
* @var string
|
772 |
-
*/
|
773 |
-
_ns: null,
|
774 |
-
|
775 |
-
/**
|
776 |
-
* Valid component references for current component
|
777 |
-
* @var object
|
778 |
-
* > Key (string): Property name that stores reference
|
779 |
-
* > Value (function): Data type of component
|
780 |
-
*/
|
781 |
-
_refs: {},
|
782 |
-
|
783 |
-
/**
|
784 |
-
* Whether DOM element and component are connected in 1:1 relationship
|
785 |
-
* Some components will be assigned to different DOM elements depending on usage
|
786 |
-
* @var bool
|
787 |
-
*/
|
788 |
-
_reciprocal: false,
|
789 |
-
|
790 |
-
/**
|
791 |
-
* DOM Element tied to component
|
792 |
-
* @var DOM Element
|
793 |
-
*/
|
794 |
-
_dom: null,
|
795 |
-
|
796 |
-
/**
|
797 |
-
* Component attributes
|
798 |
-
* @var object
|
799 |
-
* > Key: Attribute ID
|
800 |
-
* > Value: Attribute value
|
801 |
-
*/
|
802 |
-
_attributes: false,
|
803 |
-
|
804 |
-
/**
|
805 |
-
* Default attributes
|
806 |
-
* @var object
|
807 |
-
*/
|
808 |
-
_attr_default: {},
|
809 |
-
|
810 |
-
/**
|
811 |
-
* Flag indicates whether default attributes have previously been parsed
|
812 |
-
* @var bool
|
813 |
-
*/
|
814 |
-
_attr_default_parsed: false,
|
815 |
-
|
816 |
-
/**
|
817 |
-
* Attributes passed to constructor
|
818 |
-
* @var obj
|
819 |
-
*/
|
820 |
-
_attr_init: null,
|
821 |
-
|
822 |
-
/**
|
823 |
-
* Defines how parent properties should be remapped to component properties
|
824 |
-
* @var object
|
825 |
-
*/
|
826 |
-
_attr_map: {},
|
827 |
-
|
828 |
-
/**
|
829 |
-
* Event handlers
|
830 |
-
* @var object
|
831 |
-
* > Key: string Event type
|
832 |
-
* > Value: array Handlers
|
833 |
-
*/
|
834 |
-
_events: {},
|
835 |
-
|
836 |
-
/**
|
837 |
-
* Status management
|
838 |
-
* @var object
|
839 |
-
* > Key: Status ID
|
840 |
-
* > Value: Status value
|
841 |
-
*/
|
842 |
-
_status: null,
|
843 |
-
|
844 |
-
/**
|
845 |
-
* Component ID
|
846 |
-
* @var string
|
847 |
-
*/
|
848 |
-
_id: '',
|
849 |
-
|
850 |
-
/* Init */
|
851 |
-
|
852 |
-
/**
|
853 |
-
* Constructor
|
854 |
-
* @param string id (optional) Component ID (Default ID will be generated if no valid ID provided)
|
855 |
-
* @param object attributes (optional) Component attributes
|
856 |
-
*/
|
857 |
-
_c: function(id, attributes) {
|
858 |
-
// Set ID
|
859 |
-
this._set_id(id);
|
860 |
-
// Save init attributes
|
861 |
-
if ( this.util.is_obj(attributes) ) {
|
862 |
-
this._attr_init = attributes;
|
863 |
-
}
|
864 |
-
// Call hooks
|
865 |
-
this._hooks();
|
866 |
-
},
|
867 |
-
|
868 |
-
/**
|
869 |
-
* Set Component parent to View module
|
870 |
-
* @uses `_super._set_parent()`
|
871 |
-
*/
|
872 |
-
_set_parent: function() {
|
873 |
-
this._super(View);
|
874 |
-
},
|
875 |
-
|
876 |
-
/**
|
877 |
-
* Register hooks on init
|
878 |
-
* Placeholder method to be overridden by child classes
|
879 |
-
*/
|
880 |
-
_hooks: function() {},
|
881 |
-
|
882 |
-
/* Methods */
|
883 |
-
|
884 |
-
/* Properties */
|
885 |
-
|
886 |
-
/**
|
887 |
-
* Set instance ID
|
888 |
-
* Instance ID can only be set once (will not change ID if valid ID already set)
|
889 |
-
* Generates random GUID if no valid ID provided
|
890 |
-
* @uses Utilities.guid()
|
891 |
-
* @param string id Unique ID
|
892 |
-
* @return string Instance ID
|
893 |
-
*/
|
894 |
-
_set_id: function(id) {
|
895 |
-
// Set ID only once
|
896 |
-
if ( this.util.is_empty(this._id) ) {
|
897 |
-
this._id = ( this.util.is_string(id) ) ? id : this.util.guid();
|
898 |
-
}
|
899 |
-
return this._id;
|
900 |
-
},
|
901 |
-
|
902 |
-
/**
|
903 |
-
* Retrieve instance ID
|
904 |
-
* @uses id as ID base
|
905 |
-
* @uses _slug to add namespace (if necessary)
|
906 |
-
* @param bool ns (optional) Whether or not to namespace ID (Default: FALSE)
|
907 |
-
* @return string Instance ID
|
908 |
-
*/
|
909 |
-
get_id: function(ns) {
|
910 |
-
// Get raw ID
|
911 |
-
var id = this._id;
|
912 |
-
// Namespace ID
|
913 |
-
if ( this.util.is_bool(ns) && ns ) {
|
914 |
-
id = this.add_ns(id);
|
915 |
-
}
|
916 |
-
|
917 |
-
return id;
|
918 |
-
},
|
919 |
-
|
920 |
-
/**
|
921 |
-
* Get namespace
|
922 |
-
* @uses _slug for namespace segment
|
923 |
-
* @uses Util.add_prefix() to prefix slug
|
924 |
-
* @return string Component namespace
|
925 |
-
*/
|
926 |
-
get_ns: function() {
|
927 |
-
if ( null === this._ns ) {
|
928 |
-
this._ns = this.util.add_prefix(this._slug);
|
929 |
-
}
|
930 |
-
return this._ns;
|
931 |
-
},
|
932 |
-
|
933 |
-
/**
|
934 |
-
* Add namespace to value
|
935 |
-
* @param string val Value to namespace
|
936 |
-
* @return string Namespaced value (Empty string if invalid value provided)
|
937 |
-
*/
|
938 |
-
add_ns: function(val) {
|
939 |
-
return ( this.util.is_string(val) ) ? this.get_ns() + '_' + val : '';
|
940 |
-
},
|
941 |
-
|
942 |
-
/**
|
943 |
-
* Retrieve status
|
944 |
-
* @param string id Status to retrieve
|
945 |
-
* @param bool raw (optional) Retrieve raw value (Default: FALSE)
|
946 |
-
* @return mixed Status value (Default: bool)
|
947 |
-
*/
|
948 |
-
get_status: function(id, raw) {
|
949 |
-
var ret = false;
|
950 |
-
if ( this.util.in_obj(this._status, id) ) {
|
951 |
-
ret = ( !!raw ) ? this._status[id] : !!this._status[id];
|
952 |
-
}
|
953 |
-
return ret;
|
954 |
-
},
|
955 |
-
|
956 |
-
/**
|
957 |
-
* Set status
|
958 |
-
* @param string id Status to retrieve
|
959 |
-
* @param mixed val Status value (Default: TRUE)
|
960 |
-
* @return mixed Status value
|
961 |
-
*/
|
962 |
-
set_status: function(id, val) {
|
963 |
-
// Validate ID
|
964 |
-
if ( this.util.is_string(id) ) {
|
965 |
-
// Validate value
|
966 |
-
if ( !this.util.is_set(val) ) {
|
967 |
-
val = true;
|
968 |
-
}
|
969 |
-
// Initialize status collection
|
970 |
-
if ( !this.util.is_obj(this._status, false) ) {
|
971 |
-
this._status = {};
|
972 |
-
}
|
973 |
-
// Set status
|
974 |
-
this._status[id] = val;
|
975 |
-
} else if ( !this.util.is_set(val) ) {
|
976 |
-
val = false;
|
977 |
-
}
|
978 |
-
return val;
|
979 |
-
},
|
980 |
-
|
981 |
-
/**
|
982 |
-
* Get controller object
|
983 |
-
* @uses get_parent() (alias)
|
984 |
-
* @return object Controller object (SLB.View)
|
985 |
-
*/
|
986 |
-
get_controller: function() {
|
987 |
-
return this.get_parent();
|
988 |
-
},
|
989 |
-
|
990 |
-
/* Components */
|
991 |
-
|
992 |
-
/**
|
993 |
-
* Check if reference exists in object
|
994 |
-
* @param string ref Reference ID
|
995 |
-
* @return bool TRUE if reference exists, FALSE otherwise
|
996 |
-
*/
|
997 |
-
has_reference: function(ref) {
|
998 |
-
return ( this.util.is_string(ref) && ( ref in this ) && ( ref in this.get_references() ) ) ? true : false;
|
999 |
-
},
|
1000 |
-
|
1001 |
-
/**
|
1002 |
-
* Retrieve object references
|
1003 |
-
* @uses _refs
|
1004 |
-
* @return obj References object
|
1005 |
-
|
1006 |
-
*/
|
1007 |
-
get_references: function() {
|
1008 |
-
return this._refs;
|
1009 |
-
},
|
1010 |
-
|
1011 |
-
/**
|
1012 |
-
* Retrieve reference data type
|
1013 |
-
* @param string ref Reference ID
|
1014 |
-
* @return function Reference data type (NULL if invalid)
|
1015 |
-
*/
|
1016 |
-
get_reference: function(ref) {
|
1017 |
-
return ( this.has_reference(ref) ) ? this._refs[ref] : null;
|
1018 |
-
},
|
1019 |
-
|
1020 |
-
/**
|
1021 |
-
* Retrieve component reference from current object
|
1022 |
-
* > Procedure:
|
1023 |
-
* > Check if top-level property already set
|
1024 |
-
* > Check attributes
|
1025 |
-
* > Check parent object (controller)
|
1026 |
-
* @param string cname Component name
|
1027 |
-
* @param object options (optional) Request options
|
1028 |
-
* > check_attr bool Whether or not to check instance attributes for component (Default: TRUE)
|
1029 |
-
* > get_default bool Whether or not to retrieve default object from controller if none exists in current instance (Default: FALSE)
|
1030 |
-
* @return object|null Component reference (NULL if no component found)
|
1031 |
-
*/
|
1032 |
-
get_component: function(cname, options) {
|
1033 |
-
var c = null;
|
1034 |
-
// Validate request
|
1035 |
-
if ( !this.has_reference(cname) ) {
|
1036 |
-
return c;
|
1037 |
-
}
|
1038 |
-
|
1039 |
-
// Initialize options
|
1040 |
-
var opt_defaults = {
|
1041 |
-
check_attr: true,
|
1042 |
-
get_default: false
|
1043 |
-
};
|
1044 |
-
options = $.extend({}, opt_defaults, options);
|
1045 |
-
|
1046 |
-
// Get component type
|
1047 |
-
var ctype = this.get_reference(cname);
|
1048 |
-
|
1049 |
-
// Phase 1: Check if component reference previously set
|
1050 |
-
if ( this.util.is_type(this[cname], ctype) ) {
|
1051 |
-
return this[cname];
|
1052 |
-
}
|
1053 |
-
// If reference not set, iterate through component hierarchy until reference is found
|
1054 |
-
c = this[cname] = null;
|
1055 |
-
|
1056 |
-
// Phase 2: Check attributes
|
1057 |
-
if ( options.check_attr ) {
|
1058 |
-
c = this.get_attribute(cname);
|
1059 |
-
// Save object-specific component reference
|
1060 |
-
if ( !this.util.is_empty(c) ) {
|
1061 |
-
c = this.set_component(cname, c);
|
1062 |
-
}
|
1063 |
-
}
|
1064 |
-
|
1065 |
-
// Phase 3: From controller (optional)
|
1066 |
-
if ( this.util.is_empty(c) && options.get_default ) {
|
1067 |
-
c = this.get_controller().get_component(ctype);
|
1068 |
-
}
|
1069 |
-
return c;
|
1070 |
-
},
|
1071 |
-
|
1072 |
-
/**
|
1073 |
-
* Sets component reference on current object
|
1074 |
-
* > Component property reset (set to NULL) if invalid component supplied
|
1075 |
-
* @param string name Name of property to set component on object
|
1076 |
-
* @param string|object ref Component or Component ID (to be retrieved from controller)
|
1077 |
-
* @param function validate (optional) Additional validation to be performed (Must return bool: TRUE (Valid)/FALSE (Invalid))
|
1078 |
-
* @return object Component (NULL if invalid)
|
1079 |
-
*/
|
1080 |
-
set_component: function(name, ref, validate) {
|
1081 |
-
var invalid = null;
|
1082 |
-
// Make sure component property exists
|
1083 |
-
if ( !this.has_reference(name) ) {
|
1084 |
-
return invalid;
|
1085 |
-
}
|
1086 |
-
|
1087 |
-
// Validate reference
|
1088 |
-
if ( this.util.is_empty(ref) ) {
|
1089 |
-
ref = invalid;
|
1090 |
-
} else {
|
1091 |
-
var ctype = this.get_reference(name);
|
1092 |
-
|
1093 |
-
// Get component from controller when ID supplied
|
1094 |
-
if ( this.util.is_string(ref, false) ) {
|
1095 |
-
ref = this.get_controller().get_component(ctype, ref);
|
1096 |
-
}
|
1097 |
-
|
1098 |
-
// Validation callback
|
1099 |
-
if ( !this.util.is_type(ref, ctype) || ( this.util.is_func(validate) && !validate.call(this, ref) ) ) {
|
1100 |
-
ref = invalid;
|
1101 |
-
}
|
1102 |
-
}
|
1103 |
-
|
1104 |
-
// Set (or clear) component reference
|
1105 |
-
this[name] = ref;
|
1106 |
-
// Return value for confirmation
|
1107 |
-
return this[name];
|
1108 |
-
},
|
1109 |
-
|
1110 |
-
|
1111 |
-
/**
|
1112 |
-
* Clear component reference
|
1113 |
-
* @uses set_component() to handle component manipulation
|
1114 |
-
* @param string Component name
|
1115 |
-
*/
|
1116 |
-
clear_component: function(name) {
|
1117 |
-
this.set_component(name, null);
|
1118 |
-
},
|
1119 |
-
|
1120 |
-
/* Attributes */
|
1121 |
-
|
1122 |
-
/**
|
1123 |
-
* Initialize attributes
|
1124 |
-
* @param bool force (optional) Force full initialization of attributes (Default: FALSE)
|
1125 |
-
* @return void
|
1126 |
-
*/
|
1127 |
-
init_attributes: function(force) {
|
1128 |
-
if ( !this.util.is_bool(force) ) {
|
1129 |
-
force = false;
|
1130 |
-
}
|
1131 |
-
if ( force || !this.util.is_obj(this._attributes) ) {
|
1132 |
-
var a = this._attributes = {};
|
1133 |
-
// Default attributes
|
1134 |
-
$.extend(a, this.init_default_attributes());
|
1135 |
-
// Instantiation attributes
|
1136 |
-
if ( this.util.is_obj(this._attr_init) ) {
|
1137 |
-
$.extend(a, this._attr_init);
|
1138 |
-
}
|
1139 |
-
// DOM attributes
|
1140 |
-
$.extend(a, this.get_dom_attributes());
|
1141 |
-
}
|
1142 |
-
},
|
1143 |
-
|
1144 |
-
/**
|
1145 |
-
* Generate default attributes for component
|
1146 |
-
* @uses View.get_options() to get values from controller
|
1147 |
-
* @uses _attr_map to Remap controller attributes to instance attributes
|
1148 |
-
* @uses _attr_default to Store default attributes
|
1149 |
-
* @return obj Default attributes
|
1150 |
-
*/
|
1151 |
-
init_default_attributes: function() {
|
1152 |
-
// Get options from controller
|
1153 |
-
if ( !this._attr_default_parsed && this.util.is_obj(this._attr_map) ) {
|
1154 |
-
var opts = this.get_controller().get_options(this.util.obj_keys(this._attr_map));
|
1155 |
-
|
1156 |
-
if ( this.util.is_obj(opts) ) {
|
1157 |
-
// Remap
|
1158 |
-
for ( var opt in this._attr_map ) {
|
1159 |
-
if ( opt in opts && null !== this._attr_map[opt]) {
|
1160 |
-
// Move value to new property
|
1161 |
-
opts[this._attr_map[opt]] = opts[opt];
|
1162 |
-
// Delete old property
|
1163 |
-
delete opts[opt];
|
1164 |
-
}
|
1165 |
-
}
|
1166 |
-
// Merge with default attributes
|
1167 |
-
$.extend(true, this._attr_default, opts);
|
1168 |
-
}
|
1169 |
-
this._attr_default_parsed = true;
|
1170 |
-
}
|
1171 |
-
return this._attr_default;
|
1172 |
-
},
|
1173 |
-
|
1174 |
-
/**
|
1175 |
-
* Retrieve DOM attributes
|
1176 |
-
* @return obj DOM Attributes
|
1177 |
-
*/
|
1178 |
-
get_dom_attributes: function() {
|
1179 |
-
var attrs = {};
|
1180 |
-
var el = this.dom_get(null, {'init': false});
|
1181 |
-
if ( el.length > 0 ) {
|
1182 |
-
// Get attributes from element
|
1183 |
-
var attrs_full = $(el).get(0).attributes;
|
1184 |
-
if ( this.util.is_obj(attrs_full) ) {
|
1185 |
-
var attr_prefix = this.util.get_attribute();
|
1186 |
-
var attr_key;
|
1187 |
-
$.each(attrs_full, function(idx, attr) {
|
1188 |
-
if ( attr.name.indexOf( attr_prefix ) === -1 ) {
|
1189 |
-
return true;
|
1190 |
-
}
|
1191 |
-
// Process custom attributes (Strip prefix)
|
1192 |
-
attr_key = attr.name.substr(attr_prefix.length + 1);
|
1193 |
-
attrs[attr_key] = attr.value;
|
1194 |
-
});
|
1195 |
-
}
|
1196 |
-
}
|
1197 |
-
return attrs;
|
1198 |
-
},
|
1199 |
-
|
1200 |
-
/**
|
1201 |
-
* Retrieve all instance attributes
|
1202 |
-
* @uses init_attributes() to initialize attributes (if necessary)
|
1203 |
-
* @uses _attributes object
|
1204 |
-
* @return obj Component attributes
|
1205 |
-
*/
|
1206 |
-
get_attributes: function() {
|
1207 |
-
// Initilize attributes
|
1208 |
-
this.init_attributes();
|
1209 |
-
// Return attributes
|
1210 |
-
return this._attributes;
|
1211 |
-
},
|
1212 |
-
|
1213 |
-
/**
|
1214 |
-
* Retrieve value of specified attribute for value
|
1215 |
-
* @param string key Attribute to retrieve
|
1216 |
-
* @param mixed def (optional) Default value if attribute is not set
|
1217 |
-
* @param bool enforce_type (optional) Whether data type should match default value (Default: TRUE)
|
1218 |
-
* > If possible, attribute value will be converted to match default data type
|
1219 |
-
* > If attribute value cannot match default data type, default value will be used
|
1220 |
-
* @return mixed Attribute value (NULL if attribute is not set)
|
1221 |
-
*/
|
1222 |
-
get_attribute: function(key, def, enforce_type) {
|
1223 |
-
// Validate
|
1224 |
-
if ( !this.util.is_set(def) ) {
|
1225 |
-
def = null;
|
1226 |
-
}
|
1227 |
-
if ( !this.util.is_string(key) ) {
|
1228 |
-
return def;
|
1229 |
-
}
|
1230 |
-
if ( !this.util.is_bool(enforce_type) ) {
|
1231 |
-
enforce_type = true;
|
1232 |
-
}
|
1233 |
-
|
1234 |
-
// Get attribute value
|
1235 |
-
var ret = ( this.has_attribute(key) ) ? this.get_attributes()[key] : def;
|
1236 |
-
// Validate type
|
1237 |
-
if ( enforce_type && ret !== def && null !== def && !this.util.is_type(ret, $.type(def), false) ) {
|
1238 |
-
// Convert type
|
1239 |
-
// Scalar default
|
1240 |
-
if ( this.util.is_scalar(def, false) ) {
|
1241 |
-
if ( !this.util.is_scalar(ret, false) ) {
|
1242 |
-
// Non-scalar attribute
|
1243 |
-
ret = def;
|
1244 |
-
} else if ( this.util.is_string(def, false) ) {
|
1245 |
-
// Convert to string
|
1246 |
-
ret = ret.toString();
|
1247 |
-
} else if ( this.util.is_num(def, false) && !this.util.is_num(ret, false) ) {
|
1248 |
-
// Convert to number
|
1249 |
-
ret = ( this.util.is_int(def, false) ) ? parseInt(ret) : parseFloat(ret);
|
1250 |
-
if ( !this.util.is_num(ret, false) ) {
|
1251 |
-
ret = def;
|
1252 |
-
}
|
1253 |
-
} else if ( this.util.is_bool(def, false) ) {
|
1254 |
-
// Convert to boolean
|
1255 |
-
ret = ( this.util.is_string(ret) || ( this.util.is_num(ret) ) );
|
1256 |
-
} else {
|
1257 |
-
// Fallback: Set to default
|
1258 |
-
ret = def;
|
1259 |
-
}
|
1260 |
-
}
|
1261 |
-
// Non-scalar default
|
1262 |
-
else {
|
1263 |
-
ret = def;
|
1264 |
-
}
|
1265 |
-
}
|
1266 |
-
return ret;
|
1267 |
-
},
|
1268 |
-
|
1269 |
-
/**
|
1270 |
-
* Call attribute as method
|
1271 |
-
* @param string attr Attribute to call
|
1272 |
-
* @param arguments (optional) Additional arguments to pass to method
|
1273 |
-
* @return mixed Attribute return value (if attribute is not a function, attribute's value is returned)
|
1274 |
-
*/
|
1275 |
-
call_attribute: function(attr, args) {
|
1276 |
-
attr = this.get_attribute(attr);
|
1277 |
-
if ( this.util.is_func(attr) ) {
|
1278 |
-
// Get arguments
|
1279 |
-
args = Array.prototype.slice.call(arguments, 1);
|
1280 |
-
// Pass arguments to user-defined method
|
1281 |
-
attr = attr.apply(this, args);
|
1282 |
-
}
|
1283 |
-
return attr;
|
1284 |
-
},
|
1285 |
-
|
1286 |
-
/**
|
1287 |
-
* Check if attribute exists
|
1288 |
-
* @param string key Attribute name
|
1289 |
-
* @return bool TRUE if exists, FALSE otherwise
|
1290 |
-
*/
|
1291 |
-
has_attribute: function(key) {
|
1292 |
-
return ( this.util.is_string(key) && ( key in this.get_attributes() ) );
|
1293 |
-
},
|
1294 |
-
|
1295 |
-
/**
|
1296 |
-
* Set component attributes
|
1297 |
-
* @param obj attributes Attributes to set
|
1298 |
-
* @param bool full (optional) Whether to fully replace or merge component's attributes with new values (Default: Merge)
|
1299 |
-
*/
|
1300 |
-
set_attributes: function(attributes, full) {
|
1301 |
-
// Validate
|
1302 |
-
if ( !this.util.is_bool(full) ) {
|
1303 |
-
full = false;
|
1304 |
-
}
|
1305 |
-
|
1306 |
-
// Initialize attributes
|
1307 |
-
this.init_attributes(full);
|
1308 |
-
|
1309 |
-
// Merge new/existing attributes
|
1310 |
-
if ( this.util.is_obj(attributes) ) {
|
1311 |
-
$.extend(this._attributes, attributes);
|
1312 |
-
}
|
1313 |
-
},
|
1314 |
-
|
1315 |
-
/**
|
1316 |
-
* Set value for a component attribute
|
1317 |
-
* @uses get_attributes() to retrieve attributes
|
1318 |
-
* @param string key Attribute to set
|
1319 |
-
* @param mixed val Attribute value
|
1320 |
-
* @return mixed Attribute value
|
1321 |
-
*/
|
1322 |
-
set_attribute: function(key, val) {
|
1323 |
-
if ( this.util.is_string(key) && this.util.is_set(val) ) {
|
1324 |
-
this.get_attributes()[key] = val;
|
1325 |
-
}
|
1326 |
-
return val;
|
1327 |
-
},
|
1328 |
-
|
1329 |
-
/* DOM */
|
1330 |
-
|
1331 |
-
/**
|
1332 |
-
* Generate selector for retrieving child element
|
1333 |
-
* @param string element Class name of child element
|
1334 |
-
* @return string Element selector
|
1335 |
-
*/
|
1336 |
-
dom_get_selector: function(element) {
|
1337 |
-
return ( this.util.is_string(element) ) ? '.' + this.add_ns(element) : '';
|
1338 |
-
},
|
1339 |
-
|
1340 |
-
dom_get_attribute: function() {
|
1341 |
-
return this.util.get_attribute(this._slug);
|
1342 |
-
},
|
1343 |
-
|
1344 |
-
/**
|
1345 |
-
* Set reference of instance on DOM element
|
1346 |
-
* @uses _reciprocal to determine if DOM element should also be attached to instance
|
1347 |
-
* @param string|obj (jQuery) el DOM element to attach instance to
|
1348 |
-
* @return jQuery DOM element set
|
1349 |
-
*/
|
1350 |
-
dom_set: function(el) {
|
1351 |
-
el = $(el);
|
1352 |
-
// Save instance to DOM object
|
1353 |
-
el.data(this.get_data_key(), this);
|
1354 |
-
// Save DOM object to instance
|
1355 |
-
if ( this._reciprocal ) {
|
1356 |
-
this._dom = el;
|
1357 |
-
}
|
1358 |
-
return el;
|
1359 |
-
},
|
1360 |
-
|
1361 |
-
/**
|
1362 |
-
* Retrieve attached DOM element
|
1363 |
-
* @uses _dom to retrieve attached DOM element
|
1364 |
-
* @uses dom_put() to insert child element
|
1365 |
-
* @param string element (optional) ID of child element to retrieve (Default: Main element)
|
1366 |
-
* @param bool put (optional) Whether to insert element if it does not exist (Default: FALSE)
|
1367 |
-
* @param obj options (optional) Runtime options
|
1368 |
-
* @return obj jQuery DOM element
|
1369 |
-
*/
|
1370 |
-
dom_get: function(element, options) {
|
1371 |
-
// Build options
|
1372 |
-
var opts_default = {
|
1373 |
-
'init': true,
|
1374 |
-
'put': false
|
1375 |
-
};
|
1376 |
-
options = ( this.util.is_obj(options) ) ? $.extend({}, opts_default, options) : opts_default;
|
1377 |
-
|
1378 |
-
// Init Component DOM
|
1379 |
-
if ( options.init && !this.get_status('dom_init') ) {
|
1380 |
-
this.set_status('dom_init');
|
1381 |
-
this.dom_init();
|
1382 |
-
}
|
1383 |
-
// Check for main DOM element
|
1384 |
-
var ret = this._dom;
|
1385 |
-
if ( !!ret && this.util.is_string(element) ) {
|
1386 |
-
var ch = $(ret).find( this.dom_get_selector(element) );
|
1387 |
-
// Check for child element
|
1388 |
-
if ( ch.length ) {
|
1389 |
-
ret = ch;
|
1390 |
-
} else if ( true === options.put || this.util.is_obj(options.put) ) {
|
1391 |
-
// Insert child element
|
1392 |
-
ret = this.dom_put(element, options.put);
|
1393 |
-
}
|
1394 |
-
}
|
1395 |
-
return $(ret);
|
1396 |
-
},
|
1397 |
-
|
1398 |
-
/**
|
1399 |
-
* Initialize DOM element
|
1400 |
-
* To be overridden by child classes
|
1401 |
-
*/
|
1402 |
-
dom_init: function() {},
|
1403 |
-
|
1404 |
-
/**
|
1405 |
-
* Wrap output in DOM element
|
1406 |
-
* Wrapper element created and added to main DOM element if not yet created
|
1407 |
-
* @param string element ID for DOM element (Used as class name for wrapper)
|
1408 |
-
* @param string|jQuery|obj content Content to add to DOM (Object contains element properties)
|
1409 |
-
* > tag : Element tag name
|
1410 |
-
* > content : Element content
|
1411 |
-
* @return jQuery Inserted element(s)
|
1412 |
-
*/
|
1413 |
-
dom_put: function(element, content) {
|
1414 |
-
var r = null;
|
1415 |
-
// Stop processing if main DOM element not set or element is not valid
|
1416 |
-
if ( !this.dom_has() || !this.util.is_string(element) ) {
|
1417 |
-
return $(r);
|
1418 |
-
}
|
1419 |
-
// Setup options
|
1420 |
-
var strip = ['tag', 'content', 'success'];
|
1421 |
-
var options = {
|
1422 |
-
'tag': 'div',
|
1423 |
-
'content': '',
|
1424 |
-
'class': this.add_ns(element)
|
1425 |
-
};
|
1426 |
-
// Setup content
|
1427 |
-
if ( !this.util.is_empty(content) ) {
|
1428 |
-
if ( this.util.is_type(content, jQuery, false) || this.util.is_string(content, false) ) {
|
1429 |
-
options.content = content;
|
1430 |
-
}
|
1431 |
-
else if ( this.util.is_obj(content, false) ) {
|
1432 |
-
$.extend(options, content);
|
1433 |
-
}
|
1434 |
-
}
|
1435 |
-
var attrs = $.extend({}, options);
|
1436 |
-
for ( var x = 0; x < strip.length; x++ ) {
|
1437 |
-
delete attrs[strip[x]];
|
1438 |
-
}
|
1439 |
-
// Retrieve existing element
|
1440 |
-
var d = this.dom_get();
|
1441 |
-
r = $(this.dom_get_selector(element), d);
|
1442 |
-
// Create element (if necessary)
|
1443 |
-
if ( !r.length ) {
|
1444 |
-
r = $(this.util.format('<%s />', options.tag), attrs).appendTo(d);
|
1445 |
-
if ( r.length && this.util.is_method(options, 'success') ) {
|
1446 |
-
options['success'].call(r, r);
|
1447 |
-
}
|
1448 |
-
}
|
1449 |
-
// Set content
|
1450 |
-
$(r).append(options.content);
|
1451 |
-
return $(r);
|
1452 |
-
},
|
1453 |
-
|
1454 |
-
/**
|
1455 |
-
* Check if DOM element is set for instance
|
1456 |
-
* DOM is initialized before evaluation
|
1457 |
-
* @return bool TRUE if DOM element set, FALSE otherwise
|
1458 |
-
*/
|
1459 |
-
dom_has: function() {
|
1460 |
-
return ( !!this.dom_get().length );
|
1461 |
-
},
|
1462 |
-
|
1463 |
-
/* Data */
|
1464 |
-
|
1465 |
-
/**
|
1466 |
-
* Retrieve key used to store data in DOM element
|
1467 |
-
* @return string Data key
|
1468 |
-
*/
|
1469 |
-
get_data_key: function() {
|
1470 |
-
return this.get_ns();
|
1471 |
-
},
|
1472 |
-
|
1473 |
-
/* Events */
|
1474 |
-
|
1475 |
-
/**
|
1476 |
-
* Register event handler for custom event
|
1477 |
-
* Structure
|
1478 |
-
* > Events (obj)
|
1479 |
-
* > Event-Name (array)
|
1480 |
-
* > Handlers (functions)
|
1481 |
-
* @param mixed event Custom event to register handler for
|
1482 |
-
* > string: Standard event handler
|
1483 |
-
* > array: Multiple events to register single handler on
|
1484 |
-
* > object: Map of events/handlers
|
1485 |
-
* @param function fn Event handler
|
1486 |
-
* @param obj options Handler registration options
|
1487 |
-
* > clear (bool) Clear existing event handlers before setting current handler (Default: FALSE)
|
1488 |
-
* @return obj Component instance (allows chaining)
|
1489 |
-
*/
|
1490 |
-
on: function(event, fn, options) {
|
1491 |
-
// Handle request types
|
1492 |
-
if ( !this.util.is_string(event) || !this.util.is_func(fn) ) {
|
1493 |
-
var t = this;
|
1494 |
-
var args = Array.prototype.slice.call(arguments, 1);
|
1495 |
-
if ( this.util.is_array(event) ) {
|
1496 |
-
// Events array
|
1497 |
-
$.each(event, function(idx, val) {
|
1498 |
-
t.on.apply(t, [val].concat(args));
|
1499 |
-
});
|
1500 |
-
} else if ( this.util.is_obj(event) ) {
|
1501 |
-
// Events map
|
1502 |
-
$.each(event, function(ev, hdl) {
|
1503 |
-
t.on.apply(t, [ev, hdl].concat(args));
|
1504 |
-
});
|
1505 |
-
}
|
1506 |
-
return this;
|
1507 |
-
}
|
1508 |
-
|
1509 |
-
// Options
|
1510 |
-
|
1511 |
-
// Default options
|
1512 |
-
var options_std = {
|
1513 |
-
clear: false
|
1514 |
-
};
|
1515 |
-
if ( !this.util.is_obj(options, false) ) {
|
1516 |
-
// Reset options
|
1517 |
-
options = {};
|
1518 |
-
}
|
1519 |
-
// Build options
|
1520 |
-
options = $.extend({}, options_std, options);
|
1521 |
-
// Initialize events bucket
|
1522 |
-
if ( !this.util.is_obj(this._events, false) ) {
|
1523 |
-
this._events = {};
|
1524 |
-
}
|
1525 |
-
// Setup event
|
1526 |
-
var es = this._events;
|
1527 |
-
if ( !( event in es ) || !this.util.is_obj(es[event], false) || !!options.clear ) {
|
1528 |
-
es[event] = [];
|
1529 |
-
}
|
1530 |
-
// Add event handler
|
1531 |
-
es[event].push(fn);
|
1532 |
-
return this;
|
1533 |
-
},
|
1534 |
-
|
1535 |
-
/**
|
1536 |
-
* Trigger custom event
|
1537 |
-
* Event handlers are executed in the context of the current component instance
|
1538 |
-
* Event handlers are passed parameters
|
1539 |
-
* > ev (obj) Event object
|
1540 |
-
* > type (string) Event name
|
1541 |
-
* > data (mixed) Data to pass to handlers (if supplied)
|
1542 |
-
* > component (obj) Current component instance
|
1543 |
-
* @param string event Custom event to trigger
|
1544 |
-
* @param mixed data (optional) Data to pass to event handlers
|
1545 |
-
* @return jQuery.Promise Promise that is resolved once event handlers are resolved
|
1546 |
-
*/
|
1547 |
-
trigger: function(event, data) {
|
1548 |
-
var dfr = $.Deferred();
|
1549 |
-
var dfrs = [];
|
1550 |
-
var t = this;
|
1551 |
-
// Handle array of events
|
1552 |
-
if ( this.util.is_array(event) ) {
|
1553 |
-
$.each(event, function(idx, val) {
|
1554 |
-
// Collect promises from triggered events
|
1555 |
-
dfrs.push( t.trigger(val, data) );
|
1556 |
-
});
|
1557 |
-
// Resolve trigger when all events have been resolved
|
1558 |
-
$.when.apply(t, dfrs).done(function() {
|
1559 |
-
dfr.resolve();
|
1560 |
-
});
|
1561 |
-
return dfr.promise();
|
1562 |
-
}
|
1563 |
-
// Validate
|
1564 |
-
if ( !this.util.is_string(event) || !( event in this._events ) ) {
|
1565 |
-
dfr.resolve();
|
1566 |
-
return dfr.promise();
|
1567 |
-
}
|
1568 |
-
// Create event object
|
1569 |
-
var ev = { 'type': event, 'data': null };
|
1570 |
-
// Add data to event object
|
1571 |
-
if ( this.util.is_set(data) ) {
|
1572 |
-
ev.data = data;
|
1573 |
-
}
|
1574 |
-
// Fire handlers for event
|
1575 |
-
$.each(this._events[event], function(idx, fn) {
|
1576 |
-
// Call handler (`this` set to current instance)
|
1577 |
-
// Collect promises from event handlers
|
1578 |
-
dfrs.push( fn.call(t, ev, t) );
|
1579 |
-
});
|
1580 |
-
// Resolve trigger when all handlers have been resolved
|
1581 |
-
$.when.apply(this, dfrs).done(function() {
|
1582 |
-
dfr.resolve();
|
1583 |
-
});
|
1584 |
-
return dfr.promise();
|
1585 |
-
}
|
1586 |
-
};
|
1587 |
-
|
1588 |
-
View.Component = Component = SLB.Class.extend(Component);
|
1589 |
-
|
1590 |
-
/**
|
1591 |
-
* Content viewer
|
1592 |
-
* @param obj options Init options
|
1593 |
-
*/
|
1594 |
-
var Viewer = {
|
1595 |
-
|
1596 |
-
/* Configuration */
|
1597 |
-
|
1598 |
-
_slug: 'viewer',
|
1599 |
-
|
1600 |
-
_refs: {
|
1601 |
-
item: 'Content_Item',
|
1602 |
-
theme: 'Theme'
|
1603 |
-
},
|
1604 |
-
|
1605 |
-
_reciprocal: true,
|
1606 |
-
|
1607 |
-
_attr_default: {
|
1608 |
-
loop: true,
|
1609 |
-
animate: true,
|
1610 |
-
autofit: true,
|
1611 |
-
overlay_enabled: true,
|
1612 |
-
overlay_opacity: '0.8',
|
1613 |
-
title_default: false,
|
1614 |
-
container: null,
|
1615 |
-
slideshow_enabled: true,
|
1616 |
-
slideshow_autostart: false,
|
1617 |
-
slideshow_duration: 2,
|
1618 |
-
slideshow_active: false,
|
1619 |
-
slideshow_timer: null,
|
1620 |
-
labels: {
|
1621 |
-
close: 'close',
|
1622 |
-
nav_prev: '« prev',
|
1623 |
-
nav_next: 'next »',
|
1624 |
-
slideshow_start: 'start slideshow',
|
1625 |
-
slideshow_stop: 'stop slideshow',
|
1626 |
-
group_status: 'Image %current% of %total%',
|
1627 |
-
loading: 'loading'
|
1628 |
-
}
|
1629 |
-
},
|
1630 |
-
|
1631 |
-
_attr_map: {
|
1632 |
-
'theme': null,
|
1633 |
-
'group_loop': 'loop',
|
1634 |
-
'ui_autofit': 'autofit',
|
1635 |
-
'ui_animate': 'animate',
|
1636 |
-
'ui_overlay_opacity': 'overlay_opacity',
|
1637 |
-
'ui_labels': 'labels',
|
1638 |
-
'ui_title_default': 'title_default',
|
1639 |
-
'slideshow_enabled': null,
|
1640 |
-
'slideshow_autostart': null,
|
1641 |
-
'slideshow_duration': null
|
1642 |
-
},
|
1643 |
-
|
1644 |
-
/* References */
|
1645 |
-
|
1646 |
-
/**
|
1647 |
-
* Item currently loaded in viewer
|
1648 |
-
* @var object Content_Item
|
1649 |
-
*/
|
1650 |
-
item: null,
|
1651 |
-
|
1652 |
-
/**
|
1653 |
-
* Queued item to be loaded once viewer is available
|
1654 |
-
* @var object Content_Item
|
1655 |
-
*/
|
1656 |
-
item_queued: null,
|
1657 |
-
|
1658 |
-
/**
|
1659 |
-
* Theme used by viewer
|
1660 |
-
* @var object Theme
|
1661 |
-
*/
|
1662 |
-
theme: null,
|
1663 |
-
|
1664 |
-
/* Properties */
|
1665 |
-
|
1666 |
-
item_working: null,
|
1667 |
-
|
1668 |
-
active: false,
|
1669 |
-
init: false,
|
1670 |
-
open: false,
|
1671 |
-
loading: false,
|
1672 |
-
|
1673 |
-
/* Methods */
|
1674 |
-
|
1675 |
-
/* Init */
|
1676 |
-
|
1677 |
-
_hooks: function() {
|
1678 |
-
var t = this;
|
1679 |
-
this
|
1680 |
-
.on(['item-prev', 'item-next'], function() {
|
1681 |
-
t.trigger('item-change');
|
1682 |
-
})
|
1683 |
-
.on(['close', 'item-change'], function() {
|
1684 |
-
t.unload().done(function() {
|
1685 |
-
t.unlock();
|
1686 |
-
});
|
1687 |
-
});
|
1688 |
-
},
|
1689 |
-
|
1690 |
-
/* References */
|
1691 |
-
|
1692 |
-
/**
|
1693 |
-
* Retrieve item instance current attached to viewer
|
1694 |
-
* @return Content_Item|NULL Current item instance
|
1695 |
-
*/
|
1696 |
-
get_item: function() {
|
1697 |
-
return this.get_component('item');
|
1698 |
-
},
|
1699 |
-
|
1700 |
-
/**
|
1701 |
-
* Set item reference
|
1702 |
-
* Validates item before setting
|
1703 |
-
* @param obj item Content_Item instance
|
1704 |
-
* @return bool TRUE if valid item set, FALSE otherwise
|
1705 |
-
*/
|
1706 |
-
set_item: function(item) {
|
1707 |
-
// Clear existing item
|
1708 |
-
this.clear_item(false);
|
1709 |
-
var i = this.set_component('item', item, function(item) {
|
1710 |
-
return ( item.has_type() );
|
1711 |
-
});
|
1712 |
-
return ( !this.util.is_empty(i) );
|
1713 |
-
},
|
1714 |
-
|
1715 |
-
/**
|
1716 |
-
* Clear item from viewer
|
1717 |
-
* Resets item state and removes reference (if necessary)
|
1718 |
-
* @param bool full (optional) Fully remove item? (Default: TRUE)
|
1719 |
-
*/
|
1720 |
-
clear_item: function(full) {
|
1721 |
-
// Validate
|
1722 |
-
if ( !this.util.is_bool(full) ) {
|
1723 |
-
full = true;
|
1724 |
-
}
|
1725 |
-
var item = this.get_item();
|
1726 |
-
if ( !!item ) {
|
1727 |
-
item.reset();
|
1728 |
-
}
|
1729 |
-
if ( full ) {
|
1730 |
-
this.clear_component('item');
|
1731 |
-
}
|
1732 |
-
},
|
1733 |
-
|
1734 |
-
/**
|
1735 |
-
* Retrieve theme reference
|
1736 |
-
* @return object Theme reference
|
1737 |
-
*/
|
1738 |
-
get_theme: function() {
|
1739 |
-
// Get saved theme
|
1740 |
-
var ret = this.get_component('theme', {check_attr: false});
|
1741 |
-
if ( this.util.is_empty(ret) ) {
|
1742 |
-
// Theme needs to be initialized
|
1743 |
-
ret = this.set_component('theme', new View.Theme(this));
|
1744 |
-
}
|
1745 |
-
return ret;
|
1746 |
-
},
|
1747 |
-
|
1748 |
-
/**
|
1749 |
-
* Set viewer's theme
|
1750 |
-
* @param object theme Theme object
|
1751 |
-
*/
|
1752 |
-
set_theme: function(theme) {
|
1753 |
-
this.set_component('theme', theme);
|
1754 |
-
},
|
1755 |
-
|
1756 |
-
/* Properties */
|
1757 |
-
|
1758 |
-
/**
|
1759 |
-
* Lock the viewer
|
1760 |
-
* Indicates that item is currently being processed
|
1761 |
-
* @return jQuery.Deferred Resolved when item processing is complete
|
1762 |
-
*/
|
1763 |
-
lock: function() {
|
1764 |
-
return this.set_status('item_working', $.Deferred());
|
1765 |
-
},
|
1766 |
-
|
1767 |
-
/**
|
1768 |
-
* Retrieve lock
|
1769 |
-
* @param bool simple (optional) Whether to return a simple status of the locked status (Default: FALSE)
|
1770 |
-
* @param bool full (optional) Whether to return Deferred (TRUE) or Promise (FALSE) object (Default: FALSE)
|
1771 |
-
* @return jQuery.Promise Resolved when item processing is complete
|
1772 |
-
*/
|
1773 |
-
get_lock: function(simple, full) {
|
1774 |
-
// Validate
|
1775 |
-
if ( !this.util.is_bool(simple) ) {
|
1776 |
-
simple = false;
|
1777 |
-
}
|
1778 |
-
if ( !this.util.is_bool(full) ) {
|
1779 |
-
full = false;
|
1780 |
-
}
|
1781 |
-
var s = 'item_working';
|
1782 |
-
// Simple status
|
1783 |
-
if ( simple ) {
|
1784 |
-
return this.get_status(s);
|
1785 |
-
}
|
1786 |
-
// Full value
|
1787 |
-
var r = this.get_status(s, true);
|
1788 |
-
if ( !this.util.is_promise(r) ) {
|
1789 |
-
// Create default
|
1790 |
-
r = this.lock();
|
1791 |
-
}
|
1792 |
-
return ( full ) ? r : r.promise();
|
1793 |
-
},
|
1794 |
-
|
1795 |
-
is_locked: function() {
|
1796 |
-
return this.get_lock(true);
|
1797 |
-
},
|
1798 |
-
|
1799 |
-
/**
|
1800 |
-
* Unlock the viewer
|
1801 |
-
* Any callbacks registered for this action will be executed
|
1802 |
-
* @return jQuery.Deferred Resolved instance
|
1803 |
-
*/
|
1804 |
-
unlock: function() {
|
1805 |
-
return this.get_lock(false, true).resolve();
|
1806 |
-
},
|
1807 |
-
|
1808 |
-
/**
|
1809 |
-
* Set Viewer active status
|
1810 |
-
* @param bool mode (optional) Activate or deactivate status (Default: TRUE)
|
1811 |
-
* @return bool Active status
|
1812 |
-
*/
|
1813 |
-
set_active: function(mode) {
|
1814 |
-
if ( !this.util.is_bool(mode) ) {
|
1815 |
-
mode = true;
|
1816 |
-
}
|
1817 |
-
return this.set_status('active', mode);
|
1818 |
-
},
|
1819 |
-
|
1820 |
-
/**
|
1821 |
-
* Check Viewer active status
|
1822 |
-
* @return bool Active status
|
1823 |
-
*/
|
1824 |
-
is_active: function() {
|
1825 |
-
return this.get_status('active');
|
1826 |
-
},
|
1827 |
-
|
1828 |
-
/**
|
1829 |
-
* Set loading mode
|
1830 |
-
* @param bool mode (optional) Set (TRUE) or unset (FALSE) loading mode (Default: TRUE)
|
1831 |
-
* @return jQuery.Promise Promise that resolves when loading mode is set
|
1832 |
-
*/
|
1833 |
-
set_loading: function(mode) {
|
1834 |
-
var dfr = $.Deferred();
|
1835 |
-
if ( !this.util.is_bool(mode) ) {
|
1836 |
-
mode = true;
|
1837 |
-
}
|
1838 |
-
this.loading = mode;
|
1839 |
-
// Pause/Resume slideshow
|
1840 |
-
if ( this.slideshow_active() ) {
|
1841 |
-
this.slideshow_pause(mode);
|
1842 |
-
}
|
1843 |
-
// Set CSS class on DOM element
|
1844 |
-
var m = ( mode ) ? 'addClass' : 'removeClass';
|
1845 |
-
$(this.dom_get())[m]('loading');
|
1846 |
-
if ( mode ) {
|
1847 |
-
// Loading transition
|
1848 |
-
this.get_theme().transition('load').always(function() {
|
1849 |
-
dfr.resolve();
|
1850 |
-
});
|
1851 |
-
} else {
|
1852 |
-
dfr.resolve();
|
1853 |
-
}
|
1854 |
-
return dfr.promise();
|
1855 |
-
},
|
1856 |
-
|
1857 |
-
/**
|
1858 |
-
* Unset loading mode
|
1859 |
-
* @see set_loading()
|
1860 |
-
* @return jQuery.Promise Promise that resovles when loading mode is set
|
1861 |
-
*/
|
1862 |
-
unset_loading: function() {
|
1863 |
-
return this.set_loading(false);
|
1864 |
-
},
|
1865 |
-
|
1866 |
-
/**
|
1867 |
-
* Retrieve loading status
|
1868 |
-
* @return bool Loading status (Default: FALSE)
|
1869 |
-
*/
|
1870 |
-
get_loading: function() {
|
1871 |
-
return ( this.util.is_bool(this.loading) ) ? this.loading : false;
|
1872 |
-
},
|
1873 |
-
|
1874 |
-
/**
|
1875 |
-
* Check if viewer is currently loading content
|
1876 |
-
* @return bool Loading status (Default: FALSE)
|
1877 |
-
*/
|
1878 |
-
is_loading: function() {
|
1879 |
-
return this.get_loading();
|
1880 |
-
},
|
1881 |
-
|
1882 |
-
/* Display */
|
1883 |
-
|
1884 |
-
/**
|
1885 |
-
* Display content in viewer
|
1886 |
-
* @param Content_Item item Item to show
|
1887 |
-
* @param obj options (optional) Display options
|
1888 |
-
*/
|
1889 |
-
show: function(item) {
|
1890 |
-
this.item_queued = item;
|
1891 |
-
var fin_set = 'show_deferred';
|
1892 |
-
// Validate theme
|
1893 |
-
var vt = 'theme_valid';
|
1894 |
-
var valid = true;
|
1895 |
-
if ( this.has_attribute(vt)) {
|
1896 |
-
valid = this.get_attribute(vt, true);
|
1897 |
-
} else {
|
1898 |
-
valid = ( this.get_theme() && this.get_theme().get_template().get_layout(false) !== "" ) ? true : false;
|
1899 |
-
this.set_attribute(vt, valid);
|
1900 |
-
}
|
1901 |
-
|
1902 |
-
if ( !valid ) {
|
1903 |
-
this.close();
|
1904 |
-
return false;
|
1905 |
-
}
|
1906 |
-
var v = this;
|
1907 |
-
var fin = function() {
|
1908 |
-
// Lock viewer
|
1909 |
-
v.lock();
|
1910 |
-
// Reset callback flag (for new lock)
|
1911 |
-
v.set_status(fin_set, false);
|
1912 |
-
// Validate request
|
1913 |
-
if ( !v.set_item(v.item_queued) ) {
|
1914 |
-
v.close();
|
1915 |
-
return false;
|
1916 |
-
}
|
1917 |
-
// Add item to history stack
|
1918 |
-
v.history_add();
|
1919 |
-
// Activate
|
1920 |
-
v.set_active();
|
1921 |
-
// Display
|
1922 |
-
v.render();
|
1923 |
-
};
|
1924 |
-
if ( !this.is_locked() ) {
|
1925 |
-
fin();
|
1926 |
-
} else if ( !this.get_status(fin_set) ) {
|
1927 |
-
// Set flag to avoid duplicate callbacks
|
1928 |
-
this.set_status(fin_set);
|
1929 |
-
this.get_lock().always(function() {
|
1930 |
-
fin();
|
1931 |
-
});
|
1932 |
-
}
|
1933 |
-
},
|
1934 |
-
|
1935 |
-
/* History Management */
|
1936 |
-
|
1937 |
-
history_handle: function(e) {
|
1938 |
-
var state = e.originalEvent.state;
|
1939 |
-
// Load item
|
1940 |
-
if ( this.util.is_string(state.item, false) ) {
|
1941 |
-
this.get_controller().get_item(state.item).show({'event': e});
|
1942 |
-
this.trigger('item-change');
|
1943 |
-
} else {
|
1944 |
-
var count = this.history_get(true);
|
1945 |
-
// Reset count
|
1946 |
-
this.history_set(0);
|
1947 |
-
// Close viewer
|
1948 |
-
if ( -1 !== count ) {
|
1949 |
-
this.close();
|
1950 |
-
}
|
1951 |
-
}
|
1952 |
-
},
|
1953 |
-
|
1954 |
-
history_get: function(full) {
|
1955 |
-
return this.get_status('history_count', full);
|
1956 |
-
},
|
1957 |
-
history_set: function(val) {
|
1958 |
-
return this.set_status('history_count', val);
|
1959 |
-
},
|
1960 |
-
history_add: function() {
|
1961 |
-
if ( !history.pushState ) {
|
1962 |
-
return false;
|
1963 |
-
}
|
1964 |
-
// Get display options
|
1965 |
-
var item = this.get_item();
|
1966 |
-
var opts = item.get_attribute('options_show');
|
1967 |
-
// Save history state
|
1968 |
-
var count = ( this.history_get() ) ? this.history_get(true) : 0;
|
1969 |
-
if ( !this.util.in_obj(opts, 'event') ) {
|
1970 |
-
// Create state
|
1971 |
-
var state = {
|
1972 |
-
'viewer': this.get_id(),
|
1973 |
-
'item': null,
|
1974 |
-
'count': count
|
1975 |
-
};
|
1976 |
-
// Init: Save viewer state
|
1977 |
-
if ( !count ) {
|
1978 |
-
history.replaceState(state, null);
|
1979 |
-
}
|
1980 |
-
// Always: Save item state
|
1981 |
-
state.item = this.get_controller().save_item(item).get_id();
|
1982 |
-
state.count = ++count;
|
1983 |
-
history.pushState(state, '');
|
1984 |
-
} else {
|
1985 |
-
var e = opts.event.originalEvent;
|
1986 |
-
if ( this.util.in_obj(e, 'state') && this.util.in_obj(e.state, 'count') ) {
|
1987 |
-
count = e.state.count;
|
1988 |
-
}
|
1989 |
-
}
|
1990 |
-
// Save history item count
|
1991 |
-
this.history_set(count);
|
1992 |
-
},
|
1993 |
-
history_reset: function() {
|
1994 |
-
var count = this.history_get(true);
|
1995 |
-
if ( count ) {
|
1996 |
-
// Clear history status
|
1997 |
-
this.history_set(-1);
|
1998 |
-
// Restore history stack
|
1999 |
-
history.go( -1 * count );
|
2000 |
-
}
|
2001 |
-
},
|
2002 |
-
|
2003 |
-
/**
|
2004 |
-
* Check if viewer is currently open
|
2005 |
-
* Checks if node is actually visible in DOM
|
2006 |
-
* @return bool TRUE if viewer is open, FALSE otherwise
|
2007 |
-
*/
|
2008 |
-
is_open: function() {
|
2009 |
-
return ( this.dom_get().css('display') === 'none' ) ? false : true;
|
2010 |
-
},
|
2011 |
-
|
2012 |
-
/**
|
2013 |
-
* Load output into DOM
|
2014 |
-
*/
|
2015 |
-
render: function() {
|
2016 |
-
// Get theme output
|
2017 |
-
var v = this;
|
2018 |
-
var thm = this.get_theme();
|
2019 |
-
v.dom_prep();
|
2020 |
-
// Register theme event handlers
|
2021 |
-
if ( !this.get_status('render-events') ) {
|
2022 |
-
this.set_status('render-events');
|
2023 |
-
thm
|
2024 |
-
// Loading
|
2025 |
-
.on('render-loading', function(ev, thm) {
|
2026 |
-
var dfr = $.Deferred();
|
2027 |
-
if ( !v.is_active() ) {
|
2028 |
-
dfr.reject();
|
2029 |
-
return dfr.promise();
|
2030 |
-
}
|
2031 |
-
var set_pos = function() {
|
2032 |
-
// Set position
|
2033 |
-
v.dom_get().css('top', $(window).scrollTop());
|
2034 |
-
};
|
2035 |
-
var always = function() {
|
2036 |
-
// Set loading flag
|
2037 |
-
v.set_loading().always(function() {
|
2038 |
-
dfr.resolve();
|
2039 |
-
});
|
2040 |
-
};
|
2041 |
-
if ( v.is_open() ) {
|
2042 |
-
thm.transition('unload')
|
2043 |
-
.fail(function() {
|
2044 |
-
set_pos();
|
2045 |
-
thm.dom_get_tag('item', 'content').attr('style', '');
|
2046 |
-
})
|
2047 |
-
.always(always);
|
2048 |
-
} else {
|
2049 |
-
thm.transition('open')
|
2050 |
-
.always(function() {
|
2051 |
-
always();
|
2052 |
-
v.events_open();
|
2053 |
-
v.open = true;
|
2054 |
-
})
|
2055 |
-
.fail(function() {
|
2056 |
-
set_pos();
|
2057 |
-
// Fallback open
|
2058 |
-
v.get_overlay().show();
|
2059 |
-
v.dom_get().show();
|
2060 |
-
});
|
2061 |
-
}
|
2062 |
-
return dfr.promise();
|
2063 |
-
})
|
2064 |
-
// Complete
|
2065 |
-
.on('render-complete', function(ev, thm) {
|
2066 |
-
// Stop if viewer not active
|
2067 |
-
if ( !v.is_active() ) {
|
2068 |
-
return false;
|
2069 |
-
}
|
2070 |
-
// Set classes
|
2071 |
-
var d = v.dom_get();
|
2072 |
-
var classes = ['item_single', 'item_multi'];
|
2073 |
-
var ms = ['addClass', 'removeClass'];
|
2074 |
-
if ( !v.get_item().get_group().is_single() ) {
|
2075 |
-
ms.reverse();
|
2076 |
-
}
|
2077 |
-
$.each(ms, function(idx, val) {
|
2078 |
-
d[val](classes[idx]);
|
2079 |
-
});
|
2080 |
-
// Bind events
|
2081 |
-
v.events_complete();
|
2082 |
-
// Transition
|
2083 |
-
thm.transition('complete')
|
2084 |
-
.fail(function() {
|
2085 |
-
// Autofit content
|
2086 |
-
if ( v.get_attribute('autofit', true) ) {
|
2087 |
-
var dims = $.extend({'display': 'inline-block'}, thm.get_item_dimensions());
|
2088 |
-
thm.dom_get_tag('item', 'content').css(dims);
|
2089 |
-
}
|
2090 |
-
})
|
2091 |
-
.always(function() {
|
2092 |
-
// Unset loading flag
|
2093 |
-
v.unset_loading();
|
2094 |
-
// Trigger event
|
2095 |
-
v.trigger('render-complete');
|
2096 |
-
// Set viewer as initialized
|
2097 |
-
v.init = true;
|
2098 |
-
});
|
2099 |
-
});
|
2100 |
-
}
|
2101 |
-
// Render
|
2102 |
-
thm.render();
|
2103 |
-
},
|
2104 |
-
|
2105 |
-
/**
|
2106 |
-
* Retrieve container element
|
2107 |
-
* Creates default container element if not yet created
|
2108 |
-
* @return jQuery Container element
|
2109 |
-
*/
|
2110 |
-
dom_get_container: function() {
|
2111 |
-
var sel = this.get_attribute('container');
|
2112 |
-
// Set default container
|
2113 |
-
if ( this.util.is_empty(sel) ) {
|
2114 |
-
sel = '#' + this.add_ns('wrap');
|
2115 |
-
}
|
2116 |
-
// Add default container to DOM if not yet present
|
2117 |
-
var c = $(sel);
|
2118 |
-
if ( !c.length ) {
|
2119 |
-
// Prepare ID
|
2120 |
-
var id = ( sel.indexOf('#') === 0 ) ? sel.substr(1) : sel;
|
2121 |
-
// Add element
|
2122 |
-
c = $('<div />', {'id': id}).appendTo('body');
|
2123 |
-
}
|
2124 |
-
return c;
|
2125 |
-
},
|
2126 |
-
|
2127 |
-
/**
|
2128 |
-
* Custom Viewer DOM initialization
|
2129 |
-
*/
|
2130 |
-
dom_init: function() {
|
2131 |
-
// Create element & add to DOM
|
2132 |
-
// Save element to instance
|
2133 |
-
var d = this.dom_set($('<div/>', {
|
2134 |
-
'id': this.get_id(true),
|
2135 |
-
'class': this.get_ns()
|
2136 |
-
})).appendTo(this.dom_get_container()).hide();
|
2137 |
-
// Add theme classes
|
2138 |
-
var thm = this.get_theme();
|
2139 |
-
d.addClass(thm.get_classes(' '));
|
2140 |
-
// Add theme layout (basic)
|
2141 |
-
var v = this;
|
2142 |
-
if ( !this.get_status('render-init') ) {
|
2143 |
-
this.set_status('render-init');
|
2144 |
-
thm.on('render-init', function(ev) {
|
2145 |
-
// Add rendered theme layout to viewer DOM
|
2146 |
-
v.dom_put('layout', ev.data);
|
2147 |
-
});
|
2148 |
-
}
|
2149 |
-
thm.render(true);
|
2150 |
-
},
|
2151 |
-
|
2152 |
-
/**
|
2153 |
-
* Prepare DOM for viewer
|
2154 |
-
*/
|
2155 |
-
dom_prep: function(mode) {
|
2156 |
-
var m = ( this.util.is_bool(mode) && !mode ) ? 'removeClass' : 'addClass';
|
2157 |
-
$('html')[m](this.util.add_prefix('overlay'));
|
2158 |
-
},
|
2159 |
-
|
2160 |
-
/**
|
2161 |
-
* Restore DOM
|
2162 |
-
* Required after viewer is closed
|
2163 |
-
*/
|
2164 |
-
dom_restore: function() {
|
2165 |
-
this.dom_prep(false);
|
2166 |
-
},
|
2167 |
-
|
2168 |
-
/* Layout */
|
2169 |
-
|
2170 |
-
get_layout: function() {
|
2171 |
-
var ret = this.dom_get('layout', {
|
2172 |
-
'put': {
|
2173 |
-
'success': function() {
|
2174 |
-
$(this).hide();
|
2175 |
-
}
|
2176 |
-
}
|
2177 |
-
});
|
2178 |
-
return ret;
|
2179 |
-
},
|
2180 |
-
|
2181 |
-
/* Animation */
|
2182 |
-
|
2183 |
-
animation_enabled: function() {
|
2184 |
-
return this.get_attribute('animate', true);
|
2185 |
-
},
|
2186 |
-
|
2187 |
-
/* Overlay */
|
2188 |
-
|
2189 |
-
/**
|
2190 |
-
* Determine if overlay is enabled for viewer
|
2191 |
-
* @return bool TRUE if overlay is enabled, FALSE otherwise
|
2192 |
-
*/
|
2193 |
-
overlay_enabled: function() {
|
2194 |
-
var ov = this.get_attribute('overlay_enabled');
|
2195 |
-
return ( this.util.is_bool(ov) ) ? ov : false;
|
2196 |
-
},
|
2197 |
-
|
2198 |
-
/**
|
2199 |
-
* Retrieve overlay DOM element
|
2200 |
-
* @return jQuery Overlay element (NULL if no overlay set for viewer)
|
2201 |
-
*/
|
2202 |
-
get_overlay: function() {
|
2203 |
-
var o = null;
|
2204 |
-
var v = this;
|
2205 |
-
if ( this.overlay_enabled() ) {
|
2206 |
-
o = this.dom_get('overlay', {
|
2207 |
-
'put': {
|
2208 |
-
'success': function() {
|
2209 |
-
$(this).hide().css('opacity', v.get_attribute('overlay_opacity'));
|
2210 |
-
}
|
2211 |
-
}
|
2212 |
-
});
|
2213 |
-
}
|
2214 |
-
return $(o);
|
2215 |
-
},
|
2216 |
-
|
2217 |
-
/**
|
2218 |
-
* Unload viewer
|
2219 |
-
*/
|
2220 |
-
unload: function() {
|
2221 |
-
var dfr = $.Deferred();
|
2222 |
-
// Unload item data
|
2223 |
-
this.get_theme().dom_get_tag('item').text('');
|
2224 |
-
dfr.resolve();
|
2225 |
-
return dfr.promise();
|
2226 |
-
},
|
2227 |
-
|
2228 |
-
/**
|
2229 |
-
* Reset viewer
|
2230 |
-
*/
|
2231 |
-
reset: function() {
|
2232 |
-
// Hide viewer
|
2233 |
-
this.dom_get().hide();
|
2234 |
-
// Restore DOM
|
2235 |
-
this.dom_restore();
|
2236 |
-
// History
|
2237 |
-
this.history_reset();
|
2238 |
-
// Item
|
2239 |
-
this.clear_item();
|
2240 |
-
// Reset properties
|
2241 |
-
this.set_active(false);
|
2242 |
-
this.set_loading(false);
|
2243 |
-
this.slideshow_stop();
|
2244 |
-
this.keys_disable();
|
2245 |
-
// Clear for next item
|
2246 |
-
this.unlock();
|
2247 |
-
},
|
2248 |
-
|
2249 |
-
/* Content */
|
2250 |
-
|
2251 |
-
get_labels: function() {
|
2252 |
-
return this.get_attribute('labels', {});
|
2253 |
-
},
|
2254 |
-
|
2255 |
-
get_label: function(name) {
|
2256 |
-
var lbls = this.get_labels();
|
2257 |
-
return ( name in lbls ) ? lbls[name] : '';
|
2258 |
-
},
|
2259 |
-
|
2260 |
-
/* Interactivity */
|
2261 |
-
|
2262 |
-
/**
|
2263 |
-
* Initialize event handlers upon opening lightbox
|
2264 |
-
*/
|
2265 |
-
events_open: function() {
|
2266 |
-
// Keyboard bindings
|
2267 |
-
this.keys_enable();
|
2268 |
-
if ( this.open ) {
|
2269 |
-
return false;
|
2270 |
-
}
|
2271 |
-
|
2272 |
-
// Control event bubbling
|
2273 |
-
var l = this.get_layout();
|
2274 |
-
l.children().click(function(ev) {
|
2275 |
-
ev.stopPropagation();
|
2276 |
-
});
|
2277 |
-
|
2278 |
-
/* Close */
|
2279 |
-
var v = this;
|
2280 |
-
var close = function() {
|
2281 |
-
v.close();
|
2282 |
-
};
|
2283 |
-
// Layout
|
2284 |
-
l.click(close);
|
2285 |
-
// Overlay
|
2286 |
-
this.get_overlay().click(close);
|
2287 |
-
// Fire event
|
2288 |
-
this.trigger('events-open');
|
2289 |
-
},
|
2290 |
-
|
2291 |
-
/**
|
2292 |
-
* Initialize event handlers upon completing lightbox rendering
|
2293 |
-
*/
|
2294 |
-
events_complete: function() {
|
2295 |
-
if ( this.init ) {
|
2296 |
-
return false;
|
2297 |
-
}
|
2298 |
-
// Fire event
|
2299 |
-
this.trigger('events-complete');
|
2300 |
-
},
|
2301 |
-
|
2302 |
-
keys_enable: function(mode) {
|
2303 |
-
if ( !this.util.is_bool(mode) ) {
|
2304 |
-
mode = true;
|
2305 |
-
}
|
2306 |
-
var e = ['keyup', this.util.get_prefix()].join('.');
|
2307 |
-
var v = this;
|
2308 |
-
var h = function(ev) {
|
2309 |
-
return v.keys_control(ev);
|
2310 |
-
};
|
2311 |
-
if ( mode ) {
|
2312 |
-
$(document).on(e, h);
|
2313 |
-
} else {
|
2314 |
-
$(document).off(e);
|
2315 |
-
}
|
2316 |
-
},
|
2317 |
-
|
2318 |
-
keys_disable: function() {
|
2319 |
-
this.keys_enable(false);
|
2320 |
-
},
|
2321 |
-
|
2322 |
-
keys_control: function(ev) {
|
2323 |
-
var handlers = {
|
2324 |
-
27: this.close, /* esc */
|
2325 |
-
37: this.item_prev, /* left-arrow */
|
2326 |
-
39: this.item_next, /* right-arrow */
|
2327 |
-
};
|
2328 |
-
// Swap next/prev keys on RTL pages
|
2329 |
-
if ('rtl' === document.documentElement.getAttribute('dir')) {
|
2330 |
-
handlers[37] = this.item_next; /* left-arrow */
|
2331 |
-
handlers[39] = this.item_prev; /* right-arrow */
|
2332 |
-
}
|
2333 |
-
if ( ev.which in handlers ) {
|
2334 |
-
handlers[ev.which].call(this);
|
2335 |
-
return false;
|
2336 |
-
}
|
2337 |
-
},
|
2338 |
-
|
2339 |
-
/**
|
2340 |
-
* Check if slideshow functionality is enabled
|
2341 |
-
* @return bool TRUE if slideshow is enabled, FALSE otherwise
|
2342 |
-
*/
|
2343 |
-
slideshow_enabled: function() {
|
2344 |
-
var o = this.get_attribute('slideshow_enabled');
|
2345 |
-
return ( this.util.is_bool(o) && o && this.get_item() && !this.get_item().get_group().is_single() ) ? true : false;
|
2346 |
-
},
|
2347 |
-
|
2348 |
-
/**
|
2349 |
-
* Checks if slideshow is currently active
|
2350 |
-
* @return bool TRUE if slideshow is active, FALSE otherwise
|
2351 |
-
*/
|
2352 |
-
slideshow_active: function() {
|
2353 |
-
return ( this.slideshow_enabled() && ( this.get_attribute('slideshow_active') || ( !this.init && this.get_attribute('slideshow_autostart') ) ) ) ? true : false;
|
2354 |
-
},
|
2355 |
-
|
2356 |
-
/**
|
2357 |
-
* Clear slideshow timer
|
2358 |
-
*/
|
2359 |
-
slideshow_clear_timer: function() {
|
2360 |
-
clearInterval(this.get_attribute('slideshow_timer'));
|
2361 |
-
},
|
2362 |
-
|
2363 |
-
/**
|
2364 |
-
* Start slideshow timer
|
2365 |
-
* @param function callback Callback function
|
2366 |
-
*/
|
2367 |
-
slideshow_set_timer: function(callback) {
|
2368 |
-
this.set_attribute('slideshow_timer', setInterval(callback, this.get_attribute('slideshow_duration') * 1000));
|
2369 |
-
},
|
2370 |
-
|
2371 |
-
/**
|
2372 |
-
* Start Slideshow
|
2373 |
-
*/
|
2374 |
-
slideshow_start: function() {
|
2375 |
-
if ( !this.slideshow_enabled() ) {
|
2376 |
-
return false;
|
2377 |
-
}
|
2378 |
-
this.set_attribute('slideshow_active', true);
|
2379 |
-
this.dom_get().addClass('slideshow_active');
|
2380 |
-
// Clear residual timers
|
2381 |
-
this.slideshow_clear_timer();
|
2382 |
-
// Start timer
|
2383 |
-
var v = this;
|
2384 |
-
this.slideshow_set_timer(function() {
|
2385 |
-
// Pause slideshow until next item fully loaded
|
2386 |
-
v.slideshow_pause();
|
2387 |
-
|
2388 |
-
// Show next item
|
2389 |
-
v.item_next();
|
2390 |
-
});
|
2391 |
-
this.trigger('slideshow-start');
|
2392 |
-
},
|
2393 |
-
|
2394 |
-
/**
|
2395 |
-
* Stop Slideshow
|
2396 |
-
* @param bool full (optional) Full stop (TRUE) or pause (FALSE) (Default: TRUE)
|
2397 |
-
*/
|
2398 |
-
slideshow_stop: function(full) {
|
2399 |
-
if ( !this.util.is_bool(full) ) {
|
2400 |
-
full = true;
|
2401 |
-
}
|
2402 |
-
if ( full ) {
|
2403 |
-
this.set_attribute('slideshow_active', false);
|
2404 |
-
this.dom_get().removeClass('slideshow_active');
|
2405 |
-
}
|
2406 |
-
// Kill timers
|
2407 |
-
this.slideshow_clear_timer();
|
2408 |
-
this.trigger('slideshow-stop');
|
2409 |
-
},
|
2410 |
-
|
2411 |
-
slideshow_toggle: function() {
|
2412 |
-
if ( !this.slideshow_enabled() ) {
|
2413 |
-
return false;
|
2414 |
-
}
|
2415 |
-
if ( this.slideshow_active() ) {
|
2416 |
-
this.slideshow_stop();
|
2417 |
-
} else {
|
2418 |
-
this.slideshow_start();
|
2419 |
-
}
|
2420 |
-
this.trigger('slideshow-toggle');
|
2421 |
-
},
|
2422 |
-
|
2423 |
-
/**
|
2424 |
-
* Pause Slideshow
|
2425 |
-
* @param bool mode (optional) Pause (TRUE) or Resume (FALSE) slideshow (default: TRUE)
|
2426 |
-
*/
|
2427 |
-
slideshow_pause: function(mode) {
|
2428 |
-
// Validate
|
2429 |
-
if ( !this.util.is_bool(mode) ) {
|
2430 |
-
mode = true;
|
2431 |
-
}
|
2432 |
-
// Set viewer slideshow properties
|
2433 |
-
if ( this.slideshow_active() ) {
|
2434 |
-
if ( !mode ) {
|
2435 |
-
// Slideshow resumed
|
2436 |
-
this.slideshow_start();
|
2437 |
-
} else {
|
2438 |
-
// Slideshow paused
|
2439 |
-
this.slideshow_stop(false);
|
2440 |
-
}
|
2441 |
-
}
|
2442 |
-
this.trigger('slideshow-pause');
|
2443 |
-
},
|
2444 |
-
|
2445 |
-
/**
|
2446 |
-
* Resume slideshow
|
2447 |
-
*/
|
2448 |
-
slideshow_resume: function() {
|
2449 |
-
this.slideshow_pause(false);
|
2450 |
-
},
|
2451 |
-
|
2452 |
-
/**
|
2453 |
-
* Next item
|
2454 |
-
*/
|
2455 |
-
item_next: function() {
|
2456 |
-
var g = this.get_item().get_group(true);
|
2457 |
-
var v = this;
|
2458 |
-
var ev = 'item-next';
|
2459 |
-
var st = ['events', 'viewer', ev].join('_');
|
2460 |
-
// Setup event handler
|
2461 |
-
if ( !g.get_status(st) ) {
|
2462 |
-
g.set_status(st);
|
2463 |
-
g.on(ev, function(e) {
|
2464 |
-
v.trigger(e.type);
|
2465 |
-
});
|
2466 |
-
}
|
2467 |
-
g.show_next();
|
2468 |
-
},
|
2469 |
-
|
2470 |
-
/**
|
2471 |
-
* Previous item
|
2472 |
-
*/
|
2473 |
-
item_prev: function() {
|
2474 |
-
var g = this.get_item().get_group(true);
|
2475 |
-
var v = this;
|
2476 |
-
var ev = 'item-prev';
|
2477 |
-
var st = ['events', 'viewer', ev].join('_');
|
2478 |
-
if ( !g.get_status(st) ) {
|
2479 |
-
g.set_status(st);
|
2480 |
-
g.on(ev, function() {
|
2481 |
-
v.trigger(ev);
|
2482 |
-
});
|
2483 |
-
}
|
2484 |
-
g.show_prev();
|
2485 |
-
},
|
2486 |
-
|
2487 |
-
/**
|
2488 |
-
* Close viewer
|
2489 |
-
*/
|
2490 |
-
close: function() {
|
2491 |
-
// Deactivate
|
2492 |
-
this.set_active(false);
|
2493 |
-
var v = this;
|
2494 |
-
var thm = this.get_theme();
|
2495 |
-
thm.transition('unload')
|
2496 |
-
.always(function() {
|
2497 |
-
thm.transition('close', true).always(function() {
|
2498 |
-
// End processes
|
2499 |
-
v.reset();
|
2500 |
-
v.trigger('close');
|
2501 |
-
});
|
2502 |
-
})
|
2503 |
-
.fail(function() {
|
2504 |
-
thm.dom_get_tag('item', 'content').attr('style', '');
|
2505 |
-
});
|
2506 |
-
return false;
|
2507 |
-
}
|
2508 |
-
};
|
2509 |
-
|
2510 |
-
View.Viewer = Component.extend(Viewer);
|
2511 |
-
|
2512 |
-
/**
|
2513 |
-
* Content group
|
2514 |
-
* @param obj options Init options
|
2515 |
-
*/
|
2516 |
-
var Group = {
|
2517 |
-
/* Configuration */
|
2518 |
-
|
2519 |
-
_slug: 'group',
|
2520 |
-
_reciprocal: true,
|
2521 |
-
_refs: {
|
2522 |
-
'current': 'Content_Item'
|
2523 |
-
},
|
2524 |
-
|
2525 |
-
/* References */
|
2526 |
-
|
2527 |
-
current: null,
|
2528 |
-
|
2529 |
-
/* Properties */
|
2530 |
-
|
2531 |
-
/**
|
2532 |
-
* Selector for getting group items
|
2533 |
-
* @var string
|
2534 |
-
*/
|
2535 |
-
selector: null,
|
2536 |
-
|
2537 |
-
/* Methods */
|
2538 |
-
|
2539 |
-
/* Init */
|
2540 |
-
|
2541 |
-
_hooks: function() {
|
2542 |
-
var t = this;
|
2543 |
-
this.on(['item-prev', 'item-next'], function() {
|
2544 |
-
t.trigger('item-change');
|
2545 |
-
});
|
2546 |
-
},
|
2547 |
-
|
2548 |
-
/* Properties */
|
2549 |
-
|
2550 |
-
/**
|
2551 |
-
* Retrieve selector for group items
|
2552 |
-
* @return string Group items selector
|
2553 |
-
*/
|
2554 |
-
get_selector: function() {
|
2555 |
-
if ( this.util.is_empty(this.selector) ) {
|
2556 |
-
// Build selector
|
2557 |
-
this.selector = this.util.format('a[%s="%s"]', this.dom_get_attribute(), this.get_id());
|
2558 |
-
}
|
2559 |
-
return this.selector;
|
2560 |
-
},
|
2561 |
-
|
2562 |
-
/**
|
2563 |
-
* Retrieve group items
|
2564 |
-
*/
|
2565 |
-
get_items: function() {
|
2566 |
-
var items = $(this.get_selector());
|
2567 |
-
if ( 0 === items.length && this.has_current() ) {
|
2568 |
-
items = this.get_current().dom_get();
|
2569 |
-
}
|
2570 |
-
return items;
|
2571 |
-
},
|
2572 |
-
|
2573 |
-
/**
|
2574 |
-
* Retrieve item at specified index
|
2575 |
-
* If no index specified, first item is returned
|
2576 |
-
* @param int idx Index of item to return
|
2577 |
-
* @return Content_Item Item
|
2578 |
-
*/
|
2579 |
-
get_item: function(idx) {
|
2580 |
-
// Validation
|
2581 |
-
if ( !this.util.is_int(idx) ) {
|
2582 |
-
idx = 0;
|
2583 |
-
}
|
2584 |
-
// Retrieve all items
|
2585 |
-
var items = this.get_items();
|
2586 |
-
// Validate index
|
2587 |
-
var max = this.get_size() - 1;
|
2588 |
-
if ( idx > max ) {
|
2589 |
-
idx = max;
|
2590 |
-
}
|
2591 |
-
// Return specified item
|
2592 |
-
return items.get(idx);
|
2593 |
-
},
|
2594 |
-
|
2595 |
-
/**
|
2596 |
-
* Retrieve (zero-based) position of specified item in group
|
2597 |
-
* @param Content_Item item Item to locate in group
|
2598 |
-
* @return int Index position of item in group (-1 if item not in group)
|
2599 |
-
*/
|
2600 |
-
get_pos: function(item) {
|
2601 |
-
if ( this.util.is_empty(item) ) {
|
2602 |
-
// Get current item
|
2603 |
-
item = this.get_current();
|
2604 |
-
}
|
2605 |
-
return ( this.util.is_type(item, View.Content_Item) ) ? this.get_items().index(item.dom_get()) : -1;
|
2606 |
-
},
|
2607 |
-
|
2608 |
-
/**
|
2609 |
-
* Check if current item set in group
|
2610 |
-
* @return bool TRUE if current item is set
|
2611 |
-
*/
|
2612 |
-
has_current: function() {
|
2613 |
-
// Sanitize
|
2614 |
-
return ( !this.util.is_empty( this.get_current() ) );
|
2615 |
-
},
|
2616 |
-
|
2617 |
-
/**
|
2618 |
-
* Retrieve current item
|
2619 |
-
* @uses Group.current
|
2620 |
-
* @return NULL|Content_Item Current item (NULL if current item not set or invalid)
|
2621 |
-
*/
|
2622 |
-
get_current: function() {
|
2623 |
-
// Sanitize
|
2624 |
-
if ( null !== this.current && !this.util.is_type(this.current, View.Content_Item) ) {
|
2625 |
-
this.current = null;
|
2626 |
-
}
|
2627 |
-
return this.current;
|
2628 |
-
},
|
2629 |
-
|
2630 |
-
/**
|
2631 |
-
* Sets current group item
|
2632 |
-
* @param Content_Item item Item to set as current
|
2633 |
-
*/
|
2634 |
-
set_current: function(item) {
|
2635 |
-
// Validate
|
2636 |
-
if ( this.util.is_type(item, View.Content_Item) ) {
|
2637 |
-
// Set current item
|
2638 |
-
this.current = item;
|
2639 |
-
}
|
2640 |
-
},
|
2641 |
-
|
2642 |
-
get_next: function(item) {
|
2643 |
-
// Validate
|
2644 |
-
if ( !this.util.is_type(item, View.Content_Item) ) {
|
2645 |
-
item = this.get_current();
|
2646 |
-
}
|
2647 |
-
if ( this.get_size() === 1 ) {
|
2648 |
-
return item;
|
2649 |
-
}
|
2650 |
-
var next = null;
|
2651 |
-
var pos = this.get_pos(item);
|
2652 |
-
if ( pos !== -1 ) {
|
2653 |
-
pos = ( pos + 1 < this.get_size() ) ? pos + 1 : 0;
|
2654 |
-
if ( 0 !== pos || item.get_viewer().get_attribute('loop') ) {
|
2655 |
-
next = this.get_item(pos);
|
2656 |
-
}
|
2657 |
-
}
|
2658 |
-
return next;
|
2659 |
-
},
|
2660 |
-
|
2661 |
-
get_prev: function(item) {
|
2662 |
-
// Validate
|
2663 |
-
if ( !this.util.is_type(item, View.Content_Item) ) {
|
2664 |
-
item = this.get_current();
|
2665 |
-
}
|
2666 |
-
if ( this.get_size() === 1 ) {
|
2667 |
-
return item;
|
2668 |
-
}
|
2669 |
-
var prev = null;
|
2670 |
-
var pos = this.get_pos(item);
|
2671 |
-
if ( pos !== -1 && ( 0 !== pos || item.get_viewer().get_attribute('loop') ) ) {
|
2672 |
-
if ( pos === 0 ) {
|
2673 |
-
pos = this.get_size();
|
2674 |
-
}
|
2675 |
-
pos -= 1;
|
2676 |
-
prev = this.get_item(pos);
|
2677 |
-
}
|
2678 |
-
return prev;
|
2679 |
-
},
|
2680 |
-
|
2681 |
-
show_next: function(item) {
|
2682 |
-
if ( this.get_size() > 1 ) {
|
2683 |
-
// Retrieve item
|
2684 |
-
var next = this.get_next(item);
|
2685 |
-
if ( !next ) {
|
2686 |
-
if ( !this.util.is_type(item, View.Content_Item) ) {
|
2687 |
-
item = this.get_current();
|
2688 |
-
}
|
2689 |
-
item.get_viewer().close();
|
2690 |
-
}
|
2691 |
-
var i = this.get_controller().get_item(next);
|
2692 |
-
// Update current item
|
2693 |
-
this.set_current(i);
|
2694 |
-
// Show item
|
2695 |
-
i.show();
|
2696 |
-
// Fire event
|
2697 |
-
this.trigger('item-next');
|
2698 |
-
}
|
2699 |
-
},
|
2700 |
-
|
2701 |
-
show_prev: function(item) {
|
2702 |
-
if ( this.get_size() > 1 ) {
|
2703 |
-
// Retrieve item
|
2704 |
-
var prev = this.get_prev(item);
|
2705 |
-
if ( !prev ) {
|
2706 |
-
if ( !this.util.is_type(item, View.Content_Item) ) {
|
2707 |
-
item = this.get_current();
|
2708 |
-
}
|
2709 |
-
item.get_viewer().close();
|
2710 |
-
}
|
2711 |
-
var i = this.get_controller().get_item(prev);
|
2712 |
-
// Update current item
|
2713 |
-
this.set_current(i);
|
2714 |
-
// Show item
|
2715 |
-
i.show();
|
2716 |
-
// Fire event
|
2717 |
-
this.trigger('item-prev');
|
2718 |
-
}
|
2719 |
-
},
|
2720 |
-
|
2721 |
-
/**
|
2722 |
-
* Retrieve total number of items in group
|
2723 |
-
* @return int Number of items in group
|
2724 |
-
*/
|
2725 |
-
get_size: function() {
|
2726 |
-
return this.get_items().length;
|
2727 |
-
},
|
2728 |
-
|
2729 |
-
is_single: function() {
|
2730 |
-
return ( this.get_size() === 1 );
|
2731 |
-
}
|
2732 |
-
};
|
2733 |
-
|
2734 |
-
View.Group = Component.extend(Group);
|
2735 |
-
|
2736 |
-
/**
|
2737 |
-
* Content Handler
|
2738 |
-
* @param obj options Init options
|
2739 |
-
*/
|
2740 |
-
var Content_Handler = {
|
2741 |
-
|
2742 |
-
/* Configuration */
|
2743 |
-
|
2744 |
-
_slug: 'content_handler',
|
2745 |
-
_refs: {
|
2746 |
-
'item': 'Content_Item'
|
2747 |
-
},
|
2748 |
-
|
2749 |
-
/* References */
|
2750 |
-
|
2751 |
-
item: null,
|
2752 |
-
|
2753 |
-
/* Properties */
|
2754 |
-
|
2755 |
-
/**
|
2756 |
-
* Raw layout template
|
2757 |
-
* @var string
|
2758 |
-
*/
|
2759 |
-
template: '',
|
2760 |
-
|
2761 |
-
/* Methods */
|
2762 |
-
|
2763 |
-
/* Item */
|
2764 |
-
|
2765 |
-
/**
|
2766 |
-
* Check if item instance set for type
|
2767 |
-
* @uses get_item()
|
2768 |
-
* @uses clear_item() to remove invalid item values
|
2769 |
-
* @return bool TRUE if valid item set, FALSE otherwise
|
2770 |
-
*/
|
2771 |
-
has_item: function() {
|
2772 |
-
return ( this.util.is_empty(this.get_item()) ) ? false : true;
|
2773 |
-
},
|
2774 |
-
|
2775 |
-
/**
|
2776 |
-
* Retrieve item instance set on type
|
2777 |
-
* @uses get_component()
|
2778 |
-
* @return mixed Content_Item if valid item set, NULL otherwise
|
2779 |
-
*/
|
2780 |
-
get_item: function() {
|
2781 |
-
return this.get_component('item');
|
2782 |
-
},
|
2783 |
-
|
2784 |
-
/**
|
2785 |
-
* Set item instance for type
|
2786 |
-
* Items are only meant to be set/used while item is being processed
|
2787 |
-
* @uses set_component()
|
2788 |
-
* @param Content_Item item Item instance
|
2789 |
-
* @return obj|null Item instance if item successfully set, NULL otherwise
|
2790 |
-
*/
|
2791 |
-
set_item: function(item) {
|
2792 |
-
// Set reference
|
2793 |
-
var r = this.set_component('item', item);
|
2794 |
-
return r;
|
2795 |
-
},
|
2796 |
-
|
2797 |
-
/**
|
2798 |
-
* Clear item instance from type
|
2799 |
-
* Sets value to NULL
|
2800 |
-
*/
|
2801 |
-
clear_item: function() {
|
2802 |
-
this.clear_component('item');
|
2803 |
-
},
|
2804 |
-
|
2805 |
-
/* Evaluation */
|
2806 |
-
|
2807 |
-
/**
|
2808 |
-
* Check if item matches content handler
|
2809 |
-
* @param object item Content_Item instance to check for type match
|
2810 |
-
* @return bool TRUE if type matches, FALSE otherwise
|
2811 |
-
*/
|
2812 |
-
match: function(item) {
|
2813 |
-
// Validate
|
2814 |
-
var attr = 'match';
|
2815 |
-
var m = this.get_attribute(attr);
|
2816 |
-
// Stop processing types with no matching algorithm
|
2817 |
-
if ( !this.util.is_empty(m) ) {
|
2818 |
-
// Process regex patterns
|
2819 |
-
|
2820 |
-
// String-based
|
2821 |
-
if ( this.util.is_string(m) ) {
|
2822 |
-
// Create new regexp object
|
2823 |
-
m = new RegExp(m, "i");
|
2824 |
-
this.set_attribute(attr, m);
|
2825 |
-
}
|
2826 |
-
// RegExp based
|
2827 |
-
if ( this.util.is_type(m, RegExp) ) {
|
2828 |
-
return m.test(item.get_uri());
|
2829 |
-
}
|
2830 |
-
// Process function
|
2831 |
-
if ( this.util.is_func(m) ) {
|
2832 |
-
return ( m.call(this, item) ) ? true : false;
|
2833 |
-
}
|
2834 |
-
}
|
2835 |
-
// Default
|
2836 |
-
return false;
|
2837 |
-
},
|
2838 |
-
|
2839 |
-
/* Processing/Output */
|
2840 |
-
|
2841 |
-
/**
|
2842 |
-
* Loads item data
|
2843 |
-
* @param obj item Content item to load data for
|
2844 |
-
* @return obj Promise that is resolved when item data is loaded
|
2845 |
-
*/
|
2846 |
-
load: function(item) {
|
2847 |
-
var dfr = $.Deferred();
|
2848 |
-
var ret = this.call_attribute('load', item, dfr);
|
2849 |
-
// Handle missing load method
|
2850 |
-
if ( null === ret ) {
|
2851 |
-
dfr.resolve();
|
2852 |
-
}
|
2853 |
-
return dfr.promise();
|
2854 |
-
},
|
2855 |
-
|
2856 |
-
/**
|
2857 |
-
* Render output to display item
|
2858 |
-
* @param Content_Item item Item to render output for
|
2859 |
-
* @return obj jQuery.Promise that is resolved when item is rendered
|
2860 |
-
*/
|
2861 |
-
render: function(item) {
|
2862 |
-
var dfr = $.Deferred();
|
2863 |
-
// Validate
|
2864 |
-
this.call_attribute('render', item, dfr);
|
2865 |
-
return dfr.promise();
|
2866 |
-
}
|
2867 |
-
};
|
2868 |
-
|
2869 |
-
View.Content_Handler = Component.extend(Content_Handler);
|
2870 |
-
|
2871 |
-
/**
|
2872 |
-
* Content Item
|
2873 |
-
* @param obj options Init options
|
2874 |
-
*/
|
2875 |
-
var Content_Item = {
|
2876 |
-
/* Configuration */
|
2877 |
-
|
2878 |
-
_slug: 'content_item',
|
2879 |
-
_reciprocal: true,
|
2880 |
-
_refs: {
|
2881 |
-
'viewer': 'Viewer',
|
2882 |
-
'group': 'Group',
|
2883 |
-
'type': 'Content_Handler'
|
2884 |
-
},
|
2885 |
-
|
2886 |
-
_attr_default: {
|
2887 |
-
source: null,
|
2888 |
-
permalink: null,
|
2889 |
-
dimensions: null,
|
2890 |
-
title: '',
|
2891 |
-
group: null,
|
2892 |
-
internal: false,
|
2893 |
-
output: null
|
2894 |
-
},
|
2895 |
-
|
2896 |
-
/* References */
|
2897 |
-
|
2898 |
-
group: null,
|
2899 |
-
viewer: null,
|
2900 |
-
type: null,
|
2901 |
-
|
2902 |
-
/* Properties */
|
2903 |
-
|
2904 |
-
data: null,
|
2905 |
-
loaded: null,
|
2906 |
-
|
2907 |
-
/* Init */
|
2908 |
-
|
2909 |
-
_c: function(el) {
|
2910 |
-
// Save element to instance
|
2911 |
-
this.dom_set(el);
|
2912 |
-
// Default initialization
|
2913 |
-
this._super();
|
2914 |
-
},
|
2915 |
-
|
2916 |
-
/* Methods */
|
2917 |
-
|
2918 |
-
/*-** Attributes **-*/
|
2919 |
-
|
2920 |
-
/**
|
2921 |
-
* Build default attributes
|
2922 |
-
* Populates attributes with asset properties (attachments)
|
2923 |
-
* Overrides super class method
|
2924 |
-
* @uses Component.init_default_attributes()
|
2925 |
-
*/
|
2926 |
-
init_default_attributes: function() {
|
2927 |
-
this._super();
|
2928 |
-
// Add asset properties
|
2929 |
-
var d = this.dom_get();
|
2930 |
-
var key = d.attr(this.util.get_attribute('asset')) || null;
|
2931 |
-
var assets = this.get_controller().assets || null;
|
2932 |
-
// Merge asset data with default attributes
|
2933 |
-
if ( this.util.is_string(key) ) {
|
2934 |
-
var attrs = [{}, this._attr_default, {'permalink': d.attr('href')}];
|
2935 |
-
if ( this.util.is_obj(assets) ) {
|
2936 |
-
var t = this;
|
2937 |
-
/**
|
2938 |
-
* Retrieve item assets
|
2939 |
-
* Handles variant items as well (Retrieves parent item assets)
|
2940 |
-
* @param string key Item URI
|
2941 |
-
* @return obj Item assets (Empty if no match)
|
2942 |
-
*/
|
2943 |
-
var get_assets = function(key) {
|
2944 |
-
var ret = {};
|
2945 |
-
if ( key in assets && t.util.is_obj(assets[key]) ) {
|
2946 |
-
ret = assets[key];
|
2947 |
-
}
|
2948 |
-
return ret;
|
2949 |
-
};
|
2950 |
-
// Save assets
|
2951 |
-
attrs.push(get_assets(key));
|
2952 |
-
}
|
2953 |
-
this._attr_default = $.extend.apply(this, attrs);
|
2954 |
-
}
|
2955 |
-
return this._attr_default;
|
2956 |
-
},
|
2957 |
-
|
2958 |
-
/*-** Properties **-*/
|
2959 |
-
|
2960 |
-
/**
|
2961 |
-
* Retrieve item output
|
2962 |
-
* Output generated based on content handler if not previously generated
|
2963 |
-
* @uses get_attribute() to retrieve cached output
|
2964 |
-
* @uses set_attribute() to cache generated output
|
2965 |
-
* @uses get_type() to retrieve item type
|
2966 |
-
* @uses Content_Handler.render() to generate item output
|
2967 |
-
* @return obj jQuery.Promise that is resolved when output is retrieved
|
2968 |
-
*/
|
2969 |
-
get_output: function() {
|
2970 |
-
var dfr = $.Deferred();
|
2971 |
-
// Check for cached output
|
2972 |
-
var ret = this.get_attribute('output');
|
2973 |
-
if ( this.util.is_string(ret) ) {
|
2974 |
-
dfr.resolve(ret);
|
2975 |
-
} else if ( this.has_type() ) {
|
2976 |
-
// Render output from scratch (if necessary)
|
2977 |
-
// Get item type
|
2978 |
-
var type = this.get_type();
|
2979 |
-
// Render type-based output
|
2980 |
-
var item = this;
|
2981 |
-
type.render(this).done(function(output) {
|
2982 |
-
// Cache output
|
2983 |
-
item.set_output(output);
|
2984 |
-
dfr.resolve(output);
|
2985 |
-
});
|
2986 |
-
} else {
|
2987 |
-
dfr.resolve('');
|
2988 |
-
}
|
2989 |
-
return dfr.promise();
|
2990 |
-
},
|
2991 |
-
|
2992 |
-
/**
|
2993 |
-
* Cache output for future retrieval
|
2994 |
-
* @uses set_attribute() to cache output
|
2995 |
-
*/
|
2996 |
-
set_output: function(out) {
|
2997 |
-
if ( this.util.is_string(out, false) ) {
|
2998 |
-
this.set_attribute('output', out);
|
2999 |
-
}
|
3000 |
-
},
|
3001 |
-
|
3002 |
-
/**
|
3003 |
-
* Retrieve item output
|
3004 |
-
* Alias for `get_output()`
|
3005 |
-
* @return jQuery.Promise Deferred that is resolved when content is retrieved
|
3006 |
-
*/
|
3007 |
-
get_content: function() {
|
3008 |
-
return this.get_output();
|
3009 |
-
},
|
3010 |
-
|
3011 |
-
/**
|
3012 |
-
* Retrieve item URI
|
3013 |
-
* @param string mode (optional) Which URI should be retrieved
|
3014 |
-
* > source: Media source
|
3015 |
-
* > permalink: Item permalink
|
3016 |
-
* @return string Item URI
|
3017 |
-
*/
|
3018 |
-
get_uri: function(mode) {
|
3019 |
-
// Validate
|
3020 |
-
if ( $.inArray(mode ,['source', 'permalink']) === -1 ) {
|
3021 |
-
mode = 'source';
|
3022 |
-
}
|
3023 |
-
// Retrieve URI
|
3024 |
-
var ret = this.get_attribute(mode);
|
3025 |
-
if ( !this.util.is_string(ret) ) {
|
3026 |
-
ret = ( 'source' === mode ) ? this.get_attribute('permalink') : '';
|
3027 |
-
}
|
3028 |
-
// Format
|
3029 |
-
ret = ret.replace(/&(#38|amp);/, '&');
|
3030 |
-
return ret;
|
3031 |
-
},
|
3032 |
-
|
3033 |
-
/**
|
3034 |
-
* Retrieve item title
|
3035 |
-
*/
|
3036 |
-
get_title: function() {
|
3037 |
-
var prop = 'title';
|
3038 |
-
var prop_cached = prop + '_cached';
|
3039 |
-
// Check for cached value
|
3040 |
-
if ( this.has_attribute(prop_cached) ) {
|
3041 |
-
return this.get_attribute(prop_cached, '');
|
3042 |
-
}
|
3043 |
-
|
3044 |
-
var title = '';
|
3045 |
-
// Generate title from DOM values
|
3046 |
-
var dom = this.dom_get();
|
3047 |
-
var t = this;
|
3048 |
-
/**
|
3049 |
-
* Validate title value.
|
3050 |
-
*
|
3051 |
-
* Removes default title based on user option.
|
3052 |
-
*
|
3053 |
-
* @param string title Title to check.
|
3054 |
-
* @return string Current title or empty string (if default title set and not permitted).
|
3055 |
-
*/
|
3056 |
-
var validate = function(title) {
|
3057 |
-
// Return empty string if empty title set.
|
3058 |
-
if ( typeof title !== 'string' || '' === title.trim() ) {
|
3059 |
-
return '';
|
3060 |
-
}
|
3061 |
-
// Cleanup title.
|
3062 |
-
title = title.trim();
|
3063 |
-
// Stop processing if default title is allowed.
|
3064 |
-
if ( t.get_viewer().get_attribute('title_default') ) {
|
3065 |
-
return title;
|
3066 |
-
}
|
3067 |
-
|
3068 |
-
// Check if default title is used.
|
3069 |
-
if ( title === t.get_title_default() ) {
|
3070 |
-
title = '';
|
3071 |
-
}
|
3072 |
-
return title;
|
3073 |
-
};
|
3074 |
-
|
3075 |
-
// DOM-based caption
|
3076 |
-
if ( dom.length ) {
|
3077 |
-
// Link title (generally must be manually-entered)
|
3078 |
-
title = dom.attr(prop);
|
3079 |
-
|
3080 |
-
// Figcaption element
|
3081 |
-
if ( !title ) {
|
3082 |
-
title = dom.closest('figure').find('figcaption').first().html();
|
3083 |
-
}
|
3084 |
-
|
3085 |
-
// Class Name
|
3086 |
-
if ( !title ) {
|
3087 |
-
title = dom.closest('figure').find('.wp-caption-text').first().html();
|
3088 |
-
}
|
3089 |
-
}
|
3090 |
-
|
3091 |
-
// Saved attributes
|
3092 |
-
if ( !title ) {
|
3093 |
-
var props = ['caption', 'title'];
|
3094 |
-
for ( var x = 0; x < props.length; x++ ) {
|
3095 |
-
title = validate( this.get_attribute(props[x], '') );
|
3096 |
-
if ( !this.util.is_empty(title) ) {
|
3097 |
-
break;
|
3098 |
-
}
|
3099 |
-
}
|
3100 |
-
}
|
3101 |
-
|
3102 |
-
// Fallbacks
|
3103 |
-
if ( !title && dom.length ) {
|
3104 |
-
// Image Alt attribute
|
3105 |
-
title = validate( dom.find('img').first().attr('alt') );
|
3106 |
-
|
3107 |
-
// Element text
|
3108 |
-
if ( !title ) {
|
3109 |
-
title = validate( dom.get(0).innerText.trim() );
|
3110 |
-
}
|
3111 |
-
}
|
3112 |
-
|
3113 |
-
// Final validation.
|
3114 |
-
title = validate(title);
|
3115 |
-
|
3116 |
-
// Cache retrieved value
|
3117 |
-
this.set_attribute(prop_cached, title);
|
3118 |
-
// Return value
|
3119 |
-
return title;
|
3120 |
-
},
|
3121 |
-
|
3122 |
-
/**
|
3123 |
-
* Retrieve default title.
|
3124 |
-
*
|
3125 |
-
* WordPress-generated default title for attachments is base file name (without extension).
|
3126 |
-
*
|
3127 |
-
* @return string Default title.
|
3128 |
-
*/
|
3129 |
-
get_title_default: function() {
|
3130 |
-
var val = '';
|
3131 |
-
var prop = 'title_default';
|
3132 |
-
// Build default title if necessary.
|
3133 |
-
if ( !this.has_attribute(prop) ) {
|
3134 |
-
var f = this.get_uri('source');
|
3135 |
-
var i = f.lastIndexOf('/');
|
3136 |
-
if ( -1 !== i ) {
|
3137 |
-
f = f.substr(i + 1);
|
3138 |
-
i = f.lastIndexOf('.');
|
3139 |
-
if ( -1 !== i ) {
|
3140 |
-
f = f.substr(0, i);
|
3141 |
-
}
|
3142 |
-
}
|
3143 |
-
// Save default title
|
3144 |
-
val = this.set_attribute(prop, f);
|
3145 |
-
} else {
|
3146 |
-
val = this.get_attribute(prop);
|
3147 |
-
}
|
3148 |
-
return val;
|
3149 |
-
},
|
3150 |
-
|
3151 |
-
/**
|
3152 |
-
* Retrieve item dimensions
|
3153 |
-
* @return obj Item `width` and `height` properties (px)
|
3154 |
-
*/
|
3155 |
-
get_dimensions: function() {
|
3156 |
-
return $.extend({'width': 0, 'height': 0}, this.get_attribute('dimensions'), {});
|
3157 |
-
},
|
3158 |
-
|
3159 |
-
/**
|
3160 |
-
* Save item data to instance
|
3161 |
-
* Item data is saved when rendered
|
3162 |
-
* @param mixed data Item data (property cleared if NULL)
|
3163 |
-
*/
|
3164 |
-
set_data: function(data) {
|
3165 |
-
this.data = data;
|
3166 |
-
},
|
3167 |
-
|
3168 |
-
get_data: function() {
|
3169 |
-
return this.data;
|
3170 |
-
},
|
3171 |
-
|
3172 |
-
/**
|
3173 |
-
* Determine gallery type
|
3174 |
-
* @return string|null Gallery type ID (NULL if item not in gallery)
|
3175 |
-
*/
|
3176 |
-
gallery_type: function() {
|
3177 |
-
var ret = null;
|
3178 |
-
var types = {
|
3179 |
-
'wp': '.gallery-icon',
|
3180 |
-
'ngg': '.ngg-gallery-thumbnail'
|
3181 |
-
};
|
3182 |
-
|
3183 |
-
var dom = this.dom_get();
|
3184 |
-
for ( var type in types ) {
|
3185 |
-
if ( dom.parent(types[type]).length > 0 ) {
|
3186 |
-
ret = type;
|
3187 |
-
break;
|
3188 |
-
}
|
3189 |
-
}
|
3190 |
-
return ret;
|
3191 |
-
},
|
3192 |
-
|
3193 |
-
/**
|
3194 |
-
* Check if current link is part of a gallery
|
3195 |
-
* @param string gType (optional) Gallery type to check for
|
3196 |
-
* @return bool TRUE if link is part of (specified) gallery (FALSE otherwise)
|
3197 |
-
*/
|
3198 |
-
in_gallery: function(gType) {
|
3199 |
-
var type = this.gallery_type();
|
3200 |
-
// No gallery
|
3201 |
-
if ( null === type ) {
|
3202 |
-
return false;
|
3203 |
-
}
|
3204 |
-
// Boolean check
|
3205 |
-
if ( !this.util.is_string(gType) ) {
|
3206 |
-
return true;
|
3207 |
-
}
|
3208 |
-
// Check for specific gallery type
|
3209 |
-
return ( gType === type ) ? true : false;
|
3210 |
-
},
|
3211 |
-
|
3212 |
-
/*-** Component References **-*/
|
3213 |
-
|
3214 |
-
/* Viewer */
|
3215 |
-
|
3216 |
-
get_viewer: function() {
|
3217 |
-
return this.get_component('viewer', {get_default: true});
|
3218 |
-
},
|
3219 |
-
|
3220 |
-
/**
|
3221 |
-
* Sets item's viewer property
|
3222 |
-
* @uses View.get_viewer() to retrieve global viewer
|
3223 |
-
* @uses this.viewer to save item's viewer
|
3224 |
-
* @param string|View.Viewer v Viewer to set for item
|
3225 |
-
* > Item's viewer is reset if invalid viewer provided
|
3226 |
-
*/
|
3227 |
-
set_viewer: function(v) {
|
3228 |
-
return this.set_component('viewer', v);
|
3229 |
-
},
|
3230 |
-
|
3231 |
-
/* Group */
|
3232 |
-
|
3233 |
-
/**
|
3234 |
-
* Retrieve item's group
|
3235 |
-
* @param bool set_current (optional) Sets item as current item in group (Default: FALSE)
|
3236 |
-
* @return View.Group|bool Group reference item belongs to (FALSE if no group)
|
3237 |
-
*/
|
3238 |
-
get_group: function(set_current) {
|
3239 |
-
var prop = 'group';
|
3240 |
-
// Check if group reference already set
|
3241 |
-
var g = this.get_component(prop);
|
3242 |
-
if ( g ) {
|
3243 |
-
} else {
|
3244 |
-
// Set empty group if no group exists
|
3245 |
-
g = this.set_component(prop, new View.Group());
|
3246 |
-
set_current = true;
|
3247 |
-
}
|
3248 |
-
if ( !!set_current ) {
|
3249 |
-
g.set_current(this);
|
3250 |
-
}
|
3251 |
-
return g;
|
3252 |
-
},
|
3253 |
-
|
3254 |
-
/**
|
3255 |
-
* Sets item's group property
|
3256 |
-
* @uses View.get_group() to retrieve global group
|
3257 |
-
* @uses this.group to set item's group
|
3258 |
-
* @param string|View.Group g Group to set for item
|
3259 |
-
* > Item's group is reset if invalid group provided
|
3260 |
-
*/
|
3261 |
-
set_group: function(g) {
|
3262 |
-
// If group ID set, get object reference
|
3263 |
-
if ( this.util.is_string(g) ) {
|
3264 |
-
g = this.get_controller().get_group(g);
|
3265 |
-
}
|
3266 |
-
|
3267 |
-
// Set (or clear) group property
|
3268 |
-
this.group = ( this.util.is_type(g, View.Group) ) ? g : false;
|
3269 |
-
},
|
3270 |
-
|
3271 |
-
/* Content Handler */
|
3272 |
-
|
3273 |
-
/**
|
3274 |
-
* Retrieve item type
|
3275 |
-
* @uses get_component() to retrieve saved reference to Content_Handler instance
|
3276 |
-
* @uses View.get_content_handler() to determine item content handler (if necessary)
|
3277 |
-
* @return Content_Handler|null Content Handler of item (NULL no valid type exists)
|
3278 |
-
*/
|
3279 |
-
get_type: function() {
|
3280 |
-
var t = this.get_component('type', {check_attr: false});
|
3281 |
-
if ( !t ) {
|
3282 |
-
t = this.set_type(this.get_controller().get_content_handler(this));
|
3283 |
-
}
|
3284 |
-
return t;
|
3285 |
-
},
|
3286 |
-
|
3287 |
-
/**
|
3288 |
-
* Save content handler reference
|
3289 |
-
* @uses set_component() to save type reference
|
3290 |
-
* @return Content_Handler|null Saved content handler (NULL if invalid)
|
3291 |
-
*/
|
3292 |
-
set_type: function(type) {
|
3293 |
-
return this.set_component('type', type);
|
3294 |
-
},
|
3295 |
-
|
3296 |
-
/**
|
3297 |
-
* Check if content handler exists for item
|
3298 |
-
* @return bool TRUE if content handler exists, FALSE otherwise
|
3299 |
-
*/
|
3300 |
-
has_type: function() {
|
3301 |
-
var ret = !this.util.is_empty(this.get_type());
|
3302 |
-
return ret;
|
3303 |
-
},
|
3304 |
-
|
3305 |
-
/* Actions */
|
3306 |
-
|
3307 |
-
/**
|
3308 |
-
* Display item in viewer
|
3309 |
-
* @uses get_viewer() to retrieve viewer instance for item
|
3310 |
-
* @uses Viewer.show() to display item in viewer
|
3311 |
-
* @param obj options (optional) Options
|
3312 |
-
*/
|
3313 |
-
show: function(options) {
|
3314 |
-
// Validate content handler
|
3315 |
-
if ( !this.has_type() ) {
|
3316 |
-
return false;
|
3317 |
-
}
|
3318 |
-
// Set display options
|
3319 |
-
this.set_attribute('options_show', options);
|
3320 |
-
// Retrieve viewer
|
3321 |
-
var v = this.get_viewer();
|
3322 |
-
// Load item
|
3323 |
-
this.load();
|
3324 |
-
var ret = v.show(this);
|
3325 |
-
return ret;
|
3326 |
-
},
|
3327 |
-
|
3328 |
-
/**
|
3329 |
-
* Load item data
|
3330 |
-
*
|
3331 |
-
* Retrieves item data from external sources (if necessary)
|
3332 |
-
* @uses this.loaded to save loaded state
|
3333 |
-
* @return obj Promise that is resolved when item data is loaded
|
3334 |
-
*/
|
3335 |
-
load: function() {
|
3336 |
-
if ( !this.util.is_promise(this.loaded) ) {
|
3337 |
-
// Load item data (via content handler)
|
3338 |
-
this.loaded = this.get_type().load(this);
|
3339 |
-
}
|
3340 |
-
return this.loaded.promise();
|
3341 |
-
},
|
3342 |
-
|
3343 |
-
reset: function() {
|
3344 |
-
this.set_attribute('options_show', null);
|
3345 |
-
}
|
3346 |
-
};
|
3347 |
-
|
3348 |
-
View.Content_Item = Component.extend(Content_Item);
|
3349 |
-
|
3350 |
-
/**
|
3351 |
-
* Modeled Component
|
3352 |
-
*/
|
3353 |
-
var Modeled_Component = {
|
3354 |
-
|
3355 |
-
_slug: 'modeled_component',
|
3356 |
-
|
3357 |
-
/* Methods */
|
3358 |
-
|
3359 |
-
/* Attributes */
|
3360 |
-
|
3361 |
-
/**
|
3362 |
-
* Retrieve attribute
|
3363 |
-
* Gives priority to model values
|
3364 |
-
* @see Component.get_attribute()
|
3365 |
-
* @param string key Attribute to retrieve
|
3366 |
-
* @param mixed def (optional) Default value (Default: NULL)
|
3367 |
-
* @param bool check_model (optional) Check model for value (Default: TRUE)
|
3368 |
-
* @param bool enforce_type (optional) Return value data type should match default value data type (Default: TRUE)
|
3369 |
-
* @return mixed Attribute value
|
3370 |
-
*/
|
3371 |
-
get_attribute: function(key, def, check_model, enforce_type) {
|
3372 |
-
// Validate
|
3373 |
-
if ( !this.util.is_string(key) ) {
|
3374 |
-
// Invalid requests sent straight to super method
|
3375 |
-
return this._super(key, def, enforce_type);
|
3376 |
-
}
|
3377 |
-
if ( !this.util.is_bool(check_model) ) {
|
3378 |
-
check_model = true;
|
3379 |
-
}
|
3380 |
-
var ret = null;
|
3381 |
-
// Check model for attribute
|
3382 |
-
if ( check_model ) {
|
3383 |
-
var m = this.get_ancestor(key, false);
|
3384 |
-
if ( this.util.in_obj(m, key) ) {
|
3385 |
-
ret = m[key];
|
3386 |
-
}
|
3387 |
-
}
|
3388 |
-
// Check standard attributes as fallback
|
3389 |
-
if ( null === ret ) {
|
3390 |
-
ret = this._super(key, def, enforce_type);
|
3391 |
-
}
|
3392 |
-
return ret;
|
3393 |
-
},
|
3394 |
-
|
3395 |
-
/**
|
3396 |
-
* Get attribute recursively
|
3397 |
-
* Merges objects from ancestors together
|
3398 |
-
* @see Component.get_attribute() for more information
|
3399 |
-
*/
|
3400 |
-
get_attribute_recursive: function(key, def, enforce_type) {
|
3401 |
-
var ret = this.get_attribute(key, def, true, enforce_type);
|
3402 |
-
if ( this.util.is_obj(ret) ) {
|
3403 |
-
// Merge ancestor objects
|
3404 |
-
var models = this.get_ancestors(false);
|
3405 |
-
ret = [ret];
|
3406 |
-
var t = this;
|
3407 |
-
$.each(models, function(idx, model) {
|
3408 |
-
if ( key in model && t.util.is_obj(model[key]) ) {
|
3409 |
-
ret.push(model[key]);
|
3410 |
-
}
|
3411 |
-
});
|
3412 |
-
// Merge transition handlers into current theme
|
3413 |
-
ret.push({});
|
3414 |
-
ret = $.extend.apply($, ret.reverse());
|
3415 |
-
}
|
3416 |
-
return ret;
|
3417 |
-
},
|
3418 |
-
|
3419 |
-
/**
|
3420 |
-
* Set attribute value
|
3421 |
-
* Gives priority to model values
|
3422 |
-
* @see Component.set_attribute()
|
3423 |
-
* @param string key Attribute to set
|
3424 |
-
* @param mixed val Value to set for attribute
|
3425 |
-
* @param bool|obj use_model (optional) Set the value on the model (Default: TRUE)
|
3426 |
-
* > bool: Set attribute on current model (TRUE) or as standard attribute (FALSE)
|
3427 |
-
* > obj: Model object to set attribute on
|
3428 |
-
* @return mixed Attribute value
|
3429 |
-
*/
|
3430 |
-
set_attribute: function(key, val, use_model) {
|
3431 |
-
// Validate
|
3432 |
-
if ( ( !this.util.is_string(key) ) || !this.util.is_set(val) ) {
|
3433 |
-
return false;
|
3434 |
-
}
|
3435 |
-
if ( !this.util.is_bool(use_model) && !this.util.is_obj(use_model) ) {
|
3436 |
-
use_model = true;
|
3437 |
-
}
|
3438 |
-
// Determine where to set attribute
|
3439 |
-
if ( !!use_model ) {
|
3440 |
-
var model = this.util.is_obj(use_model) ? use_model : this.get_model();
|
3441 |
-
|
3442 |
-
// Set attribute in model
|
3443 |
-
model[key] = val;
|
3444 |
-
} else {
|
3445 |
-
// Set as standard attribute
|
3446 |
-
this._super(key, val);
|
3447 |
-
}
|
3448 |
-
return val;
|
3449 |
-
},
|
3450 |
-
|
3451 |
-
|
3452 |
-
/* Model */
|
3453 |
-
|
3454 |
-
/**
|
3455 |
-
* Retrieve Template model
|
3456 |
-
* @return obj Model (Default: Empty object)
|
3457 |
-
*/
|
3458 |
-
get_model: function() {
|
3459 |
-
var m = this.get_attribute('model', null, false);
|
3460 |
-
if ( !this.util.is_obj(m) ) {
|
3461 |
-
// Set default value
|
3462 |
-
m = {};
|
3463 |
-
this.set_attribute('model', m, false);
|
3464 |
-
}
|
3465 |
-
return m;
|
3466 |
-
},
|
3467 |
-
|
3468 |
-
|
3469 |
-
/**
|
3470 |
-
* Check if instance has model
|
3471 |
-
* @return bool TRUE if model is set, FALSE otherwise
|
3472 |
-
*/
|
3473 |
-
has_model: function() {
|
3474 |
-
return ( this.util.is_empty( this.get_model() ) ) ? false : true;
|
3475 |
-
},
|
3476 |
-
|
3477 |
-
|
3478 |
-
|
3479 |
-
/**
|
3480 |
-
* Check if specified attribute exists in model
|
3481 |
-
* @param string key Attribute to check for
|
3482 |
-
* @return bool TRUE if attribute exists, FALSE otherwise
|
3483 |
-
*/
|
3484 |
-
in_model: function(key) {
|
3485 |
-
return ( this.util.in_obj(this.get_model(), key) ) ? true : false;
|
3486 |
-
},
|
3487 |
-
|
3488 |
-
/**
|
3489 |
-
* Retrieve all ancestor models
|
3490 |
-
* @param bool inc_current (optional) Include current model in list (Default: FALSE)
|
3491 |
-
* @return array Theme ancestor models (Closest parent first)
|
3492 |
-
*/
|
3493 |
-
get_ancestors: function(inc_current) {
|
3494 |
-
var ret = [];
|
3495 |
-
var m = this.get_model();
|
3496 |
-
while ( this.util.is_obj(m) ) {
|
3497 |
-
ret.push(m);
|
3498 |
-
m = ( this.util.in_obj(m, 'parent') && this.util.is_obj(m.parent) ) ? m.parent : null;
|
3499 |
-
}
|
3500 |
-
// Remove current model from list
|
3501 |
-
if ( !inc_current ) {
|
3502 |
-
ret.shift();
|
3503 |
-
}
|
3504 |
-
return ret;
|
3505 |
-
},
|
3506 |
-
|
3507 |
-
/**
|
3508 |
-
* Retrieve first ancestor of current theme with specified attribute
|
3509 |
-
* > Current model is also evaluated
|
3510 |
-
* @param string attr Attribute to search ancestors for
|
3511 |
-
* @param bool safe_mode (optional) Return current model if no matching ancestor found (Default: TRUE)
|
3512 |
-
* @return obj Theme ancestor (Default: Current theme model)
|
3513 |
-
*/
|
3514 |
-
get_ancestor: function(attr, safe_mode) {
|
3515 |
-
// Validate
|
3516 |
-
if ( !this.util.is_string(attr) ) {
|
3517 |
-
return false;
|
3518 |
-
}
|
3519 |
-
if ( !this.util.is_bool(safe_mode) ) {
|
3520 |
-
safe_mode = true;
|
3521 |
-
}
|
3522 |
-
var mcurr = this.get_model();
|
3523 |
-
var m = mcurr;
|
3524 |
-
var found = false;
|
3525 |
-
while ( this.util.is_obj(m) ) {
|
3526 |
-
// Check if attribute exists in model
|
3527 |
-
if ( this.util.in_obj(m, attr) && !this.util.is_empty(m[attr]) ) {
|
3528 |
-
found = true;
|
3529 |
-
break;
|
3530 |
-
}
|
3531 |
-
// Get next model
|
3532 |
-
m = ( this.util.in_obj(m, 'parent') ) ? m['parent'] : null;
|
3533 |
-
}
|
3534 |
-
if ( !found ) {
|
3535 |
-
if ( safe_mode ) {
|
3536 |
-
// Use current model as fallback
|
3537 |
-
if ( this.util.is_empty(m) ) {
|
3538 |
-
m = mcurr;
|
3539 |
-
}
|
3540 |
-
// Add attribute to object
|
3541 |
-
if ( !this.util.in_obj(m, attr) ) {
|
3542 |
-
m[attr] = null;
|
3543 |
-
}
|
3544 |
-
} else {
|
3545 |
-
m = null;
|
3546 |
-
}
|
3547 |
-
}
|
3548 |
-
return m;
|
3549 |
-
}
|
3550 |
-
|
3551 |
-
};
|
3552 |
-
|
3553 |
-
Modeled_Component = Component.extend(Modeled_Component);
|
3554 |
-
|
3555 |
-
/**
|
3556 |
-
* Theme
|
3557 |
-
*/
|
3558 |
-
var Theme = {
|
3559 |
-
|
3560 |
-
/* Configuration */
|
3561 |
-
|
3562 |
-
_slug: 'theme',
|
3563 |
-
_refs: {
|
3564 |
-
'viewer': 'Viewer',
|
3565 |
-
'template': 'Template'
|
3566 |
-
},
|
3567 |
-
_models: {},
|
3568 |
-
|
3569 |
-
_attr_default: {
|
3570 |
-
template: null,
|
3571 |
-
model: null
|
3572 |
-
},
|
3573 |
-
|
3574 |
-
/* References */
|
3575 |
-
|
3576 |
-
viewer: null,
|
3577 |
-
template: null,
|
3578 |
-
|
3579 |
-
/* Methods */
|
3580 |
-
|
3581 |
-
/**
|
3582 |
-
* Custom constructor
|
3583 |
-
* @see Component._c()
|
3584 |
-
*/
|
3585 |
-
_c: function(id, attributes, viewer) {
|
3586 |
-
// Validate
|
3587 |
-
if ( arguments.length === 1 && this.util.is_type(arguments[0], View.Viewer) ) {
|
3588 |
-
viewer = arguments[0];
|
3589 |
-
id = null;
|
3590 |
-
}
|
3591 |
-
// Pass parameters to parent constructor
|
3592 |
-
this._super(id, attributes);
|
3593 |
-
|
3594 |
-
// Set viewer instance
|
3595 |
-
this.set_viewer(viewer);
|
3596 |
-
|
3597 |
-
// Set theme model
|
3598 |
-
this.set_model(id);
|
3599 |
-
},
|
3600 |
-
|
3601 |
-
/* Viewer */
|
3602 |
-
|
3603 |
-
get_viewer: function() {
|
3604 |
-
return this.get_component('viewer', {check_attr: false, get_default: true});
|
3605 |
-
},
|
3606 |
-
|
3607 |
-
/**
|
3608 |
-
* Sets theme's viewer property
|
3609 |
-
* @uses View.get_viewer() to retrieve global viewer
|
3610 |
-
* @uses this.viewer to save item's viewer
|
3611 |
-
* @param string|View.Viewer v Viewer to set for item
|
3612 |
-
* > Theme's viewer is reset if invalid viewer provided
|
3613 |
-
*/
|
3614 |
-
set_viewer: function(v) {
|
3615 |
-
return this.set_component('viewer', v);
|
3616 |
-
},
|
3617 |
-
|
3618 |
-
/* Template */
|
3619 |
-
|
3620 |
-
/**
|
3621 |
-
* Retrieve template instance
|
3622 |
-
* @return Template instance
|
3623 |
-
*/
|
3624 |
-
get_template: function() {
|
3625 |
-
// Get saved template
|
3626 |
-
var ret = this.get_component('template');
|
3627 |
-
// Template needs to be initialized
|
3628 |
-
if ( this.util.is_empty(ret) ) {
|
3629 |
-
// Pass model to Template instance
|
3630 |
-
var attr = { 'theme': this, 'model': this.get_model() };
|
3631 |
-
ret = this.set_component('template', new View.Template(attr));
|
3632 |
-
}
|
3633 |
-
return ret;
|
3634 |
-
},
|
3635 |
-
|
3636 |
-
/* Tags */
|
3637 |
-
|
3638 |
-
/**
|
3639 |
-
* Retrieve tags from template
|
3640 |
-
* All tags will be retrieved by default
|
3641 |
-
* Specific tag/property instances can be retrieved as well
|
3642 |
-
* @see Template.get_tags()
|
3643 |
-
* @param string name (optional) Name of tags to retrieve
|
3644 |
-
* @param string prop (optional) Specific tag property to retrieve
|
3645 |
-
* @return array Tags in template
|
3646 |
-
*/
|
3647 |
-
get_tags: function(name, prop) {
|
3648 |
-
return this.get_template().get_tags(name, prop);
|
3649 |
-
},
|
3650 |
-
|
3651 |
-
/**
|
3652 |
-
* Retrieve tag DOM elements
|
3653 |
-
* @see Template.dom_get_tag()
|
3654 |
-
*/
|
3655 |
-
dom_get_tag: function(tag, prop) {
|
3656 |
-
return $(this.get_template().dom_get_tag(tag, prop));
|
3657 |
-
},
|
3658 |
-
|
3659 |
-
/**
|
3660 |
-
* Retrieve template tag CSS selector
|
3661 |
-
* @uses Template.get_tag_selector()
|
3662 |
-
* @param name string Tag name
|
3663 |
-
* @param prop string Tag Property
|
3664 |
-
* @return string Template tag CSS selector
|
3665 |
-
*/
|
3666 |
-
get_tag_selector: function(name, prop) {
|
3667 |
-
return this.get_template().get_tag_selector(name, prop);
|
3668 |
-
},
|
3669 |
-
|
3670 |
-
/* Model */
|
3671 |
-
|
3672 |
-
/**
|
3673 |
-
* Retrieve theme models
|
3674 |
-
* @return obj Theme models
|
3675 |
-
*/
|
3676 |
-
get_models: function() {
|
3677 |
-
return this._models;
|
3678 |
-
},
|
3679 |
-
|
3680 |
-
/**
|
3681 |
-
* Retrieve specified theme model
|
3682 |
-
* @param string id (optional) Theme model to retrieve
|
3683 |
-
* > Default model retrieved if ID is invalid/not set
|
3684 |
-
* @return obj Specified theme model
|
3685 |
-
*/
|
3686 |
-
get_model: function(id) {
|
3687 |
-
var ret = null;
|
3688 |
-
// Pass request to superclass method
|
3689 |
-
if ( !this.util.is_set(id) && this.util.is_obj( this.get_attribute('model', null, false) ) ) {
|
3690 |
-
ret = this._super();
|
3691 |
-
} else {
|
3692 |
-
// Retrieve matching theme model
|
3693 |
-
var models = this.get_models();
|
3694 |
-
if ( !this.util.is_string(id) ) {
|
3695 |
-
id = this.get_controller().get_option('theme_default');
|
3696 |
-
}
|
3697 |
-
// Select first theme model if specified model is invalid
|
3698 |
-
if ( !this.util.in_obj(models, id) ) {
|
3699 |
-
id = $.map(models, function(v, key) { return key; })[0];
|
3700 |
-
}
|
3701 |
-
ret = models[id];
|
3702 |
-
}
|
3703 |
-
return ret;
|
3704 |
-
},
|
3705 |
-
|
3706 |
-
/**
|
3707 |
-
* Set model for current theme instance
|
3708 |
-
* @param string id (optional) Theme ID (Default theme retrieved if ID invalid)
|
3709 |
-
*/
|
3710 |
-
set_model: function(id) {
|
3711 |
-
this.set_attribute('model', this.get_model(id), false);
|
3712 |
-
/* @deprecated
|
3713 |
-
// Set ID using model attributes (if necessary)
|
3714 |
-
if ( !this._check_id(true) ) {
|
3715 |
-
var m = this.get_model();
|
3716 |
-
if ( 'id' in m ) {
|
3717 |
-
this._set_id(m.id);
|
3718 |
-
}
|
3719 |
-
}
|
3720 |
-
*/
|
3721 |
-
},
|
3722 |
-
|
3723 |
-
/* Properties */
|
3724 |
-
|
3725 |
-
/**
|
3726 |
-
* Generate class names for DOM node
|
3727 |
-
* @param string rtype (optional) Return data type
|
3728 |
-
* > Default: array
|
3729 |
-
* > If string supplied: Joined classes delimited by parameter
|
3730 |
-
* @uses get_class() to generate class names
|
3731 |
-
* @uses Array.join() to convert class names array to string
|
3732 |
-
* @return array Class names
|
3733 |
-
*/
|
3734 |
-
get_classes: function(rtype) {
|
3735 |
-
// Build array of class names
|
3736 |
-
var cls = [];
|
3737 |
-
var thm = this;
|
3738 |
-
// Include theme parent's class name
|
3739 |
-
var models = this.get_ancestors(true);
|
3740 |
-
$.each(models, function(idx, model) {
|
3741 |
-
cls.push(thm.add_ns(model.id));
|
3742 |
-
});
|
3743 |
-
// Convert class names array to string
|
3744 |
-
if ( this.util.is_string(rtype) ) {
|
3745 |
-
cls = cls.join(rtype);
|
3746 |
-
}
|
3747 |
-
// Return class names
|
3748 |
-
return cls;
|
3749 |
-
},
|
3750 |
-
|
3751 |
-
/**
|
3752 |
-
* Get custom measurement
|
3753 |
-
* @param string attr Measurement to retrieve
|
3754 |
-
* @param obj def (optional) Default value
|
3755 |
-
* @return obj Attribute measurements
|
3756 |
-
*/
|
3757 |
-
get_measurement: function(attr, def) {
|
3758 |
-
var meas = null;
|
3759 |
-
// Validate
|
3760 |
-
if ( !this.util.is_string(attr) ) {
|
3761 |
-
return meas;
|
3762 |
-
}
|
3763 |
-
if ( !this.util.is_obj(def, false) ) {
|
3764 |
-
def = {};
|
3765 |
-
}
|
3766 |
-
// Manage cache
|
3767 |
-
var attr_cache = this.util.format('%s_cache', attr);
|
3768 |
-
var cache = this.get_attribute(attr_cache, {}, false);
|
3769 |
-
var status = '_status';
|
3770 |
-
var item = this.get_viewer().get_item();
|
3771 |
-
var w = $(window);
|
3772 |
-
// Check cache freshness
|
3773 |
-
if ( !( status in cache ) || !this.util.is_obj(cache[status]) || cache[status].width !== w.width() || cache[status].height !== w.height() ) {
|
3774 |
-
cache = {};
|
3775 |
-
}
|
3776 |
-
if ( this.util.is_empty(cache) ) {
|
3777 |
-
// Set status
|
3778 |
-
cache[status] = {
|
3779 |
-
'width': w.width(),
|
3780 |
-
'height': w.height(),
|
3781 |
-
'index': []
|
3782 |
-
};
|
3783 |
-
}
|
3784 |
-
// Retrieve cached values
|
3785 |
-
var pos = $.inArray(item, cache[status].index);
|
3786 |
-
if ( pos !== -1 && pos in cache ) {
|
3787 |
-
meas = cache[pos];
|
3788 |
-
}
|
3789 |
-
// Generate measurement
|
3790 |
-
if ( !this.util.is_obj(meas) ) {
|
3791 |
-
// Get custom theme measurement
|
3792 |
-
meas = this.call_attribute(attr);
|
3793 |
-
if ( !this.util.is_obj(meas) ) {
|
3794 |
-
// Retrieve fallback value
|
3795 |
-
meas = this.get_measurement_default(attr);
|
3796 |
-
}
|
3797 |
-
}
|
3798 |
-
// Normalize measurement
|
3799 |
-
meas = ( this.util.is_obj(meas) ) ? $.extend({}, def, meas) : def;
|
3800 |
-
// Cache measurement
|
3801 |
-
pos = cache[status].index.push(item) - 1;
|
3802 |
-
cache[pos] = meas;
|
3803 |
-
this.set_attribute(attr_cache, cache, false);
|
3804 |
-
// Return measurement (copy)
|
3805 |
-
return $.extend({}, meas);
|
3806 |
-
},
|
3807 |
-
|
3808 |
-
/**
|
3809 |
-
* Get default measurement using attribute's default handler
|
3810 |
-
* @param string attr Measurement attribute
|
3811 |
-
* @return obj Measurement values
|
3812 |
-
*/
|
3813 |
-
get_measurement_default: function(attr) {
|
3814 |
-
// Validate
|
3815 |
-
if ( !this.util.is_string(attr) ) {
|
3816 |
-
return null;
|
3817 |
-
}
|
3818 |
-
// Find default handler
|
3819 |
-
attr = this.util.format('get_%s_default', attr);
|
3820 |
-
if ( this.util.in_obj(this, attr) ) {
|
3821 |
-
attr = this[attr];
|
3822 |
-
if ( this.util.is_func(attr) ) {
|
3823 |
-
// Execute default handler
|
3824 |
-
attr = attr.call(this);
|
3825 |
-
}
|
3826 |
-
} else {
|
3827 |
-
attr = null;
|
3828 |
-
}
|
3829 |
-
return attr;
|
3830 |
-
},
|
3831 |
-
|
3832 |
-
/**
|
3833 |
-
* Retrieve theme offset
|
3834 |
-
* @return obj Theme offset with `width` & `height` properties
|
3835 |
-
*/
|
3836 |
-
get_offset: function() {
|
3837 |
-
return this.get_measurement('offset', { 'width': 0, 'height': 0});
|
3838 |
-
},
|
3839 |
-
|
3840 |
-
/**
|
3841 |
-
* Generate default offset
|
3842 |
-
* @return obj Theme offsets with `width` & `height` properties
|
3843 |
-
*/
|
3844 |
-
get_offset_default: function() {
|
3845 |
-
var offset = { 'width': 0, 'height': 0 };
|
3846 |
-
var v = this.get_viewer();
|
3847 |
-
var vn = v.dom_get();
|
3848 |
-
// Clone viewer
|
3849 |
-
var vc = vn
|
3850 |
-
.clone()
|
3851 |
-
.attr('id', '')
|
3852 |
-
.css({'visibility': 'hidden', 'position': 'absolute', 'top': ''})
|
3853 |
-
.removeClass('loading')
|
3854 |
-
.appendTo(vn.parent());
|
3855 |
-
// Get offset from layout node
|
3856 |
-
var l = vc.find(v.dom_get_selector('layout'));
|
3857 |
-
if ( l.length ) {
|
3858 |
-
// Clear inline styles
|
3859 |
-
l.find('*').css({
|
3860 |
-
'width': '',
|
3861 |
-
'height': '',
|
3862 |
-
'display': ''
|
3863 |
-
});
|
3864 |
-
// Resize content nodes
|
3865 |
-
var tags = this.get_tags('item', 'content');
|
3866 |
-
if ( tags.length ) {
|
3867 |
-
var offset_item = v.get_item().get_dimensions();
|
3868 |
-
// Set content dimensions
|
3869 |
-
tags = $(l.find(tags[0].get_selector('full')).get(0)).css({'width': offset_item.width, 'height': offset_item.height});
|
3870 |
-
$.each(offset_item, function(key, val) {
|
3871 |
-
offset[key] = -1 * val;
|
3872 |
-
});
|
3873 |
-
}
|
3874 |
-
|
3875 |
-
// Set offset
|
3876 |
-
offset.width += l.width();
|
3877 |
-
offset.height += l.height();
|
3878 |
-
// Normalize
|
3879 |
-
$.each(offset, function(key, val) {
|
3880 |
-
if ( val < 0 ) {
|
3881 |
-
offset[key] = 0;
|
3882 |
-
}
|
3883 |
-
});
|
3884 |
-
}
|
3885 |
-
vc.empty().remove();
|
3886 |
-
return offset;
|
3887 |
-
},
|
3888 |
-
|
3889 |
-
/**
|
3890 |
-
* Retrieve theme margins
|
3891 |
-
* @return obj Theme margin with `width` & `height` properties
|
3892 |
-
*/
|
3893 |
-
get_margin: function() {
|
3894 |
-
return this.get_measurement('margin', {'width': 0, 'height': 0});
|
3895 |
-
},
|
3896 |
-
|
3897 |
-
/**
|
3898 |
-
* Retrieve item dimensions
|
3899 |
-
* Dimensions are adjusted to fit window (if necessary)
|
3900 |
-
* @return obj Item dimensions with `width` & `height` properties
|
3901 |
-
*/
|
3902 |
-
get_item_dimensions: function() {
|
3903 |
-
var v = this.get_viewer();
|
3904 |
-
var dims = v.get_item().get_dimensions();
|
3905 |
-
if ( v.get_attribute('autofit', false) ) {
|
3906 |
-
// Get maximum dimensions
|
3907 |
-
var margin = this.get_margin();
|
3908 |
-
var offset = this.get_offset();
|
3909 |
-
offset.height += margin.height;
|
3910 |
-
offset.width += margin.width;
|
3911 |
-
var max = {'width': $(window).width(), 'height': $(window).height() };
|
3912 |
-
if ( max.width > offset.width ) {
|
3913 |
-
max.width -= offset.width;
|
3914 |
-
}
|
3915 |
-
if ( max.height > offset.height ) {
|
3916 |
-
max.height -= offset.height;
|
3917 |
-
}
|
3918 |
-
// Get resize factor
|
3919 |
-
var factor = Math.min(max.width / dims.width, max.height / dims.height);
|
3920 |
-
// Resize dimensions
|
3921 |
-
if ( factor < 1 ) {
|
3922 |
-
$.each(dims, function(key) {
|
3923 |
-
dims[key] = Math.round(dims[key] * factor);
|
3924 |
-
});
|
3925 |
-
}
|
3926 |
-
}
|
3927 |
-
return $.extend({}, dims);
|
3928 |
-
},
|
3929 |
-
|
3930 |
-
/**
|
3931 |
-
* Retrieve theme dimensions
|
3932 |
-
* @return obj Theme dimensions with `width` & `height` properties
|
3933 |
-
*/
|
3934 |
-
get_dimensions: function() {
|
3935 |
-
var dims = this.get_item_dimensions();
|
3936 |
-
var offset = this.get_offset();
|
3937 |
-
$.each(dims, function(key) {
|
3938 |
-
dims[key] += offset[key];
|
3939 |
-
});
|
3940 |
-
return dims;
|
3941 |
-
},
|
3942 |
-
|
3943 |
-
/**
|
3944 |
-
* Retrieve all breakpoints
|
3945 |
-
* @return object Breakpoints
|
3946 |
-
*/
|
3947 |
-
get_breakpoints: function() {
|
3948 |
-
return this.get_attribute_recursive('breakpoints');
|
3949 |
-
},
|
3950 |
-
|
3951 |
-
/**
|
3952 |
-
* Get breakpoint value
|
3953 |
-
* @param string target Breakpoint target
|
3954 |
-
* @return int Breakpoint value (pixels)
|
3955 |
-
*/
|
3956 |
-
get_breakpoint: function(target) {
|
3957 |
-
var ret = 0;
|
3958 |
-
if ( this.util.is_string(target) ) {
|
3959 |
-
var b = this.get_attribute_recursive('breakpoints');
|
3960 |
-
if ( this.util.is_obj(b) && target in b ) {
|
3961 |
-
ret = b[target];
|
3962 |
-
}
|
3963 |
-
}
|
3964 |
-
return ret;
|
3965 |
-
},
|
3966 |
-
|
3967 |
-
/* Output */
|
3968 |
-
|
3969 |
-
/**
|
3970 |
-
* Render Theme output
|
3971 |
-
* @param bool init (optional) Initialize theme (Default: FALSE)
|
3972 |
-
* @see Template.render()
|
3973 |
-
*/
|
3974 |
-
render: function(init) {
|
3975 |
-
var thm = this;
|
3976 |
-
var tpl = this.get_template();
|
3977 |
-
var st = 'events_render';
|
3978 |
-
if ( !this.get_status(st) ) {
|
3979 |
-
this.set_status(st);
|
3980 |
-
// Register events
|
3981 |
-
tpl.on([
|
3982 |
-
'render-init',
|
3983 |
-
'render-loading',
|
3984 |
-
'render-complete'
|
3985 |
-
],
|
3986 |
-
function(ev) {
|
3987 |
-
return thm.trigger(ev.type, ev.data);
|
3988 |
-
});
|
3989 |
-
}
|
3990 |
-
// Render template
|
3991 |
-
tpl.render(init);
|
3992 |
-
},
|
3993 |
-
|
3994 |
-
transition: function(event, clear_queue) {
|
3995 |
-
var dfr = null;
|
3996 |
-
var attr = 'transition';
|
3997 |
-
var v = this.get_viewer();
|
3998 |
-
var fx_temp = null;
|
3999 |
-
var anim_on = v.animation_enabled();
|
4000 |
-
if ( v.get_attribute(attr, true) && this.util.is_string(event) ) {
|
4001 |
-
var anim_stop = function() {
|
4002 |
-
var l = v.get_layout();
|
4003 |
-
l.find('*').each(function() {
|
4004 |
-
var el = $(this);
|
4005 |
-
while ( el.queue().length ) {
|
4006 |
-
el.stop(false, true);
|
4007 |
-
}
|
4008 |
-
});
|
4009 |
-
};
|
4010 |
-
// Stop queued animations
|
4011 |
-
if ( !!clear_queue ) {
|
4012 |
-
anim_stop();
|
4013 |
-
}
|
4014 |
-
// Get transition handlers
|
4015 |
-
var attr_set = [attr, 'set'].join('_');
|
4016 |
-
var trns;
|
4017 |
-
if ( !this.get_attribute(attr_set) ) {
|
4018 |
-
var models = this.get_ancestors(true);
|
4019 |
-
trns = [];
|
4020 |
-
this.set_attribute(attr_set, true);
|
4021 |
-
var thm = this;
|
4022 |
-
$.each(models, function(idx, model) {
|
4023 |
-
if ( attr in model && thm.util.is_obj(model[attr]) ) {
|
4024 |
-
trns.push(model[attr]);
|
4025 |
-
}
|
4026 |
-
});
|
4027 |
-
// Merge transition handlers into current theme
|
4028 |
-
trns.push({});
|
4029 |
-
trns = this.set_attribute(attr, $.extend.apply($, trns.reverse()));
|
4030 |
-
} else {
|
4031 |
-
trns = this.get_attribute(attr, {});
|
4032 |
-
}
|
4033 |
-
if ( this.util.is_method(trns, event) ) {
|
4034 |
-
// Disable animations if necessary
|
4035 |
-
if ( !anim_on ) {
|
4036 |
-
fx_temp = $.fx.off;
|
4037 |
-
$.fx.off = true;
|
4038 |
-
}
|
4039 |
-
// Pass control to transition event
|
4040 |
-
dfr = trns[event].call(this, v, $.Deferred());
|
4041 |
-
}
|
4042 |
-
}
|
4043 |
-
if ( !this.util.is_promise(dfr) ) {
|
4044 |
-
dfr = $.Deferred();
|
4045 |
-
dfr.reject();
|
4046 |
-
}
|
4047 |
-
dfr.always(function() {
|
4048 |
-
// Restore animation state
|
4049 |
-
if ( null !== fx_temp ) {
|
4050 |
-
$.fx.off = fx_temp;
|
4051 |
-
}
|
4052 |
-
});
|
4053 |
-
return dfr.promise();
|
4054 |
-
}
|
4055 |
-
};
|
4056 |
-
|
4057 |
-
View.Theme = Modeled_Component.extend(Theme);
|
4058 |
-
|
4059 |
-
/**
|
4060 |
-
* Template handler
|
4061 |
-
* Parses and Builds layout from raw template
|
4062 |
-
*/
|
4063 |
-
var Template = {
|
4064 |
-
/* Configuration */
|
4065 |
-
|
4066 |
-
_slug: 'template',
|
4067 |
-
_reciprocal: true,
|
4068 |
-
|
4069 |
-
_refs: {
|
4070 |
-
'theme': 'Theme'
|
4071 |
-
},
|
4072 |
-
|
4073 |
-
_attr_default: {
|
4074 |
-
/**
|
4075 |
-
* URI to layout (raw) file
|
4076 |
-
* @var string
|
4077 |
-
*/
|
4078 |
-
layout_uri: '',
|
4079 |
-
|
4080 |
-
/**
|
4081 |
-
* Raw layout template
|
4082 |
-
* @var string
|
4083 |
-
*/
|
4084 |
-
layout_raw: '',
|
4085 |
-
/**
|
4086 |
-
* Parsed layout
|
4087 |
-
* Placeholders processed
|
4088 |
-
* @var string
|
4089 |
-
*/
|
4090 |
-
layout_parsed: '',
|
4091 |
-
/**
|
4092 |
-
* Tags in template
|
4093 |
-
* Populated once template has been parsed
|
4094 |
-
* @var array
|
4095 |
-
*/
|
4096 |
-
tags: null,
|
4097 |
-
/**
|
4098 |
-
* Model to use for properties
|
4099 |
-
* Usually reference to an object in other component
|
4100 |
-
* @var obj
|
4101 |
-
*/
|
4102 |
-
model: null
|
4103 |
-
},
|
4104 |
-
|
4105 |
-
/* References */
|
4106 |
-
|
4107 |
-
theme: null,
|
4108 |
-
|
4109 |
-
/* Methods */
|
4110 |
-
|
4111 |
-
_c: function(attributes) {
|
4112 |
-
this._super('', attributes);
|
4113 |
-
},
|
4114 |
-
|
4115 |
-
_hooks: function() {
|
4116 |
-
// TODO: Refactor to event that can save retrieved tags
|
4117 |
-
// (`dom_init` event called during attribute initialization so tags are not saved)
|
4118 |
-
this.on('dom_init', function(ev) {
|
4119 |
-
// Init tag handlers
|
4120 |
-
var tags = this.get_tags(null, null, true);
|
4121 |
-
var names = [];
|
4122 |
-
var t = this;
|
4123 |
-
$.each(tags, function(idx, tag) {
|
4124 |
-
var name = tag.get_name();
|
4125 |
-
if ( -1 === $.inArray(name, names) ) {
|
4126 |
-
names.push(name);
|
4127 |
-
tag.get_handler().trigger(ev.type, {template: t});
|
4128 |
-
}
|
4129 |
-
});
|
4130 |
-
});
|
4131 |
-
},
|
4132 |
-
|
4133 |
-
get_theme: function() {
|
4134 |
-
var ret = this.get_component('theme');
|
4135 |
-
return ret;
|
4136 |
-
},
|
4137 |
-
|
4138 |
-
/* Output */
|
4139 |
-
|
4140 |
-
/**
|
4141 |
-
* Render output
|
4142 |
-
* @param bool init (optional) Whether to initialize layout (TRUE) or render item (FALSE) (Default: FALSE)
|
4143 |
-
* Events
|
4144 |
-
* > render-init: Initialize template
|
4145 |
-
* > render-loading: DOM elements created and item content about to be loaded
|
4146 |
-
* > render-complete: Item content loaded, ready for display
|
4147 |
-
*/
|
4148 |
-
render: function(init) {
|
4149 |
-
var v = this.get_theme().get_viewer();
|
4150 |
-
if ( !this.util.is_bool(init) ) {
|
4151 |
-
init = false;
|
4152 |
-
}
|
4153 |
-
// Populate layout
|
4154 |
-
if ( !init ) {
|
4155 |
-
if ( !v.is_active() ) {
|
4156 |
-
return false;
|
4157 |
-
}
|
4158 |
-
var item = v.get_item();
|
4159 |
-
if ( !this.util.is_type(item, View.Content_Item) ) {
|
4160 |
-
v.close();
|
4161 |
-
return false;
|
4162 |
-
}
|
4163 |
-
// Iterate through tags and populate layout
|
4164 |
-
if ( v.is_active() && this.has_tags() ) {
|
4165 |
-
var loading_promise = this.trigger('render-loading');
|
4166 |
-
var tpl = this;
|
4167 |
-
var tags = this.get_tags(),
|
4168 |
-
tag_promises = [];
|
4169 |
-
// Render Tag output
|
4170 |
-
$.when(item.load(), loading_promise).done(function() {
|
4171 |
-
if ( !v.is_active() ) {
|
4172 |
-
return false;
|
4173 |
-
}
|
4174 |
-
$.each(tags, function(idx, tag) {
|
4175 |
-
if ( !v.is_active() ) {
|
4176 |
-
return false;
|
4177 |
-
}
|
4178 |
-
tag_promises.push(tag.render(item).done(function(r) {
|
4179 |
-
if ( !v.is_active() ) {
|
4180 |
-
return false;
|
4181 |
-
}
|
4182 |
-
r.tag.dom_get().html(r.output);
|
4183 |
-
}));
|
4184 |
-
});
|
4185 |
-
// Fire event when all tags rendered
|
4186 |
-
if ( !v.is_active() ) {
|
4187 |
-
return false;
|
4188 |
-
}
|
4189 |
-
$.when.apply($, tag_promises).done(function() {
|
4190 |
-
tpl.trigger('render-complete');
|
4191 |
-
});
|
4192 |
-
});
|
4193 |
-
}
|
4194 |
-
} else {
|
4195 |
-
// Get Layout (basic)
|
4196 |
-
this.trigger('render-init', this.dom_get());
|
4197 |
-
}
|
4198 |
-
},
|
4199 |
-
|
4200 |
-
/*-** Layout **-*/
|
4201 |
-
|
4202 |
-
/**
|
4203 |
-
* Retrieve layout
|
4204 |
-
* @param bool parsed (optional) TRUE retrieves parsed layout, FALSE retrieves raw layout (Default: TRUE)
|
4205 |
-
* @return string Layout (HTML)
|
4206 |
-
*/
|
4207 |
-
get_layout: function(parsed) {
|
4208 |
-
// Validate
|
4209 |
-
if ( !this.util.is_bool(parsed) ) {
|
4210 |
-
parsed = true;
|
4211 |
-
}
|
4212 |
-
// Determine which layout to retrieve (raw/parsed)
|
4213 |
-
var l = ( parsed ) ? this.parse_layout() : this.get_attribute('layout_raw', '');
|
4214 |
-
return l;
|
4215 |
-
},
|
4216 |
-
|
4217 |
-
/**
|
4218 |
-
* Parse layout
|
4219 |
-
* Converts template tags to HTML elements
|
4220 |
-
* > Template tag properties saved to HTML elements for future initialization
|
4221 |
-
* Returns saved layout if previously parsed
|
4222 |
-
* @return string Parsed layout
|
4223 |
-
*/
|
4224 |
-
parse_layout: function() {
|
4225 |
-
// Check for previously-parsed layout
|
4226 |
-
var a = 'layout_parsed';
|
4227 |
-
var ret = this.get_attribute(a);
|
4228 |
-
// Return cached layout immediately
|
4229 |
-
if ( this.util.is_string(ret) ) {
|
4230 |
-
return ret;
|
4231 |
-
}
|
4232 |
-
// Parse raw layout
|
4233 |
-
ret = this.sanitize_layout( this.get_layout(false) );
|
4234 |
-
ret = this.parse_tags(ret);
|
4235 |
-
// Save parsed layout
|
4236 |
-
this.set_attribute(a, ret);
|
4237 |
-
|
4238 |
-
// Return parsed layout
|
4239 |
-
return ret;
|
4240 |
-
},
|
4241 |
-
|
4242 |
-
/**
|
4243 |
-
* Sanitize layout
|
4244 |
-
* @param obj|string l Layout string or jQuery object
|
4245 |
-
* @return obj|string Sanitized layout (Same data type that was passed to method)
|
4246 |
-
*/
|
4247 |
-
sanitize_layout: function(l) {
|
4248 |
-
// Stop processing if invalid value
|
4249 |
-
if ( this.util.is_empty(l) ) {
|
4250 |
-
return l;
|
4251 |
-
}
|
4252 |
-
// Set return type
|
4253 |
-
var rtype = ( this.util.is_string(l) ) ? 'string' : null;
|
4254 |
-
/* Quarantine hard-coded tags */
|
4255 |
-
|
4256 |
-
// Create DOM structure from raw template
|
4257 |
-
var dom = $(l);
|
4258 |
-
// Find hard-coded tag nodes
|
4259 |
-
var tag_temp = this.get_tag_temp();
|
4260 |
-
var cls = tag_temp.get_class();
|
4261 |
-
var cls_new = ['x', cls].join('_');
|
4262 |
-
$(tag_temp.get_selector(), dom).each(function() {
|
4263 |
-
// Replace matching class name with blocking class
|
4264 |
-
$(this).removeClass(cls).addClass(cls_new);
|
4265 |
-
});
|
4266 |
-
// Format return value
|
4267 |
-
switch ( rtype ) {
|
4268 |
-
case 'string' :
|
4269 |
-
dom = dom.wrap('<div />').parent().html();
|
4270 |
-
l = dom;
|
4271 |
-
break;
|
4272 |
-
default :
|
4273 |
-
l = dom;
|
4274 |
-
}
|
4275 |
-
return l;
|
4276 |
-
},
|
4277 |
-
|
4278 |
-
/*-** Tags **-*/
|
4279 |
-
|
4280 |
-
/**
|
4281 |
-
* Extract tags from template
|
4282 |
-
* Tags are replaced with DOM element placeholders
|
4283 |
-
* Extracted tags are saved as element attribute values (for future use)
|
4284 |
-
* @param string l Raw layout to parse
|
4285 |
-
* @return string Parsed layout
|
4286 |
-
*/
|
4287 |
-
parse_tags: function(l) {
|
4288 |
-
// Validate
|
4289 |
-
if ( !this.util.is_string(l) ) {
|
4290 |
-
return '';
|
4291 |
-
}
|
4292 |
-
// Parse tags in layout
|
4293 |
-
// Tag regex
|
4294 |
-
var re = /\{{2}\s*(\w.*?)\s*\}{2}/gim;
|
4295 |
-
// Tag match results
|
4296 |
-
var match;
|
4297 |
-
// Iterate through template and find tags
|
4298 |
-
while ( match = re.exec(l) ) {
|
4299 |
-
// Replace tag in layout with DOM container
|
4300 |
-
l = l.substring(0, match.index) + this.get_tag_container(match[1]) + l.substring(match.index + match[0].length);
|
4301 |
-
}
|
4302 |
-
return l;
|
4303 |
-
},
|
4304 |
-
|
4305 |
-
/**
|
4306 |
-
* Create DOM element container for tag
|
4307 |
-
* @param string Tag ID (will be prefixed)
|
4308 |
-
* @return string DOM element
|
4309 |
-
*/
|
4310 |
-
get_tag_container: function(tag) {
|
4311 |
-
// Build element
|
4312 |
-
var attr = this.get_tag_attribute();
|
4313 |
-
return this.util.format('<span %s="%s"></span>', attr, encodeURI(tag));
|
4314 |
-
},
|
4315 |
-
|
4316 |
-
get_tag_attribute: function() {
|
4317 |
-
return this.get_tag_temp().dom_get_attribute();
|
4318 |
-
},
|
4319 |
-
|
4320 |
-
/**
|
4321 |
-
* Retrieve Template_Tag instance at specified index
|
4322 |
-
* @param int idx (optional) Index to retrieve tag from
|
4323 |
-
* @return Template_Tag Tag instance
|
4324 |
-
*/
|
4325 |
-
get_tag: function(idx) {
|
4326 |
-
var ret = null;
|
4327 |
-
if ( this.has_tags() ) {
|
4328 |
-
var tags = this.get_tags();
|
4329 |
-
if ( !this.util.is_int(idx) || 0 > idx || idx >= tags.length ) {
|
4330 |
-
idx = 0;
|
4331 |
-
}
|
4332 |
-
ret = tags[idx];
|
4333 |
-
}
|
4334 |
-
return ret;
|
4335 |
-
},
|
4336 |
-
|
4337 |
-
/**
|
4338 |
-
* Retrieve tags from template
|
4339 |
-
* Subset of tags may be retrieved based on parameter values
|
4340 |
-
* Template is parsed if tags not set
|
4341 |
-
* @param string name (optional) Tag type to retrieve instances of
|
4342 |
-
* @param string prop (optional) Tag property to retrieve instances of
|
4343 |
-
* @param bool isolate (optional) Do not save retrieved tags, only fetch and return (Default: TRUE)
|
4344 |
-
* @return array Template_Tag instances
|
4345 |
-
*/
|
4346 |
-
get_tags: function(name, prop, isolate) {
|
4347 |
-
// Validate
|
4348 |
-
if ( !this.util.is_bool(isolate) ) {
|
4349 |
-
isolate = false;
|
4350 |
-
}
|
4351 |
-
// Setup
|
4352 |
-
var a = 'tags';
|
4353 |
-
var tags = this.get_attribute(a);
|
4354 |
-
// Initialize tags
|
4355 |
-
if ( !this.util.is_array(tags) ) {
|
4356 |
-
tags = [];
|
4357 |
-
// Retrieve layout DOM tree
|
4358 |
-
var d = this.dom_get();
|
4359 |
-
// Select tag nodes
|
4360 |
-
var attr = this.get_tag_attribute();
|
4361 |
-
var nodes = $(d).find('[' + attr + ']');
|
4362 |
-
// Build tag instances from nodes
|
4363 |
-
$(nodes).each(function() {
|
4364 |
-
// Get tag placeholder
|
4365 |
-
var el = $(this);
|
4366 |
-
var tag = new View.Template_Tag(decodeURI(el.attr(attr)));
|
4367 |
-
// Populate valid tags
|
4368 |
-
if ( tag.has_handler() ) {
|
4369 |
-
// Add tag to array
|
4370 |
-
tags.push(tag);
|
4371 |
-
if ( !isolate ) {
|
4372 |
-
// Connect tag to DOM node
|
4373 |
-
tag.dom_set(el);
|
4374 |
-
// Set classes
|
4375 |
-
el.addClass(tag.get_classes(' '));
|
4376 |
-
}
|
4377 |
-
}
|
4378 |
-
// Clear data attribute
|
4379 |
-
if ( !isolate ) {
|
4380 |
-
el.removeAttr(attr);
|
4381 |
-
}
|
4382 |
-
});
|
4383 |
-
if ( !isolate ) {
|
4384 |
-
// Save tags
|
4385 |
-
this.set_attribute(a, tags, false);
|
4386 |
-
}
|
4387 |
-
}
|
4388 |
-
// Filter tags by parameters
|
4389 |
-
if ( !this.util.is_empty(tags) && this.util.is_string(name) ) {
|
4390 |
-
// Normalize
|
4391 |
-
if ( !this.util.is_string(prop) ) {
|
4392 |
-
prop = false;
|
4393 |
-
}
|
4394 |
-
var tags_filtered = [];
|
4395 |
-
var tc = null;
|
4396 |
-
for ( var x = 0; x < tags.length; x++ ) {
|
4397 |
-
tc = tags[x];
|
4398 |
-
if ( name === tc.get_name() ) {
|
4399 |
-
// Check tag property
|
4400 |
-
if ( !prop || prop === tc.get_prop() ) {
|
4401 |
-
tags_filtered.push(tc);
|
4402 |
-
}
|
4403 |
-
}
|
4404 |
-
}
|
4405 |
-
tags = tags_filtered;
|
4406 |
-
}
|
4407 |
-
return ( this.util.is_array(tags, false) ) ? tags : [];
|
4408 |
-
},
|
4409 |
-
|
4410 |
-
/**
|
4411 |
-
* Check if template contains tags
|
4412 |
-
* @return bool TRUE if tags exist, FALSE otherwise
|
4413 |
-
*/
|
4414 |
-
has_tags: function() {
|
4415 |
-
return ( this.get_tags().length > 0 ) ? true : false;
|
4416 |
-
},
|
4417 |
-
|
4418 |
-
/**
|
4419 |
-
* Retrieve temporary tag instance
|
4420 |
-
* @return Template_Tag Temporary tag
|
4421 |
-
*/
|
4422 |
-
get_tag_temp: function() {
|
4423 |
-
return this.get_controller().get_component_temp(View.Template_Tag);
|
4424 |
-
},
|
4425 |
-
|
4426 |
-
/**
|
4427 |
-
* Retrieve Template tag CSS selector
|
4428 |
-
* @uses Template.get_tag_temp() to retrieve temporary tag instance
|
4429 |
-
* @uses Template_Tag.get_selector() to retrieve selector
|
4430 |
-
* @param name string Tag name
|
4431 |
-
* @param prop string Tag Property
|
4432 |
-
* @return string Template Tag CSS selector
|
4433 |
-
*/
|
4434 |
-
get_tag_selector: function(name, prop) {
|
4435 |
-
if ( !this.util.is_string(name) ) {
|
4436 |
-
name = '';
|
4437 |
-
}
|
4438 |
-
if ( !this.util.is_string(prop) ) {
|
4439 |
-
prop = '';
|
4440 |
-
}
|
4441 |
-
var tag = this.get_tag_temp();
|
4442 |
-
tag.set_attribute('name', name);
|
4443 |
-
tag.set_attribute('prop', prop);
|
4444 |
-
return tag.get_selector('full');
|
4445 |
-
},
|
4446 |
-
|
4447 |
-
/*-** DOM **-*/
|
4448 |
-
|
4449 |
-
/**
|
4450 |
-
* Custom DOM initialization
|
4451 |
-
*/
|
4452 |
-
dom_init: function() {
|
4453 |
-
// Create DOM object from parsed layout
|
4454 |
-
this.dom_set(this.get_layout());
|
4455 |
-
this.trigger('dom_init');
|
4456 |
-
},
|
4457 |
-
|
4458 |
-
/**
|
4459 |
-
* Retrieve DOM element(s) for specified tag
|
4460 |
-
* @param string tag Name of tag to retrieve
|
4461 |
-
* @param string prop (optional) Specific tag property to retrieve
|
4462 |
-
* @return array DOM elements for tag
|
4463 |
-
*/
|
4464 |
-
dom_get_tag: function(tag, prop) {
|
4465 |
-
var ret = $();
|
4466 |
-
var tags = this.get_tags(tag, prop);
|
4467 |
-
if ( tags.length ) {
|
4468 |
-
// Build selector
|
4469 |
-
var level = null;
|
4470 |
-
if ( this.util.is_string(tag) ) {
|
4471 |
-
level = ( this.util.is_string(prop) ) ? 'full' : 'tag';
|
4472 |
-
}
|
4473 |
-
var sel = '.' + tags[0].get_class(level);
|
4474 |
-
ret = this.dom_get().find(sel);
|
4475 |
-
}
|
4476 |
-
return ret;
|
4477 |
-
}
|
4478 |
-
};
|
4479 |
-
|
4480 |
-
View.Template = Modeled_Component.extend(Template);
|
4481 |
-
|
4482 |
-
/**
|
4483 |
-
* Template tag
|
4484 |
-
*/
|
4485 |
-
var Template_Tag = {
|
4486 |
-
/* Configuration */
|
4487 |
-
_slug: 'template_tag',
|
4488 |
-
_reciprocal: true,
|
4489 |
-
/* Properties */
|
4490 |
-
_attr_default: {
|
4491 |
-
name: null,
|
4492 |
-
prop: null,
|
4493 |
-
match: null
|
4494 |
-
},
|
4495 |
-
/**
|
4496 |
-
* Tag Handlers
|
4497 |
-
* Collection of Template_Tag_Handler instances
|
4498 |
-
* @var obj
|
4499 |
-
*/
|
4500 |
-
handlers: {},
|
4501 |
-
/* Methods */
|
4502 |
-
|
4503 |
-
/**
|
4504 |
-
* Constructor
|
4505 |
-
* @param
|
4506 |
-
*/
|
4507 |
-
_c: function(tag_match) {
|
4508 |
-
this.parse(tag_match);
|
4509 |
-
},
|
4510 |
-
|
4511 |
-
/**
|
4512 |
-
* Set instance attributes using tag extracted from template
|
4513 |
-
* @param string tag_match Extracted tag match
|
4514 |
-
*/
|
4515 |
-
parse: function(tag_match) {
|
4516 |
-
// Return default value for invalid instances
|
4517 |
-
if ( !this.util.is_string(tag_match) ) {
|
4518 |
-
return false;
|
4519 |
-
}
|
4520 |
-
// Parse instance options
|
4521 |
-
var parts = tag_match.split('|'),
|
4522 |
-
part;
|
4523 |
-
if ( !parts.length ) {
|
4524 |
-
return null;
|
4525 |
-
}
|
4526 |
-
var attrs = {
|
4527 |
-
name: null,
|
4528 |
-
prop: null,
|
4529 |
-
match: tag_match
|
4530 |
-
};
|
4531 |
-
// Get tag ID
|
4532 |
-
attrs.name = parts[0];
|
4533 |
-
// Get main property
|
4534 |
-
if ( attrs.name.indexOf('.') !== -1 ) {
|
4535 |
-
attrs.name = attrs.name.split('.', 2);
|
4536 |
-
attrs.prop = attrs.name[1];
|
4537 |
-
attrs.name = attrs.name[0];
|
4538 |
-
}
|
4539 |
-
// Get other attributes
|
4540 |
-
for ( var x = 1; x < parts.length; x++ ) {
|
4541 |
-
part = parts[x].split(':', 1);
|
4542 |
-
if ( part.length > 1 && !( part[0] in attrs ) ) {
|
4543 |
-
// Add key/value pair to attributes
|
4544 |
-
attrs[part[0]] = part[1];
|
4545 |
-
}
|
4546 |
-
}
|
4547 |
-
// Save to instance
|
4548 |
-
this.set_attributes(attrs, true);
|
4549 |
-
},
|
4550 |
-
|
4551 |
-
/**
|
4552 |
-
* Render tag output
|
4553 |
-
* @param Content_Item item
|
4554 |
-
* @return obj jQuery.Promise object that is resolved when tag is rendered
|
4555 |
-
* Parameters passed to callbacks
|
4556 |
-
* > tag obj Current tag instance
|
4557 |
-
* > output string Tag output
|
4558 |
-
*/
|
4559 |
-
render: function(item) {
|
4560 |
-
var tag = this;
|
4561 |
-
return tag.get_handler().render(item, tag).pipe(function(output) {
|
4562 |
-
return {'tag': tag, 'output': output};
|
4563 |
-
});
|
4564 |
-
},
|
4565 |
-
|
4566 |
-
/**
|
4567 |
-
* Retrieve tag name
|
4568 |
-
* @return string Tag name (DEFAULT: NULL)
|
4569 |
-
*/
|
4570 |
-
get_name: function() {
|
4571 |
-
return this.get_attribute('name');
|
4572 |
-
},
|
4573 |
-
|
4574 |
-
/**
|
4575 |
-
* Retrieve tag property
|
4576 |
-
*/
|
4577 |
-
get_prop: function() {
|
4578 |
-
return this.get_attribute('prop');
|
4579 |
-
},
|
4580 |
-
|
4581 |
-
/**
|
4582 |
-
* Retrieve tag handler
|
4583 |
-
* @return Template_Tag_Handler Handler instance (Empty instance if handler does not exist)
|
4584 |
-
*/
|
4585 |
-
get_handler: function() {
|
4586 |
-
return ( this.has_handler() ) ? this.handlers[this.get_name()] : new View.Template_Tag_Handler('');
|
4587 |
-
},
|
4588 |
-
|
4589 |
-
/**
|
4590 |
-
* Check if handler exists for tag
|
4591 |
-
* @return bool TRUE if handler exists, FALSE otherwise
|
4592 |
-
*/
|
4593 |
-
has_handler: function() {
|
4594 |
-
return ( this.get_name() in this.handlers );
|
4595 |
-
},
|
4596 |
-
|
4597 |
-
/**
|
4598 |
-
* Generate class names for DOM node
|
4599 |
-
* @param string rtype (optional) Return data type
|
4600 |
-
* > Default: array
|
4601 |
-
* > If string supplied: Joined classes delimited by parameter
|
4602 |
-
* @uses get_class() to generate class names
|
4603 |
-
* @uses Array.join() to convert class names array to string
|
4604 |
-
* @return array Class names
|
4605 |
-
*/
|
4606 |
-
get_classes: function(rtype) {
|
4607 |
-
// Build array of class names
|
4608 |
-
var cls = [
|
4609 |
-
// General tag class
|
4610 |
-
this.get_class(),
|
4611 |
-
// Tag name
|
4612 |
-
this.get_class('tag'),
|
4613 |
-
// Tag name + property
|
4614 |
-
this.get_class('full')
|
4615 |
-
];
|
4616 |
-
// Convert class names array to string
|
4617 |
-
if ( this.util.is_string(rtype) ) {
|
4618 |
-
cls = cls.join(rtype);
|
4619 |
-
}
|
4620 |
-
// Return class names
|
4621 |
-
return cls;
|
4622 |
-
},
|
4623 |
-
|
4624 |
-
/**
|
4625 |
-
* Generate DOM-compatible class name based with varied levels of specificity
|
4626 |
-
* @param int level (optional) Class name specificity
|
4627 |
-
* > Default: General tag class (common to all tag elements)
|
4628 |
-
* > tag: Tag Name
|
4629 |
-
* > full: Tag Name + Property
|
4630 |
-
* @return string Class name
|
4631 |
-
*/
|
4632 |
-
get_class: function(level) {
|
4633 |
-
var cls = '';
|
4634 |
-
// Build base
|
4635 |
-
switch ( level ) {
|
4636 |
-
case 'tag' :
|
4637 |
-
// Tag name
|
4638 |
-
cls = this.get_name();
|
4639 |
-
break;
|
4640 |
-
case 'full' :
|
4641 |
-
// Tag name + property
|
4642 |
-
var parts = [this.get_name(), this.get_prop()];
|
4643 |
-
var a = [];
|
4644 |
-
var i;
|
4645 |
-
for ( i = 0; i < parts.length; i++ ) {
|
4646 |
-
if ( this.util.is_string(parts[i]) ) {
|
4647 |
-
a.push(parts[i]);
|
4648 |
-
}
|
4649 |
-
}
|
4650 |
-
cls = a.join('_');
|
4651 |
-
break;
|
4652 |
-
}
|
4653 |
-
// Format & return
|
4654 |
-
return ( !this.util.is_string(cls) ) ? this.get_ns() : this.add_ns(cls);
|
4655 |
-
},
|
4656 |
-
|
4657 |
-
/**
|
4658 |
-
* Generate tag selector based on specified class name level
|
4659 |
-
* @param string level (optional) Class name specificity (@see get_class() for parameter values)
|
4660 |
-
* @return string Tag selector
|
4661 |
-
*/
|
4662 |
-
get_selector: function(level) {
|
4663 |
-
// Get base
|
4664 |
-
var ret = this.get_class(level);
|
4665 |
-
// Format
|
4666 |
-
if ( this.util.is_string(ret) ) {
|
4667 |
-
ret = '.' + ret;
|
4668 |
-
} else {
|
4669 |
-
ret = '';
|
4670 |
-
}
|
4671 |
-
return ret;
|
4672 |
-
}
|
4673 |
-
};
|
4674 |
-
|
4675 |
-
View.Template_Tag = Component.extend(Template_Tag);
|
4676 |
-
|
4677 |
-
/**
|
4678 |
-
* Theme tag handler
|
4679 |
-
*/
|
4680 |
-
var Template_Tag_Handler = {
|
4681 |
-
/* Configuration */
|
4682 |
-
_slug: 'template_tag_handler',
|
4683 |
-
/* Properties */
|
4684 |
-
_attr_default: {
|
4685 |
-
supports_modifiers: false,
|
4686 |
-
dynamic: false,
|
4687 |
-
props: {}
|
4688 |
-
},
|
4689 |
-
|
4690 |
-
/* Methods */
|
4691 |
-
|
4692 |
-
/**
|
4693 |
-
* Render tag output
|
4694 |
-
* @param Content_Item item Item currently being displayed
|
4695 |
-
* @param Template_Tag Tag instance (from template)
|
4696 |
-
* @return obj jQuery.Promise linked to rendering process
|
4697 |
-
*/
|
4698 |
-
render: function(item, instance) {
|
4699 |
-
var dfr = $.Deferred();
|
4700 |
-
// Pass to attribute method
|
4701 |
-
this.call_attribute('render', item, instance, dfr);
|
4702 |
-
// Return promise
|
4703 |
-
return dfr.promise();
|
4704 |
-
},
|
4705 |
-
|
4706 |
-
add_prop: function(prop, fn) {
|
4707 |
-
// Get attribute
|
4708 |
-
var a = 'props';
|
4709 |
-
var props = this.get_attribute(a);
|
4710 |
-
// Validate
|
4711 |
-
if ( !this.util.is_string(prop) || !this.util.is_func(fn) ) {
|
4712 |
-
return false;
|
4713 |
-
}
|
4714 |
-
if ( !this.util.is_obj(props, false) ) {
|
4715 |
-
props = {};
|
4716 |
-
}
|
4717 |
-
// Add property
|
4718 |
-
props[prop] = fn;
|
4719 |
-
// Save attribute
|
4720 |
-
this.set_attribute(a, props);
|
4721 |
-
},
|
4722 |
-
|
4723 |
-
handle_prop: function(prop, item, instance) {
|
4724 |
-
// Locate property
|
4725 |
-
var props = this.get_attribute('props');
|
4726 |
-
var out = '';
|
4727 |
-
if ( this.util.is_obj(props) && ( prop in props ) && this.util.is_func(props[prop]) ) {
|
4728 |
-
out = props[prop].call(this, item, instance);
|
4729 |
-
} else {
|
4730 |
-
out = item.get_viewer().get_label(prop);
|
4731 |
-
}
|
4732 |
-
return out;
|
4733 |
-
}
|
4734 |
-
};
|
4735 |
-
|
4736 |
-
View.Template_Tag_Handler = Component.extend(Template_Tag_Handler);
|
4737 |
-
/* Update References */
|
4738 |
-
|
4739 |
-
// Attach to global object
|
4740 |
-
View = SLB.attach('View', View);
|
4741 |
})(jQuery);}
|
1 |
+
/**
|
2 |
+
* View (Lightbox) functionality
|
3 |
+
* @package Simple Lightbox
|
4 |
+
* @subpackage View
|
5 |
+
* @author Archetyped
|
6 |
+
*/
|
7 |
+
/* global SLB */
|
8 |
+
if ( !!window.SLB && !!SLB.attach ) { (function ($) {
|
9 |
+
|
10 |
+
/*-** Controller **-*/
|
11 |
+
|
12 |
+
var View = {
|
13 |
+
|
14 |
+
/* Properties */
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Media item properties
|
18 |
+
* > Item key: Link URI
|
19 |
+
* > Base properties
|
20 |
+
* > id: WP Attachment ID
|
21 |
+
* > source: Source URI
|
22 |
+
* > title: Media title (generally WP attachment title)
|
23 |
+
* > desc: Media description (generally WP Attachment content)
|
24 |
+
* > type: Asset type (attachment, image, etc.)
|
25 |
+
*/
|
26 |
+
assets: {},
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Component types that can have default instances
|
30 |
+
* @var array
|
31 |
+
*/
|
32 |
+
component_defaults: [],
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Collection of jQuery.Deferred instances added during loading routine
|
36 |
+
* @var array
|
37 |
+
*/
|
38 |
+
loading: [],
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Cache
|
42 |
+
* @var object
|
43 |
+
*/
|
44 |
+
cache: {},
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Temporary component instances
|
48 |
+
* For use by controller when no component instance is available
|
49 |
+
* > Key: Component slug
|
50 |
+
* > Value: Component instance
|
51 |
+
*/
|
52 |
+
component_temps: {},
|
53 |
+
|
54 |
+
/* Options */
|
55 |
+
options: {},
|
56 |
+
|
57 |
+
/* Methods */
|
58 |
+
|
59 |
+
/* Init */
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Instance initialization
|
63 |
+
*/
|
64 |
+
_init: function() {
|
65 |
+
this._super();
|
66 |
+
// Component References
|
67 |
+
this.init_refs();
|
68 |
+
// Components
|
69 |
+
this.init_components();
|
70 |
+
},
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Update component references in component definitions
|
74 |
+
*/
|
75 |
+
init_refs: function() {
|
76 |
+
var r;
|
77 |
+
var ref;
|
78 |
+
var prop;
|
79 |
+
for ( prop in this ) {
|
80 |
+
prop = this[prop];
|
81 |
+
// Process only components
|
82 |
+
if ( !this.is_component(prop) ) {
|
83 |
+
continue;
|
84 |
+
}
|
85 |
+
// Update component references
|
86 |
+
if ( !this.util.is_empty(prop.prototype._refs) ) {
|
87 |
+
for ( r in prop.prototype._refs ) {
|
88 |
+
ref = prop.prototype._refs[r];
|
89 |
+
if ( this.util.is_string(ref) && ref in this ) {
|
90 |
+
ref = prop.prototype._refs[r] = this[ref];
|
91 |
+
}
|
92 |
+
if ( !this.util.is_class(ref) ) {
|
93 |
+
delete prop.prototype_refs[r];
|
94 |
+
}
|
95 |
+
}
|
96 |
+
}
|
97 |
+
}
|
98 |
+
},
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Initialize Components
|
102 |
+
*/
|
103 |
+
init_components: function() {
|
104 |
+
this.component_defaults = [
|
105 |
+
this.Viewer
|
106 |
+
];
|
107 |
+
},
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Client Initialization
|
111 |
+
* @param obj options Global options
|
112 |
+
*/
|
113 |
+
init: function(options) {
|
114 |
+
var t = this;
|
115 |
+
// Defer initialization until all components loaded
|
116 |
+
$.when.apply($, this.loading).always(function() {
|
117 |
+
// Set options
|
118 |
+
$.extend(true, t.options, options);
|
119 |
+
|
120 |
+
/* Event handlers */
|
121 |
+
|
122 |
+
// History
|
123 |
+
$(window).on('popstate', function(e) {
|
124 |
+
var state = e.originalEvent.state;
|
125 |
+
if ( t.util.in_obj(state, ['item', 'viewer']) ) {
|
126 |
+
var v = t.get_viewer(state.viewer);
|
127 |
+
v.history_handle(e);
|
128 |
+
return e.preventDefault();
|
129 |
+
}
|
130 |
+
});
|
131 |
+
|
132 |
+
/* Set defaults */
|
133 |
+
|
134 |
+
// Items
|
135 |
+
t.init_items();
|
136 |
+
});
|
137 |
+
},
|
138 |
+
|
139 |
+
/* Components */
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Check if default component instance can be created
|
143 |
+
* @uses View.component_defaults
|
144 |
+
* @param func type Component type to check
|
145 |
+
* @return bool TRUE if default component instance creation is allowed
|
146 |
+
*/
|
147 |
+
can_make_default_component: function(type) {
|
148 |
+
return ( -1 !== $.inArray(type, this.component_defaults) );
|
149 |
+
},
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Check if object is valid component class
|
153 |
+
* @param func comp Component to check
|
154 |
+
* @return bool TRUE if object is valid component class
|
155 |
+
*/
|
156 |
+
is_component: function(comp) {
|
157 |
+
return ( this.util.is_class(comp, this.Component) );
|
158 |
+
},
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Retrieve collection of components of specified type
|
162 |
+
* @param func type Component type
|
163 |
+
* @return object Component collection (Default: Empty object)
|
164 |
+
*/
|
165 |
+
get_components: function(type) {
|
166 |
+
var ret = {};
|
167 |
+
if ( this.is_component(type) ) {
|
168 |
+
// Determine collection based on component slug
|
169 |
+
var coll = type.prototype._slug + 's';
|
170 |
+
// Create default collection
|
171 |
+
if ( ! ( coll in this.cache ) ) {
|
172 |
+
this.cache[coll] = {};
|
173 |
+
}
|
174 |
+
ret = this.cache[coll];
|
175 |
+
}
|
176 |
+
return ret;
|
177 |
+
},
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Retrieve component from specific collection
|
181 |
+
* @param function type Component type
|
182 |
+
* @param string id Component ID
|
183 |
+
* @return object|null Component reference (NULL if invalid)
|
184 |
+
*/
|
185 |
+
get_component: function(type, id) {
|
186 |
+
var ret = null;
|
187 |
+
// Validate parameters
|
188 |
+
if ( !this.util.is_func(type) ) {
|
189 |
+
return ret;
|
190 |
+
}
|
191 |
+
// Sanitize id
|
192 |
+
if ( !this.util.is_string(id) ) {
|
193 |
+
id = null;
|
194 |
+
}
|
195 |
+
|
196 |
+
// Get component from collection
|
197 |
+
var coll = this.get_components(type);
|
198 |
+
if ( this.util.is_obj(coll) ) {
|
199 |
+
var tid = ( this.util.is_string(id) ) ? id : this.util.add_prefix('default');
|
200 |
+
if ( tid in coll ) {
|
201 |
+
ret = coll[tid];
|
202 |
+
}
|
203 |
+
}
|
204 |
+
|
205 |
+
// Default: Create default component
|
206 |
+
if ( this.util.is_empty(ret) ) {
|
207 |
+
if ( this.util.is_string(id) || this.can_make_default_component(type) ) {
|
208 |
+
ret = this.add_component(type, id);
|
209 |
+
}
|
210 |
+
}
|
211 |
+
// Return component
|
212 |
+
return ret;
|
213 |
+
},
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Create new component instance and save to appropriate collection
|
217 |
+
* @param function type Component type to create
|
218 |
+
* @param string id ID of component
|
219 |
+
* @param object options Component initialization options (Default options used if default component is allowed)
|
220 |
+
* @return object|null New component (NULL if invalid)
|
221 |
+
*/
|
222 |
+
add_component: function(type, id, options) {
|
223 |
+
// Validate type
|
224 |
+
if ( !this.util.is_func(type) ) {
|
225 |
+
return false;
|
226 |
+
}
|
227 |
+
// Validate request
|
228 |
+
if ( this.util.is_empty(id) && !this.can_make_default_component(type) ) {
|
229 |
+
return false;
|
230 |
+
}
|
231 |
+
// Defaults
|
232 |
+
var ret = null;
|
233 |
+
if ( this.util.is_empty(id) ) {
|
234 |
+
id = this.util.add_prefix('default');
|
235 |
+
}
|
236 |
+
if ( !this.util.is_obj(options) ) {
|
237 |
+
options = {};
|
238 |
+
}
|
239 |
+
// Check if specialized method exists for component type
|
240 |
+
var m = ( 'component' !== type.prototype._slug ) ? 'add_' + type.prototype._slug : null;
|
241 |
+
if ( !this.util.is_empty(m) && ( m in this ) && this.util.is_func(this[m]) ) {
|
242 |
+
ret = this[m](id, options);
|
243 |
+
}
|
244 |
+
// Default process
|
245 |
+
else {
|
246 |
+
ret = new type(id, options);
|
247 |
+
}
|
248 |
+
|
249 |
+
// Add new component to collection
|
250 |
+
if ( this.util.is_type(ret, type) ) {
|
251 |
+
// Get collection
|
252 |
+
var coll = this.get_components(type);
|
253 |
+
// Add to collection
|
254 |
+
switch ( $.type(coll) ) {
|
255 |
+
case 'object' :
|
256 |
+
coll[id] = ret;
|
257 |
+
break;
|
258 |
+
case 'array' :
|
259 |
+
coll.push(ret);
|
260 |
+
break;
|
261 |
+
}
|
262 |
+
} else {
|
263 |
+
ret = null;
|
264 |
+
}
|
265 |
+
// Return new component
|
266 |
+
return ret;
|
267 |
+
},
|
268 |
+
|
269 |
+
/**
|
270 |
+
* Create new temporary component instance
|
271 |
+
* @param function type Component type
|
272 |
+
* @return New temporary instance
|
273 |
+
*/
|
274 |
+
add_component_temp: function(type) {
|
275 |
+
var ret = null;
|
276 |
+
if ( this.is_component(type) ) {
|
277 |
+
// Create new instance
|
278 |
+
ret = new type('');
|
279 |
+
// Save to collection
|
280 |
+
this.component_temps[ret._slug] = ret;
|
281 |
+
}
|
282 |
+
return ret;
|
283 |
+
},
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Retrieve temporary component instance
|
287 |
+
* Creates new temp component instance for type if not previously created
|
288 |
+
* @param function type Component type to retrieve temp instance for
|
289 |
+
* @return obj Temporary component instance
|
290 |
+
*/
|
291 |
+
get_component_temp: function(type) {
|
292 |
+
return ( this.has_component_temp(type) ) ? this.component_temps[type.prototype._slug] : this.add_component_temp(type);
|
293 |
+
},
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Check if temporary component instance exists
|
297 |
+
* @param function type Component type to check for
|
298 |
+
* @return bool TRUE if temp instance exists, FALSE otherwise
|
299 |
+
*/
|
300 |
+
has_component_temp: function(type) {
|
301 |
+
return ( this.is_component(type) && ( type.prototype._slug in this.component_temps ) ) ? true : false;
|
302 |
+
},
|
303 |
+
|
304 |
+
/* Properties */
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Retrieve specified options
|
308 |
+
* @param array opts Array of option names
|
309 |
+
* @return object Specified options (Default: empty object)
|
310 |
+
*/
|
311 |
+
get_options: function(opts) {
|
312 |
+
var ret = {};
|
313 |
+
// Validate
|
314 |
+
if ( this.util.is_string(opts) ) {
|
315 |
+
opts = [opts];
|
316 |
+
}
|
317 |
+
if ( !this.util.is_array(opts) ) {
|
318 |
+
return ret;
|
319 |
+
}
|
320 |
+
// Get specified options
|
321 |
+
for ( var x = 0; x < opts.length; x++ ) {
|
322 |
+
// Skip if option not set
|
323 |
+
if ( !( opts[x] in this.options ) ) {
|
324 |
+
continue;
|
325 |
+
}
|
326 |
+
ret[ opts[x] ] = this.options[ opts[x] ];
|
327 |
+
}
|
328 |
+
return ret;
|
329 |
+
},
|
330 |
+
|
331 |
+
/**
|
332 |
+
* Retrieve option
|
333 |
+
* @uses View.options
|
334 |
+
* @param string opt Option to retrieve
|
335 |
+
* @param mixed def (optional) Default value if option does not exist (Default: NULL)
|
336 |
+
* @return mixed Option value
|
337 |
+
*/
|
338 |
+
get_option: function(opt, def) {
|
339 |
+
var ret = this.get_options(opt);
|
340 |
+
if ( this.util.is_obj(ret) && ( opt in ret ) ) {
|
341 |
+
ret = ret[opt];
|
342 |
+
} else {
|
343 |
+
ret = ( this.util.is_set(def) ) ? def : null;
|
344 |
+
}
|
345 |
+
return ret;
|
346 |
+
},
|
347 |
+
|
348 |
+
/* Viewers */
|
349 |
+
|
350 |
+
/**
|
351 |
+
* Add viewer instance to collection
|
352 |
+
* @param string id Viewer ID
|
353 |
+
* @param obj options Viewer options
|
354 |
+
* @return Viewer New viewer instance
|
355 |
+
*/
|
356 |
+
add_viewer: function(id, options) {
|
357 |
+
// Create viewer
|
358 |
+
var v = new this.Viewer(id, options);
|
359 |
+
// Save viewer
|
360 |
+
this.get_viewers()[v.get_id()] = v;
|
361 |
+
// Return viewer
|
362 |
+
return v;
|
363 |
+
},
|
364 |
+
|
365 |
+
/**
|
366 |
+
* Retrieve all viewer instances
|
367 |
+
* @return obj Viewer instances
|
368 |
+
*/
|
369 |
+
get_viewers: function() {
|
370 |
+
return this.get_components(this.Viewer);
|
371 |
+
},
|
372 |
+
|
373 |
+
/**
|
374 |
+
* Check if viewer exists
|
375 |
+
* @param string v Viewer ID
|
376 |
+
* @return bool TRUE if viewer exists, FALSE otherwise
|
377 |
+
*/
|
378 |
+
has_viewer: function(v) {
|
379 |
+
return ( this.util.is_string(v) && v in this.get_viewers() ) ? true : false;
|
380 |
+
},
|
381 |
+
|
382 |
+
/**
|
383 |
+
* Retrieve Viewer instance
|
384 |
+
* Default viewer retrieved if specified viewer does not exist
|
385 |
+
* > Default viewer created if necessary
|
386 |
+
* @param string v Viewer ID to retrieve
|
387 |
+
* @return Viewer Viewer instance
|
388 |
+
*/
|
389 |
+
get_viewer: function(v) {
|
390 |
+
// Retrieve default viewer if specified viewer not set
|
391 |
+
if ( !this.has_viewer(v) ) {
|
392 |
+
v = this.util.add_prefix('default');
|
393 |
+
// Create default viewer if necessary
|
394 |
+
if ( !this.has_viewer(v) ) {
|
395 |
+
v = this.add_viewer(v);
|
396 |
+
v = v.get_id();
|
397 |
+
}
|
398 |
+
}
|
399 |
+
return this.get_viewers()[v];
|
400 |
+
},
|
401 |
+
|
402 |
+
/* Items */
|
403 |
+
|
404 |
+
/**
|
405 |
+
* Set event handlers
|
406 |
+
*/
|
407 |
+
init_items: function() {
|
408 |
+
// Define handler
|
409 |
+
var t = this;
|
410 |
+
var handler = function() {
|
411 |
+
var ret = t.show_item(this);
|
412 |
+
if ( !t.util.is_bool(ret) ) {
|
413 |
+
ret = true;
|
414 |
+
}
|
415 |
+
return !ret;
|
416 |
+
};
|
417 |
+
|
418 |
+
// Get activated links
|
419 |
+
var sel = this.util.format('a[href][%s="%s"]', this.util.get_attribute('active'), 1);
|
420 |
+
// Add event handler
|
421 |
+
$(document).on('click', sel, null, handler);
|
422 |
+
},
|
423 |
+
|
424 |
+
/**
|
425 |
+
* Retrieve cached items
|
426 |
+
* @return obj Items collection
|
427 |
+
*/
|
428 |
+
get_items: function() {
|
429 |
+
return this.get_components(this.Content_Item);
|
430 |
+
},
|
431 |
+
|
432 |
+
/**
|
433 |
+
* Retrieve specific Content_Item instance
|
434 |
+
* @param mixed Item reference
|
435 |
+
* > Content_Item: Item instance (returned immediately)
|
436 |
+
* > DOM element: DOM element to get item for
|
437 |
+
* > int: Index of cached item
|
438 |
+
* @return Content_Item Item instance for DOM node
|
439 |
+
*/
|
440 |
+
get_item: function(ref) {
|
441 |
+
// Evaluate reference type
|
442 |
+
|
443 |
+
// Content Item instance
|
444 |
+
if ( this.util.is_type(ref, this.Content_Item) ) {
|
445 |
+
return ref;
|
446 |
+
}
|
447 |
+
// Retrieve item instance
|
448 |
+
var item = null;
|
449 |
+
|
450 |
+
// DOM element
|
451 |
+
if ( this.util.in_obj(ref, 'nodeType') ) {
|
452 |
+
// Check if item instance attached to element
|
453 |
+
var key = this.get_component_temp(this.Content_Item).get_data_key();
|
454 |
+
item = $(ref).data(key);
|
455 |
+
}
|
456 |
+
// Cached item (index)
|
457 |
+
else if ( this.util.is_string(ref, false) ) {
|
458 |
+
var items = this.get_items();
|
459 |
+
if ( ref in items ) {
|
460 |
+
item = items[ref];
|
461 |
+
}
|
462 |
+
}
|
463 |
+
// Create default item instance
|
464 |
+
if ( !this.util.is_instance(item, this.Content_Item) ) {
|
465 |
+
item = this.add_item(ref);
|
466 |
+
}
|
467 |
+
return item;
|
468 |
+
},
|
469 |
+
|
470 |
+
/**
|
471 |
+
* Create new item instance
|
472 |
+
* @param obj el DOM element representing item
|
473 |
+
* @return Content_Item New item instance
|
474 |
+
*/
|
475 |
+
add_item: function(el) {
|
476 |
+
return ( new this.Content_Item(el) );
|
477 |
+
},
|
478 |
+
|
479 |
+
/**
|
480 |
+
* Display item in viewer
|
481 |
+
* @param obj el DOM element representing item
|
482 |
+
* @return bool Display result (TRUE if item displayed without issues)
|
483 |
+
*/
|
484 |
+
show_item: function(el) {
|
485 |
+
return this.get_item(el).show();
|
486 |
+
},
|
487 |
+
|
488 |
+
/**
|
489 |
+
* Cache item instance
|
490 |
+
* @uses View.get_items() to retrieve item cache
|
491 |
+
* @param Content_Item item Item to cache
|
492 |
+
* @return Content_item Item instance
|
493 |
+
*/
|
494 |
+
save_item: function(item) {
|
495 |
+
if ( !this.util.is_instance(item, this.Content_Item) ) {
|
496 |
+
return item;
|
497 |
+
}
|
498 |
+
// Save item
|
499 |
+
this.get_items()[item.get_id()] = item;
|
500 |
+
// Return item instance
|
501 |
+
return item;
|
502 |
+
},
|
503 |
+
|
504 |
+
/* Content Handler */
|
505 |
+
|
506 |
+
/**
|
507 |
+
* Retrieve content handlers
|
508 |
+
* @return object Content handlers
|
509 |
+
*/
|
510 |
+
get_content_handlers: function() {
|
511 |
+
return this.get_components(this.Content_Handler);
|
512 |
+
},
|
513 |
+
|
514 |
+
/**
|
515 |
+
* Find matching content handler for item
|
516 |
+
* @param Content_Item|string item Item to find handler for (or ID of Handler)
|
517 |
+
* @return Content_Handler|null Matching content handler (NULL if no matching handler found)
|
518 |
+
*/
|
519 |
+
get_content_handler: function(item) {
|
520 |
+
// Determine handler to retrieve
|
521 |
+
var type = ( this.util.is_instance(item, this.Content_Item) ) ? item.get_attribute('type', '') : item.toString();
|
522 |
+
// Retrieve handler
|
523 |
+
var types = this.get_content_handlers();
|
524 |
+
return ( type in types ) ? types[type] : null;
|
525 |
+
},
|
526 |
+
|
527 |
+
/**
|
528 |
+
* Add/Update Content Handler
|
529 |
+
* @param string id Handler ID
|
530 |
+
* @param obj attr Handler attributes
|
531 |
+
* @return obj|null Handler instance (NULL on failure)
|
532 |
+
*/
|
533 |
+
extend_content_handler: function(id, attr) {
|
534 |
+
var hdl = null;
|
535 |
+
if ( !this.util.is_string(id) || !this.util.is_obj(attr) ) {
|
536 |
+
return hdl;
|
537 |
+
}
|
538 |
+
hdl = this.get_content_handler(id);
|
539 |
+
// Add new content handler
|
540 |
+
if ( null === hdl ) {
|
541 |
+
var hdls = this.get_content_handlers();
|
542 |
+
hdls[id] = hdl = new this.Content_Handler(id, attr);
|
543 |
+
}
|
544 |
+
// Update existing handler
|
545 |
+
else {
|
546 |
+
hdl.set_attributes(attr);
|
547 |
+
}
|
548 |
+
// Load styles
|
549 |
+
if ( this.util.in_obj(attr, 'styles') ) {
|
550 |
+
this.load_styles(attr.styles);
|
551 |
+
}
|
552 |
+
return hdl;
|
553 |
+
},
|
554 |
+
|
555 |
+
/* Group */
|
556 |
+
|
557 |
+
/**
|
558 |
+
* Add new group
|
559 |
+
* @param string g Group ID
|
560 |
+
* > If group with same ID already set, new group replaces existing one
|
561 |
+
* @param object attrs (optional) Group attributes
|
562 |
+
* @return Group New group
|
563 |
+
*/
|
564 |
+
add_group: function(g, attrs) {
|
565 |
+
// Create new group
|
566 |
+
g = new this.Group(g, attrs);
|
567 |
+
// Cache group
|
568 |
+
this.get_groups()[g.get_id()] = g;
|
569 |
+
|
570 |
+
return g;
|
571 |
+
},
|
572 |
+
|
573 |
+
/**
|
574 |
+
* Retrieve groups
|
575 |
+
* @uses groups property
|
576 |
+
* @return object Registered groups
|
577 |
+
*/
|
578 |
+
get_groups: function() {
|
579 |
+
return this.get_components(this.Group);
|
580 |
+
},
|
581 |
+
|
582 |
+
/**
|
583 |
+
* Retrieve specified group
|
584 |
+
* New group created if not yet set
|
585 |
+
* @uses View.has_group()
|
586 |
+
* @uses View.add_group()
|
587 |
+
* @uses View.get_groups()
|
588 |
+
* @param string g Group ID
|
589 |
+
* @return Group Group instance
|
590 |
+
*/
|
591 |
+
get_group: function(g) {
|
592 |
+
return ( !this.has_group(g) ) ? this.add_group(g) : this.get_groups()[g];
|
593 |
+
},
|
594 |
+
|
595 |
+
/**
|
596 |
+
* Checks if group is registered
|
597 |
+
* @uses get_groups() to retrieve registered groups
|
598 |
+
* @return bool TRUE if group exists, FALSE otherwise
|
599 |
+
*/
|
600 |
+
has_group: function(g) {
|
601 |
+
return ( this.util.is_string(g) && ( g in this.get_groups() ) );
|
602 |
+
},
|
603 |
+
|
604 |
+
/* Theme */
|
605 |
+
|
606 |
+
/**
|
607 |
+
* Add/Update theme
|
608 |
+
* @param string name Theme name
|
609 |
+
* @param obj attr (optional) Theme options
|
610 |
+
* @return obj|bool Theme model
|
611 |
+
*/
|
612 |
+
extend_theme: function(id, attr) {
|
613 |
+
// Validate
|
614 |
+
if ( !this.util.is_string(id) ) {
|
615 |
+
return false;
|
616 |
+
}
|
617 |
+
var dfr = $.Deferred();
|
618 |
+
this.loading.push(dfr);
|
619 |
+
|
620 |
+
// Get model if it already exists
|
621 |
+
var model = this.get_theme_model(id);
|
622 |
+
|
623 |
+
// Create default attributes for new theme
|
624 |
+
if ( this.util.is_empty(model) ) {
|
625 |
+
// Save default model
|
626 |
+
model = this.save_theme_model( {'parent': null, 'id': id} );
|
627 |
+
}
|
628 |
+
|
629 |
+
// Add custom attributes
|
630 |
+
if ( this.util.is_obj(attr) ) {
|
631 |
+
// Sanitize
|
632 |
+
if ( 'id' in attr ) {
|
633 |
+
delete(attr['id']);
|
634 |
+
}
|
635 |
+
$.extend(model, attr);
|
636 |
+
}
|
637 |
+
|
638 |
+
// Load styles
|
639 |
+
if ( this.util.in_obj(attr, 'styles') ) {
|
640 |
+
this.load_styles(attr.styles);
|
641 |
+
}
|
642 |
+
|
643 |
+
// Link parent model
|
644 |
+
if ( !this.util.is_obj(model.parent) ) {
|
645 |
+
model.parent = this.get_theme_model(model.parent);
|
646 |
+
}
|
647 |
+
|
648 |
+
// Complete loading when all components loaded
|
649 |
+
dfr.resolve();
|
650 |
+
return model;
|
651 |
+
},
|
652 |
+
|
653 |
+
/**
|
654 |
+
* Retrieve theme models
|
655 |
+
* @return obj Theme models
|
656 |
+
*/
|
657 |
+
get_theme_models: function() {
|
658 |
+
// Retrieve matching theme model
|
659 |
+
return this.Theme.prototype._models;
|
660 |
+
},
|
661 |
+
|
662 |
+
/**
|
663 |
+
* Retrieve theme model
|
664 |
+
* @param string id Theme to retrieve
|
665 |
+
* @return obj Theme model (Default: empty object)
|
666 |
+
*/
|
667 |
+
get_theme_model: function(id) {
|
668 |
+
var ms = this.get_theme_models();
|
669 |
+
return ( this.util.in_obj(ms, id) ) ? ms[id] : {};
|
670 |
+
},
|
671 |
+
|
672 |
+
/**
|
673 |
+
* Save theme model
|
674 |
+
* @uses View.get_theme_models() to retrieve Theme model collection
|
675 |
+
* @param obj Theme model to save
|
676 |
+
* @return obj Saved model
|
677 |
+
*/
|
678 |
+
save_theme_model: function(model) {
|
679 |
+
if ( this.util.in_obj(model, 'id') && this.util.is_string(model.id) ) {
|
680 |
+
// Save model
|
681 |
+
this.get_theme_models()[model.id] = model;
|
682 |
+
}
|
683 |
+
return model;
|
684 |
+
},
|
685 |
+
|
686 |
+
/**
|
687 |
+
* Add/Update Template Tag Handler
|
688 |
+
* @param string id Handler ID
|
689 |
+
* @param obj attr Handler attributes
|
690 |
+
* @return obj|bool Handler instance (FALSE on failure)
|
691 |
+
*/
|
692 |
+
extend_template_tag_handler: function(id, attr) {
|
693 |
+
if ( !this.util.is_string(id) || !this.util.is_obj(attr) ) {
|
694 |
+
return false;
|
695 |
+
}
|
696 |
+
var hdl;
|
697 |
+
var hdls = this.get_template_tag_handlers();
|
698 |
+
if ( this.util.in_obj(hdls, id) ) {
|
699 |
+
// Update existing handler
|
700 |
+
hdl = hdls[id];
|
701 |
+
hdl.set_attributes(attr);
|
702 |
+
} else {
|
703 |
+
// Add new content handler
|
704 |
+
hdl = new this.Template_Tag_Handler(id, attr);
|
705 |
+
hdls[hdl.get_id()] = hdl;
|
706 |
+
}
|
707 |
+
// Load styles
|
708 |
+
if ( this.util.in_obj(attr, 'styles') ) {
|
709 |
+
this.load_styles(attr.styles);
|
710 |
+
}
|
711 |
+
// Set hooks
|
712 |
+
if ( this.util.in_obj(attr, '_hooks') ) {
|
713 |
+
attr._hooks.call(hdl);
|
714 |
+
}
|
715 |
+
return hdl;
|
716 |
+
},
|
717 |
+
|
718 |
+
/**
|
719 |
+
* Retrieve Template Tag Handler collection
|
720 |
+
* @return obj Template_Tag_Handler objects
|
721 |
+
*/
|
722 |
+
get_template_tag_handlers: function() {
|
723 |
+
return this.Template_Tag.prototype.handlers;
|
724 |
+
},
|
725 |
+
|
726 |
+
/**
|
727 |
+
* Retrieve template tag handler
|
728 |
+
* @param string id ID of tag handler to retrieve
|
729 |
+
* @return Template_Tag_Handler|null Tag Handler instance (NULL for invalid ID)
|
730 |
+
*/
|
731 |
+
get_template_tag_handler: function(id) {
|
732 |
+
var handlers = this.get_template_tag_handlers();
|
733 |
+
// Retrieve existing handler or return new handler
|
734 |
+
return ( this.util.in_obj(handlers, id) ) ? handlers[id] : null;
|
735 |
+
},
|
736 |
+
|
737 |
+
/**
|
738 |
+
* Load styles
|
739 |
+
* @param array styles Styles to load
|
740 |
+
*/
|
741 |
+
load_styles: function(styles) {
|
742 |
+
if ( this.util.is_array(styles) ) {
|
743 |
+
var out = [];
|
744 |
+
var style;
|
745 |
+
for ( var x = 0; x < styles.length; x++ ) {
|
746 |
+
style = styles[x];
|
747 |
+
if ( !this.util.in_obj(style, 'uri') || !this.util.is_string(style.uri) ) {
|
748 |
+
continue;
|
749 |
+
}
|
750 |
+
out.push('<link rel="stylesheet" type="text/css" href="' + style.uri + '" />');
|
751 |
+
}
|
752 |
+
$('head').append(out.join(''));
|
753 |
+
}
|
754 |
+
}
|
755 |
+
};
|
756 |
+
|
757 |
+
/* Components */
|
758 |
+
var Component = {
|
759 |
+
/*-** Properties **-*/
|
760 |
+
|
761 |
+
/* Internal/Configuration */
|
762 |
+
|
763 |
+
/**
|
764 |
+
* Base name of component type
|
765 |
+
* @var string
|
766 |
+
*/
|
767 |
+
_slug: 'component',
|
768 |
+
|
769 |
+
/**
|
770 |
+
* Component namespace
|
771 |
+
* @var string
|
772 |
+
*/
|
773 |
+
_ns: null,
|
774 |
+
|
775 |
+
/**
|
776 |
+
* Valid component references for current component
|
777 |
+
* @var object
|
778 |
+
* > Key (string): Property name that stores reference
|
779 |
+
* > Value (function): Data type of component
|
780 |
+
*/
|
781 |
+
_refs: {},
|
782 |
+
|
783 |
+
/**
|
784 |
+
* Whether DOM element and component are connected in 1:1 relationship
|
785 |
+
* Some components will be assigned to different DOM elements depending on usage
|
786 |
+
* @var bool
|
787 |
+
*/
|
788 |
+
_reciprocal: false,
|
789 |
+
|
790 |
+
/**
|
791 |
+
* DOM Element tied to component
|
792 |
+
* @var DOM Element
|
793 |
+
*/
|
794 |
+
_dom: null,
|
795 |
+
|
796 |
+
/**
|
797 |
+
* Component attributes
|
798 |
+
* @var object
|
799 |
+
* > Key: Attribute ID
|
800 |
+
* > Value: Attribute value
|
801 |
+
*/
|
802 |
+
_attributes: false,
|
803 |
+
|
804 |
+
/**
|
805 |
+
* Default attributes
|
806 |
+
* @var object
|
807 |
+
*/
|
808 |
+
_attr_default: {},
|
809 |
+
|
810 |
+
/**
|
811 |
+
* Flag indicates whether default attributes have previously been parsed
|
812 |
+
* @var bool
|
813 |
+
*/
|
814 |
+
_attr_default_parsed: false,
|
815 |
+
|
816 |
+
/**
|
817 |
+
* Attributes passed to constructor
|
818 |
+
* @var obj
|
819 |
+
*/
|
820 |
+
_attr_init: null,
|
821 |
+
|
822 |
+
/**
|
823 |
+
* Defines how parent properties should be remapped to component properties
|
824 |
+
* @var object
|
825 |
+
*/
|
826 |
+
_attr_map: {},
|
827 |
+
|
828 |
+
/**
|
829 |
+
* Event handlers
|
830 |
+
* @var object
|
831 |
+
* > Key: string Event type
|
832 |
+
* > Value: array Handlers
|
833 |
+
*/
|
834 |
+
_events: {},
|
835 |
+
|
836 |
+
/**
|
837 |
+
* Status management
|
838 |
+
* @var object
|
839 |
+
* > Key: Status ID
|
840 |
+
* > Value: Status value
|
841 |
+
*/
|
842 |
+
_status: null,
|
843 |
+
|
844 |
+
/**
|
845 |
+
* Component ID
|
846 |
+
* @var string
|
847 |
+
*/
|
848 |
+
_id: '',
|
849 |
+
|
850 |
+
/* Init */
|
851 |
+
|
852 |
+
/**
|
853 |
+
* Constructor
|
854 |
+
* @param string id (optional) Component ID (Default ID will be generated if no valid ID provided)
|
855 |
+
* @param object attributes (optional) Component attributes
|
856 |
+
*/
|
857 |
+
_c: function(id, attributes) {
|
858 |
+
// Set ID
|
859 |
+
this._set_id(id);
|
860 |
+
// Save init attributes
|
861 |
+
if ( this.util.is_obj(attributes) ) {
|
862 |
+
this._attr_init = attributes;
|
863 |
+
}
|
864 |
+
// Call hooks
|
865 |
+
this._hooks();
|
866 |
+
},
|
867 |
+
|
868 |
+
/**
|
869 |
+
* Set Component parent to View module
|
870 |
+
* @uses `_super._set_parent()`
|
871 |
+
*/
|
872 |
+
_set_parent: function() {
|
873 |
+
this._super(View);
|
874 |
+
},
|
875 |
+
|
876 |
+
/**
|
877 |
+
* Register hooks on init
|
878 |
+
* Placeholder method to be overridden by child classes
|
879 |
+
*/
|
880 |
+
_hooks: function() {},
|
881 |
+
|
882 |
+
/* Methods */
|
883 |
+
|
884 |
+
/* Properties */
|
885 |
+
|
886 |
+
/**
|
887 |
+
* Set instance ID
|
888 |
+
* Instance ID can only be set once (will not change ID if valid ID already set)
|
889 |
+
* Generates random GUID if no valid ID provided
|
890 |
+
* @uses Utilities.guid()
|
891 |
+
* @param string id Unique ID
|
892 |
+
* @return string Instance ID
|
893 |
+
*/
|
894 |
+
_set_id: function(id) {
|
895 |
+
// Set ID only once
|
896 |
+
if ( this.util.is_empty(this._id) ) {
|
897 |
+
this._id = ( this.util.is_string(id) ) ? id : this.util.guid();
|
898 |
+
}
|
899 |
+
return this._id;
|
900 |
+
},
|
901 |
+
|
902 |
+
/**
|
903 |
+
* Retrieve instance ID
|
904 |
+
* @uses id as ID base
|
905 |
+
* @uses _slug to add namespace (if necessary)
|
906 |
+
* @param bool ns (optional) Whether or not to namespace ID (Default: FALSE)
|
907 |
+
* @return string Instance ID
|
908 |
+
*/
|
909 |
+
get_id: function(ns) {
|
910 |
+
// Get raw ID
|
911 |
+
var id = this._id;
|
912 |
+
// Namespace ID
|
913 |
+
if ( this.util.is_bool(ns) && ns ) {
|
914 |
+
id = this.add_ns(id);
|
915 |
+
}
|
916 |
+
|
917 |
+
return id;
|
918 |
+
},
|
919 |
+
|
920 |
+
/**
|
921 |
+
* Get namespace
|
922 |
+
* @uses _slug for namespace segment
|
923 |
+
* @uses Util.add_prefix() to prefix slug
|
924 |
+
* @return string Component namespace
|
925 |
+
*/
|
926 |
+
get_ns: function() {
|
927 |
+
if ( null === this._ns ) {
|
928 |
+
this._ns = this.util.add_prefix(this._slug);
|
929 |
+
}
|
930 |
+
return this._ns;
|
931 |
+
},
|
932 |
+
|
933 |
+
/**
|
934 |
+
* Add namespace to value
|
935 |
+
* @param string val Value to namespace
|
936 |
+
* @return string Namespaced value (Empty string if invalid value provided)
|
937 |
+
*/
|
938 |
+
add_ns: function(val) {
|
939 |
+
return ( this.util.is_string(val) ) ? this.get_ns() + '_' + val : '';
|
940 |
+
},
|
941 |
+
|
942 |
+
/**
|
943 |
+
* Retrieve status
|
944 |
+
* @param string id Status to retrieve
|
945 |
+
* @param bool raw (optional) Retrieve raw value (Default: FALSE)
|
946 |
+
* @return mixed Status value (Default: bool)
|
947 |
+
*/
|
948 |
+
get_status: function(id, raw) {
|
949 |
+
var ret = false;
|
950 |
+
if ( this.util.in_obj(this._status, id) ) {
|
951 |
+
ret = ( !!raw ) ? this._status[id] : !!this._status[id];
|
952 |
+
}
|
953 |
+
return ret;
|
954 |
+
},
|
955 |
+
|
956 |
+
/**
|
957 |
+
* Set status
|
958 |
+
* @param string id Status to retrieve
|
959 |
+
* @param mixed val Status value (Default: TRUE)
|
960 |
+
* @return mixed Status value
|
961 |
+
*/
|
962 |
+
set_status: function(id, val) {
|
963 |
+
// Validate ID
|
964 |
+
if ( this.util.is_string(id) ) {
|
965 |
+
// Validate value
|
966 |
+
if ( !this.util.is_set(val) ) {
|
967 |
+
val = true;
|
968 |
+
}
|
969 |
+
// Initialize status collection
|
970 |
+
if ( !this.util.is_obj(this._status, false) ) {
|
971 |
+
this._status = {};
|
972 |
+
}
|
973 |
+
// Set status
|
974 |
+
this._status[id] = val;
|
975 |
+
} else if ( !this.util.is_set(val) ) {
|
976 |
+
val = false;
|
977 |
+
}
|
978 |
+
return val;
|
979 |
+
},
|
980 |
+
|
981 |
+
/**
|
982 |
+
* Get controller object
|
983 |
+
* @uses get_parent() (alias)
|
984 |
+
* @return object Controller object (SLB.View)
|
985 |
+
*/
|
986 |
+
get_controller: function() {
|
987 |
+
return this.get_parent();
|
988 |
+
},
|
989 |
+
|
990 |
+
/* Components */
|
991 |
+
|
992 |
+
/**
|
993 |
+
* Check if reference exists in object
|
994 |
+
* @param string ref Reference ID
|
995 |
+
* @return bool TRUE if reference exists, FALSE otherwise
|
996 |
+
*/
|
997 |
+
has_reference: function(ref) {
|
998 |
+
return ( this.util.is_string(ref) && ( ref in this ) && ( ref in this.get_references() ) ) ? true : false;
|
999 |
+
},
|
1000 |
+
|
1001 |
+
/**
|
1002 |
+
* Retrieve object references
|
1003 |
+
* @uses _refs
|
1004 |
+
* @return obj References object
|
1005 |
+
|
1006 |
+
*/
|
1007 |
+
get_references: function() {
|
1008 |
+
return this._refs;
|
1009 |
+
},
|
1010 |
+
|
1011 |
+
/**
|
1012 |
+
* Retrieve reference data type
|
1013 |
+
* @param string ref Reference ID
|
1014 |
+
* @return function Reference data type (NULL if invalid)
|
1015 |
+
*/
|
1016 |
+
get_reference: function(ref) {
|
1017 |
+
return ( this.has_reference(ref) ) ? this._refs[ref] : null;
|
1018 |
+
},
|
1019 |
+
|
1020 |
+
/**
|
1021 |
+
* Retrieve component reference from current object
|
1022 |
+
* > Procedure:
|
1023 |
+
* > Check if top-level property already set
|
1024 |
+
* > Check attributes
|
1025 |
+
* > Check parent object (controller)
|
1026 |
+
* @param string cname Component name
|
1027 |
+
* @param object options (optional) Request options
|
1028 |
+
* > check_attr bool Whether or not to check instance attributes for component (Default: TRUE)
|
1029 |
+
* > get_default bool Whether or not to retrieve default object from controller if none exists in current instance (Default: FALSE)
|
1030 |
+
* @return object|null Component reference (NULL if no component found)
|
1031 |
+
*/
|
1032 |
+
get_component: function(cname, options) {
|
1033 |
+
var c = null;
|
1034 |
+
// Validate request
|
1035 |
+
if ( !this.has_reference(cname) ) {
|
1036 |
+
return c;
|
1037 |
+
}
|
1038 |
+
|
1039 |
+
// Initialize options
|
1040 |
+
var opt_defaults = {
|
1041 |
+
check_attr: true,
|
1042 |
+
get_default: false
|
1043 |
+
};
|
1044 |
+
options = $.extend({}, opt_defaults, options);
|
1045 |
+
|
1046 |
+
// Get component type
|
1047 |
+
var ctype = this.get_reference(cname);
|
1048 |
+
|
1049 |
+
// Phase 1: Check if component reference previously set
|
1050 |
+
if ( this.util.is_type(this[cname], ctype) ) {
|
1051 |
+
return this[cname];
|
1052 |
+
}
|
1053 |
+
// If reference not set, iterate through component hierarchy until reference is found
|
1054 |
+
c = this[cname] = null;
|
1055 |
+
|
1056 |
+
// Phase 2: Check attributes
|
1057 |
+
if ( options.check_attr ) {
|
1058 |
+
c = this.get_attribute(cname);
|
1059 |
+
// Save object-specific component reference
|
1060 |
+
if ( !this.util.is_empty(c) ) {
|
1061 |
+
c = this.set_component(cname, c);
|
1062 |
+
}
|
1063 |
+
}
|
1064 |
+
|
1065 |
+
// Phase 3: From controller (optional)
|
1066 |
+
if ( this.util.is_empty(c) && options.get_default ) {
|
1067 |
+
c = this.get_controller().get_component(ctype);
|
1068 |
+
}
|
1069 |
+
return c;
|
1070 |
+
},
|
1071 |
+
|
1072 |
+
/**
|
1073 |
+
* Sets component reference on current object
|
1074 |
+
* > Component property reset (set to NULL) if invalid component supplied
|
1075 |
+
* @param string name Name of property to set component on object
|
1076 |
+
* @param string|object ref Component or Component ID (to be retrieved from controller)
|
1077 |
+
* @param function validate (optional) Additional validation to be performed (Must return bool: TRUE (Valid)/FALSE (Invalid))
|
1078 |
+
* @return object Component (NULL if invalid)
|
1079 |
+
*/
|
1080 |
+
set_component: function(name, ref, validate) {
|
1081 |
+
var invalid = null;
|
1082 |
+
// Make sure component property exists
|
1083 |
+
if ( !this.has_reference(name) ) {
|
1084 |
+
return invalid;
|
1085 |
+
}
|
1086 |
+
|
1087 |
+
// Validate reference
|
1088 |
+
if ( this.util.is_empty(ref) ) {
|
1089 |
+
ref = invalid;
|
1090 |
+
} else {
|
1091 |
+
var ctype = this.get_reference(name);
|
1092 |
+
|
1093 |
+
// Get component from controller when ID supplied
|
1094 |
+
if ( this.util.is_string(ref, false) ) {
|
1095 |
+
ref = this.get_controller().get_component(ctype, ref);
|
1096 |
+
}
|
1097 |
+
|
1098 |
+
// Validation callback
|
1099 |
+
if ( !this.util.is_type(ref, ctype) || ( this.util.is_func(validate) && !validate.call(this, ref) ) ) {
|
1100 |
+
ref = invalid;
|
1101 |
+
}
|
1102 |
+
}
|
1103 |
+
|
1104 |
+
// Set (or clear) component reference
|
1105 |
+
this[name] = ref;
|
1106 |
+
// Return value for confirmation
|
1107 |
+
return this[name];
|
1108 |
+
},
|
1109 |
+
|
1110 |
+
|
1111 |
+
/**
|
1112 |
+
* Clear component reference
|
1113 |
+
* @uses set_component() to handle component manipulation
|
1114 |
+
* @param string Component name
|
1115 |
+
*/
|
1116 |
+
clear_component: function(name) {
|
1117 |
+
this.set_component(name, null);
|
1118 |
+
},
|
1119 |
+
|
1120 |
+
/* Attributes */
|
1121 |
+
|
1122 |
+
/**
|
1123 |
+
* Initialize attributes
|
1124 |
+
* @param bool force (optional) Force full initialization of attributes (Default: FALSE)
|
1125 |
+
* @return void
|
1126 |
+
*/
|
1127 |
+
init_attributes: function(force) {
|
1128 |
+
if ( !this.util.is_bool(force) ) {
|
1129 |
+
force = false;
|
1130 |
+
}
|
1131 |
+
if ( force || !this.util.is_obj(this._attributes) ) {
|
1132 |
+
var a = this._attributes = {};
|
1133 |
+
// Default attributes
|
1134 |
+
$.extend(a, this.init_default_attributes());
|
1135 |
+
// Instantiation attributes
|
1136 |
+
if ( this.util.is_obj(this._attr_init) ) {
|
1137 |
+
$.extend(a, this._attr_init);
|
1138 |
+
}
|
1139 |
+
// DOM attributes
|
1140 |
+
$.extend(a, this.get_dom_attributes());
|
1141 |
+
}
|
1142 |
+
},
|
1143 |
+
|
1144 |
+
/**
|
1145 |
+
* Generate default attributes for component
|
1146 |
+
* @uses View.get_options() to get values from controller
|
1147 |
+
* @uses _attr_map to Remap controller attributes to instance attributes
|
1148 |
+
* @uses _attr_default to Store default attributes
|
1149 |
+
* @return obj Default attributes
|
1150 |
+
*/
|
1151 |
+
init_default_attributes: function() {
|
1152 |
+
// Get options from controller
|
1153 |
+
if ( !this._attr_default_parsed && this.util.is_obj(this._attr_map) ) {
|
1154 |
+
var opts = this.get_controller().get_options(this.util.obj_keys(this._attr_map));
|
1155 |
+
|
1156 |
+
if ( this.util.is_obj(opts) ) {
|
1157 |
+
// Remap
|
1158 |
+
for ( var opt in this._attr_map ) {
|
1159 |
+
if ( opt in opts && null !== this._attr_map[opt]) {
|
1160 |
+
// Move value to new property
|
1161 |
+
opts[this._attr_map[opt]] = opts[opt];
|
1162 |
+
// Delete old property
|
1163 |
+
delete opts[opt];
|
1164 |
+
}
|
1165 |
+
}
|
1166 |
+
// Merge with default attributes
|
1167 |
+
$.extend(true, this._attr_default, opts);
|
1168 |
+
}
|
1169 |
+
this._attr_default_parsed = true;
|
1170 |
+
}
|
1171 |
+
return this._attr_default;
|
1172 |
+
},
|
1173 |
+
|
1174 |
+
/**
|
1175 |
+
* Retrieve DOM attributes
|
1176 |
+
* @return obj DOM Attributes
|
1177 |
+
*/
|
1178 |
+
get_dom_attributes: function() {
|
1179 |
+
var attrs = {};
|
1180 |
+
var el = this.dom_get(null, {'init': false});
|
1181 |
+
if ( el.length > 0 ) {
|
1182 |
+
// Get attributes from element
|
1183 |
+
var attrs_full = $(el).get(0).attributes;
|
1184 |
+
if ( this.util.is_obj(attrs_full) ) {
|
1185 |
+
var attr_prefix = this.util.get_attribute();
|
1186 |
+
var attr_key;
|
1187 |
+
$.each(attrs_full, function(idx, attr) {
|
1188 |
+
if ( attr.name.indexOf( attr_prefix ) === -1 ) {
|
1189 |
+
return true;
|
1190 |
+
}
|
1191 |
+
// Process custom attributes (Strip prefix)
|
1192 |
+
attr_key = attr.name.substr(attr_prefix.length + 1);
|
1193 |
+
attrs[attr_key] = attr.value;
|
1194 |
+
});
|
1195 |
+
}
|
1196 |
+
}
|
1197 |
+
return attrs;
|
1198 |
+
},
|
1199 |
+
|
1200 |
+
/**
|
1201 |
+
* Retrieve all instance attributes
|
1202 |
+
* @uses init_attributes() to initialize attributes (if necessary)
|
1203 |
+
* @uses _attributes object
|
1204 |
+
* @return obj Component attributes
|
1205 |
+
*/
|
1206 |
+
get_attributes: function() {
|
1207 |
+
// Initilize attributes
|
1208 |
+
this.init_attributes();
|
1209 |
+
// Return attributes
|
1210 |
+
return this._attributes;
|
1211 |
+
},
|
1212 |
+
|
1213 |
+
/**
|
1214 |
+
* Retrieve value of specified attribute for value
|
1215 |
+
* @param string key Attribute to retrieve
|
1216 |
+
* @param mixed def (optional) Default value if attribute is not set
|
1217 |
+
* @param bool enforce_type (optional) Whether data type should match default value (Default: TRUE)
|
1218 |
+
* > If possible, attribute value will be converted to match default data type
|
1219 |
+
* > If attribute value cannot match default data type, default value will be used
|
1220 |
+
* @return mixed Attribute value (NULL if attribute is not set)
|
1221 |
+
*/
|
1222 |
+
get_attribute: function(key, def, enforce_type) {
|
1223 |
+
// Validate
|
1224 |
+
if ( !this.util.is_set(def) ) {
|
1225 |
+
def = null;
|
1226 |
+
}
|
1227 |
+
if ( !this.util.is_string(key) ) {
|
1228 |
+
return def;
|
1229 |
+
}
|
1230 |
+
if ( !this.util.is_bool(enforce_type) ) {
|
1231 |
+
enforce_type = true;
|
1232 |
+
}
|
1233 |
+
|
1234 |
+
// Get attribute value
|
1235 |
+
var ret = ( this.has_attribute(key) ) ? this.get_attributes()[key] : def;
|
1236 |
+
// Validate type
|
1237 |
+
if ( enforce_type && ret !== def && null !== def && !this.util.is_type(ret, $.type(def), false) ) {
|
1238 |
+
// Convert type
|
1239 |
+
// Scalar default
|
1240 |
+
if ( this.util.is_scalar(def, false) ) {
|
1241 |
+
if ( !this.util.is_scalar(ret, false) ) {
|
1242 |
+
// Non-scalar attribute
|
1243 |
+
ret = def;
|
1244 |
+
} else if ( this.util.is_string(def, false) ) {
|
1245 |
+
// Convert to string
|
1246 |
+
ret = ret.toString();
|
1247 |
+
} else if ( this.util.is_num(def, false) && !this.util.is_num(ret, false) ) {
|
1248 |
+
// Convert to number
|
1249 |
+
ret = ( this.util.is_int(def, false) ) ? parseInt(ret) : parseFloat(ret);
|
1250 |
+
if ( !this.util.is_num(ret, false) ) {
|
1251 |
+
ret = def;
|
1252 |
+
}
|
1253 |
+
} else if ( this.util.is_bool(def, false) ) {
|
1254 |
+
// Convert to boolean
|
1255 |
+
ret = ( this.util.is_string(ret) || ( this.util.is_num(ret) ) );
|
1256 |
+
} else {
|
1257 |
+
// Fallback: Set to default
|
1258 |
+
ret = def;
|
1259 |
+
}
|
1260 |
+
}
|
1261 |
+
// Non-scalar default
|
1262 |
+
else {
|
1263 |
+
ret = def;
|
1264 |
+
}
|
1265 |
+
}
|
1266 |
+
return ret;
|
1267 |
+
},
|
1268 |
+
|
1269 |
+
/**
|
1270 |
+
* Call attribute as method
|
1271 |
+
* @param string attr Attribute to call
|
1272 |
+
* @param arguments (optional) Additional arguments to pass to method
|
1273 |
+
* @return mixed Attribute return value (if attribute is not a function, attribute's value is returned)
|
1274 |
+
*/
|
1275 |
+
call_attribute: function(attr, args) {
|
1276 |
+
attr = this.get_attribute(attr);
|
1277 |
+
if ( this.util.is_func(attr) ) {
|
1278 |
+
// Get arguments
|
1279 |
+
args = Array.prototype.slice.call(arguments, 1);
|
1280 |
+
// Pass arguments to user-defined method
|
1281 |
+
attr = attr.apply(this, args);
|
1282 |
+
}
|
1283 |
+
return attr;
|
1284 |
+
},
|
1285 |
+
|
1286 |
+
/**
|
1287 |
+
* Check if attribute exists
|
1288 |
+
* @param string key Attribute name
|
1289 |
+
* @return bool TRUE if exists, FALSE otherwise
|
1290 |
+
*/
|
1291 |
+
has_attribute: function(key) {
|
1292 |
+
return ( this.util.is_string(key) && ( key in this.get_attributes() ) );
|
1293 |
+
},
|
1294 |
+
|
1295 |
+
/**
|
1296 |
+
* Set component attributes
|
1297 |
+
* @param obj attributes Attributes to set
|
1298 |
+
* @param bool full (optional) Whether to fully replace or merge component's attributes with new values (Default: Merge)
|
1299 |
+
*/
|
1300 |
+
set_attributes: function(attributes, full) {
|
1301 |
+
// Validate
|
1302 |
+
if ( !this.util.is_bool(full) ) {
|
1303 |
+
full = false;
|
1304 |
+
}
|
1305 |
+
|
1306 |
+
// Initialize attributes
|
1307 |
+
this.init_attributes(full);
|
1308 |
+
|
1309 |
+
// Merge new/existing attributes
|
1310 |
+
if ( this.util.is_obj(attributes) ) {
|
1311 |
+
$.extend(this._attributes, attributes);
|
1312 |
+
}
|
1313 |
+
},
|
1314 |
+
|
1315 |
+
/**
|
1316 |
+
* Set value for a component attribute
|
1317 |
+
* @uses get_attributes() to retrieve attributes
|
1318 |
+
* @param string key Attribute to set
|
1319 |
+
* @param mixed val Attribute value
|
1320 |
+
* @return mixed Attribute value
|
1321 |
+
*/
|
1322 |
+
set_attribute: function(key, val) {
|
1323 |
+
if ( this.util.is_string(key) && this.util.is_set(val) ) {
|
1324 |
+
this.get_attributes()[key] = val;
|
1325 |
+
}
|
1326 |
+
return val;
|
1327 |
+
},
|
1328 |
+
|
1329 |
+
/* DOM */
|
1330 |
+
|
1331 |
+
/**
|
1332 |
+
* Generate selector for retrieving child element
|
1333 |
+
* @param string element Class name of child element
|
1334 |
+
* @return string Element selector
|
1335 |
+
*/
|
1336 |
+
dom_get_selector: function(element) {
|
1337 |
+
return ( this.util.is_string(element) ) ? '.' + this.add_ns(element) : '';
|
1338 |
+
},
|
1339 |
+
|
1340 |
+
dom_get_attribute: function() {
|
1341 |
+
return this.util.get_attribute(this._slug);
|
1342 |
+
},
|
1343 |
+
|
1344 |
+
/**
|
1345 |
+
* Set reference of instance on DOM element
|
1346 |
+
* @uses _reciprocal to determine if DOM element should also be attached to instance
|
1347 |
+
* @param string|obj (jQuery) el DOM element to attach instance to
|
1348 |
+
* @return jQuery DOM element set
|
1349 |
+
*/
|
1350 |
+
dom_set: function(el) {
|
1351 |
+
el = $(el);
|
1352 |
+
// Save instance to DOM object
|
1353 |
+
el.data(this.get_data_key(), this);
|
1354 |
+
// Save DOM object to instance
|
1355 |
+
if ( this._reciprocal ) {
|
1356 |
+
this._dom = el;
|
1357 |
+
}
|
1358 |
+
return el;
|
1359 |
+
},
|
1360 |
+
|
1361 |
+
/**
|
1362 |
+
* Retrieve attached DOM element
|
1363 |
+
* @uses _dom to retrieve attached DOM element
|
1364 |
+
* @uses dom_put() to insert child element
|
1365 |
+
* @param string element (optional) ID of child element to retrieve (Default: Main element)
|
1366 |
+
* @param bool put (optional) Whether to insert element if it does not exist (Default: FALSE)
|
1367 |
+
* @param obj options (optional) Runtime options
|
1368 |
+
* @return obj jQuery DOM element
|
1369 |
+
*/
|
1370 |
+
dom_get: function(element, options) {
|
1371 |
+
// Build options
|
1372 |
+
var opts_default = {
|
1373 |
+
'init': true,
|
1374 |
+
'put': false
|
1375 |
+
};
|
1376 |
+
options = ( this.util.is_obj(options) ) ? $.extend({}, opts_default, options) : opts_default;
|
1377 |
+
|
1378 |
+
// Init Component DOM
|
1379 |
+
if ( options.init && !this.get_status('dom_init') ) {
|
1380 |
+
this.set_status('dom_init');
|
1381 |
+
this.dom_init();
|
1382 |
+
}
|
1383 |
+
// Check for main DOM element
|
1384 |
+
var ret = this._dom;
|
1385 |
+
if ( !!ret && this.util.is_string(element) ) {
|
1386 |
+
var ch = $(ret).find( this.dom_get_selector(element) );
|
1387 |
+
// Check for child element
|
1388 |
+
if ( ch.length ) {
|
1389 |
+
ret = ch;
|
1390 |
+
} else if ( true === options.put || this.util.is_obj(options.put) ) {
|
1391 |
+
// Insert child element
|
1392 |
+
ret = this.dom_put(element, options.put);
|
1393 |
+
}
|
1394 |
+
}
|
1395 |
+
return $(ret);
|
1396 |
+
},
|
1397 |
+
|
1398 |
+
/**
|
1399 |
+
* Initialize DOM element
|
1400 |
+
* To be overridden by child classes
|
1401 |
+
*/
|
1402 |
+
dom_init: function() {},
|
1403 |
+
|
1404 |
+
/**
|
1405 |
+
* Wrap output in DOM element
|
1406 |
+
* Wrapper element created and added to main DOM element if not yet created
|
1407 |
+
* @param string element ID for DOM element (Used as class name for wrapper)
|
1408 |
+
* @param string|jQuery|obj content Content to add to DOM (Object contains element properties)
|
1409 |
+
* > tag : Element tag name
|
1410 |
+
* > content : Element content
|
1411 |
+
* @return jQuery Inserted element(s)
|
1412 |
+
*/
|
1413 |
+
dom_put: function(element, content) {
|
1414 |
+
var r = null;
|
1415 |
+
// Stop processing if main DOM element not set or element is not valid
|
1416 |
+
if ( !this.dom_has() || !this.util.is_string(element) ) {
|
1417 |
+
return $(r);
|
1418 |
+
}
|
1419 |
+
// Setup options
|
1420 |
+
var strip = ['tag', 'content', 'success'];
|
1421 |
+
var options = {
|
1422 |
+
'tag': 'div',
|
1423 |
+
'content': '',
|
1424 |
+
'class': this.add_ns(element)
|
1425 |
+
};
|
1426 |
+
// Setup content
|
1427 |
+
if ( !this.util.is_empty(content) ) {
|
1428 |
+
if ( this.util.is_type(content, jQuery, false) || this.util.is_string(content, false) ) {
|
1429 |
+
options.content = content;
|
1430 |
+
}
|
1431 |
+
else if ( this.util.is_obj(content, false) ) {
|
1432 |
+
$.extend(options, content);
|
1433 |
+
}
|
1434 |
+
}
|
1435 |
+
var attrs = $.extend({}, options);
|
1436 |
+
for ( var x = 0; x < strip.length; x++ ) {
|
1437 |
+
delete attrs[strip[x]];
|
1438 |
+
}
|
1439 |
+
// Retrieve existing element
|
1440 |
+
var d = this.dom_get();
|
1441 |
+
r = $(this.dom_get_selector(element), d);
|
1442 |
+
// Create element (if necessary)
|
1443 |
+
if ( !r.length ) {
|
1444 |
+
r = $(this.util.format('<%s />', options.tag), attrs).appendTo(d);
|
1445 |
+
if ( r.length && this.util.is_method(options, 'success') ) {
|
1446 |
+
options['success'].call(r, r);
|
1447 |
+
}
|
1448 |
+
}
|
1449 |
+
// Set content
|
1450 |
+
$(r).append(options.content);
|
1451 |
+
return $(r);
|
1452 |
+
},
|
1453 |
+
|
1454 |
+
/**
|
1455 |
+
* Check if DOM element is set for instance
|
1456 |
+
* DOM is initialized before evaluation
|
1457 |
+
* @return bool TRUE if DOM element set, FALSE otherwise
|
1458 |
+
*/
|
1459 |
+
dom_has: function() {
|
1460 |
+
return ( !!this.dom_get().length );
|
1461 |
+
},
|
1462 |
+
|
1463 |
+
/* Data */
|
1464 |
+
|
1465 |
+
/**
|
1466 |
+
* Retrieve key used to store data in DOM element
|
1467 |
+
* @return string Data key
|
1468 |
+
*/
|
1469 |
+
get_data_key: function() {
|
1470 |
+
return this.get_ns();
|
1471 |
+
},
|
1472 |
+
|
1473 |
+
/* Events */
|
1474 |
+
|
1475 |
+
/**
|
1476 |
+
* Register event handler for custom event
|
1477 |
+
* Structure
|
1478 |
+
* > Events (obj)
|
1479 |
+
* > Event-Name (array)
|
1480 |
+
* > Handlers (functions)
|
1481 |
+
* @param mixed event Custom event to register handler for
|
1482 |
+
* > string: Standard event handler
|
1483 |
+
* > array: Multiple events to register single handler on
|
1484 |
+
* > object: Map of events/handlers
|
1485 |
+
* @param function fn Event handler
|
1486 |
+
* @param obj options Handler registration options
|
1487 |
+
* > clear (bool) Clear existing event handlers before setting current handler (Default: FALSE)
|
1488 |
+
* @return obj Component instance (allows chaining)
|
1489 |
+
*/
|
1490 |
+
on: function(event, fn, options) {
|
1491 |
+
// Handle request types
|
1492 |
+
if ( !this.util.is_string(event) || !this.util.is_func(fn) ) {
|
1493 |
+
var t = this;
|
1494 |
+
var args = Array.prototype.slice.call(arguments, 1);
|
1495 |
+
if ( this.util.is_array(event) ) {
|
1496 |
+
// Events array
|
1497 |
+
$.each(event, function(idx, val) {
|
1498 |
+
t.on.apply(t, [val].concat(args));
|
1499 |
+
});
|
1500 |
+
} else if ( this.util.is_obj(event) ) {
|
1501 |
+
// Events map
|
1502 |
+
$.each(event, function(ev, hdl) {
|
1503 |
+
t.on.apply(t, [ev, hdl].concat(args));
|
1504 |
+
});
|
1505 |
+
}
|
1506 |
+
return this;
|
1507 |
+
}
|
1508 |
+
|
1509 |
+
// Options
|
1510 |
+
|
1511 |
+
// Default options
|
1512 |
+
var options_std = {
|
1513 |
+
clear: false
|
1514 |
+
};
|
1515 |
+
if ( !this.util.is_obj(options, false) ) {
|
1516 |
+
// Reset options
|
1517 |
+
options = {};
|
1518 |
+
}
|
1519 |
+
// Build options
|
1520 |
+
options = $.extend({}, options_std, options);
|
1521 |
+
// Initialize events bucket
|
1522 |
+
if ( !this.util.is_obj(this._events, false) ) {
|
1523 |
+
this._events = {};
|
1524 |
+
}
|
1525 |
+
// Setup event
|
1526 |
+
var es = this._events;
|
1527 |
+
if ( !( event in es ) || !this.util.is_obj(es[event], false) || !!options.clear ) {
|
1528 |
+
es[event] = [];
|
1529 |
+
}
|
1530 |
+
// Add event handler
|
1531 |
+
es[event].push(fn);
|
1532 |
+
return this;
|
1533 |
+
},
|
1534 |
+
|
1535 |
+
/**
|
1536 |
+
* Trigger custom event
|
1537 |
+
* Event handlers are executed in the context of the current component instance
|
1538 |
+
* Event handlers are passed parameters
|
1539 |
+
* > ev (obj) Event object
|
1540 |
+
* > type (string) Event name
|
1541 |
+
* > data (mixed) Data to pass to handlers (if supplied)
|
1542 |
+
* > component (obj) Current component instance
|
1543 |
+
* @param string event Custom event to trigger
|
1544 |
+
* @param mixed data (optional) Data to pass to event handlers
|
1545 |
+
* @return jQuery.Promise Promise that is resolved once event handlers are resolved
|
1546 |
+
*/
|
1547 |
+
trigger: function(event, data) {
|
1548 |
+
var dfr = $.Deferred();
|
1549 |
+
var dfrs = [];
|
1550 |
+
var t = this;
|
1551 |
+
// Handle array of events
|
1552 |
+
if ( this.util.is_array(event) ) {
|
1553 |
+
$.each(event, function(idx, val) {
|
1554 |
+
// Collect promises from triggered events
|
1555 |
+
dfrs.push( t.trigger(val, data) );
|
1556 |
+
});
|
1557 |
+
// Resolve trigger when all events have been resolved
|
1558 |
+
$.when.apply(t, dfrs).done(function() {
|
1559 |
+
dfr.resolve();
|
1560 |
+
});
|
1561 |
+
return dfr.promise();
|
1562 |
+
}
|
1563 |
+
// Validate
|
1564 |
+
if ( !this.util.is_string(event) || !( event in this._events ) ) {
|
1565 |
+
dfr.resolve();
|
1566 |
+
return dfr.promise();
|
1567 |
+
}
|
1568 |
+
// Create event object
|
1569 |
+
var ev = { 'type': event, 'data': null };
|
1570 |
+
// Add data to event object
|
1571 |
+
if ( this.util.is_set(data) ) {
|
1572 |
+
ev.data = data;
|
1573 |
+
}
|
1574 |
+
// Fire handlers for event
|
1575 |
+
$.each(this._events[event], function(idx, fn) {
|
1576 |
+
// Call handler (`this` set to current instance)
|
1577 |
+
// Collect promises from event handlers
|
1578 |
+
dfrs.push( fn.call(t, ev, t) );
|
1579 |
+
});
|
1580 |
+
// Resolve trigger when all handlers have been resolved
|
1581 |
+
$.when.apply(this, dfrs).done(function() {
|
1582 |
+
dfr.resolve();
|
1583 |
+
});
|
1584 |
+
return dfr.promise();
|
1585 |
+
}
|
1586 |
+
};
|
1587 |
+
|
1588 |
+
View.Component = Component = SLB.Class.extend(Component);
|
1589 |
+
|
1590 |
+
/**
|
1591 |
+
* Content viewer
|
1592 |
+
* @param obj options Init options
|
1593 |
+
*/
|
1594 |
+
var Viewer = {
|
1595 |
+
|
1596 |
+
/* Configuration */
|
1597 |
+
|
1598 |
+
_slug: 'viewer',
|
1599 |
+
|
1600 |
+
_refs: {
|
1601 |
+
item: 'Content_Item',
|
1602 |
+
theme: 'Theme'
|
1603 |
+
},
|
1604 |
+
|
1605 |
+
_reciprocal: true,
|
1606 |
+
|
1607 |
+
_attr_default: {
|
1608 |
+
loop: true,
|
1609 |
+
animate: true,
|
1610 |
+
autofit: true,
|
1611 |
+
overlay_enabled: true,
|
1612 |
+
overlay_opacity: '0.8',
|
1613 |
+
title_default: false,
|
1614 |
+
container: null,
|
1615 |
+
slideshow_enabled: true,
|
1616 |
+
slideshow_autostart: false,
|
1617 |
+
slideshow_duration: 2,
|
1618 |
+
slideshow_active: false,
|
1619 |
+
slideshow_timer: null,
|
1620 |
+
labels: {
|
1621 |
+
close: 'close',
|
1622 |
+
nav_prev: '« prev',
|
1623 |
+
nav_next: 'next »',
|
1624 |
+
slideshow_start: 'start slideshow',
|
1625 |
+
slideshow_stop: 'stop slideshow',
|
1626 |
+
group_status: 'Image %current% of %total%',
|
1627 |
+
loading: 'loading'
|
1628 |
+
}
|
1629 |
+
},
|
1630 |
+
|
1631 |
+
_attr_map: {
|
1632 |
+
'theme': null,
|
1633 |
+
'group_loop': 'loop',
|
1634 |
+
'ui_autofit': 'autofit',
|
1635 |
+
'ui_animate': 'animate',
|
1636 |
+
'ui_overlay_opacity': 'overlay_opacity',
|
1637 |
+
'ui_labels': 'labels',
|
1638 |
+
'ui_title_default': 'title_default',
|
1639 |
+
'slideshow_enabled': null,
|
1640 |
+
'slideshow_autostart': null,
|
1641 |
+
'slideshow_duration': null
|
1642 |
+
},
|
1643 |
+
|
1644 |
+
/* References */
|
1645 |
+
|
1646 |
+
/**
|
1647 |
+
* Item currently loaded in viewer
|
1648 |
+
* @var object Content_Item
|
1649 |
+
*/
|
1650 |
+
item: null,
|
1651 |
+
|
1652 |
+
/**
|
1653 |
+
* Queued item to be loaded once viewer is available
|
1654 |
+
* @var object Content_Item
|
1655 |
+
*/
|
1656 |
+
item_queued: null,
|
1657 |
+
|
1658 |
+
/**
|
1659 |
+
* Theme used by viewer
|
1660 |
+
* @var object Theme
|
1661 |
+
*/
|
1662 |
+
theme: null,
|
1663 |
+
|
1664 |
+
/* Properties */
|
1665 |
+
|
1666 |
+
item_working: null,
|
1667 |
+
|
1668 |
+
active: false,
|
1669 |
+
init: false,
|
1670 |
+
open: false,
|
1671 |
+
loading: false,
|
1672 |
+
|
1673 |
+
/* Methods */
|
1674 |
+
|
1675 |
+
/* Init */
|
1676 |
+
|
1677 |
+
_hooks: function() {
|
1678 |
+
var t = this;
|
1679 |
+
this
|
1680 |
+
.on(['item-prev', 'item-next'], function() {
|
1681 |
+
t.trigger('item-change');
|
1682 |
+
})
|
1683 |
+
.on(['close', 'item-change'], function() {
|
1684 |
+
t.unload().done(function() {
|
1685 |
+
t.unlock();
|
1686 |
+
});
|
1687 |
+
});
|
1688 |
+
},
|
1689 |
+
|
1690 |
+
/* References */
|
1691 |
+
|
1692 |
+
/**
|
1693 |
+
* Retrieve item instance current attached to viewer
|
1694 |
+
* @return Content_Item|NULL Current item instance
|
1695 |
+
*/
|
1696 |
+
get_item: function() {
|
1697 |
+
return this.get_component('item');
|
1698 |
+
},
|
1699 |
+
|
1700 |
+
/**
|
1701 |
+
* Set item reference
|
1702 |
+
* Validates item before setting
|
1703 |
+
* @param obj item Content_Item instance
|
1704 |
+
* @return bool TRUE if valid item set, FALSE otherwise
|
1705 |
+
*/
|
1706 |
+
set_item: function(item) {
|
1707 |
+
// Clear existing item
|
1708 |
+
this.clear_item(false);
|
1709 |
+
var i = this.set_component('item', item, function(item) {
|
1710 |
+
return ( item.has_type() );
|
1711 |
+
});
|
1712 |
+
return ( !this.util.is_empty(i) );
|
1713 |
+
},
|
1714 |
+
|
1715 |
+
/**
|
1716 |
+
* Clear item from viewer
|
1717 |
+
* Resets item state and removes reference (if necessary)
|
1718 |
+
* @param bool full (optional) Fully remove item? (Default: TRUE)
|
1719 |
+
*/
|
1720 |
+
clear_item: function(full) {
|
1721 |
+
// Validate
|
1722 |
+
if ( !this.util.is_bool(full) ) {
|
1723 |
+
full = true;
|
1724 |
+
}
|
1725 |
+
var item = this.get_item();
|
1726 |
+
if ( !!item ) {
|
1727 |
+
item.reset();
|
1728 |
+
}
|
1729 |
+
if ( full ) {
|
1730 |
+
this.clear_component('item');
|
1731 |
+
}
|
1732 |
+
},
|
1733 |
+
|
1734 |
+
/**
|
1735 |
+
* Retrieve theme reference
|
1736 |
+
* @return object Theme reference
|
1737 |
+
*/
|
1738 |
+
get_theme: function() {
|
1739 |
+
// Get saved theme
|
1740 |
+
var ret = this.get_component('theme', {check_attr: false});
|
1741 |
+
if ( this.util.is_empty(ret) ) {
|
1742 |
+
// Theme needs to be initialized
|
1743 |
+
ret = this.set_component('theme', new View.Theme(this));
|
1744 |
+
}
|
1745 |
+
return ret;
|
1746 |
+
},
|
1747 |
+
|
1748 |
+
/**
|
1749 |
+
* Set viewer's theme
|
1750 |
+
* @param object theme Theme object
|
1751 |
+
*/
|
1752 |
+
set_theme: function(theme) {
|
1753 |
+
this.set_component('theme', theme);
|
1754 |
+
},
|
1755 |
+
|
1756 |
+
/* Properties */
|
1757 |
+
|
1758 |
+
/**
|
1759 |
+
* Lock the viewer
|
1760 |
+
* Indicates that item is currently being processed
|
1761 |
+
* @return jQuery.Deferred Resolved when item processing is complete
|
1762 |
+
*/
|
1763 |
+
lock: function() {
|
1764 |
+
return this.set_status('item_working', $.Deferred());
|
1765 |
+
},
|
1766 |
+
|
1767 |
+
/**
|
1768 |
+
* Retrieve lock
|
1769 |
+
* @param bool simple (optional) Whether to return a simple status of the locked status (Default: FALSE)
|
1770 |
+
* @param bool full (optional) Whether to return Deferred (TRUE) or Promise (FALSE) object (Default: FALSE)
|
1771 |
+
* @return jQuery.Promise Resolved when item processing is complete
|
1772 |
+
*/
|
1773 |
+
get_lock: function(simple, full) {
|
1774 |
+
// Validate
|
1775 |
+
if ( !this.util.is_bool(simple) ) {
|
1776 |
+
simple = false;
|
1777 |
+
}
|
1778 |
+
if ( !this.util.is_bool(full) ) {
|
1779 |
+
full = false;
|
1780 |
+
}
|
1781 |
+
var s = 'item_working';
|
1782 |
+
// Simple status
|
1783 |
+
if ( simple ) {
|
1784 |
+
return this.get_status(s);
|
1785 |
+
}
|
1786 |
+
// Full value
|
1787 |
+
var r = this.get_status(s, true);
|
1788 |
+
if ( !this.util.is_promise(r) ) {
|
1789 |
+
// Create default
|
1790 |
+
r = this.lock();
|
1791 |
+
}
|
1792 |
+
return ( full ) ? r : r.promise();
|
1793 |
+
},
|
1794 |
+
|
1795 |
+
is_locked: function() {
|
1796 |
+
return this.get_lock(true);
|
1797 |
+
},
|
1798 |
+
|
1799 |
+
/**
|
1800 |
+
* Unlock the viewer
|
1801 |
+
* Any callbacks registered for this action will be executed
|
1802 |
+
* @return jQuery.Deferred Resolved instance
|
1803 |
+
*/
|
1804 |
+
unlock: function() {
|
1805 |
+
return this.get_lock(false, true).resolve();
|
1806 |
+
},
|
1807 |
+
|
1808 |
+
/**
|
1809 |
+
* Set Viewer active status
|
1810 |
+
* @param bool mode (optional) Activate or deactivate status (Default: TRUE)
|
1811 |
+
* @return bool Active status
|
1812 |
+
*/
|
1813 |
+
set_active: function(mode) {
|
1814 |
+
if ( !this.util.is_bool(mode) ) {
|
1815 |
+
mode = true;
|
1816 |
+
}
|
1817 |
+
return this.set_status('active', mode);
|
1818 |
+
},
|
1819 |
+
|
1820 |
+
/**
|
1821 |
+
* Check Viewer active status
|
1822 |
+
* @return bool Active status
|
1823 |
+
*/
|
1824 |
+
is_active: function() {
|
1825 |
+
return this.get_status('active');
|
1826 |
+
},
|
1827 |
+
|
1828 |
+
/**
|
1829 |
+
* Set loading mode
|
1830 |
+
* @param bool mode (optional) Set (TRUE) or unset (FALSE) loading mode (Default: TRUE)
|
1831 |
+
* @return jQuery.Promise Promise that resolves when loading mode is set
|
1832 |
+
*/
|
1833 |
+
set_loading: function(mode) {
|
1834 |
+
var dfr = $.Deferred();
|
1835 |
+
if ( !this.util.is_bool(mode) ) {
|
1836 |
+
mode = true;
|
1837 |
+
}
|
1838 |
+
this.loading = mode;
|
1839 |
+
// Pause/Resume slideshow
|
1840 |
+
if ( this.slideshow_active() ) {
|
1841 |
+
this.slideshow_pause(mode);
|
1842 |
+
}
|
1843 |
+
// Set CSS class on DOM element
|
1844 |
+
var m = ( mode ) ? 'addClass' : 'removeClass';
|
1845 |
+
$(this.dom_get())[m]('loading');
|
1846 |
+
if ( mode ) {
|
1847 |
+
// Loading transition
|
1848 |
+
this.get_theme().transition('load').always(function() {
|
1849 |
+
dfr.resolve();
|
1850 |
+
});
|
1851 |
+
} else {
|
1852 |
+
dfr.resolve();
|
1853 |
+
}
|
1854 |
+
return dfr.promise();
|
1855 |
+
},
|
1856 |
+
|
1857 |
+
/**
|
1858 |
+
* Unset loading mode
|
1859 |
+
* @see set_loading()
|
1860 |
+
* @return jQuery.Promise Promise that resovles when loading mode is set
|
1861 |
+
*/
|
1862 |
+
unset_loading: function() {
|
1863 |
+
return this.set_loading(false);
|
1864 |
+
},
|
1865 |
+
|
1866 |
+
/**
|
1867 |
+
* Retrieve loading status
|
1868 |
+
* @return bool Loading status (Default: FALSE)
|
1869 |
+
*/
|
1870 |
+
get_loading: function() {
|
1871 |
+
return ( this.util.is_bool(this.loading) ) ? this.loading : false;
|
1872 |
+
},
|
1873 |
+
|
1874 |
+
/**
|
1875 |
+
* Check if viewer is currently loading content
|
1876 |
+
* @return bool Loading status (Default: FALSE)
|
1877 |
+
*/
|
1878 |
+
is_loading: function() {
|
1879 |
+
return this.get_loading();
|
1880 |
+
},
|
1881 |
+
|
1882 |
+
/* Display */
|
1883 |
+
|
1884 |
+
/**
|
1885 |
+
* Display content in viewer
|
1886 |
+
* @param Content_Item item Item to show
|
1887 |
+
* @param obj options (optional) Display options
|
1888 |
+
*/
|
1889 |
+
show: function(item) {
|
1890 |
+
this.item_queued = item;
|
1891 |
+
var fin_set = 'show_deferred';
|
1892 |
+
// Validate theme
|
1893 |
+
var vt = 'theme_valid';
|
1894 |
+
var valid = true;
|
1895 |
+
if ( this.has_attribute(vt)) {
|
1896 |
+
valid = this.get_attribute(vt, true);
|
1897 |
+
} else {
|
1898 |
+
valid = ( this.get_theme() && this.get_theme().get_template().get_layout(false) !== "" ) ? true : false;
|
1899 |
+
this.set_attribute(vt, valid);
|
1900 |
+
}
|
1901 |
+
|
1902 |
+
if ( !valid ) {
|
1903 |
+
this.close();
|
1904 |
+
return false;
|
1905 |
+
}
|
1906 |
+
var v = this;
|
1907 |
+
var fin = function() {
|
1908 |
+
// Lock viewer
|
1909 |
+
v.lock();
|
1910 |
+
// Reset callback flag (for new lock)
|
1911 |
+
v.set_status(fin_set, false);
|
1912 |
+
// Validate request
|
1913 |
+
if ( !v.set_item(v.item_queued) ) {
|
1914 |
+
v.close();
|
1915 |
+
return false;
|
1916 |
+
}
|
1917 |
+
// Add item to history stack
|
1918 |
+
v.history_add();
|
1919 |
+
// Activate
|
1920 |
+
v.set_active();
|
1921 |
+
// Display
|
1922 |
+
v.render();
|
1923 |
+
};
|
1924 |
+
if ( !this.is_locked() ) {
|
1925 |
+
fin();
|
1926 |
+
} else if ( !this.get_status(fin_set) ) {
|
1927 |
+
// Set flag to avoid duplicate callbacks
|
1928 |
+
this.set_status(fin_set);
|
1929 |
+
this.get_lock().always(function() {
|
1930 |
+
fin();
|
1931 |
+
});
|
1932 |
+
}
|
1933 |
+
},
|
1934 |
+
|
1935 |
+
/* History Management */
|
1936 |
+
|
1937 |
+
history_handle: function(e) {
|
1938 |
+
var state = e.originalEvent.state;
|
1939 |
+
// Load item
|
1940 |
+
if ( this.util.is_string(state.item, false) ) {
|
1941 |
+
this.get_controller().get_item(state.item).show({'event': e});
|
1942 |
+
this.trigger('item-change');
|
1943 |
+
} else {
|
1944 |
+
var count = this.history_get(true);
|
1945 |
+
// Reset count
|
1946 |
+
this.history_set(0);
|
1947 |
+
// Close viewer
|
1948 |
+
if ( -1 !== count ) {
|
1949 |
+
this.close();
|
1950 |
+
}
|
1951 |
+
}
|
1952 |
+
},
|
1953 |
+
|
1954 |
+
history_get: function(full) {
|
1955 |
+
return this.get_status('history_count', full);
|
1956 |
+
},
|
1957 |
+
history_set: function(val) {
|
1958 |
+
return this.set_status('history_count', val);
|
1959 |
+
},
|
1960 |
+
history_add: function() {
|
1961 |
+
if ( !history.pushState ) {
|
1962 |
+
return false;
|
1963 |
+
}
|
1964 |
+
// Get display options
|
1965 |
+
var item = this.get_item();
|
1966 |
+
var opts = item.get_attribute('options_show');
|
1967 |
+
// Save history state
|
1968 |
+
var count = ( this.history_get() ) ? this.history_get(true) : 0;
|
1969 |
+
if ( !this.util.in_obj(opts, 'event') ) {
|
1970 |
+
// Create state
|
1971 |
+
var state = {
|
1972 |
+
'viewer': this.get_id(),
|
1973 |
+
'item': null,
|
1974 |
+
'count': count
|
1975 |
+
};
|
1976 |
+
// Init: Save viewer state
|
1977 |
+
if ( !count ) {
|
1978 |
+
history.replaceState(state, null);
|
1979 |
+
}
|
1980 |
+
// Always: Save item state
|
1981 |
+
state.item = this.get_controller().save_item(item).get_id();
|
1982 |
+
state.count = ++count;
|
1983 |
+
history.pushState(state, '');
|
1984 |
+
} else {
|
1985 |
+
var e = opts.event.originalEvent;
|
1986 |
+
if ( this.util.in_obj(e, 'state') && this.util.in_obj(e.state, 'count') ) {
|
1987 |
+
count = e.state.count;
|
1988 |
+
}
|
1989 |
+
}
|
1990 |
+
// Save history item count
|
1991 |
+
this.history_set(count);
|
1992 |
+
},
|
1993 |
+
history_reset: function() {
|
1994 |
+
var count = this.history_get(true);
|
1995 |
+
if ( count ) {
|
1996 |
+
// Clear history status
|
1997 |
+
this.history_set(-1);
|
1998 |
+
// Restore history stack
|
1999 |
+
history.go( -1 * count );
|
2000 |
+
}
|
2001 |
+
},
|
2002 |
+
|
2003 |
+
/**
|
2004 |
+
* Check if viewer is currently open
|
2005 |
+
* Checks if node is actually visible in DOM
|
2006 |
+
* @return bool TRUE if viewer is open, FALSE otherwise
|
2007 |
+
*/
|
2008 |
+
is_open: function() {
|
2009 |
+
return ( this.dom_get().css('display') === 'none' ) ? false : true;
|
2010 |
+
},
|
2011 |
+
|
2012 |
+
/**
|
2013 |
+
* Load output into DOM
|
2014 |
+
*/
|
2015 |
+
render: function() {
|
2016 |
+
// Get theme output
|
2017 |
+
var v = this;
|
2018 |
+
var thm = this.get_theme();
|
2019 |
+
v.dom_prep();
|
2020 |
+
// Register theme event handlers
|
2021 |
+
if ( !this.get_status('render-events') ) {
|
2022 |
+
this.set_status('render-events');
|
2023 |
+
thm
|
2024 |
+
// Loading
|
2025 |
+
.on('render-loading', function(ev, thm) {
|
2026 |
+
var dfr = $.Deferred();
|
2027 |
+
if ( !v.is_active() ) {
|
2028 |
+
dfr.reject();
|
2029 |
+
return dfr.promise();
|
2030 |
+
}
|
2031 |
+
var set_pos = function() {
|
2032 |
+
// Set position
|
2033 |
+
v.dom_get().css('top', $(window).scrollTop());
|
2034 |
+
};
|
2035 |
+
var always = function() {
|
2036 |
+
// Set loading flag
|
2037 |
+
v.set_loading().always(function() {
|
2038 |
+
dfr.resolve();
|
2039 |
+
});
|
2040 |
+
};
|
2041 |
+
if ( v.is_open() ) {
|
2042 |
+
thm.transition('unload')
|
2043 |
+
.fail(function() {
|
2044 |
+
set_pos();
|
2045 |
+
thm.dom_get_tag('item', 'content').attr('style', '');
|
2046 |
+
})
|
2047 |
+
.always(always);
|
2048 |
+
} else {
|
2049 |
+
thm.transition('open')
|
2050 |
+
.always(function() {
|
2051 |
+
always();
|
2052 |
+
v.events_open();
|
2053 |
+
v.open = true;
|
2054 |
+
})
|
2055 |
+
.fail(function() {
|
2056 |
+
set_pos();
|
2057 |
+
// Fallback open
|
2058 |
+
v.get_overlay().show();
|
2059 |
+
v.dom_get().show();
|
2060 |
+
});
|
2061 |
+
}
|
2062 |
+
return dfr.promise();
|
2063 |
+
})
|
2064 |
+
// Complete
|
2065 |
+
.on('render-complete', function(ev, thm) {
|
2066 |
+
// Stop if viewer not active
|
2067 |
+
if ( !v.is_active() ) {
|
2068 |
+
return false;
|
2069 |
+
}
|
2070 |
+
// Set classes
|
2071 |
+
var d = v.dom_get();
|
2072 |
+
var classes = ['item_single', 'item_multi'];
|
2073 |
+
var ms = ['addClass', 'removeClass'];
|
2074 |
+
if ( !v.get_item().get_group().is_single() ) {
|
2075 |
+
ms.reverse();
|
2076 |
+
}
|
2077 |
+
$.each(ms, function(idx, val) {
|
2078 |
+
d[val](classes[idx]);
|
2079 |
+
});
|
2080 |
+
// Bind events
|
2081 |
+
v.events_complete();
|
2082 |
+
// Transition
|
2083 |
+
thm.transition('complete')
|
2084 |
+
.fail(function() {
|
2085 |
+
// Autofit content
|
2086 |
+
if ( v.get_attribute('autofit', true) ) {
|
2087 |
+
var dims = $.extend({'display': 'inline-block'}, thm.get_item_dimensions());
|
2088 |
+
thm.dom_get_tag('item', 'content').css(dims);
|
2089 |
+
}
|
2090 |
+
})
|
2091 |
+
.always(function() {
|
2092 |
+
// Unset loading flag
|
2093 |
+
v.unset_loading();
|
2094 |
+
// Trigger event
|
2095 |
+
v.trigger('render-complete');
|
2096 |
+
// Set viewer as initialized
|
2097 |
+
v.init = true;
|
2098 |
+
});
|
2099 |
+
});
|
2100 |
+
}
|
2101 |
+
// Render
|
2102 |
+
thm.render();
|
2103 |
+
},
|
2104 |
+
|
2105 |
+
/**
|
2106 |
+
* Retrieve container element
|
2107 |
+
* Creates default container element if not yet created
|
2108 |
+
* @return jQuery Container element
|
2109 |
+
*/
|
2110 |
+
dom_get_container: function() {
|
2111 |
+
var sel = this.get_attribute('container');
|
2112 |
+
// Set default container
|
2113 |
+
if ( this.util.is_empty(sel) ) {
|
2114 |
+
sel = '#' + this.add_ns('wrap');
|
2115 |
+
}
|
2116 |
+
// Add default container to DOM if not yet present
|
2117 |
+
var c = $(sel);
|
2118 |
+
if ( !c.length ) {
|
2119 |
+
// Prepare ID
|
2120 |
+
var id = ( sel.indexOf('#') === 0 ) ? sel.substr(1) : sel;
|
2121 |
+
// Add element
|
2122 |
+
c = $('<div />', {'id': id}).appendTo('body');
|
2123 |
+
}
|
2124 |
+
return c;
|
2125 |
+
},
|
2126 |
+
|
2127 |
+
/**
|
2128 |
+
* Custom Viewer DOM initialization
|
2129 |
+
*/
|
2130 |
+
dom_init: function() {
|
2131 |
+
// Create element & add to DOM
|
2132 |
+
// Save element to instance
|
2133 |
+
var d = this.dom_set($('<div/>', {
|
2134 |
+
'id': this.get_id(true),
|
2135 |
+
'class': this.get_ns()
|
2136 |
+
})).appendTo(this.dom_get_container()).hide();
|
2137 |
+
// Add theme classes
|
2138 |
+
var thm = this.get_theme();
|
2139 |
+
d.addClass(thm.get_classes(' '));
|
2140 |
+
// Add theme layout (basic)
|
2141 |
+
var v = this;
|
2142 |
+
if ( !this.get_status('render-init') ) {
|
2143 |
+
this.set_status('render-init');
|
2144 |
+
thm.on('render-init', function(ev) {
|
2145 |
+
// Add rendered theme layout to viewer DOM
|
2146 |
+
v.dom_put('layout', ev.data);
|
2147 |
+
});
|
2148 |
+
}
|
2149 |
+
thm.render(true);
|
2150 |
+
},
|
2151 |
+
|
2152 |
+
/**
|
2153 |
+
* Prepare DOM for viewer
|
2154 |
+
*/
|
2155 |
+
dom_prep: function(mode) {
|
2156 |
+
var m = ( this.util.is_bool(mode) && !mode ) ? 'removeClass' : 'addClass';
|
2157 |
+
$('html')[m](this.util.add_prefix('overlay'));
|
2158 |
+
},
|
2159 |
+
|
2160 |
+
/**
|
2161 |
+
* Restore DOM
|
2162 |
+
* Required after viewer is closed
|
2163 |
+
*/
|
2164 |
+
dom_restore: function() {
|
2165 |
+
this.dom_prep(false);
|
2166 |
+
},
|
2167 |
+
|
2168 |
+
/* Layout */
|
2169 |
+
|
2170 |
+
get_layout: function() {
|
2171 |
+
var ret = this.dom_get('layout', {
|
2172 |
+
'put': {
|
2173 |
+
'success': function() {
|
2174 |
+
$(this).hide();
|
2175 |
+
}
|
2176 |
+
}
|
2177 |
+
});
|
2178 |
+
return ret;
|
2179 |
+
},
|
2180 |
+
|
2181 |
+
/* Animation */
|
2182 |
+
|
2183 |
+
animation_enabled: function() {
|
2184 |
+
return this.get_attribute('animate', true);
|
2185 |
+
},
|
2186 |
+
|
2187 |
+
/* Overlay */
|
2188 |
+
|
2189 |
+
/**
|
2190 |
+
* Determine if overlay is enabled for viewer
|
2191 |
+
* @return bool TRUE if overlay is enabled, FALSE otherwise
|
2192 |
+
*/
|
2193 |
+
overlay_enabled: function() {
|
2194 |
+
var ov = this.get_attribute('overlay_enabled');
|
2195 |
+
return ( this.util.is_bool(ov) ) ? ov : false;
|
2196 |
+
},
|
2197 |
+
|
2198 |
+
/**
|
2199 |
+
* Retrieve overlay DOM element
|
2200 |
+
* @return jQuery Overlay element (NULL if no overlay set for viewer)
|
2201 |
+
*/
|
2202 |
+
get_overlay: function() {
|
2203 |
+
var o = null;
|
2204 |
+
var v = this;
|
2205 |
+
if ( this.overlay_enabled() ) {
|
2206 |
+
o = this.dom_get('overlay', {
|
2207 |
+
'put': {
|
2208 |
+
'success': function() {
|
2209 |
+
$(this).hide().css('opacity', v.get_attribute('overlay_opacity'));
|
2210 |
+
}
|
2211 |
+
}
|
2212 |
+
});
|
2213 |
+
}
|
2214 |
+
return $(o);
|
2215 |
+
},
|
2216 |
+
|
2217 |
+
/**
|
2218 |
+
* Unload viewer
|
2219 |
+
*/
|
2220 |
+
unload: function() {
|
2221 |
+
var dfr = $.Deferred();
|
2222 |
+
// Unload item data
|
2223 |
+
this.get_theme().dom_get_tag('item').text('');
|
2224 |
+
dfr.resolve();
|
2225 |
+
return dfr.promise();
|
2226 |
+
},
|
2227 |
+
|
2228 |
+
/**
|
2229 |
+
* Reset viewer
|
2230 |
+
*/
|
2231 |
+
reset: function() {
|
2232 |
+
// Hide viewer
|
2233 |
+
this.dom_get().hide();
|
2234 |
+
// Restore DOM
|
2235 |
+
this.dom_restore();
|
2236 |
+
// History
|
2237 |
+
this.history_reset();
|
2238 |
+
// Item
|
2239 |
+
this.clear_item();
|
2240 |
+
// Reset properties
|
2241 |
+
this.set_active(false);
|
2242 |
+
this.set_loading(false);
|
2243 |
+
this.slideshow_stop();
|
2244 |
+
this.keys_disable();
|
2245 |
+
// Clear for next item
|
2246 |
+
this.unlock();
|
2247 |
+
},
|
2248 |
+
|
2249 |
+
/* Content */
|
2250 |
+
|
2251 |
+
get_labels: function() {
|
2252 |
+
return this.get_attribute('labels', {});
|
2253 |
+
},
|
2254 |
+
|
2255 |
+
get_label: function(name) {
|
2256 |
+
var lbls = this.get_labels();
|
2257 |
+
return ( name in lbls ) ? lbls[name] : '';
|
2258 |
+
},
|
2259 |
+
|
2260 |
+
/* Interactivity */
|
2261 |
+
|
2262 |
+
/**
|
2263 |
+
* Initialize event handlers upon opening lightbox
|
2264 |
+
*/
|
2265 |
+
events_open: function() {
|
2266 |
+
// Keyboard bindings
|
2267 |
+
this.keys_enable();
|
2268 |
+
if ( this.open ) {
|
2269 |
+
return false;
|
2270 |
+
}
|
2271 |
+
|
2272 |
+
// Control event bubbling
|
2273 |
+
var l = this.get_layout();
|
2274 |
+
l.children().click(function(ev) {
|
2275 |
+
ev.stopPropagation();
|
2276 |
+
});
|
2277 |
+
|
2278 |
+
/* Close */
|
2279 |
+
var v = this;
|
2280 |
+
var close = function() {
|
2281 |
+
v.close();
|
2282 |
+
};
|
2283 |
+
// Layout
|
2284 |
+
l.click(close);
|
2285 |
+
// Overlay
|
2286 |
+
this.get_overlay().click(close);
|
2287 |
+
// Fire event
|
2288 |
+
this.trigger('events-open');
|
2289 |
+
},
|
2290 |
+
|
2291 |
+
/**
|
2292 |
+
* Initialize event handlers upon completing lightbox rendering
|
2293 |
+
*/
|
2294 |
+
events_complete: function() {
|
2295 |
+
if ( this.init ) {
|
2296 |
+
return false;
|
2297 |
+
}
|
2298 |
+
// Fire event
|
2299 |
+
this.trigger('events-complete');
|
2300 |
+
},
|
2301 |
+
|
2302 |
+
keys_enable: function(mode) {
|
2303 |
+
if ( !this.util.is_bool(mode) ) {
|
2304 |
+
mode = true;
|
2305 |
+
}
|
2306 |
+
var e = ['keyup', this.util.get_prefix()].join('.');
|
2307 |
+
var v = this;
|
2308 |
+
var h = function(ev) {
|
2309 |
+
return v.keys_control(ev);
|
2310 |
+
};
|
2311 |
+
if ( mode ) {
|
2312 |
+
$(document).on(e, h);
|
2313 |
+
} else {
|
2314 |
+
$(document).off(e);
|
2315 |
+
}
|
2316 |
+
},
|
2317 |
+
|
2318 |
+
keys_disable: function() {
|
2319 |
+
this.keys_enable(false);
|
2320 |
+
},
|
2321 |
+
|
2322 |
+
keys_control: function(ev) {
|
2323 |
+
var handlers = {
|
2324 |
+
27: this.close, /* esc */
|
2325 |
+
37: this.item_prev, /* left-arrow */
|
2326 |
+
39: this.item_next, /* right-arrow */
|
2327 |
+
};
|
2328 |
+
// Swap next/prev keys on RTL pages
|
2329 |
+
if ('rtl' === document.documentElement.getAttribute('dir')) {
|
2330 |
+
handlers[37] = this.item_next; /* left-arrow */
|
2331 |
+
handlers[39] = this.item_prev; /* right-arrow */
|
2332 |
+
}
|
2333 |
+
if ( ev.which in handlers ) {
|
2334 |
+
handlers[ev.which].call(this);
|
2335 |
+
return false;
|
2336 |
+
}
|
2337 |
+
},
|
2338 |
+
|
2339 |
+
/**
|
2340 |
+
* Check if slideshow functionality is enabled
|
2341 |
+
* @return bool TRUE if slideshow is enabled, FALSE otherwise
|
2342 |
+
*/
|
2343 |
+
slideshow_enabled: function() {
|
2344 |
+
var o = this.get_attribute('slideshow_enabled');
|
2345 |
+
return ( this.util.is_bool(o) && o && this.get_item() && !this.get_item().get_group().is_single() ) ? true : false;
|
2346 |
+
},
|
2347 |
+
|
2348 |
+
/**
|
2349 |
+
* Checks if slideshow is currently active
|
2350 |
+
* @return bool TRUE if slideshow is active, FALSE otherwise
|
2351 |
+
*/
|
2352 |
+
slideshow_active: function() {
|
2353 |
+
return ( this.slideshow_enabled() && ( this.get_attribute('slideshow_active') || ( !this.init && this.get_attribute('slideshow_autostart') ) ) ) ? true : false;
|
2354 |
+
},
|
2355 |
+
|
2356 |
+
/**
|
2357 |
+
* Clear slideshow timer
|
2358 |
+
*/
|
2359 |
+
slideshow_clear_timer: function() {
|
2360 |
+
clearInterval(this.get_attribute('slideshow_timer'));
|
2361 |
+
},
|
2362 |
+
|
2363 |
+
/**
|
2364 |
+
* Start slideshow timer
|
2365 |
+
* @param function callback Callback function
|
2366 |
+
*/
|
2367 |
+
slideshow_set_timer: function(callback) {
|
2368 |
+
this.set_attribute('slideshow_timer', setInterval(callback, this.get_attribute('slideshow_duration') * 1000));
|
2369 |
+
},
|
2370 |
+
|
2371 |
+
/**
|
2372 |
+
* Start Slideshow
|
2373 |
+
*/
|
2374 |
+
slideshow_start: function() {
|
2375 |
+
if ( !this.slideshow_enabled() ) {
|
2376 |
+
return false;
|
2377 |
+
}
|
2378 |
+
this.set_attribute('slideshow_active', true);
|
2379 |
+
this.dom_get().addClass('slideshow_active');
|
2380 |
+
// Clear residual timers
|
2381 |
+
this.slideshow_clear_timer();
|
2382 |
+
// Start timer
|
2383 |
+
var v = this;
|
2384 |
+
this.slideshow_set_timer(function() {
|
2385 |
+
// Pause slideshow until next item fully loaded
|
2386 |
+
v.slideshow_pause();
|
2387 |
+
|
2388 |
+
// Show next item
|
2389 |
+
v.item_next();
|
2390 |
+
});
|
2391 |
+
this.trigger('slideshow-start');
|
2392 |
+
},
|
2393 |
+
|
2394 |
+
/**
|
2395 |
+
* Stop Slideshow
|
2396 |
+
* @param bool full (optional) Full stop (TRUE) or pause (FALSE) (Default: TRUE)
|
2397 |
+
*/
|
2398 |
+
slideshow_stop: function(full) {
|
2399 |
+
if ( !this.util.is_bool(full) ) {
|
2400 |
+
full = true;
|
2401 |
+
}
|
2402 |
+
if ( full ) {
|
2403 |
+
this.set_attribute('slideshow_active', false);
|
2404 |
+
this.dom_get().removeClass('slideshow_active');
|
2405 |
+
}
|
2406 |
+
// Kill timers
|
2407 |
+
this.slideshow_clear_timer();
|
2408 |
+
this.trigger('slideshow-stop');
|
2409 |
+
},
|
2410 |
+
|
2411 |
+
slideshow_toggle: function() {
|
2412 |
+
if ( !this.slideshow_enabled() ) {
|
2413 |
+
return false;
|
2414 |
+
}
|
2415 |
+
if ( this.slideshow_active() ) {
|
2416 |
+
this.slideshow_stop();
|
2417 |
+
} else {
|
2418 |
+
this.slideshow_start();
|
2419 |
+
}
|
2420 |
+
this.trigger('slideshow-toggle');
|
2421 |
+
},
|
2422 |
+
|
2423 |
+
/**
|
2424 |
+
* Pause Slideshow
|
2425 |
+
* @param bool mode (optional) Pause (TRUE) or Resume (FALSE) slideshow (default: TRUE)
|
2426 |
+
*/
|
2427 |
+
slideshow_pause: function(mode) {
|
2428 |
+
// Validate
|
2429 |
+
if ( !this.util.is_bool(mode) ) {
|
2430 |
+
mode = true;
|
2431 |
+
}
|
2432 |
+
// Set viewer slideshow properties
|
2433 |
+
if ( this.slideshow_active() ) {
|
2434 |
+
if ( !mode ) {
|
2435 |
+
// Slideshow resumed
|
2436 |
+
this.slideshow_start();
|
2437 |
+
} else {
|
2438 |
+
// Slideshow paused
|
2439 |
+
this.slideshow_stop(false);
|
2440 |
+
}
|
2441 |
+
}
|
2442 |
+
this.trigger('slideshow-pause');
|
2443 |
+
},
|
2444 |
+
|
2445 |
+
/**
|
2446 |
+
* Resume slideshow
|
2447 |
+
*/
|
2448 |
+
slideshow_resume: function() {
|
2449 |
+
this.slideshow_pause(false);
|
2450 |
+
},
|
2451 |
+
|
2452 |
+
/**
|
2453 |
+
* Next item
|
2454 |
+
*/
|
2455 |
+
item_next: function() {
|
2456 |
+
var g = this.get_item().get_group(true);
|
2457 |
+
var v = this;
|
2458 |
+
var ev = 'item-next';
|
2459 |
+
var st = ['events', 'viewer', ev].join('_');
|
2460 |
+
// Setup event handler
|
2461 |
+
if ( !g.get_status(st) ) {
|
2462 |
+
g.set_status(st);
|
2463 |
+
g.on(ev, function(e) {
|
2464 |
+
v.trigger(e.type);
|
2465 |
+
});
|
2466 |
+
}
|
2467 |
+
g.show_next();
|
2468 |
+
},
|
2469 |
+
|
2470 |
+
/**
|
2471 |
+
* Previous item
|
2472 |
+
*/
|
2473 |
+
item_prev: function() {
|
2474 |
+
var g = this.get_item().get_group(true);
|
2475 |
+
var v = this;
|
2476 |
+
var ev = 'item-prev';
|
2477 |
+
var st = ['events', 'viewer', ev].join('_');
|
2478 |
+
if ( !g.get_status(st) ) {
|
2479 |
+
g.set_status(st);
|
2480 |
+
g.on(ev, function() {
|
2481 |
+
v.trigger(ev);
|
2482 |
+
});
|
2483 |
+
}
|
2484 |
+
g.show_prev();
|
2485 |
+
},
|
2486 |
+
|
2487 |
+
/**
|
2488 |
+
* Close viewer
|
2489 |
+
*/
|
2490 |
+
close: function() {
|
2491 |
+
// Deactivate
|
2492 |
+
this.set_active(false);
|
2493 |
+
var v = this;
|
2494 |
+
var thm = this.get_theme();
|
2495 |
+
thm.transition('unload')
|
2496 |
+
.always(function() {
|
2497 |
+
thm.transition('close', true).always(function() {
|
2498 |
+
// End processes
|
2499 |
+
v.reset();
|
2500 |
+
v.trigger('close');
|
2501 |
+
});
|
2502 |
+
})
|
2503 |
+
.fail(function() {
|
2504 |
+
thm.dom_get_tag('item', 'content').attr('style', '');
|
2505 |
+
});
|
2506 |
+
return false;
|
2507 |
+
}
|
2508 |
+
};
|
2509 |
+
|
2510 |
+
View.Viewer = Component.extend(Viewer);
|
2511 |
+
|
2512 |
+
/**
|
2513 |
+
* Content group
|
2514 |
+
* @param obj options Init options
|
2515 |
+
*/
|
2516 |
+
var Group = {
|
2517 |
+
/* Configuration */
|
2518 |
+
|
2519 |
+
_slug: 'group',
|
2520 |
+
_reciprocal: true,
|
2521 |
+
_refs: {
|
2522 |
+
'current': 'Content_Item'
|
2523 |
+
},
|
2524 |
+
|
2525 |
+
/* References */
|
2526 |
+
|
2527 |
+
current: null,
|
2528 |
+
|
2529 |
+
/* Properties */
|
2530 |
+
|
2531 |
+
/**
|
2532 |
+
* Selector for getting group items
|
2533 |
+
* @var string
|
2534 |
+
*/
|
2535 |
+
selector: null,
|
2536 |
+
|
2537 |
+
/* Methods */
|
2538 |
+
|
2539 |
+
/* Init */
|
2540 |
+
|
2541 |
+
_hooks: function() {
|
2542 |
+
var t = this;
|
2543 |
+
this.on(['item-prev', 'item-next'], function() {
|
2544 |
+
t.trigger('item-change');
|
2545 |
+
});
|
2546 |
+
},
|
2547 |
+
|
2548 |
+
/* Properties */
|
2549 |
+
|
2550 |
+
/**
|
2551 |
+
* Retrieve selector for group items
|
2552 |
+
* @return string Group items selector
|
2553 |
+
*/
|
2554 |
+
get_selector: function() {
|
2555 |
+
if ( this.util.is_empty(this.selector) ) {
|
2556 |
+
// Build selector
|
2557 |
+
this.selector = this.util.format('a[%s="%s"]', this.dom_get_attribute(), this.get_id());
|
2558 |
+
}
|
2559 |
+
return this.selector;
|
2560 |
+
},
|
2561 |
+
|
2562 |
+
/**
|
2563 |
+
* Retrieve group items
|
2564 |
+
*/
|
2565 |
+
get_items: function() {
|
2566 |
+
var items = $(this.get_selector());
|
2567 |
+
if ( 0 === items.length && this.has_current() ) {
|
2568 |
+
items = this.get_current().dom_get();
|
2569 |
+
}
|
2570 |
+
return items;
|
2571 |
+
},
|
2572 |
+
|
2573 |
+
/**
|
2574 |
+
* Retrieve item at specified index
|
2575 |
+
* If no index specified, first item is returned
|
2576 |
+
* @param int idx Index of item to return
|
2577 |
+
* @return Content_Item Item
|
2578 |
+
*/
|
2579 |
+
get_item: function(idx) {
|
2580 |
+
// Validation
|
2581 |
+
if ( !this.util.is_int(idx) ) {
|
2582 |
+
idx = 0;
|
2583 |
+
}
|
2584 |
+
// Retrieve all items
|
2585 |
+
var items = this.get_items();
|
2586 |
+
// Validate index
|
2587 |
+
var max = this.get_size() - 1;
|
2588 |
+
if ( idx > max ) {
|
2589 |
+
idx = max;
|
2590 |
+
}
|
2591 |
+
// Return specified item
|
2592 |
+
return items.get(idx);
|
2593 |
+
},
|
2594 |
+
|
2595 |
+
/**
|
2596 |
+
* Retrieve (zero-based) position of specified item in group
|
2597 |
+
* @param Content_Item item Item to locate in group
|
2598 |
+
* @return int Index position of item in group (-1 if item not in group)
|
2599 |
+
*/
|
2600 |
+
get_pos: function(item) {
|
2601 |
+
if ( this.util.is_empty(item) ) {
|
2602 |
+
// Get current item
|
2603 |
+
item = this.get_current();
|
2604 |
+
}
|
2605 |
+
return ( this.util.is_type(item, View.Content_Item) ) ? this.get_items().index(item.dom_get()) : -1;
|
2606 |
+
},
|
2607 |
+
|
2608 |
+
/**
|
2609 |
+
* Check if current item set in group
|
2610 |
+
* @return bool TRUE if current item is set
|
2611 |
+
*/
|
2612 |
+
has_current: function() {
|
2613 |
+
// Sanitize
|
2614 |
+
return ( !this.util.is_empty( this.get_current() ) );
|
2615 |
+
},
|
2616 |
+
|
2617 |
+
/**
|
2618 |
+
* Retrieve current item
|
2619 |
+
* @uses Group.current
|
2620 |
+
* @return NULL|Content_Item Current item (NULL if current item not set or invalid)
|
2621 |
+
*/
|
2622 |
+
get_current: function() {
|
2623 |
+
// Sanitize
|
2624 |
+
if ( null !== this.current && !this.util.is_type(this.current, View.Content_Item) ) {
|
2625 |
+
this.current = null;
|
2626 |
+
}
|
2627 |
+
return this.current;
|
2628 |
+
},
|
2629 |
+
|
2630 |
+
/**
|
2631 |
+
* Sets current group item
|
2632 |
+
* @param Content_Item item Item to set as current
|
2633 |
+
*/
|
2634 |
+
set_current: function(item) {
|
2635 |
+
// Validate
|
2636 |
+
if ( this.util.is_type(item, View.Content_Item) ) {
|
2637 |
+
// Set current item
|
2638 |
+
this.current = item;
|
2639 |
+
}
|
2640 |
+
},
|
2641 |
+
|
2642 |
+
get_next: function(item) {
|
2643 |
+
// Validate
|
2644 |
+
if ( !this.util.is_type(item, View.Content_Item) ) {
|
2645 |
+
item = this.get_current();
|
2646 |
+
}
|
2647 |
+
if ( this.get_size() === 1 ) {
|
2648 |
+
return item;
|
2649 |
+
}
|
2650 |
+
var next = null;
|
2651 |
+
var pos = this.get_pos(item);
|
2652 |
+
if ( pos !== -1 ) {
|
2653 |
+
pos = ( pos + 1 < this.get_size() ) ? pos + 1 : 0;
|
2654 |
+
if ( 0 !== pos || item.get_viewer().get_attribute('loop') ) {
|
2655 |
+
next = this.get_item(pos);
|
2656 |
+
}
|
2657 |
+
}
|
2658 |
+
return next;
|
2659 |
+
},
|
2660 |
+
|
2661 |
+
get_prev: function(item) {
|
2662 |
+
// Validate
|
2663 |
+
if ( !this.util.is_type(item, View.Content_Item) ) {
|
2664 |
+
item = this.get_current();
|
2665 |
+
}
|
2666 |
+
if ( this.get_size() === 1 ) {
|
2667 |
+
return item;
|
2668 |
+
}
|
2669 |
+
var prev = null;
|
2670 |
+
var pos = this.get_pos(item);
|
2671 |
+
if ( pos !== -1 && ( 0 !== pos || item.get_viewer().get_attribute('loop') ) ) {
|
2672 |
+
if ( pos === 0 ) {
|
2673 |
+
pos = this.get_size();
|
2674 |
+
}
|
2675 |
+
pos -= 1;
|
2676 |
+
prev = this.get_item(pos);
|
2677 |
+
}
|
2678 |
+
return prev;
|
2679 |
+
},
|
2680 |
+
|
2681 |
+
show_next: function(item) {
|
2682 |
+
if ( this.get_size() > 1 ) {
|
2683 |
+
// Retrieve item
|
2684 |
+
var next = this.get_next(item);
|
2685 |
+
if ( !next ) {
|
2686 |
+
if ( !this.util.is_type(item, View.Content_Item) ) {
|
2687 |
+
item = this.get_current();
|
2688 |
+
}
|
2689 |
+
item.get_viewer().close();
|
2690 |
+
}
|
2691 |
+
var i = this.get_controller().get_item(next);
|
2692 |
+
// Update current item
|
2693 |
+
this.set_current(i);
|
2694 |
+
// Show item
|
2695 |
+
i.show();
|
2696 |
+
// Fire event
|
2697 |
+
this.trigger('item-next');
|
2698 |
+
}
|
2699 |
+
},
|
2700 |
+
|
2701 |
+
show_prev: function(item) {
|
2702 |
+
if ( this.get_size() > 1 ) {
|
2703 |
+
// Retrieve item
|
2704 |
+
var prev = this.get_prev(item);
|
2705 |
+
if ( !prev ) {
|
2706 |
+
if ( !this.util.is_type(item, View.Content_Item) ) {
|
2707 |
+
item = this.get_current();
|
2708 |
+
}
|
2709 |
+
item.get_viewer().close();
|
2710 |
+
}
|
2711 |
+
var i = this.get_controller().get_item(prev);
|
2712 |
+
// Update current item
|
2713 |
+
this.set_current(i);
|
2714 |
+
// Show item
|
2715 |
+
i.show();
|
2716 |
+
// Fire event
|
2717 |
+
this.trigger('item-prev');
|
2718 |
+
}
|
2719 |
+
},
|
2720 |
+
|
2721 |
+
/**
|
2722 |
+
* Retrieve total number of items in group
|
2723 |
+
* @return int Number of items in group
|
2724 |
+
*/
|
2725 |
+
get_size: function() {
|
2726 |
+
return this.get_items().length;
|
2727 |
+
},
|
2728 |
+
|
2729 |
+
is_single: function() {
|
2730 |
+
return ( this.get_size() === 1 );
|
2731 |
+
}
|
2732 |
+
};
|
2733 |
+
|
2734 |
+
View.Group = Component.extend(Group);
|
2735 |
+
|
2736 |
+
/**
|
2737 |
+
* Content Handler
|
2738 |
+
* @param obj options Init options
|
2739 |
+
*/
|
2740 |
+
var Content_Handler = {
|
2741 |
+
|
2742 |
+
/* Configuration */
|
2743 |
+
|
2744 |
+
_slug: 'content_handler',
|
2745 |
+
_refs: {
|
2746 |
+
'item': 'Content_Item'
|
2747 |
+
},
|
2748 |
+
|
2749 |
+
/* References */
|
2750 |
+
|
2751 |
+
item: null,
|
2752 |
+
|
2753 |
+
/* Properties */
|
2754 |
+
|
2755 |
+
/**
|
2756 |
+
* Raw layout template
|
2757 |
+
* @var string
|
2758 |
+
*/
|
2759 |
+
template: '',
|
2760 |
+
|
2761 |
+
/* Methods */
|
2762 |
+
|
2763 |
+
/* Item */
|
2764 |
+
|
2765 |
+
/**
|
2766 |
+
* Check if item instance set for type
|
2767 |
+
* @uses get_item()
|
2768 |
+
* @uses clear_item() to remove invalid item values
|
2769 |
+
* @return bool TRUE if valid item set, FALSE otherwise
|
2770 |
+
*/
|
2771 |
+
has_item: function() {
|
2772 |
+
return ( this.util.is_empty(this.get_item()) ) ? false : true;
|
2773 |
+
},
|
2774 |
+
|
2775 |
+
/**
|
2776 |
+
* Retrieve item instance set on type
|
2777 |
+
* @uses get_component()
|
2778 |
+
* @return mixed Content_Item if valid item set, NULL otherwise
|
2779 |
+
*/
|
2780 |
+
get_item: function() {
|
2781 |
+
return this.get_component('item');
|
2782 |
+
},
|
2783 |
+
|
2784 |
+
/**
|
2785 |
+
* Set item instance for type
|
2786 |
+
* Items are only meant to be set/used while item is being processed
|
2787 |
+
* @uses set_component()
|
2788 |
+
* @param Content_Item item Item instance
|
2789 |
+
* @return obj|null Item instance if item successfully set, NULL otherwise
|
2790 |
+
*/
|
2791 |
+
set_item: function(item) {
|
2792 |
+
// Set reference
|
2793 |
+
var r = this.set_component('item', item);
|
2794 |
+
return r;
|
2795 |
+
},
|
2796 |
+
|
2797 |
+
/**
|
2798 |
+
* Clear item instance from type
|
2799 |
+
* Sets value to NULL
|
2800 |
+
*/
|
2801 |
+
clear_item: function() {
|
2802 |
+
this.clear_component('item');
|
2803 |
+
},
|
2804 |
+
|
2805 |
+
/* Evaluation */
|
2806 |
+
|
2807 |
+
/**
|
2808 |
+
* Check if item matches content handler
|
2809 |
+
* @param object item Content_Item instance to check for type match
|
2810 |
+
* @return bool TRUE if type matches, FALSE otherwise
|
2811 |
+
*/
|
2812 |
+
match: function(item) {
|
2813 |
+
// Validate
|
2814 |
+
var attr = 'match';
|
2815 |
+
var m = this.get_attribute(attr);
|
2816 |
+
// Stop processing types with no matching algorithm
|
2817 |
+
if ( !this.util.is_empty(m) ) {
|
2818 |
+
// Process regex patterns
|
2819 |
+
|
2820 |
+
// String-based
|
2821 |
+
if ( this.util.is_string(m) ) {
|
2822 |
+
// Create new regexp object
|
2823 |
+
m = new RegExp(m, "i");
|
2824 |
+
this.set_attribute(attr, m);
|
2825 |
+
}
|
2826 |
+
// RegExp based
|
2827 |
+
if ( this.util.is_type(m, RegExp) ) {
|
2828 |
+
return m.test(item.get_uri());
|
2829 |
+
}
|
2830 |
+
// Process function
|
2831 |
+
if ( this.util.is_func(m) ) {
|
2832 |
+
return ( m.call(this, item) ) ? true : false;
|
2833 |
+
}
|
2834 |
+
}
|
2835 |
+
// Default
|
2836 |
+
return false;
|
2837 |
+
},
|
2838 |
+
|
2839 |
+
/* Processing/Output */
|
2840 |
+
|
2841 |
+
/**
|
2842 |
+
* Loads item data
|
2843 |
+
* @param obj item Content item to load data for
|
2844 |
+
* @return obj Promise that is resolved when item data is loaded
|
2845 |
+
*/
|
2846 |
+
load: function(item) {
|
2847 |
+
var dfr = $.Deferred();
|
2848 |
+
var ret = this.call_attribute('load', item, dfr);
|
2849 |
+
// Handle missing load method
|
2850 |
+
if ( null === ret ) {
|
2851 |
+
dfr.resolve();
|
2852 |
+
}
|
2853 |
+
return dfr.promise();
|
2854 |
+
},
|
2855 |
+
|
2856 |
+
/**
|
2857 |
+
* Render output to display item
|
2858 |
+
* @param Content_Item item Item to render output for
|
2859 |
+
* @return obj jQuery.Promise that is resolved when item is rendered
|
2860 |
+
*/
|
2861 |
+
render: function(item) {
|
2862 |
+
var dfr = $.Deferred();
|
2863 |
+
// Validate
|
2864 |
+
this.call_attribute('render', item, dfr);
|
2865 |
+
return dfr.promise();
|
2866 |
+
}
|
2867 |
+
};
|
2868 |
+
|
2869 |
+
View.Content_Handler = Component.extend(Content_Handler);
|
2870 |
+
|
2871 |
+
/**
|
2872 |
+
* Content Item
|
2873 |
+
* @param obj options Init options
|
2874 |
+
*/
|
2875 |
+
var Content_Item = {
|
2876 |
+
/* Configuration */
|
2877 |
+
|
2878 |
+
_slug: 'content_item',
|
2879 |
+
_reciprocal: true,
|
2880 |
+
_refs: {
|
2881 |
+
'viewer': 'Viewer',
|
2882 |
+
'group': 'Group',
|
2883 |
+
'type': 'Content_Handler'
|
2884 |
+
},
|
2885 |
+
|
2886 |
+
_attr_default: {
|
2887 |
+
source: null,
|
2888 |
+
permalink: null,
|
2889 |
+
dimensions: null,
|
2890 |
+
title: '',
|
2891 |
+
group: null,
|
2892 |
+
internal: false,
|
2893 |
+
output: null
|
2894 |
+
},
|
2895 |
+
|
2896 |
+
/* References */
|
2897 |
+
|
2898 |
+
group: null,
|
2899 |
+
viewer: null,
|
2900 |
+
type: null,
|
2901 |
+
|
2902 |
+
/* Properties */
|
2903 |
+
|
2904 |
+
data: null,
|
2905 |
+
loaded: null,
|
2906 |
+
|
2907 |
+
/* Init */
|
2908 |
+
|
2909 |
+
_c: function(el) {
|
2910 |
+
// Save element to instance
|
2911 |
+
this.dom_set(el);
|
2912 |
+
// Default initialization
|
2913 |
+
this._super();
|
2914 |
+
},
|
2915 |
+
|
2916 |
+
/* Methods */
|
2917 |
+
|
2918 |
+
/*-** Attributes **-*/
|
2919 |
+
|
2920 |
+
/**
|
2921 |
+
* Build default attributes
|
2922 |
+
* Populates attributes with asset properties (attachments)
|
2923 |
+
* Overrides super class method
|
2924 |
+
* @uses Component.init_default_attributes()
|
2925 |
+
*/
|
2926 |
+
init_default_attributes: function() {
|
2927 |
+
this._super();
|
2928 |
+
// Add asset properties
|
2929 |
+
var d = this.dom_get();
|
2930 |
+
var key = d.attr(this.util.get_attribute('asset')) || null;
|
2931 |
+
var assets = this.get_controller().assets || null;
|
2932 |
+
// Merge asset data with default attributes
|
2933 |
+
if ( this.util.is_string(key) ) {
|
2934 |
+
var attrs = [{}, this._attr_default, {'permalink': d.attr('href')}];
|
2935 |
+
if ( this.util.is_obj(assets) ) {
|
2936 |
+
var t = this;
|
2937 |
+
/**
|
2938 |
+
* Retrieve item assets
|
2939 |
+
* Handles variant items as well (Retrieves parent item assets)
|
2940 |
+
* @param string key Item URI
|
2941 |
+
* @return obj Item assets (Empty if no match)
|
2942 |
+
*/
|
2943 |
+
var get_assets = function(key) {
|
2944 |
+
var ret = {};
|
2945 |
+
if ( key in assets && t.util.is_obj(assets[key]) ) {
|
2946 |
+
ret = assets[key];
|
2947 |
+
}
|
2948 |
+
return ret;
|
2949 |
+
};
|
2950 |
+
// Save assets
|
2951 |
+
attrs.push(get_assets(key));
|
2952 |
+
}
|
2953 |
+
this._attr_default = $.extend.apply(this, attrs);
|
2954 |
+
}
|
2955 |
+
return this._attr_default;
|
2956 |
+
},
|
2957 |
+
|
2958 |
+
/*-** Properties **-*/
|
2959 |
+
|
2960 |
+
/**
|
2961 |
+
* Retrieve item output
|
2962 |
+
* Output generated based on content handler if not previously generated
|
2963 |
+
* @uses get_attribute() to retrieve cached output
|
2964 |
+
* @uses set_attribute() to cache generated output
|
2965 |
+
* @uses get_type() to retrieve item type
|
2966 |
+
* @uses Content_Handler.render() to generate item output
|
2967 |
+
* @return obj jQuery.Promise that is resolved when output is retrieved
|
2968 |
+
*/
|
2969 |
+
get_output: function() {
|
2970 |
+
var dfr = $.Deferred();
|
2971 |
+
// Check for cached output
|
2972 |
+
var ret = this.get_attribute('output');
|
2973 |
+
if ( this.util.is_string(ret) ) {
|
2974 |
+
dfr.resolve(ret);
|
2975 |
+
} else if ( this.has_type() ) {
|
2976 |
+
// Render output from scratch (if necessary)
|
2977 |
+
// Get item type
|
2978 |
+
var type = this.get_type();
|
2979 |
+
// Render type-based output
|
2980 |
+
var item = this;
|
2981 |
+
type.render(this).done(function(output) {
|
2982 |
+
// Cache output
|
2983 |
+
item.set_output(output);
|
2984 |
+
dfr.resolve(output);
|
2985 |
+
});
|
2986 |
+
} else {
|
2987 |
+
dfr.resolve('');
|
2988 |
+
}
|
2989 |
+
return dfr.promise();
|
2990 |
+
},
|
2991 |
+
|
2992 |
+
/**
|
2993 |
+
* Cache output for future retrieval
|
2994 |
+
* @uses set_attribute() to cache output
|
2995 |
+
*/
|
2996 |
+
set_output: function(out) {
|
2997 |
+
if ( this.util.is_string(out, false) ) {
|
2998 |
+
this.set_attribute('output', out);
|
2999 |
+
}
|
3000 |
+
},
|
3001 |
+
|
3002 |
+
/**
|
3003 |
+
* Retrieve item output
|
3004 |
+
* Alias for `get_output()`
|
3005 |
+
* @return jQuery.Promise Deferred that is resolved when content is retrieved
|
3006 |
+
*/
|
3007 |
+
get_content: function() {
|
3008 |
+
return this.get_output();
|
3009 |
+
},
|
3010 |
+
|
3011 |
+
/**
|
3012 |
+
* Retrieve item URI
|
3013 |
+
* @param string mode (optional) Which URI should be retrieved
|
3014 |
+
* > source: Media source
|
3015 |
+
* > permalink: Item permalink
|
3016 |
+
* @return string Item URI
|
3017 |
+
*/
|
3018 |
+
get_uri: function(mode) {
|
3019 |
+
// Validate
|
3020 |
+
if ( $.inArray(mode ,['source', 'permalink']) === -1 ) {
|
3021 |
+
mode = 'source';
|
3022 |
+
}
|
3023 |
+
// Retrieve URI
|
3024 |
+
var ret = this.get_attribute(mode);
|
3025 |
+
if ( !this.util.is_string(ret) ) {
|
3026 |
+
ret = ( 'source' === mode ) ? this.get_attribute('permalink') : '';
|
3027 |
+
}
|
3028 |
+
// Format
|
3029 |
+
ret = ret.replace(/&(#38|amp);/, '&');
|
3030 |
+
return ret;
|
3031 |
+
},
|
3032 |
+
|
3033 |
+
/**
|
3034 |
+
* Retrieve item title
|
3035 |
+
*/
|
3036 |
+
get_title: function() {
|
3037 |
+
var prop = 'title';
|
3038 |
+
var prop_cached = prop + '_cached';
|
3039 |
+
// Check for cached value
|
3040 |
+
if ( this.has_attribute(prop_cached) ) {
|
3041 |
+
return this.get_attribute(prop_cached, '');
|
3042 |
+
}
|
3043 |
+
|
3044 |
+
var title = '';
|
3045 |
+
// Generate title from DOM values
|
3046 |
+
var dom = this.dom_get();
|
3047 |
+
var t = this;
|
3048 |
+
/**
|
3049 |
+
* Validate title value.
|
3050 |
+
*
|
3051 |
+
* Removes default title based on user option.
|
3052 |
+
*
|
3053 |
+
* @param string title Title to check.
|
3054 |
+
* @return string Current title or empty string (if default title set and not permitted).
|
3055 |
+
*/
|
3056 |
+
var validate = function(title) {
|
3057 |
+
// Return empty string if empty title set.
|
3058 |
+
if ( typeof title !== 'string' || '' === title.trim() ) {
|
3059 |
+
return '';
|
3060 |
+
}
|
3061 |
+
// Cleanup title.
|
3062 |
+
title = title.trim();
|
3063 |
+
// Stop processing if default title is allowed.
|
3064 |
+
if ( t.get_viewer().get_attribute('title_default') ) {
|
3065 |
+
return title;
|
3066 |
+
}
|
3067 |
+
|
3068 |
+
// Check if default title is used.
|
3069 |
+
if ( title === t.get_title_default() ) {
|
3070 |
+
title = '';
|
3071 |
+
}
|
3072 |
+
return title;
|
3073 |
+
};
|
3074 |
+
|
3075 |
+
// DOM-based caption
|
3076 |
+
if ( dom.length ) {
|
3077 |
+
// Link title (generally must be manually-entered)
|
3078 |
+
title = dom.attr(prop);
|
3079 |
+
|
3080 |
+
// Figcaption element
|
3081 |
+
if ( !title ) {
|
3082 |
+
title = dom.closest('figure').find('figcaption').first().html();
|
3083 |
+
}
|
3084 |
+
|
3085 |
+
// Class Name
|
3086 |
+
if ( !title ) {
|
3087 |
+
title = dom.closest('figure').find('.wp-caption-text').first().html();
|
3088 |
+
}
|
3089 |
+
}
|
3090 |
+
|
3091 |
+
// Saved attributes
|
3092 |
+
if ( !title ) {
|
3093 |
+
var props = ['caption', 'title'];
|
3094 |
+
for ( var x = 0; x < props.length; x++ ) {
|
3095 |
+
title = validate( this.get_attribute(props[x], '') );
|
3096 |
+
if ( !this.util.is_empty(title) ) {
|
3097 |
+
break;
|
3098 |
+
}
|
3099 |
+
}
|
3100 |
+
}
|
3101 |
+
|
3102 |
+
// Fallbacks
|
3103 |
+
if ( !title && dom.length ) {
|
3104 |
+
// Image Alt attribute
|
3105 |
+
title = validate( dom.find('img').first().attr('alt') );
|
3106 |
+
|
3107 |
+
// Element text
|
3108 |
+
if ( !title ) {
|
3109 |
+
title = validate( dom.get(0).innerText.trim() );
|
3110 |
+
}
|
3111 |
+
}
|
3112 |
+
|
3113 |
+
// Final validation.
|
3114 |
+
title = validate(title);
|
3115 |
+
|
3116 |
+
// Cache retrieved value
|
3117 |
+
this.set_attribute(prop_cached, title);
|
3118 |
+
// Return value
|
3119 |
+
return title;
|
3120 |
+
},
|
3121 |
+
|
3122 |
+
/**
|
3123 |
+
* Retrieve default title.
|
3124 |
+
*
|
3125 |
+
* WordPress-generated default title for attachments is base file name (without extension).
|
3126 |
+
*
|
3127 |
+
* @return string Default title.
|
3128 |
+
*/
|
3129 |
+
get_title_default: function() {
|
3130 |
+
var val = '';
|
3131 |
+
var prop = 'title_default';
|
3132 |
+
// Build default title if necessary.
|
3133 |
+
if ( !this.has_attribute(prop) ) {
|
3134 |
+
var f = this.get_uri('source');
|
3135 |
+
var i = f.lastIndexOf('/');
|
3136 |
+
if ( -1 !== i ) {
|
3137 |
+
f = f.substr(i + 1);
|
3138 |
+
i = f.lastIndexOf('.');
|
3139 |
+
if ( -1 !== i ) {
|
3140 |
+
f = f.substr(0, i);
|
3141 |
+
}
|
3142 |
+
}
|
3143 |
+
// Save default title
|
3144 |
+
val = this.set_attribute(prop, f);
|
3145 |
+
} else {
|
3146 |
+
val = this.get_attribute(prop);
|
3147 |
+
}
|
3148 |
+
return val;
|
3149 |
+
},
|
3150 |
+
|
3151 |
+
/**
|
3152 |
+
* Retrieve item dimensions
|
3153 |
+
* @return obj Item `width` and `height` properties (px)
|
3154 |
+
*/
|
3155 |
+
get_dimensions: function() {
|
3156 |
+
return $.extend({'width': 0, 'height': 0}, this.get_attribute('dimensions'), {});
|
3157 |
+
},
|
3158 |
+
|
3159 |
+
/**
|
3160 |
+
* Save item data to instance
|
3161 |
+
* Item data is saved when rendered
|
3162 |
+
* @param mixed data Item data (property cleared if NULL)
|
3163 |
+
*/
|
3164 |
+
set_data: function(data) {
|
3165 |
+
this.data = data;
|
3166 |
+
},
|
3167 |
+
|
3168 |
+
get_data: function() {
|
3169 |
+
return this.data;
|
3170 |
+
},
|
3171 |
+
|
3172 |
+
/**
|
3173 |
+
* Determine gallery type
|
3174 |
+
* @return string|null Gallery type ID (NULL if item not in gallery)
|
3175 |
+
*/
|
3176 |
+
gallery_type: function() {
|
3177 |
+
var ret = null;
|
3178 |
+
var types = {
|
3179 |
+
'wp': '.gallery-icon',
|
3180 |
+
'ngg': '.ngg-gallery-thumbnail'
|
3181 |
+
};
|
3182 |
+
|
3183 |
+
var dom = this.dom_get();
|
3184 |
+
for ( var type in types ) {
|
3185 |
+
if ( dom.parent(types[type]).length > 0 ) {
|
3186 |
+
ret = type;
|
3187 |
+
break;
|
3188 |
+
}
|
3189 |
+
}
|
3190 |
+
return ret;
|
3191 |
+
},
|
3192 |
+
|
3193 |
+
/**
|
3194 |
+
* Check if current link is part of a gallery
|
3195 |
+
* @param string gType (optional) Gallery type to check for
|
3196 |
+
* @return bool TRUE if link is part of (specified) gallery (FALSE otherwise)
|
3197 |
+
*/
|
3198 |
+
in_gallery: function(gType) {
|
3199 |
+
var type = this.gallery_type();
|
3200 |
+
// No gallery
|
3201 |
+
if ( null === type ) {
|
3202 |
+
return false;
|
3203 |
+
}
|
3204 |
+
// Boolean check
|
3205 |
+
if ( !this.util.is_string(gType) ) {
|
3206 |
+
return true;
|
3207 |
+
}
|
3208 |
+
// Check for specific gallery type
|
3209 |
+
return ( gType === type ) ? true : false;
|
3210 |
+
},
|
3211 |
+
|
3212 |
+
/*-** Component References **-*/
|
3213 |
+
|
3214 |
+
/* Viewer */
|
3215 |
+
|
3216 |
+
get_viewer: function() {
|
3217 |
+
return this.get_component('viewer', {get_default: true});
|
3218 |
+
},
|
3219 |
+
|
3220 |
+
/**
|
3221 |
+
* Sets item's viewer property
|
3222 |
+
* @uses View.get_viewer() to retrieve global viewer
|
3223 |
+
* @uses this.viewer to save item's viewer
|
3224 |
+
* @param string|View.Viewer v Viewer to set for item
|
3225 |
+
* > Item's viewer is reset if invalid viewer provided
|
3226 |
+
*/
|
3227 |
+
set_viewer: function(v) {
|
3228 |
+
return this.set_component('viewer', v);
|
3229 |
+
},
|
3230 |
+
|
3231 |
+
/* Group */
|
3232 |
+
|
3233 |
+
/**
|
3234 |
+
* Retrieve item's group
|
3235 |
+
* @param bool set_current (optional) Sets item as current item in group (Default: FALSE)
|
3236 |
+
* @return View.Group|bool Group reference item belongs to (FALSE if no group)
|
3237 |
+
*/
|
3238 |
+
get_group: function(set_current) {
|
3239 |
+
var prop = 'group';
|
3240 |
+
// Check if group reference already set
|
3241 |
+
var g = this.get_component(prop);
|
3242 |
+
if ( g ) {
|
3243 |
+
} else {
|
3244 |
+
// Set empty group if no group exists
|
3245 |
+
g = this.set_component(prop, new View.Group());
|
3246 |
+
set_current = true;
|
3247 |
+
}
|
3248 |
+
if ( !!set_current ) {
|
3249 |
+
g.set_current(this);
|
3250 |
+
}
|
3251 |
+
return g;
|
3252 |
+
},
|
3253 |
+
|
3254 |
+
/**
|
3255 |
+
* Sets item's group property
|
3256 |
+
* @uses View.get_group() to retrieve global group
|
3257 |
+
* @uses this.group to set item's group
|
3258 |
+
* @param string|View.Group g Group to set for item
|
3259 |
+
* > Item's group is reset if invalid group provided
|
3260 |
+
*/
|
3261 |
+
set_group: function(g) {
|
3262 |
+
// If group ID set, get object reference
|
3263 |
+
if ( this.util.is_string(g) ) {
|
3264 |
+
g = this.get_controller().get_group(g);
|
3265 |
+
}
|
3266 |
+
|
3267 |
+
// Set (or clear) group property
|
3268 |
+
this.group = ( this.util.is_type(g, View.Group) ) ? g : false;
|
3269 |
+
},
|
3270 |
+
|
3271 |
+
/* Content Handler */
|
3272 |
+
|
3273 |
+
/**
|
3274 |
+
* Retrieve item type
|
3275 |
+
* @uses get_component() to retrieve saved reference to Content_Handler instance
|
3276 |
+
* @uses View.get_content_handler() to determine item content handler (if necessary)
|
3277 |
+
* @return Content_Handler|null Content Handler of item (NULL no valid type exists)
|
3278 |
+
*/
|
3279 |
+
get_type: function() {
|
3280 |
+
var t = this.get_component('type', {check_attr: false});
|
3281 |
+
if ( !t ) {
|
3282 |
+
t = this.set_type(this.get_controller().get_content_handler(this));
|
3283 |
+
}
|
3284 |
+
return t;
|
3285 |
+
},
|
3286 |
+
|
3287 |
+
/**
|
3288 |
+
* Save content handler reference
|
3289 |
+
* @uses set_component() to save type reference
|
3290 |
+
* @return Content_Handler|null Saved content handler (NULL if invalid)
|
3291 |
+
*/
|
3292 |
+
set_type: function(type) {
|
3293 |
+
return this.set_component('type', type);
|
3294 |
+
},
|
3295 |
+
|
3296 |
+
/**
|
3297 |
+
* Check if content handler exists for item
|
3298 |
+
* @return bool TRUE if content handler exists, FALSE otherwise
|
3299 |
+
*/
|
3300 |
+
has_type: function() {
|
3301 |
+
var ret = !this.util.is_empty(this.get_type());
|
3302 |
+
return ret;
|
3303 |
+
},
|
3304 |
+
|
3305 |
+
/* Actions */
|
3306 |
+
|
3307 |
+
/**
|
3308 |
+
* Display item in viewer
|
3309 |
+
* @uses get_viewer() to retrieve viewer instance for item
|
3310 |
+
* @uses Viewer.show() to display item in viewer
|
3311 |
+
* @param obj options (optional) Options
|
3312 |
+
*/
|
3313 |
+
show: function(options) {
|
3314 |
+
// Validate content handler
|
3315 |
+
if ( !this.has_type() ) {
|
3316 |
+
return false;
|
3317 |
+
}
|
3318 |
+
// Set display options
|
3319 |
+
this.set_attribute('options_show', options);
|
3320 |
+
// Retrieve viewer
|
3321 |
+
var v = this.get_viewer();
|
3322 |
+
// Load item
|
3323 |
+
this.load();
|
3324 |
+
var ret = v.show(this);
|
3325 |
+
return ret;
|
3326 |
+
},
|
3327 |
+
|
3328 |
+
/**
|
3329 |
+
* Load item data
|
3330 |
+
*
|
3331 |
+
* Retrieves item data from external sources (if necessary)
|
3332 |
+
* @uses this.loaded to save loaded state
|
3333 |
+
* @return obj Promise that is resolved when item data is loaded
|
3334 |
+
*/
|
3335 |
+
load: function() {
|
3336 |
+
if ( !this.util.is_promise(this.loaded) ) {
|
3337 |
+
// Load item data (via content handler)
|
3338 |
+
this.loaded = this.get_type().load(this);
|
3339 |
+
}
|
3340 |
+
return this.loaded.promise();
|
3341 |
+
},
|
3342 |
+
|
3343 |
+
reset: function() {
|
3344 |
+
this.set_attribute('options_show', null);
|
3345 |
+
}
|
3346 |
+
};
|
3347 |
+
|
3348 |
+
View.Content_Item = Component.extend(Content_Item);
|
3349 |
+
|
3350 |
+
/**
|
3351 |
+
* Modeled Component
|
3352 |
+
*/
|
3353 |
+
var Modeled_Component = {
|
3354 |
+
|
3355 |
+
_slug: 'modeled_component',
|
3356 |
+
|
3357 |
+
/* Methods */
|
3358 |
+
|
3359 |
+
/* Attributes */
|
3360 |
+
|
3361 |
+
/**
|
3362 |
+
* Retrieve attribute
|
3363 |
+
* Gives priority to model values
|
3364 |
+
* @see Component.get_attribute()
|
3365 |
+
* @param string key Attribute to retrieve
|
3366 |
+
* @param mixed def (optional) Default value (Default: NULL)
|
3367 |
+
* @param bool check_model (optional) Check model for value (Default: TRUE)
|
3368 |
+
* @param bool enforce_type (optional) Return value data type should match default value data type (Default: TRUE)
|
3369 |
+
* @return mixed Attribute value
|
3370 |
+
*/
|
3371 |
+
get_attribute: function(key, def, check_model, enforce_type) {
|
3372 |
+
// Validate
|
3373 |
+
if ( !this.util.is_string(key) ) {
|
3374 |
+
// Invalid requests sent straight to super method
|
3375 |
+
return this._super(key, def, enforce_type);
|
3376 |
+
}
|
3377 |
+
if ( !this.util.is_bool(check_model) ) {
|
3378 |
+
check_model = true;
|
3379 |
+
}
|
3380 |
+
var ret = null;
|
3381 |
+
// Check model for attribute
|
3382 |
+
if ( check_model ) {
|
3383 |
+
var m = this.get_ancestor(key, false);
|
3384 |
+
if ( this.util.in_obj(m, key) ) {
|
3385 |
+
ret = m[key];
|
3386 |
+
}
|
3387 |
+
}
|
3388 |
+
// Check standard attributes as fallback
|
3389 |
+
if ( null === ret ) {
|
3390 |
+
ret = this._super(key, def, enforce_type);
|
3391 |
+
}
|
3392 |
+
return ret;
|
3393 |
+
},
|
3394 |
+
|
3395 |
+
/**
|
3396 |
+
* Get attribute recursively
|
3397 |
+
* Merges objects from ancestors together
|
3398 |
+
* @see Component.get_attribute() for more information
|
3399 |
+
*/
|
3400 |
+
get_attribute_recursive: function(key, def, enforce_type) {
|
3401 |
+
var ret = this.get_attribute(key, def, true, enforce_type);
|
3402 |
+
if ( this.util.is_obj(ret) ) {
|
3403 |
+
// Merge ancestor objects
|
3404 |
+
var models = this.get_ancestors(false);
|
3405 |
+
ret = [ret];
|
3406 |
+
var t = this;
|
3407 |
+
$.each(models, function(idx, model) {
|
3408 |
+
if ( key in model && t.util.is_obj(model[key]) ) {
|
3409 |
+
ret.push(model[key]);
|
3410 |
+
}
|
3411 |
+
});
|
3412 |
+
// Merge transition handlers into current theme
|
3413 |
+
ret.push({});
|
3414 |
+
ret = $.extend.apply($, ret.reverse());
|
3415 |
+
}
|
3416 |
+
return ret;
|
3417 |
+
},
|
3418 |
+
|
3419 |
+
/**
|
3420 |
+
* Set attribute value
|
3421 |
+
* Gives priority to model values
|
3422 |
+
* @see Component.set_attribute()
|
3423 |
+
* @param string key Attribute to set
|
3424 |
+
* @param mixed val Value to set for attribute
|
3425 |
+
* @param bool|obj use_model (optional) Set the value on the model (Default: TRUE)
|
3426 |
+
* > bool: Set attribute on current model (TRUE) or as standard attribute (FALSE)
|
3427 |
+
* > obj: Model object to set attribute on
|
3428 |
+
* @return mixed Attribute value
|
3429 |
+
*/
|
3430 |
+
set_attribute: function(key, val, use_model) {
|
3431 |
+
// Validate
|
3432 |
+
if ( ( !this.util.is_string(key) ) || !this.util.is_set(val) ) {
|
3433 |
+
return false;
|
3434 |
+
}
|
3435 |
+
if ( !this.util.is_bool(use_model) && !this.util.is_obj(use_model) ) {
|
3436 |
+
use_model = true;
|
3437 |
+
}
|
3438 |
+
// Determine where to set attribute
|
3439 |
+
if ( !!use_model ) {
|
3440 |
+
var model = this.util.is_obj(use_model) ? use_model : this.get_model();
|
3441 |
+
|
3442 |
+
// Set attribute in model
|
3443 |
+
model[key] = val;
|
3444 |
+
} else {
|
3445 |
+
// Set as standard attribute
|
3446 |
+
this._super(key, val);
|
3447 |
+
}
|
3448 |
+
return val;
|
3449 |
+
},
|
3450 |
+
|
3451 |
+
|
3452 |
+
/* Model */
|
3453 |
+
|
3454 |
+
/**
|
3455 |
+
* Retrieve Template model
|
3456 |
+
* @return obj Model (Default: Empty object)
|
3457 |
+
*/
|
3458 |
+
get_model: function() {
|
3459 |
+
var m = this.get_attribute('model', null, false);
|
3460 |
+
if ( !this.util.is_obj(m) ) {
|
3461 |
+
// Set default value
|
3462 |
+
m = {};
|
3463 |
+
this.set_attribute('model', m, false);
|
3464 |
+
}
|
3465 |
+
return m;
|
3466 |
+
},
|
3467 |
+
|
3468 |
+
|
3469 |
+
/**
|
3470 |
+
* Check if instance has model
|
3471 |
+
* @return bool TRUE if model is set, FALSE otherwise
|
3472 |
+
*/
|
3473 |
+
has_model: function() {
|
3474 |
+
return ( this.util.is_empty( this.get_model() ) ) ? false : true;
|
3475 |
+
},
|
3476 |
+
|
3477 |
+
|
3478 |
+
|
3479 |
+
/**
|
3480 |
+
* Check if specified attribute exists in model
|
3481 |
+
* @param string key Attribute to check for
|
3482 |
+
* @return bool TRUE if attribute exists, FALSE otherwise
|
3483 |
+
*/
|
3484 |
+
in_model: function(key) {
|
3485 |
+
return ( this.util.in_obj(this.get_model(), key) ) ? true : false;
|
3486 |
+
},
|
3487 |
+
|
3488 |
+
/**
|
3489 |
+
* Retrieve all ancestor models
|
3490 |
+
* @param bool inc_current (optional) Include current model in list (Default: FALSE)
|
3491 |
+
* @return array Theme ancestor models (Closest parent first)
|
3492 |
+
*/
|
3493 |
+
get_ancestors: function(inc_current) {
|
3494 |
+
var ret = [];
|
3495 |
+
var m = this.get_model();
|
3496 |
+
while ( this.util.is_obj(m) ) {
|
3497 |
+
ret.push(m);
|
3498 |
+
m = ( this.util.in_obj(m, 'parent') && this.util.is_obj(m.parent) ) ? m.parent : null;
|
3499 |
+
}
|
3500 |
+
// Remove current model from list
|
3501 |
+
if ( !inc_current ) {
|
3502 |
+
ret.shift();
|
3503 |
+
}
|
3504 |
+
return ret;
|
3505 |
+
},
|
3506 |
+
|
3507 |
+
/**
|
3508 |
+
* Retrieve first ancestor of current theme with specified attribute
|
3509 |
+
* > Current model is also evaluated
|
3510 |
+
* @param string attr Attribute to search ancestors for
|
3511 |
+
* @param bool safe_mode (optional) Return current model if no matching ancestor found (Default: TRUE)
|
3512 |
+
* @return obj Theme ancestor (Default: Current theme model)
|
3513 |
+
*/
|
3514 |
+
get_ancestor: function(attr, safe_mode) {
|
3515 |
+
// Validate
|
3516 |
+
if ( !this.util.is_string(attr) ) {
|
3517 |
+
return false;
|
3518 |
+
}
|
3519 |
+
if ( !this.util.is_bool(safe_mode) ) {
|
3520 |
+
safe_mode = true;
|
3521 |
+
}
|
3522 |
+
var mcurr = this.get_model();
|
3523 |
+
var m = mcurr;
|
3524 |
+
var found = false;
|
3525 |
+
while ( this.util.is_obj(m) ) {
|
3526 |
+
// Check if attribute exists in model
|
3527 |
+
if ( this.util.in_obj(m, attr) && !this.util.is_empty(m[attr]) ) {
|
3528 |
+
found = true;
|
3529 |
+
break;
|
3530 |
+
}
|
3531 |
+
// Get next model
|
3532 |
+
m = ( this.util.in_obj(m, 'parent') ) ? m['parent'] : null;
|
3533 |
+
}
|
3534 |
+
if ( !found ) {
|
3535 |
+
if ( safe_mode ) {
|
3536 |
+
// Use current model as fallback
|
3537 |
+
if ( this.util.is_empty(m) ) {
|
3538 |
+
m = mcurr;
|
3539 |
+
}
|
3540 |
+
// Add attribute to object
|
3541 |
+
if ( !this.util.in_obj(m, attr) ) {
|
3542 |
+
m[attr] = null;
|
3543 |
+
}
|
3544 |
+
} else {
|
3545 |
+
m = null;
|
3546 |
+
}
|
3547 |
+
}
|
3548 |
+
return m;
|
3549 |
+
}
|
3550 |
+
|
3551 |
+
};
|
3552 |
+
|
3553 |
+
Modeled_Component = Component.extend(Modeled_Component);
|
3554 |
+
|
3555 |
+
/**
|
3556 |
+
* Theme
|
3557 |
+
*/
|
3558 |
+
var Theme = {
|
3559 |
+
|
3560 |
+
/* Configuration */
|
3561 |
+
|
3562 |
+
_slug: 'theme',
|
3563 |
+
_refs: {
|
3564 |
+
'viewer': 'Viewer',
|
3565 |
+
'template': 'Template'
|
3566 |
+
},
|
3567 |
+
_models: {},
|
3568 |
+
|
3569 |
+
_attr_default: {
|
3570 |
+
template: null,
|
3571 |
+
model: null
|
3572 |
+
},
|
3573 |
+
|
3574 |
+
/* References */
|
3575 |
+
|
3576 |
+
viewer: null,
|
3577 |
+
template: null,
|
3578 |
+
|
3579 |
+
/* Methods */
|
3580 |
+
|
3581 |
+
/**
|
3582 |
+
* Custom constructor
|
3583 |
+
* @see Component._c()
|
3584 |
+
*/
|
3585 |
+
_c: function(id, attributes, viewer) {
|
3586 |
+
// Validate
|
3587 |
+
if ( arguments.length === 1 && this.util.is_type(arguments[0], View.Viewer) ) {
|
3588 |
+
viewer = arguments[0];
|
3589 |
+
id = null;
|
3590 |
+
}
|
3591 |
+
// Pass parameters to parent constructor
|
3592 |
+
this._super(id, attributes);
|
3593 |
+
|
3594 |
+
// Set viewer instance
|
3595 |
+
this.set_viewer(viewer);
|
3596 |
+
|
3597 |
+
// Set theme model
|
3598 |
+
this.set_model(id);
|
3599 |
+
},
|
3600 |
+
|
3601 |
+
/* Viewer */
|
3602 |
+
|
3603 |
+
get_viewer: function() {
|
3604 |
+
return this.get_component('viewer', {check_attr: false, get_default: true});
|
3605 |
+
},
|
3606 |
+
|
3607 |
+
/**
|
3608 |
+
* Sets theme's viewer property
|
3609 |
+
* @uses View.get_viewer() to retrieve global viewer
|
3610 |
+
* @uses this.viewer to save item's viewer
|
3611 |
+
* @param string|View.Viewer v Viewer to set for item
|
3612 |
+
* > Theme's viewer is reset if invalid viewer provided
|
3613 |
+
*/
|
3614 |
+
set_viewer: function(v) {
|
3615 |
+
return this.set_component('viewer', v);
|
3616 |
+
},
|
3617 |
+
|
3618 |
+
/* Template */
|
3619 |
+
|
3620 |
+
/**
|
3621 |
+
* Retrieve template instance
|
3622 |
+
* @return Template instance
|
3623 |
+
*/
|
3624 |
+
get_template: function() {
|
3625 |
+
// Get saved template
|
3626 |
+
var ret = this.get_component('template');
|
3627 |
+
// Template needs to be initialized
|
3628 |
+
if ( this.util.is_empty(ret) ) {
|
3629 |
+
// Pass model to Template instance
|
3630 |
+
var attr = { 'theme': this, 'model': this.get_model() };
|
3631 |
+
ret = this.set_component('template', new View.Template(attr));
|
3632 |
+
}
|
3633 |
+
return ret;
|
3634 |
+
},
|
3635 |
+
|
3636 |
+
/* Tags */
|
3637 |
+
|
3638 |
+
/**
|
3639 |
+
* Retrieve tags from template
|
3640 |
+
* All tags will be retrieved by default
|
3641 |
+
* Specific tag/property instances can be retrieved as well
|
3642 |
+
* @see Template.get_tags()
|
3643 |
+
* @param string name (optional) Name of tags to retrieve
|
3644 |
+
* @param string prop (optional) Specific tag property to retrieve
|
3645 |
+
* @return array Tags in template
|
3646 |
+
*/
|
3647 |
+
get_tags: function(name, prop) {
|
3648 |
+
return this.get_template().get_tags(name, prop);
|
3649 |
+
},
|
3650 |
+
|
3651 |
+
/**
|
3652 |
+
* Retrieve tag DOM elements
|
3653 |
+
* @see Template.dom_get_tag()
|
3654 |
+
*/
|
3655 |
+
dom_get_tag: function(tag, prop) {
|
3656 |
+
return $(this.get_template().dom_get_tag(tag, prop));
|
3657 |
+
},
|
3658 |
+
|
3659 |
+
/**
|
3660 |
+
* Retrieve template tag CSS selector
|
3661 |
+
* @uses Template.get_tag_selector()
|
3662 |
+
* @param name string Tag name
|
3663 |
+
* @param prop string Tag Property
|
3664 |
+
* @return string Template tag CSS selector
|
3665 |
+
*/
|
3666 |
+
get_tag_selector: function(name, prop) {
|
3667 |
+
return this.get_template().get_tag_selector(name, prop);
|
3668 |
+
},
|
3669 |
+
|
3670 |
+
/* Model */
|
3671 |
+
|
3672 |
+
/**
|
3673 |
+
* Retrieve theme models
|
3674 |
+
* @return obj Theme models
|
3675 |
+
*/
|
3676 |
+
get_models: function() {
|
3677 |
+
return this._models;
|
3678 |
+
},
|
3679 |
+
|
3680 |
+
/**
|
3681 |
+
* Retrieve specified theme model
|
3682 |
+
* @param string id (optional) Theme model to retrieve
|
3683 |
+
* > Default model retrieved if ID is invalid/not set
|
3684 |
+
* @return obj Specified theme model
|
3685 |
+
*/
|
3686 |
+
get_model: function(id) {
|
3687 |
+
var ret = null;
|
3688 |
+
// Pass request to superclass method
|
3689 |
+
if ( !this.util.is_set(id) && this.util.is_obj( this.get_attribute('model', null, false) ) ) {
|
3690 |
+
ret = this._super();
|
3691 |
+
} else {
|
3692 |
+
// Retrieve matching theme model
|
3693 |
+
var models = this.get_models();
|
3694 |
+
if ( !this.util.is_string(id) ) {
|
3695 |
+
id = this.get_controller().get_option('theme_default');
|
3696 |
+
}
|
3697 |
+
// Select first theme model if specified model is invalid
|
3698 |
+
if ( !this.util.in_obj(models, id) ) {
|
3699 |
+
id = $.map(models, function(v, key) { return key; })[0];
|
3700 |
+
}
|
3701 |
+
ret = models[id];
|
3702 |
+
}
|
3703 |
+
return ret;
|
3704 |
+
},
|
3705 |
+
|
3706 |
+
/**
|
3707 |
+
* Set model for current theme instance
|
3708 |
+
* @param string id (optional) Theme ID (Default theme retrieved if ID invalid)
|
3709 |
+
*/
|
3710 |
+
set_model: function(id) {
|
3711 |
+
this.set_attribute('model', this.get_model(id), false);
|
3712 |
+
/* @deprecated
|
3713 |
+
// Set ID using model attributes (if necessary)
|
3714 |
+
if ( !this._check_id(true) ) {
|
3715 |
+
var m = this.get_model();
|
3716 |
+
if ( 'id' in m ) {
|
3717 |
+
this._set_id(m.id);
|
3718 |
+
}
|
3719 |
+
}
|
3720 |
+
*/
|
3721 |
+
},
|
3722 |
+
|
3723 |
+
/* Properties */
|
3724 |
+
|
3725 |
+
/**
|
3726 |
+
* Generate class names for DOM node
|
3727 |
+
* @param string rtype (optional) Return data type
|
3728 |
+
* > Default: array
|
3729 |
+
* > If string supplied: Joined classes delimited by parameter
|
3730 |
+
* @uses get_class() to generate class names
|
3731 |
+
* @uses Array.join() to convert class names array to string
|
3732 |
+
* @return array Class names
|
3733 |
+
*/
|
3734 |
+
get_classes: function(rtype) {
|
3735 |
+
// Build array of class names
|
3736 |
+
var cls = [];
|
3737 |
+
var thm = this;
|
3738 |
+
// Include theme parent's class name
|
3739 |
+
var models = this.get_ancestors(true);
|
3740 |
+
$.each(models, function(idx, model) {
|
3741 |
+
cls.push(thm.add_ns(model.id));
|
3742 |
+
});
|
3743 |
+
// Convert class names array to string
|
3744 |
+
if ( this.util.is_string(rtype) ) {
|
3745 |
+
cls = cls.join(rtype);
|
3746 |
+
}
|
3747 |
+
// Return class names
|
3748 |
+
return cls;
|
3749 |
+
},
|
3750 |
+
|
3751 |
+
/**
|
3752 |
+
* Get custom measurement
|
3753 |
+
* @param string attr Measurement to retrieve
|
3754 |
+
* @param obj def (optional) Default value
|
3755 |
+
* @return obj Attribute measurements
|
3756 |
+
*/
|
3757 |
+
get_measurement: function(attr, def) {
|
3758 |
+
var meas = null;
|
3759 |
+
// Validate
|
3760 |
+
if ( !this.util.is_string(attr) ) {
|
3761 |
+
return meas;
|
3762 |
+
}
|
3763 |
+
if ( !this.util.is_obj(def, false) ) {
|
3764 |
+
def = {};
|
3765 |
+
}
|
3766 |
+
// Manage cache
|
3767 |
+
var attr_cache = this.util.format('%s_cache', attr);
|
3768 |
+
var cache = this.get_attribute(attr_cache, {}, false);
|
3769 |
+
var status = '_status';
|
3770 |
+
var item = this.get_viewer().get_item();
|
3771 |
+
var w = $(window);
|
3772 |
+
// Check cache freshness
|
3773 |
+
if ( !( status in cache ) || !this.util.is_obj(cache[status]) || cache[status].width !== w.width() || cache[status].height !== w.height() ) {
|
3774 |
+
cache = {};
|
3775 |
+
}
|
3776 |
+
if ( this.util.is_empty(cache) ) {
|
3777 |
+
// Set status
|
3778 |
+
cache[status] = {
|
3779 |
+
'width': w.width(),
|
3780 |
+
'height': w.height(),
|
3781 |
+
'index': []
|
3782 |
+
};
|
3783 |
+
}
|
3784 |
+
// Retrieve cached values
|
3785 |
+
var pos = $.inArray(item, cache[status].index);
|
3786 |
+
if ( pos !== -1 && pos in cache ) {
|
3787 |
+
meas = cache[pos];
|
3788 |
+
}
|
3789 |
+
// Generate measurement
|
3790 |
+
if ( !this.util.is_obj(meas) ) {
|
3791 |
+
// Get custom theme measurement
|
3792 |
+
meas = this.call_attribute(attr);
|
3793 |
+
if ( !this.util.is_obj(meas) ) {
|
3794 |
+
// Retrieve fallback value
|
3795 |
+
meas = this.get_measurement_default(attr);
|
3796 |
+
}
|
3797 |
+
}
|
3798 |
+
// Normalize measurement
|
3799 |
+
meas = ( this.util.is_obj(meas) ) ? $.extend({}, def, meas) : def;
|
3800 |
+
// Cache measurement
|
3801 |
+
pos = cache[status].index.push(item) - 1;
|
3802 |
+
cache[pos] = meas;
|
3803 |
+
this.set_attribute(attr_cache, cache, false);
|
3804 |
+
// Return measurement (copy)
|
3805 |
+
return $.extend({}, meas);
|
3806 |
+
},
|
3807 |
+
|
3808 |
+
/**
|
3809 |
+
* Get default measurement using attribute's default handler
|
3810 |
+
* @param string attr Measurement attribute
|
3811 |
+
* @return obj Measurement values
|
3812 |
+
*/
|
3813 |
+
get_measurement_default: function(attr) {
|
3814 |
+
// Validate
|
3815 |
+
if ( !this.util.is_string(attr) ) {
|
3816 |
+
return null;
|
3817 |
+
}
|
3818 |
+
// Find default handler
|
3819 |
+
attr = this.util.format('get_%s_default', attr);
|
3820 |
+
if ( this.util.in_obj(this, attr) ) {
|
3821 |
+
attr = this[attr];
|
3822 |
+
if ( this.util.is_func(attr) ) {
|
3823 |
+
// Execute default handler
|
3824 |
+
attr = attr.call(this);
|
3825 |
+
}
|
3826 |
+
} else {
|
3827 |
+
attr = null;
|
3828 |
+
}
|
3829 |
+
return attr;
|
3830 |
+
},
|
3831 |
+
|
3832 |
+
/**
|
3833 |
+
* Retrieve theme offset
|
3834 |
+
* @return obj Theme offset with `width` & `height` properties
|
3835 |
+
*/
|
3836 |
+
get_offset: function() {
|
3837 |
+
return this.get_measurement('offset', { 'width': 0, 'height': 0});
|
3838 |
+
},
|
3839 |
+
|
3840 |
+
/**
|
3841 |
+
* Generate default offset
|
3842 |
+
* @return obj Theme offsets with `width` & `height` properties
|
3843 |
+
*/
|
3844 |
+
get_offset_default: function() {
|
3845 |
+
var offset = { 'width': 0, 'height': 0 };
|
3846 |
+
var v = this.get_viewer();
|
3847 |
+
var vn = v.dom_get();
|
3848 |
+
// Clone viewer
|
3849 |
+
var vc = vn
|
3850 |
+
.clone()
|
3851 |
+
.attr('id', '')
|
3852 |
+
.css({'visibility': 'hidden', 'position': 'absolute', 'top': ''})
|
3853 |
+
.removeClass('loading')
|
3854 |
+
.appendTo(vn.parent());
|
3855 |
+
// Get offset from layout node
|
3856 |
+
var l = vc.find(v.dom_get_selector('layout'));
|
3857 |
+
if ( l.length ) {
|
3858 |
+
// Clear inline styles
|
3859 |
+
l.find('*').css({
|
3860 |
+
'width': '',
|
3861 |
+
'height': '',
|
3862 |
+
'display': ''
|
3863 |
+
});
|
3864 |
+
// Resize content nodes
|
3865 |
+
var tags = this.get_tags('item', 'content');
|
3866 |
+
if ( tags.length ) {
|
3867 |
+
var offset_item = v.get_item().get_dimensions();
|
3868 |
+
// Set content dimensions
|
3869 |
+
tags = $(l.find(tags[0].get_selector('full')).get(0)).css({'width': offset_item.width, 'height': offset_item.height});
|
3870 |
+
$.each(offset_item, function(key, val) {
|
3871 |
+
offset[key] = -1 * val;
|
3872 |
+
});
|
3873 |
+
}
|
3874 |
+
|
3875 |
+
// Set offset
|
3876 |
+
offset.width += l.width();
|
3877 |
+
offset.height += l.height();
|
3878 |
+
// Normalize
|
3879 |
+
$.each(offset, function(key, val) {
|
3880 |
+
if ( val < 0 ) {
|
3881 |
+
offset[key] = 0;
|
3882 |
+
}
|
3883 |
+
});
|
3884 |
+
}
|
3885 |
+
vc.empty().remove();
|
3886 |
+
return offset;
|
3887 |
+
},
|
3888 |
+
|
3889 |
+
/**
|
3890 |
+
* Retrieve theme margins
|
3891 |
+
* @return obj Theme margin with `width` & `height` properties
|
3892 |
+
*/
|
3893 |
+
get_margin: function() {
|
3894 |
+
return this.get_measurement('margin', {'width': 0, 'height': 0});
|
3895 |
+
},
|
3896 |
+
|
3897 |
+
/**
|
3898 |
+
* Retrieve item dimensions
|
3899 |
+
* Dimensions are adjusted to fit window (if necessary)
|
3900 |
+
* @return obj Item dimensions with `width` & `height` properties
|
3901 |
+
*/
|
3902 |
+
get_item_dimensions: function() {
|
3903 |
+
var v = this.get_viewer();
|
3904 |
+
var dims = v.get_item().get_dimensions();
|
3905 |
+
if ( v.get_attribute('autofit', false) ) {
|
3906 |
+
// Get maximum dimensions
|
3907 |
+
var margin = this.get_margin();
|
3908 |
+
var offset = this.get_offset();
|
3909 |
+
offset.height += margin.height;
|
3910 |
+
offset.width += margin.width;
|
3911 |
+
var max = {'width': $(window).width(), 'height': $(window).height() };
|
3912 |
+
if ( max.width > offset.width ) {
|
3913 |
+
max.width -= offset.width;
|
3914 |
+
}
|
3915 |
+
if ( max.height > offset.height ) {
|
3916 |
+
max.height -= offset.height;
|
3917 |
+
}
|
3918 |
+
// Get resize factor
|
3919 |
+
var factor = Math.min(max.width / dims.width, max.height / dims.height);
|
3920 |
+
// Resize dimensions
|
3921 |
+
if ( factor < 1 ) {
|
3922 |
+
$.each(dims, function(key) {
|
3923 |
+
dims[key] = Math.round(dims[key] * factor);
|
3924 |
+
});
|
3925 |
+
}
|
3926 |
+
}
|
3927 |
+
return $.extend({}, dims);
|
3928 |
+
},
|
3929 |
+
|
3930 |
+
/**
|
3931 |
+
* Retrieve theme dimensions
|
3932 |
+
* @return obj Theme dimensions with `width` & `height` properties
|
3933 |
+
*/
|
3934 |
+
get_dimensions: function() {
|
3935 |
+
var dims = this.get_item_dimensions();
|
3936 |
+
var offset = this.get_offset();
|
3937 |
+
$.each(dims, function(key) {
|
3938 |
+
dims[key] += offset[key];
|
3939 |
+
});
|
3940 |
+
return dims;
|
3941 |
+
},
|
3942 |
+
|
3943 |
+
/**
|
3944 |
+
* Retrieve all breakpoints
|
3945 |
+
* @return object Breakpoints
|
3946 |
+
*/
|
3947 |
+
get_breakpoints: function() {
|
3948 |
+
return this.get_attribute_recursive('breakpoints');
|
3949 |
+
},
|
3950 |
+
|
3951 |
+
/**
|
3952 |
+
* Get breakpoint value
|
3953 |
+
* @param string target Breakpoint target
|
3954 |
+
* @return int Breakpoint value (pixels)
|
3955 |
+
*/
|
3956 |
+
get_breakpoint: function(target) {
|
3957 |
+
var ret = 0;
|
3958 |
+
if ( this.util.is_string(target) ) {
|
3959 |
+
var b = this.get_attribute_recursive('breakpoints');
|
3960 |
+
if ( this.util.is_obj(b) && target in b ) {
|
3961 |
+
ret = b[target];
|
3962 |
+
}
|
3963 |
+
}
|
3964 |
+
return ret;
|
3965 |
+
},
|
3966 |
+
|
3967 |
+
/* Output */
|
3968 |
+
|
3969 |
+
/**
|
3970 |
+
* Render Theme output
|
3971 |
+
* @param bool init (optional) Initialize theme (Default: FALSE)
|
3972 |
+
* @see Template.render()
|
3973 |
+
*/
|
3974 |
+
render: function(init) {
|
3975 |
+
var thm = this;
|
3976 |
+
var tpl = this.get_template();
|
3977 |
+
var st = 'events_render';
|
3978 |
+
if ( !this.get_status(st) ) {
|
3979 |
+
this.set_status(st);
|
3980 |
+
// Register events
|
3981 |
+
tpl.on([
|
3982 |
+
'render-init',
|
3983 |
+
'render-loading',
|
3984 |
+
'render-complete'
|
3985 |
+
],
|
3986 |
+
function(ev) {
|
3987 |
+
return thm.trigger(ev.type, ev.data);
|
3988 |
+
});
|
3989 |
+
}
|
3990 |
+
// Render template
|
3991 |
+
tpl.render(init);
|
3992 |
+
},
|
3993 |
+
|
3994 |
+
transition: function(event, clear_queue) {
|
3995 |
+
var dfr = null;
|
3996 |
+
var attr = 'transition';
|
3997 |
+
var v = this.get_viewer();
|
3998 |
+
var fx_temp = null;
|
3999 |
+
var anim_on = v.animation_enabled();
|
4000 |
+
if ( v.get_attribute(attr, true) && this.util.is_string(event) ) {
|
4001 |
+
var anim_stop = function() {
|
4002 |
+
var l = v.get_layout();
|
4003 |
+
l.find('*').each(function() {
|
4004 |
+
var el = $(this);
|
4005 |
+
while ( el.queue().length ) {
|
4006 |
+
el.stop(false, true);
|
4007 |
+
}
|
4008 |
+
});
|
4009 |
+
};
|
4010 |
+
// Stop queued animations
|
4011 |
+
if ( !!clear_queue ) {
|
4012 |
+
anim_stop();
|
4013 |
+
}
|
4014 |
+
// Get transition handlers
|
4015 |
+
var attr_set = [attr, 'set'].join('_');
|
4016 |
+
var trns;
|
4017 |
+
if ( !this.get_attribute(attr_set) ) {
|
4018 |
+
var models = this.get_ancestors(true);
|
4019 |
+
trns = [];
|
4020 |
+
this.set_attribute(attr_set, true);
|
4021 |
+
var thm = this;
|
4022 |
+
$.each(models, function(idx, model) {
|
4023 |
+
if ( attr in model && thm.util.is_obj(model[attr]) ) {
|
4024 |
+
trns.push(model[attr]);
|
4025 |
+
}
|
4026 |
+
});
|
4027 |
+
// Merge transition handlers into current theme
|
4028 |
+
trns.push({});
|
4029 |
+
trns = this.set_attribute(attr, $.extend.apply($, trns.reverse()));
|
4030 |
+
} else {
|
4031 |
+
trns = this.get_attribute(attr, {});
|
4032 |
+
}
|
4033 |
+
if ( this.util.is_method(trns, event) ) {
|
4034 |
+
// Disable animations if necessary
|
4035 |
+
if ( !anim_on ) {
|
4036 |
+
fx_temp = $.fx.off;
|
4037 |
+
$.fx.off = true;
|
4038 |
+
}
|
4039 |
+
// Pass control to transition event
|
4040 |
+
dfr = trns[event].call(this, v, $.Deferred());
|
4041 |
+
}
|
4042 |
+
}
|
4043 |
+
if ( !this.util.is_promise(dfr) ) {
|
4044 |
+
dfr = $.Deferred();
|
4045 |
+
dfr.reject();
|
4046 |
+
}
|
4047 |
+
dfr.always(function() {
|
4048 |
+
// Restore animation state
|
4049 |
+
if ( null !== fx_temp ) {
|
4050 |
+
$.fx.off = fx_temp;
|
4051 |
+
}
|
4052 |
+
});
|
4053 |
+
return dfr.promise();
|
4054 |
+
}
|
4055 |
+
};
|
4056 |
+
|
4057 |
+
View.Theme = Modeled_Component.extend(Theme);
|
4058 |
+
|
4059 |
+
/**
|
4060 |
+
* Template handler
|
4061 |
+
* Parses and Builds layout from raw template
|
4062 |
+
*/
|
4063 |
+
var Template = {
|
4064 |
+
/* Configuration */
|
4065 |
+
|
4066 |
+
_slug: 'template',
|
4067 |
+
_reciprocal: true,
|
4068 |
+
|
4069 |
+
_refs: {
|
4070 |
+
'theme': 'Theme'
|
4071 |
+
},
|
4072 |
+
|
4073 |
+
_attr_default: {
|
4074 |
+
/**
|
4075 |
+
* URI to layout (raw) file
|
4076 |
+
* @var string
|
4077 |
+
*/
|
4078 |
+
layout_uri: '',
|
4079 |
+
|
4080 |
+
/**
|
4081 |
+
* Raw layout template
|
4082 |
+
* @var string
|
4083 |
+
*/
|
4084 |
+
layout_raw: '',
|
4085 |
+
/**
|
4086 |
+
* Parsed layout
|
4087 |
+
* Placeholders processed
|
4088 |
+
* @var string
|
4089 |
+
*/
|
4090 |
+
layout_parsed: '',
|
4091 |
+
/**
|
4092 |
+
* Tags in template
|
4093 |
+
* Populated once template has been parsed
|
4094 |
+
* @var array
|
4095 |
+
*/
|
4096 |
+
tags: null,
|
4097 |
+
/**
|
4098 |
+
* Model to use for properties
|
4099 |
+
* Usually reference to an object in other component
|
4100 |
+
* @var obj
|
4101 |
+
*/
|
4102 |
+
model: null
|
4103 |
+
},
|
4104 |
+
|
4105 |
+
/* References */
|
4106 |
+
|
4107 |
+
theme: null,
|
4108 |
+
|
4109 |
+
/* Methods */
|
4110 |
+
|
4111 |
+
_c: function(attributes) {
|
4112 |
+
this._super('', attributes);
|
4113 |
+
},
|
4114 |
+
|
4115 |
+
_hooks: function() {
|
4116 |
+
// TODO: Refactor to event that can save retrieved tags
|
4117 |
+
// (`dom_init` event called during attribute initialization so tags are not saved)
|
4118 |
+
this.on('dom_init', function(ev) {
|
4119 |
+
// Init tag handlers
|
4120 |
+
var tags = this.get_tags(null, null, true);
|
4121 |
+
var names = [];
|
4122 |
+
var t = this;
|
4123 |
+
$.each(tags, function(idx, tag) {
|
4124 |
+
var name = tag.get_name();
|
4125 |
+
if ( -1 === $.inArray(name, names) ) {
|
4126 |
+
names.push(name);
|
4127 |
+
tag.get_handler().trigger(ev.type, {template: t});
|
4128 |
+
}
|
4129 |
+
});
|
4130 |
+
});
|
4131 |
+
},
|
4132 |
+
|
4133 |
+
get_theme: function() {
|
4134 |
+
var ret = this.get_component('theme');
|
4135 |
+
return ret;
|
4136 |
+
},
|
4137 |
+
|
4138 |
+
/* Output */
|
4139 |
+
|
4140 |
+
/**
|
4141 |
+
* Render output
|
4142 |
+
* @param bool init (optional) Whether to initialize layout (TRUE) or render item (FALSE) (Default: FALSE)
|
4143 |
+
* Events
|
4144 |
+
* > render-init: Initialize template
|
4145 |
+
* > render-loading: DOM elements created and item content about to be loaded
|
4146 |
+
* > render-complete: Item content loaded, ready for display
|
4147 |
+
*/
|
4148 |
+
render: function(init) {
|
4149 |
+
var v = this.get_theme().get_viewer();
|
4150 |
+
if ( !this.util.is_bool(init) ) {
|
4151 |
+
init = false;
|
4152 |
+
}
|
4153 |
+
// Populate layout
|
4154 |
+
if ( !init ) {
|
4155 |
+
if ( !v.is_active() ) {
|
4156 |
+
return false;
|
4157 |
+
}
|
4158 |
+
var item = v.get_item();
|
4159 |
+
if ( !this.util.is_type(item, View.Content_Item) ) {
|
4160 |
+
v.close();
|
4161 |
+
return false;
|
4162 |
+
}
|
4163 |
+
// Iterate through tags and populate layout
|
4164 |
+
if ( v.is_active() && this.has_tags() ) {
|
4165 |
+
var loading_promise = this.trigger('render-loading');
|
4166 |
+
var tpl = this;
|
4167 |
+
var tags = this.get_tags(),
|
4168 |
+
tag_promises = [];
|
4169 |
+
// Render Tag output
|
4170 |
+
$.when(item.load(), loading_promise).done(function() {
|
4171 |
+
if ( !v.is_active() ) {
|
4172 |
+
return false;
|
4173 |
+
}
|
4174 |
+
$.each(tags, function(idx, tag) {
|
4175 |
+
if ( !v.is_active() ) {
|
4176 |
+
return false;
|
4177 |
+
}
|
4178 |
+
tag_promises.push(tag.render(item).done(function(r) {
|
4179 |
+
if ( !v.is_active() ) {
|
4180 |
+
return false;
|
4181 |
+
}
|
4182 |
+
r.tag.dom_get().html(r.output);
|
4183 |
+
}));
|
4184 |
+
});
|
4185 |
+
// Fire event when all tags rendered
|
4186 |
+
if ( !v.is_active() ) {
|
4187 |
+
return false;
|
4188 |
+
}
|
4189 |
+
$.when.apply($, tag_promises).done(function() {
|
4190 |
+
tpl.trigger('render-complete');
|
4191 |
+
});
|
4192 |
+
});
|
4193 |
+
}
|
4194 |
+
} else {
|
4195 |
+
// Get Layout (basic)
|
4196 |
+
this.trigger('render-init', this.dom_get());
|
4197 |
+
}
|
4198 |
+
},
|
4199 |
+
|
4200 |
+
/*-** Layout **-*/
|
4201 |
+
|
4202 |
+
/**
|
4203 |
+
* Retrieve layout
|
4204 |
+
* @param bool parsed (optional) TRUE retrieves parsed layout, FALSE retrieves raw layout (Default: TRUE)
|
4205 |
+
* @return string Layout (HTML)
|
4206 |
+
*/
|
4207 |
+
get_layout: function(parsed) {
|
4208 |
+
// Validate
|
4209 |
+
if ( !this.util.is_bool(parsed) ) {
|
4210 |
+
parsed = true;
|
4211 |
+
}
|
4212 |
+
// Determine which layout to retrieve (raw/parsed)
|
4213 |
+
var l = ( parsed ) ? this.parse_layout() : this.get_attribute('layout_raw', '');
|
4214 |
+
return l;
|
4215 |
+
},
|
4216 |
+
|
4217 |
+
/**
|
4218 |
+
* Parse layout
|
4219 |
+
* Converts template tags to HTML elements
|
4220 |
+
* > Template tag properties saved to HTML elements for future initialization
|
4221 |
+
* Returns saved layout if previously parsed
|
4222 |
+
* @return string Parsed layout
|
4223 |
+
*/
|
4224 |
+
parse_layout: function() {
|
4225 |
+
// Check for previously-parsed layout
|
4226 |
+
var a = 'layout_parsed';
|
4227 |
+
var ret = this.get_attribute(a);
|
4228 |
+
// Return cached layout immediately
|
4229 |
+
if ( this.util.is_string(ret) ) {
|
4230 |
+
return ret;
|
4231 |
+
}
|
4232 |
+
// Parse raw layout
|
4233 |
+
ret = this.sanitize_layout( this.get_layout(false) );
|
4234 |
+
ret = this.parse_tags(ret);
|
4235 |
+
// Save parsed layout
|
4236 |
+
this.set_attribute(a, ret);
|
4237 |
+
|
4238 |
+
// Return parsed layout
|
4239 |
+
return ret;
|
4240 |
+
},
|
4241 |
+
|
4242 |
+
/**
|
4243 |
+
* Sanitize layout
|
4244 |
+
* @param obj|string l Layout string or jQuery object
|
4245 |
+
* @return obj|string Sanitized layout (Same data type that was passed to method)
|
4246 |
+
*/
|
4247 |
+
sanitize_layout: function(l) {
|
4248 |
+
// Stop processing if invalid value
|
4249 |
+
if ( this.util.is_empty(l) ) {
|
4250 |
+
return l;
|
4251 |
+
}
|
4252 |
+
// Set return type
|
4253 |
+
var rtype = ( this.util.is_string(l) ) ? 'string' : null;
|
4254 |
+
/* Quarantine hard-coded tags */
|
4255 |
+
|
4256 |
+
// Create DOM structure from raw template
|
4257 |
+
var dom = $(l);
|
4258 |
+
// Find hard-coded tag nodes
|
4259 |
+
var tag_temp = this.get_tag_temp();
|
4260 |
+
var cls = tag_temp.get_class();
|
4261 |
+
var cls_new = ['x', cls].join('_');
|
4262 |
+
$(tag_temp.get_selector(), dom).each(function() {
|
4263 |
+
// Replace matching class name with blocking class
|
4264 |
+
$(this).removeClass(cls).addClass(cls_new);
|
4265 |
+
});
|
4266 |
+
// Format return value
|
4267 |
+
switch ( rtype ) {
|
4268 |
+
case 'string' :
|
4269 |
+
dom = dom.wrap('<div />').parent().html();
|
4270 |
+
l = dom;
|
4271 |
+
break;
|
4272 |
+
default :
|
4273 |
+
l = dom;
|
4274 |
+
}
|
4275 |
+
return l;
|
4276 |
+
},
|
4277 |
+
|
4278 |
+
/*-** Tags **-*/
|
4279 |
+
|
4280 |
+
/**
|
4281 |
+
* Extract tags from template
|
4282 |
+
* Tags are replaced with DOM element placeholders
|
4283 |
+
* Extracted tags are saved as element attribute values (for future use)
|
4284 |
+
* @param string l Raw layout to parse
|
4285 |
+
* @return string Parsed layout
|
4286 |
+
*/
|
4287 |
+
parse_tags: function(l) {
|
4288 |
+
// Validate
|
4289 |
+
if ( !this.util.is_string(l) ) {
|
4290 |
+
return '';
|
4291 |
+
}
|
4292 |
+
// Parse tags in layout
|
4293 |
+
// Tag regex
|
4294 |
+
var re = /\{{2}\s*(\w.*?)\s*\}{2}/gim;
|
4295 |
+
// Tag match results
|
4296 |
+
var match;
|
4297 |
+
// Iterate through template and find tags
|
4298 |
+
while ( match = re.exec(l) ) {
|
4299 |
+
// Replace tag in layout with DOM container
|
4300 |
+
l = l.substring(0, match.index) + this.get_tag_container(match[1]) + l.substring(match.index + match[0].length);
|
4301 |
+
}
|
4302 |
+
return l;
|
4303 |
+
},
|
4304 |
+
|
4305 |
+
/**
|
4306 |
+
* Create DOM element container for tag
|
4307 |
+
* @param string Tag ID (will be prefixed)
|
4308 |
+
* @return string DOM element
|
4309 |
+
*/
|
4310 |
+
get_tag_container: function(tag) {
|
4311 |
+
// Build element
|
4312 |
+
var attr = this.get_tag_attribute();
|
4313 |
+
return this.util.format('<span %s="%s"></span>', attr, encodeURI(tag));
|
4314 |
+
},
|
4315 |
+
|
4316 |
+
get_tag_attribute: function() {
|
4317 |
+
return this.get_tag_temp().dom_get_attribute();
|
4318 |
+
},
|
4319 |
+
|
4320 |
+
/**
|
4321 |
+
* Retrieve Template_Tag instance at specified index
|
4322 |
+
* @param int idx (optional) Index to retrieve tag from
|
4323 |
+
* @return Template_Tag Tag instance
|
4324 |
+
*/
|
4325 |
+
get_tag: function(idx) {
|
4326 |
+
var ret = null;
|
4327 |
+
if ( this.has_tags() ) {
|
4328 |
+
var tags = this.get_tags();
|
4329 |
+
if ( !this.util.is_int(idx) || 0 > idx || idx >= tags.length ) {
|
4330 |
+
idx = 0;
|
4331 |
+
}
|
4332 |
+
ret = tags[idx];
|
4333 |
+
}
|
4334 |
+
return ret;
|
4335 |
+
},
|
4336 |
+
|
4337 |
+
/**
|
4338 |
+
* Retrieve tags from template
|
4339 |
+
* Subset of tags may be retrieved based on parameter values
|
4340 |
+
* Template is parsed if tags not set
|
4341 |
+
* @param string name (optional) Tag type to retrieve instances of
|
4342 |
+
* @param string prop (optional) Tag property to retrieve instances of
|
4343 |
+
* @param bool isolate (optional) Do not save retrieved tags, only fetch and return (Default: TRUE)
|
4344 |
+
* @return array Template_Tag instances
|
4345 |
+
*/
|
4346 |
+
get_tags: function(name, prop, isolate) {
|
4347 |
+
// Validate
|
4348 |
+
if ( !this.util.is_bool(isolate) ) {
|
4349 |
+
isolate = false;
|
4350 |
+
}
|
4351 |
+
// Setup
|
4352 |
+
var a = 'tags';
|
4353 |
+
var tags = this.get_attribute(a);
|
4354 |
+
// Initialize tags
|
4355 |
+
if ( !this.util.is_array(tags) ) {
|
4356 |
+
tags = [];
|
4357 |
+
// Retrieve layout DOM tree
|
4358 |
+
var d = this.dom_get();
|
4359 |
+
// Select tag nodes
|
4360 |
+
var attr = this.get_tag_attribute();
|
4361 |
+
var nodes = $(d).find('[' + attr + ']');
|
4362 |
+
// Build tag instances from nodes
|
4363 |
+
$(nodes).each(function() {
|
4364 |
+
// Get tag placeholder
|
4365 |
+
var el = $(this);
|
4366 |
+
var tag = new View.Template_Tag(decodeURI(el.attr(attr)));
|
4367 |
+
// Populate valid tags
|
4368 |
+
if ( tag.has_handler() ) {
|
4369 |
+
// Add tag to array
|
4370 |
+
tags.push(tag);
|
4371 |
+
if ( !isolate ) {
|
4372 |
+
// Connect tag to DOM node
|
4373 |
+
tag.dom_set(el);
|
4374 |
+
// Set classes
|
4375 |
+
el.addClass(tag.get_classes(' '));
|
4376 |
+
}
|
4377 |
+
}
|
4378 |
+
// Clear data attribute
|
4379 |
+
if ( !isolate ) {
|
4380 |
+
el.removeAttr(attr);
|
4381 |
+
}
|
4382 |
+
});
|
4383 |
+
if ( !isolate ) {
|
4384 |
+
// Save tags
|
4385 |
+
this.set_attribute(a, tags, false);
|
4386 |
+
}
|
4387 |
+
}
|
4388 |
+
// Filter tags by parameters
|
4389 |
+
if ( !this.util.is_empty(tags) && this.util.is_string(name) ) {
|
4390 |
+
// Normalize
|
4391 |
+
if ( !this.util.is_string(prop) ) {
|
4392 |
+
prop = false;
|
4393 |
+
}
|
4394 |
+
var tags_filtered = [];
|
4395 |
+
var tc = null;
|
4396 |
+
for ( var x = 0; x < tags.length; x++ ) {
|
4397 |
+
tc = tags[x];
|
4398 |
+
if ( name === tc.get_name() ) {
|
4399 |
+
// Check tag property
|
4400 |
+
if ( !prop || prop === tc.get_prop() ) {
|
4401 |
+
tags_filtered.push(tc);
|
4402 |
+
}
|
4403 |
+
}
|
4404 |
+
}
|
4405 |
+
tags = tags_filtered;
|
4406 |
+
}
|
4407 |
+
return ( this.util.is_array(tags, false) ) ? tags : [];
|
4408 |
+
},
|
4409 |
+
|
4410 |
+
/**
|
4411 |
+
* Check if template contains tags
|
4412 |
+
* @return bool TRUE if tags exist, FALSE otherwise
|
4413 |
+
*/
|
4414 |
+
has_tags: function() {
|
4415 |
+
return ( this.get_tags().length > 0 ) ? true : false;
|
4416 |
+
},
|
4417 |
+
|
4418 |
+
/**
|
4419 |
+
* Retrieve temporary tag instance
|
4420 |
+
* @return Template_Tag Temporary tag
|
4421 |
+
*/
|
4422 |
+
get_tag_temp: function() {
|
4423 |
+
return this.get_controller().get_component_temp(View.Template_Tag);
|
4424 |
+
},
|
4425 |
+
|
4426 |
+
/**
|
4427 |
+
* Retrieve Template tag CSS selector
|
4428 |
+
* @uses Template.get_tag_temp() to retrieve temporary tag instance
|
4429 |
+
* @uses Template_Tag.get_selector() to retrieve selector
|
4430 |
+
* @param name string Tag name
|
4431 |
+
* @param prop string Tag Property
|
4432 |
+
* @return string Template Tag CSS selector
|
4433 |
+
*/
|
4434 |
+
get_tag_selector: function(name, prop) {
|
4435 |
+
if ( !this.util.is_string(name) ) {
|
4436 |
+
name = '';
|
4437 |
+
}
|
4438 |
+
if ( !this.util.is_string(prop) ) {
|
4439 |
+
prop = '';
|
4440 |
+
}
|
4441 |
+
var tag = this.get_tag_temp();
|
4442 |
+
tag.set_attribute('name', name);
|
4443 |
+
tag.set_attribute('prop', prop);
|
4444 |
+
return tag.get_selector('full');
|
4445 |
+
},
|
4446 |
+
|
4447 |
+
/*-** DOM **-*/
|
4448 |
+
|
4449 |
+
/**
|
4450 |
+
* Custom DOM initialization
|
4451 |
+
*/
|
4452 |
+
dom_init: function() {
|
4453 |
+
// Create DOM object from parsed layout
|
4454 |
+
this.dom_set(this.get_layout());
|
4455 |
+
this.trigger('dom_init');
|
4456 |
+
},
|
4457 |
+
|
4458 |
+
/**
|
4459 |
+
* Retrieve DOM element(s) for specified tag
|
4460 |
+
* @param string tag Name of tag to retrieve
|
4461 |
+
* @param string prop (optional) Specific tag property to retrieve
|
4462 |
+
* @return array DOM elements for tag
|
4463 |
+
*/
|
4464 |
+
dom_get_tag: function(tag, prop) {
|
4465 |
+
var ret = $();
|
4466 |
+
var tags = this.get_tags(tag, prop);
|
4467 |
+
if ( tags.length ) {
|
4468 |
+
// Build selector
|
4469 |
+
var level = null;
|
4470 |
+
if ( this.util.is_string(tag) ) {
|
4471 |
+
level = ( this.util.is_string(prop) ) ? 'full' : 'tag';
|
4472 |
+
}
|
4473 |
+
var sel = '.' + tags[0].get_class(level);
|
4474 |
+
ret = this.dom_get().find(sel);
|
4475 |
+
}
|
4476 |
+
return ret;
|
4477 |
+
}
|
4478 |
+
};
|
4479 |
+
|
4480 |
+
View.Template = Modeled_Component.extend(Template);
|
4481 |
+
|
4482 |
+
/**
|
4483 |
+
* Template tag
|
4484 |
+
*/
|
4485 |
+
var Template_Tag = {
|
4486 |
+
/* Configuration */
|
4487 |
+
_slug: 'template_tag',
|
4488 |
+
_reciprocal: true,
|
4489 |
+
/* Properties */
|
4490 |
+
_attr_default: {
|
4491 |
+
name: null,
|
4492 |
+
prop: null,
|
4493 |
+
match: null
|
4494 |
+
},
|
4495 |
+
/**
|
4496 |
+
* Tag Handlers
|
4497 |
+
* Collection of Template_Tag_Handler instances
|
4498 |
+
* @var obj
|
4499 |
+
*/
|
4500 |
+
handlers: {},
|
4501 |
+
/* Methods */
|
4502 |
+
|
4503 |
+
/**
|
4504 |
+
* Constructor
|
4505 |
+
* @param
|
4506 |
+
*/
|
4507 |
+
_c: function(tag_match) {
|
4508 |
+
this.parse(tag_match);
|
4509 |
+
},
|
4510 |
+
|
4511 |
+
/**
|
4512 |
+
* Set instance attributes using tag extracted from template
|
4513 |
+
* @param string tag_match Extracted tag match
|
4514 |
+
*/
|
4515 |
+
parse: function(tag_match) {
|
4516 |
+
// Return default value for invalid instances
|
4517 |
+
if ( !this.util.is_string(tag_match) ) {
|
4518 |
+
return false;
|
4519 |
+
}
|
4520 |
+
// Parse instance options
|
4521 |
+
var parts = tag_match.split('|'),
|
4522 |
+
part;
|
4523 |
+
if ( !parts.length ) {
|
4524 |
+
return null;
|
4525 |
+
}
|
4526 |
+
var attrs = {
|
4527 |
+
name: null,
|
4528 |
+
prop: null,
|
4529 |
+
match: tag_match
|
4530 |
+
};
|
4531 |
+
// Get tag ID
|
4532 |
+
attrs.name = parts[0];
|
4533 |
+
// Get main property
|
4534 |
+
if ( attrs.name.indexOf('.') !== -1 ) {
|
4535 |
+
attrs.name = attrs.name.split('.', 2);
|
4536 |
+
attrs.prop = attrs.name[1];
|
4537 |
+
attrs.name = attrs.name[0];
|
4538 |
+
}
|
4539 |
+
// Get other attributes
|
4540 |
+
for ( var x = 1; x < parts.length; x++ ) {
|
4541 |
+
part = parts[x].split(':', 1);
|
4542 |
+
if ( part.length > 1 && !( part[0] in attrs ) ) {
|
4543 |
+
// Add key/value pair to attributes
|
4544 |
+
attrs[part[0]] = part[1];
|
4545 |
+
}
|
4546 |
+
}
|
4547 |
+
// Save to instance
|
4548 |
+
this.set_attributes(attrs, true);
|
4549 |
+
},
|
4550 |
+
|
4551 |
+
/**
|
4552 |
+
* Render tag output
|
4553 |
+
* @param Content_Item item
|
4554 |
+
* @return obj jQuery.Promise object that is resolved when tag is rendered
|
4555 |
+
* Parameters passed to callbacks
|
4556 |
+
* > tag obj Current tag instance
|
4557 |
+
* > output string Tag output
|
4558 |
+
*/
|
4559 |
+
render: function(item) {
|
4560 |
+
var tag = this;
|
4561 |
+
return tag.get_handler().render(item, tag).pipe(function(output) {
|
4562 |
+
return {'tag': tag, 'output': output};
|
4563 |
+
});
|
4564 |
+
},
|
4565 |
+
|
4566 |
+
/**
|
4567 |
+
* Retrieve tag name
|
4568 |
+
* @return string Tag name (DEFAULT: NULL)
|
4569 |
+
*/
|
4570 |
+
get_name: function() {
|
4571 |
+
return this.get_attribute('name');
|
4572 |
+
},
|
4573 |
+
|
4574 |
+
/**
|
4575 |
+
* Retrieve tag property
|
4576 |
+
*/
|
4577 |
+
get_prop: function() {
|
4578 |
+
return this.get_attribute('prop');
|
4579 |
+
},
|
4580 |
+
|
4581 |
+
/**
|
4582 |
+
* Retrieve tag handler
|
4583 |
+
* @return Template_Tag_Handler Handler instance (Empty instance if handler does not exist)
|
4584 |
+
*/
|
4585 |
+
get_handler: function() {
|
4586 |
+
return ( this.has_handler() ) ? this.handlers[this.get_name()] : new View.Template_Tag_Handler('');
|
4587 |
+
},
|
4588 |
+
|
4589 |
+
/**
|
4590 |
+
* Check if handler exists for tag
|
4591 |
+
* @return bool TRUE if handler exists, FALSE otherwise
|
4592 |
+
*/
|
4593 |
+
has_handler: function() {
|
4594 |
+
return ( this.get_name() in this.handlers );
|
4595 |
+
},
|
4596 |
+
|
4597 |
+
/**
|
4598 |
+
* Generate class names for DOM node
|
4599 |
+
* @param string rtype (optional) Return data type
|
4600 |
+
* > Default: array
|
4601 |
+
* > If string supplied: Joined classes delimited by parameter
|
4602 |
+
* @uses get_class() to generate class names
|
4603 |
+
* @uses Array.join() to convert class names array to string
|
4604 |
+
* @return array Class names
|
4605 |
+
*/
|
4606 |
+
get_classes: function(rtype) {
|
4607 |
+
// Build array of class names
|
4608 |
+
var cls = [
|
4609 |
+
// General tag class
|
4610 |
+
this.get_class(),
|
4611 |
+
// Tag name
|
4612 |
+
this.get_class('tag'),
|
4613 |
+
// Tag name + property
|
4614 |
+
this.get_class('full')
|
4615 |
+
];
|
4616 |
+
// Convert class names array to string
|
4617 |
+
if ( this.util.is_string(rtype) ) {
|
4618 |
+
cls = cls.join(rtype);
|
4619 |
+
}
|
4620 |
+
// Return class names
|
4621 |
+
return cls;
|
4622 |
+
},
|
4623 |
+
|
4624 |
+
/**
|
4625 |
+
* Generate DOM-compatible class name based with varied levels of specificity
|
4626 |
+
* @param int level (optional) Class name specificity
|
4627 |
+
* > Default: General tag class (common to all tag elements)
|
4628 |
+
* > tag: Tag Name
|
4629 |
+
* > full: Tag Name + Property
|
4630 |
+
* @return string Class name
|
4631 |
+
*/
|
4632 |
+
get_class: function(level) {
|
4633 |
+
var cls = '';
|
4634 |
+
// Build base
|
4635 |
+
switch ( level ) {
|
4636 |
+
case 'tag' :
|
4637 |
+
// Tag name
|
4638 |
+
cls = this.get_name();
|
4639 |
+
break;
|
4640 |
+
case 'full' :
|
4641 |
+
// Tag name + property
|
4642 |
+
var parts = [this.get_name(), this.get_prop()];
|
4643 |
+
var a = [];
|
4644 |
+
var i;
|
4645 |
+
for ( i = 0; i < parts.length; i++ ) {
|
4646 |
+
if ( this.util.is_string(parts[i]) ) {
|
4647 |
+
a.push(parts[i]);
|
4648 |
+
}
|
4649 |
+
}
|
4650 |
+
cls = a.join('_');
|
4651 |
+
break;
|
4652 |
+
}
|
4653 |
+
// Format & return
|
4654 |
+
return ( !this.util.is_string(cls) ) ? this.get_ns() : this.add_ns(cls);
|
4655 |
+
},
|
4656 |
+
|
4657 |
+
/**
|
4658 |
+
* Generate tag selector based on specified class name level
|
4659 |
+
* @param string level (optional) Class name specificity (@see get_class() for parameter values)
|
4660 |
+
* @return string Tag selector
|
4661 |
+
*/
|
4662 |
+
get_selector: function(level) {
|
4663 |
+
// Get base
|
4664 |
+
var ret = this.get_class(level);
|
4665 |
+
// Format
|
4666 |
+
if ( this.util.is_string(ret) ) {
|
4667 |
+
ret = '.' + ret;
|
4668 |
+
} else {
|
4669 |
+
ret = '';
|
4670 |
+
}
|
4671 |
+
return ret;
|
4672 |
+
}
|
4673 |
+
};
|
4674 |
+
|
4675 |
+
View.Template_Tag = Component.extend(Template_Tag);
|
4676 |
+
|
4677 |
+
/**
|
4678 |
+
* Theme tag handler
|
4679 |
+
*/
|
4680 |
+
var Template_Tag_Handler = {
|
4681 |
+
/* Configuration */
|
4682 |
+
_slug: 'template_tag_handler',
|
4683 |
+
/* Properties */
|
4684 |
+
_attr_default: {
|
4685 |
+
supports_modifiers: false,
|
4686 |
+
dynamic: false,
|
4687 |
+
props: {}
|
4688 |
+
},
|
4689 |
+
|
4690 |
+
/* Methods */
|
4691 |
+
|
4692 |
+
/**
|
4693 |
+
* Render tag output
|
4694 |
+
* @param Content_Item item Item currently being displayed
|
4695 |
+
* @param Template_Tag Tag instance (from template)
|
4696 |
+
* @return obj jQuery.Promise linked to rendering process
|
4697 |
+
*/
|
4698 |
+
render: function(item, instance) {
|
4699 |
+
var dfr = $.Deferred();
|
4700 |
+
// Pass to attribute method
|
4701 |
+
this.call_attribute('render', item, instance, dfr);
|
4702 |
+
// Return promise
|
4703 |
+
return dfr.promise();
|
4704 |
+
},
|
4705 |
+
|
4706 |
+
add_prop: function(prop, fn) {
|
4707 |
+
// Get attribute
|
4708 |
+
var a = 'props';
|
4709 |
+
var props = this.get_attribute(a);
|
4710 |
+
// Validate
|
4711 |
+
if ( !this.util.is_string(prop) || !this.util.is_func(fn) ) {
|
4712 |
+
return false;
|
4713 |
+
}
|
4714 |
+
if ( !this.util.is_obj(props, false) ) {
|
4715 |
+
props = {};
|
4716 |
+
}
|
4717 |
+
// Add property
|
4718 |
+
props[prop] = fn;
|
4719 |
+
// Save attribute
|
4720 |
+
this.set_attribute(a, props);
|
4721 |
+
},
|
4722 |
+
|
4723 |
+
handle_prop: function(prop, item, instance) {
|
4724 |
+
// Locate property
|
4725 |
+
var props = this.get_attribute('props');
|
4726 |
+
var out = '';
|
4727 |
+
if ( this.util.is_obj(props) && ( prop in props ) && this.util.is_func(props[prop]) ) {
|
4728 |
+
out = props[prop].call(this, item, instance);
|
4729 |
+
} else {
|
4730 |
+
out = item.get_viewer().get_label(prop);
|
4731 |
+
}
|
4732 |
+
return out;
|
4733 |
+
}
|
4734 |
+
};
|
4735 |
+
|
4736 |
+
View.Template_Tag_Handler = Component.extend(Template_Tag_Handler);
|
4737 |
+
/* Update References */
|
4738 |
+
|
4739 |
+
// Attach to global object
|
4740 |
+
View = SLB.attach('View', View);
|
4741 |
})(jQuery);}
|
client/js/prod/lib.admin.js
CHANGED
@@ -1 +1 @@
|
|
1 |
-
window.SLB&&SLB.attach
|
1 |
+
window.SLB&&SLB.attach&&!function($){SLB.attach("Admin",{init:function(){postboxes&&postboxes.add_postbox_toggles(pagenow)}}),$(document).ready(function(){SLB.Admin.init()})}(jQuery);
|
client/js/prod/lib.core.js
CHANGED
@@ -1 +1 @@
|
|
1 |
-
window.jQuery
|
1 |
+
window.jQuery&&!function($){"use strict";function Class(){}var c_init=!1,Base={base:!(Class.extend=function(members){var val,name,_super=this.prototype,proto=(c_init=!0,new this);for(name in c_init=!1,proto)$.isPlainObject(proto[name])&&(val=$.extend({},proto[name]),proto[name]=val);for(name in members)"function"==typeof members[name]&&"function"==typeof _super[name]?proto[name]=function(nm,fn){return function(){var tmp=this._super,ret=(this._super=_super[nm],fn.apply(this,arguments));return this._super=tmp,ret}}(name,members[name]):proto[name]=$.isPlainObject(members[name])?$.extend({},members[name]):members[name];function Class(){c_init||("function"==typeof this._init&&this._init.apply(this,arguments),"function"==typeof this._c&&this._c.apply(this,arguments))}return((Class.prototype=proto).constructor=Class).extend=this.extend,Class}),_parent:null,prefix:"slb",_init:function(){this._set_parent()},_set_parent:function(p){this.util.is_set(p)&&(this._parent=p),this.util._parent=this},attach:function(member,data,simple){var ret=data;return simple=void 0!==simple&&!!simple,"string"===$.type(member)&&($.isPlainObject(data)&&!simple&&(data._parent=this,data=this.Class.extend(data)),this[member]="function"===$.type(data)?new data:data,ret=this[member]),ret},has_child:function(child){if(!this.util.is_string(child))return!1;for(var children=child.split("."),o=(child=null,this),x=0;x<children.length;x++)if(""!==(child=children[x])){if(!this.util.is_obj(o)||!o[child])return!1;o=o[child]}return!0},is_base:function(){return!!this.base},get_parent:function(){return this._parent||(this._parent={}),this._parent}},Base=(Base.attach("util",{_base:null,_parent:null,get_base:function(){if(!this._base){for(var p=this.get_parent(),p_prev=null,methods=["is_base","get_parent"];p_prev!==p&&this.is_method(p,methods)&&!p.is_base();)p=(p_prev=p).get_parent();this._base=p}return this._base},get_parent:function(prop){var ret=(ret=this._parent)||(this._parent={});return ret=this.is_string(prop)?this.in_obj(ret,prop)?ret[prop]:null:ret},get_sep:function(sep){return this.is_string(sep,!1)?sep:"_"},get_prefix:function(){var p=this.get_parent("prefix");return this.is_string(p,!1)?p:""},has_prefix:function(val,sep){return this.is_string(val)&&0===val.indexOf(this.get_prefix()+this.get_sep(sep))},add_prefix:function(val,sep,once){return this.is_string(val)?(sep=this.get_sep(sep),(once=this.is_bool(once)?once:!0)&&this.has_prefix(val,sep)?val:[this.get_prefix(),val].join(sep)):this.get_prefix()},remove_prefix:function(val,sep,once){if(!this.is_string(val,!0))return"";if(sep=this.get_sep(sep),this.is_bool(once)||(once=!0),this.has_prefix(val,sep))for(var prfx=this.get_prefix()+sep;val=val.substr(prfx.length),!once&&this.has_prefix(val,sep););return val},get_attribute:function(attr_base){var attr=["data",this.get_prefix()].join("-");return attr=this.is_string(attr_base)&&0!==attr_base.indexOf(attr+"-")?[attr,attr_base].join("-"):attr},get_context:function(){var b=this.get_base();return $.isArray(b.context)||(b.context=[]),b.context},is_context:function(ctx){return this.is_string(ctx)&&(ctx=[ctx]),this.is_array(ctx)&&0<this.arr_intersect(this.get_context(),ctx).length},is_set:function(val){return void 0!==val},is_type:function(val,type,nonempty){var ret=!1;if(this.is_set(val)&&null!==val&&this.is_set(type))switch($.type(type)){case"function":ret=val instanceof type;break;case"string":ret=$.type(val)===type;break;default:ret=!1}return ret=!ret||this.is_set(nonempty)&&!nonempty?ret:!this.is_empty(val)},is_string:function(value,nonempty){return this.is_type(value,"string",nonempty)},is_array:function(value,nonempty){return this.is_type(value,"array",nonempty)},is_bool:function(value){return this.is_type(value,"boolean",!1)},is_obj:function(value,nonempty){return this.is_type(value,"object",nonempty)},is_func:function(value){return this.is_type(value,"function",!1)},is_method:function(obj,key){var ret=!1;if(this.is_string(key)&&(key=[key]),this.in_obj(obj,key))for(var ret=!0,x=0;ret&&x<key.length;)ret=this.is_func(obj[key[x]]),x++;return ret},is_instance:function(obj,parent){return!!this.is_func(parent)&&(this.is_obj(obj)&&obj instanceof parent)},is_class:function(cls,parent){var ret=this.is_func(cls)&&"prototype"in cls;return ret=ret&&this.is_set(parent)?this.is_instance(cls.prototype,parent):ret},is_num:function(value,nonempty){var f={nan:Number.isNaN||isNaN,finite:Number.isFinite||isFinite};return this.is_type(value,"number",nonempty)&&!f.nan(value)&&f.finite(value)},is_int:function(value,nonempty){return this.is_num(value,nonempty)&&Math.floor(value)===value},is_scalar:function(value,nonempty){return this.is_num(value,nonempty)||this.is_string(value,nonempty)||this.is_bool(value)},is_empty:function(value,type){var ret=!1;if(this.is_set(value))for(var empties=[null,"",!1,0],x=0;!ret&&x<empties.length;)ret=empties[x]===value,x++;else ret=!0;if(!ret)if(this.is_set(type)||(type=$.type(value)),this.is_type(value,type,!1))switch(type){case"string":case"array":ret=0===value.length;break;case"number":ret=0==value;break;case"object":if($.isPlainObject(value)){if(Object.getOwnPropertyNames)ret=0===Object.getOwnPropertyNames(value).length;else if(value.hasOwnProperty)for(var key in ret=!0,value)if(value.hasOwnProperty(key)){ret=!1;break}}else ret=!1}else ret=!0;return ret},is_promise:function(obj){return this.is_method(obj,["then","done","always","fail","pipe"])},format:function(fmt,val){if(!this.is_string(fmt))return"";function strip(txt){return-1!==txt.indexOf(ph)?txt.replace(ph,""):txt}var params=[],ph="%s";if(arguments.length<2||-1===fmt.indexOf(ph))return strip(fmt);params=Array.prototype.slice.call(arguments,1);for(var x=0;x<params.length;x++)this.is_scalar(params[x],!1)||(params[x]="");if(1===params.length)fmt=fmt.replace(ph,params[0].toString());else{for(var pos,idx=0,len=params.length,rlen=ph.length;(pos=fmt.indexOf(ph))&&-1!==pos&&idx<len;)fmt=fmt.substr(0,pos)+params[idx].toString()+fmt.substr(pos+rlen),idx++;fmt=strip(fmt)}return fmt},in_obj:function(obj,key,all){this.is_bool(all)||(all=!0),this.is_string(key)&&(key=[key]);var ret=!1;if(this.is_obj(obj)&&this.is_array(key))for(var val,x=0;x<key.length&&(val=key[x],ret=!!(this.is_string(val)&&val in obj),!(!all&&ret||all&&!ret));x++);return ret},obj_keys:function(obj){var prop,keys=[];if(this.is_obj(obj))if(Object.keys)keys=Object.keys(obj);else for(prop in obj)obj.hasOwnProperty(prop)&&keys.push(prop);return keys},arr_intersect:function(arr1,arr2){var ret=[],params=Array.prototype.slice.call(arguments),arrs=[];for(x=0;x<params.length;x++)this.is_array(params[x],!1)&&arrs.push(params[x]);if(!(arrs.length<2))for(var add,sub,params=null,base=arrs.shift(),x=0;x<base.length;x++){for(add=!0,sub=0;sub<arrs.length;sub++)if(-1===arrs[sub].indexOf(base[x])){add=!1;break}add&&ret.push(base[x])}return ret},guid:function(){function _p8(s){var p=(Math.random().toString(16)+"000000000").substr(2,8);return s?"-"+p.substr(0,4)+"-"+p.substr(4,4):p}return _p8()+_p8(!0)+_p8(!0)+_p8()},parse_uri:function(uri){return $('<a href="'+uri+'"/>').get(0)},parse_query:function(uri){var i,key,temp,delim_vars="&",delim_val="=",query={raw:[],parsed:{},string:""};if(0===(uri=this.parse_uri(uri)).search.indexOf("?"))for(query.raw=uri.search.substr(1).split(delim_vars),i=0;i<query.raw.length;i++)key=(temp=query.raw[i].split(delim_val)).shift(),temp=0<temp.length?temp.join(delim_val):null,query.parsed[key]=temp;return query.parsed},build_query:function(query){var val,key,q=[],delim_vars="&",delim_val="=";for(key in query)val=null!==query[key]?delim_val+query[key]:"",q.push(key+val);return q.join(delim_vars)}},!0),Class.extend(Base)),Base=Base.extend({base:!0,context:[],Class:Base,_init:function(){this._super(),$("html").addClass(this.util.get_prefix())}});window.SLB=new Base}(jQuery);
|
client/js/prod/lib.view.js
CHANGED
@@ -1 +1 @@
|
|
1 |
-
window.SLB&&SLB.attach&&function($){var View={assets:{},component_defaults:[],loading:[],cache:{},component_temps:{},options:{},_init:function(){this._super(),this.init_refs(),this.init_components()},init_refs:function(){var r,ref,prop;for(prop in this)if(prop=this[prop],this.is_component(prop)&&!this.util.is_empty(prop.prototype._refs))for(r in prop.prototype._refs)ref=prop.prototype._refs[r],this.util.is_string(ref)&&ref in this&&(ref=prop.prototype._refs[r]=this[ref]),this.util.is_class(ref)||delete prop.prototype_refs[r]},init_components:function(){this.component_defaults=[this.Viewer]},init:function(options){var t=this;$.when.apply($,this.loading).always(function(){$.extend(!0,t.options,options),$(window).on("popstate",function(e){var state=e.originalEvent.state;if(t.util.in_obj(state,["item","viewer"]))return t.get_viewer(state.viewer).history_handle(e),e.preventDefault()}),t.init_items()})},can_make_default_component:function(type){return-1!==$.inArray(type,this.component_defaults)},is_component:function(comp){return this.util.is_class(comp,this.Component)},get_components:function(type){var ret={};if(this.is_component(type)){var coll=type.prototype._slug+"s";coll in this.cache||(this.cache[coll]={}),ret=this.cache[coll]}return ret},get_component:function(type,id){var ret=null;if(!this.util.is_func(type))return ret;this.util.is_string(id)||(id=null);var coll=this.get_components(type);if(this.util.is_obj(coll)){var tid=this.util.is_string(id)?id:this.util.add_prefix("default");tid in coll&&(ret=coll[tid])}return this.util.is_empty(ret)&&(this.util.is_string(id)||this.can_make_default_component(type))&&(ret=this.add_component(type,id)),ret},add_component:function(type,id,options){if(!this.util.is_func(type))return!1;if(this.util.is_empty(id)&&!this.can_make_default_component(type))return!1;var ret=null;this.util.is_empty(id)&&(id=this.util.add_prefix("default")),this.util.is_obj(options)||(options={});var m="component"!==type.prototype._slug?"add_"+type.prototype._slug:null;if(ret=!this.util.is_empty(m)&&m in this&&this.util.is_func(this[m])?this[m](id,options):new type(id,options),this.util.is_type(ret,type)){var coll=this.get_components(type);switch($.type(coll)){case"object":coll[id]=ret;break;case"array":coll.push(ret)}}else ret=null;return ret},add_component_temp:function(type){var ret=null;return this.is_component(type)&&(ret=new type(""),this.component_temps[ret._slug]=ret),ret},get_component_temp:function(type){return this.has_component_temp(type)?this.component_temps[type.prototype._slug]:this.add_component_temp(type)},has_component_temp:function(type){return!!(this.is_component(type)&&type.prototype._slug in this.component_temps)},get_options:function(opts){var ret={};if(this.util.is_string(opts)&&(opts=[opts]),!this.util.is_array(opts))return ret;for(var x=0;x<opts.length;x++)opts[x]in this.options&&(ret[opts[x]]=this.options[opts[x]]);return ret},get_option:function(opt,def){var ret=this.get_options(opt);return ret=this.util.is_obj(ret)&&opt in ret?ret[opt]:this.util.is_set(def)?def:null},add_viewer:function(id,options){var v=new this.Viewer(id,options);return this.get_viewers()[v.get_id()]=v},get_viewers:function(){return this.get_components(this.Viewer)},has_viewer:function(v){return!!(this.util.is_string(v)&&v in this.get_viewers())},get_viewer:function(v){return this.has_viewer(v)||(v=this.util.add_prefix("default"),this.has_viewer(v)||(v=(v=this.add_viewer(v)).get_id())),this.get_viewers()[v]},init_items:function(){var t=this,sel=this.util.format('a[href][%s="%s"]',this.util.get_attribute("active"),1);$(document).on("click",sel,null,function(){var ret=t.show_item(this);return t.util.is_bool(ret)||(ret=!0),!ret})},get_items:function(){return this.get_components(this.Content_Item)},get_item:function(ref){if(this.util.is_type(ref,this.Content_Item))return ref;var item=null;if(this.util.in_obj(ref,"nodeType")){var key=this.get_component_temp(this.Content_Item).get_data_key();item=$(ref).data(key)}else if(this.util.is_string(ref,!1)){var items=this.get_items();ref in items&&(item=items[ref])}return this.util.is_instance(item,this.Content_Item)||(item=this.add_item(ref)),item},add_item:function(el){return new this.Content_Item(el)},show_item:function(el){return this.get_item(el).show()},save_item:function(item){return this.util.is_instance(item,this.Content_Item)?this.get_items()[item.get_id()]=item:item},get_content_handlers:function(){return this.get_components(this.Content_Handler)},get_content_handler:function(item){var type=this.util.is_instance(item,this.Content_Item)?item.get_attribute("type",""):item.toString(),types=this.get_content_handlers();return type in types?types[type]:null},extend_content_handler:function(id,attr){var hdl=null;if(!this.util.is_string(id)||!this.util.is_obj(attr))return hdl;null===(hdl=this.get_content_handler(id))?this.get_content_handlers()[id]=hdl=new this.Content_Handler(id,attr):hdl.set_attributes(attr);return this.util.in_obj(attr,"styles")&&this.load_styles(attr.styles),hdl},add_group:function(g,attrs){return g=new this.Group(g,attrs),this.get_groups()[g.get_id()]=g},get_groups:function(){return this.get_components(this.Group)},get_group:function(g){return this.has_group(g)?this.get_groups()[g]:this.add_group(g)},has_group:function(g){return this.util.is_string(g)&&g in this.get_groups()},extend_theme:function(id,attr){if(!this.util.is_string(id))return!1;var dfr=$.Deferred();this.loading.push(dfr);var model=this.get_theme_model(id);return this.util.is_empty(model)&&(model=this.save_theme_model({parent:null,id:id})),this.util.is_obj(attr)&&("id"in attr&&delete attr.id,$.extend(model,attr)),this.util.in_obj(attr,"styles")&&this.load_styles(attr.styles),this.util.is_obj(model.parent)||(model.parent=this.get_theme_model(model.parent)),dfr.resolve(),model},get_theme_models:function(){return this.Theme.prototype._models},get_theme_model:function(id){var ms=this.get_theme_models();return this.util.in_obj(ms,id)?ms[id]:{}},save_theme_model:function(model){return this.util.in_obj(model,"id")&&this.util.is_string(model.id)&&(this.get_theme_models()[model.id]=model),model},extend_template_tag_handler:function(id,attr){if(!this.util.is_string(id)||!this.util.is_obj(attr))return!1;var hdl,hdls=this.get_template_tag_handlers();return this.util.in_obj(hdls,id)?(hdl=hdls[id]).set_attributes(attr):hdls[(hdl=new this.Template_Tag_Handler(id,attr)).get_id()]=hdl,this.util.in_obj(attr,"styles")&&this.load_styles(attr.styles),this.util.in_obj(attr,"_hooks")&&attr._hooks.call(hdl),hdl},get_template_tag_handlers:function(){return this.Template_Tag.prototype.handlers},get_template_tag_handler:function(id){var handlers=this.get_template_tag_handlers();return this.util.in_obj(handlers,id)?handlers[id]:null},load_styles:function(styles){if(this.util.is_array(styles)){for(var style,out=[],x=0;x<styles.length;x++)style=styles[x],this.util.in_obj(style,"uri")&&this.util.is_string(style.uri)&&out.push('<link rel="stylesheet" type="text/css" href="'+style.uri+'" />');$("head").append(out.join(""))}}},Component={_slug:"component",_ns:null,_refs:{},_reciprocal:!1,_dom:null,_attributes:!1,_attr_default:{},_attr_default_parsed:!1,_attr_init:null,_attr_map:{},_events:{},_status:null,_id:"",_c:function(id,attributes){this._set_id(id),this.util.is_obj(attributes)&&(this._attr_init=attributes),this._hooks()},_set_parent:function(){this._super(View)},_hooks:function(){},_set_id:function(id){return this.util.is_empty(this._id)&&(this._id=this.util.is_string(id)?id:this.util.guid()),this._id},get_id:function(ns){var id=this._id;return this.util.is_bool(ns)&&ns&&(id=this.add_ns(id)),id},get_ns:function(){return null===this._ns&&(this._ns=this.util.add_prefix(this._slug)),this._ns},add_ns:function(val){return this.util.is_string(val)?this.get_ns()+"_"+val:""},get_status:function(id,raw){var ret=!1;return this.util.in_obj(this._status,id)&&(ret=raw?this._status[id]:!!this._status[id]),ret},set_status:function(id,val){return this.util.is_string(id)?(this.util.is_set(val)||(val=!0),this.util.is_obj(this._status,!1)||(this._status={}),this._status[id]=val):this.util.is_set(val)||(val=!1),val},get_controller:function(){return this.get_parent()},has_reference:function(ref){return!!(this.util.is_string(ref)&&ref in this&&ref in this.get_references())},get_references:function(){return this._refs},get_reference:function(ref){return this.has_reference(ref)?this._refs[ref]:null},get_component:function(cname,options){var c=null;if(!this.has_reference(cname))return c;options=$.extend({},{check_attr:!0,get_default:!1},options);var ctype=this.get_reference(cname);return this.util.is_type(this[cname],ctype)?this[cname]:(c=this[cname]=null,options.check_attr&&(c=this.get_attribute(cname),this.util.is_empty(c)||(c=this.set_component(cname,c))),this.util.is_empty(c)&&options.get_default&&(c=this.get_controller().get_component(ctype)),c)},set_component:function(name,ref,validate){if(!this.has_reference(name))return null;if(this.util.is_empty(ref))ref=null;else{var ctype=this.get_reference(name);this.util.is_string(ref,!1)&&(ref=this.get_controller().get_component(ctype,ref)),this.util.is_type(ref,ctype)&&(!this.util.is_func(validate)||validate.call(this,ref))||(ref=null)}return this[name]=ref,this[name]},clear_component:function(name){this.set_component(name,null)},init_attributes:function(force){if(this.util.is_bool(force)||(force=!1),force||!this.util.is_obj(this._attributes)){var a=this._attributes={};$.extend(a,this.init_default_attributes()),this.util.is_obj(this._attr_init)&&$.extend(a,this._attr_init),$.extend(a,this.get_dom_attributes())}},init_default_attributes:function(){if(!this._attr_default_parsed&&this.util.is_obj(this._attr_map)){var opts=this.get_controller().get_options(this.util.obj_keys(this._attr_map));if(this.util.is_obj(opts)){for(var opt in this._attr_map)opt in opts&&null!==this._attr_map[opt]&&(opts[this._attr_map[opt]]=opts[opt],delete opts[opt]);$.extend(!0,this._attr_default,opts)}this._attr_default_parsed=!0}return this._attr_default},get_dom_attributes:function(){var attrs={},el=this.dom_get(null,{init:!1});if(0<el.length){var attrs_full=$(el).get(0).attributes;if(this.util.is_obj(attrs_full)){var attr_key,attr_prefix=this.util.get_attribute();$.each(attrs_full,function(idx,attr){if(-1===attr.name.indexOf(attr_prefix))return!0;attr_key=attr.name.substr(attr_prefix.length+1),attrs[attr_key]=attr.value})}}return attrs},get_attributes:function(){return this.init_attributes(),this._attributes},get_attribute:function(key,def,enforce_type){if(this.util.is_set(def)||(def=null),!this.util.is_string(key))return def;this.util.is_bool(enforce_type)||(enforce_type=!0);var ret=this.has_attribute(key)?this.get_attributes()[key]:def;return enforce_type&&ret!==def&&null!==def&&!this.util.is_type(ret,$.type(def),!1)&&(this.util.is_scalar(def,!1)&&this.util.is_scalar(ret,!1)?this.util.is_string(def,!1)?ret=ret.toString():this.util.is_num(def,!1)&&!this.util.is_num(ret,!1)?(ret=this.util.is_int(def,!1)?parseInt(ret):parseFloat(ret),this.util.is_num(ret,!1)||(ret=def)):ret=this.util.is_bool(def,!1)?this.util.is_string(ret)||this.util.is_num(ret):def:ret=def),ret},call_attribute:function(attr,args){return attr=this.get_attribute(attr),this.util.is_func(attr)&&(args=Array.prototype.slice.call(arguments,1),attr=attr.apply(this,args)),attr},has_attribute:function(key){return this.util.is_string(key)&&key in this.get_attributes()},set_attributes:function(attributes,full){this.util.is_bool(full)||(full=!1),this.init_attributes(full),this.util.is_obj(attributes)&&$.extend(this._attributes,attributes)},set_attribute:function(key,val){return this.util.is_string(key)&&this.util.is_set(val)&&(this.get_attributes()[key]=val),val},dom_get_selector:function(element){return this.util.is_string(element)?"."+this.add_ns(element):""},dom_get_attribute:function(){return this.util.get_attribute(this._slug)},dom_set:function(el){return(el=$(el)).data(this.get_data_key(),this),this._reciprocal&&(this._dom=el),el},dom_get:function(element,options){var opts_default={init:!0,put:!1};(options=this.util.is_obj(options)?$.extend({},opts_default,options):opts_default).init&&!this.get_status("dom_init")&&(this.set_status("dom_init"),this.dom_init());var ret=this._dom;if(ret&&this.util.is_string(element)){var ch=$(ret).find(this.dom_get_selector(element));ch.length?ret=ch:!0!==options.put&&!this.util.is_obj(options.put)||(ret=this.dom_put(element,options.put))}return $(ret)},dom_init:function(){},dom_put:function(element,content){var r=null;if(!this.dom_has()||!this.util.is_string(element))return $(r);var strip=["tag","content","success"],options={tag:"div",content:"",class:this.add_ns(element)};this.util.is_empty(content)||(this.util.is_type(content,jQuery,!1)||this.util.is_string(content,!1)?options.content=content:this.util.is_obj(content,!1)&&$.extend(options,content));for(var attrs=$.extend({},options),x=0;x<strip.length;x++)delete attrs[strip[x]];var d=this.dom_get();return(r=$(this.dom_get_selector(element),d)).length||(r=$(this.util.format("<%s />",options.tag),attrs).appendTo(d)).length&&this.util.is_method(options,"success")&&options.success.call(r,r),$(r).append(options.content),$(r)},dom_has:function(){return!!this.dom_get().length},get_data_key:function(){return this.get_ns()},on:function(event,fn,options){if(!this.util.is_string(event)||!this.util.is_func(fn)){var t=this,args=Array.prototype.slice.call(arguments,1);return this.util.is_array(event)?$.each(event,function(idx,val){t.on.apply(t,[val].concat(args))}):this.util.is_obj(event)&&$.each(event,function(ev,hdl){t.on.apply(t,[ev,hdl].concat(args))}),this}this.util.is_obj(options,!1)||(options={}),options=$.extend({},{clear:!1},options),this.util.is_obj(this._events,!1)||(this._events={});var es=this._events;return event in es&&this.util.is_obj(es[event],!1)&&!options.clear||(es[event]=[]),es[event].push(fn),this},trigger:function(event,data){var dfr=$.Deferred(),dfrs=[],t=this;if(this.util.is_array(event))return $.each(event,function(idx,val){dfrs.push(t.trigger(val,data))}),$.when.apply(t,dfrs).done(function(){dfr.resolve()}),dfr.promise();if(!(this.util.is_string(event)&&event in this._events))return dfr.resolve(),dfr.promise();var ev={type:event,data:null};return this.util.is_set(data)&&(ev.data=data),$.each(this._events[event],function(idx,fn){dfrs.push(fn.call(t,ev,t))}),$.when.apply(this,dfrs).done(function(){dfr.resolve()}),dfr.promise()}};View.Component=Component=SLB.Class.extend(Component);var Viewer={_slug:"viewer",_refs:{item:"Content_Item",theme:"Theme"},_reciprocal:!0,_attr_default:{loop:!0,animate:!0,autofit:!0,overlay_enabled:!0,overlay_opacity:"0.8",title_default:!1,container:null,slideshow_enabled:!0,slideshow_autostart:!1,slideshow_duration:2,slideshow_active:!1,slideshow_timer:null,labels:{close:"close",nav_prev:"« prev",nav_next:"next »",slideshow_start:"start slideshow",slideshow_stop:"stop slideshow",group_status:"Image %current% of %total%",loading:"loading"}},_attr_map:{theme:null,group_loop:"loop",ui_autofit:"autofit",ui_animate:"animate",ui_overlay_opacity:"overlay_opacity",ui_labels:"labels",ui_title_default:"title_default",slideshow_enabled:null,slideshow_autostart:null,slideshow_duration:null},item:null,item_queued:null,theme:null,item_working:null,active:!1,init:!1,open:!1,loading:!1,_hooks:function(){var t=this;this.on(["item-prev","item-next"],function(){t.trigger("item-change")}).on(["close","item-change"],function(){t.unload().done(function(){t.unlock()})})},get_item:function(){return this.get_component("item")},set_item:function(item){this.clear_item(!1);var i=this.set_component("item",item,function(item){return item.has_type()});return!this.util.is_empty(i)},clear_item:function(full){this.util.is_bool(full)||(full=!0);var item=this.get_item();item&&item.reset(),full&&this.clear_component("item")},get_theme:function(){var ret=this.get_component("theme",{check_attr:!1});return this.util.is_empty(ret)&&(ret=this.set_component("theme",new View.Theme(this))),ret},set_theme:function(theme){this.set_component("theme",theme)},lock:function(){return this.set_status("item_working",$.Deferred())},get_lock:function(simple,full){this.util.is_bool(simple)||(simple=!1),this.util.is_bool(full)||(full=!1);var s="item_working";if(simple)return this.get_status(s);var r=this.get_status(s,!0);return this.util.is_promise(r)||(r=this.lock()),full?r:r.promise()},is_locked:function(){return this.get_lock(!0)},unlock:function(){return this.get_lock(!1,!0).resolve()},set_active:function(mode){return this.util.is_bool(mode)||(mode=!0),this.set_status("active",mode)},is_active:function(){return this.get_status("active")},set_loading:function(mode){var dfr=$.Deferred();this.util.is_bool(mode)||(mode=!0),this.loading=mode,this.slideshow_active()&&this.slideshow_pause(mode);var m=mode?"addClass":"removeClass";return $(this.dom_get())[m]("loading"),mode?this.get_theme().transition("load").always(function(){dfr.resolve()}):dfr.resolve(),dfr.promise()},unset_loading:function(){return this.set_loading(!1)},get_loading:function(){return!!this.util.is_bool(this.loading)&&this.loading},is_loading:function(){return this.get_loading()},show:function(item){this.item_queued=item;var vt="theme_valid",valid=!0;if(this.has_attribute(vt)?valid=this.get_attribute(vt,!0):(valid=!(!this.get_theme()||""===this.get_theme().get_template().get_layout(!1)),this.set_attribute(vt,valid)),!valid)return this.close(),!1;function fin(){if(v.lock(),v.set_status("show_deferred",!1),!v.set_item(v.item_queued))return v.close(),!1;v.history_add(),v.set_active(),v.render()}var v=this;this.is_locked()?this.get_status("show_deferred")||(this.set_status("show_deferred"),this.get_lock().always(function(){fin()})):fin()},history_handle:function(e){var state=e.originalEvent.state;if(this.util.is_string(state.item,!1))this.get_controller().get_item(state.item).show({event:e}),this.trigger("item-change");else{var count=this.history_get(!0);this.history_set(0),-1!==count&&this.close()}},history_get:function(full){return this.get_status("history_count",full)},history_set:function(val){return this.set_status("history_count",val)},history_add:function(){if(!history.pushState)return!1;var item=this.get_item(),opts=item.get_attribute("options_show"),count=this.history_get()?this.history_get(!0):0;if(this.util.in_obj(opts,"event")){var e=opts.event.originalEvent;this.util.in_obj(e,"state")&&this.util.in_obj(e.state,"count")&&(count=e.state.count)}else{var state={viewer:this.get_id(),item:null,count:count};count||history.replaceState(state,null),state.item=this.get_controller().save_item(item).get_id(),state.count=++count,history.pushState(state,"")}this.history_set(count)},history_reset:function(){var count=this.history_get(!0);count&&(this.history_set(-1),history.go(-1*count))},is_open:function(){return"none"!==this.dom_get().css("display")},render:function(){var v=this,thm=this.get_theme();v.dom_prep(),this.get_status("render-events")||(this.set_status("render-events"),thm.on("render-loading",function(ev,thm){var dfr=$.Deferred();if(!v.is_active())return dfr.reject(),dfr.promise();function set_pos(){v.dom_get().css("top",$(window).scrollTop())}function always(){v.set_loading().always(function(){dfr.resolve()})}return v.is_open()?thm.transition("unload").fail(function(){set_pos(),thm.dom_get_tag("item","content").attr("style","")}).always(always):thm.transition("open").always(function(){always(),v.events_open(),v.open=!0}).fail(function(){set_pos(),v.get_overlay().show(),v.dom_get().show()}),dfr.promise()}).on("render-complete",function(ev,thm){if(!v.is_active())return!1;var d=v.dom_get(),classes=["item_single","item_multi"],ms=["addClass","removeClass"];v.get_item().get_group().is_single()||ms.reverse(),$.each(ms,function(idx,val){d[val](classes[idx])}),v.events_complete(),thm.transition("complete").fail(function(){if(v.get_attribute("autofit",!0)){var dims=$.extend({display:"inline-block"},thm.get_item_dimensions());thm.dom_get_tag("item","content").css(dims)}}).always(function(){v.unset_loading(),v.trigger("render-complete"),v.init=!0})})),thm.render()},dom_get_container:function(){var sel=this.get_attribute("container");this.util.is_empty(sel)&&(sel="#"+this.add_ns("wrap"));var c=$(sel);if(!c.length){var id=0===sel.indexOf("#")?sel.substr(1):sel;c=$("<div />",{id:id}).appendTo("body")}return c},dom_init:function(){var d=this.dom_set($("<div/>",{id:this.get_id(!0),class:this.get_ns()})).appendTo(this.dom_get_container()).hide(),thm=this.get_theme();d.addClass(thm.get_classes(" "));var v=this;this.get_status("render-init")||(this.set_status("render-init"),thm.on("render-init",function(ev){v.dom_put("layout",ev.data)})),thm.render(!0)},dom_prep:function(mode){var m=this.util.is_bool(mode)&&!mode?"removeClass":"addClass";$("html")[m](this.util.add_prefix("overlay"))},dom_restore:function(){this.dom_prep(!1)},get_layout:function(){return this.dom_get("layout",{put:{success:function(){$(this).hide()}}})},animation_enabled:function(){return this.get_attribute("animate",!0)},overlay_enabled:function(){var ov=this.get_attribute("overlay_enabled");return!!this.util.is_bool(ov)&&ov},get_overlay:function(){var o=null,v=this;return this.overlay_enabled()&&(o=this.dom_get("overlay",{put:{success:function(){$(this).hide().css("opacity",v.get_attribute("overlay_opacity"))}}})),$(o)},unload:function(){var dfr=$.Deferred();return this.get_theme().dom_get_tag("item").text(""),dfr.resolve(),dfr.promise()},reset:function(){this.dom_get().hide(),this.dom_restore(),this.history_reset(),this.clear_item(),this.set_active(!1),this.set_loading(!1),this.slideshow_stop(),this.keys_disable(),this.unlock()},get_labels:function(){return this.get_attribute("labels",{})},get_label:function(name){var lbls=this.get_labels();return name in lbls?lbls[name]:""},events_open:function(){if(this.keys_enable(),this.open)return!1;var l=this.get_layout();l.children().click(function(ev){ev.stopPropagation()});function close(){v.close()}var v=this;l.click(close),this.get_overlay().click(close),this.trigger("events-open")},events_complete:function(){if(this.init)return!1;this.trigger("events-complete")},keys_enable:function(mode){this.util.is_bool(mode)||(mode=!0);var e=["keyup",this.util.get_prefix()].join("."),v=this;mode?$(document).on(e,function(ev){return v.keys_control(ev)}):$(document).off(e)},keys_disable:function(){this.keys_enable(!1)},keys_control:function(ev){var handlers={27:this.close,37:this.item_prev,39:this.item_next};if("rtl"===document.documentElement.getAttribute("dir")&&(handlers[37]=this.item_next,handlers[39]=this.item_prev),ev.which in handlers)return handlers[ev.which].call(this),!1},slideshow_enabled:function(){var o=this.get_attribute("slideshow_enabled");return!(!(this.util.is_bool(o)&&o&&this.get_item())||this.get_item().get_group().is_single())},slideshow_active:function(){return!(!this.slideshow_enabled()||!(this.get_attribute("slideshow_active")||!this.init&&this.get_attribute("slideshow_autostart")))},slideshow_clear_timer:function(){clearInterval(this.get_attribute("slideshow_timer"))},slideshow_set_timer:function(callback){this.set_attribute("slideshow_timer",setInterval(callback,1e3*this.get_attribute("slideshow_duration")))},slideshow_start:function(){if(!this.slideshow_enabled())return!1;this.set_attribute("slideshow_active",!0),this.dom_get().addClass("slideshow_active"),this.slideshow_clear_timer();var v=this;this.slideshow_set_timer(function(){v.slideshow_pause(),v.item_next()}),this.trigger("slideshow-start")},slideshow_stop:function(full){this.util.is_bool(full)||(full=!0),full&&(this.set_attribute("slideshow_active",!1),this.dom_get().removeClass("slideshow_active")),this.slideshow_clear_timer(),this.trigger("slideshow-stop")},slideshow_toggle:function(){if(!this.slideshow_enabled())return!1;this.slideshow_active()?this.slideshow_stop():this.slideshow_start(),this.trigger("slideshow-toggle")},slideshow_pause:function(mode){this.util.is_bool(mode)||(mode=!0),this.slideshow_active()&&(mode?this.slideshow_stop(!1):this.slideshow_start()),this.trigger("slideshow-pause")},slideshow_resume:function(){this.slideshow_pause(!1)},item_next:function(){var g=this.get_item().get_group(!0),v=this,ev="item-next",st=["events","viewer",ev].join("_");g.get_status(st)||(g.set_status(st),g.on(ev,function(e){v.trigger(e.type)})),g.show_next()},item_prev:function(){var g=this.get_item().get_group(!0),v=this,ev="item-prev",st=["events","viewer",ev].join("_");g.get_status(st)||(g.set_status(st),g.on(ev,function(){v.trigger(ev)})),g.show_prev()},close:function(){this.set_active(!1);var v=this,thm=this.get_theme();return thm.transition("unload").always(function(){thm.transition("close",!0).always(function(){v.reset(),v.trigger("close")})}).fail(function(){thm.dom_get_tag("item","content").attr("style","")}),!1}};View.Viewer=Component.extend(Viewer);var Group={_slug:"group",_reciprocal:!0,_refs:{current:"Content_Item"},current:null,selector:null,_hooks:function(){var t=this;this.on(["item-prev","item-next"],function(){t.trigger("item-change")})},get_selector:function(){return this.util.is_empty(this.selector)&&(this.selector=this.util.format('a[%s="%s"]',this.dom_get_attribute(),this.get_id())),this.selector},get_items:function(){var items=$(this.get_selector());return 0===items.length&&this.has_current()&&(items=this.get_current().dom_get()),items},get_item:function(idx){this.util.is_int(idx)||(idx=0);var items=this.get_items(),max=this.get_size()-1;return max<idx&&(idx=max),items.get(idx)},get_pos:function(item){return this.util.is_empty(item)&&(item=this.get_current()),this.util.is_type(item,View.Content_Item)?this.get_items().index(item.dom_get()):-1},has_current:function(){return!this.util.is_empty(this.get_current())},get_current:function(){return null===this.current||this.util.is_type(this.current,View.Content_Item)||(this.current=null),this.current},set_current:function(item){this.util.is_type(item,View.Content_Item)&&(this.current=item)},get_next:function(item){if(this.util.is_type(item,View.Content_Item)||(item=this.get_current()),1===this.get_size())return item;var next=null,pos=this.get_pos(item);return-1!==pos&&(0===(pos=pos+1<this.get_size()?pos+1:0)&&!item.get_viewer().get_attribute("loop")||(next=this.get_item(pos))),next},get_prev:function(item){if(this.util.is_type(item,View.Content_Item)||(item=this.get_current()),1===this.get_size())return item;var prev=null,pos=this.get_pos(item);return-1===pos||0===pos&&!item.get_viewer().get_attribute("loop")||(0===pos&&(pos=this.get_size()),pos-=1,prev=this.get_item(pos)),prev},show_next:function(item){if(1<this.get_size()){var next=this.get_next(item);next||(this.util.is_type(item,View.Content_Item)||(item=this.get_current()),item.get_viewer().close());var i=this.get_controller().get_item(next);this.set_current(i),i.show(),this.trigger("item-next")}},show_prev:function(item){if(1<this.get_size()){var prev=this.get_prev(item);prev||(this.util.is_type(item,View.Content_Item)||(item=this.get_current()),item.get_viewer().close());var i=this.get_controller().get_item(prev);this.set_current(i),i.show(),this.trigger("item-prev")}},get_size:function(){return this.get_items().length},is_single:function(){return 1===this.get_size()}};View.Group=Component.extend(Group);var Content_Handler={_slug:"content_handler",_refs:{item:"Content_Item"},item:null,template:"",has_item:function(){return!this.util.is_empty(this.get_item())},get_item:function(){return this.get_component("item")},set_item:function(item){return this.set_component("item",item)},clear_item:function(){this.clear_component("item")},match:function(item){var m=this.get_attribute("match");if(!this.util.is_empty(m)){if(this.util.is_string(m)&&(m=new RegExp(m,"i"),this.set_attribute("match",m)),this.util.is_type(m,RegExp))return m.test(item.get_uri());if(this.util.is_func(m))return!!m.call(this,item)}return!1},load:function(item){var dfr=$.Deferred();return null===this.call_attribute("load",item,dfr)&&dfr.resolve(),dfr.promise()},render:function(item){var dfr=$.Deferred();return this.call_attribute("render",item,dfr),dfr.promise()}};View.Content_Handler=Component.extend(Content_Handler);var Content_Item={_slug:"content_item",_reciprocal:!0,_refs:{viewer:"Viewer",group:"Group",type:"Content_Handler"},_attr_default:{source:null,permalink:null,dimensions:null,title:"",group:null,internal:!1,output:null},group:null,viewer:null,type:null,data:null,loaded:null,_c:function(el){this.dom_set(el),this._super()},init_default_attributes:function(){this._super();var d=this.dom_get(),key=d.attr(this.util.get_attribute("asset"))||null,assets=this.get_controller().assets||null;if(this.util.is_string(key)){var attrs=[{},this._attr_default,{permalink:d.attr("href")}];if(this.util.is_obj(assets)){var t=this;attrs.push(function(key){var ret={};return key in assets&&t.util.is_obj(assets[key])&&(ret=assets[key]),ret}(key))}this._attr_default=$.extend.apply(this,attrs)}return this._attr_default},get_output:function(){var dfr=$.Deferred(),ret=this.get_attribute("output");if(this.util.is_string(ret))dfr.resolve(ret);else if(this.has_type()){var type=this.get_type(),item=this;type.render(this).done(function(output){item.set_output(output),dfr.resolve(output)})}else dfr.resolve("");return dfr.promise()},set_output:function(out){this.util.is_string(out,!1)&&this.set_attribute("output",out)},get_content:function(){return this.get_output()},get_uri:function(mode){-1===$.inArray(mode,["source","permalink"])&&(mode="source");var ret=this.get_attribute(mode);return this.util.is_string(ret)||(ret="source"===mode?this.get_attribute("permalink"):""),ret=ret.replace(/&(#38|amp);/,"&")},get_title:function(){if(this.has_attribute("title_cached"))return this.get_attribute("title_cached","");function validate(title){return"string"!=typeof title||""===title.trim()?"":(title=title.trim(),t.get_viewer().get_attribute("title_default")||title===t.get_title_default()&&(title=""),title)}var title="",dom=this.dom_get(),t=this;if(dom.length&&(title=(title=(title=dom.attr("title"))||dom.closest("figure").find("figcaption").first().html())||dom.closest("figure").find(".wp-caption-text").first().html()),!title)for(var props=["caption","title"],x=0;x<props.length&&(title=validate(this.get_attribute(props[x],"")),this.util.is_empty(title));x++);return!title&&dom.length&&(title=(title=validate(dom.find("img").first().attr("alt")))||validate(dom.get(0).innerText.trim())),title=validate(title),this.set_attribute("title_cached",title),title},get_title_default:function(){var val="",prop="title_default";if(this.has_attribute(prop))val=this.get_attribute(prop);else{var f=this.get_uri("source"),i=f.lastIndexOf("/");-1!==i&&-1!==(i=(f=f.substr(i+1)).lastIndexOf("."))&&(f=f.substr(0,i)),val=this.set_attribute(prop,f)}return val},get_dimensions:function(){return $.extend({width:0,height:0},this.get_attribute("dimensions"),{})},set_data:function(data){this.data=data},get_data:function(){return this.data},gallery_type:function(){var ret=null,types={wp:".gallery-icon",ngg:".ngg-gallery-thumbnail"},dom=this.dom_get();for(var type in types)if(0<dom.parent(types[type]).length){ret=type;break}return ret},in_gallery:function(gType){var type=this.gallery_type();return null!==type&&(!this.util.is_string(gType)||gType===type)},get_viewer:function(){return this.get_component("viewer",{get_default:!0})},set_viewer:function(v){return this.set_component("viewer",v)},get_group:function(set_current){var g=this.get_component("group");return g||(g=this.set_component("group",new View.Group),set_current=!0),set_current&&g.set_current(this),g},set_group:function(g){this.util.is_string(g)&&(g=this.get_controller().get_group(g)),this.group=!!this.util.is_type(g,View.Group)&&g},get_type:function(){var t=this.get_component("type",{check_attr:!1});return t=t||this.set_type(this.get_controller().get_content_handler(this))},set_type:function(type){return this.set_component("type",type)},has_type:function(){return!this.util.is_empty(this.get_type())},show:function(options){if(!this.has_type())return!1;this.set_attribute("options_show",options);var v=this.get_viewer();return this.load(),v.show(this)},load:function(){return this.util.is_promise(this.loaded)||(this.loaded=this.get_type().load(this)),this.loaded.promise()},reset:function(){this.set_attribute("options_show",null)}};View.Content_Item=Component.extend(Content_Item);var Modeled_Component={_slug:"modeled_component",get_attribute:function(key,def,check_model,enforce_type){if(!this.util.is_string(key))return this._super(key,def,enforce_type);this.util.is_bool(check_model)||(check_model=!0);var ret=null;if(check_model){var m=this.get_ancestor(key,!1);this.util.in_obj(m,key)&&(ret=m[key])}return null===ret&&(ret=this._super(key,def,enforce_type)),ret},get_attribute_recursive:function(key,def,enforce_type){var ret=this.get_attribute(key,def,!0,enforce_type);if(this.util.is_obj(ret)){var models=this.get_ancestors(!1);ret=[ret];var t=this;$.each(models,function(idx,model){key in model&&t.util.is_obj(model[key])&&ret.push(model[key])}),ret.push({}),ret=$.extend.apply($,ret.reverse())}return ret},set_attribute:function(key,val,use_model){if(!this.util.is_string(key)||!this.util.is_set(val))return!1;(this.util.is_bool(use_model)||this.util.is_obj(use_model)||(use_model=!0),use_model)?(this.util.is_obj(use_model)?use_model:this.get_model())[key]=val:this._super(key,val);return val},get_model:function(){var m=this.get_attribute("model",null,!1);return this.util.is_obj(m)||(m={},this.set_attribute("model",m,!1)),m},has_model:function(){return!this.util.is_empty(this.get_model())},in_model:function(key){return!!this.util.in_obj(this.get_model(),key)},get_ancestors:function(inc_current){for(var ret=[],m=this.get_model();this.util.is_obj(m);)ret.push(m),m=this.util.in_obj(m,"parent")&&this.util.is_obj(m.parent)?m.parent:null;return inc_current||ret.shift(),ret},get_ancestor:function(attr,safe_mode){if(!this.util.is_string(attr))return!1;this.util.is_bool(safe_mode)||(safe_mode=!0);for(var mcurr=this.get_model(),m=mcurr,found=!1;this.util.is_obj(m);){if(this.util.in_obj(m,attr)&&!this.util.is_empty(m[attr])){found=!0;break}m=this.util.in_obj(m,"parent")?m.parent:null}return found||(safe_mode?(this.util.is_empty(m)&&(m=mcurr),this.util.in_obj(m,attr)||(m[attr]=null)):m=null),m}};Modeled_Component=Component.extend(Modeled_Component);var Theme={_slug:"theme",_refs:{viewer:"Viewer",template:"Template"},_models:{},_attr_default:{template:null,model:null},viewer:null,template:null,_c:function(id,attributes,viewer){1===arguments.length&&this.util.is_type(id,View.Viewer)&&(viewer=id,id=null),this._super(id,attributes),this.set_viewer(viewer),this.set_model(id)},get_viewer:function(){return this.get_component("viewer",{check_attr:!1,get_default:!0})},set_viewer:function(v){return this.set_component("viewer",v)},get_template:function(){var ret=this.get_component("template");if(this.util.is_empty(ret)){var attr={theme:this,model:this.get_model()};ret=this.set_component("template",new View.Template(attr))}return ret},get_tags:function(name,prop){return this.get_template().get_tags(name,prop)},dom_get_tag:function(tag,prop){return $(this.get_template().dom_get_tag(tag,prop))},get_tag_selector:function(name,prop){return this.get_template().get_tag_selector(name,prop)},get_models:function(){return this._models},get_model:function(id){var ret=null;if(!this.util.is_set(id)&&this.util.is_obj(this.get_attribute("model",null,!1)))ret=this._super();else{var models=this.get_models();this.util.is_string(id)||(id=this.get_controller().get_option("theme_default")),this.util.in_obj(models,id)||(id=$.map(models,function(v,key){return key})[0]),ret=models[id]}return ret},set_model:function(id){this.set_attribute("model",this.get_model(id),!1)},get_classes:function(rtype){var cls=[],thm=this,models=this.get_ancestors(!0);return $.each(models,function(idx,model){cls.push(thm.add_ns(model.id))}),this.util.is_string(rtype)&&(cls=cls.join(rtype)),cls},get_measurement:function(attr,def){var meas=null;if(!this.util.is_string(attr))return meas;this.util.is_obj(def,!1)||(def={});var attr_cache=this.util.format("%s_cache",attr),cache=this.get_attribute(attr_cache,{},!1),status="_status",item=this.get_viewer().get_item(),w=$(window);status in cache&&this.util.is_obj(cache._status)&&cache._status.width===w.width()&&cache._status.height===w.height()||(cache={}),this.util.is_empty(cache)&&(cache._status={width:w.width(),height:w.height(),index:[]});var pos=$.inArray(item,cache._status.index);return-1!==pos&&pos in cache&&(meas=cache[pos]),this.util.is_obj(meas)||(meas=this.call_attribute(attr),this.util.is_obj(meas)||(meas=this.get_measurement_default(attr))),meas=this.util.is_obj(meas)?$.extend({},def,meas):def,pos=cache._status.index.push(item)-1,cache[pos]=meas,this.set_attribute(attr_cache,cache,!1),$.extend({},meas)},get_measurement_default:function(attr){return this.util.is_string(attr)?(attr=this.util.format("get_%s_default",attr),this.util.in_obj(this,attr)?(attr=this[attr],this.util.is_func(attr)&&(attr=attr.call(this))):attr=null,attr):null},get_offset:function(){return this.get_measurement("offset",{width:0,height:0})},get_offset_default:function(){var offset={width:0,height:0},v=this.get_viewer(),vn=v.dom_get(),vc=vn.clone().attr("id","").css({visibility:"hidden",position:"absolute",top:""}).removeClass("loading").appendTo(vn.parent()),l=vc.find(v.dom_get_selector("layout"));if(l.length){l.find("*").css({width:"",height:"",display:""});var tags=this.get_tags("item","content");if(tags.length){var offset_item=v.get_item().get_dimensions();tags=$(l.find(tags[0].get_selector("full")).get(0)).css({width:offset_item.width,height:offset_item.height}),$.each(offset_item,function(key,val){offset[key]=-1*val})}offset.width+=l.width(),offset.height+=l.height(),$.each(offset,function(key,val){val<0&&(offset[key]=0)})}return vc.empty().remove(),offset},get_margin:function(){return this.get_measurement("margin",{width:0,height:0})},get_item_dimensions:function(){var v=this.get_viewer(),dims=v.get_item().get_dimensions();if(v.get_attribute("autofit",!1)){var margin=this.get_margin(),offset=this.get_offset();offset.height+=margin.height,offset.width+=margin.width;var max={width:$(window).width(),height:$(window).height()};max.width>offset.width&&(max.width-=offset.width),max.height>offset.height&&(max.height-=offset.height);var factor=Math.min(max.width/dims.width,max.height/dims.height);factor<1&&$.each(dims,function(key){dims[key]=Math.round(dims[key]*factor)})}return $.extend({},dims)},get_dimensions:function(){var dims=this.get_item_dimensions(),offset=this.get_offset();return $.each(dims,function(key){dims[key]+=offset[key]}),dims},get_breakpoints:function(){return this.get_attribute_recursive("breakpoints")},get_breakpoint:function(target){var ret=0;if(this.util.is_string(target)){var b=this.get_attribute_recursive("breakpoints");this.util.is_obj(b)&&target in b&&(ret=b[target])}return ret},render:function(init){var thm=this,tpl=this.get_template(),st="events_render";this.get_status(st)||(this.set_status(st),tpl.on(["render-init","render-loading","render-complete"],function(ev){return thm.trigger(ev.type,ev.data)})),tpl.render(init)},transition:function(event,clear_queue){var dfr=null,attr="transition",v=this.get_viewer(),fx_temp=null,anim_on=v.animation_enabled();if(v.get_attribute(attr,!0)&&this.util.is_string(event)){clear_queue&&v.get_layout().find("*").each(function(){for(var el=$(this);el.queue().length;)el.stop(!1,!0)});var trns,attr_set=[attr,"set"].join("_");if(this.get_attribute(attr_set))trns=this.get_attribute(attr,{});else{var models=this.get_ancestors(!0);trns=[],this.set_attribute(attr_set,!0);var thm=this;$.each(models,function(idx,model){attr in model&&thm.util.is_obj(model[attr])&&trns.push(model[attr])}),trns.push({}),trns=this.set_attribute(attr,$.extend.apply($,trns.reverse()))}this.util.is_method(trns,event)&&(anim_on||(fx_temp=$.fx.off,$.fx.off=!0),dfr=trns[event].call(this,v,$.Deferred()))}return this.util.is_promise(dfr)||(dfr=$.Deferred()).reject(),dfr.always(function(){null!==fx_temp&&($.fx.off=fx_temp)}),dfr.promise()}};View.Theme=Modeled_Component.extend(Theme);var Template={_slug:"template",_reciprocal:!0,_refs:{theme:"Theme"},_attr_default:{layout_uri:"",layout_raw:"",layout_parsed:"",tags:null,model:null},theme:null,_c:function(attributes){this._super("",attributes)},_hooks:function(){this.on("dom_init",function(ev){var tags=this.get_tags(null,null,!0),names=[],t=this;$.each(tags,function(idx,tag){var name=tag.get_name();-1===$.inArray(name,names)&&(names.push(name),tag.get_handler().trigger(ev.type,{template:t}))})})},get_theme:function(){return this.get_component("theme")},render:function(init){var v=this.get_theme().get_viewer();if(this.util.is_bool(init)||(init=!1),init)this.trigger("render-init",this.dom_get());else{if(!v.is_active())return!1;var item=v.get_item();if(!this.util.is_type(item,View.Content_Item))return v.close(),!1;if(v.is_active()&&this.has_tags()){var loading_promise=this.trigger("render-loading"),tpl=this,tags=this.get_tags(),tag_promises=[];$.when(item.load(),loading_promise).done(function(){return!!v.is_active()&&($.each(tags,function(idx,tag){if(!v.is_active())return!1;tag_promises.push(tag.render(item).done(function(r){if(!v.is_active())return!1;r.tag.dom_get().html(r.output)}))}),!!v.is_active()&&void $.when.apply($,tag_promises).done(function(){tpl.trigger("render-complete")}))})}}},get_layout:function(parsed){return this.util.is_bool(parsed)||(parsed=!0),parsed?this.parse_layout():this.get_attribute("layout_raw","")},parse_layout:function(){var a="layout_parsed",ret=this.get_attribute(a);return this.util.is_string(ret)||(ret=this.sanitize_layout(this.get_layout(!1)),ret=this.parse_tags(ret),this.set_attribute(a,ret)),ret},sanitize_layout:function(l){if(this.util.is_empty(l))return l;var rtype=this.util.is_string(l)?"string":null,dom=$(l),tag_temp=this.get_tag_temp(),cls=tag_temp.get_class(),cls_new=["x",cls].join("_");switch($(tag_temp.get_selector(),dom).each(function(){$(this).removeClass(cls).addClass(cls_new)}),rtype){case"string":l=dom=dom.wrap("<div />").parent().html();break;default:l=dom}return l},parse_tags:function(l){if(!this.util.is_string(l))return"";for(var match,re=/\{{2}\s*(\w.*?)\s*\}{2}/gim;match=re.exec(l);)l=l.substring(0,match.index)+this.get_tag_container(match[1])+l.substring(match.index+match[0].length);return l},get_tag_container:function(tag){var attr=this.get_tag_attribute();return this.util.format('<span %s="%s"></span>',attr,encodeURI(tag))},get_tag_attribute:function(){return this.get_tag_temp().dom_get_attribute()},get_tag:function(idx){var ret=null;if(this.has_tags()){var tags=this.get_tags();(!this.util.is_int(idx)||idx<0||idx>=tags.length)&&(idx=0),ret=tags[idx]}return ret},get_tags:function(name,prop,isolate){this.util.is_bool(isolate)||(isolate=!1);var a="tags",tags=this.get_attribute(a);if(!this.util.is_array(tags)){tags=[];var d=this.dom_get(),attr=this.get_tag_attribute(),nodes=$(d).find("["+attr+"]");$(nodes).each(function(){var el=$(this),tag=new View.Template_Tag(decodeURI(el.attr(attr)));tag.has_handler()&&(tags.push(tag),isolate||(tag.dom_set(el),el.addClass(tag.get_classes(" ")))),isolate||el.removeAttr(attr)}),isolate||this.set_attribute(a,tags,!1)}if(!this.util.is_empty(tags)&&this.util.is_string(name)){this.util.is_string(prop)||(prop=!1);for(var tags_filtered=[],tc=null,x=0;x<tags.length;x++)name===(tc=tags[x]).get_name()&&(prop&&prop!==tc.get_prop()||tags_filtered.push(tc));tags=tags_filtered}return this.util.is_array(tags,!1)?tags:[]},has_tags:function(){return 0<this.get_tags().length},get_tag_temp:function(){return this.get_controller().get_component_temp(View.Template_Tag)},get_tag_selector:function(name,prop){this.util.is_string(name)||(name=""),this.util.is_string(prop)||(prop="");var tag=this.get_tag_temp();return tag.set_attribute("name",name),tag.set_attribute("prop",prop),tag.get_selector("full")},dom_init:function(){this.dom_set(this.get_layout()),this.trigger("dom_init")},dom_get_tag:function(tag,prop){var ret=$(),tags=this.get_tags(tag,prop);if(tags.length){var level=null;this.util.is_string(tag)&&(level=this.util.is_string(prop)?"full":"tag");var sel="."+tags[0].get_class(level);ret=this.dom_get().find(sel)}return ret}};View.Template=Modeled_Component.extend(Template);var Template_Tag={_slug:"template_tag",_reciprocal:!0,_attr_default:{name:null,prop:null,match:null},handlers:{},_c:function(tag_match){this.parse(tag_match)},parse:function(tag_match){if(!this.util.is_string(tag_match))return!1;var part,parts=tag_match.split("|");if(!parts.length)return null;var attrs={name:null,prop:null,match:tag_match};attrs.name=parts[0],-1!==attrs.name.indexOf(".")&&(attrs.name=attrs.name.split(".",2),attrs.prop=attrs.name[1],attrs.name=attrs.name[0]);for(var x=1;x<parts.length;x++)1<(part=parts[x].split(":",1)).length&&!(part[0]in attrs)&&(attrs[part[0]]=part[1]);this.set_attributes(attrs,!0)},render:function(item){var tag=this;return tag.get_handler().render(item,tag).pipe(function(output){return{tag:tag,output:output}})},get_name:function(){return this.get_attribute("name")},get_prop:function(){return this.get_attribute("prop")},get_handler:function(){return this.has_handler()?this.handlers[this.get_name()]:new View.Template_Tag_Handler("")},has_handler:function(){return this.get_name()in this.handlers},get_classes:function(rtype){var cls=[this.get_class(),this.get_class("tag"),this.get_class("full")];return this.util.is_string(rtype)&&(cls=cls.join(rtype)),cls},get_class:function(level){var cls="";switch(level){case"tag":cls=this.get_name();break;case"full":var i,parts=[this.get_name(),this.get_prop()],a=[];for(i=0;i<parts.length;i++)this.util.is_string(parts[i])&&a.push(parts[i]);cls=a.join("_")}return this.util.is_string(cls)?this.add_ns(cls):this.get_ns()},get_selector:function(level){var ret=this.get_class(level);return ret=this.util.is_string(ret)?"."+ret:""}};View.Template_Tag=Component.extend(Template_Tag);var Template_Tag_Handler={_slug:"template_tag_handler",_attr_default:{supports_modifiers:!1,dynamic:!1,props:{}},render:function(item,instance){var dfr=$.Deferred();return this.call_attribute("render",item,instance,dfr),dfr.promise()},add_prop:function(prop,fn){var a="props",props=this.get_attribute(a);if(!this.util.is_string(prop)||!this.util.is_func(fn))return!1;this.util.is_obj(props,!1)||(props={}),props[prop]=fn,this.set_attribute(a,props)},handle_prop:function(prop,item,instance){var props=this.get_attribute("props");return this.util.is_obj(props)&&prop in props&&this.util.is_func(props[prop])?props[prop].call(this,item,instance):item.get_viewer().get_label(prop)}};View.Template_Tag_Handler=Component.extend(Template_Tag_Handler),View=SLB.attach("View",View)}(jQuery);
|
1 |
+
window.SLB&&SLB.attach&&!function($){var View={assets:{},component_defaults:[],loading:[],cache:{},component_temps:{},options:{},_init:function(){this._super(),this.init_refs(),this.init_components()},init_refs:function(){var r,ref,prop;for(prop in this)if(prop=this[prop],this.is_component(prop)&&!this.util.is_empty(prop.prototype._refs))for(r in prop.prototype._refs)ref=prop.prototype._refs[r],this.util.is_string(ref)&&ref in this&&(ref=prop.prototype._refs[r]=this[ref]),this.util.is_class(ref)||delete prop.prototype_refs[r]},init_components:function(){this.component_defaults=[this.Viewer]},init:function(options){var t=this;$.when.apply($,this.loading).always(function(){$.extend(!0,t.options,options),$(window).on("popstate",function(e){var state=e.originalEvent.state;if(t.util.in_obj(state,["item","viewer"]))return t.get_viewer(state.viewer).history_handle(e),e.preventDefault()}),t.init_items()})},can_make_default_component:function(type){return-1!==$.inArray(type,this.component_defaults)},is_component:function(comp){return this.util.is_class(comp,this.Component)},get_components:function(type){var ret={};return this.is_component(type)&&((type=type.prototype._slug+"s")in this.cache||(this.cache[type]={}),ret=this.cache[type]),ret},get_component:function(type,id){var coll,tid,ret=null;return this.util.is_func(type)&&(this.util.is_string(id)||(id=null),coll=this.get_components(type),this.util.is_obj(coll)&&(tid=this.util.is_string(id)?id:this.util.add_prefix("default"))in coll&&(ret=coll[tid]),this.util.is_empty(ret)&&(this.util.is_string(id)||this.can_make_default_component(type))&&(ret=this.add_component(type,id))),ret},add_component:function(type,id,options){if(!this.util.is_func(type))return!1;if(this.util.is_empty(id)&&!this.can_make_default_component(type))return!1;var ret=null,m=(this.util.is_empty(id)&&(id=this.util.add_prefix("default")),this.util.is_obj(options)||(options={}),"component"!==type.prototype._slug?"add_"+type.prototype._slug:null),ret=!this.util.is_empty(m)&&m in this&&this.util.is_func(this[m])?this[m](id,options):new type(id,options);if(this.util.is_type(ret,type)){var coll=this.get_components(type);switch($.type(coll)){case"object":coll[id]=ret;break;case"array":coll.push(ret)}}else ret=null;return ret},add_component_temp:function(type){var ret=null;return this.is_component(type)&&(ret=new type(""),this.component_temps[ret._slug]=ret),ret},get_component_temp:function(type){return this.has_component_temp(type)?this.component_temps[type.prototype._slug]:this.add_component_temp(type)},has_component_temp:function(type){return!!(this.is_component(type)&&type.prototype._slug in this.component_temps)},get_options:function(opts){var ret={};if(this.util.is_string(opts)&&(opts=[opts]),this.util.is_array(opts))for(var x=0;x<opts.length;x++)opts[x]in this.options&&(ret[opts[x]]=this.options[opts[x]]);return ret},get_option:function(opt,def){var ret=this.get_options(opt);return ret=this.util.is_obj(ret)&&opt in ret?ret[opt]:this.util.is_set(def)?def:null},add_viewer:function(id,options){id=new this.Viewer(id,options);return this.get_viewers()[id.get_id()]=id},get_viewers:function(){return this.get_components(this.Viewer)},has_viewer:function(v){return!!(this.util.is_string(v)&&v in this.get_viewers())},get_viewer:function(v){return this.has_viewer(v)||(v=this.util.add_prefix("default"),this.has_viewer(v)||(v=(v=this.add_viewer(v)).get_id())),this.get_viewers()[v]},init_items:function(){var t=this,sel=this.util.format('a[href][%s="%s"]',this.util.get_attribute("active"),1);$(document).on("click",sel,null,function(){var ret=t.show_item(this);return!(ret=t.util.is_bool(ret)?ret:!0)})},get_items:function(){return this.get_components(this.Content_Item)},get_item:function(ref){var item,key;return this.util.is_type(ref,this.Content_Item)?ref:(item=null,this.util.in_obj(ref,"nodeType")?(key=this.get_component_temp(this.Content_Item).get_data_key(),item=$(ref).data(key)):this.util.is_string(ref,!1)&&ref in(key=this.get_items())&&(item=key[ref]),this.util.is_instance(item,this.Content_Item)?item:this.add_item(ref))},add_item:function(el){return new this.Content_Item(el)},show_item:function(el){return this.get_item(el).show()},save_item:function(item){return this.util.is_instance(item,this.Content_Item)&&(this.get_items()[item.get_id()]=item),item},get_content_handlers:function(){return this.get_components(this.Content_Handler)},get_content_handler:function(item){var item=this.util.is_instance(item,this.Content_Item)?item.get_attribute("type",""):item.toString(),types=this.get_content_handlers();return item in types?types[item]:null},extend_content_handler:function(id,attr){var hdl=null;return this.util.is_string(id)&&this.util.is_obj(attr)&&(null===(hdl=this.get_content_handler(id))?this.get_content_handlers()[id]=hdl=new this.Content_Handler(id,attr):hdl.set_attributes(attr),this.util.in_obj(attr,"styles")&&this.load_styles(attr.styles)),hdl},add_group:function(g,attrs){return g=new this.Group(g,attrs),this.get_groups()[g.get_id()]=g},get_groups:function(){return this.get_components(this.Group)},get_group:function(g){return this.has_group(g)?this.get_groups()[g]:this.add_group(g)},has_group:function(g){return this.util.is_string(g)&&g in this.get_groups()},extend_theme:function(id,attr){var dfr,model;return!!this.util.is_string(id)&&(dfr=$.Deferred(),this.loading.push(dfr),model=this.get_theme_model(id),this.util.is_empty(model)&&(model=this.save_theme_model({parent:null,id:id})),this.util.is_obj(attr)&&("id"in attr&&delete attr.id,$.extend(model,attr)),this.util.in_obj(attr,"styles")&&this.load_styles(attr.styles),this.util.is_obj(model.parent)||(model.parent=this.get_theme_model(model.parent)),dfr.resolve(),model)},get_theme_models:function(){return this.Theme.prototype._models},get_theme_model:function(id){var ms=this.get_theme_models();return this.util.in_obj(ms,id)?ms[id]:{}},save_theme_model:function(model){return this.util.in_obj(model,"id")&&this.util.is_string(model.id)&&(this.get_theme_models()[model.id]=model),model},extend_template_tag_handler:function(id,attr){var hdl,hdls;return!(!this.util.is_string(id)||!this.util.is_obj(attr))&&(hdls=this.get_template_tag_handlers(),this.util.in_obj(hdls,id)?(hdl=hdls[id]).set_attributes(attr):hdls[(hdl=new this.Template_Tag_Handler(id,attr)).get_id()]=hdl,this.util.in_obj(attr,"styles")&&this.load_styles(attr.styles),this.util.in_obj(attr,"_hooks")&&attr._hooks.call(hdl),hdl)},get_template_tag_handlers:function(){return this.Template_Tag.prototype.handlers},get_template_tag_handler:function(id){var handlers=this.get_template_tag_handlers();return this.util.in_obj(handlers,id)?handlers[id]:null},load_styles:function(styles){if(this.util.is_array(styles)){for(var style,out=[],x=0;x<styles.length;x++)style=styles[x],this.util.in_obj(style,"uri")&&this.util.is_string(style.uri)&&out.push('<link rel="stylesheet" type="text/css" href="'+style.uri+'" />');$("head").append(out.join(""))}}},Component={_slug:"component",_ns:null,_refs:{},_reciprocal:!1,_dom:null,_attributes:!1,_attr_default:{},_attr_default_parsed:!1,_attr_init:null,_attr_map:{},_events:{},_status:null,_id:"",_c:function(id,attributes){this._set_id(id),this.util.is_obj(attributes)&&(this._attr_init=attributes),this._hooks()},_set_parent:function(){this._super(View)},_hooks:function(){},_set_id:function(id){return this.util.is_empty(this._id)&&(this._id=this.util.is_string(id)?id:this.util.guid()),this._id},get_id:function(ns){var id=this._id;return id=this.util.is_bool(ns)&&ns?this.add_ns(id):id},get_ns:function(){return null===this._ns&&(this._ns=this.util.add_prefix(this._slug)),this._ns},add_ns:function(val){return this.util.is_string(val)?this.get_ns()+"_"+val:""},get_status:function(id,raw){var ret=!1;return ret=this.util.in_obj(this._status,id)?raw?this._status[id]:!!this._status[id]:ret},set_status:function(id,val){return this.util.is_string(id)?(this.util.is_set(val)||(val=!0),this.util.is_obj(this._status,!1)||(this._status={}),this._status[id]=val):this.util.is_set(val)||(val=!1),val},get_controller:function(){return this.get_parent()},has_reference:function(ref){return!!(this.util.is_string(ref)&&ref in this&&ref in this.get_references())},get_references:function(){return this._refs},get_reference:function(ref){return this.has_reference(ref)?this._refs[ref]:null},get_component:function(cname,options){var c=null;if(this.has_reference(cname)){options=$.extend({},{check_attr:!0,get_default:!1},options);var ctype=this.get_reference(cname);if(this.util.is_type(this[cname],ctype))return this[cname];c=this[cname]=null,options.check_attr&&(c=this.get_attribute(cname),this.util.is_empty(c)||(c=this.set_component(cname,c))),this.util.is_empty(c)&&options.get_default&&(c=this.get_controller().get_component(ctype))}return c},set_component:function(name,ref,validate){var ctype;return this.has_reference(name)?((this.util.is_empty(ref)||(ctype=this.get_reference(name),this.util.is_string(ref,!1)&&(ref=this.get_controller().get_component(ctype,ref)),!this.util.is_type(ref,ctype)||this.util.is_func(validate)&&!validate.call(this,ref)))&&(ref=null),this[name]=ref,this[name]):null},clear_component:function(name){this.set_component(name,null)},init_attributes:function(force){!(force=this.util.is_bool(force)?force:!1)&&this.util.is_obj(this._attributes)||(force=this._attributes={},$.extend(force,this.init_default_attributes()),this.util.is_obj(this._attr_init)&&$.extend(force,this._attr_init),$.extend(force,this.get_dom_attributes()))},init_default_attributes:function(){if(!this._attr_default_parsed&&this.util.is_obj(this._attr_map)){var opts=this.get_controller().get_options(this.util.obj_keys(this._attr_map));if(this.util.is_obj(opts)){for(var opt in this._attr_map)opt in opts&&null!==this._attr_map[opt]&&(opts[this._attr_map[opt]]=opts[opt],delete opts[opt]);$.extend(!0,this._attr_default,opts)}this._attr_default_parsed=!0}return this._attr_default},get_dom_attributes:function(){var attr_prefix,attr_key,attrs={},el=this.dom_get(null,{init:!1});return 0<el.length&&(el=$(el).get(0).attributes,this.util.is_obj(el)&&(attr_prefix=this.util.get_attribute(),$.each(el,function(idx,attr){if(-1===attr.name.indexOf(attr_prefix))return!0;attr_key=attr.name.substr(attr_prefix.length+1),attrs[attr_key]=attr.value}))),attrs},get_attributes:function(){return this.init_attributes(),this._attributes},get_attribute:function(key,def,enforce_type){if(this.util.is_set(def)||(def=null),!this.util.is_string(key))return def;this.util.is_bool(enforce_type)||(enforce_type=!0);key=this.has_attribute(key)?this.get_attributes()[key]:def;return enforce_type&&key!==def&&null!==def&&!this.util.is_type(key,$.type(def),!1)&&(this.util.is_scalar(def,!1)&&this.util.is_scalar(key,!1)?this.util.is_string(def,!1)?key=key.toString():this.util.is_num(def,!1)&&!this.util.is_num(key,!1)?(key=(this.util.is_int(def,!1)?parseInt:parseFloat)(key),this.util.is_num(key,!1)||(key=def)):key=this.util.is_bool(def,!1)?this.util.is_string(key)||this.util.is_num(key):def:key=def),key},call_attribute:function(attr,args){return attr=this.get_attribute(attr),this.util.is_func(attr)&&(args=Array.prototype.slice.call(arguments,1),attr=attr.apply(this,args)),attr},has_attribute:function(key){return this.util.is_string(key)&&key in this.get_attributes()},set_attributes:function(attributes,full){this.util.is_bool(full)||(full=!1),this.init_attributes(full),this.util.is_obj(attributes)&&$.extend(this._attributes,attributes)},set_attribute:function(key,val){return this.util.is_string(key)&&this.util.is_set(val)&&(this.get_attributes()[key]=val),val},dom_get_selector:function(element){return this.util.is_string(element)?"."+this.add_ns(element):""},dom_get_attribute:function(){return this.util.get_attribute(this._slug)},dom_set:function(el){return(el=$(el)).data(this.get_data_key(),this),this._reciprocal&&(this._dom=el),el},dom_get:function(element,options){var ch,opts_default={init:!0,put:!1},opts_default=((options=this.util.is_obj(options)?$.extend({},opts_default,options):opts_default).init&&!this.get_status("dom_init")&&(this.set_status("dom_init"),this.dom_init()),this._dom);return opts_default&&this.util.is_string(element)&&((ch=$(opts_default).find(this.dom_get_selector(element))).length?opts_default=ch:!0!==options.put&&!this.util.is_obj(options.put)||(opts_default=this.dom_put(element,options.put))),$(opts_default)},dom_init:function(){},dom_put:function(element,content){var r=null;if(this.dom_has()&&this.util.is_string(element)){for(var strip=["tag","content","success"],options={tag:"div",content:"",class:this.add_ns(element)},attrs=(this.util.is_empty(content)||(this.util.is_type(content,jQuery,!1)||this.util.is_string(content,!1)?options.content=content:this.util.is_obj(content,!1)&&$.extend(options,content)),$.extend({},options)),x=0;x<strip.length;x++)delete attrs[strip[x]];content=this.dom_get();(r=$(this.dom_get_selector(element),content)).length||(r=$(this.util.format("<%s />",options.tag),attrs).appendTo(content)).length&&this.util.is_method(options,"success")&&options.success.call(r,r),$(r).append(options.content)}return $(r)},dom_has:function(){return!!this.dom_get().length},get_data_key:function(){return this.get_ns()},on:function(event,fn,options){var t,args,es;return this.util.is_string(event)&&this.util.is_func(fn)?(this.util.is_obj(options,!1)||(options={}),options=$.extend({},{clear:!1},options),this.util.is_obj(this._events,!1)||(this._events={}),event in(es=this._events)&&this.util.is_obj(es[event],!1)&&!options.clear||(es[event]=[]),es[event].push(fn)):(t=this,args=Array.prototype.slice.call(arguments,1),this.util.is_array(event)?$.each(event,function(idx,val){t.on.apply(t,[val].concat(args))}):this.util.is_obj(event)&&$.each(event,function(ev,hdl){t.on.apply(t,[ev,hdl].concat(args))})),this},trigger:function(event,data){var ev,dfr=$.Deferred(),dfrs=[],t=this;return this.util.is_array(event)?($.each(event,function(idx,val){dfrs.push(t.trigger(val,data))}),$.when.apply(t,dfrs).done(function(){dfr.resolve()})):this.util.is_string(event)&&event in this._events?(ev={type:event,data:null},this.util.is_set(data)&&(ev.data=data),$.each(this._events[event],function(idx,fn){dfrs.push(fn.call(t,ev,t))}),$.when.apply(this,dfrs).done(function(){dfr.resolve()})):dfr.resolve(),dfr.promise()}},Viewer=(View.Component=Component=SLB.Class.extend(Component),{_slug:"viewer",_refs:{item:"Content_Item",theme:"Theme"},_reciprocal:!0,_attr_default:{loop:!0,animate:!0,autofit:!0,overlay_enabled:!0,overlay_opacity:"0.8",title_default:!1,container:null,slideshow_enabled:!0,slideshow_autostart:!1,slideshow_duration:2,slideshow_active:!1,slideshow_timer:null,labels:{close:"close",nav_prev:"« prev",nav_next:"next »",slideshow_start:"start slideshow",slideshow_stop:"stop slideshow",group_status:"Image %current% of %total%",loading:"loading"}},_attr_map:{theme:null,group_loop:"loop",ui_autofit:"autofit",ui_animate:"animate",ui_overlay_opacity:"overlay_opacity",ui_labels:"labels",ui_title_default:"title_default",slideshow_enabled:null,slideshow_autostart:null,slideshow_duration:null},item:null,item_queued:null,theme:null,item_working:null,active:!1,init:!1,open:!1,loading:!1,_hooks:function(){var t=this;this.on(["item-prev","item-next"],function(){t.trigger("item-change")}).on(["close","item-change"],function(){t.unload().done(function(){t.unlock()})})},get_item:function(){return this.get_component("item")},set_item:function(item){this.clear_item(!1);item=this.set_component("item",item,function(item){return item.has_type()});return!this.util.is_empty(item)},clear_item:function(full){this.util.is_bool(full)||(full=!0);var item=this.get_item();item&&item.reset(),full&&this.clear_component("item")},get_theme:function(){var ret=this.get_component("theme",{check_attr:!1});return ret=this.util.is_empty(ret)?this.set_component("theme",new View.Theme(this)):ret},set_theme:function(theme){this.set_component("theme",theme)},lock:function(){return this.set_status("item_working",$.Deferred())},get_lock:function(simple,full){this.util.is_bool(simple)||(simple=!1),this.util.is_bool(full)||(full=!1);var s="item_working";return simple?this.get_status(s):(simple=this.get_status(s,!0),this.util.is_promise(simple)||(simple=this.lock()),full?simple:simple.promise())},is_locked:function(){return this.get_lock(!0)},unlock:function(){return this.get_lock(!1,!0).resolve()},set_active:function(mode){return this.util.is_bool(mode)||(mode=!0),this.set_status("active",mode)},is_active:function(){return this.get_status("active")},set_loading:function(mode){var dfr=$.Deferred(),m=(this.util.is_bool(mode)||(mode=!0),this.loading=mode,this.slideshow_active()&&this.slideshow_pause(mode),mode?"addClass":"removeClass");return $(this.dom_get())[m]("loading"),mode?this.get_theme().transition("load").always(function(){dfr.resolve()}):dfr.resolve(),dfr.promise()},unset_loading:function(){return this.set_loading(!1)},get_loading:function(){return!!this.util.is_bool(this.loading)&&this.loading},is_loading:function(){return this.get_loading()},show:function(item){this.item_queued=item;var fin_set="show_deferred",item="theme_valid",valid=!0;if(this.has_attribute(item)?valid=this.get_attribute(item,!0):(valid=!(!this.get_theme()||""===this.get_theme().get_template().get_layout(!1)),this.set_attribute(item,valid)),!valid)return this.close(),!1;function fin(){if(v.lock(),v.set_status(fin_set,!1),!v.set_item(v.item_queued))return v.close();v.history_add(),v.set_active(),v.render()}var v=this;this.is_locked()?this.get_status(fin_set)||(this.set_status(fin_set),this.get_lock().always(function(){fin()})):fin()},history_handle:function(e){var state=e.originalEvent.state;this.util.is_string(state.item,!1)?(this.get_controller().get_item(state.item).show({event:e}),this.trigger("item-change")):(state=this.history_get(!0),this.history_set(0),-1!==state&&this.close())},history_get:function(full){return this.get_status("history_count",full)},history_set:function(val){return this.set_status("history_count",val)},history_add:function(){if(!history.pushState)return!1;var item=this.get_item(),opts=item.get_attribute("options_show"),count=this.history_get()?this.history_get(!0):0;this.util.in_obj(opts,"event")?(opts=opts.event.originalEvent,this.util.in_obj(opts,"state")&&this.util.in_obj(opts.state,"count")&&(count=opts.state.count)):(opts={viewer:this.get_id(),item:null,count:count},count||history.replaceState(opts,null),opts.item=this.get_controller().save_item(item).get_id(),opts.count=++count,history.pushState(opts,"")),this.history_set(count)},history_reset:function(){var count=this.history_get(!0);count&&(this.history_set(-1),history.go(-1*count))},is_open:function(){return"none"!==this.dom_get().css("display")},render:function(){var v=this,thm=this.get_theme();v.dom_prep(),this.get_status("render-events")||(this.set_status("render-events"),thm.on("render-loading",function(ev,thm){var set_pos,always,dfr=$.Deferred();return v.is_active()?(set_pos=function(){v.dom_get().css("top",$(window).scrollTop())},always=function(){v.set_loading().always(function(){dfr.resolve()})},v.is_open()?thm.transition("unload").fail(function(){set_pos(),thm.dom_get_tag("item","content").attr("style","")}).always(always):thm.transition("open").always(function(){always(),v.events_open(),v.open=!0}).fail(function(){set_pos(),v.get_overlay().show(),v.dom_get().show()})):dfr.reject(),dfr.promise()}).on("render-complete",function(ev,thm){if(!v.is_active())return!1;var d=v.dom_get(),classes=["item_single","item_multi"],ms=["addClass","removeClass"];v.get_item().get_group().is_single()||ms.reverse(),$.each(ms,function(idx,val){d[val](classes[idx])}),v.events_complete(),thm.transition("complete").fail(function(){var dims;v.get_attribute("autofit",!0)&&(dims=$.extend({display:"inline-block"},thm.get_item_dimensions()),thm.dom_get_tag("item","content").css(dims))}).always(function(){v.unset_loading(),v.trigger("render-complete"),v.init=!0})})),thm.render()},dom_get_container:function(){var sel=this.get_attribute("container"),c=(this.util.is_empty(sel)&&(sel="#"+this.add_ns("wrap")),$(sel));return c.length||(sel=0===sel.indexOf("#")?sel.substr(1):sel,c=$("<div />",{id:sel}).appendTo("body")),c},dom_init:function(){var d=this.dom_set($("<div/>",{id:this.get_id(!0),class:this.get_ns()})).appendTo(this.dom_get_container()).hide(),thm=this.get_theme(),v=(d.addClass(thm.get_classes(" ")),this);this.get_status("render-init")||(this.set_status("render-init"),thm.on("render-init",function(ev){v.dom_put("layout",ev.data)})),thm.render(!0)},dom_prep:function(mode){mode=this.util.is_bool(mode)&&!mode?"removeClass":"addClass";$("html")[mode](this.util.add_prefix("overlay"))},dom_restore:function(){this.dom_prep(!1)},get_layout:function(){return this.dom_get("layout",{put:{success:function(){$(this).hide()}}})},animation_enabled:function(){return this.get_attribute("animate",!0)},overlay_enabled:function(){var ov=this.get_attribute("overlay_enabled");return!!this.util.is_bool(ov)&&ov},get_overlay:function(){var o=null,v=this;return this.overlay_enabled()&&(o=this.dom_get("overlay",{put:{success:function(){$(this).hide().css("opacity",v.get_attribute("overlay_opacity"))}}})),$(o)},unload:function(){var dfr=$.Deferred();return this.get_theme().dom_get_tag("item").text(""),dfr.resolve(),dfr.promise()},reset:function(){this.dom_get().hide(),this.dom_restore(),this.history_reset(),this.clear_item(),this.set_active(!1),this.set_loading(!1),this.slideshow_stop(),this.keys_disable(),this.unlock()},get_labels:function(){return this.get_attribute("labels",{})},get_label:function(name){var lbls=this.get_labels();return name in lbls?lbls[name]:""},events_open:function(){if(this.keys_enable(),this.open)return!1;function close(){v.close()}var l=this.get_layout(),v=(l.children().click(function(ev){ev.stopPropagation()}),this);l.click(close),this.get_overlay().click(close),this.trigger("events-open")},events_complete:function(){if(this.init)return!1;this.trigger("events-complete")},keys_enable:function(mode){this.util.is_bool(mode)||(mode=!0);var e=["keyup",this.util.get_prefix()].join("."),v=this;mode?$(document).on(e,function(ev){return v.keys_control(ev)}):$(document).off(e)},keys_disable:function(){this.keys_enable(!1)},keys_control:function(ev){var handlers={27:this.close,37:this.item_prev,39:this.item_next};if("rtl"===document.documentElement.getAttribute("dir")&&(handlers[37]=this.item_next,handlers[39]=this.item_prev),ev.which in handlers)return handlers[ev.which].call(this),!1},slideshow_enabled:function(){var o=this.get_attribute("slideshow_enabled");return!(!(this.util.is_bool(o)&&o&&this.get_item())||this.get_item().get_group().is_single())},slideshow_active:function(){return!(!this.slideshow_enabled()||!(this.get_attribute("slideshow_active")||!this.init&&this.get_attribute("slideshow_autostart")))},slideshow_clear_timer:function(){clearInterval(this.get_attribute("slideshow_timer"))},slideshow_set_timer:function(callback){this.set_attribute("slideshow_timer",setInterval(callback,1e3*this.get_attribute("slideshow_duration")))},slideshow_start:function(){if(!this.slideshow_enabled())return!1;this.set_attribute("slideshow_active",!0),this.dom_get().addClass("slideshow_active"),this.slideshow_clear_timer();var v=this;this.slideshow_set_timer(function(){v.slideshow_pause(),v.item_next()}),this.trigger("slideshow-start")},slideshow_stop:function(full){(full=this.util.is_bool(full)?full:!0)&&(this.set_attribute("slideshow_active",!1),this.dom_get().removeClass("slideshow_active")),this.slideshow_clear_timer(),this.trigger("slideshow-stop")},slideshow_toggle:function(){if(!this.slideshow_enabled())return!1;this.slideshow_active()?this.slideshow_stop():this.slideshow_start(),this.trigger("slideshow-toggle")},slideshow_pause:function(mode){this.util.is_bool(mode)||(mode=!0),this.slideshow_active()&&(mode?this.slideshow_stop(!1):this.slideshow_start()),this.trigger("slideshow-pause")},slideshow_resume:function(){this.slideshow_pause(!1)},item_next:function(){var g=this.get_item().get_group(!0),v=this,ev="item-next",st=["events","viewer",ev].join("_");g.get_status(st)||(g.set_status(st),g.on(ev,function(e){v.trigger(e.type)})),g.show_next()},item_prev:function(){var g=this.get_item().get_group(!0),v=this,ev="item-prev",st=["events","viewer",ev].join("_");g.get_status(st)||(g.set_status(st),g.on(ev,function(){v.trigger(ev)})),g.show_prev()},close:function(){this.set_active(!1);var v=this,thm=this.get_theme();return thm.transition("unload").always(function(){thm.transition("close",!0).always(function(){v.reset(),v.trigger("close")})}).fail(function(){thm.dom_get_tag("item","content").attr("style","")}),!1}}),Viewer=(View.Viewer=Component.extend(Viewer),{_slug:"group",_reciprocal:!0,_refs:{current:"Content_Item"},current:null,selector:null,_hooks:function(){var t=this;this.on(["item-prev","item-next"],function(){t.trigger("item-change")})},get_selector:function(){return this.util.is_empty(this.selector)&&(this.selector=this.util.format('a[%s="%s"]',this.dom_get_attribute(),this.get_id())),this.selector},get_items:function(){var items=$(this.get_selector());return items=0===items.length&&this.has_current()?this.get_current().dom_get():items},get_item:function(idx){this.util.is_int(idx)||(idx=0);var items=this.get_items(),max=this.get_size()-1;return items.get(idx=max<idx?max:idx)},get_pos:function(item){return this.util.is_empty(item)&&(item=this.get_current()),this.util.is_type(item,View.Content_Item)?this.get_items().index(item.dom_get()):-1},has_current:function(){return!this.util.is_empty(this.get_current())},get_current:function(){return null===this.current||this.util.is_type(this.current,View.Content_Item)||(this.current=null),this.current},set_current:function(item){this.util.is_type(item,View.Content_Item)&&(this.current=item)},get_next:function(item){var next,pos;return this.util.is_type(item,View.Content_Item)||(item=this.get_current()),1===this.get_size()?item:(next=null,-1===(pos=this.get_pos(item))||0===(pos=pos+1<this.get_size()?pos+1:0)&&!item.get_viewer().get_attribute("loop")?next:this.get_item(pos))},get_prev:function(item){var prev,pos;return this.util.is_type(item,View.Content_Item)||(item=this.get_current()),1===this.get_size()?item:(prev=null,-1===(pos=this.get_pos(item))||0===pos&&!item.get_viewer().get_attribute("loop")||(0===pos&&(pos=this.get_size()),prev=this.get_item(--pos)),prev)},show_next:function(item){var next;1<this.get_size()&&((next=this.get_next(item))||(item=this.util.is_type(item,View.Content_Item)?item:this.get_current()).get_viewer().close(),item=this.get_controller().get_item(next),this.set_current(item),item.show(),this.trigger("item-next"))},show_prev:function(item){var prev;1<this.get_size()&&((prev=this.get_prev(item))||(item=this.util.is_type(item,View.Content_Item)?item:this.get_current()).get_viewer().close(),item=this.get_controller().get_item(prev),this.set_current(item),item.show(),this.trigger("item-prev"))},get_size:function(){return this.get_items().length},is_single:function(){return 1===this.get_size()}}),Viewer=(View.Group=Component.extend(Viewer),{_slug:"content_handler",_refs:{item:"Content_Item"},item:null,template:"",has_item:function(){return!this.util.is_empty(this.get_item())},get_item:function(){return this.get_component("item")},set_item:function(item){return this.set_component("item",item)},clear_item:function(){this.clear_component("item")},match:function(item){var m=this.get_attribute("match");if(!this.util.is_empty(m)){if(this.util.is_string(m)&&(m=new RegExp(m,"i"),this.set_attribute("match",m)),this.util.is_type(m,RegExp))return m.test(item.get_uri());if(this.util.is_func(m))return!!m.call(this,item)}return!1},load:function(item){var dfr=$.Deferred();return null===this.call_attribute("load",item,dfr)&&dfr.resolve(),dfr.promise()},render:function(item){var dfr=$.Deferred();return this.call_attribute("render",item,dfr),dfr.promise()}}),Viewer=(View.Content_Handler=Component.extend(Viewer),{_slug:"content_item",_reciprocal:!0,_refs:{viewer:"Viewer",group:"Group",type:"Content_Handler"},_attr_default:{source:null,permalink:null,dimensions:null,title:"",group:null,internal:!1,output:null},group:null,viewer:null,type:null,data:null,loaded:null,_c:function(el){this.dom_set(el),this._super()},init_default_attributes:function(){this._super();var t,d=this.dom_get(),key=d.attr(this.util.get_attribute("asset"))||null,assets=this.get_controller().assets||null;return this.util.is_string(key)&&(d=[{},this._attr_default,{permalink:d.attr("href")}],this.util.is_obj(assets)&&(t=this,d.push(function(key){var ret={};return ret=key in assets&&t.util.is_obj(assets[key])?assets[key]:ret}(key))),this._attr_default=$.extend.apply(this,d)),this._attr_default},get_output:function(){var item,dfr=$.Deferred(),ret=this.get_attribute("output");return this.util.is_string(ret)?dfr.resolve(ret):this.has_type()?this.get_type().render(item=this).done(function(output){item.set_output(output),dfr.resolve(output)}):dfr.resolve(""),dfr.promise()},set_output:function(out){this.util.is_string(out,!1)&&this.set_attribute("output",out)},get_content:function(){return this.get_output()},get_uri:function(mode){-1===$.inArray(mode,["source","permalink"])&&(mode="source");var ret=this.get_attribute(mode);return ret=(ret=this.util.is_string(ret)?ret:"source"===mode?this.get_attribute("permalink"):"").replace(/&(#38|amp);/,"&")},get_title:function(){if(this.has_attribute("title_cached"))return this.get_attribute("title_cached","");function validate(title){return"string"!=typeof title||""===title.trim()?"":(title=title.trim(),t.get_viewer().get_attribute("title_default")||title===t.get_title_default()&&(title=""),title)}var title="",dom=this.dom_get(),t=this;if(!(title=dom.length?(title=(title=dom.attr("title"))||dom.closest("figure").find("figcaption").first().html())||dom.closest("figure").find(".wp-caption-text").first().html():title))for(var props=["caption","title"],x=0;x<props.length&&(title=validate(this.get_attribute(props[x],"")),this.util.is_empty(title));x++);return title=validate(title=!title&&dom.length?(title=validate(dom.find("img").first().attr("alt")))||validate(dom.get(0).innerText.trim()):title),this.set_attribute("title_cached",title),title},get_title_default:function(){var f,i,prop="title_default";return this.has_attribute(prop)?this.get_attribute(prop):(-1!==(i=(f=this.get_uri("source")).lastIndexOf("/"))&&-1!==(i=(f=f.substr(i+1)).lastIndexOf("."))&&(f=f.substr(0,i)),this.set_attribute(prop,f))},get_dimensions:function(){return $.extend({width:0,height:0},this.get_attribute("dimensions"),{})},set_data:function(data){this.data=data},get_data:function(){return this.data},gallery_type:function(){var type,ret=null,types={wp:".gallery-icon",ngg:".ngg-gallery-thumbnail"},dom=this.dom_get();for(type in types)if(0<dom.parent(types[type]).length){ret=type;break}return ret},in_gallery:function(gType){var type=this.gallery_type();return null!==type&&(!this.util.is_string(gType)||gType===type)},get_viewer:function(){return this.get_component("viewer",{get_default:!0})},set_viewer:function(v){return this.set_component("viewer",v)},get_group:function(set_current){var g=this.get_component("group");return g||(g=this.set_component("group",new View.Group),set_current=!0),set_current&&g.set_current(this),g},set_group:function(g){this.util.is_string(g)&&(g=this.get_controller().get_group(g)),this.group=!!this.util.is_type(g,View.Group)&&g},get_type:function(){return this.get_component("type",{check_attr:!1})||this.set_type(this.get_controller().get_content_handler(this))},set_type:function(type){return this.set_component("type",type)},has_type:function(){return!this.util.is_empty(this.get_type())},show:function(options){if(!this.has_type())return!1;this.set_attribute("options_show",options);options=this.get_viewer();return this.load(),options.show(this)},load:function(){return this.util.is_promise(this.loaded)||(this.loaded=this.get_type().load(this)),this.loaded.promise()},reset:function(){this.set_attribute("options_show",null)}}),Viewer=(View.Content_Item=Component.extend(Viewer),{_slug:"modeled_component",get_attribute:function(key,def,check_model,enforce_type){var ret;return!this.util.is_string(key)||(ret=null,(check_model=this.util.is_bool(check_model)?check_model:!0)&&(check_model=this.get_ancestor(key,!1),this.util.in_obj(check_model,key)&&(ret=check_model[key])),null===ret)?this._super(key,def,enforce_type):ret},get_attribute_recursive:function(key,def,enforce_type){var t,ret=this.get_attribute(key,def,!0,enforce_type);return this.util.is_obj(ret)&&(def=this.get_ancestors(!1),ret=[ret],t=this,$.each(def,function(idx,model){key in model&&t.util.is_obj(model[key])&&ret.push(model[key])}),ret.push({}),ret=$.extend.apply($,ret.reverse())),ret},set_attribute:function(key,val,use_model){return!(!this.util.is_string(key)||!this.util.is_set(val))&&((use_model=this.util.is_bool(use_model)||this.util.is_obj(use_model)?use_model:!0)?(this.util.is_obj(use_model)?use_model:this.get_model())[key]=val:this._super(key,val),val)},get_model:function(){var m=this.get_attribute("model",null,!1);return this.util.is_obj(m)||this.set_attribute("model",m={},!1),m},has_model:function(){return!this.util.is_empty(this.get_model())},in_model:function(key){return!!this.util.in_obj(this.get_model(),key)},get_ancestors:function(inc_current){for(var ret=[],m=this.get_model();this.util.is_obj(m);)ret.push(m),m=this.util.in_obj(m,"parent")&&this.util.is_obj(m.parent)?m.parent:null;return inc_current||ret.shift(),ret},get_ancestor:function(attr,safe_mode){if(!this.util.is_string(attr))return!1;this.util.is_bool(safe_mode)||(safe_mode=!0);for(var mcurr=this.get_model(),m=mcurr,found=!1;this.util.is_obj(m);){if(this.util.in_obj(m,attr)&&!this.util.is_empty(m[attr])){found=!0;break}m=this.util.in_obj(m,"parent")?m.parent:null}return found||(safe_mode?(this.util.is_empty(m)&&(m=mcurr),this.util.in_obj(m,attr)||(m[attr]=null)):m=null),m}}),Viewer=Component.extend(Viewer),Template=(View.Theme=Viewer.extend({_slug:"theme",_refs:{viewer:"Viewer",template:"Template"},_models:{},_attr_default:{template:null,model:null},viewer:null,template:null,_c:function(id,attributes,viewer){1===arguments.length&&this.util.is_type(arguments[0],View.Viewer)&&(viewer=arguments[0],id=null),this._super(id,attributes),this.set_viewer(viewer),this.set_model(id)},get_viewer:function(){return this.get_component("viewer",{check_attr:!1,get_default:!0})},set_viewer:function(v){return this.set_component("viewer",v)},get_template:function(){var attr,ret=this.get_component("template");return this.util.is_empty(ret)&&(attr={theme:this,model:this.get_model()},ret=this.set_component("template",new View.Template(attr))),ret},get_tags:function(name,prop){return this.get_template().get_tags(name,prop)},dom_get_tag:function(tag,prop){return $(this.get_template().dom_get_tag(tag,prop))},get_tag_selector:function(name,prop){return this.get_template().get_tag_selector(name,prop)},get_models:function(){return this._models},get_model:function(id){var models;return!this.util.is_set(id)&&this.util.is_obj(this.get_attribute("model",null,!1))?this._super():(models=this.get_models(),this.util.is_string(id)||(id=this.get_controller().get_option("theme_default")),models[id=this.util.in_obj(models,id)?id:$.map(models,function(v,key){return key})[0]])},set_model:function(id){this.set_attribute("model",this.get_model(id),!1)},get_classes:function(rtype){var cls=[],thm=this,models=this.get_ancestors(!0);return $.each(models,function(idx,model){cls.push(thm.add_ns(model.id))}),cls=this.util.is_string(rtype)?cls.join(rtype):cls},get_measurement:function(attr,def){var meas=null;if(!this.util.is_string(attr))return meas;this.util.is_obj(def,!1)||(def={});var attr_cache=this.util.format("%s_cache",attr),cache=this.get_attribute(attr_cache,{},!1),status="_status",item=this.get_viewer().get_item(),w=$(window),status=(status in cache&&this.util.is_obj(cache._status)&&cache._status.width===w.width()&&cache._status.height===w.height()||(cache={}),this.util.is_empty(cache)&&(cache._status={width:w.width(),height:w.height(),index:[]}),$.inArray(item,cache._status.index));return-1!==status&&status in cache&&(meas=cache[status]),this.util.is_obj(meas)||(meas=this.call_attribute(attr),this.util.is_obj(meas)||(meas=this.get_measurement_default(attr))),meas=this.util.is_obj(meas)?$.extend({},def,meas):def,status=cache._status.index.push(item)-1,cache[status]=meas,this.set_attribute(attr_cache,cache,!1),$.extend({},meas)},get_measurement_default:function(attr){return this.util.is_string(attr)?(attr=this.util.format("get_%s_default",attr),this.util.in_obj(this,attr)?(attr=this[attr],this.util.is_func(attr)&&(attr=attr.call(this))):attr=null,attr):null},get_offset:function(){return this.get_measurement("offset",{width:0,height:0})},get_offset_default:function(){var tags,offset={width:0,height:0},v=this.get_viewer(),vn=v.dom_get(),vn=vn.clone().attr("id","").css({visibility:"hidden",position:"absolute",top:""}).removeClass("loading").appendTo(vn.parent()),l=vn.find(v.dom_get_selector("layout"));return l.length&&(l.find("*").css({width:"",height:"",display:""}),(tags=this.get_tags("item","content")).length&&(v=v.get_item().get_dimensions(),tags=$(l.find(tags[0].get_selector("full")).get(0)).css({width:v.width,height:v.height}),$.each(v,function(key,val){offset[key]=-1*val})),offset.width+=l.width(),offset.height+=l.height(),$.each(offset,function(key,val){val<0&&(offset[key]=0)})),vn.empty().remove(),offset},get_margin:function(){return this.get_measurement("margin",{width:0,height:0})},get_item_dimensions:function(){var offset,factor,v=this.get_viewer(),dims=v.get_item().get_dimensions();return v.get_attribute("autofit",!1)&&(v=this.get_margin(),(offset=this.get_offset()).height+=v.height,offset.width+=v.width,(v={width:$(window).width(),height:$(window).height()}).width>offset.width&&(v.width-=offset.width),v.height>offset.height&&(v.height-=offset.height),(factor=Math.min(v.width/dims.width,v.height/dims.height))<1&&$.each(dims,function(key){dims[key]=Math.round(dims[key]*factor)})),$.extend({},dims)},get_dimensions:function(){var dims=this.get_item_dimensions(),offset=this.get_offset();return $.each(dims,function(key){dims[key]+=offset[key]}),dims},get_breakpoints:function(){return this.get_attribute_recursive("breakpoints")},get_breakpoint:function(target){var b,ret=0;return this.util.is_string(target)&&(b=this.get_attribute_recursive("breakpoints"),this.util.is_obj(b)&&target in b&&(ret=b[target])),ret},render:function(init){var thm=this,tpl=this.get_template(),st="events_render";this.get_status(st)||(this.set_status(st),tpl.on(["render-init","render-loading","render-complete"],function(ev){return thm.trigger(ev.type,ev.data)})),tpl.render(init)},transition:function(event,clear_queue){var models,trns,thm,dfr=null,attr="transition",v=this.get_viewer(),fx_temp=null,anim_on=v.animation_enabled();return v.get_attribute(attr,!0)&&this.util.is_string(event)&&(clear_queue&&v.get_layout().find("*").each(function(){for(var el=$(this);el.queue().length;)el.stop(!1,!0)}),clear_queue=[attr,"set"].join("_"),trns=this.get_attribute(clear_queue)?this.get_attribute(attr,{}):(models=this.get_ancestors(!0),trns=[],this.set_attribute(clear_queue,!0),thm=this,$.each(models,function(idx,model){attr in model&&thm.util.is_obj(model[attr])&&trns.push(model[attr])}),trns.push({}),this.set_attribute(attr,$.extend.apply($,trns.reverse()))),this.util.is_method(trns,event)&&(anim_on||(fx_temp=$.fx.off,$.fx.off=!0),dfr=trns[event].call(this,v,$.Deferred()))),this.util.is_promise(dfr)||(dfr=$.Deferred()).reject(),dfr.always(function(){null!==fx_temp&&($.fx.off=fx_temp)}),dfr.promise()}}),{_slug:"template",_reciprocal:!0,_refs:{theme:"Theme"},_attr_default:{layout_uri:"",layout_raw:"",layout_parsed:"",tags:null,model:null},theme:null,_c:function(attributes){this._super("",attributes)},_hooks:function(){this.on("dom_init",function(ev){var tags=this.get_tags(null,null,!0),names=[],t=this;$.each(tags,function(idx,tag){var name=tag.get_name();-1===$.inArray(name,names)&&(names.push(name),tag.get_handler().trigger(ev.type,{template:t}))})})},get_theme:function(){return this.get_component("theme")},render:function(init){var item,tpl,tags,tag_promises,v=this.get_theme().get_viewer();if(!(init=this.util.is_bool(init)?init:!1))return!!v.is_active()&&(item=v.get_item(),this.util.is_type(item,View.Content_Item)?void(v.is_active()&&this.has_tags()&&(init=this.trigger("render-loading"),tags=(tpl=this).get_tags(),tag_promises=[],$.when(item.load(),init).done(function(){return!!v.is_active()&&($.each(tags,function(idx,tag){if(!v.is_active())return!1;tag_promises.push(tag.render(item).done(function(r){if(!v.is_active())return!1;r.tag.dom_get().html(r.output)}))}),!!v.is_active()&&void $.when.apply($,tag_promises).done(function(){tpl.trigger("render-complete")}))}))):(v.close(),!1));this.trigger("render-init",this.dom_get())},get_layout:function(parsed){return(parsed=this.util.is_bool(parsed)?parsed:!0)?this.parse_layout():this.get_attribute("layout_raw","")},parse_layout:function(){var a="layout_parsed",ret=this.get_attribute(a);return this.util.is_string(ret)||(ret=this.sanitize_layout(this.get_layout(!1)),ret=this.parse_tags(ret),this.set_attribute(a,ret)),ret},sanitize_layout:function(l){var rtype,dom,tag_temp,cls,cls_new;return this.util.is_empty(l)||(rtype=this.util.is_string(l)?"string":null,dom=$(l),tag_temp=this.get_tag_temp(),cls=tag_temp.get_class(),cls_new=["x",cls].join("_"),$(tag_temp.get_selector(),dom).each(function(){$(this).removeClass(cls).addClass(cls_new)}),l="string"===rtype?dom=dom.wrap("<div />").parent().html():dom),l},parse_tags:function(l){if(!this.util.is_string(l))return"";for(var match,re=/\{{2}\s*(\w.*?)\s*\}{2}/gim;match=re.exec(l);)l=l.substring(0,match.index)+this.get_tag_container(match[1])+l.substring(match.index+match[0].length);return l},get_tag_container:function(tag){var attr=this.get_tag_attribute();return this.util.format('<span %s="%s"></span>',attr,encodeURI(tag))},get_tag_attribute:function(){return this.get_tag_temp().dom_get_attribute()},get_tag:function(idx){var tags,ret=null;return ret=this.has_tags()?(tags=this.get_tags())[idx=!this.util.is_int(idx)||idx<0||idx>=tags.length?0:idx]:ret},get_tags:function(name,prop,isolate){this.util.is_bool(isolate)||(isolate=!1);var attr,d,a="tags",tags=this.get_attribute(a);if(this.util.is_array(tags)||(tags=[],d=this.dom_get(),attr=this.get_tag_attribute(),d=$(d).find("["+attr+"]"),$(d).each(function(){var el=$(this),tag=new View.Template_Tag(decodeURI(el.attr(attr)));tag.has_handler()&&(tags.push(tag),isolate||(tag.dom_set(el),el.addClass(tag.get_classes(" ")))),isolate||el.removeAttr(attr)}),isolate||this.set_attribute(a,tags,!1)),!this.util.is_empty(tags)&&this.util.is_string(name)){this.util.is_string(prop)||(prop=!1);for(var tags_filtered=[],tc=null,x=0;x<tags.length;x++)name!==(tc=tags[x]).get_name()||prop&&prop!==tc.get_prop()||tags_filtered.push(tc);tags=tags_filtered}return this.util.is_array(tags,!1)?tags:[]},has_tags:function(){return 0<this.get_tags().length},get_tag_temp:function(){return this.get_controller().get_component_temp(View.Template_Tag)},get_tag_selector:function(name,prop){this.util.is_string(name)||(name=""),this.util.is_string(prop)||(prop="");var tag=this.get_tag_temp();return tag.set_attribute("name",name),tag.set_attribute("prop",prop),tag.get_selector("full")},dom_init:function(){this.dom_set(this.get_layout()),this.trigger("dom_init")},dom_get_tag:function(tag,prop){var level,ret=$(),tags=this.get_tags(tag,prop);return tags.length&&(level=null,this.util.is_string(tag)&&(level=this.util.is_string(prop)?"full":"tag"),tag="."+tags[0].get_class(level),ret=this.dom_get().find(tag)),ret}}),Viewer=(View.Template=Viewer.extend(Template),{_slug:"template_tag",_reciprocal:!0,_attr_default:{name:null,prop:null,match:null},handlers:{},_c:function(tag_match){this.parse(tag_match)},parse:function(tag_match){if(!this.util.is_string(tag_match))return!1;var part,parts=tag_match.split("|");if(!parts.length)return null;var attrs={name:null,prop:null,match:tag_match};attrs.name=parts[0],-1!==attrs.name.indexOf(".")&&(attrs.name=attrs.name.split(".",2),attrs.prop=attrs.name[1],attrs.name=attrs.name[0]);for(var x=1;x<parts.length;x++)1<(part=parts[x].split(":",1)).length&&!(part[0]in attrs)&&(attrs[part[0]]=part[1]);this.set_attributes(attrs,!0)},render:function(item){var tag=this;return tag.get_handler().render(item,tag).pipe(function(output){return{tag:tag,output:output}})},get_name:function(){return this.get_attribute("name")},get_prop:function(){return this.get_attribute("prop")},get_handler:function(){return this.has_handler()?this.handlers[this.get_name()]:new View.Template_Tag_Handler("")},has_handler:function(){return this.get_name()in this.handlers},get_classes:function(rtype){var cls=[this.get_class(),this.get_class("tag"),this.get_class("full")];return cls=this.util.is_string(rtype)?cls.join(rtype):cls},get_class:function(level){var cls="";switch(level){case"tag":cls=this.get_name();break;case"full":for(var parts=[this.get_name(),this.get_prop()],a=[],i=0;i<parts.length;i++)this.util.is_string(parts[i])&&a.push(parts[i]);cls=a.join("_")}return this.util.is_string(cls)?this.add_ns(cls):this.get_ns()},get_selector:function(level){level=this.get_class(level);return level=this.util.is_string(level)?"."+level:""}}),Template=(View.Template_Tag=Component.extend(Viewer),{_slug:"template_tag_handler",_attr_default:{supports_modifiers:!1,dynamic:!1,props:{}},render:function(item,instance){var dfr=$.Deferred();return this.call_attribute("render",item,instance,dfr),dfr.promise()},add_prop:function(prop,fn){var a="props",props=this.get_attribute(a);if(!this.util.is_string(prop)||!this.util.is_func(fn))return!1;(props=this.util.is_obj(props,!1)?props:{})[prop]=fn,this.set_attribute(a,props)},handle_prop:function(prop,item,instance){var props=this.get_attribute("props");return this.util.is_obj(props)&&prop in props&&this.util.is_func(props[prop])?props[prop].call(this,item,instance):item.get_viewer().get_label(prop)}});View.Template_Tag_Handler=Component.extend(Template),View=SLB.attach("View",View)}(jQuery);
|
client/sass/admin.scss
CHANGED
@@ -1,54 +1,54 @@
|
|
1 |
-
.slb_section_head {
|
2 |
-
display: block;
|
3 |
-
padding: 2em 0 0;
|
4 |
-
}
|
5 |
-
|
6 |
-
.slb_option_item {
|
7 |
-
.block {
|
8 |
-
display: inline-block;
|
9 |
-
}
|
10 |
-
|
11 |
-
label.title {
|
12 |
-
width: 200px;
|
13 |
-
padding: 10px;
|
14 |
-
}
|
15 |
-
|
16 |
-
.input {
|
17 |
-
font-size: 11px;
|
18 |
-
line-height: 20px;
|
19 |
-
margin-bottom: 9px;
|
20 |
-
padding: 8px 10px;
|
21 |
-
}
|
22 |
-
|
23 |
-
.input select {
|
24 |
-
min-width: 12em;
|
25 |
-
}
|
26 |
-
}
|
27 |
-
|
28 |
-
.slb_notice {
|
29 |
-
color: #f00;
|
30 |
-
font-weight: bold;
|
31 |
-
}
|
32 |
-
|
33 |
-
.slb {
|
34 |
-
.columns-2 {
|
35 |
-
margin-right: 300px;
|
36 |
-
.postbox-container {
|
37 |
-
float: left;
|
38 |
-
width: 100%;
|
39 |
-
}
|
40 |
-
.content-secondary {
|
41 |
-
margin-right: -300px;
|
42 |
-
width: 280px;
|
43 |
-
float: right;
|
44 |
-
}
|
45 |
-
}
|
46 |
-
}
|
47 |
-
|
48 |
-
.slb_admin_action_reset {
|
49 |
-
color: #a00;
|
50 |
-
&:hover {
|
51 |
-
color: #dc3232;
|
52 |
-
border: none;
|
53 |
-
}
|
54 |
}
|
1 |
+
.slb_section_head {
|
2 |
+
display: block;
|
3 |
+
padding: 2em 0 0;
|
4 |
+
}
|
5 |
+
|
6 |
+
.slb_option_item {
|
7 |
+
.block {
|
8 |
+
display: inline-block;
|
9 |
+
}
|
10 |
+
|
11 |
+
label.title {
|
12 |
+
width: 200px;
|
13 |
+
padding: 10px;
|
14 |
+
}
|
15 |
+
|
16 |
+
.input {
|
17 |
+
font-size: 11px;
|
18 |
+
line-height: 20px;
|
19 |
+
margin-bottom: 9px;
|
20 |
+
padding: 8px 10px;
|
21 |
+
}
|
22 |
+
|
23 |
+
.input select {
|
24 |
+
min-width: 12em;
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
.slb_notice {
|
29 |
+
color: #f00;
|
30 |
+
font-weight: bold;
|
31 |
+
}
|
32 |
+
|
33 |
+
.slb {
|
34 |
+
.columns-2 {
|
35 |
+
margin-right: 300px;
|
36 |
+
.postbox-container {
|
37 |
+
float: left;
|
38 |
+
width: 100%;
|
39 |
+
}
|
40 |
+
.content-secondary {
|
41 |
+
margin-right: -300px;
|
42 |
+
width: 280px;
|
43 |
+
float: right;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
.slb_admin_action_reset {
|
49 |
+
color: #a00;
|
50 |
+
&:hover {
|
51 |
+
color: #dc3232;
|
52 |
+
border: none;
|
53 |
+
}
|
54 |
}
|
client/sass/app.scss
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
-
html.slb_overlay {
|
2 |
-
object,embed,iframe {
|
3 |
-
visibility: hidden;
|
4 |
-
}
|
5 |
-
#slb_viewer_wrap {
|
6 |
-
object,embed,iframe {
|
7 |
-
visibility: visible;
|
8 |
-
}
|
9 |
-
}
|
10 |
}
|
1 |
+
html.slb_overlay {
|
2 |
+
object,embed,iframe {
|
3 |
+
visibility: hidden;
|
4 |
+
}
|
5 |
+
#slb_viewer_wrap {
|
6 |
+
object,embed,iframe {
|
7 |
+
visibility: visible;
|
8 |
+
}
|
9 |
+
}
|
10 |
}
|
composer.json
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
{
|
2 |
-
"require-dev": {
|
3 |
-
"squizlabs/php_codesniffer": "^3.5",
|
4 |
-
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2",
|
5 |
-
"wp-coding-standards/wpcs": "^2.2",
|
6 |
-
"phpcompatibility/phpcompatibility-wp": "*"
|
7 |
-
}
|
8 |
-
}
|
1 |
+
{
|
2 |
+
"require-dev": {
|
3 |
+
"squizlabs/php_codesniffer": "^3.5",
|
4 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2",
|
5 |
+
"wp-coding-standards/wpcs": "^2.2",
|
6 |
+
"phpcompatibility/phpcompatibility-wp": "*"
|
7 |
+
}
|
8 |
+
}
|
composer.lock
CHANGED
@@ -1,340 +1,342 @@
|
|
1 |
-
{
|
2 |
-
"_readme": [
|
3 |
-
"This file locks the dependencies of your project to a known state",
|
4 |
-
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
5 |
-
"This file is @generated automatically"
|
6 |
-
],
|
7 |
-
"content-hash": "d58ae19bd7c4cf76ada3935405677c26",
|
8 |
-
"packages": [],
|
9 |
-
"packages-dev": [
|
10 |
-
{
|
11 |
-
"name": "dealerdirect/phpcodesniffer-composer-installer",
|
12 |
-
"version": "v0.6.2",
|
13 |
-
"source": {
|
14 |
-
"type": "git",
|
15 |
-
"url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
|
16 |
-
"reference": "8001af8eb107fbfcedc31a8b51e20b07d85b457a"
|
17 |
-
},
|
18 |
-
"dist": {
|
19 |
-
"type": "zip",
|
20 |
-
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/8001af8eb107fbfcedc31a8b51e20b07d85b457a",
|
21 |
-
"reference": "8001af8eb107fbfcedc31a8b51e20b07d85b457a",
|
22 |
-
"shasum": ""
|
23 |
-
},
|
24 |
-
"require": {
|
25 |
-
"composer-plugin-api": "^1.0",
|
26 |
-
"php": "^5.3|^7",
|
27 |
-
"squizlabs/php_codesniffer": "^2|^3"
|
28 |
-
},
|
29 |
-
"require-dev": {
|
30 |
-
"composer/composer": "*",
|
31 |
-
"phpcompatibility/php-compatibility": "^9.0",
|
32 |
-
"sensiolabs/security-checker": "^4.1.0"
|
33 |
-
},
|
34 |
-
"type": "composer-plugin",
|
35 |
-
"extra": {
|
36 |
-
"class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
|
37 |
-
},
|
38 |
-
"autoload": {
|
39 |
-
"psr-4": {
|
40 |
-
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
|
41 |
-
}
|
42 |
-
},
|
43 |
-
"notification-url": "https://packagist.org/downloads/",
|
44 |
-
"license": [
|
45 |
-
"MIT"
|
46 |
-
],
|
47 |
-
"authors": [
|
48 |
-
{
|
49 |
-
"name": "Franck Nijhof",
|
50 |
-
"email": "franck.nijhof@dealerdirect.com",
|
51 |
-
"homepage": "http://www.frenck.nl",
|
52 |
-
"role": "Developer / IT Manager"
|
53 |
-
}
|
54 |
-
],
|
55 |
-
"description": "PHP_CodeSniffer Standards Composer Installer Plugin",
|
56 |
-
"homepage": "http://www.dealerdirect.com",
|
57 |
-
"keywords": [
|
58 |
-
"PHPCodeSniffer",
|
59 |
-
"PHP_CodeSniffer",
|
60 |
-
"code quality",
|
61 |
-
"codesniffer",
|
62 |
-
"composer",
|
63 |
-
"installer",
|
64 |
-
"phpcs",
|
65 |
-
"plugin",
|
66 |
-
"qa",
|
67 |
-
"quality",
|
68 |
-
"standard",
|
69 |
-
"standards",
|
70 |
-
"style guide",
|
71 |
-
"stylecheck",
|
72 |
-
"tests"
|
73 |
-
],
|
74 |
-
"time": "2020-01-29T20:22:20+00:00"
|
75 |
-
},
|
76 |
-
{
|
77 |
-
"name": "phpcompatibility/php-compatibility",
|
78 |
-
"version": "9.3.5",
|
79 |
-
"source": {
|
80 |
-
"type": "git",
|
81 |
-
"url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
|
82 |
-
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243"
|
83 |
-
},
|
84 |
-
"dist": {
|
85 |
-
"type": "zip",
|
86 |
-
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243",
|
87 |
-
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243",
|
88 |
-
"shasum": ""
|
89 |
-
},
|
90 |
-
"require": {
|
91 |
-
"php": ">=5.3",
|
92 |
-
"squizlabs/php_codesniffer": "^2.3 || ^3.0.2"
|
93 |
-
},
|
94 |
-
"conflict": {
|
95 |
-
"squizlabs/php_codesniffer": "2.6.2"
|
96 |
-
},
|
97 |
-
"require-dev": {
|
98 |
-
"phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0"
|
99 |
-
},
|
100 |
-
"suggest": {
|
101 |
-
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.",
|
102 |
-
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
|
103 |
-
},
|
104 |
-
"type": "phpcodesniffer-standard",
|
105 |
-
"notification-url": "https://packagist.org/downloads/",
|
106 |
-
"license": [
|
107 |
-
"LGPL-3.0-or-later"
|
108 |
-
],
|
109 |
-
"authors": [
|
110 |
-
{
|
111 |
-
"name": "Wim Godden",
|
112 |
-
"homepage": "https://github.com/wimg",
|
113 |
-
"role": "lead"
|
114 |
-
},
|
115 |
-
{
|
116 |
-
"name": "Juliette Reinders Folmer",
|
117 |
-
"homepage": "https://github.com/jrfnl",
|
118 |
-
"role": "lead"
|
119 |
-
},
|
120 |
-
{
|
121 |
-
"name": "Contributors",
|
122 |
-
"homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors"
|
123 |
-
}
|
124 |
-
],
|
125 |
-
"description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.",
|
126 |
-
"homepage": "http://techblog.wimgodden.be/tag/codesniffer/",
|
127 |
-
"keywords": [
|
128 |
-
"compatibility",
|
129 |
-
"phpcs",
|
130 |
-
"standards"
|
131 |
-
],
|
132 |
-
"time": "2019-12-27T09:44:58+00:00"
|
133 |
-
},
|
134 |
-
{
|
135 |
-
"name": "phpcompatibility/phpcompatibility-paragonie",
|
136 |
-
"version": "1.3.0",
|
137 |
-
"source": {
|
138 |
-
"type": "git",
|
139 |
-
"url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git",
|
140 |
-
"reference": "b862bc32f7e860d0b164b199bd995e690b4b191c"
|
141 |
-
},
|
142 |
-
"dist": {
|
143 |
-
"type": "zip",
|
144 |
-
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b862bc32f7e860d0b164b199bd995e690b4b191c",
|
145 |
-
"reference": "b862bc32f7e860d0b164b199bd995e690b4b191c",
|
146 |
-
"shasum": ""
|
147 |
-
},
|
148 |
-
"require": {
|
149 |
-
"phpcompatibility/php-compatibility": "^9.0"
|
150 |
-
},
|
151 |
-
"require-dev": {
|
152 |
-
"dealerdirect/phpcodesniffer-composer-installer": "^0.5",
|
153 |
-
"paragonie/random_compat": "dev-master",
|
154 |
-
"paragonie/sodium_compat": "dev-master"
|
155 |
-
},
|
156 |
-
"suggest": {
|
157 |
-
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
|
158 |
-
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
|
159 |
-
},
|
160 |
-
"type": "phpcodesniffer-standard",
|
161 |
-
"notification-url": "https://packagist.org/downloads/",
|
162 |
-
"license": [
|
163 |
-
"LGPL-3.0-or-later"
|
164 |
-
],
|
165 |
-
"authors": [
|
166 |
-
{
|
167 |
-
"name": "Wim Godden",
|
168 |
-
"role": "lead"
|
169 |
-
},
|
170 |
-
{
|
171 |
-
"name": "Juliette Reinders Folmer",
|
172 |
-
"role": "lead"
|
173 |
-
}
|
174 |
-
],
|
175 |
-
"description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.",
|
176 |
-
"homepage": "http://phpcompatibility.com/",
|
177 |
-
"keywords": [
|
178 |
-
"compatibility",
|
179 |
-
"paragonie",
|
180 |
-
"phpcs",
|
181 |
-
"polyfill",
|
182 |
-
"standards"
|
183 |
-
],
|
184 |
-
"time": "2019-11-04T15:17:54+00:00"
|
185 |
-
},
|
186 |
-
{
|
187 |
-
"name": "phpcompatibility/phpcompatibility-wp",
|
188 |
-
"version": "2.1.0",
|
189 |
-
"source": {
|
190 |
-
"type": "git",
|
191 |
-
"url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git",
|
192 |
-
"reference": "41bef18ba688af638b7310666db28e1ea9158b2f"
|
193 |
-
},
|
194 |
-
"dist": {
|
195 |
-
"type": "zip",
|
196 |
-
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/41bef18ba688af638b7310666db28e1ea9158b2f",
|
197 |
-
"reference": "41bef18ba688af638b7310666db28e1ea9158b2f",
|
198 |
-
"shasum": ""
|
199 |
-
},
|
200 |
-
"require": {
|
201 |
-
"phpcompatibility/php-compatibility": "^9.0",
|
202 |
-
"phpcompatibility/phpcompatibility-paragonie": "^1.0"
|
203 |
-
},
|
204 |
-
"require-dev": {
|
205 |
-
"dealerdirect/phpcodesniffer-composer-installer": "^0.5"
|
206 |
-
},
|
207 |
-
"suggest": {
|
208 |
-
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
|
209 |
-
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
|
210 |
-
},
|
211 |
-
"type": "phpcodesniffer-standard",
|
212 |
-
"notification-url": "https://packagist.org/downloads/",
|
213 |
-
"license": [
|
214 |
-
"LGPL-3.0-or-later"
|
215 |
-
],
|
216 |
-
"authors": [
|
217 |
-
{
|
218 |
-
"name": "Wim Godden",
|
219 |
-
"role": "lead"
|
220 |
-
},
|
221 |
-
{
|
222 |
-
"name": "Juliette Reinders Folmer",
|
223 |
-
"role": "lead"
|
224 |
-
}
|
225 |
-
],
|
226 |
-
"description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.",
|
227 |
-
"homepage": "http://phpcompatibility.com/",
|
228 |
-
"keywords": [
|
229 |
-
"compatibility",
|
230 |
-
"phpcs",
|
231 |
-
"standards",
|
232 |
-
"wordpress"
|
233 |
-
],
|
234 |
-
"time": "2019-08-28T14:22:28+00:00"
|
235 |
-
},
|
236 |
-
{
|
237 |
-
"name": "squizlabs/php_codesniffer",
|
238 |
-
"version": "3.5.
|
239 |
-
"source": {
|
240 |
-
"type": "git",
|
241 |
-
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
242 |
-
"reference": "
|
243 |
-
},
|
244 |
-
"dist": {
|
245 |
-
"type": "zip",
|
246 |
-
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/
|
247 |
-
"reference": "
|
248 |
-
"shasum": ""
|
249 |
-
},
|
250 |
-
"require": {
|
251 |
-
"ext-simplexml": "*",
|
252 |
-
"ext-tokenizer": "*",
|
253 |
-
"ext-xmlwriter": "*",
|
254 |
-
"php": ">=5.4.0"
|
255 |
-
},
|
256 |
-
"require-dev": {
|
257 |
-
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
258 |
-
},
|
259 |
-
"bin": [
|
260 |
-
"bin/phpcs",
|
261 |
-
"bin/phpcbf"
|
262 |
-
],
|
263 |
-
"type": "library",
|
264 |
-
"extra": {
|
265 |
-
"branch-alias": {
|
266 |
-
"dev-master": "3.x-dev"
|
267 |
-
}
|
268 |
-
},
|
269 |
-
"notification-url": "https://packagist.org/downloads/",
|
270 |
-
"license": [
|
271 |
-
"BSD-3-Clause"
|
272 |
-
],
|
273 |
-
"authors": [
|
274 |
-
{
|
275 |
-
"name": "Greg Sherwood",
|
276 |
-
"role": "lead"
|
277 |
-
}
|
278 |
-
],
|
279 |
-
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
280 |
-
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
|
281 |
-
"keywords": [
|
282 |
-
"phpcs",
|
283 |
-
"standards"
|
284 |
-
],
|
285 |
-
"time": "2020-
|
286 |
-
},
|
287 |
-
{
|
288 |
-
"name": "wp-coding-standards/wpcs",
|
289 |
-
"version": "2.
|
290 |
-
"source": {
|
291 |
-
"type": "git",
|
292 |
-
"url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
|
293 |
-
"reference": "
|
294 |
-
},
|
295 |
-
"dist": {
|
296 |
-
"type": "zip",
|
297 |
-
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/
|
298 |
-
"reference": "
|
299 |
-
"shasum": ""
|
300 |
-
},
|
301 |
-
"require": {
|
302 |
-
"php": ">=5.4",
|
303 |
-
"squizlabs/php_codesniffer": "^3.3.1"
|
304 |
-
},
|
305 |
-
"require-dev": {
|
306 |
-
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
|
307 |
-
"phpcompatibility/php-compatibility": "^9.0",
|
308 |
-
"
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
"
|
315 |
-
"
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
"
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
"
|
326 |
-
|
327 |
-
"
|
328 |
-
"
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
"
|
335 |
-
"stability
|
336 |
-
"
|
337 |
-
"prefer-
|
338 |
-
"
|
339 |
-
"platform
|
340 |
-
|
|
|
|
1 |
+
{
|
2 |
+
"_readme": [
|
3 |
+
"This file locks the dependencies of your project to a known state",
|
4 |
+
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
5 |
+
"This file is @generated automatically"
|
6 |
+
],
|
7 |
+
"content-hash": "d58ae19bd7c4cf76ada3935405677c26",
|
8 |
+
"packages": [],
|
9 |
+
"packages-dev": [
|
10 |
+
{
|
11 |
+
"name": "dealerdirect/phpcodesniffer-composer-installer",
|
12 |
+
"version": "v0.6.2",
|
13 |
+
"source": {
|
14 |
+
"type": "git",
|
15 |
+
"url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
|
16 |
+
"reference": "8001af8eb107fbfcedc31a8b51e20b07d85b457a"
|
17 |
+
},
|
18 |
+
"dist": {
|
19 |
+
"type": "zip",
|
20 |
+
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/8001af8eb107fbfcedc31a8b51e20b07d85b457a",
|
21 |
+
"reference": "8001af8eb107fbfcedc31a8b51e20b07d85b457a",
|
22 |
+
"shasum": ""
|
23 |
+
},
|
24 |
+
"require": {
|
25 |
+
"composer-plugin-api": "^1.0",
|
26 |
+
"php": "^5.3|^7",
|
27 |
+
"squizlabs/php_codesniffer": "^2|^3"
|
28 |
+
},
|
29 |
+
"require-dev": {
|
30 |
+
"composer/composer": "*",
|
31 |
+
"phpcompatibility/php-compatibility": "^9.0",
|
32 |
+
"sensiolabs/security-checker": "^4.1.0"
|
33 |
+
},
|
34 |
+
"type": "composer-plugin",
|
35 |
+
"extra": {
|
36 |
+
"class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
|
37 |
+
},
|
38 |
+
"autoload": {
|
39 |
+
"psr-4": {
|
40 |
+
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
|
41 |
+
}
|
42 |
+
},
|
43 |
+
"notification-url": "https://packagist.org/downloads/",
|
44 |
+
"license": [
|
45 |
+
"MIT"
|
46 |
+
],
|
47 |
+
"authors": [
|
48 |
+
{
|
49 |
+
"name": "Franck Nijhof",
|
50 |
+
"email": "franck.nijhof@dealerdirect.com",
|
51 |
+
"homepage": "http://www.frenck.nl",
|
52 |
+
"role": "Developer / IT Manager"
|
53 |
+
}
|
54 |
+
],
|
55 |
+
"description": "PHP_CodeSniffer Standards Composer Installer Plugin",
|
56 |
+
"homepage": "http://www.dealerdirect.com",
|
57 |
+
"keywords": [
|
58 |
+
"PHPCodeSniffer",
|
59 |
+
"PHP_CodeSniffer",
|
60 |
+
"code quality",
|
61 |
+
"codesniffer",
|
62 |
+
"composer",
|
63 |
+
"installer",
|
64 |
+
"phpcs",
|
65 |
+
"plugin",
|
66 |
+
"qa",
|
67 |
+
"quality",
|
68 |
+
"standard",
|
69 |
+
"standards",
|
70 |
+
"style guide",
|
71 |
+
"stylecheck",
|
72 |
+
"tests"
|
73 |
+
],
|
74 |
+
"time": "2020-01-29T20:22:20+00:00"
|
75 |
+
},
|
76 |
+
{
|
77 |
+
"name": "phpcompatibility/php-compatibility",
|
78 |
+
"version": "9.3.5",
|
79 |
+
"source": {
|
80 |
+
"type": "git",
|
81 |
+
"url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
|
82 |
+
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243"
|
83 |
+
},
|
84 |
+
"dist": {
|
85 |
+
"type": "zip",
|
86 |
+
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243",
|
87 |
+
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243",
|
88 |
+
"shasum": ""
|
89 |
+
},
|
90 |
+
"require": {
|
91 |
+
"php": ">=5.3",
|
92 |
+
"squizlabs/php_codesniffer": "^2.3 || ^3.0.2"
|
93 |
+
},
|
94 |
+
"conflict": {
|
95 |
+
"squizlabs/php_codesniffer": "2.6.2"
|
96 |
+
},
|
97 |
+
"require-dev": {
|
98 |
+
"phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0"
|
99 |
+
},
|
100 |
+
"suggest": {
|
101 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.",
|
102 |
+
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
|
103 |
+
},
|
104 |
+
"type": "phpcodesniffer-standard",
|
105 |
+
"notification-url": "https://packagist.org/downloads/",
|
106 |
+
"license": [
|
107 |
+
"LGPL-3.0-or-later"
|
108 |
+
],
|
109 |
+
"authors": [
|
110 |
+
{
|
111 |
+
"name": "Wim Godden",
|
112 |
+
"homepage": "https://github.com/wimg",
|
113 |
+
"role": "lead"
|
114 |
+
},
|
115 |
+
{
|
116 |
+
"name": "Juliette Reinders Folmer",
|
117 |
+
"homepage": "https://github.com/jrfnl",
|
118 |
+
"role": "lead"
|
119 |
+
},
|
120 |
+
{
|
121 |
+
"name": "Contributors",
|
122 |
+
"homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors"
|
123 |
+
}
|
124 |
+
],
|
125 |
+
"description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.",
|
126 |
+
"homepage": "http://techblog.wimgodden.be/tag/codesniffer/",
|
127 |
+
"keywords": [
|
128 |
+
"compatibility",
|
129 |
+
"phpcs",
|
130 |
+
"standards"
|
131 |
+
],
|
132 |
+
"time": "2019-12-27T09:44:58+00:00"
|
133 |
+
},
|
134 |
+
{
|
135 |
+
"name": "phpcompatibility/phpcompatibility-paragonie",
|
136 |
+
"version": "1.3.0",
|
137 |
+
"source": {
|
138 |
+
"type": "git",
|
139 |
+
"url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git",
|
140 |
+
"reference": "b862bc32f7e860d0b164b199bd995e690b4b191c"
|
141 |
+
},
|
142 |
+
"dist": {
|
143 |
+
"type": "zip",
|
144 |
+
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b862bc32f7e860d0b164b199bd995e690b4b191c",
|
145 |
+
"reference": "b862bc32f7e860d0b164b199bd995e690b4b191c",
|
146 |
+
"shasum": ""
|
147 |
+
},
|
148 |
+
"require": {
|
149 |
+
"phpcompatibility/php-compatibility": "^9.0"
|
150 |
+
},
|
151 |
+
"require-dev": {
|
152 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5",
|
153 |
+
"paragonie/random_compat": "dev-master",
|
154 |
+
"paragonie/sodium_compat": "dev-master"
|
155 |
+
},
|
156 |
+
"suggest": {
|
157 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
|
158 |
+
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
|
159 |
+
},
|
160 |
+
"type": "phpcodesniffer-standard",
|
161 |
+
"notification-url": "https://packagist.org/downloads/",
|
162 |
+
"license": [
|
163 |
+
"LGPL-3.0-or-later"
|
164 |
+
],
|
165 |
+
"authors": [
|
166 |
+
{
|
167 |
+
"name": "Wim Godden",
|
168 |
+
"role": "lead"
|
169 |
+
},
|
170 |
+
{
|
171 |
+
"name": "Juliette Reinders Folmer",
|
172 |
+
"role": "lead"
|
173 |
+
}
|
174 |
+
],
|
175 |
+
"description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.",
|
176 |
+
"homepage": "http://phpcompatibility.com/",
|
177 |
+
"keywords": [
|
178 |
+
"compatibility",
|
179 |
+
"paragonie",
|
180 |
+
"phpcs",
|
181 |
+
"polyfill",
|
182 |
+
"standards"
|
183 |
+
],
|
184 |
+
"time": "2019-11-04T15:17:54+00:00"
|
185 |
+
},
|
186 |
+
{
|
187 |
+
"name": "phpcompatibility/phpcompatibility-wp",
|
188 |
+
"version": "2.1.0",
|
189 |
+
"source": {
|
190 |
+
"type": "git",
|
191 |
+
"url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git",
|
192 |
+
"reference": "41bef18ba688af638b7310666db28e1ea9158b2f"
|
193 |
+
},
|
194 |
+
"dist": {
|
195 |
+
"type": "zip",
|
196 |
+
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/41bef18ba688af638b7310666db28e1ea9158b2f",
|
197 |
+
"reference": "41bef18ba688af638b7310666db28e1ea9158b2f",
|
198 |
+
"shasum": ""
|
199 |
+
},
|
200 |
+
"require": {
|
201 |
+
"phpcompatibility/php-compatibility": "^9.0",
|
202 |
+
"phpcompatibility/phpcompatibility-paragonie": "^1.0"
|
203 |
+
},
|
204 |
+
"require-dev": {
|
205 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5"
|
206 |
+
},
|
207 |
+
"suggest": {
|
208 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
|
209 |
+
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
|
210 |
+
},
|
211 |
+
"type": "phpcodesniffer-standard",
|
212 |
+
"notification-url": "https://packagist.org/downloads/",
|
213 |
+
"license": [
|
214 |
+
"LGPL-3.0-or-later"
|
215 |
+
],
|
216 |
+
"authors": [
|
217 |
+
{
|
218 |
+
"name": "Wim Godden",
|
219 |
+
"role": "lead"
|
220 |
+
},
|
221 |
+
{
|
222 |
+
"name": "Juliette Reinders Folmer",
|
223 |
+
"role": "lead"
|
224 |
+
}
|
225 |
+
],
|
226 |
+
"description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.",
|
227 |
+
"homepage": "http://phpcompatibility.com/",
|
228 |
+
"keywords": [
|
229 |
+
"compatibility",
|
230 |
+
"phpcs",
|
231 |
+
"standards",
|
232 |
+
"wordpress"
|
233 |
+
],
|
234 |
+
"time": "2019-08-28T14:22:28+00:00"
|
235 |
+
},
|
236 |
+
{
|
237 |
+
"name": "squizlabs/php_codesniffer",
|
238 |
+
"version": "3.5.5",
|
239 |
+
"source": {
|
240 |
+
"type": "git",
|
241 |
+
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
242 |
+
"reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6"
|
243 |
+
},
|
244 |
+
"dist": {
|
245 |
+
"type": "zip",
|
246 |
+
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
|
247 |
+
"reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
|
248 |
+
"shasum": ""
|
249 |
+
},
|
250 |
+
"require": {
|
251 |
+
"ext-simplexml": "*",
|
252 |
+
"ext-tokenizer": "*",
|
253 |
+
"ext-xmlwriter": "*",
|
254 |
+
"php": ">=5.4.0"
|
255 |
+
},
|
256 |
+
"require-dev": {
|
257 |
+
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
258 |
+
},
|
259 |
+
"bin": [
|
260 |
+
"bin/phpcs",
|
261 |
+
"bin/phpcbf"
|
262 |
+
],
|
263 |
+
"type": "library",
|
264 |
+
"extra": {
|
265 |
+
"branch-alias": {
|
266 |
+
"dev-master": "3.x-dev"
|
267 |
+
}
|
268 |
+
},
|
269 |
+
"notification-url": "https://packagist.org/downloads/",
|
270 |
+
"license": [
|
271 |
+
"BSD-3-Clause"
|
272 |
+
],
|
273 |
+
"authors": [
|
274 |
+
{
|
275 |
+
"name": "Greg Sherwood",
|
276 |
+
"role": "lead"
|
277 |
+
}
|
278 |
+
],
|
279 |
+
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
280 |
+
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
|
281 |
+
"keywords": [
|
282 |
+
"phpcs",
|
283 |
+
"standards"
|
284 |
+
],
|
285 |
+
"time": "2020-04-17T01:09:41+00:00"
|
286 |
+
},
|
287 |
+
{
|
288 |
+
"name": "wp-coding-standards/wpcs",
|
289 |
+
"version": "2.3.0",
|
290 |
+
"source": {
|
291 |
+
"type": "git",
|
292 |
+
"url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
|
293 |
+
"reference": "7da1894633f168fe244afc6de00d141f27517b62"
|
294 |
+
},
|
295 |
+
"dist": {
|
296 |
+
"type": "zip",
|
297 |
+
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62",
|
298 |
+
"reference": "7da1894633f168fe244afc6de00d141f27517b62",
|
299 |
+
"shasum": ""
|
300 |
+
},
|
301 |
+
"require": {
|
302 |
+
"php": ">=5.4",
|
303 |
+
"squizlabs/php_codesniffer": "^3.3.1"
|
304 |
+
},
|
305 |
+
"require-dev": {
|
306 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
|
307 |
+
"phpcompatibility/php-compatibility": "^9.0",
|
308 |
+
"phpcsstandards/phpcsdevtools": "^1.0",
|
309 |
+
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
310 |
+
},
|
311 |
+
"suggest": {
|
312 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
|
313 |
+
},
|
314 |
+
"type": "phpcodesniffer-standard",
|
315 |
+
"notification-url": "https://packagist.org/downloads/",
|
316 |
+
"license": [
|
317 |
+
"MIT"
|
318 |
+
],
|
319 |
+
"authors": [
|
320 |
+
{
|
321 |
+
"name": "Contributors",
|
322 |
+
"homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
|
323 |
+
}
|
324 |
+
],
|
325 |
+
"description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
|
326 |
+
"keywords": [
|
327 |
+
"phpcs",
|
328 |
+
"standards",
|
329 |
+
"wordpress"
|
330 |
+
],
|
331 |
+
"time": "2020-05-13T23:57:56+00:00"
|
332 |
+
}
|
333 |
+
],
|
334 |
+
"aliases": [],
|
335 |
+
"minimum-stability": "stable",
|
336 |
+
"stability-flags": [],
|
337 |
+
"prefer-stable": false,
|
338 |
+
"prefer-lowest": false,
|
339 |
+
"platform": [],
|
340 |
+
"platform-dev": [],
|
341 |
+
"plugin-api-version": "1.1.0"
|
342 |
+
}
|
content-handlers/image/js/dev/handler.image.js
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
if ( !!window.SLB && SLB.has_child('View.extend_content_handler') ) {(function($) {
|
2 |
-
SLB.View.extend_content_handler('image', {
|
3 |
-
/**
|
4 |
-
* Render images
|
5 |
-
* @param obj item Content Item
|
6 |
-
* @param obj dfr Promise for rendering process
|
7 |
-
* @return obj Promise for rendering process (Resolved when content is loaded)
|
8 |
-
*/
|
9 |
-
render: function(item, dfr) {
|
10 |
-
// Create image object
|
11 |
-
var img = new Image();
|
12 |
-
// Set load event
|
13 |
-
var handler = function() {
|
14 |
-
// Save Data
|
15 |
-
item.set_data(img);
|
16 |
-
// Set attributes
|
17 |
-
item.set_attribute('dimensions', {'width': img.width, 'height': img.height});
|
18 |
-
// Build output
|
19 |
-
var out = $('<img />', {'src': item.get_uri()});
|
20 |
-
// Resolve deferred
|
21 |
-
dfr.resolve(out);
|
22 |
-
};
|
23 |
-
|
24 |
-
// Attach event handler
|
25 |
-
$(img).on('load', function(e) { handler(e); });
|
26 |
-
// Load image
|
27 |
-
img.src = item.get_uri();
|
28 |
-
// Return promise
|
29 |
-
return dfr.promise();
|
30 |
-
}
|
31 |
-
});
|
32 |
-
})(jQuery);
|
33 |
}
|
1 |
+
if ( !!window.SLB && SLB.has_child('View.extend_content_handler') ) {(function($) {
|
2 |
+
SLB.View.extend_content_handler('image', {
|
3 |
+
/**
|
4 |
+
* Render images
|
5 |
+
* @param obj item Content Item
|
6 |
+
* @param obj dfr Promise for rendering process
|
7 |
+
* @return obj Promise for rendering process (Resolved when content is loaded)
|
8 |
+
*/
|
9 |
+
render: function(item, dfr) {
|
10 |
+
// Create image object
|
11 |
+
var img = new Image();
|
12 |
+
// Set load event
|
13 |
+
var handler = function() {
|
14 |
+
// Save Data
|
15 |
+
item.set_data(img);
|
16 |
+
// Set attributes
|
17 |
+
item.set_attribute('dimensions', {'width': img.width, 'height': img.height});
|
18 |
+
// Build output
|
19 |
+
var out = $('<img />', {'src': item.get_uri()});
|
20 |
+
// Resolve deferred
|
21 |
+
dfr.resolve(out);
|
22 |
+
};
|
23 |
+
|
24 |
+
// Attach event handler
|
25 |
+
$(img).on('load', function(e) { handler(e); });
|
26 |
+
// Load image
|
27 |
+
img.src = item.get_uri();
|
28 |
+
// Return promise
|
29 |
+
return dfr.promise();
|
30 |
+
}
|
31 |
+
});
|
32 |
+
})(jQuery);
|
33 |
}
|
content-handlers/image/js/prod/handler.image.js
CHANGED
@@ -1 +1 @@
|
|
1 |
-
window.SLB&&SLB.has_child("View.extend_content_handler")
|
1 |
+
window.SLB&&SLB.has_child("View.extend_content_handler")&&!function($){SLB.View.extend_content_handler("image",{render:function(item,dfr){var img=new Image;return $(img).on("load",function(e){var out;item.set_data(img),item.set_attribute("dimensions",{width:img.width,height:img.height}),out=$("<img />",{src:item.get_uri()}),dfr.resolve(out)}),img.src=item.get_uri(),dfr.promise()}})}(jQuery);
|
controller.php
CHANGED
@@ -1,1705 +1,1891 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Controller
|
4 |
-
* @package Simple Lightbox
|
5 |
-
* @author Archetyped
|
6 |
-
*/
|
7 |
-
class SLB_Lightbox extends SLB_Base {
|
8 |
-
|
9 |
-
/*-** Properties **-*/
|
10 |
-
|
11 |
-
protected $model = true;
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Fields
|
15 |
-
* @var SLB_Fields
|
16 |
-
*/
|
17 |
-
public $fields = null;
|
18 |
-
|
19 |
-
/**
|
20 |
-
* Themes collection
|
21 |
-
* @var SLB_Themes
|
22 |
-
*/
|
23 |
-
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Content types
|
27 |
-
* @var SLB_Content_Handlers
|
28 |
-
*/
|
29 |
-
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Template tags
|
33 |
-
* @var SLB_Template_Tags
|
34 |
-
*/
|
35 |
-
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Media item template.
|
39 |
-
*
|
40 |
-
* @var array {
|
41 |
-
* Media item properties.
|
42 |
-
*
|
43 |
-
* @type int $id WP post ID. Default null.
|
44 |
-
* @type string $type Item type. Default null.
|
45 |
-
* @type string $source Source URI.
|
46 |
-
* @type bool $internal Internal resource. Default false.
|
47 |
-
* @type string $title Item title.
|
48 |
-
* @type string $caption Item caption.
|
49 |
-
* @type string $description Item description.
|
50 |
-
* @type array $media {
|
51 |
-
* Media properties (indexed by size name).
|
52 |
-
* Original size = 'full'.
|
53 |
-
*
|
54 |
-
* @type string $file File URI.
|
55 |
-
* @type int $width File width in pixels.
|
56 |
-
* @type int $height File height in pixels.
|
57 |
-
* }
|
58 |
-
* @type array $meta {
|
59 |
-
* Item metadata.
|
60 |
-
* }
|
61 |
-
* }
|
62 |
-
*/
|
63 |
-
private $media_item_template = [
|
64 |
-
'id'
|
65 |
-
'type'
|
66 |
-
'internal' => false,
|
67 |
-
'source'
|
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 |
-
$this->
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
*
|
173 |
-
* @
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
$js_path
|
178 |
-
$
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
'
|
183 |
-
'
|
184 |
-
'
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
'
|
189 |
-
'
|
190 |
-
'
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
'
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
);
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
*
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
*
|
221 |
-
*/
|
222 |
-
public function _hooks_init() {
|
223 |
-
if ( $this->is_enabled() ) {
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
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 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
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 |
-
|
351 |
-
|
352 |
-
'
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
if ( empty($
|
563 |
-
$
|
564 |
-
}
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
'
|
570 |
-
'
|
571 |
-
'
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
$
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
return $content;
|
717 |
-
}
|
718 |
-
|
719 |
-
/**
|
720 |
-
*
|
721 |
-
* @
|
722 |
-
* @
|
723 |
-
* @
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
$links = $
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
$
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
|
865 |
-
|
866 |
-
|
867 |
-
|
868 |
-
|
869 |
-
|
870 |
-
|
871 |
-
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
876 |
-
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
-
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
//
|
991 |
-
$
|
992 |
-
|
993 |
-
|
994 |
-
|
995 |
-
|
996 |
-
|
997 |
-
|
998 |
-
|
999 |
-
|
1000 |
-
|
1001 |
-
|
1002 |
-
|
1003 |
-
|
1004 |
-
|
1005 |
-
*
|
1006 |
-
*
|
1007 |
-
* @
|
1008 |
-
* @
|
1009 |
-
*/
|
1010 |
-
|
1011 |
-
|
1012 |
-
|
1013 |
-
|
1014 |
-
|
1015 |
-
//
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
-
|
1020 |
-
|
1021 |
-
|
1022 |
-
|
1023 |
-
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
|
1028 |
-
$
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
|
1040 |
-
|
1041 |
-
|
1042 |
-
|
1043 |
-
|
1044 |
-
|
1045 |
-
|
1046 |
-
|
1047 |
-
|
1048 |
-
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
|
1061 |
-
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
|
1069 |
-
|
1070 |
-
|
1071 |
-
|
1072 |
-
|
1073 |
-
|
1074 |
-
|
1075 |
-
|
1076 |
-
|
1077 |
-
|
1078 |
-
|
1079 |
-
|
1080 |
-
|
1081 |
-
|
1082 |
-
|
1083 |
-
|
1084 |
-
|
1085 |
-
|
1086 |
-
|
1087 |
-
|
1088 |
-
|
1089 |
-
|
1090 |
-
|
1091 |
-
|
1092 |
-
|
1093 |
-
|
1094 |
-
|
1095 |
-
|
1096 |
-
|
1097 |
-
|
1098 |
-
|
1099 |
-
|
1100 |
-
|
1101 |
-
|
1102 |
-
|
1103 |
-
|
1104 |
-
|
1105 |
-
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
|
1128 |
-
|
1129 |
-
|
1130 |
-
|
1131 |
-
|
1132 |
-
|
1133 |
-
|
1134 |
-
|
1135 |
-
|
1136 |
-
|
1137 |
-
|
1138 |
-
|
1139 |
-
|
1140 |
-
|
1141 |
-
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
1156 |
-
|
1157 |
-
|
1158 |
-
|
1159 |
-
|
1160 |
-
|
1161 |
-
|
1162 |
-
|
1163 |
-
|
1164 |
-
|
1165 |
-
|
1166 |
-
|
1167 |
-
|
1168 |
-
|
1169 |
-
|
1170 |
-
|
1171 |
-
|
1172 |
-
}
|
1173 |
-
|
1174 |
-
|
1175 |
-
|
1176 |
-
|
1177 |
-
|
1178 |
-
|
1179 |
-
|
1180 |
-
|
1181 |
-
|
1182 |
-
|
1183 |
-
|
1184 |
-
|
1185 |
-
|
1186 |
-
|
1187 |
-
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
|
1195 |
-
|
1196 |
-
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
|
1201 |
-
|
1202 |
-
|
1203 |
-
|
1204 |
-
|
1205 |
-
|
1206 |
-
|
1207 |
-
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
1216 |
-
|
1217 |
-
|
1218 |
-
|
1219 |
-
|
1220 |
-
|
1221 |
-
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
1225 |
-
|
1226 |
-
|
1227 |
-
|
1228 |
-
|
1229 |
-
|
1230 |
-
|
1231 |
-
|
1232 |
-
|
1233 |
-
|
1234 |
-
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
1238 |
-
*
|
1239 |
-
* @
|
1240 |
-
|
1241 |
-
|
1242 |
-
|
1243 |
-
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
1247 |
-
|
1248 |
-
|
1249 |
-
|
1250 |
-
|
1251 |
-
|
1252 |
-
|
1253 |
-
|
1254 |
-
|
1255 |
-
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
1259 |
-
|
1260 |
-
|
1261 |
-
|
1262 |
-
|
1263 |
-
|
1264 |
-
|
1265 |
-
|
1266 |
-
|
1267 |
-
|
1268 |
-
|
1269 |
-
|
1270 |
-
|
1271 |
-
|
1272 |
-
|
1273 |
-
|
1274 |
-
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
-
|
1280 |
-
|
1281 |
-
|
1282 |
-
$
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
-
|
1287 |
-
|
1288 |
-
|
1289 |
-
|
1290 |
-
|
1291 |
-
|
1292 |
-
|
1293 |
-
|
1294 |
-
|
1295 |
-
|
1296 |
-
|
1297 |
-
|
1298 |
-
|
1299 |
-
|
1300 |
-
|
1301 |
-
|
1302 |
-
return $
|
1303 |
-
}
|
1304 |
-
|
1305 |
-
|
1306 |
-
|
1307 |
-
|
1308 |
-
*
|
1309 |
-
*
|
1310 |
-
|
1311 |
-
|
1312 |
-
|
1313 |
-
|
1314 |
-
|
1315 |
-
|
1316 |
-
|
1317 |
-
|
1318 |
-
|
1319 |
-
|
1320 |
-
|
1321 |
-
|
1322 |
-
|
1323 |
-
*
|
1324 |
-
* @return
|
1325 |
-
*/
|
1326 |
-
function
|
1327 |
-
|
1328 |
-
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
|
1338 |
-
|
1339 |
-
|
1340 |
-
|
1341 |
-
|
1342 |
-
|
1343 |
-
|
1344 |
-
|
1345 |
-
|
1346 |
-
|
1347 |
-
|
1348 |
-
|
1349 |
-
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
|
1357 |
-
|
1358 |
-
|
1359 |
-
|
1360 |
-
|
1361 |
-
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
1365 |
-
|
1366 |
-
|
1367 |
-
|
1368 |
-
|
1369 |
-
|
1370 |
-
|
1371 |
-
|
1372 |
-
|
1373 |
-
|
1374 |
-
|
1375 |
-
|
1376 |
-
|
1377 |
-
|
1378 |
-
|
1379 |
-
|
1380 |
-
|
1381 |
-
|
1382 |
-
|
1383 |
-
|
1384 |
-
|
1385 |
-
|
1386 |
-
|
1387 |
-
|
1388 |
-
|
1389 |
-
|
1390 |
-
|
1391 |
-
if (
|
1392 |
-
|
1393 |
-
|
1394 |
-
|
1395 |
-
|
1396 |
-
|
1397 |
-
|
1398 |
-
|
1399 |
-
|
1400 |
-
|
1401 |
-
|
1402 |
-
|
1403 |
-
|
1404 |
-
|
1405 |
-
|
1406 |
-
|
1407 |
-
|
1408 |
-
|
1409 |
-
|
1410 |
-
|
1411 |
-
$
|
1412 |
-
|
1413 |
-
|
1414 |
-
|
1415 |
-
|
1416 |
-
*
|
1417 |
-
*
|
1418 |
-
|
1419 |
-
|
1420 |
-
|
1421 |
-
|
1422 |
-
|
1423 |
-
|
1424 |
-
|
1425 |
-
|
1426 |
-
|
1427 |
-
|
1428 |
-
|
1429 |
-
|
1430 |
-
|
1431 |
-
|
1432 |
-
|
1433 |
-
|
1434 |
-
|
1435 |
-
|
1436 |
-
|
1437 |
-
|
1438 |
-
|
1439 |
-
|
1440 |
-
|
1441 |
-
|
1442 |
-
|
1443 |
-
|
1444 |
-
|
1445 |
-
|
1446 |
-
|
1447 |
-
|
1448 |
-
|
1449 |
-
|
1450 |
-
|
1451 |
-
|
1452 |
-
|
1453 |
-
|
1454 |
-
|
1455 |
-
|
1456 |
-
|
1457 |
-
|
1458 |
-
|
1459 |
-
|
1460 |
-
|
1461 |
-
|
1462 |
-
|
1463 |
-
|
1464 |
-
|
1465 |
-
|
1466 |
-
|
1467 |
-
|
1468 |
-
|
1469 |
-
|
1470 |
-
|
1471 |
-
|
1472 |
-
|
1473 |
-
|
1474 |
-
|
1475 |
-
|
1476 |
-
|
1477 |
-
|
1478 |
-
|
1479 |
-
|
1480 |
-
|
1481 |
-
|
1482 |
-
|
1483 |
-
|
1484 |
-
|
1485 |
-
|
1486 |
-
|
1487 |
-
|
1488 |
-
|
1489 |
-
*
|
1490 |
-
|
1491 |
-
|
1492 |
-
|
1493 |
-
|
1494 |
-
|
1495 |
-
|
1496 |
-
|
1497 |
-
|
1498 |
-
|
1499 |
-
|
1500 |
-
|
1501 |
-
|
1502 |
-
|
1503 |
-
|
1504 |
-
|
1505 |
-
|
1506 |
-
|
1507 |
-
|
1508 |
-
|
1509 |
-
|
1510 |
-
|
1511 |
-
|
1512 |
-
|
1513 |
-
|
1514 |
-
|
1515 |
-
|
1516 |
-
|
1517 |
-
|
1518 |
-
|
1519 |
-
*
|
1520 |
-
|
1521 |
-
|
1522 |
-
|
1523 |
-
|
1524 |
-
|
1525 |
-
|
1526 |
-
|
1527 |
-
|
1528 |
-
|
1529 |
-
|
1530 |
-
|
1531 |
-
|
1532 |
-
|
1533 |
-
|
1534 |
-
|
1535 |
-
|
1536 |
-
|
1537 |
-
|
1538 |
-
|
1539 |
-
|
1540 |
-
|
1541 |
-
|
1542 |
-
|
1543 |
-
|
1544 |
-
*
|
1545 |
-
*
|
1546 |
-
|
1547 |
-
|
1548 |
-
|
1549 |
-
|
1550 |
-
|
1551 |
-
|
1552 |
-
$
|
1553 |
-
|
1554 |
-
|
1555 |
-
|
1556 |
-
|
1557 |
-
}
|
1558 |
-
return $group;
|
1559 |
-
}
|
1560 |
-
|
1561 |
-
/*-**
|
1562 |
-
|
1563 |
-
/**
|
1564 |
-
*
|
1565 |
-
*
|
1566 |
-
* @param
|
1567 |
-
* @return
|
1568 |
-
*/
|
1569 |
-
function
|
1570 |
-
//
|
1571 |
-
if (
|
1572 |
-
|
1573 |
-
}
|
1574 |
-
|
1575 |
-
|
1576 |
-
|
1577 |
-
|
1578 |
-
$
|
1579 |
-
|
1580 |
-
|
1581 |
-
|
1582 |
-
|
1583 |
-
|
1584 |
-
|
1585 |
-
|
1586 |
-
|
1587 |
-
*
|
1588 |
-
*
|
1589 |
-
|
1590 |
-
|
1591 |
-
|
1592 |
-
|
1593 |
-
|
1594 |
-
|
1595 |
-
|
1596 |
-
|
1597 |
-
|
1598 |
-
|
1599 |
-
|
1600 |
-
|
1601 |
-
|
1602 |
-
|
1603 |
-
|
1604 |
-
|
1605 |
-
|
1606 |
-
|
1607 |
-
|
1608 |
-
|
1609 |
-
|
1610 |
-
|
1611 |
-
|
1612 |
-
|
1613 |
-
|
1614 |
-
|
1615 |
-
|
1616 |
-
if (
|
1617 |
-
$
|
1618 |
-
}
|
1619 |
-
|
1620 |
-
|
1621 |
-
|
1622 |
-
|
1623 |
-
|
1624 |
-
|
1625 |
-
|
1626 |
-
|
1627 |
-
|
1628 |
-
|
1629 |
-
|
1630 |
-
|
1631 |
-
|
1632 |
-
|
1633 |
-
|
1634 |
-
|
1635 |
-
|
1636 |
-
|
1637 |
-
|
1638 |
-
|
1639 |
-
|
1640 |
-
|
1641 |
-
|
1642 |
-
|
1643 |
-
|
1644 |
-
|
1645 |
-
|
1646 |
-
|
1647 |
-
|
1648 |
-
|
1649 |
-
|
1650 |
-
|
1651 |
-
|
1652 |
-
|
1653 |
-
|
1654 |
-
|
1655 |
-
|
1656 |
-
|
1657 |
-
|
1658 |
-
*
|
1659 |
-
* @
|
1660 |
-
|
1661 |
-
|
1662 |
-
|
1663 |
-
|
1664 |
-
|
1665 |
-
|
1666 |
-
|
1667 |
-
|
1668 |
-
|
1669 |
-
|
1670 |
-
|
1671 |
-
|
1672 |
-
|
1673 |
-
|
1674 |
-
|
1675 |
-
|
1676 |
-
|
1677 |
-
|
1678 |
-
|
1679 |
-
|
1680 |
-
|
1681 |
-
|
1682 |
-
|
1683 |
-
|
1684 |
-
|
1685 |
-
|
1686 |
-
|
1687 |
-
|
1688 |
-
|
1689 |
-
|
1690 |
-
|
1691 |
-
|
1692 |
-
|
1693 |
-
|
1694 |
-
|
1695 |
-
|
1696 |
-
|
1697 |
-
|
1698 |
-
|
1699 |
-
|
1700 |
-
|
1701 |
-
|
1702 |
-
|
1703 |
-
|
1704 |
-
|
1705 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Controller
|
4 |
+
* @package Simple Lightbox
|
5 |
+
* @author Archetyped
|
6 |
+
*/
|
7 |
+
class SLB_Lightbox extends SLB_Base {
|
8 |
+
|
9 |
+
/*-** Properties **-*/
|
10 |
+
|
11 |
+
protected $model = true;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Fields
|
15 |
+
* @var SLB_Fields
|
16 |
+
*/
|
17 |
+
public $fields = null;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Themes collection
|
21 |
+
* @var SLB_Themes
|
22 |
+
*/
|
23 |
+
public $themes = null;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Content types
|
27 |
+
* @var SLB_Content_Handlers
|
28 |
+
*/
|
29 |
+
public $handlers = null;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Template tags
|
33 |
+
* @var SLB_Template_Tags
|
34 |
+
*/
|
35 |
+
public $template_tags = null;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Media item template.
|
39 |
+
*
|
40 |
+
* @var array {
|
41 |
+
* Media item properties.
|
42 |
+
*
|
43 |
+
* @type int $id WP post ID. Default null.
|
44 |
+
* @type string $type Item type. Default null.
|
45 |
+
* @type string $source Source URI.
|
46 |
+
* @type bool $internal Internal resource. Default false.
|
47 |
+
* @type string $title Item title.
|
48 |
+
* @type string $caption Item caption.
|
49 |
+
* @type string $description Item description.
|
50 |
+
* @type array $media {
|
51 |
+
* Media properties (indexed by size name).
|
52 |
+
* Original size = 'full'.
|
53 |
+
*
|
54 |
+
* @type string $file File URI.
|
55 |
+
* @type int $width File width in pixels.
|
56 |
+
* @type int $height File height in pixels.
|
57 |
+
* }
|
58 |
+
* @type array $meta {
|
59 |
+
* Item metadata.
|
60 |
+
* }
|
61 |
+
* }
|
62 |
+
*/
|
63 |
+
private $media_item_template = [
|
64 |
+
'id' => null,
|
65 |
+
'type' => null,
|
66 |
+
'internal' => false,
|
67 |
+
'source' => '',
|
68 |
+
];
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Processed media items for output to client.
|
72 |
+
*
|
73 |
+
* @var object[string] {
|
74 |
+
* Media item properties.
|
75 |
+
*
|
76 |
+
* @index string Unique ID (system-generated).
|
77 |
+
*
|
78 |
+
* @see $media_item_template.
|
79 |
+
* }
|
80 |
+
*/
|
81 |
+
private $media_items = [];
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Collection of unprocessed media items.
|
85 |
+
*
|
86 |
+
* @var array {
|
87 |
+
* @type object[string] $props {
|
88 |
+
* Media item properties.
|
89 |
+
*
|
90 |
+
* @index string Unique ID (system-generated).
|
91 |
+
*
|
92 |
+
* @see $media_item_template
|
93 |
+
* }
|
94 |
+
* @type string[string] $uri {
|
95 |
+
* Cached URIs.
|
96 |
+
*
|
97 |
+
* @index string URI.
|
98 |
+
*
|
99 |
+
* @type string Item ID (points to item in `props` array)
|
100 |
+
* }
|
101 |
+
* }
|
102 |
+
*/
|
103 |
+
private $media_items_raw = [
|
104 |
+
'props' => [],
|
105 |
+
'uri' => [],
|
106 |
+
];
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Manage excluded content
|
110 |
+
* @var object
|
111 |
+
*/
|
112 |
+
private $exclude = null;
|
113 |
+
|
114 |
+
private $groups = array(
|
115 |
+
'auto' => 0,
|
116 |
+
'manual' => array(),
|
117 |
+
);
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Validated URIs
|
121 |
+
* Caches validation of parsed URIs
|
122 |
+
* > Key: URI
|
123 |
+
* > Value: (bool) TRUE if valid
|
124 |
+
* @var array
|
125 |
+
*/
|
126 |
+
private $validated_uris = array();
|
127 |
+
|
128 |
+
/* Widget properties */
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Used to track if widget is currently being processed or not
|
132 |
+
* Set to Widget ID currently being processed
|
133 |
+
* @var bool|string
|
134 |
+
*/
|
135 |
+
private $widget_processing = false;
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Parameters for widget being processed
|
139 |
+
* @param array
|
140 |
+
*/
|
141 |
+
private $widget_processing_params = null;
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Manage nested widget processing
|
145 |
+
* Used to avoid premature widget output
|
146 |
+
* @var int
|
147 |
+
*/
|
148 |
+
private $widget_processing_level = 0;
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Constructor
|
152 |
+
*/
|
153 |
+
public function __construct() {
|
154 |
+
parent::__construct();
|
155 |
+
// Init instances
|
156 |
+
$this->fields = new SLB_Fields();
|
157 |
+
$this->themes = new SLB_Themes( $this );
|
158 |
+
if ( ! is_admin() ) {
|
159 |
+
$this->template_tags = new SLB_Template_Tags( $this );
|
160 |
+
}
|
161 |
+
}
|
162 |
+
|
163 |
+
/* Init */
|
164 |
+
|
165 |
+
public function _init() {
|
166 |
+
parent::_init();
|
167 |
+
$this->util->do_action( 'init' );
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Declare client files (scripts, styles)
|
172 |
+
* @uses parent::_client_files()
|
173 |
+
* @return void
|
174 |
+
*/
|
175 |
+
protected function _client_files( $files = null ) {
|
176 |
+
$js_path = 'client/js/';
|
177 |
+
$js_path .= ( SLB_DEV ) ? 'dev' : 'prod';
|
178 |
+
$files = array(
|
179 |
+
'scripts' => array(
|
180 |
+
'core' => array(
|
181 |
+
'file' => "$js_path/lib.core.js",
|
182 |
+
'deps' => 'jquery',
|
183 |
+
'enqueue' => false,
|
184 |
+
'in_footer' => true,
|
185 |
+
),
|
186 |
+
'view' => array(
|
187 |
+
'file' => "$js_path/lib.view.js",
|
188 |
+
'deps' => array( '[core]' ),
|
189 |
+
'context' => array( array( 'public', $this->m( 'is_request_valid' ) ) ),
|
190 |
+
'in_footer' => true,
|
191 |
+
),
|
192 |
+
),
|
193 |
+
'styles' => array(
|
194 |
+
'core' => array(
|
195 |
+
'file' => 'client/css/app.css',
|
196 |
+
'context' => array( 'public' ),
|
197 |
+
),
|
198 |
+
),
|
199 |
+
);
|
200 |
+
parent::_client_files( $files );
|
201 |
+
}
|
202 |
+
|
203 |
+
/**
|
204 |
+
* Register hooks
|
205 |
+
* @uses parent::_hooks()
|
206 |
+
*/
|
207 |
+
protected function _hooks() {
|
208 |
+
parent::_hooks();
|
209 |
+
|
210 |
+
/* Admin */
|
211 |
+
add_action( 'admin_menu', $this->m( 'admin_menus' ) );
|
212 |
+
|
213 |
+
/* Init */
|
214 |
+
add_action( 'wp', $this->m( '_hooks_init' ) );
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Initialize hooks.
|
219 |
+
*
|
220 |
+
* @return void
|
221 |
+
*/
|
222 |
+
public function _hooks_init() {
|
223 |
+
if ( ! $this->is_enabled() ) {
|
224 |
+
return;
|
225 |
+
}
|
226 |
+
// Callback for hooks that need to have method added to end of stack.
|
227 |
+
$cb_hooks_add_last = $this->m( 'hooks_add_last' );
|
228 |
+
|
229 |
+
// Init lightbox
|
230 |
+
add_action( 'wp_footer', $this->m( 'client_footer' ) );
|
231 |
+
$this->util->add_action( 'footer_script', $this->m( 'client_init' ), 1 );
|
232 |
+
$this->util->add_filter( 'footer_script', $this->m( 'client_script_media' ), 2 );
|
233 |
+
// Link activation
|
234 |
+
add_filter( 'the_content', $cb_hooks_add_last );
|
235 |
+
add_filter( 'get_post_galleries', $cb_hooks_add_last );
|
236 |
+
$this->util->add_filter( 'post_process_links', $this->m( 'activate_groups' ), 11 );
|
237 |
+
$this->util->add_filter( 'validate_uri_regex', $this->m( 'validate_uri_regex_default' ), 1 );
|
238 |
+
// Content exclusion
|
239 |
+
$this->util->add_filter( 'pre_process_links', $this->m( 'exclude_content' ) );
|
240 |
+
$this->util->add_filter( 'pre_exclude_content', $this->m( 'exclude_shortcodes' ) );
|
241 |
+
$this->util->add_filter( 'post_process_links', $this->m( 'restore_excluded_content' ) );
|
242 |
+
|
243 |
+
// Grouping
|
244 |
+
if ( $this->options->get_bool( 'group_post' ) ) {
|
245 |
+
$this->util->add_filter( 'get_group_id', $this->m( 'post_group_id' ), 1 );
|
246 |
+
}
|
247 |
+
|
248 |
+
// Shortcode grouping
|
249 |
+
if ( $this->options->get_bool( 'group_gallery' ) ) {
|
250 |
+
add_filter( 'the_content', $this->m( 'group_shortcodes' ), 1 );
|
251 |
+
}
|
252 |
+
|
253 |
+
// Widgets
|
254 |
+
if ( $this->options->get_bool( 'enabled_widget' ) ) {
|
255 |
+
add_action( 'dynamic_sidebar_before', $this->m( 'widget_process_nested' ) );
|
256 |
+
add_action( 'dynamic_sidebar', $cb_hooks_add_last );
|
257 |
+
add_filter( 'dynamic_sidebar_params', $this->m( 'widget_process_inter' ), 1 );
|
258 |
+
add_action( 'dynamic_sidebar_after', $cb_hooks_add_last );
|
259 |
+
add_action( 'dynamic_sidebar_after', $cb_hooks_add_last );
|
260 |
+
} else {
|
261 |
+
add_action( 'dynamic_sidebar_before', $this->m( 'widget_block_start' ) );
|
262 |
+
add_action( 'dynamic_sidebar_after', $this->m( 'widget_block_finish' ) );
|
263 |
+
}
|
264 |
+
|
265 |
+
// Menus
|
266 |
+
if ( $this->options->get_bool( 'enabled_menu' ) ) {
|
267 |
+
add_filter( 'wp_nav_menu', $cb_hooks_add_last );
|
268 |
+
}
|
269 |
+
}
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Adds hook(s) to end of filter/action stack.
|
273 |
+
*
|
274 |
+
* @param string $data Optional. Data being filtered.
|
275 |
+
* @return string Filtered content.
|
276 |
+
*/
|
277 |
+
public function hooks_add_last( $data = null ) {
|
278 |
+
global $wp_filter;
|
279 |
+
|
280 |
+
$tag = current_filter();
|
281 |
+
|
282 |
+
// Stop processing on invalid hook.
|
283 |
+
if ( empty( $tag ) || ! is_string( $tag ) ) {
|
284 |
+
return $data;
|
285 |
+
}
|
286 |
+
|
287 |
+
// Get lowest priority for filter.
|
288 |
+
$max_priority = max( array_keys( $wp_filter[ $tag ]->callbacks ) ) + 123;
|
289 |
+
|
290 |
+
switch ( $tag ) {
|
291 |
+
case 'the_content':
|
292 |
+
add_filter( $tag, $this->m( 'activate_links' ), $max_priority );
|
293 |
+
break;
|
294 |
+
case 'get_post_galleries':
|
295 |
+
add_filter( $tag, $this->m( 'activate_galleries' ), $max_priority );
|
296 |
+
break;
|
297 |
+
case 'dynamic_sidebar':
|
298 |
+
add_action( $tag, $this->m( 'widget_process_start' ), $max_priority );
|
299 |
+
break;
|
300 |
+
case 'dynamic_sidebar_after':
|
301 |
+
add_action( $tag, $this->m( 'widget_process_finish' ), $max_priority );
|
302 |
+
add_action( $tag, $this->m( 'widget_process_nested_finish' ), $max_priority );
|
303 |
+
break;
|
304 |
+
case 'wp_nav_menu':
|
305 |
+
add_filter( $tag, $this->m( 'menu_process' ), $max_priority, 2 );
|
306 |
+
break;
|
307 |
+
}
|
308 |
+
|
309 |
+
// Remove init hook.
|
310 |
+
remove_filter( $tag, $this->m( __FUNCTION__ ) );
|
311 |
+
|
312 |
+
// Return content (for filters).
|
313 |
+
return $data;
|
314 |
+
}
|
315 |
+
|
316 |
+
/**
|
317 |
+
* Add post ID to link group ID
|
318 |
+
* @uses `SLB::get_group_id` filter
|
319 |
+
* @param array $group_segments Group ID segments
|
320 |
+
* @return array Modified group ID segments
|
321 |
+
*/
|
322 |
+
public function post_group_id( $group_segments ) {
|
323 |
+
if ( in_the_loop() ) {
|
324 |
+
// Prepend post ID to group ID
|
325 |
+
$post = get_post();
|
326 |
+
if ( $post ) {
|
327 |
+
array_unshift( $group_segments, $post->ID );
|
328 |
+
}
|
329 |
+
}
|
330 |
+
return $group_segments;
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
* Init options
|
335 |
+
*/
|
336 |
+
protected function _options() {
|
337 |
+
// Setup options
|
338 |
+
$opts = array(
|
339 |
+
'groups' => array(
|
340 |
+
'activation' => array(
|
341 |
+
'title' => __( 'Activation', 'simple-lightbox' ),
|
342 |
+
'priority' => 10,
|
343 |
+
),
|
344 |
+
'grouping' => array(
|
345 |
+
'title' => __( 'Grouping', 'simple-lightbox' ),
|
346 |
+
'priority' => 20,
|
347 |
+
),
|
348 |
+
'ui' => array(
|
349 |
+
'title' => __( 'UI', 'simple-lightbox' ),
|
350 |
+
'priority' => 30,
|
351 |
+
),
|
352 |
+
'labels' => array(
|
353 |
+
'title' => __( 'Labels', 'simple-lightbox' ),
|
354 |
+
'priority' => 40,
|
355 |
+
),
|
356 |
+
),
|
357 |
+
'items' => array(
|
358 |
+
'enabled' => array(
|
359 |
+
'title' => __( 'Enable Lightbox Functionality', 'simple-lightbox' ),
|
360 |
+
'default' => true,
|
361 |
+
'group' => array( 'activation', 10 ),
|
362 |
+
),
|
363 |
+
'enabled_home' => array(
|
364 |
+
'title' => __( 'Enable on Home page', 'simple-lightbox' ),
|
365 |
+
'default' => true,
|
366 |
+
'group' => array( 'activation', 20 ),
|
367 |
+
),
|
368 |
+
'enabled_post' => array(
|
369 |
+
'title' => __( 'Enable on Single Posts', 'simple-lightbox' ),
|
370 |
+
'default' => true,
|
371 |
+
'group' => array( 'activation', 30 ),
|
372 |
+
),
|
373 |
+
'enabled_page' => array(
|
374 |
+
'title' => __( 'Enable on Pages', 'simple-lightbox' ),
|
375 |
+
'default' => true,
|
376 |
+
'group' => array( 'activation', 40 ),
|
377 |
+
),
|
378 |
+
'enabled_archive' => array(
|
379 |
+
'title' => __( 'Enable on Archive Pages (tags, categories, etc.)', 'simple-lightbox' ),
|
380 |
+
'default' => true,
|
381 |
+
'group' => array( 'activation', 50 ),
|
382 |
+
),
|
383 |
+
'enabled_widget' => array(
|
384 |
+
'title' => __( 'Enable for Widgets', 'simple-lightbox' ),
|
385 |
+
'default' => false,
|
386 |
+
'group' => array( 'activation', 60 ),
|
387 |
+
),
|
388 |
+
'enabled_menu' => array(
|
389 |
+
'title' => __( 'Enable for Menus', 'simple-lightbox' ),
|
390 |
+
'default' => false,
|
391 |
+
'group' => array( 'activation', 60 ),
|
392 |
+
),
|
393 |
+
'group_links' => array(
|
394 |
+
'title' => __( 'Group items (for displaying as a slideshow)', 'simple-lightbox' ),
|
395 |
+
'default' => true,
|
396 |
+
'group' => array( 'grouping', 10 ),
|
397 |
+
),
|
398 |
+
'group_post' => array(
|
399 |
+
'title' => __( 'Group items by Post (e.g. on pages with multiple posts)', 'simple-lightbox' ),
|
400 |
+
'default' => true,
|
401 |
+
'group' => array( 'grouping', 20 ),
|
402 |
+
),
|
403 |
+
'group_gallery' => array(
|
404 |
+
'title' => __( 'Group gallery items separately', 'simple-lightbox' ),
|
405 |
+
'default' => false,
|
406 |
+
'group' => array( 'grouping', 30 ),
|
407 |
+
),
|
408 |
+
'group_widget' => array(
|
409 |
+
'title' => __( 'Group widget items separately', 'simple-lightbox' ),
|
410 |
+
'default' => false,
|
411 |
+
'group' => array( 'grouping', 40 ),
|
412 |
+
),
|
413 |
+
'group_menu' => array(
|
414 |
+
'title' => __( 'Group menu items separately', 'simple-lightbox' ),
|
415 |
+
'default' => false,
|
416 |
+
'group' => array( 'grouping', 50 ),
|
417 |
+
),
|
418 |
+
'ui_autofit' => array(
|
419 |
+
'title' => __( 'Resize lightbox to fit in window', 'simple-lightbox' ),
|
420 |
+
'default' => true,
|
421 |
+
'group' => array( 'ui', 10 ),
|
422 |
+
'in_client' => true,
|
423 |
+
),
|
424 |
+
'ui_animate' => array(
|
425 |
+
'title' => __( 'Enable animations', 'simple-lightbox' ),
|
426 |
+
'default' => true,
|
427 |
+
'group' => array( 'ui', 20 ),
|
428 |
+
'in_client' => true,
|
429 |
+
),
|
430 |
+
'slideshow_autostart' => array(
|
431 |
+
'title' => __( 'Start Slideshow Automatically', 'simple-lightbox' ),
|
432 |
+
'default' => true,
|
433 |
+
'group' => array( 'ui', 30 ),
|
434 |
+
'in_client' => true,
|
435 |
+
),
|
436 |
+
'slideshow_duration' => array(
|
437 |
+
'title' => __( 'Slide Duration (Seconds)', 'simple-lightbox' ),
|
438 |
+
'default' => '6',
|
439 |
+
'attr' => array(
|
440 |
+
'size' => 3,
|
441 |
+
'maxlength' => 3,
|
442 |
+
),
|
443 |
+
'group' => array( 'ui', 40 ),
|
444 |
+
'in_client' => true,
|
445 |
+
),
|
446 |
+
'group_loop' => array(
|
447 |
+
'title' => __( 'Loop through items', 'simple-lightbox' ),
|
448 |
+
'default' => true,
|
449 |
+
'group' => array( 'ui', 50 ),
|
450 |
+
'in_client' => true,
|
451 |
+
),
|
452 |
+
'ui_overlay_opacity' => array(
|
453 |
+
'title' => __( 'Overlay Opacity (0 - 1)', 'simple-lightbox' ),
|
454 |
+
'default' => '0.8',
|
455 |
+
'attr' => array(
|
456 |
+
'size' => 3,
|
457 |
+
'maxlength' => 3,
|
458 |
+
),
|
459 |
+
'group' => array( 'ui', 60 ),
|
460 |
+
'in_client' => true,
|
461 |
+
),
|
462 |
+
'ui_title_default' => array(
|
463 |
+
'title' => __( 'Enable default title', 'simple-lightbox' ),
|
464 |
+
'default' => false,
|
465 |
+
'group' => array( 'ui', 70 ),
|
466 |
+
'in_client' => true,
|
467 |
+
),
|
468 |
+
'txt_loading' => array(
|
469 |
+
'title' => __( 'Loading indicator', 'simple-lightbox' ),
|
470 |
+
'default' => 'Loading',
|
471 |
+
'group' => array( 'labels', 20 ),
|
472 |
+
),
|
473 |
+
'txt_close' => array(
|
474 |
+
'title' => __( 'Close button', 'simple-lightbox' ),
|
475 |
+
'default' => 'Close',
|
476 |
+
'group' => array( 'labels', 10 ),
|
477 |
+
),
|
478 |
+
'txt_nav_next' => array(
|
479 |
+
'title' => __( 'Next Item button', 'simple-lightbox' ),
|
480 |
+
'default' => 'Next',
|
481 |
+
'group' => array( 'labels', 30 ),
|
482 |
+
),
|
483 |
+
'txt_nav_prev' => array(
|
484 |
+
'title' => __( 'Previous Item button', 'simple-lightbox' ),
|
485 |
+
'default' => 'Previous',
|
486 |
+
'group' => array( 'labels', 40 ),
|
487 |
+
),
|
488 |
+
'txt_slideshow_start' => array(
|
489 |
+
'title' => __( 'Start Slideshow button', 'simple-lightbox' ),
|
490 |
+
'default' => 'Start slideshow',
|
491 |
+
'group' => array( 'labels', 50 ),
|
492 |
+
),
|
493 |
+
'txt_slideshow_stop' => array(
|
494 |
+
'title' => __( 'Stop Slideshow button', 'simple-lightbox' ),
|
495 |
+
'default' => 'Stop slideshow',
|
496 |
+
'group' => array( 'labels', 60 ),
|
497 |
+
),
|
498 |
+
'txt_group_status' => array(
|
499 |
+
'title' => __( 'Slideshow status format', 'simple-lightbox' ),
|
500 |
+
'default' => 'Item %current% of %total%',
|
501 |
+
'group' => array( 'labels', 70 ),
|
502 |
+
),
|
503 |
+
),
|
504 |
+
'legacy' => array(
|
505 |
+
'header_activation' => null,
|
506 |
+
'header_enabled' => null,
|
507 |
+
'header_strings' => null,
|
508 |
+
'header_ui' => null,
|
509 |
+
'activate_attachments' => null,
|
510 |
+
'validate_links' => null,
|
511 |
+
'enabled_compat' => null,
|
512 |
+
'enabled_single' => array( 'enabled_post', 'enabled_page' ),
|
513 |
+
'enabled_caption' => null,
|
514 |
+
'enabled_desc' => null,
|
515 |
+
'ui_enabled_caption' => null,
|
516 |
+
'ui_caption_src' => null,
|
517 |
+
'ui_enabled_desc' => null,
|
518 |
+
'caption_src' => null,
|
519 |
+
'animate' => 'ui_animate',
|
520 |
+
'overlay_opacity' => 'ui_overlay_opacity',
|
521 |
+
'loop' => 'group_loop',
|
522 |
+
'autostart' => 'slideshow_autostart',
|
523 |
+
'duration' => 'slideshow_duration',
|
524 |
+
'txt_numDisplayPrefix' => null,
|
525 |
+
'txt_numDisplaySeparator' => null,
|
526 |
+
'txt_closeLink' => 'txt_link_close',
|
527 |
+
'txt_nextLink' => 'txt_link_next',
|
528 |
+
'txt_prevLink' => 'txt_link_prev',
|
529 |
+
'txt_startSlideshow' => 'txt_slideshow_start',
|
530 |
+
'txt_stopSlideshow' => 'txt_slideshow_stop',
|
531 |
+
'txt_loadingMsg' => 'txt_loading',
|
532 |
+
'txt_link_next' => 'txt_nav_next',
|
533 |
+
'txt_link_prev' => 'txt_nav_prev',
|
534 |
+
'txt_link_close' => 'txt_close',
|
535 |
+
),
|
536 |
+
);
|
537 |
+
|
538 |
+
parent::_set_options( $opts );
|
539 |
+
}
|
540 |
+
|
541 |
+
/* Methods */
|
542 |
+
|
543 |
+
/*-** Admin **-*/
|
544 |
+
|
545 |
+
/**
|
546 |
+
* Add admin menus
|
547 |
+
* @uses this->admin->add_theme_page
|
548 |
+
*/
|
549 |
+
function admin_menus() {
|
550 |
+
// Build options page
|
551 |
+
$lbls_opts = array(
|
552 |
+
'menu' => __( 'Lightbox', 'simple-lightbox' ),
|
553 |
+
'header' => __( 'Lightbox Settings', 'simple-lightbox' ),
|
554 |
+
'plugin_action' => __( 'Settings', 'simple-lightbox' ),
|
555 |
+
);
|
556 |
+
$pg_opts = $this->admin->add_theme_page( 'options', $lbls_opts )
|
557 |
+
->require_form()
|
558 |
+
->add_content( 'options', 'Options', $this->options );
|
559 |
+
|
560 |
+
// Add Support information
|
561 |
+
$support = $this->util->get_plugin_info( 'SupportURI' );
|
562 |
+
if ( ! empty( $support ) ) {
|
563 |
+
$pg_opts->add_content( 'support', __( 'Feedback & Support', 'simple-lightbox' ), $this->m( 'theme_page_callback_support' ), 'secondary' );
|
564 |
+
}
|
565 |
+
|
566 |
+
// Add Actions
|
567 |
+
$lbls_reset = array(
|
568 |
+
'title' => __( 'Reset', 'simple-lightbox' ),
|
569 |
+
'confirm' => __( 'Are you sure you want to reset Simple Lightbox\'s settings?', 'simple-lightbox' ),
|
570 |
+
'success' => __( 'Settings have been reset', 'simple-lightbox' ),
|
571 |
+
'failure' => __( 'Settings were not reset', 'simple-lightbox' ),
|
572 |
+
);
|
573 |
+
$this->admin->add_action( 'reset', $lbls_reset, $this->options );
|
574 |
+
}
|
575 |
+
|
576 |
+
/**
|
577 |
+
* Support information
|
578 |
+
*/
|
579 |
+
public function theme_page_callback_support() {
|
580 |
+
// Description
|
581 |
+
$desc = __( '<p>Simple Lightbox thrives on your feedback!</p><p>Click the button below to <strong>get help</strong>, <strong>request a feature</strong>, or <strong>provide some feedback</strong>!</p>', 'simple-lightbox' );
|
582 |
+
echo $desc;
|
583 |
+
// Link
|
584 |
+
$lnk_uri = $this->util->get_plugin_info( 'SupportURI' );
|
585 |
+
$lnk_txt = __( 'Get Support & Provide Feedback', 'simple-lightbox' );
|
586 |
+
echo $this->util->build_html_link(
|
587 |
+
$lnk_uri,
|
588 |
+
$lnk_txt,
|
589 |
+
array(
|
590 |
+
'target' => '_blank',
|
591 |
+
'class' => 'button',
|
592 |
+
)
|
593 |
+
);
|
594 |
+
}
|
595 |
+
|
596 |
+
/*-** Functionality **-*/
|
597 |
+
|
598 |
+
/**
|
599 |
+
* Checks whether lightbox is currently enabled/disabled
|
600 |
+
* @return bool TRUE if lightbox is currently enabled, FALSE otherwise
|
601 |
+
*/
|
602 |
+
function is_enabled() {
|
603 |
+
static $ret = null;
|
604 |
+
if ( is_null( $ret ) ) {
|
605 |
+
$ret = ( ! is_admin() && $this->options->get_bool( 'enabled' ) && ! is_feed() ) ? true : false;
|
606 |
+
if ( $ret ) {
|
607 |
+
$opt = '';
|
608 |
+
// Determine option to check
|
609 |
+
if ( is_home() || is_front_page() ) {
|
610 |
+
$opt = 'home';
|
611 |
+
} elseif ( is_singular() ) {
|
612 |
+
$opt = ( is_page() ) ? 'page' : 'post';
|
613 |
+
} elseif ( is_archive() || is_search() ) {
|
614 |
+
$opt = 'archive';
|
615 |
+
}
|
616 |
+
// Check sub-option
|
617 |
+
if ( ! empty( $opt ) ) {
|
618 |
+
// Prefix option name.
|
619 |
+
$opt = 'enabled_' . $opt;
|
620 |
+
if ( $this->options->has( $opt ) ) {
|
621 |
+
$ret = $this->options->get_bool( $opt );
|
622 |
+
}
|
623 |
+
}
|
624 |
+
}
|
625 |
+
}
|
626 |
+
// Filter return value
|
627 |
+
if ( ! is_admin() ) {
|
628 |
+
$ret = $this->util->apply_filters( 'is_enabled', $ret );
|
629 |
+
}
|
630 |
+
// Return value (force boolean)
|
631 |
+
return ! ! $ret;
|
632 |
+
}
|
633 |
+
|
634 |
+
/**
|
635 |
+
* Make sure content is valid for processing/activation
|
636 |
+
*
|
637 |
+
* @param string $content Content to validate
|
638 |
+
* @return bool TRUE if content is valid (FALSE otherwise)
|
639 |
+
*/
|
640 |
+
protected function is_content_valid( $content ) {
|
641 |
+
// Invalid hooks
|
642 |
+
if ( doing_filter( 'get_the_excerpt' ) ) {
|
643 |
+
return false;
|
644 |
+
}
|
645 |
+
|
646 |
+
// Non-string value
|
647 |
+
if ( ! is_string( $content ) ) {
|
648 |
+
return false;
|
649 |
+
}
|
650 |
+
|
651 |
+
// Empty string
|
652 |
+
$content = trim( $content );
|
653 |
+
if ( empty( $content ) ) {
|
654 |
+
return false;
|
655 |
+
}
|
656 |
+
|
657 |
+
// Content is valid
|
658 |
+
return $this->util->apply_filters( 'is_content_valid', true, $content );
|
659 |
+
}
|
660 |
+
|
661 |
+
/**
|
662 |
+
* Activates galleries extracted from post
|
663 |
+
* @see get_post_galleries()
|
664 |
+
* @param array $galleries A list of galleries in post
|
665 |
+
* @return A list of galleries with links activated
|
666 |
+
*/
|
667 |
+
function activate_galleries( $galleries ) {
|
668 |
+
// Validate
|
669 |
+
if ( empty( $galleries ) ) {
|
670 |
+
return $galleries;
|
671 |
+
}
|
672 |
+
// Check galleries for HTML output
|
673 |
+
$gallery = reset( $galleries );
|
674 |
+
if ( is_array( $gallery ) ) {
|
675 |
+
return $galleries;
|
676 |
+
}
|
677 |
+
|
678 |
+
// Activate galleries
|
679 |
+
$group = ( $this->options->get_bool( 'group_gallery' ) ) ? true : null;
|
680 |
+
foreach ( $galleries as $key => $val ) {
|
681 |
+
if ( ! is_null( $group ) ) {
|
682 |
+
$group = 'gallery_' . $key;
|
683 |
+
}
|
684 |
+
// Activate links in gallery
|
685 |
+
$gallery = $this->process_links( $val, $group );
|
686 |
+
|
687 |
+
// Save modified gallery
|
688 |
+
$galleries[ $key ] = $gallery;
|
689 |
+
}
|
690 |
+
|
691 |
+
return $galleries;
|
692 |
+
}
|
693 |
+
|
694 |
+
/**
|
695 |
+
* Scans post content for image links and activates them
|
696 |
+
*
|
697 |
+
* Lightbox will not be activated for feeds
|
698 |
+
* @param string $content Content to activate
|
699 |
+
* @param string (optonal) $group Group ID for content
|
700 |
+
* @return string Post content
|
701 |
+
*/
|
702 |
+
public function activate_links( $content, $group = null ) {
|
703 |
+
// Validate content
|
704 |
+
if ( ! $this->is_content_valid( $content ) ) {
|
705 |
+
return $content;
|
706 |
+
}
|
707 |
+
// Filter content before processing links
|
708 |
+
$content = $this->util->apply_filters( 'pre_process_links', $content );
|
709 |
+
|
710 |
+
// Process links
|
711 |
+
$content = $this->process_links( $content, $group );
|
712 |
+
|
713 |
+
// Filter content after processing links
|
714 |
+
$content = $this->util->apply_filters( 'post_process_links', $content );
|
715 |
+
|
716 |
+
return $content;
|
717 |
+
}
|
718 |
+
|
719 |
+
/**
|
720 |
+
* Process links in content
|
721 |
+
* @global obj $wpdb DB instance
|
722 |
+
* @global obj $post Current post
|
723 |
+
* @param string $content Text containing links
|
724 |
+
* @param string (optional) $group Group to add links to (Default: none)
|
725 |
+
* @return string Content with processed links
|
726 |
+
*/
|
727 |
+
protected function process_links( $content, $group = null ) {
|
728 |
+
// Extract links
|
729 |
+
$links = $this->get_links( $content, true );
|
730 |
+
// Do not process content without links
|
731 |
+
if ( empty( $links ) ) {
|
732 |
+
return $content;
|
733 |
+
}
|
734 |
+
// Process links
|
735 |
+
static $protocol = array( 'http://', 'https://' );
|
736 |
+
static $qv_att = 'attachment_id';
|
737 |
+
static $uri_origin = null;
|
738 |
+
if ( ! is_array( $uri_origin ) ) {
|
739 |
+
$uri_parts = array_fill_keys( array( 'scheme', 'host', 'path' ), '' );
|
740 |
+
$uri_origin = wp_parse_args( wp_parse_url( strtolower( home_url() ) ), $uri_parts );
|
741 |
+
}
|
742 |
+
static $uri_proto = null;
|
743 |
+
if ( empty( $uri_proto ) ) {
|
744 |
+
$uri_proto = (object) array(
|
745 |
+
'raw' => '',
|
746 |
+
'source' => '',
|
747 |
+
'parts' => '',
|
748 |
+
);
|
749 |
+
}
|
750 |
+
$uri_parts_required = array( 'host' => '' );
|
751 |
+
|
752 |
+
// Setup group properties
|
753 |
+
$g_props = (object) array(
|
754 |
+
'enabled' => $this->options->get_bool( 'group_links' ),
|
755 |
+
'attr' => 'group',
|
756 |
+
'base' => '',
|
757 |
+
'legacy_prefix' => 'lightbox[',
|
758 |
+
'legacy_suffix' => ']',
|
759 |
+
);
|
760 |
+
if ( $g_props->enabled ) {
|
761 |
+
$g_props->base = ( is_scalar( $group ) ) ? trim( strval( $group ) ) : '';
|
762 |
+
}
|
763 |
+
|
764 |
+
// Initialize content handlers
|
765 |
+
if ( ! ( $this->handlers instanceof SLB_Content_Handlers ) ) {
|
766 |
+
$this->handlers = new SLB_Content_Handlers( $this );
|
767 |
+
}
|
768 |
+
|
769 |
+
// Iterate through and activate supported links
|
770 |
+
|
771 |
+
foreach ( $links as $link ) {
|
772 |
+
// Init vars
|
773 |
+
$pid = 0;
|
774 |
+
$link_new = $link;
|
775 |
+
$uri = clone $uri_proto;
|
776 |
+
$type = false;
|
777 |
+
$props_extra = array();
|
778 |
+
$key = null;
|
779 |
+
$internal = false;
|
780 |
+
|
781 |
+
// Parse link attributes
|
782 |
+
$attrs = $this->util->parse_attribute_string( $link_new, array( 'href' => '' ) );
|
783 |
+
// Get URI
|
784 |
+
$uri->raw = $attrs['href'];
|
785 |
+
|
786 |
+
// Stop processing invalid links
|
787 |
+
if ( ! $this->validate_uri( $uri->raw )
|
788 |
+
|| $this->has_attribute( $attrs, 'active' ) // Previously-processed.
|
789 |
+
) {
|
790 |
+
continue;
|
791 |
+
}
|
792 |
+
|
793 |
+
// Normalize URI (make absolute)
|
794 |
+
$uri->source = WP_HTTP::make_absolute_url( $uri->raw, $uri_origin['scheme'] . '://' . $uri_origin['host'] );
|
795 |
+
|
796 |
+
// URI cached?
|
797 |
+
$key = $this->get_media_item_id( $uri->source );
|
798 |
+
|
799 |
+
// Internal URI? (e.g. attachments)
|
800 |
+
if ( ! $key ) {
|
801 |
+
$uri->parts = array_merge( $uri_parts_required, (array) wp_parse_url( $uri->source ) );
|
802 |
+
$internal = ( $uri->parts['host'] === $uri_origin['host'] ) ? true : false;
|
803 |
+
|
804 |
+
// Attachment?
|
805 |
+
if ( $internal && is_local_attachment( $uri->source ) ) {
|
806 |
+
$pid = url_to_postid( $uri->source );
|
807 |
+
$src = wp_get_attachment_url( $pid );
|
808 |
+
if ( ! ! $src ) {
|
809 |
+
$uri->source = $src;
|
810 |
+
$props_extra['id'] = $pid;
|
811 |
+
// Check cache for attachment source URI
|
812 |
+
$key = $this->get_media_item_id( $uri->source );
|
813 |
+
}
|
814 |
+
unset( $src );
|
815 |
+
}
|
816 |
+
}
|
817 |
+
|
818 |
+
// Determine content type
|
819 |
+
if ( ! $key ) {
|
820 |
+
// Get handler match
|
821 |
+
$hdl_result = $this->handlers->match( $uri->source );
|
822 |
+
if ( ! ! $hdl_result->handler ) {
|
823 |
+
$type = $hdl_result->handler->get_id();
|
824 |
+
$props_extra = $hdl_result->props;
|
825 |
+
// Updated source URI
|
826 |
+
if ( isset( $props_extra['uri'] ) ) {
|
827 |
+
$uri->source = $props_extra['uri'];
|
828 |
+
unset( $props_extra['uri'] );
|
829 |
+
}
|
830 |
+
}
|
831 |
+
|
832 |
+
// Cache valid item
|
833 |
+
if ( ! ! $type ) {
|
834 |
+
$key = $this->cache_media_item( $uri, $type, $internal, $props_extra );
|
835 |
+
}
|
836 |
+
}
|
837 |
+
|
838 |
+
// Stop processing invalid links
|
839 |
+
if ( ! $key ) {
|
840 |
+
// Cache invalid URI
|
841 |
+
$this->validated_uris[ $uri->source ] = false;
|
842 |
+
if ( $uri->raw !== $uri->source ) {
|
843 |
+
$this->validated_uris[ $uri->raw ] = false;
|
844 |
+
}
|
845 |
+
continue;
|
846 |
+
}
|
847 |
+
|
848 |
+
// Activate link
|
849 |
+
$this->set_attribute( $attrs, 'active' );
|
850 |
+
$this->set_attribute( $attrs, 'asset', $key );
|
851 |
+
// Mark internal links
|
852 |
+
if ( $internal ) {
|
853 |
+
$this->set_attribute( $attrs, 'internal', $pid );
|
854 |
+
}
|
855 |
+
|
856 |
+
// Set group (if enabled)
|
857 |
+
if ( $g_props->enabled ) {
|
858 |
+
$group = array();
|
859 |
+
// Get preset group attribute
|
860 |
+
$g = ( $this->has_attribute( $attrs, $g_props->attr ) ) ? $this->get_attribute( $attrs, $g_props->attr ) : '';
|
861 |
+
if ( ! empty( $g ) ) {
|
862 |
+
$group[] = $g;
|
863 |
+
} elseif ( ! empty( $g_props->base ) ) {
|
864 |
+
$group[] = $g_props->base;
|
865 |
+
}
|
866 |
+
|
867 |
+
/**
|
868 |
+
* Filter group ID components
|
869 |
+
*
|
870 |
+
* @see process_links()
|
871 |
+
*
|
872 |
+
* @param array $group Components used to build group ID
|
873 |
+
*/
|
874 |
+
$group = $this->util->apply_filters( 'get_group_id', $group );
|
875 |
+
|
876 |
+
// Default group
|
877 |
+
if ( empty( $group ) || ! is_array( $group ) ) {
|
878 |
+
$group = $this->get_prefix();
|
879 |
+
} else {
|
880 |
+
$group = implode( '_', $group );
|
881 |
+
}
|
882 |
+
|
883 |
+
// Set group attribute
|
884 |
+
$this->set_attribute( $attrs, $g_props->attr, $group );
|
885 |
+
unset( $g );
|
886 |
+
}
|
887 |
+
|
888 |
+
// Filter attributes
|
889 |
+
$attrs = $this->util->apply_filters( 'process_link_attributes', $attrs );
|
890 |
+
|
891 |
+
// Update link in content
|
892 |
+
$link_new = '<a ' . $this->util->build_attribute_string( $attrs ) . '>';
|
893 |
+
$content = str_replace( $link, $link_new, $content );
|
894 |
+
}
|
895 |
+
|
896 |
+
// Handle widget content
|
897 |
+
if ( ! ! $this->widget_processing && 'the_content' === current_filter() ) {
|
898 |
+
$content = $this->exclude_wrap( $content );
|
899 |
+
}
|
900 |
+
|
901 |
+
return $content;
|
902 |
+
}
|
903 |
+
|
904 |
+
/**
|
905 |
+
* Retrieve HTML links in content
|
906 |
+
* @param string $content Content to get links from
|
907 |
+
* @param bool (optional) $unique Remove duplicates from returned links (Default: FALSE)
|
908 |
+
* @return array Links in content
|
909 |
+
*/
|
910 |
+
function get_links( $content, $unique = false ) {
|
911 |
+
$rgx = "/\<a\b(?:(?!\shref=|\>).)*\shref=[^\>\<]++\>/i";
|
912 |
+
$links = [];
|
913 |
+
preg_match_all( $rgx, $content, $links );
|
914 |
+
$links = $links[0];
|
915 |
+
if ( $unique ) {
|
916 |
+
$links = array_unique( $links );
|
917 |
+
}
|
918 |
+
return $links;
|
919 |
+
}
|
920 |
+
|
921 |
+
/**
|
922 |
+
* Validate URI
|
923 |
+
* Matches specified URI against internal & external regex patterns
|
924 |
+
* URI is **invalid** if it matches a regex
|
925 |
+
*
|
926 |
+
* @param string $uri URI to validate
|
927 |
+
* @return bool TRUE if URI is valid
|
928 |
+
*/
|
929 |
+
protected function validate_uri( $uri ) {
|
930 |
+
static $patterns = null;
|
931 |
+
// Previously-validated URI
|
932 |
+
if ( isset( $this->validated_uris[ $uri ] ) ) {
|
933 |
+
return $this->validated_uris[ $uri ];
|
934 |
+
}
|
935 |
+
|
936 |
+
$valid = true;
|
937 |
+
// Boilerplate validation
|
938 |
+
if ( empty( $uri ) // Empty
|
939 |
+
|| 0 === strpos( $uri, '#' ) // Anchor
|
940 |
+
) {
|
941 |
+
$valid = false;
|
942 |
+
}
|
943 |
+
|
944 |
+
// Regex matching
|
945 |
+
if ( $valid ) {
|
946 |
+
// Get patterns
|
947 |
+
if ( is_null( $patterns ) ) {
|
948 |
+
$patterns = $this->util->apply_filters( 'validate_uri_regex', array() );
|
949 |
+
}
|
950 |
+
// Iterate through patterns until match found
|
951 |
+
foreach ( $patterns as $pattern ) {
|
952 |
+
if ( 1 === preg_match( $pattern, $uri ) ) {
|
953 |
+
$valid = false;
|
954 |
+
break;
|
955 |
+
}
|
956 |
+
}
|
957 |
+
}
|
958 |
+
|
959 |
+
// Cache
|
960 |
+
$this->validated_uris[ $uri ] = $valid;
|
961 |
+
return $valid;
|
962 |
+
}
|
963 |
+
|
964 |
+
/**
|
965 |
+
* Add URI validation regex pattern
|
966 |
+
* @param
|
967 |
+
*/
|
968 |
+
public function validate_uri_regex_default( $patterns ) {
|
969 |
+
$patterns[] = '@^https?://[^/]*(wikipedia|wikimedia)\.org/wiki/file:.*$@i';
|
970 |
+
return $patterns;
|
971 |
+
}
|
972 |
+
|
973 |
+
/* Client */
|
974 |
+
|
975 |
+
/**
|
976 |
+
* Checks if output should be loaded in current request
|
977 |
+
* @uses `is_enabled()`
|
978 |
+
* @uses `has_cached_media_items()`
|
979 |
+
* @return bool TRUE if output is being loaded into client
|
980 |
+
*/
|
981 |
+
public function is_request_valid() {
|
982 |
+
return ( $this->is_enabled() && $this->has_cached_media_items() ) ? true : false;
|
983 |
+
}
|
984 |
+
|
985 |
+
/**
|
986 |
+
* Sets options/settings to initialize lightbox functionality on page load
|
987 |
+
* @return void
|
988 |
+
*/
|
989 |
+
function client_init( $client_script ) {
|
990 |
+
// Get options
|
991 |
+
$options = $this->options->build_client_output();
|
992 |
+
|
993 |
+
// Load UI Strings
|
994 |
+
$labels = $this->build_labels();
|
995 |
+
if ( ! empty( $labels ) ) {
|
996 |
+
$options['ui_labels'] = $labels;
|
997 |
+
}
|
998 |
+
|
999 |
+
// Build client output
|
1000 |
+
$client_script[] = $this->util->call_client_method( 'View.init', $options );
|
1001 |
+
return $client_script;
|
1002 |
+
}
|
1003 |
+
|
1004 |
+
/**
|
1005 |
+
* Output code in footer
|
1006 |
+
* > Media attachment URLs
|
1007 |
+
* @uses `_wp_attached_file` to match attachment ID to URI
|
1008 |
+
* @uses `_wp_attachment_metadata` to retrieve attachment metadata
|
1009 |
+
*/
|
1010 |
+
function client_footer() {
|
1011 |
+
if ( ! $this->has_cached_media_items() ) {
|
1012 |
+
return false;
|
1013 |
+
}
|
1014 |
+
|
1015 |
+
// Set up hooks
|
1016 |
+
add_action( 'wp_print_footer_scripts', $this->m( 'client_footer_script' ) );
|
1017 |
+
|
1018 |
+
// Build client output
|
1019 |
+
$this->util->do_action( 'footer' );
|
1020 |
+
}
|
1021 |
+
|
1022 |
+
/**
|
1023 |
+
* Output client footer scripts
|
1024 |
+
*/
|
1025 |
+
function client_footer_script() {
|
1026 |
+
$client_script = $this->util->apply_filters( 'footer_script', array() );
|
1027 |
+
if ( ! empty( $client_script ) ) {
|
1028 |
+
echo $this->util->build_script_element( $client_script, 'footer', true, true );
|
1029 |
+
}
|
1030 |
+
}
|
1031 |
+
|
1032 |
+
/**
|
1033 |
+
* Add media information to client output
|
1034 |
+
*
|
1035 |
+
* @param array $client_script Client script commands.
|
1036 |
+
* @return array Modified script commands.
|
1037 |
+
* TODO Refactor
|
1038 |
+
*/
|
1039 |
+
public function client_script_media( $client_script ) {
|
1040 |
+
global $wpdb;
|
1041 |
+
|
1042 |
+
// Init.
|
1043 |
+
$this->media_items = $this->get_cached_media_items();
|
1044 |
+
|
1045 |
+
// Extract internal links for additional processing.
|
1046 |
+
$m_internals = [];
|
1047 |
+
foreach ( $this->media_items as $key => $p ) {
|
1048 |
+
if ( $p->internal ) {
|
1049 |
+
$m_internals[ $key ] =& $this->media_items[ $key ];
|
1050 |
+
}
|
1051 |
+
}
|
1052 |
+
// Cleanup.
|
1053 |
+
unset( $key, $p );
|
1054 |
+
|
1055 |
+
// Process internal links.
|
1056 |
+
if ( ! empty( $m_internals ) ) {
|
1057 |
+
$uris_base = [];
|
1058 |
+
$uri_prefix = wp_upload_dir();
|
1059 |
+
$uri_prefix = $this->util->normalize_path( $uri_prefix['baseurl'], true );
|
1060 |
+
foreach ( $m_internals as $key => $p ) {
|
1061 |
+
// Prepare internal links.
|
1062 |
+
// Create relative URIs for attachment data retrieval.
|
1063 |
+
if ( ! $p->id && strpos( $p->source, $uri_prefix ) === 0 ) {
|
1064 |
+
$uris_base[ str_replace( $uri_prefix, '', $p->source ) ] = $key;
|
1065 |
+
}
|
1066 |
+
}
|
1067 |
+
// Cleanup.
|
1068 |
+
unset( $key, $p );
|
1069 |
+
|
1070 |
+
// Retrieve attachment IDs.
|
1071 |
+
$uris_flat = "('" . implode( "','", array_keys( $uris_base ) ) . "')";
|
1072 |
+
$q = $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE `meta_key` = %s AND LOWER(`meta_value`) IN $uris_flat LIMIT %d", '_wp_attached_file', count( $uris_base ) );
|
1073 |
+
$pids = $wpdb->get_results( $q );
|
1074 |
+
// Match IDs to URIs.
|
1075 |
+
if ( $pids ) {
|
1076 |
+
foreach ( $pids as $pd ) {
|
1077 |
+
$file =& $pd->meta_value;
|
1078 |
+
if ( isset( $uris_base[ $file ] ) ) {
|
1079 |
+
$m_internals[ $uris_base[ $file ] ]->id = absint( $pd->post_id );
|
1080 |
+
}
|
1081 |
+
}
|
1082 |
+
}
|
1083 |
+
// Cleanup.
|
1084 |
+
unset( $uris_base, $uris_flat, $q, $pids, $pd, $file );
|
1085 |
+
}
|
1086 |
+
|
1087 |
+
// Process items with attachment IDs.
|
1088 |
+
$pids = [];
|
1089 |
+
foreach ( $this->media_items as $key => $p ) {
|
1090 |
+
// Add post ID to query.
|
1091 |
+
if ( ! ! $p->id ) {
|
1092 |
+
// Create array for ID (support multiple URIs per ID).
|
1093 |
+
if ( ! isset( $pids[ $p->id ] ) ) {
|
1094 |
+
$pids[ $p->id ] = [];
|
1095 |
+
}
|
1096 |
+
// Add URI to ID.
|
1097 |
+
$pids[ $p->id ][] = $key;
|
1098 |
+
}
|
1099 |
+
}
|
1100 |
+
// Cleanup.
|
1101 |
+
unset( $key, $p );
|
1102 |
+
|
1103 |
+
// Retrieve attachment properties.
|
1104 |
+
if ( ! empty( $pids ) ) {
|
1105 |
+
$pids_flat = array_keys( $pids );
|
1106 |
+
// Retrieve attachment post data.
|
1107 |
+
$atts = get_posts(
|
1108 |
+
array(
|
1109 |
+
'post_type' => 'attachment',
|
1110 |
+
'include' => $pids_flat,
|
1111 |
+
)
|
1112 |
+
);
|
1113 |
+
|
1114 |
+
// Process attachments.
|
1115 |
+
if ( $atts ) {
|
1116 |
+
$props_post_map = [
|
1117 |
+
'title' => 'post_title',
|
1118 |
+
'caption' => 'post_excerpt',
|
1119 |
+
'description' => 'post_content',
|
1120 |
+
];
|
1121 |
+
|
1122 |
+
foreach ( $atts as $att ) {
|
1123 |
+
$data = [];
|
1124 |
+
// Remap post data to metadata.
|
1125 |
+
foreach ( $props_post_map as $props_post_key => $props_post_source ) {
|
1126 |
+
$data[ $props_post_key ] = $att->{$props_post_source};
|
1127 |
+
}
|
1128 |
+
// Cleanup.
|
1129 |
+
unset( $props_post_key, $props_post_source );
|
1130 |
+
|
1131 |
+
// Save data to corresponding media item(s).
|
1132 |
+
if ( isset( $pids[ $att->ID ] ) ) {
|
1133 |
+
foreach ( $pids[ $att->ID ] as $key ) {
|
1134 |
+
$this->media_items[ $key ] = (object) array_merge( (array) $this->media_items[ $key ], $data );
|
1135 |
+
}
|
1136 |
+
}
|
1137 |
+
}
|
1138 |
+
// Cleanup.
|
1139 |
+
unset( $att, $data );
|
1140 |
+
}
|
1141 |
+
// Cleanup.
|
1142 |
+
unset( $atts, $atts_meta, $m, $a, $uri, $pids, $pids_flat );
|
1143 |
+
}
|
1144 |
+
|
1145 |
+
// Filter media items.
|
1146 |
+
$this->media_items = $this->util->apply_filters( 'media_items', $this->media_items );
|
1147 |
+
|
1148 |
+
// Build client output.
|
1149 |
+
$obj = 'View.assets';
|
1150 |
+
$client_script[] = $this->util->extend_client_object( $obj, $this->media_items );
|
1151 |
+
return $client_script;
|
1152 |
+
}
|
1153 |
+
|
1154 |
+
/*-** Media **-*/
|
1155 |
+
|
1156 |
+
/**
|
1157 |
+
* Cache media properties for later processing
|
1158 |
+
* @uses array self::$media_items_raw Stores media items for output
|
1159 |
+
* @param object $uri URI to cache
|
1160 |
+
* Members
|
1161 |
+
* > raw: Raw Link URI
|
1162 |
+
* > source: Source URI (e.g. for attachment URIs)
|
1163 |
+
* @param string $type Media type (image, attachment, etc.)
|
1164 |
+
* @param bool $internal TRUE if media is internal (e.g. attachment)
|
1165 |
+
* @param array $props (optional) Properties to store for item (Default: NULL)
|
1166 |
+
* @return string Unique ID for cached media item
|
1167 |
+
*/
|
1168 |
+
private function cache_media_item( $uri, $type, $internal, $props = null ) {
|
1169 |
+
// Validate.
|
1170 |
+
if ( ! is_object( $uri ) || ! is_string( $type ) ) {
|
1171 |
+
return false;
|
1172 |
+
}
|
1173 |
+
// Check if URI already cached.
|
1174 |
+
$key = $this->get_media_item_id( $uri->source );
|
1175 |
+
// Cache new item.
|
1176 |
+
if ( null === $key ) {
|
1177 |
+
// Generate Unique ID.
|
1178 |
+
do {
|
1179 |
+
$key = (string) wp_rand();
|
1180 |
+
} while ( isset( $this->media_items_raw['props'][ $key ] ) );
|
1181 |
+
// Build properties object.
|
1182 |
+
$i = $this->media_item_template;
|
1183 |
+
if ( is_array( $props ) && ! empty( $props ) ) {
|
1184 |
+
$i = array_merge( $i, $props );
|
1185 |
+
}
|
1186 |
+
$i = array_merge(
|
1187 |
+
$i,
|
1188 |
+
[
|
1189 |
+
'type' => $type,
|
1190 |
+
'source' => $uri->source,
|
1191 |
+
'internal' => $internal,
|
1192 |
+
]
|
1193 |
+
);
|
1194 |
+
// Cache item properties.
|
1195 |
+
$this->media_items_raw['props'][ $key ] = (object) $i;
|
1196 |
+
// Cache Source URI (point to properties object).
|
1197 |
+
$this->media_items_raw['uri'][ $uri->source ] = $key;
|
1198 |
+
}
|
1199 |
+
return $key;
|
1200 |
+
}
|
1201 |
+
|
1202 |
+
/**
|
1203 |
+
* Retrieve ID for media item
|
1204 |
+
* @uses self::$media_items_raw
|
1205 |
+
* @param string $uri Media item URI
|
1206 |
+
* @return string|null Media item ID (Default: NULL if URI doesn't exist in collection)
|
1207 |
+
*/
|
1208 |
+
private function get_media_item_id( $uri ) {
|
1209 |
+
if ( $this->media_item_cached( $uri ) ) {
|
1210 |
+
return $this->media_items_raw['uri'][ $uri ];
|
1211 |
+
}
|
1212 |
+
return null;
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
/**
|
1216 |
+
* Checks if media item has already been cached
|
1217 |
+
* @param string $uri URI of media item
|
1218 |
+
* @return boolean Whether media item has been cached
|
1219 |
+
*/
|
1220 |
+
private function media_item_cached( $uri ) {
|
1221 |
+
return ( is_string( $uri ) && ! empty( $uri ) && isset( $this->media_items_raw['uri'][ $uri ] ) ) ? true : false;
|
1222 |
+
}
|
1223 |
+
|
1224 |
+
/**
|
1225 |
+
* Retrieve cached media item
|
1226 |
+
* @param string $uri Media item URI
|
1227 |
+
* @return object|null Media item properties (NULL if not set)
|
1228 |
+
*/
|
1229 |
+
private function get_cached_media_item( $uri ) {
|
1230 |
+
$key = $this->get_media_item_id( $uri );
|
1231 |
+
if ( null !== $key ) {
|
1232 |
+
return $this->media_items_raw['props'][ $key ];
|
1233 |
+
}
|
1234 |
+
return null;
|
1235 |
+
}
|
1236 |
+
|
1237 |
+
/**
|
1238 |
+
* Retrieve cached media items (properties)
|
1239 |
+
* @uses self::$media_items_raw
|
1240 |
+
* @return array Cached media items (objects)
|
1241 |
+
*/
|
1242 |
+
private function &get_cached_media_items() {
|
1243 |
+
return $this->media_items_raw['props'];
|
1244 |
+
}
|
1245 |
+
|
1246 |
+
/**
|
1247 |
+
* Check if media items have been cached
|
1248 |
+
* @return boolean
|
1249 |
+
*/
|
1250 |
+
private function has_cached_media_items() {
|
1251 |
+
return ( empty( $this->media_items_raw['props'] ) ) ? false : true;
|
1252 |
+
}
|
1253 |
+
|
1254 |
+
/*-** Exclusion **-*/
|
1255 |
+
|
1256 |
+
/**
|
1257 |
+
* Retrieve exclude object
|
1258 |
+
* Initialize object properties if necessary
|
1259 |
+
* @return object Exclude properties
|
1260 |
+
*/
|
1261 |
+
private function get_exclude() {
|
1262 |
+
// Initialize exclude data
|
1263 |
+
if ( ! is_object( $this->exclude ) ) {
|
1264 |
+
$this->exclude = (object) array(
|
1265 |
+
'tags' => $this->get_exclude_tags(),
|
1266 |
+
'ph' => $this->get_exclude_placeholder(),
|
1267 |
+
'group_default' => 'default',
|
1268 |
+
'cache' => array(),
|
1269 |
+
);
|
1270 |
+
}
|
1271 |
+
return $this->exclude;
|
1272 |
+
}
|
1273 |
+
|
1274 |
+
/**
|
1275 |
+
* Get exclusion tags (open/close)
|
1276 |
+
* Example: open => [slb_exclude], close => [/slb_exclude]
|
1277 |
+
*
|
1278 |
+
* @return object Exclusion tags
|
1279 |
+
*/
|
1280 |
+
private function get_exclude_tags() {
|
1281 |
+
static $tags = null;
|
1282 |
+
if ( null === $tags ) {
|
1283 |
+
/* Init tag elements */
|
1284 |
+
$tags = (object) [
|
1285 |
+
// Tag base.
|
1286 |
+
'base' => $this->add_prefix( 'exclude' ),
|
1287 |
+
];
|
1288 |
+
// Opening tag.
|
1289 |
+
$tags->open = $this->util->add_wrapper( $tags->base );
|
1290 |
+
// Closing tag.
|
1291 |
+
$tags->close = $this->util->add_wrapper( $tags->base, '[/', ']' );
|
1292 |
+
|
1293 |
+
/* Build tag search pattern */
|
1294 |
+
|
1295 |
+
// Pattern delimeter.
|
1296 |
+
$dlm = '#';
|
1297 |
+
// Pattern flags.
|
1298 |
+
$flags = 's';
|
1299 |
+
// Tag search pattern.
|
1300 |
+
$tags->search = $dlm . preg_quote( $tags->open, $dlm ) . '(.*?)' . preg_quote( $tags->close, $dlm ) . $dlm . $flags;
|
1301 |
+
}
|
1302 |
+
return $tags;
|
1303 |
+
}
|
1304 |
+
|
1305 |
+
|
1306 |
+
/**
|
1307 |
+
* Get exclusion tag ("[slb_exclude]")
|
1308 |
+
* @uses `get_exclude_tags()` to retrieve tag
|
1309 |
+
*
|
1310 |
+
* @param string $type (optional) Tag to retrieve (open or close)
|
1311 |
+
* @return string Exclusion tag
|
1312 |
+
*/
|
1313 |
+
private function get_exclude_tag( $type = 'open' ) {
|
1314 |
+
// Validate
|
1315 |
+
$tags = $this->get_exclude_tags();
|
1316 |
+
if ( ! isset( $tags->{$type} ) ) {
|
1317 |
+
$type = 'open';
|
1318 |
+
}
|
1319 |
+
return $tags->{$type};
|
1320 |
+
}
|
1321 |
+
|
1322 |
+
/**
|
1323 |
+
* Build exclude placeholder
|
1324 |
+
* @return object Exclude placeholder properties
|
1325 |
+
*/
|
1326 |
+
private function get_exclude_placeholder() {
|
1327 |
+
static $ph;
|
1328 |
+
if ( ! is_object( $ph ) ) {
|
1329 |
+
$ph = (object) array(
|
1330 |
+
'base' => $this->add_prefix( 'exclude_temp' ),
|
1331 |
+
'open' => '{{',
|
1332 |
+
'close' => '}}',
|
1333 |
+
'attrs' => array(
|
1334 |
+
'group' => '',
|
1335 |
+
'key' => '',
|
1336 |
+
),
|
1337 |
+
);
|
1338 |
+
// Search Patterns
|
1339 |
+
$sub = '(.+?)';
|
1340 |
+
$dlm = '#';
|
1341 |
+
$flags = 's';
|
1342 |
+
$ph->search = $dlm . preg_quote( $ph->open, $dlm ) . $ph->base . '\s+' . $sub . preg_quote( $ph->close, $dlm ) . $dlm . $flags;
|
1343 |
+
$ph->search_group = str_replace( $sub, '(group="%s"\s+.?)', $ph->search );
|
1344 |
+
// Templates
|
1345 |
+
$attr_string = '';
|
1346 |
+
foreach ( $ph->attrs as $attr => $val ) {
|
1347 |
+
$attr_string .= ' ' . $attr . '="%s"';
|
1348 |
+
}
|
1349 |
+
$ph->template = $ph->open . $ph->base . $attr_string . $ph->close;
|
1350 |
+
}
|
1351 |
+
return $ph;
|
1352 |
+
}
|
1353 |
+
|
1354 |
+
/**
|
1355 |
+
* Wrap content in exclusion tags
|
1356 |
+
* @uses `get_exclude_tag()` to wrap content with exclusion tag
|
1357 |
+
* @param string $content Content to exclude
|
1358 |
+
* @return string Content wrapped in exclusion tags
|
1359 |
+
*/
|
1360 |
+
private function exclude_wrap( $content ) {
|
1361 |
+
// Validate
|
1362 |
+
if ( ! is_string( $content ) ) {
|
1363 |
+
$content = '';
|
1364 |
+
}
|
1365 |
+
// Wrap
|
1366 |
+
$tags = $this->get_exclude_tags();
|
1367 |
+
return $tags->open . $content . $tags->close;
|
1368 |
+
}
|
1369 |
+
|
1370 |
+
/**
|
1371 |
+
* Remove excluded content
|
1372 |
+
* Caches content for restoring later
|
1373 |
+
* @param string $content Content to remove excluded content from
|
1374 |
+
* @return string Updated content
|
1375 |
+
*/
|
1376 |
+
public function exclude_content( $content, $group = null ) {
|
1377 |
+
$ex = $this->get_exclude();
|
1378 |
+
// Setup cache
|
1379 |
+
if ( ! is_string( $group ) || empty( $group ) ) {
|
1380 |
+
$group = $ex->group_default;
|
1381 |
+
}
|
1382 |
+
if ( ! isset( $ex->cache[ $group ] ) ) {
|
1383 |
+
$ex->cache[ $group ] = array();
|
1384 |
+
}
|
1385 |
+
$cache =& $ex->cache[ $group ];
|
1386 |
+
|
1387 |
+
$content = $this->util->apply_filters( 'pre_exclude_content', $content );
|
1388 |
+
|
1389 |
+
// Search content
|
1390 |
+
$matches = null;
|
1391 |
+
if ( false !== strpos( $content, $ex->tags->open ) && preg_match_all( $ex->tags->search, $content, $matches ) ) {
|
1392 |
+
// Determine index
|
1393 |
+
$idx = ( ! ! end( $cache ) ) ? key( $cache ) : -1;
|
1394 |
+
$ph = array();
|
1395 |
+
foreach ( $matches[1] as $midx => $match ) {
|
1396 |
+
// Update index
|
1397 |
+
$idx++;
|
1398 |
+
// Cache content
|
1399 |
+
$cache[ $idx ] = $match;
|
1400 |
+
// Build placeholder
|
1401 |
+
$ph[] = sprintf( $ex->ph->template, $group, $idx );
|
1402 |
+
}
|
1403 |
+
unset( $midx, $match );
|
1404 |
+
// Replace content with placeholder
|
1405 |
+
$content = str_replace( $matches[0], $ph, $content );
|
1406 |
+
|
1407 |
+
// Cleanup
|
1408 |
+
unset( $matches, $ph );
|
1409 |
+
}
|
1410 |
+
|
1411 |
+
return $content;
|
1412 |
+
}
|
1413 |
+
|
1414 |
+
/**
|
1415 |
+
* Exclude shortcodes from link activation
|
1416 |
+
* @param string $content Content to exclude shortcodes from
|
1417 |
+
* @return string Content with shortcodes excluded
|
1418 |
+
*/
|
1419 |
+
public function exclude_shortcodes( $content ) {
|
1420 |
+
// Get shortcodes to exclude
|
1421 |
+
$shortcodes = $this->util->apply_filters( 'exclude_shortcodes', array( $this->add_prefix( 'group' ) ) );
|
1422 |
+
// Set callback
|
1423 |
+
$shortcodes = array_fill_keys( $shortcodes, $this->m( 'exclude_shortcodes_handler' ) );
|
1424 |
+
return $this->util->do_shortcode( $content, $shortcodes );
|
1425 |
+
}
|
1426 |
+
|
1427 |
+
/**
|
1428 |
+
* Wrap shortcode in exclude tags
|
1429 |
+
* @uses Util->make_shortcode() to rebuild original shortcode
|
1430 |
+
*
|
1431 |
+
* @param array $attr Shortcode attributes
|
1432 |
+
* @param string $content Content enclosed in shortcode
|
1433 |
+
* @param string $tag Shortcode name
|
1434 |
+
* @return string Excluded shortcode
|
1435 |
+
*/
|
1436 |
+
public function exclude_shortcodes_handler( $attr, $content, $tag ) {
|
1437 |
+
$code = $this->util->make_shortcode( $tag, $attr, $content );
|
1438 |
+
// Exclude shortcode
|
1439 |
+
return $this->exclude_wrap( $code );
|
1440 |
+
}
|
1441 |
+
|
1442 |
+
/**
|
1443 |
+
* Restore excluded content
|
1444 |
+
* @param string $content Content to restore excluded content to
|
1445 |
+
* @return string Content with excluded content restored
|
1446 |
+
*/
|
1447 |
+
public function restore_excluded_content( $content, $group = null ) {
|
1448 |
+
$ex = $this->get_exclude();
|
1449 |
+
// Setup cache
|
1450 |
+
if ( ! is_string( $group ) || empty( $group ) ) {
|
1451 |
+
$group = $ex->group_default;
|
1452 |
+
}
|
1453 |
+
// Nothing to restore if cache group doesn't exist
|
1454 |
+
if ( ! isset( $ex->cache[ $group ] ) ) {
|
1455 |
+
return $content;
|
1456 |
+
}
|
1457 |
+
$cache =& $ex->cache[ $group ];
|
1458 |
+
|
1459 |
+
// Search content for placeholders
|
1460 |
+
$matches = null;
|
1461 |
+
if ( false !== strpos( $content, $ex->ph->open . $ex->ph->base ) && preg_match_all( $ex->ph->search, $content, $matches ) ) {
|
1462 |
+
// Restore placeholders
|
1463 |
+
foreach ( $matches[1] as $idx => $ph ) {
|
1464 |
+
// Parse placeholder attributes
|
1465 |
+
$attrs = $this->util->parse_attribute_string( $ph, $ex->ph->attrs );
|
1466 |
+
// Validate
|
1467 |
+
if ( $attrs['group'] !== $group ) {
|
1468 |
+
continue;
|
1469 |
+
}
|
1470 |
+
// Restore content
|
1471 |
+
$attrs['key'] = intval( $attrs['key'] );
|
1472 |
+
$key = $attrs['key'];
|
1473 |
+
|
1474 |
+
if ( isset( $cache[ $key ] ) ) {
|
1475 |
+
$content = str_replace( $matches[0][ $idx ], $cache[ $key ], $content );
|
1476 |
+
}
|
1477 |
+
}
|
1478 |
+
// Cleanup
|
1479 |
+
unset( $idx, $ph, $matches, $key );
|
1480 |
+
}
|
1481 |
+
|
1482 |
+
return $content;
|
1483 |
+
}
|
1484 |
+
|
1485 |
+
/*-** Grouping **-*/
|
1486 |
+
|
1487 |
+
/**
|
1488 |
+
* Builds wrapper for grouping
|
1489 |
+
* @return string Format for wrapping content in group
|
1490 |
+
*/
|
1491 |
+
function group_get_wrapper() {
|
1492 |
+
static $fmt = null;
|
1493 |
+
if ( is_null( $fmt ) ) {
|
1494 |
+
$fmt = $this->util->make_shortcode( $this->add_prefix( 'group' ), null, '%s' );
|
1495 |
+
}
|
1496 |
+
return $fmt;
|
1497 |
+
}
|
1498 |
+
|
1499 |
+
/**
|
1500 |
+
* Wraps shortcodes for automatic grouping
|
1501 |
+
* @uses `the_content` Filter hook
|
1502 |
+
* @uses group_shortcodes_handler to Wrap shortcodes for grouping
|
1503 |
+
* @param string $content Post content
|
1504 |
+
* @return string Modified post content
|
1505 |
+
*/
|
1506 |
+
function group_shortcodes( $content ) {
|
1507 |
+
if ( ! $this->is_content_valid( $content ) ) {
|
1508 |
+
return $content;
|
1509 |
+
}
|
1510 |
+
// Setup shortcodes to wrap
|
1511 |
+
$shortcodes = $this->util->apply_filters( 'group_shortcodes', array( 'gallery', 'nggallery' ) );
|
1512 |
+
// Set custom callback
|
1513 |
+
$shortcodes = array_fill_keys( $shortcodes, $this->m( 'group_shortcodes_handler' ) );
|
1514 |
+
// Process gallery shortcodes
|
1515 |
+
return $this->util->do_shortcode( $content, $shortcodes );
|
1516 |
+
}
|
1517 |
+
|
1518 |
+
/**
|
1519 |
+
* Groups shortcodes for later processing
|
1520 |
+
* @param array $attr Shortcode attributes
|
1521 |
+
* @param string $content Content enclosed in shortcode
|
1522 |
+
* @param string $tag Shortcode name
|
1523 |
+
* @return string Grouped shortcode
|
1524 |
+
*/
|
1525 |
+
function group_shortcodes_handler( $attr, $content, $tag ) {
|
1526 |
+
$code = $this->util->make_shortcode( $tag, $attr, $content );
|
1527 |
+
// Wrap shortcode
|
1528 |
+
return sprintf( $this->group_get_wrapper(), $code );
|
1529 |
+
}
|
1530 |
+
|
1531 |
+
/**
|
1532 |
+
* Activate groups in content
|
1533 |
+
* @param string $content Content to activate
|
1534 |
+
* @return string Updated content
|
1535 |
+
*/
|
1536 |
+
public function activate_groups( $content ) {
|
1537 |
+
return $this->util->do_shortcode( $content, array( $this->add_prefix( 'group' ) => $this->m( 'activate_groups_handler' ) ) );
|
1538 |
+
}
|
1539 |
+
|
1540 |
+
/**
|
1541 |
+
* Groups shortcodes for later processing
|
1542 |
+
* @param array $attr Shortcode attributes
|
1543 |
+
* @param string $content Content enclosed in shortcode
|
1544 |
+
* @param string $tag Shortcode name
|
1545 |
+
* @return string Grouped shortcode
|
1546 |
+
*/
|
1547 |
+
function activate_groups_handler( $attr, $content, $tag ) {
|
1548 |
+
// Get Group ID
|
1549 |
+
// Custom group
|
1550 |
+
if ( isset( $attr['id'] ) ) {
|
1551 |
+
$group = $attr['id'];
|
1552 |
+
trim( $group );
|
1553 |
+
}
|
1554 |
+
// Automatically-generated group
|
1555 |
+
if ( empty( $group ) ) {
|
1556 |
+
$group = 'auto_' . ( ++$this->groups['auto'] );
|
1557 |
+
}
|
1558 |
+
return $this->process_links( $content, $group );
|
1559 |
+
}
|
1560 |
+
|
1561 |
+
/*-** Widgets **-*/
|
1562 |
+
|
1563 |
+
/**
|
1564 |
+
* Set widget up for processing/activation
|
1565 |
+
* Buffers widget output for further processing
|
1566 |
+
* @param array $widget_args Widget arguments
|
1567 |
+
* @return void
|
1568 |
+
*/
|
1569 |
+
public function widget_process_start( $widget_args ) {
|
1570 |
+
// Do not continue if a widget is currently being processed (avoid nested processing)
|
1571 |
+
if ( 0 < $this->widget_processing_level ) {
|
1572 |
+
return;
|
1573 |
+
}
|
1574 |
+
// Start widget processing
|
1575 |
+
$this->widget_processing = true;
|
1576 |
+
$this->widget_processing_params = $widget_args;
|
1577 |
+
// Enable widget grouping
|
1578 |
+
if ( $this->options->get_bool( 'group_widget' ) ) {
|
1579 |
+
$this->util->add_filter( 'get_group_id', $this->m( 'widget_group_id' ) );
|
1580 |
+
}
|
1581 |
+
// Begin output buffer
|
1582 |
+
ob_start();
|
1583 |
+
}
|
1584 |
+
|
1585 |
+
/**
|
1586 |
+
* Handles inter-widget processing
|
1587 |
+
* After widget output generated, Before next widget starts
|
1588 |
+
* @param array $params New widget parameters
|
1589 |
+
*/
|
1590 |
+
public function widget_process_inter( $params ) {
|
1591 |
+
$this->widget_process_finish();
|
1592 |
+
return $params;
|
1593 |
+
}
|
1594 |
+
|
1595 |
+
/**
|
1596 |
+
* Complete widget processing
|
1597 |
+
* Activate widget output
|
1598 |
+
* @uses $widget_processing
|
1599 |
+
* @uses $widget_processing_level
|
1600 |
+
* @uses $widget_processing_params
|
1601 |
+
* @return void
|
1602 |
+
*/
|
1603 |
+
public function widget_process_finish() {
|
1604 |
+
/**
|
1605 |
+
* Stop processing on conditions:
|
1606 |
+
* - No widget is being processed
|
1607 |
+
* - Processing a nested widget
|
1608 |
+
*/
|
1609 |
+
if ( ! $this->widget_processing || 0 < $this->widget_processing_level ) {
|
1610 |
+
return;
|
1611 |
+
}
|
1612 |
+
// Activate widget output
|
1613 |
+
$out = $this->activate_links( ob_get_clean() );
|
1614 |
+
|
1615 |
+
// Clear grouping callback
|
1616 |
+
if ( $this->options->get_bool( 'group_widget' ) ) {
|
1617 |
+
$this->util->remove_filter( 'get_group_id', $this->m( 'widget_group_id' ) );
|
1618 |
+
}
|
1619 |
+
// End widget processing
|
1620 |
+
$this->widget_processing = false;
|
1621 |
+
$this->widget_processing_params = null;
|
1622 |
+
// Output widget
|
1623 |
+
echo $out;
|
1624 |
+
}
|
1625 |
+
|
1626 |
+
/**
|
1627 |
+
* Add widget ID to link group ID
|
1628 |
+
* Widget ID precedes all other group segments
|
1629 |
+
* @uses `SLB::get_group_id` filter
|
1630 |
+
* @param array $group_segments Group ID segments
|
1631 |
+
* @return array Modified group ID segments
|
1632 |
+
*/
|
1633 |
+
public function widget_group_id( $group_segments ) {
|
1634 |
+
// Add current widget ID to group ID
|
1635 |
+
if ( isset( $this->widget_processing_params['id'] ) ) {
|
1636 |
+
array_unshift( $group_segments, $this->widget_processing_params['id'] );
|
1637 |
+
}
|
1638 |
+
return $group_segments;
|
1639 |
+
}
|
1640 |
+
|
1641 |
+
/**
|
1642 |
+
* Handles nested activation in widgets
|
1643 |
+
* @uses widget_processing
|
1644 |
+
* @uses $widget_processing_level
|
1645 |
+
* @return void
|
1646 |
+
*/
|
1647 |
+
public function widget_process_nested() {
|
1648 |
+
// Stop if no widget is being processed
|
1649 |
+
if ( ! $this->widget_processing ) {
|
1650 |
+
return;
|
1651 |
+
}
|
1652 |
+
|
1653 |
+
// Increment nesting level
|
1654 |
+
$this->widget_processing_level++;
|
1655 |
+
}
|
1656 |
+
|
1657 |
+
/**
|
1658 |
+
* Mark the end of a nested widget
|
1659 |
+
* @uses $widget_processing_level
|
1660 |
+
*/
|
1661 |
+
public function widget_process_nested_finish() {
|
1662 |
+
// Decrement nesting level
|
1663 |
+
if ( 0 < $this->widget_processing_level ) {
|
1664 |
+
$this->widget_processing_level--;
|
1665 |
+
}
|
1666 |
+
}
|
1667 |
+
|
1668 |
+
/**
|
1669 |
+
* Begin blocking widget activation
|
1670 |
+
* @return void
|
1671 |
+
*/
|
1672 |
+
public function widget_block_start() {
|
1673 |
+
$this->util->add_filter( 'is_content_valid', $this->m( 'widget_block_handle' ) );
|
1674 |
+
}
|
1675 |
+
|
1676 |
+
/**
|
1677 |
+
* Stop blocking widget activation
|
1678 |
+
* @return void
|
1679 |
+
*/
|
1680 |
+
public function widget_block_finish() {
|
1681 |
+
$this->util->remove_filter( 'is_content_valid', $this->m( 'widget_block_handle' ) );
|
1682 |
+
}
|
1683 |
+
|
1684 |
+
/**
|
1685 |
+
* Handle widget activation blocking
|
1686 |
+
*/
|
1687 |
+
public function widget_block_handle( $is_content_valid ) {
|
1688 |
+
return false;
|
1689 |
+
}
|
1690 |
+
|
1691 |
+
/*-** Menus **-*/
|
1692 |
+
|
1693 |
+
/**
|
1694 |
+
* Process navigation menu links
|
1695 |
+
*
|
1696 |
+
* @see wp_nav_menu()/filter: wp_nav_menu
|
1697 |
+
*
|
1698 |
+
* @param string $nav_menu HTML content for navigation menu.
|
1699 |
+
* @param object $args Navigation menu's arguments.
|
1700 |
+
*/
|
1701 |
+
public function menu_process( $nav_menu, $args ) {
|
1702 |
+
// Grouping
|
1703 |
+
if ( $this->options->get_bool( 'group_menu' ) ) {
|
1704 |
+
// Generate group ID for menu
|
1705 |
+
$group = 'menu';
|
1706 |
+
$sep = '_';
|
1707 |
+
if ( ! empty( $args->menu_id ) ) {
|
1708 |
+
$group .= $sep . $args->menu_id;
|
1709 |
+
} elseif ( ! empty( $args->menu ) ) {
|
1710 |
+
$group .= $sep . ( ( is_object( $args->menu ) ) ? $args->menu->slug : $args->menu );
|
1711 |
+
}
|
1712 |
+
$group = $this->group_id_unique( $group );
|
1713 |
+
} else {
|
1714 |
+
$group = null;
|
1715 |
+
}
|
1716 |
+
|
1717 |
+
// Process menu
|
1718 |
+
$nav_menu = $this->activate_links( $nav_menu, $group );
|
1719 |
+
|
1720 |
+
return $nav_menu;
|
1721 |
+
}
|
1722 |
+
|
1723 |
+
/**
|
1724 |
+
* Generate unique group ID
|
1725 |
+
*
|
1726 |
+
* @param string $group Group ID to check
|
1727 |
+
* @return string Unique group ID
|
1728 |
+
*/
|
1729 |
+
public function group_id_unique( $group ) {
|
1730 |
+
static $groups = array();
|
1731 |
+
while ( in_array( $group, $groups, true ) ) {
|
1732 |
+
$patt = '#-(\d+)$#';
|
1733 |
+
if ( preg_match( $patt, $group, $matches ) ) {
|
1734 |
+
$group = preg_replace( $patt, '-' . ( ++$matches[1] ), $group );
|
1735 |
+
} else {
|
1736 |
+
$group = $group . '-1';
|
1737 |
+
}
|
1738 |
+
}
|
1739 |
+
// Add final group ID to array
|
1740 |
+
$groups[] = $group;
|
1741 |
+
return $group;
|
1742 |
+
}
|
1743 |
+
|
1744 |
+
/*-** Helpers **-*/
|
1745 |
+
|
1746 |
+
/**
|
1747 |
+
* Build attribute name
|
1748 |
+
* Makes sure name is only prefixed once
|
1749 |
+
* @param string $name (optional) Attribute base name
|
1750 |
+
* @return string Formatted attribute name
|
1751 |
+
*/
|
1752 |
+
function make_attribute_name( $name = '' ) {
|
1753 |
+
// Validate
|
1754 |
+
if ( ! is_string( $name ) ) {
|
1755 |
+
$name = '';
|
1756 |
+
} else {
|
1757 |
+
$name = trim( $name );
|
1758 |
+
}
|
1759 |
+
// Setup
|
1760 |
+
$sep = '-';
|
1761 |
+
$top = 'data';
|
1762 |
+
// Generate valid name
|
1763 |
+
if ( strpos( $name, $top . $sep . $this->get_prefix() ) !== 0 ) {
|
1764 |
+
$name = $top . $sep . $this->add_prefix( $name, $sep );
|
1765 |
+
}
|
1766 |
+
return $name;
|
1767 |
+
}
|
1768 |
+
|
1769 |
+
/**
|
1770 |
+
* Sets attribute value.
|
1771 |
+
*
|
1772 |
+
* Attribute is added to array if it does not already exist.
|
1773 |
+
*
|
1774 |
+
* @param string|array $attrs Array to set attribute on (Passed by reference).
|
1775 |
+
* @param string $name Name of attribute to set.
|
1776 |
+
* @param scalar $value Optional. Attribute value.
|
1777 |
+
* @return array Updated attributes.
|
1778 |
+
*/
|
1779 |
+
function set_attribute( &$attrs, $name, $value = true ) {
|
1780 |
+
// Validate
|
1781 |
+
$attrs = $this->get_attributes( $attrs, false );
|
1782 |
+
// Stop if attribute name or value is invalid.
|
1783 |
+
if ( ! is_string( $name ) || empty( trim( $name ) ) || ! is_scalar( $value ) ) {
|
1784 |
+
return $attrs;
|
1785 |
+
}
|
1786 |
+
// Set attribute value.
|
1787 |
+
$attrs = array_merge( $attrs, array( $this->make_attribute_name( $name ) => $value ) );
|
1788 |
+
|
1789 |
+
return $attrs;
|
1790 |
+
}
|
1791 |
+
|
1792 |
+
/**
|
1793 |
+
* Converts attribute string into array.
|
1794 |
+
*
|
1795 |
+
* @param string|array $attrs Attribute string to convert. Associative array also accepted.
|
1796 |
+
* @param bool $internal Optional. Return only internal attributes. Default True.
|
1797 |
+
* @return array Associative array of attributes (`attribute-name => attribute-value`).
|
1798 |
+
*/
|
1799 |
+
function get_attributes( $attrs, $internal = true ) {
|
1800 |
+
// Parse attribute string.
|
1801 |
+
$attrs = $this->util->parse_attribute_string( $attrs );
|
1802 |
+
// Include only internal attributes (if necessary).
|
1803 |
+
if ( ! ! $internal && ! empty( $attrs ) ) {
|
1804 |
+
$prefix = $this->make_attribute_name();
|
1805 |
+
$attrs = array_filter(
|
1806 |
+
$attrs,
|
1807 |
+
function( $key ) use ( $prefix ) {
|
1808 |
+
return ( strpos( $key, $prefix ) === 0 );
|
1809 |
+
},
|
1810 |
+
ARRAY_FILTER_USE_KEY
|
1811 |
+
);
|
1812 |
+
}
|
1813 |
+
|
1814 |
+
return $attrs;
|
1815 |
+
}
|
1816 |
+
|
1817 |
+
/**
|
1818 |
+
* Retrieves an attributes value from attribute string or array.
|
1819 |
+
*
|
1820 |
+
* @param string|array $attrs Attribute string to retrieve attribute value from.
|
1821 |
+
* Associative array also accepted.
|
1822 |
+
* @param string $attr Attribute to retrieve value for.
|
1823 |
+
* @param bool $internal Optional. Retrieve internal attribute. Default true.
|
1824 |
+
* @return scalar|null Attribute value. Null if attribute is invalid or does not exist.
|
1825 |
+
*/
|
1826 |
+
function get_attribute( $attrs, $attr, $internal = true ) {
|
1827 |
+
// Validate.
|
1828 |
+
$invalid = null;
|
1829 |
+
if ( ! is_string( $attr ) || empty( trim( $attr ) ) ) {
|
1830 |
+
return $invalid;
|
1831 |
+
}
|
1832 |
+
$attrs = $this->get_attributes( $attrs, $internal );
|
1833 |
+
if ( empty( $attrs ) ) {
|
1834 |
+
return $invalid;
|
1835 |
+
}
|
1836 |
+
// Format attribute name.
|
1837 |
+
$attr = ( ! ! $internal ) ? $this->make_attribute_name( $attr ) : trim( $attr );
|
1838 |
+
// Stop if attribute does not exist or value is invalid.
|
1839 |
+
if ( ! isset( $attrs[ $attr ] ) || ! is_scalar( $attrs[ $attr ] ) ) {
|
1840 |
+
return $invalid;
|
1841 |
+
}
|
1842 |
+
// Retreive value.
|
1843 |
+
$ret = $attrs[ $attr ];
|
1844 |
+
// Validate value (type-specific).
|
1845 |
+
if ( is_string( $ret ) ) {
|
1846 |
+
$ret = trim( $ret );
|
1847 |
+
if ( '' === $ret ) {
|
1848 |
+
return $invalid;
|
1849 |
+
}
|
1850 |
+
}
|
1851 |
+
|
1852 |
+
return $ret;
|
1853 |
+
}
|
1854 |
+
|
1855 |
+
/**
|
1856 |
+
* Checks if attribute exists.
|
1857 |
+
*
|
1858 |
+
* @param string|array $attrs Attribute string to retrieve attribute value from.
|
1859 |
+
* Associative array also accepted.
|
1860 |
+
* @param string $attr Attribute to retrieve value for.
|
1861 |
+
* @param bool $internal Optional. Retrieve internal attribute. Default true.
|
1862 |
+
* @return bool True if attribute exists. False if attribute does not exist.
|
1863 |
+
*/
|
1864 |
+
function has_attribute( $attrs, $attr, $internal = true ) {
|
1865 |
+
return ( null !== $this->get_attribute( $attrs, $attr, $internal ) );
|
1866 |
+
}
|
1867 |
+
|
1868 |
+
/**
|
1869 |
+
* Build JS object of UI strings when initializing lightbox
|
1870 |
+
* @return array UI strings
|
1871 |
+
*/
|
1872 |
+
private function build_labels() {
|
1873 |
+
$ret = array();
|
1874 |
+
/* Get all UI options */
|
1875 |
+
$prefix = 'txt_';
|
1876 |
+
$opt_strings = array_filter(
|
1877 |
+
array_keys( $this->options->get_items() ),
|
1878 |
+
function ( $opt ) use ( $prefix ) {
|
1879 |
+
return ( strpos( $opt, $prefix ) === 0 );
|
1880 |
+
}
|
1881 |
+
);
|
1882 |
+
if ( count( $opt_strings ) ) {
|
1883 |
+
/* Build array of UI options */
|
1884 |
+
foreach ( $opt_strings as $key ) {
|
1885 |
+
$name = substr( $key, strlen( $prefix ) );
|
1886 |
+
$ret[ $name ] = $this->options->get_value( $key );
|
1887 |
+
}
|
1888 |
+
}
|
1889 |
+
return $ret;
|
1890 |
+
}
|
1891 |
+
}
|
functions.php
CHANGED
@@ -1,24 +1,24 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Functions
|
4 |
-
* Provides global access to specific functionality
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @author Archetyped
|
7 |
-
*/
|
8 |
-
|
9 |
-
/* Template Tags */
|
10 |
-
|
11 |
-
/**
|
12 |
-
* Activate links in user-defined content
|
13 |
-
* @param string $content
|
14 |
-
* @return string Updated content with activated links
|
15 |
-
*/
|
16 |
-
function slb_activate($content, $group = null) {
|
17 |
-
// Validate
|
18 |
-
if ( empty($content) ) {
|
19 |
-
return $content;
|
20 |
-
}
|
21 |
-
// Activate links
|
22 |
-
$content = $GLOBALS['slb']->activate_links($content, $group);
|
23 |
-
return $content;
|
24 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Functions
|
4 |
+
* Provides global access to specific functionality
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @author Archetyped
|
7 |
+
*/
|
8 |
+
|
9 |
+
/* Template Tags */
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Activate links in user-defined content
|
13 |
+
* @param string $content
|
14 |
+
* @return string Updated content with activated links
|
15 |
+
*/
|
16 |
+
function slb_activate( $content, $group = null ) {
|
17 |
+
// Validate
|
18 |
+
if ( empty( $content ) ) {
|
19 |
+
return $content;
|
20 |
+
}
|
21 |
+
// Activate links
|
22 |
+
$content = $GLOBALS['slb']->activate_links( $content, $group );
|
23 |
+
return $content;
|
24 |
+
}
|
grunt/jshint.js
CHANGED
@@ -1,38 +1,38 @@
|
|
1 |
-
module.exports = function(grunt) {
|
2 |
-
|
3 |
-
grunt.config('jshint', {
|
4 |
-
options : {
|
5 |
-
reporter: require('jshint-stylish'),
|
6 |
-
curly : true,
|
7 |
-
eqeqeq : true,
|
8 |
-
immed : true,
|
9 |
-
latedef : true,
|
10 |
-
newcap : false,
|
11 |
-
noarg : true,
|
12 |
-
sub : true,
|
13 |
-
undef : true,
|
14 |
-
unused : true,
|
15 |
-
boss : true,
|
16 |
-
eqnull : true,
|
17 |
-
browser : true,
|
18 |
-
jquery : true,
|
19 |
-
globals : {}
|
20 |
-
},
|
21 |
-
grunt : {
|
22 |
-
options : {
|
23 |
-
node : true
|
24 |
-
},
|
25 |
-
src : ['Gruntfile.js', 'grunt/*.js']
|
26 |
-
},
|
27 |
-
all : {
|
28 |
-
options : {
|
29 |
-
globals : {
|
30 |
-
'SLB' : true,
|
31 |
-
'console' : true
|
32 |
-
}
|
33 |
-
},
|
34 |
-
src : ['<%= paths.js.files %>']
|
35 |
-
},
|
36 |
-
});
|
37 |
-
|
38 |
};
|
1 |
+
module.exports = function(grunt) {
|
2 |
+
|
3 |
+
grunt.config('jshint', {
|
4 |
+
options : {
|
5 |
+
reporter: require('jshint-stylish'),
|
6 |
+
curly : true,
|
7 |
+
eqeqeq : true,
|
8 |
+
immed : true,
|
9 |
+
latedef : true,
|
10 |
+
newcap : false,
|
11 |
+
noarg : true,
|
12 |
+
sub : true,
|
13 |
+
undef : true,
|
14 |
+
unused : true,
|
15 |
+
boss : true,
|
16 |
+
eqnull : true,
|
17 |
+
browser : true,
|
18 |
+
jquery : true,
|
19 |
+
globals : {}
|
20 |
+
},
|
21 |
+
grunt : {
|
22 |
+
options : {
|
23 |
+
node : true
|
24 |
+
},
|
25 |
+
src : ['Gruntfile.js', 'grunt/*.js']
|
26 |
+
},
|
27 |
+
all : {
|
28 |
+
options : {
|
29 |
+
globals : {
|
30 |
+
'SLB' : true,
|
31 |
+
'console' : true
|
32 |
+
}
|
33 |
+
},
|
34 |
+
src : ['<%= paths.js.files %>']
|
35 |
+
},
|
36 |
+
});
|
37 |
+
|
38 |
};
|
grunt/phplint.js
CHANGED
@@ -1,14 +1,14 @@
|
|
1 |
-
module.exports = function(grunt) {
|
2 |
-
|
3 |
-
grunt.config('phplint', {
|
4 |
-
options : {
|
5 |
-
phpArgs : {
|
6 |
-
'-f': null
|
7 |
-
}
|
8 |
-
},
|
9 |
-
all : {
|
10 |
-
src : '<%= paths.php.files %>'
|
11 |
-
}
|
12 |
-
});
|
13 |
-
|
14 |
};
|
1 |
+
module.exports = function(grunt) {
|
2 |
+
|
3 |
+
grunt.config('phplint', {
|
4 |
+
options : {
|
5 |
+
phpArgs : {
|
6 |
+
'-f': null
|
7 |
+
}
|
8 |
+
},
|
9 |
+
all : {
|
10 |
+
src : '<%= paths.php.files %>'
|
11 |
+
}
|
12 |
+
});
|
13 |
+
|
14 |
};
|
grunt/sass.js
CHANGED
@@ -1,37 +1,37 @@
|
|
1 |
-
module.exports = function(grunt) {
|
2 |
-
|
3 |
-
const sass = require('node-sass');
|
4 |
-
|
5 |
-
grunt.config('sass', {
|
6 |
-
options : {
|
7 |
-
implementation: sass,
|
8 |
-
outputStyle : 'compressed',
|
9 |
-
},
|
10 |
-
core : {
|
11 |
-
files : [{
|
12 |
-
expand : true,
|
13 |
-
cwd : '<%= paths.sass.base_src %>/',
|
14 |
-
dest : '<%= paths.sass.base_dest %>/',
|
15 |
-
src : ['<%= paths.sass.target %>', '<%= paths.sass.exclude %>'],
|
16 |
-
ext : '<%= paths.sass.ext %>'
|
17 |
-
}]
|
18 |
-
},
|
19 |
-
themes : {
|
20 |
-
options : {
|
21 |
-
},
|
22 |
-
files : [{
|
23 |
-
expand : true,
|
24 |
-
cwd : 'themes/',
|
25 |
-
src : ['*/**/*.scss', '<%= paths.sass.exclude %>'],
|
26 |
-
dest : '<%= paths.sass.dest %>/',
|
27 |
-
srcd : '<%= paths.sass.src %>/',
|
28 |
-
ext : '<%= paths.sass.ext %>',
|
29 |
-
rename : function(dest, matchedSrcPath, options) {
|
30 |
-
var path = [options.cwd, matchedSrcPath.replace(options.srcd, dest)].join('');
|
31 |
-
return path;
|
32 |
-
}
|
33 |
-
}]
|
34 |
-
}
|
35 |
-
});
|
36 |
-
|
37 |
};
|
1 |
+
module.exports = function(grunt) {
|
2 |
+
|
3 |
+
const sass = require('node-sass');
|
4 |
+
|
5 |
+
grunt.config('sass', {
|
6 |
+
options : {
|
7 |
+
implementation: sass,
|
8 |
+
outputStyle : 'compressed',
|
9 |
+
},
|
10 |
+
core : {
|
11 |
+
files : [{
|
12 |
+
expand : true,
|
13 |
+
cwd : '<%= paths.sass.base_src %>/',
|
14 |
+
dest : '<%= paths.sass.base_dest %>/',
|
15 |
+
src : ['<%= paths.sass.target %>', '<%= paths.sass.exclude %>'],
|
16 |
+
ext : '<%= paths.sass.ext %>'
|
17 |
+
}]
|
18 |
+
},
|
19 |
+
themes : {
|
20 |
+
options : {
|
21 |
+
},
|
22 |
+
files : [{
|
23 |
+
expand : true,
|
24 |
+
cwd : 'themes/',
|
25 |
+
src : ['*/**/*.scss', '<%= paths.sass.exclude %>'],
|
26 |
+
dest : '<%= paths.sass.dest %>/',
|
27 |
+
srcd : '<%= paths.sass.src %>/',
|
28 |
+
ext : '<%= paths.sass.ext %>',
|
29 |
+
rename : function(dest, matchedSrcPath, options) {
|
30 |
+
var path = [options.cwd, matchedSrcPath.replace(options.srcd, dest)].join('');
|
31 |
+
return path;
|
32 |
+
}
|
33 |
+
}]
|
34 |
+
}
|
35 |
+
});
|
36 |
+
|
37 |
};
|
grunt/uglify.js
CHANGED
@@ -1,21 +1,21 @@
|
|
1 |
-
module.exports = function(grunt) {
|
2 |
-
|
3 |
-
grunt.config('uglify', {
|
4 |
-
options : {
|
5 |
-
mangle: false,
|
6 |
-
report: 'min'
|
7 |
-
},
|
8 |
-
all : {
|
9 |
-
files : [{
|
10 |
-
expand : true,
|
11 |
-
cwd : '',
|
12 |
-
dest : '',
|
13 |
-
src : ['<%= paths.js.files %>'],
|
14 |
-
rename : function(dest, srcPath) {
|
15 |
-
return srcPath.replace('/' + grunt.config.get('paths.js.src') + '/', '/' + grunt.config.get('paths.js.dest') + '/');
|
16 |
-
}
|
17 |
-
}]
|
18 |
-
},
|
19 |
-
});
|
20 |
-
|
21 |
};
|
1 |
+
module.exports = function(grunt) {
|
2 |
+
|
3 |
+
grunt.config('uglify', {
|
4 |
+
options : {
|
5 |
+
mangle: false,
|
6 |
+
report: 'min'
|
7 |
+
},
|
8 |
+
all : {
|
9 |
+
files : [{
|
10 |
+
expand : true,
|
11 |
+
cwd : '',
|
12 |
+
dest : '',
|
13 |
+
src : ['<%= paths.js.files %>'],
|
14 |
+
rename : function(dest, srcPath) {
|
15 |
+
return srcPath.replace('/' + grunt.config.get('paths.js.src') + '/', '/' + grunt.config.get('paths.js.dest') + '/');
|
16 |
+
}
|
17 |
+
}]
|
18 |
+
},
|
19 |
+
});
|
20 |
+
|
21 |
};
|
grunt/watch.js
CHANGED
@@ -1,57 +1,57 @@
|
|
1 |
-
module.exports = function(grunt) {
|
2 |
-
|
3 |
-
grunt.config('watch', {
|
4 |
-
phplint : {
|
5 |
-
files : '<%= paths.php.files_std %>',
|
6 |
-
tasks : ['phplint'],
|
7 |
-
options : {
|
8 |
-
spawn : false
|
9 |
-
}
|
10 |
-
},
|
11 |
-
sass_core : {
|
12 |
-
files : ['<%= paths.sass.base_src %>/**/*.scss'],
|
13 |
-
tasks : ['sass:core']
|
14 |
-
},
|
15 |
-
sass_themes : {
|
16 |
-
files : ['themes/**/<%= paths.sass.src %>/**/*.scss'],
|
17 |
-
tasks : ['sass:themes']
|
18 |
-
},
|
19 |
-
jshint : {
|
20 |
-
files : '<%= paths.js.files_std %>',
|
21 |
-
tasks : ['jshint:all'],
|
22 |
-
options : {
|
23 |
-
spawn : false
|
24 |
-
}
|
25 |
-
},
|
26 |
-
js : {
|
27 |
-
files : '<%= paths.js.files_std %>',
|
28 |
-
tasks : ['jshint:all', 'uglify:all'],
|
29 |
-
options : {
|
30 |
-
spawn : false
|
31 |
-
}
|
32 |
-
}
|
33 |
-
});
|
34 |
-
|
35 |
-
grunt.event.on('watch', function(action, filepath) {
|
36 |
-
// Determine task based on filepath
|
37 |
-
var get_ext = function(path) {
|
38 |
-
var ret = '';
|
39 |
-
var i = path.lastIndexOf('.');
|
40 |
-
if ( -1 !== i && i <= path.length ) {
|
41 |
-
ret = path.substr(i + 1);
|
42 |
-
}
|
43 |
-
return ret;
|
44 |
-
};
|
45 |
-
switch ( get_ext(filepath) ) {
|
46 |
-
// PHP
|
47 |
-
case 'php' :
|
48 |
-
grunt.config('paths.php.files', [filepath]);
|
49 |
-
break;
|
50 |
-
// JavaScript
|
51 |
-
case 'js' :
|
52 |
-
grunt.config('paths.js.files', [filepath]);
|
53 |
-
break;
|
54 |
-
}
|
55 |
-
});
|
56 |
-
|
57 |
};
|
1 |
+
module.exports = function(grunt) {
|
2 |
+
|
3 |
+
grunt.config('watch', {
|
4 |
+
phplint : {
|
5 |
+
files : '<%= paths.php.files_std %>',
|
6 |
+
tasks : ['phplint'],
|
7 |
+
options : {
|
8 |
+
spawn : false
|
9 |
+
}
|
10 |
+
},
|
11 |
+
sass_core : {
|
12 |
+
files : ['<%= paths.sass.base_src %>/**/*.scss'],
|
13 |
+
tasks : ['sass:core']
|
14 |
+
},
|
15 |
+
sass_themes : {
|
16 |
+
files : ['themes/**/<%= paths.sass.src %>/**/*.scss'],
|
17 |
+
tasks : ['sass:themes']
|
18 |
+
},
|
19 |
+
jshint : {
|
20 |
+
files : '<%= paths.js.files_std %>',
|
21 |
+
tasks : ['jshint:all'],
|
22 |
+
options : {
|
23 |
+
spawn : false
|
24 |
+
}
|
25 |
+
},
|
26 |
+
js : {
|
27 |
+
files : '<%= paths.js.files_std %>',
|
28 |
+
tasks : ['jshint:all', 'uglify:all'],
|
29 |
+
options : {
|
30 |
+
spawn : false
|
31 |
+
}
|
32 |
+
}
|
33 |
+
});
|
34 |
+
|
35 |
+
grunt.event.on('watch', function(action, filepath) {
|
36 |
+
// Determine task based on filepath
|
37 |
+
var get_ext = function(path) {
|
38 |
+
var ret = '';
|
39 |
+
var i = path.lastIndexOf('.');
|
40 |
+
if ( -1 !== i && i <= path.length ) {
|
41 |
+
ret = path.substr(i + 1);
|
42 |
+
}
|
43 |
+
return ret;
|
44 |
+
};
|
45 |
+
switch ( get_ext(filepath) ) {
|
46 |
+
// PHP
|
47 |
+
case 'php' :
|
48 |
+
grunt.config('paths.php.files', [filepath]);
|
49 |
+
break;
|
50 |
+
// JavaScript
|
51 |
+
case 'js' :
|
52 |
+
grunt.config('paths.js.files', [filepath]);
|
53 |
+
break;
|
54 |
+
}
|
55 |
+
});
|
56 |
+
|
57 |
};
|
includes/class-requirements-check.php
CHANGED
@@ -1,168 +1,168 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Requirements Validation
|
4 |
-
*
|
5 |
-
* Used to ensure environment meets plugin requirements.
|
6 |
-
*
|
7 |
-
* @package Simple Lightbox
|
8 |
-
* @since 2.7.0
|
9 |
-
*/
|
10 |
-
|
11 |
-
/**
|
12 |
-
* Plugin Requirements Validation class
|
13 |
-
*
|
14 |
-
* @since 2.7.0
|
15 |
-
*/
|
16 |
-
class SLB_Requirements_Check {
|
17 |
-
/**
|
18 |
-
* Plugin name
|
19 |
-
*
|
20 |
-
* @var string
|
21 |
-
*/
|
22 |
-
private $name = '';
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Plugin file
|
26 |
-
*
|
27 |
-
* @var string
|
28 |
-
*/
|
29 |
-
private $file = '';
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Plugin dependencies
|
33 |
-
*
|
34 |
-
* @var array
|
35 |
-
*/
|
36 |
-
private $deps = array(
|
37 |
-
'php' => '5.6.20',
|
38 |
-
);
|
39 |
-
|
40 |
-
/**
|
41 |
-
* Dependency failures log
|
42 |
-
*
|
43 |
-
* @var array
|
44 |
-
*/
|
45 |
-
private $fail = array();
|
46 |
-
|
47 |
-
/**
|
48 |
-
* URIs for notices, etc.
|
49 |
-
*
|
50 |
-
* @var array
|
51 |
-
*/
|
52 |
-
private $uri = array();
|
53 |
-
|
54 |
-
/**
|
55 |
-
* Constructor
|
56 |
-
*
|
57 |
-
* @param array $args Requirements data.
|
58 |
-
* @return void
|
59 |
-
*/
|
60 |
-
public function __construct( $args ) {
|
61 |
-
$args = (array) $args;
|
62 |
-
// Set properties.
|
63 |
-
foreach ( array_keys( get_class_vars( get_class( $this ) ) ) as $prop ) {
|
64 |
-
if ( ! isset( $args[ $prop ] ) ) {
|
65 |
-
continue;
|
66 |
-
}
|
67 |
-
// Merge array properties.
|
68 |
-
if ( is_array( $this->$prop ) && is_array( $args[ $prop ] ) ) {
|
69 |
-
$this->$prop = array_merge( $this->$prop, $args[ $prop ] );
|
70 |
-
continue;
|
71 |
-
}
|
72 |
-
|
73 |
-
// Set string properties.
|
74 |
-
if ( is_string( $this->$prop ) && is_scalar( $args[ $prop ] ) ) {
|
75 |
-
$this->$prop = (string) $args[ $prop ];
|
76 |
-
continue;
|
77 |
-
}
|
78 |
-
}
|
79 |
-
}
|
80 |
-
|
81 |
-
/**
|
82 |
-
* Check if plugin passes all requirements
|
83 |
-
*
|
84 |
-
* @return bool Requirements check result.
|
85 |
-
*/
|
86 |
-
public function passes() {
|
87 |
-
$result = true;
|
88 |
-
foreach ( $this->deps as $dep => $req ) {
|
89 |
-
$m = $dep . '_passes';
|
90 |
-
if ( ! method_exists( $this, $m ) ) {
|
91 |
-
continue;
|
92 |
-
}
|
93 |
-
$passes = $this->$m();
|
94 |
-
if ( ! $passes ) {
|
95 |
-
// Requirements do not pass.
|
96 |
-
$result = $passes;
|
97 |
-
// Log dependency failures.
|
98 |
-
$this->fail[] = $dep;
|
99 |
-
}
|
100 |
-
}
|
101 |
-
// Handle requirements failure.
|
102 |
-
if ( ! $result ) {
|
103 |
-
add_action( 'load-plugins.php', array( $this, 'handle_failure' ) );
|
104 |
-
}
|
105 |
-
return $result;
|
106 |
-
}
|
107 |
-
|
108 |
-
/**
|
109 |
-
* Handle requirements failure
|
110 |
-
*
|
111 |
-
* @return void
|
112 |
-
*/
|
113 |
-
public function handle_failure() {
|
114 |
-
// Handle each failed dependency.
|
115 |
-
foreach ( $this->fail as $dep ) {
|
116 |
-
$m = $dep . '_handle_failure';
|
117 |
-
if ( method_exists( $this, $m ) ) {
|
118 |
-
$this->$m();
|
119 |
-
}
|
120 |
-
}
|
121 |
-
// Deactivate plugin.
|
122 |
-
deactivate_plugins( plugin_basename( $this->file ) );
|
123 |
-
}
|
124 |
-
|
125 |
-
/**
|
126 |
-
* Validates PHP version.
|
127 |
-
*
|
128 |
-
* @return bool PHP requirement passes.
|
129 |
-
*/
|
130 |
-
private function php_passes() {
|
131 |
-
return version_compare( PHP_VERSION, $this->deps['php'], '>=' );
|
132 |
-
}
|
133 |
-
|
134 |
-
/**
|
135 |
-
* Handle PHP requirement failure
|
136 |
-
*
|
137 |
-
* @return void
|
138 |
-
*/
|
139 |
-
private function php_handle_failure() {
|
140 |
-
// Clear activation query variable from request (stop UI notices).
|
141 |
-
unset( $_GET['activate'] );
|
142 |
-
// Display notice to user.
|
143 |
-
add_action( 'admin_notices', array( $this, 'php_notice' ) );
|
144 |
-
}
|
145 |
-
|
146 |
-
/**
|
147 |
-
* Display requirements failure notice and deactivate plugin.
|
148 |
-
*
|
149 |
-
* @return void
|
150 |
-
*/
|
151 |
-
public function php_notice() {
|
152 |
-
global $slb_requirements;
|
153 |
-
// Display message to user.
|
154 |
-
$link = (object) array(
|
155 |
-
/* translators: 1: Plugin name */
|
156 |
-
'title' => sprintf( __( 'Learn more about %1$s\'s requirements', 'simple-lightbox' ), $this->name ),
|
157 |
-
/* translators: Plugin requirements link text. */
|
158 |
-
'text' => __( 'Learn More', 'simple-lightbox' ),
|
159 |
-
);
|
160 |
-
// Full link.
|
161 |
-
$link = sprintf( '<a target="_blank" href="%1$s" title="%2$s">%3$s</a>', $this->uri['reference'], esc_attr( $link->title ), esc_html( $link->text ) );
|
162 |
-
/* translators: 1: Plugin name. 2: PHP version requirement. 3: Plugin requirements link. */
|
163 |
-
$err_msg = sprintf( __( '%1$s requires PHP %2$s or higher. Please have your hosting provider update PHP to enable Simple Lightbox. (%3$s)', 'simple-lightbox' ), $this->name, $this->deps['php'], $link );
|
164 |
-
?>
|
165 |
-
<div class="error"><p><?php echo $err_msg; ?></p></div>
|
166 |
-
<?php
|
167 |
-
}
|
168 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Requirements Validation
|
4 |
+
*
|
5 |
+
* Used to ensure environment meets plugin requirements.
|
6 |
+
*
|
7 |
+
* @package Simple Lightbox
|
8 |
+
* @since 2.7.0
|
9 |
+
*/
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Plugin Requirements Validation class
|
13 |
+
*
|
14 |
+
* @since 2.7.0
|
15 |
+
*/
|
16 |
+
class SLB_Requirements_Check {
|
17 |
+
/**
|
18 |
+
* Plugin name
|
19 |
+
*
|
20 |
+
* @var string
|
21 |
+
*/
|
22 |
+
private $name = '';
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Plugin file
|
26 |
+
*
|
27 |
+
* @var string
|
28 |
+
*/
|
29 |
+
private $file = '';
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Plugin dependencies
|
33 |
+
*
|
34 |
+
* @var array
|
35 |
+
*/
|
36 |
+
private $deps = array(
|
37 |
+
'php' => '5.6.20',
|
38 |
+
);
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Dependency failures log
|
42 |
+
*
|
43 |
+
* @var array
|
44 |
+
*/
|
45 |
+
private $fail = array();
|
46 |
+
|
47 |
+
/**
|
48 |
+
* URIs for notices, etc.
|
49 |
+
*
|
50 |
+
* @var array
|
51 |
+
*/
|
52 |
+
private $uri = array();
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Constructor
|
56 |
+
*
|
57 |
+
* @param array $args Requirements data.
|
58 |
+
* @return void
|
59 |
+
*/
|
60 |
+
public function __construct( $args ) {
|
61 |
+
$args = (array) $args;
|
62 |
+
// Set properties.
|
63 |
+
foreach ( array_keys( get_class_vars( get_class( $this ) ) ) as $prop ) {
|
64 |
+
if ( ! isset( $args[ $prop ] ) ) {
|
65 |
+
continue;
|
66 |
+
}
|
67 |
+
// Merge array properties.
|
68 |
+
if ( is_array( $this->$prop ) && is_array( $args[ $prop ] ) ) {
|
69 |
+
$this->$prop = array_merge( $this->$prop, $args[ $prop ] );
|
70 |
+
continue;
|
71 |
+
}
|
72 |
+
|
73 |
+
// Set string properties.
|
74 |
+
if ( is_string( $this->$prop ) && is_scalar( $args[ $prop ] ) ) {
|
75 |
+
$this->$prop = (string) $args[ $prop ];
|
76 |
+
continue;
|
77 |
+
}
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Check if plugin passes all requirements
|
83 |
+
*
|
84 |
+
* @return bool Requirements check result.
|
85 |
+
*/
|
86 |
+
public function passes() {
|
87 |
+
$result = true;
|
88 |
+
foreach ( $this->deps as $dep => $req ) {
|
89 |
+
$m = $dep . '_passes';
|
90 |
+
if ( ! method_exists( $this, $m ) ) {
|
91 |
+
continue;
|
92 |
+
}
|
93 |
+
$passes = $this->$m();
|
94 |
+
if ( ! $passes ) {
|
95 |
+
// Requirements do not pass.
|
96 |
+
$result = $passes;
|
97 |
+
// Log dependency failures.
|
98 |
+
$this->fail[] = $dep;
|
99 |
+
}
|
100 |
+
}
|
101 |
+
// Handle requirements failure.
|
102 |
+
if ( ! $result ) {
|
103 |
+
add_action( 'load-plugins.php', array( $this, 'handle_failure' ) );
|
104 |
+
}
|
105 |
+
return $result;
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Handle requirements failure
|
110 |
+
*
|
111 |
+
* @return void
|
112 |
+
*/
|
113 |
+
public function handle_failure() {
|
114 |
+
// Handle each failed dependency.
|
115 |
+
foreach ( $this->fail as $dep ) {
|
116 |
+
$m = $dep . '_handle_failure';
|
117 |
+
if ( method_exists( $this, $m ) ) {
|
118 |
+
$this->$m();
|
119 |
+
}
|
120 |
+
}
|
121 |
+
// Deactivate plugin.
|
122 |
+
deactivate_plugins( plugin_basename( $this->file ) );
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Validates PHP version.
|
127 |
+
*
|
128 |
+
* @return bool PHP requirement passes.
|
129 |
+
*/
|
130 |
+
private function php_passes() {
|
131 |
+
return version_compare( PHP_VERSION, $this->deps['php'], '>=' );
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Handle PHP requirement failure
|
136 |
+
*
|
137 |
+
* @return void
|
138 |
+
*/
|
139 |
+
private function php_handle_failure() {
|
140 |
+
// Clear activation query variable from request (stop UI notices).
|
141 |
+
unset( $_GET['activate'] );
|
142 |
+
// Display notice to user.
|
143 |
+
add_action( 'admin_notices', array( $this, 'php_notice' ) );
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Display requirements failure notice and deactivate plugin.
|
148 |
+
*
|
149 |
+
* @return void
|
150 |
+
*/
|
151 |
+
public function php_notice() {
|
152 |
+
global $slb_requirements;
|
153 |
+
// Display message to user.
|
154 |
+
$link = (object) array(
|
155 |
+
/* translators: 1: Plugin name */
|
156 |
+
'title' => sprintf( __( 'Learn more about %1$s\'s requirements', 'simple-lightbox' ), $this->name ),
|
157 |
+
/* translators: Plugin requirements link text. */
|
158 |
+
'text' => __( 'Learn More', 'simple-lightbox' ),
|
159 |
+
);
|
160 |
+
// Full link.
|
161 |
+
$link = sprintf( '<a target="_blank" href="%1$s" title="%2$s">%3$s</a>', $this->uri['reference'], esc_attr( $link->title ), esc_html( $link->text ) );
|
162 |
+
/* translators: 1: Plugin name. 2: PHP version requirement. 3: Plugin requirements link. */
|
163 |
+
$err_msg = sprintf( __( '%1$s requires PHP %2$s or higher. Please have your hosting provider update PHP to enable Simple Lightbox. (%3$s)', 'simple-lightbox' ), $this->name, $this->deps['php'], $link );
|
164 |
+
?>
|
165 |
+
<div class="error"><p><?php echo $err_msg; ?></p></div>
|
166 |
+
<?php
|
167 |
+
}
|
168 |
+
}
|
includes/class.admin.php
CHANGED
@@ -1,661 +1,686 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Admin functionality
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Admin
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Admin extends SLB_Base {
|
10 |
-
/* Configuration */
|
11 |
-
|
12 |
-
protected $mode = 'sub';
|
13 |
-
|
14 |
-
/* Properties */
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Parent object
|
18 |
-
* Set on initialization
|
19 |
-
* @var obj
|
20 |
-
*/
|
21 |
-
protected $parent = null;
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Messages
|
25 |
-
* @var array
|
26 |
-
*/
|
27 |
-
protected $messages = array(
|
28 |
-
'reset'
|
29 |
-
'beta'
|
30 |
-
'access_denied'
|
31 |
-
);
|
32 |
-
|
33 |
-
/* Views */
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Custom admin top-level menus
|
37 |
-
* Associative Array
|
38 |
-
* > Key: Menu ID
|
39 |
-
* > Val: Menu properties
|
40 |
-
* @var array
|
41 |
-
*/
|
42 |
-
protected $menus = array();
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Custom admin pages
|
46 |
-
* Associative Array
|
47 |
-
* > Key: Page ID
|
48 |
-
* > Val: Page properties
|
49 |
-
* @var array
|
50 |
-
*/
|
51 |
-
protected $pages = array();
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Custom admin sections
|
55 |
-
* Associative Array
|
56 |
-
* > Key: Section ID
|
57 |
-
* > Val: Section properties
|
58 |
-
* @var array
|
59 |
-
*/
|
60 |
-
protected $sections = array();
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Actions
|
64 |
-
* Index Array
|
65 |
-
* @var array
|
66 |
-
*/
|
67 |
-
protected $actions = array();
|
68 |
-
|
69 |
-
/* Constructor */
|
70 |
-
|
71 |
-
public function __construct(&$parent) {
|
72 |
-
parent::__construct();
|
73 |
-
// Set parent
|
74 |
-
if ( is_object($parent) )
|
75 |
-
$this->parent = $parent;
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
add_filter('
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
*
|
101 |
-
* @
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
$js_path
|
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 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
//
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
//
|
235 |
-
$
|
236 |
-
$
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
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 |
-
* @param string
|
273 |
-
* @param
|
274 |
-
*
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
*
|
290 |
-
*
|
291 |
-
* @param string $
|
292 |
-
* @
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
*
|
304 |
-
* @
|
305 |
-
* @param string $
|
306 |
-
* @param string
|
307 |
-
*
|
308 |
-
*
|
309 |
-
*
|
310 |
-
* @
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
$
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
*
|
324 |
-
* @
|
325 |
-
* @
|
326 |
-
*
|
327 |
-
*
|
328 |
-
* @param string $capability (optional) Custom capability for accessing page
|
329 |
-
* @return Admin_Page Page instance
|
330 |
-
*/
|
331 |
-
public function
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
*
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
*
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
*
|
369 |
-
* @
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
*
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
*
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
*
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
*
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
*
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
*
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
*
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
// Add
|
499 |
-
if (
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
}
|
539 |
-
|
540 |
-
|
541 |
-
$
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
public function
|
577 |
-
|
578 |
-
|
579 |
-
if (
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Admin functionality
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @subpackage Admin
|
7 |
+
* @author Archetyped
|
8 |
+
*/
|
9 |
+
class SLB_Admin extends SLB_Base {
|
10 |
+
/* Configuration */
|
11 |
+
|
12 |
+
protected $mode = 'sub';
|
13 |
+
|
14 |
+
/* Properties */
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Parent object
|
18 |
+
* Set on initialization
|
19 |
+
* @var obj
|
20 |
+
*/
|
21 |
+
protected $parent = null;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Messages
|
25 |
+
* @var array
|
26 |
+
*/
|
27 |
+
protected $messages = array(
|
28 |
+
'reset' => 'The settings have been reset',
|
29 |
+
'beta' => '<strong class="%1$s">Notice:</strong> This update is a <strong class="%1$s">Beta version</strong>. It is highly recommended that you test the update on a test server before updating the plugin on a production server.',
|
30 |
+
'access_denied' => 'You do not have sufficient permissions',
|
31 |
+
);
|
32 |
+
|
33 |
+
/* Views */
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Custom admin top-level menus
|
37 |
+
* Associative Array
|
38 |
+
* > Key: Menu ID
|
39 |
+
* > Val: Menu properties
|
40 |
+
* @var array
|
41 |
+
*/
|
42 |
+
protected $menus = array();
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Custom admin pages
|
46 |
+
* Associative Array
|
47 |
+
* > Key: Page ID
|
48 |
+
* > Val: Page properties
|
49 |
+
* @var array
|
50 |
+
*/
|
51 |
+
protected $pages = array();
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Custom admin sections
|
55 |
+
* Associative Array
|
56 |
+
* > Key: Section ID
|
57 |
+
* > Val: Section properties
|
58 |
+
* @var array
|
59 |
+
*/
|
60 |
+
protected $sections = array();
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Actions
|
64 |
+
* Index Array
|
65 |
+
* @var array
|
66 |
+
*/
|
67 |
+
protected $actions = array();
|
68 |
+
|
69 |
+
/* Constructor */
|
70 |
+
|
71 |
+
public function __construct( &$parent ) {
|
72 |
+
parent::__construct();
|
73 |
+
// Set parent
|
74 |
+
if ( is_object( $parent ) ) {
|
75 |
+
$this->parent = $parent;
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
/* Init */
|
80 |
+
|
81 |
+
protected function _hooks() {
|
82 |
+
parent::_hooks();
|
83 |
+
// Init
|
84 |
+
add_action( 'admin_menu', $this->m( 'init_menus' ), 11 );
|
85 |
+
|
86 |
+
// Plugin actions
|
87 |
+
add_action( 'admin_action_' . $this->add_prefix( 'admin' ), $this->m( 'handle_action' ) );
|
88 |
+
|
89 |
+
// Notices
|
90 |
+
add_action( 'admin_notices', $this->m( 'handle_notices' ) );
|
91 |
+
|
92 |
+
// Plugin listing
|
93 |
+
add_filter( 'plugin_action_links_' . $this->util->get_plugin_base_name(), $this->m( 'plugin_action_links' ), 10, 4 );
|
94 |
+
add_filter( 'plugin_row_meta', $this->m( 'plugin_row_meta' ), 10, 4 );
|
95 |
+
add_action( 'in_plugin_update_message-' . $this->util->get_plugin_base_name(), $this->m( 'plugin_update_message' ), 10, 2 );
|
96 |
+
add_filter( 'site_transient_update_plugins', $this->m( 'plugin_update_transient' ) );
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Declare client files (scripts, styles)
|
101 |
+
* @uses parent::_client_files()
|
102 |
+
* @return void
|
103 |
+
*/
|
104 |
+
protected function _client_files( $files = null ) {
|
105 |
+
$js_path = 'client/js/';
|
106 |
+
$js_path .= ( SLB_DEV ) ? 'dev' : 'prod';
|
107 |
+
$pfx = $this->get_prefix();
|
108 |
+
$files = array(
|
109 |
+
'scripts' => array(
|
110 |
+
'admin' => array(
|
111 |
+
'file' => "$js_path/lib.admin.js",
|
112 |
+
'deps' => array( '[core]' ),
|
113 |
+
'context' => array( "admin_page_$pfx" ),
|
114 |
+
'in_footer' => true,
|
115 |
+
),
|
116 |
+
),
|
117 |
+
'styles' => array(
|
118 |
+
'admin' => array(
|
119 |
+
'file' => 'client/css/admin.css',
|
120 |
+
'context' => array( "admin_page_$pfx", 'admin_page_plugins' ),
|
121 |
+
),
|
122 |
+
),
|
123 |
+
);
|
124 |
+
parent::_client_files( $files );
|
125 |
+
}
|
126 |
+
|
127 |
+
/* Handlers */
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Handles routing of internal action to appropriate handler.
|
131 |
+
*
|
132 |
+
* @return void
|
133 |
+
*/
|
134 |
+
public function handle_action() {
|
135 |
+
// Parse action
|
136 |
+
$t = 'type';
|
137 |
+
$g = 'group';
|
138 |
+
$o = 'obj';
|
139 |
+
$this->add_prefix_ref( $t );
|
140 |
+
$this->add_prefix_ref( $g );
|
141 |
+
$this->add_prefix_ref( $o );
|
142 |
+
$r =& $_REQUEST;
|
143 |
+
|
144 |
+
// Confirm request contains necessary parameters.
|
145 |
+
if (
|
146 |
+
! isset( $r[ $t ], $r[ $g ], $r[ $o ] )
|
147 |
+
|| 'view' !== $r[ $t ]
|
148 |
+
) {
|
149 |
+
return;
|
150 |
+
}
|
151 |
+
// Confirm specified view instance exists.
|
152 |
+
$prop = $r[ $g ] . 's';
|
153 |
+
if (
|
154 |
+
! property_exists( $this, $prop )
|
155 |
+
|| ! is_array( $this->{$prop} )
|
156 |
+
|| ! isset( $this->{$prop}[ $r[ $o ] ] )
|
157 |
+
) {
|
158 |
+
return;
|
159 |
+
}
|
160 |
+
// Get view instance.
|
161 |
+
$view =& $this->{$prop}[ $r[ $o ] ];
|
162 |
+
// Pass request to view instance.
|
163 |
+
if ( $view instanceof SLB_Admin_View ) {
|
164 |
+
$view->do_callback();
|
165 |
+
}
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Display notices
|
170 |
+
* Messages are localized upon display
|
171 |
+
* @uses `admin_notices` action hook to display messages
|
172 |
+
*/
|
173 |
+
public function handle_notices() {
|
174 |
+
$msgs = $this->util->apply_filters( 'admin_messages', array() );
|
175 |
+
foreach ( $msgs as $mid => $msg ) {
|
176 |
+
// Filter out empty messages
|
177 |
+
if ( empty( $msg ) ) {
|
178 |
+
continue;
|
179 |
+
}
|
180 |
+
// Build and display message
|
181 |
+
$mid = $this->add_prefix( 'msg_' . $mid );
|
182 |
+
?>
|
183 |
+
<div id="<?php echo esc_attr( $mid ); ?>" class="updated fade">
|
184 |
+
<p>
|
185 |
+
<?php echo esc_html( $msg ); ?>
|
186 |
+
</p>
|
187 |
+
</div>
|
188 |
+
<?php
|
189 |
+
}
|
190 |
+
}
|
191 |
+
|
192 |
+
/* Views */
|
193 |
+
|
194 |
+
/**
|
195 |
+
* Adds settings section for plugin functionality
|
196 |
+
* Section is added to specified admin section/menu
|
197 |
+
* @uses `admin_init` hook
|
198 |
+
*/
|
199 |
+
public function init_menus() {
|
200 |
+
// Add top level menus (when necessary)
|
201 |
+
$menu;
|
202 |
+
foreach ( $this->menus as $menu ) {
|
203 |
+
// Register menu
|
204 |
+
$hook = add_menu_page( $menu->get_label( 'title' ), $menu->get_label( 'menu' ), $menu->get_capability(), $menu->get_id(), $menu->get_callback() );
|
205 |
+
// Add hook to menu object
|
206 |
+
$menu->set_hookname( $hook );
|
207 |
+
$this->menus[ $menu->get_id_raw() ] =& $menu;
|
208 |
+
}
|
209 |
+
|
210 |
+
$page;
|
211 |
+
// Add subpages
|
212 |
+
foreach ( $this->pages as $page ) {
|
213 |
+
// Build Arguments
|
214 |
+
$args = array( $page->get_label( 'header' ), $page->get_label( 'menu' ), $page->get_capability(), $page->get_id(), $page->get_callback() );
|
215 |
+
$f = null;
|
216 |
+
// Handle pages for default WP menus
|
217 |
+
if ( $page->is_parent_wp() ) {
|
218 |
+
$f = 'add_' . $page->get_parent() . '_page';
|
219 |
+
}
|
220 |
+
|
221 |
+
// Handle pages for custom menus
|
222 |
+
if ( ! function_exists( $f ) ) {
|
223 |
+
array_unshift( $args, $page->get_parent() );
|
224 |
+
$f = 'add_submenu_page';
|
225 |
+
}
|
226 |
+
|
227 |
+
// Add admin page
|
228 |
+
$hook = call_user_func_array( $f, $args );
|
229 |
+
// Save hook to page properties
|
230 |
+
$page->set_hookname( $hook );
|
231 |
+
$this->pages[ $page->get_id_raw() ] =& $page;
|
232 |
+
}
|
233 |
+
|
234 |
+
// Add sections
|
235 |
+
$section;
|
236 |
+
foreach ( $this->sections as $section ) {
|
237 |
+
add_settings_section( $section->get_id(), $section->get_title(), $section->get_callback(), $section->get_parent() );
|
238 |
+
}
|
239 |
+
}
|
240 |
+
|
241 |
+
|
242 |
+
/* Methods */
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Add a new view
|
246 |
+
* @param string $type View type
|
247 |
+
* @param string $id Unique view ID
|
248 |
+
* @param array $args Arguments to pass to view constructor
|
249 |
+
* @return Admin_View|bool View instance (FALSE if view was not properly initialized)
|
250 |
+
*/
|
251 |
+
protected function add_view( $type, $id, $args ) {
|
252 |
+
// Validate request
|
253 |
+
$class = $this->add_prefix( 'admin_' . $type );
|
254 |
+
$collection = $type . 's';
|
255 |
+
if ( ! class_exists( $class ) ) {
|
256 |
+
$class = $this->add_prefix( 'admin_view' );
|
257 |
+
$collection = null;
|
258 |
+
}
|
259 |
+
// Create new instance
|
260 |
+
$r = new ReflectionClass( $class );
|
261 |
+
$view = $r->newInstanceArgs( $args );
|
262 |
+
if ( $view->is_valid() && ! empty( $collection ) && property_exists( $this, $collection ) && is_array( $this->{$collection} ) ) {
|
263 |
+
$this->{$collection}[ $id ] =& $view;
|
264 |
+
}
|
265 |
+
unset( $r );
|
266 |
+
return $view;
|
267 |
+
}
|
268 |
+
|
269 |
+
/**
|
270 |
+
* Add plugin action link
|
271 |
+
* @uses `add_view()` to init/attach action instance
|
272 |
+
* @param string $id Action ID
|
273 |
+
* @param array $labels Text for action
|
274 |
+
* > title - Link text (also title attribute value)
|
275 |
+
* > confirm - Confirmation message
|
276 |
+
* > success - Success message
|
277 |
+
* > failure - Failure message
|
278 |
+
* @param array $data Additional data for action
|
279 |
+
* @return obj Action instance
|
280 |
+
*/
|
281 |
+
public function add_action( $id, $labels, $data = null ) {
|
282 |
+
$args = func_get_args();
|
283 |
+
return $this->add_view( 'action', $id, $args );
|
284 |
+
}
|
285 |
+
|
286 |
+
/*-** Menus **-*/
|
287 |
+
|
288 |
+
/**
|
289 |
+
* Adds custom admin panel
|
290 |
+
* @param string $id Menu ID
|
291 |
+
* @param string|array $labels Text labels
|
292 |
+
* @param int $pos (optional) Menu position in navigation (index order)
|
293 |
+
* @return Admin_Menu Menu instance
|
294 |
+
*/
|
295 |
+
public function add_menu( $id, $labels, $position = null ) {
|
296 |
+
$args = array( $id, $labels, null, null, null, $position );
|
297 |
+
return $this->add_view( 'menu', $id, $args );
|
298 |
+
}
|
299 |
+
|
300 |
+
/* Page */
|
301 |
+
|
302 |
+
/**
|
303 |
+
* Add admin page
|
304 |
+
* @uses this->pages
|
305 |
+
* @param string $id Page ID (unique)
|
306 |
+
* @param string $parent Menu ID to add page to
|
307 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
308 |
+
* > menu: Menu title
|
309 |
+
* > header: Page header
|
310 |
+
* @param string $capability (optional) Custom capability for accessing page
|
311 |
+
* @return Admin_Page Page instance
|
312 |
+
*/
|
313 |
+
public function add_page( $id, $parent, $labels, $callback = null, $capability = null ) {
|
314 |
+
$args = func_get_args();
|
315 |
+
return $this->add_view( 'page', $id, $args );
|
316 |
+
}
|
317 |
+
|
318 |
+
/* WP Pages */
|
319 |
+
|
320 |
+
/**
|
321 |
+
* Add admin page to a standard WP menu
|
322 |
+
* @uses this->add_page()
|
323 |
+
* @param string $id Page ID (unique)
|
324 |
+
* @param string $parent Name of WP menu to add page to
|
325 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
326 |
+
* > menu: Menu title
|
327 |
+
* > header: Page header
|
328 |
+
* @param string $capability (optional) Custom capability for accessing page
|
329 |
+
* @return Admin_Page Page instance
|
330 |
+
*/
|
331 |
+
public function add_wp_page( $id, $parent, $labels, $callback = null, $capability = null ) {
|
332 |
+
// Add page
|
333 |
+
$pg = $this->add_page( $id, $parent, $labels, $capability );
|
334 |
+
// Set parent as WP
|
335 |
+
if ( $pg ) {
|
336 |
+
$pg->set_parent_wp();
|
337 |
+
}
|
338 |
+
return $pg;
|
339 |
+
}
|
340 |
+
|
341 |
+
/**
|
342 |
+
* Add admin page to Dashboard menu
|
343 |
+
* @see add_dashboard_page()
|
344 |
+
* @uses this->add_wp_page()
|
345 |
+
* @param string $id Page ID (unique)
|
346 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
347 |
+
* @param string $capability (optional) Custom capability for accessing page
|
348 |
+
* @return Admin_Page Page instance
|
349 |
+
*/
|
350 |
+
public function add_dashboard_page( $id, $labels, $callback = null, $capability = null ) {
|
351 |
+
return $this->add_wp_page( $id, 'dashboard', $labels, $capability );
|
352 |
+
}
|
353 |
+
|
354 |
+
/**
|
355 |
+
* Add admin page to Comments menu
|
356 |
+
* @see add_comments_page()
|
357 |
+
* @uses this->add_wp_page()
|
358 |
+
* @param string $id Page ID (unique)
|
359 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
360 |
+
* @param string $capability (optional) Custom capability for accessing page
|
361 |
+
* @return string Page ID
|
362 |
+
*/
|
363 |
+
public function add_comments_page( $id, $labels, $callback = null, $capability = null ) {
|
364 |
+
return $this->add_wp_page( $id, 'comments', $labels, $capability );
|
365 |
+
}
|
366 |
+
|
367 |
+
/**
|
368 |
+
* Add admin page to Links menu
|
369 |
+
* @see add_links_page()
|
370 |
+
* @uses this->add_wp_page()
|
371 |
+
* @param string $id Page ID (unique)
|
372 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
373 |
+
* @param string $capability (optional) Custom capability for accessing page
|
374 |
+
* @return string Page ID
|
375 |
+
*/
|
376 |
+
public function add_links_page( $id, $labels, $callback = null, $capability = null ) {
|
377 |
+
return $this->add_wp_page( $id, 'links', $labels, $capability );
|
378 |
+
}
|
379 |
+
|
380 |
+
|
381 |
+
/**
|
382 |
+
* Add admin page to Posts menu
|
383 |
+
* @see add_posts_page()
|
384 |
+
* @uses this->add_wp_page()
|
385 |
+
* @param string $id Page ID (unique)
|
386 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
387 |
+
* @param string $capability (optional) Custom capability for accessing page
|
388 |
+
* @return string Page ID
|
389 |
+
*/
|
390 |
+
public function add_posts_page( $id, $labels, $callback = null, $capability = null ) {
|
391 |
+
return $this->add_wp_page( $id, 'posts', $labels, $capability );
|
392 |
+
}
|
393 |
+
|
394 |
+
/**
|
395 |
+
* Add admin page to Pages menu
|
396 |
+
* @see add_pages_page()
|
397 |
+
* @uses this->add_wp_page()
|
398 |
+
* @param string $id Page ID (unique)
|
399 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
400 |
+
* @param string $capability (optional) Custom capability for accessing page
|
401 |
+
* @return string Page ID
|
402 |
+
*/
|
403 |
+
public function add_pages_page( $id, $labels, $callback = null, $capability = null ) {
|
404 |
+
return $this->add_wp_page( $id, 'pages', $labels, $capability );
|
405 |
+
}
|
406 |
+
|
407 |
+
/**
|
408 |
+
* Add admin page to Media menu
|
409 |
+
* @see add_media_page()
|
410 |
+
* @uses this->add_wp_page()
|
411 |
+
* @param string $id Page ID (unique)
|
412 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
413 |
+
* @param string $capability (optional) Custom capability for accessing page
|
414 |
+
* @return string Page ID
|
415 |
+
*/
|
416 |
+
public function add_media_page( $id, $labels, $callback = null, $capability = null ) {
|
417 |
+
return $this->add_wp_page( $id, 'media', $labels, $capability );
|
418 |
+
}
|
419 |
+
|
420 |
+
/**
|
421 |
+
* Add admin page to Themes menu
|
422 |
+
* @see add_theme_page()
|
423 |
+
* @uses this->add_wp_page()
|
424 |
+
* @param string $id Page ID (unique)
|
425 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
426 |
+
* @param string $capability (optional) Custom capability for accessing page
|
427 |
+
* @return string Page ID
|
428 |
+
*/
|
429 |
+
public function add_theme_page( $id, $labels, $callback = null, $capability = null ) {
|
430 |
+
return $this->add_wp_page( $id, 'theme', $labels, $capability );
|
431 |
+
}
|
432 |
+
|
433 |
+
/**
|
434 |
+
* Add admin page to Plugins menu
|
435 |
+
* @see add_plugins_page()
|
436 |
+
* @uses this->add_wp_page()
|
437 |
+
* @param string $id Page ID (unique)
|
438 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
439 |
+
* @param string $capability (optional) Custom capability for accessing page
|
440 |
+
* @return string Page ID
|
441 |
+
*/
|
442 |
+
public function add_plugins_page( $id, $labels, $callback = null, $capability = null ) {
|
443 |
+
return $this->add_wp_page( $id, 'plugins', $labels, $capability );
|
444 |
+
}
|
445 |
+
|
446 |
+
/**
|
447 |
+
* Add admin page to Options menu
|
448 |
+
* @see add_options_page()
|
449 |
+
* @uses this->add_wp_page()
|
450 |
+
* @param string $id Page ID (unique)
|
451 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
452 |
+
* @param string $capability (optional) Custom capability for accessing page
|
453 |
+
* @return string Page ID
|
454 |
+
*/
|
455 |
+
public function add_options_page( $id, $labels, $callback = null, $capability = null ) {
|
456 |
+
return $this->add_wp_page( $id, 'options', $labels, $capability );
|
457 |
+
}
|
458 |
+
|
459 |
+
/**
|
460 |
+
* Add admin page to Tools menu
|
461 |
+
* @see add_management_page()
|
462 |
+
* @uses this->add_wp_page()
|
463 |
+
* @param string $id Page ID (unique)
|
464 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
465 |
+
* @param string $capability (optional) Custom capability for accessing page
|
466 |
+
* @return string Page ID
|
467 |
+
*/
|
468 |
+
public function add_management_page( $id, $labels, $callback = null, $capability = null ) {
|
469 |
+
return $this->add_wp_page( $id, 'management', $labels, $capability );
|
470 |
+
}
|
471 |
+
|
472 |
+
/**
|
473 |
+
* Add admin page to Users menu
|
474 |
+
* @uses this->add_wp_page()
|
475 |
+
* @param string $id Page ID (unique)
|
476 |
+
* @param string|array $labels Text labels (Associative array for multiple labels)
|
477 |
+
* @param string $capability (optional) Custom capability for accessing page
|
478 |
+
* @return string Page ID
|
479 |
+
*/
|
480 |
+
public function add_users_page( $id, $labels, $callback = null, $capability = null ) {
|
481 |
+
return $this->add_wp_page( $id, 'users', $labels, $capability );
|
482 |
+
}
|
483 |
+
|
484 |
+
/* Section */
|
485 |
+
|
486 |
+
/**
|
487 |
+
* Add section
|
488 |
+
* @uses this->sections
|
489 |
+
* @param string $id Unique section ID
|
490 |
+
* @param string $page Page ID
|
491 |
+
* @param string $labels Label text
|
492 |
+
* @return obj Section instance
|
493 |
+
*/
|
494 |
+
public function add_section( $id, $parent, $labels ) {
|
495 |
+
$args = func_get_args();
|
496 |
+
$section = $this->add_view( 'section', $id, $args );
|
497 |
+
|
498 |
+
// Add Section
|
499 |
+
if ( $section->is_valid() ) {
|
500 |
+
$this->sections[ $id ] = $section;
|
501 |
+
}
|
502 |
+
|
503 |
+
return $section;
|
504 |
+
}
|
505 |
+
|
506 |
+
/* Operations */
|
507 |
+
|
508 |
+
/**
|
509 |
+
* Adds custom links below plugin on plugin listing page
|
510 |
+
* @uses `plugin_action_links_$plugin-name` Filter hook
|
511 |
+
* @param $actions
|
512 |
+
* @param $plugin_file
|
513 |
+
* @param $plugin_data
|
514 |
+
* @param $context
|
515 |
+
*/
|
516 |
+
public function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
|
517 |
+
global $admin_page_hooks;
|
518 |
+
// Add link to settings (only if active)
|
519 |
+
if ( is_plugin_active( $this->util->get_plugin_base_name() ) ) {
|
520 |
+
/* Get Actions */
|
521 |
+
|
522 |
+
$acts = array();
|
523 |
+
$type = 'plugin_action';
|
524 |
+
|
525 |
+
/* Get view links */
|
526 |
+
foreach ( array( 'menus', 'pages', 'sections' ) as $views ) {
|
527 |
+
foreach ( $this->{$views} as $view ) {
|
528 |
+
if ( ! $view->has_label( $type ) ) {
|
529 |
+
continue;
|
530 |
+
}
|
531 |
+
$acts[] = (object) array(
|
532 |
+
'id' => $views . '_' . $view->get_id(),
|
533 |
+
'label' => $view->get_label( $type ),
|
534 |
+
'uri' => $view->get_uri(),
|
535 |
+
'attributes' => array(),
|
536 |
+
);
|
537 |
+
}
|
538 |
+
}
|
539 |
+
|
540 |
+
/* Get action links */
|
541 |
+
$type = 'title';
|
542 |
+
foreach ( $this->actions as $a ) {
|
543 |
+
if ( ! $a->has_label( $type ) ) {
|
544 |
+
continue;
|
545 |
+
}
|
546 |
+
$id = 'action_' . $a->get_id();
|
547 |
+
$acts[] = (object) array(
|
548 |
+
'id' => $id,
|
549 |
+
'label' => $a->get_label( $type ),
|
550 |
+
'uri' => $a->get_uri(),
|
551 |
+
'attributes' => $a->get_link_attr(),
|
552 |
+
);
|
553 |
+
}
|
554 |
+
unset( $a );
|
555 |
+
|
556 |
+
// Add links
|
557 |
+
$links = array();
|
558 |
+
foreach ( $acts as $act ) {
|
559 |
+
$links[ $act->id ] = $this->util->build_html_link( $act->uri, $act->label, $act->attributes );
|
560 |
+
}
|
561 |
+
|
562 |
+
// Add links
|
563 |
+
$actions = array_merge( $links, $actions );
|
564 |
+
}
|
565 |
+
return $actions;
|
566 |
+
}
|
567 |
+
|
568 |
+
/**
|
569 |
+
* Update plugin listings metadata
|
570 |
+
* @param array $plugin_meta Plugin metadata
|
571 |
+
* @param string $plugin_file Plugin file
|
572 |
+
* @param array $plugin_data Plugin Data
|
573 |
+
* @param string $status Plugin status
|
574 |
+
* @return array Updated plugin metadata
|
575 |
+
*/
|
576 |
+
public function plugin_row_meta( $plugin_meta, $plugin_file, $plugin_data, $status ) {
|
577 |
+
$u = ( is_object( $this->parent ) && isset( $this->parent->util ) ) ? $this->parent->util : $this->util;
|
578 |
+
$hook_base = 'admin_plugin_row_meta_';
|
579 |
+
if ( $plugin_file === $u->get_plugin_base_name() ) {
|
580 |
+
// Add metadata
|
581 |
+
// Support
|
582 |
+
$l = $u->get_plugin_info( 'SupportURI' );
|
583 |
+
if ( ! empty( $l ) ) {
|
584 |
+
$t = __( 'Feedback & Support', 'simple-lightbox' );
|
585 |
+
$plugin_meta[] = $u->build_html_link( $l, $t );
|
586 |
+
}
|
587 |
+
}
|
588 |
+
return $plugin_meta;
|
589 |
+
}
|
590 |
+
|
591 |
+
/**
|
592 |
+
* Adds additional message for plugin updates
|
593 |
+
* @uses `in_plugin_update_message-$plugin-name` Action hook
|
594 |
+
* @uses this->plugin_update_get_message()
|
595 |
+
* @var array $plugin_data Current plugin data
|
596 |
+
* @var object $r Update response data
|
597 |
+
*/
|
598 |
+
public function plugin_update_message( $plugin_data, $r ) {
|
599 |
+
if ( ! isset( $r->new_version ) ) {
|
600 |
+
return false;
|
601 |
+
}
|
602 |
+
if ( stripos( $r->new_version, 'beta' ) !== false ) {
|
603 |
+
$cls_notice = $this->add_prefix( 'notice' );
|
604 |
+
echo '<br />' . $this->plugin_update_get_message( $r );
|
605 |
+
}
|
606 |
+
}
|
607 |
+
|
608 |
+
/**
|
609 |
+
* Modify update plugins response data if necessary
|
610 |
+
* @uses `site_transient_update_plugins` Filter hook
|
611 |
+
* @uses this->plugin_update_get_message()
|
612 |
+
* @param obj $transient Transient data
|
613 |
+
* @return obj Modified transient data
|
614 |
+
*/
|
615 |
+
public function plugin_update_transient( $transient ) {
|
616 |
+
$n = $this->util->get_plugin_base_name();
|
617 |
+
if ( isset( $transient->response ) && isset( $transient->response[ $n ] ) && is_object( $transient->response[ $n ] ) && ! isset( $transient->response[ $n ]->upgrade_notice ) ) {
|
618 |
+
$r =& $transient->response[ $n ];
|
619 |
+
$r->upgrade_notice = $this->plugin_update_get_message( $r );
|
620 |
+
}
|
621 |
+
return $transient;
|
622 |
+
}
|
623 |
+
|
624 |
+
/**
|
625 |
+
* Retrieve custom update message
|
626 |
+
* @uses this->get_message()
|
627 |
+
* @param obj $r Response data from plugin update API
|
628 |
+
* @return string Message (Default: empty string)
|
629 |
+
*/
|
630 |
+
protected function plugin_update_get_message( $r ) {
|
631 |
+
$msg = '';
|
632 |
+
$cls_notice = $this->add_prefix( 'notice' );
|
633 |
+
if ( ! is_object( $r ) || ! isset( $r->new_version ) ) {
|
634 |
+
return $msg;
|
635 |
+
}
|
636 |
+
if ( stripos( $r->new_version, 'beta' ) !== false ) {
|
637 |
+
$msg = sprintf( $this->get_message( 'beta' ), $cls_notice );
|
638 |
+
}
|
639 |
+
return $msg;
|
640 |
+
}
|
641 |
+
|
642 |
+
/*-** Messages **-*/
|
643 |
+
|
644 |
+
/**
|
645 |
+
* Retrieve stored messages
|
646 |
+
* @param string $msg_id Message ID
|
647 |
+
* @return string Message text
|
648 |
+
*/
|
649 |
+
public function get_message( $msg_id ) {
|
650 |
+
$msg = '';
|
651 |
+
$msgs = $this->get_messages();
|
652 |
+
if ( is_string( $msg_id ) && isset( $msgs[ $msg_id ] ) ) {
|
653 |
+
$msg = $msgs[ $msg_id ];
|
654 |
+
}
|
655 |
+
return $msg;
|
656 |
+
}
|
657 |
+
|
658 |
+
/**
|
659 |
+
* Retrieve all messages
|
660 |
+
* Initializes messages if necessary
|
661 |
+
* @uses $messages
|
662 |
+
* @return array Messages
|
663 |
+
*/
|
664 |
+
function get_messages() {
|
665 |
+
if ( empty( $this->messages ) ) {
|
666 |
+
// Initialize messages if necessary
|
667 |
+
$this->messages = array(
|
668 |
+
'reset' => __( 'The settings have been reset', 'simple-lightbox' ),
|
669 |
+
/* translators: 1: Notice CSS class */
|
670 |
+
'beta' => __( '<strong class="%1$s">Notice:</strong> This update is a <strong class="%1$s">Beta version</strong>. It is highly recommended that you test the update on a test server before updating the plugin on a production server.', 'simple-lightbox' ),
|
671 |
+
'access_denied' => __( 'Access Denied', 'simple-lightbox' ),
|
672 |
+
);
|
673 |
+
}
|
674 |
+
return $this->messages;
|
675 |
+
}
|
676 |
+
|
677 |
+
/**
|
678 |
+
* Set message text
|
679 |
+
* @uses this->messages
|
680 |
+
* @param string $id Message ID
|
681 |
+
* @param string $text Message text
|
682 |
+
*/
|
683 |
+
public function set_message( $id, $text ) {
|
684 |
+
$this->messages[ trim( $id ) ] = $text;
|
685 |
+
}
|
686 |
+
}
|
includes/class.admin_action.php
CHANGED
@@ -1,109 +1,110 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Plugin action functionality
|
5 |
-
* Used for adding action links to plugin listing, etc.
|
6 |
-
* @package Simple Lightbox
|
7 |
-
* @subpackage Admin
|
8 |
-
* @author Archetyped
|
9 |
-
*/
|
10 |
-
class SLB_Admin_Action extends SLB_Admin_View {
|
11 |
-
/* Properties */
|
12 |
-
|
13 |
-
protected $parent_required = false;
|
14 |
-
|
15 |
-
public $hook_prefix = 'admin_action';
|
16 |
-
|
17 |
-
/* Init */
|
18 |
-
|
19 |
-
/**
|
20 |
-
* Init
|
21 |
-
* @param string $id ID
|
22 |
-
* @param array $labels Labels
|
23 |
-
* @param obj $data Action data
|
24 |
-
* @return obj Current instance
|
25 |
-
*/
|
26 |
-
function __construct($id, $labels, $data = null) {
|
27 |
-
parent::__construct($id, $labels);
|
28 |
-
// Default options instance
|
29 |
-
if ( !empty($data) ) {
|
30 |
-
$this->add_content('data', $data);
|
31 |
-
}
|
32 |
-
return $this;
|
33 |
-
}
|
34 |
-
|
35 |
-
/* Handlers */
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Default handler
|
39 |
-
* Handles action
|
40 |
-
* @return string Status message (success, fail, etc.)
|
41 |
-
*/
|
42 |
-
public function handle() {
|
43 |
-
// Validate user
|
44 |
-
if ( ! current_user_can('activate_plugins') || ! check_admin_referer($this->get_id()) )
|
45 |
-
wp_die(__('Access Denied', 'simple-lightbox'));
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
$
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
*
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
$this->add_prefix('
|
80 |
-
$this->add_prefix('
|
81 |
-
$this->add_prefix('
|
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 |
-
}
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Plugin action functionality
|
5 |
+
* Used for adding action links to plugin listing, etc.
|
6 |
+
* @package Simple Lightbox
|
7 |
+
* @subpackage Admin
|
8 |
+
* @author Archetyped
|
9 |
+
*/
|
10 |
+
class SLB_Admin_Action extends SLB_Admin_View {
|
11 |
+
/* Properties */
|
12 |
+
|
13 |
+
protected $parent_required = false;
|
14 |
+
|
15 |
+
public $hook_prefix = 'admin_action';
|
16 |
+
|
17 |
+
/* Init */
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Init
|
21 |
+
* @param string $id ID
|
22 |
+
* @param array $labels Labels
|
23 |
+
* @param obj $data Action data
|
24 |
+
* @return obj Current instance
|
25 |
+
*/
|
26 |
+
function __construct( $id, $labels, $data = null ) {
|
27 |
+
parent::__construct( $id, $labels );
|
28 |
+
// Default options instance
|
29 |
+
if ( ! empty( $data ) ) {
|
30 |
+
$this->add_content( 'data', $data );
|
31 |
+
}
|
32 |
+
return $this;
|
33 |
+
}
|
34 |
+
|
35 |
+
/* Handlers */
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Default handler
|
39 |
+
* Handles action
|
40 |
+
* @return string Status message (success, fail, etc.)
|
41 |
+
*/
|
42 |
+
public function handle() {
|
43 |
+
// Validate user
|
44 |
+
if ( ! current_user_can( 'activate_plugins' ) || ! check_admin_referer( $this->get_id() ) ) {
|
45 |
+
wp_die( __( 'Access Denied', 'simple-lightbox' ) );
|
46 |
+
}
|
47 |
+
|
48 |
+
// Get data
|
49 |
+
$content = $this->get_content();
|
50 |
+
|
51 |
+
$success = true;
|
52 |
+
|
53 |
+
// Iterate through data
|
54 |
+
$hook = $this->util->get_hook( $this->get_id_raw() );
|
55 |
+
foreach ( $content as $c ) {
|
56 |
+
// Trigger action
|
57 |
+
$res = apply_filters( $hook, $success, $c->data, $this );
|
58 |
+
// Set result
|
59 |
+
if ( ! ! $success ) {
|
60 |
+
$success = $res;
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
// Set Status Message
|
65 |
+
$lbl = ( $success ) ? 'success' : 'failure';
|
66 |
+
$this->set_message( $this->get_label( $lbl ) );
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Get URI
|
71 |
+
* @see Admin_View::get_uri()
|
72 |
+
*/
|
73 |
+
public function get_uri( $file = null, $format = null ) {
|
74 |
+
return wp_nonce_url( add_query_arg( $this->get_query_args(), remove_query_arg( $this->get_query_args_remove(), $_SERVER['REQUEST_URI'] ) ), $this->get_id() );
|
75 |
+
}
|
76 |
+
|
77 |
+
protected function get_query_args() {
|
78 |
+
return array(
|
79 |
+
'action' => $this->add_prefix( 'admin' ),
|
80 |
+
$this->add_prefix( 'type' ) => 'view',
|
81 |
+
$this->add_prefix( 'group' ) => 'action',
|
82 |
+
$this->add_prefix( 'obj' ) => $this->get_id_raw(),
|
83 |
+
);
|
84 |
+
}
|
85 |
+
|
86 |
+
protected function get_query_args_remove() {
|
87 |
+
$args_r = array(
|
88 |
+
'_wpnonce',
|
89 |
+
$this->add_prefix( 'action' ),
|
90 |
+
);
|
91 |
+
|
92 |
+
return array_unique( array_merge( array_keys( $this->get_query_args() ), $args_r ) );
|
93 |
+
}
|
94 |
+
|
95 |
+
public function get_link_attr() {
|
96 |
+
return array(
|
97 |
+
'class' => $this->util->get_hook( $this->get_id_raw() ),
|
98 |
+
'onclick' => "return confirm('" . esc_js( $this->get_label( 'confirm' ) ) . "')",
|
99 |
+
);
|
100 |
+
}
|
101 |
+
|
102 |
+
/* Content */
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Save options
|
106 |
+
*/
|
107 |
+
public function add_content( $id, $data ) {
|
108 |
+
return parent::add_content( $id, array( 'data' => $data ) );
|
109 |
+
}
|
110 |
+
}
|
includes/class.admin_menu.php
CHANGED
@@ -1,40 +1,41 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Admin Menu
|
5 |
-
* Menus are top-level views in the Admin UI
|
6 |
-
* @package Simple Lightbox
|
7 |
-
* @subpackage Admin
|
8 |
-
* @author Archetyped
|
9 |
-
*/
|
10 |
-
class SLB_Admin_Menu extends SLB_Admin_View {
|
11 |
-
/* Properties */
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Menu position
|
15 |
-
* @var int
|
16 |
-
*/
|
17 |
-
protected $position = null;
|
18 |
-
|
19 |
-
/* Init */
|
20 |
-
|
21 |
-
public function __construct($id, $labels, $callback = null, $capability = null, $icon = null, $position = null) {
|
22 |
-
// Default
|
23 |
-
parent::__construct($id, $labels, $callback, $capability, $icon);
|
24 |
-
// Class specific
|
25 |
-
$this->set_position($position);
|
26 |
-
return $this;
|
27 |
-
}
|
28 |
-
|
29 |
-
/* Getters/Setters */
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Set menu position
|
33 |
-
* @return obj Current instance
|
34 |
-
*/
|
35 |
-
public function set_position($position) {
|
36 |
-
if ( is_int($position) )
|
37 |
-
$this->position = $position;
|
38 |
-
|
39 |
-
|
40 |
-
}
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Admin Menu
|
5 |
+
* Menus are top-level views in the Admin UI
|
6 |
+
* @package Simple Lightbox
|
7 |
+
* @subpackage Admin
|
8 |
+
* @author Archetyped
|
9 |
+
*/
|
10 |
+
class SLB_Admin_Menu extends SLB_Admin_View {
|
11 |
+
/* Properties */
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Menu position
|
15 |
+
* @var int
|
16 |
+
*/
|
17 |
+
protected $position = null;
|
18 |
+
|
19 |
+
/* Init */
|
20 |
+
|
21 |
+
public function __construct( $id, $labels, $callback = null, $capability = null, $icon = null, $position = null ) {
|
22 |
+
// Default
|
23 |
+
parent::__construct( $id, $labels, $callback, $capability, $icon );
|
24 |
+
// Class specific
|
25 |
+
$this->set_position( $position );
|
26 |
+
return $this;
|
27 |
+
}
|
28 |
+
|
29 |
+
/* Getters/Setters */
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Set menu position
|
33 |
+
* @return obj Current instance
|
34 |
+
*/
|
35 |
+
public function set_position( $position ) {
|
36 |
+
if ( is_int( $position ) ) {
|
37 |
+
$this->position = $position;
|
38 |
+
}
|
39 |
+
return $this;
|
40 |
+
}
|
41 |
+
}
|
includes/class.admin_page.php
CHANGED
@@ -1,187 +1,188 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Admin Page
|
5 |
-
* Pages are part of a Menu
|
6 |
-
* @package Simple Lightbox
|
7 |
-
* @subpackage Admin
|
8 |
-
* @author Archetyped
|
9 |
-
*/
|
10 |
-
class SLB_Admin_Page extends SLB_Admin_View {
|
11 |
-
/* Properties */
|
12 |
-
|
13 |
-
protected $parent_required = true;
|
14 |
-
|
15 |
-
public $hook_prefix = 'admin_page';
|
16 |
-
|
17 |
-
/**
|
18 |
-
* Required features/elements
|
19 |
-
*/
|
20 |
-
private $_required = array();
|
21 |
-
|
22 |
-
/* Init */
|
23 |
-
|
24 |
-
public function __construct($id, $parent, $labels, $callback = null, $capability = null) {
|
25 |
-
// Default
|
26 |
-
parent::__construct($id, $labels, $callback, $capability);
|
27 |
-
// Class specific
|
28 |
-
$this->set_parent($parent);
|
29 |
-
return $this;
|
30 |
-
}
|
31 |
-
|
32 |
-
/* Operations */
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Add content to page
|
36 |
-
* @uses parent::add_content()
|
37 |
-
* @param string $id Module ID
|
38 |
-
* @param string $title Module title
|
39 |
-
* @param mixed $callback Callback method or other data for building module UI
|
40 |
-
* @param string $context (optional) Context to add module to (Default: primary)
|
41 |
-
* @param string $priority (optional) Controls module ordering (Default: default)
|
42 |
-
* @param array $callback_args (optional) Additional data to pass callback (Default: NULL)
|
43 |
-
* @return object Page instance reference
|
44 |
-
*/
|
45 |
-
public function add_content($id, $title, $callback = null, $context = 'primary', $priority = 'default', $callback_args = null) {
|
46 |
-
|
47 |
-
'id'
|
48 |
-
'title'
|
49 |
-
'callback'
|
50 |
-
'context'
|
51 |
-
'priority'
|
52 |
-
'callback_args'
|
53 |
-
|
54 |
-
);
|
55 |
-
}
|
56 |
-
|
57 |
-
/**
|
58 |
-
* Parse content by parameters
|
59 |
-
* Sets content value
|
60 |
-
*/
|
61 |
-
protected function parse_content() {
|
62 |
-
// Get raw content
|
63 |
-
$raw = $this->get_content(false);
|
64 |
-
// Group by context
|
65 |
-
$content = array();
|
66 |
-
foreach ( $raw as $c ) {
|
67 |
-
// Add new context
|
68 |
-
if ( !isset($content[$c->context]) ) {
|
69 |
-
$content[$c->context] = array();
|
70 |
-
}
|
71 |
-
// Add item to context
|
72 |
-
$content[$c->context][] = $c;
|
73 |
-
}
|
74 |
-
return $content;
|
75 |
-
}
|
76 |
-
|
77 |
-
/**
|
78 |
-
* Render content blocks
|
79 |
-
* @param string $context (optional) Context to render
|
80 |
-
*/
|
81 |
-
protected function render_content($context = 'primary') {
|
82 |
-
// Get content
|
83 |
-
$content = $this->get_content();
|
84 |
-
// Check for context
|
85 |
-
if ( !isset($content[$context]) ) {
|
86 |
-
return false;
|
87 |
-
}
|
88 |
-
$content = $content[$context];
|
89 |
-
$out
|
90 |
-
// Render content
|
91 |
-
?>
|
92 |
-
<div class="content-wrap">
|
93 |
-
<?php
|
94 |
-
// Add meta boxes
|
95 |
-
$screen = get_current_screen();
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
// Output meta boxes
|
108 |
-
do_meta_boxes($screen, $context, null);
|
109 |
-
?>
|
110 |
-
</div>
|
111 |
-
<?php
|
112 |
-
}
|
113 |
-
|
114 |
-
/**
|
115 |
-
* Require form submission support
|
116 |
-
* @return obj Page instance
|
117 |
-
*/
|
118 |
-
public function require_form() {
|
119 |
-
$this->_require('form_submit');
|
120 |
-
return $this;
|
121 |
-
}
|
122 |
-
|
123 |
-
/**
|
124 |
-
* Check if form submission is required
|
125 |
-
* @return bool TRUE if form submission required
|
126 |
-
*/
|
127 |
-
private function is_required_form() {
|
128 |
-
return $this->_is_required('form_submit');
|
129 |
-
}
|
130 |
-
|
131 |
-
/* Handlers */
|
132 |
-
|
133 |
-
/**
|
134 |
-
* Default Page handler
|
135 |
-
* Builds content blocks
|
136 |
-
* @see this->init_menus() Set as callback for custom admin pages
|
137 |
-
* @uses current_user_can() to check if user has access to current page
|
138 |
-
* @uses wp_die() to end execution when user does not have permission to access page
|
139 |
-
*/
|
140 |
-
public function handle() {
|
141 |
-
if ( !current_user_can($this->get_capability()) )
|
142 |
-
wp_die(__('Access Denied', 'simple-lightbox'));
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
<?php
|
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 |
-
}
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Admin Page
|
5 |
+
* Pages are part of a Menu
|
6 |
+
* @package Simple Lightbox
|
7 |
+
* @subpackage Admin
|
8 |
+
* @author Archetyped
|
9 |
+
*/
|
10 |
+
class SLB_Admin_Page extends SLB_Admin_View {
|
11 |
+
/* Properties */
|
12 |
+
|
13 |
+
protected $parent_required = true;
|
14 |
+
|
15 |
+
public $hook_prefix = 'admin_page';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Required features/elements
|
19 |
+
*/
|
20 |
+
private $_required = array();
|
21 |
+
|
22 |
+
/* Init */
|
23 |
+
|
24 |
+
public function __construct( $id, $parent, $labels, $callback = null, $capability = null ) {
|
25 |
+
// Default
|
26 |
+
parent::__construct( $id, $labels, $callback, $capability );
|
27 |
+
// Class specific
|
28 |
+
$this->set_parent( $parent );
|
29 |
+
return $this;
|
30 |
+
}
|
31 |
+
|
32 |
+
/* Operations */
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Add content to page
|
36 |
+
* @uses parent::add_content()
|
37 |
+
* @param string $id Module ID
|
38 |
+
* @param string $title Module title
|
39 |
+
* @param mixed $callback Callback method or other data for building module UI
|
40 |
+
* @param string $context (optional) Context to add module to (Default: primary)
|
41 |
+
* @param string $priority (optional) Controls module ordering (Default: default)
|
42 |
+
* @param array $callback_args (optional) Additional data to pass callback (Default: NULL)
|
43 |
+
* @return object Page instance reference
|
44 |
+
*/
|
45 |
+
public function add_content( $id, $title, $callback = null, $context = 'primary', $priority = 'default', $callback_args = null ) {
|
46 |
+
$opts = [
|
47 |
+
'id' => $id,
|
48 |
+
'title' => $title,
|
49 |
+
'callback' => $callback,
|
50 |
+
'context' => $context,
|
51 |
+
'priority' => $priority,
|
52 |
+
'callback_args' => $callback_args,
|
53 |
+
];
|
54 |
+
return parent::add_content( $id, $opts );
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Parse content by parameters
|
59 |
+
* Sets content value
|
60 |
+
*/
|
61 |
+
protected function parse_content() {
|
62 |
+
// Get raw content
|
63 |
+
$raw = $this->get_content( false );
|
64 |
+
// Group by context
|
65 |
+
$content = array();
|
66 |
+
foreach ( $raw as $c ) {
|
67 |
+
// Add new context
|
68 |
+
if ( ! isset( $content[ $c->context ] ) ) {
|
69 |
+
$content[ $c->context ] = array();
|
70 |
+
}
|
71 |
+
// Add item to context
|
72 |
+
$content[ $c->context ][] = $c;
|
73 |
+
}
|
74 |
+
return $content;
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Render content blocks
|
79 |
+
* @param string $context (optional) Context to render
|
80 |
+
*/
|
81 |
+
protected function render_content( $context = 'primary' ) {
|
82 |
+
// Get content
|
83 |
+
$content = $this->get_content();
|
84 |
+
// Check for context
|
85 |
+
if ( ! isset( $content[ $context ] ) ) {
|
86 |
+
return false;
|
87 |
+
}
|
88 |
+
$content = $content[ $context ];
|
89 |
+
$out = '';
|
90 |
+
// Render content
|
91 |
+
?>
|
92 |
+
<div class="content-wrap">
|
93 |
+
<?php
|
94 |
+
// Add meta boxes
|
95 |
+
$screen = get_current_screen();
|
96 |
+
foreach ( $content as $c ) {
|
97 |
+
$c->screen = $screen;
|
98 |
+
// Callback
|
99 |
+
if ( is_callable( $c->callback ) ) {
|
100 |
+
$callback = $c->callback;
|
101 |
+
add_meta_box( $c->id, $c->title, $c->callback, $c->screen, $c->context, $c->priority, $c->callback_args );
|
102 |
+
} else {
|
103 |
+
// Let handlers build output
|
104 |
+
$this->util->do_action( 'render_content', $c->callback, $this, $c );
|
105 |
+
}
|
106 |
+
}
|
107 |
+
// Output meta boxes
|
108 |
+
do_meta_boxes( $screen, $context, null );
|
109 |
+
?>
|
110 |
+
</div>
|
111 |
+
<?php
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Require form submission support
|
116 |
+
* @return obj Page instance
|
117 |
+
*/
|
118 |
+
public function require_form() {
|
119 |
+
$this->_require( 'form_submit' );
|
120 |
+
return $this;
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Check if form submission is required
|
125 |
+
* @return bool TRUE if form submission required
|
126 |
+
*/
|
127 |
+
private function is_required_form() {
|
128 |
+
return $this->_is_required( 'form_submit' );
|
129 |
+
}
|
130 |
+
|
131 |
+
/* Handlers */
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Default Page handler
|
135 |
+
* Builds content blocks
|
136 |
+
* @see this->init_menus() Set as callback for custom admin pages
|
137 |
+
* @uses current_user_can() to check if user has access to current page
|
138 |
+
* @uses wp_die() to end execution when user does not have permission to access page
|
139 |
+
*/
|
140 |
+
public function handle() {
|
141 |
+
if ( ! current_user_can( $this->get_capability() ) ) {
|
142 |
+
wp_die( __( 'Access Denied', 'simple-lightbox' ) );
|
143 |
+
}
|
144 |
+
wp_enqueue_script( 'postbox' );
|
145 |
+
?>
|
146 |
+
<div class="wrap slb">
|
147 |
+
<h2><?php echo esc_html( $this->get_label( 'header' ) ); ?></h2>
|
148 |
+
<?php
|
149 |
+
// Form submission support
|
150 |
+
if ( $this->is_required_form() ) {
|
151 |
+
// Build form output
|
152 |
+
$form_id = $this->add_prefix( 'admin_form_' . $this->get_id_raw() );
|
153 |
+
$nonce = (object) [
|
154 |
+
'action' => $this->get_id(),
|
155 |
+
'name' => $this->get_id() . '_nonce',
|
156 |
+
];
|
157 |
+
?>
|
158 |
+
<form id="<?php echo esc_attr( $form_id ); ?>" name="<?php echo esc_attr( $form_id ); ?>" action="" method="post">
|
159 |
+
<?php
|
160 |
+
wp_nonce_field( $nonce->action, $nonce->name );
|
161 |
+
}
|
162 |
+
?>
|
163 |
+
<div class="metabox-holder columns-2">
|
164 |
+
<div class="content-primary postbox-container">
|
165 |
+
<?php
|
166 |
+
$this->render_content( 'primary' );
|
167 |
+
?>
|
168 |
+
</div>
|
169 |
+
<div class="content-secondary postbox-container">
|
170 |
+
<?php
|
171 |
+
$this->render_content( 'secondary' );
|
172 |
+
?>
|
173 |
+
</div>
|
174 |
+
</div>
|
175 |
+
<br class="clear" />
|
176 |
+
<?php
|
177 |
+
// Form submission support
|
178 |
+
if ( $this->is_required_form() ) {
|
179 |
+
submit_button();
|
180 |
+
?>
|
181 |
+
</form>
|
182 |
+
<?php
|
183 |
+
}
|
184 |
+
?>
|
185 |
+
</div>
|
186 |
+
<?php
|
187 |
+
}
|
188 |
+
}
|
includes/class.admin_section.php
CHANGED
@@ -1,51 +1,53 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Admin Section
|
5 |
-
* Sections are part of a Page
|
6 |
-
* @package Simple Lightbox
|
7 |
-
* @subpackage Admin
|
8 |
-
* @author Archetyped
|
9 |
-
*/
|
10 |
-
class SLB_Admin_Section extends SLB_Admin_View {
|
11 |
-
/* Properties */
|
12 |
-
|
13 |
-
protected $parent_required = true;
|
14 |
-
protected $parent_custom
|
15 |
-
|
16 |
-
/* Init */
|
17 |
-
|
18 |
-
public function __construct($id, $parent, $labels, $callback = null, $capability = null) {
|
19 |
-
// Default
|
20 |
-
parent::__construct($id, $labels, $callback, $capability);
|
21 |
-
// Class specific
|
22 |
-
$this->set_parent($parent);
|
23 |
-
return $this;
|
24 |
-
}
|
25 |
-
|
26 |
-
/* Getters/Setters */
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Retrieve URI
|
30 |
-
* @uses Admin_View::get_uri()
|
31 |
-
* @param string $file (optional) Base file name
|
32 |
-
* @param string $format (optional) String format
|
33 |
-
* @return string Section URI
|
34 |
-
*/
|
35 |
-
public function get_uri($file = null, $format = null) {
|
36 |
-
if ( !is_string($file) )
|
37 |
-
$file = 'options-' . $this->get_parent() . '.php';
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
*
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Admin Section
|
5 |
+
* Sections are part of a Page
|
6 |
+
* @package Simple Lightbox
|
7 |
+
* @subpackage Admin
|
8 |
+
* @author Archetyped
|
9 |
+
*/
|
10 |
+
class SLB_Admin_Section extends SLB_Admin_View {
|
11 |
+
/* Properties */
|
12 |
+
|
13 |
+
protected $parent_required = true;
|
14 |
+
protected $parent_custom = false;
|
15 |
+
|
16 |
+
/* Init */
|
17 |
+
|
18 |
+
public function __construct( $id, $parent, $labels, $callback = null, $capability = null ) {
|
19 |
+
// Default
|
20 |
+
parent::__construct( $id, $labels, $callback, $capability );
|
21 |
+
// Class specific
|
22 |
+
$this->set_parent( $parent );
|
23 |
+
return $this;
|
24 |
+
}
|
25 |
+
|
26 |
+
/* Getters/Setters */
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Retrieve URI
|
30 |
+
* @uses Admin_View::get_uri()
|
31 |
+
* @param string $file (optional) Base file name
|
32 |
+
* @param string $format (optional) String format
|
33 |
+
* @return string Section URI
|
34 |
+
*/
|
35 |
+
public function get_uri( $file = null, $format = null ) {
|
36 |
+
if ( ! is_string( $file ) ) {
|
37 |
+
$file = 'options-' . $this->get_parent() . '.php';
|
38 |
+
}
|
39 |
+
if ( ! is_string( $format ) ) {
|
40 |
+
$format = '%1$s#%2$s';
|
41 |
+
}
|
42 |
+
return parent::get_uri( $file, $format );
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Retrieve formatted title for section
|
47 |
+
* Wraps title text in element with anchor so that it can be linked to
|
48 |
+
* @return string Title
|
49 |
+
*/
|
50 |
+
public function get_title() {
|
51 |
+
return sprintf( '<div id="%1$s" class="%2$s">%3$s</div>', $this->get_id(), $this->add_prefix( 'section_head' ), $this->get_label( 'title' ) );
|
52 |
+
}
|
53 |
+
}
|
includes/class.admin_view.php
CHANGED
@@ -1,529 +1,553 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Admin View Base
|
5 |
-
* Core functionality Admin UI components
|
6 |
-
* @package Simple Lightbox
|
7 |
-
* @subpackage Admin
|
8 |
-
* @author Archetyped
|
9 |
-
*/
|
10 |
-
class SLB_Admin_View extends SLB_Base_Object {
|
11 |
-
/* Properties */
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Labels
|
15 |
-
* @var array (Associative)
|
16 |
-
*/
|
17 |
-
protected $labels = array();
|
18 |
-
|
19 |
-
/**
|
20 |
-
* Function to handle building UI
|
21 |
-
* @var callback
|
22 |
-
*/
|
23 |
-
protected $callback = null;
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Capability for access control
|
27 |
-
* @var string
|
28 |
-
*/
|
29 |
-
protected $capability = 'manage_options';
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Icon to use
|
33 |
-
* @var string
|
34 |
-
*/
|
35 |
-
protected $icon = null;
|
36 |
-
|
37 |
-
/**
|
38 |
-
* View parent ID/Slug
|
39 |
-
* @var string
|
40 |
-
*/
|
41 |
-
protected $parent = null;
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Whether parent is a custom view or a default WP one
|
45 |
-
* @var bool
|
46 |
-
*/
|
47 |
-
protected $parent_custom = true;
|
48 |
-
|
49 |
-
/**
|
50 |
-
* If view requires a parent
|
51 |
-
* @var bool
|
52 |
-
*/
|
53 |
-
protected $parent_required = false;
|
54 |
-
|
55 |
-
/**
|
56 |
-
* WP-Generated hook name for view
|
57 |
-
* @var string
|
58 |
-
*/
|
59 |
-
protected $hookname = null;
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Raw content parameters
|
63 |
-
* Stores pre-rendered content parameters
|
64 |
-
* Items stored by ID (key)
|
65 |
-
* @var array
|
66 |
-
*/
|
67 |
-
protected $content_raw = array();
|
68 |
-
|
69 |
-
/**
|
70 |
-
* Parsed content parameters
|
71 |
-
* @var array
|
72 |
-
*/
|
73 |
-
protected $content = array();
|
74 |
-
|
75 |
-
/**
|
76 |
-
* Messages to be displayed
|
77 |
-
* Indexed Array
|
78 |
-
* @var array
|
79 |
-
*/
|
80 |
-
protected $messages = array();
|
81 |
-
|
82 |
-
/**
|
83 |
-
* Required properties
|
84 |
-
* Associative array
|
85 |
-
* > Key: Property name
|
86 |
-
* > Value: Required data type
|
87 |
-
* @var array
|
88 |
-
*/
|
89 |
-
private $required = array();
|
90 |
-
|
91 |
-
/**
|
92 |
-
* Default required properties
|
93 |
-
* Merged into $required array with this->init_required()
|
94 |
-
* @see this->required for more information
|
95 |
-
* @var array
|
96 |
-
*/
|
97 |
-
private $_required = array
|
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 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
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 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
*
|
296 |
-
*/
|
297 |
-
protected function
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
*
|
341 |
-
* @return
|
342 |
-
*/
|
343 |
-
public function
|
344 |
-
$this->
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
*
|
350 |
-
* @return
|
351 |
-
*/
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
*
|
374 |
-
* @return
|
375 |
-
*/
|
376 |
-
public function
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
*
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
return $this;
|
406 |
-
}
|
407 |
-
|
408 |
-
/**
|
409 |
-
*
|
410 |
-
*
|
411 |
-
* @
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
*
|
422 |
-
*
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
*
|
449 |
-
* @
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
*
|
461 |
-
*
|
462 |
-
*
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Admin View Base
|
5 |
+
* Core functionality Admin UI components
|
6 |
+
* @package Simple Lightbox
|
7 |
+
* @subpackage Admin
|
8 |
+
* @author Archetyped
|
9 |
+
*/
|
10 |
+
class SLB_Admin_View extends SLB_Base_Object {
|
11 |
+
/* Properties */
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Labels
|
15 |
+
* @var array (Associative)
|
16 |
+
*/
|
17 |
+
protected $labels = array();
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Function to handle building UI
|
21 |
+
* @var callback
|
22 |
+
*/
|
23 |
+
protected $callback = null;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Capability for access control
|
27 |
+
* @var string
|
28 |
+
*/
|
29 |
+
protected $capability = 'manage_options';
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Icon to use
|
33 |
+
* @var string
|
34 |
+
*/
|
35 |
+
protected $icon = null;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* View parent ID/Slug
|
39 |
+
* @var string
|
40 |
+
*/
|
41 |
+
protected $parent = null;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Whether parent is a custom view or a default WP one
|
45 |
+
* @var bool
|
46 |
+
*/
|
47 |
+
protected $parent_custom = true;
|
48 |
+
|
49 |
+
/**
|
50 |
+
* If view requires a parent
|
51 |
+
* @var bool
|
52 |
+
*/
|
53 |
+
protected $parent_required = false;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* WP-Generated hook name for view
|
57 |
+
* @var string
|
58 |
+
*/
|
59 |
+
protected $hookname = null;
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Raw content parameters
|
63 |
+
* Stores pre-rendered content parameters
|
64 |
+
* Items stored by ID (key)
|
65 |
+
* @var array
|
66 |
+
*/
|
67 |
+
protected $content_raw = array();
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Parsed content parameters
|
71 |
+
* @var array
|
72 |
+
*/
|
73 |
+
protected $content = array();
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Messages to be displayed
|
77 |
+
* Indexed Array
|
78 |
+
* @var array
|
79 |
+
*/
|
80 |
+
protected $messages = array();
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Required properties
|
84 |
+
* Associative array
|
85 |
+
* > Key: Property name
|
86 |
+
* > Value: Required data type
|
87 |
+
* @var array
|
88 |
+
*/
|
89 |
+
private $required = array();
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Default required properties
|
93 |
+
* Merged into $required array with this->init_required()
|
94 |
+
* @see this->required for more information
|
95 |
+
* @var array
|
96 |
+
*/
|
97 |
+
private $_required = array(
|
98 |
+
'id' => 'string',
|
99 |
+
'labels' => 'array',
|
100 |
+
);
|
101 |
+
|
102 |
+
/* Init */
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Constructor
|
106 |
+
* @return obj Current instance
|
107 |
+
*/
|
108 |
+
public function __construct( $id, $labels, $callback = null, $capability = null, $icon = null ) {
|
109 |
+
$props = array(
|
110 |
+
'labels' => $labels,
|
111 |
+
'callback' => $callback,
|
112 |
+
'capability' => $capability,
|
113 |
+
'icon' => $icon,
|
114 |
+
);
|
115 |
+
parent::__construct( $id, $props );
|
116 |
+
$this->init_required();
|
117 |
+
return $this;
|
118 |
+
}
|
119 |
+
|
120 |
+
protected function init_required() {
|
121 |
+
$this->required = array_merge( $this->_required, $this->required );
|
122 |
+
// Check for parent requirement
|
123 |
+
if ( $this->parent_required ) {
|
124 |
+
$this->required['parent'] = 'string';
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Set required feature
|
130 |
+
* @param string $feature Required feature
|
131 |
+
*/
|
132 |
+
protected function _require( $feature ) {
|
133 |
+
if ( ! isset( $this->_required[ $feature ] ) ) {
|
134 |
+
$this->_required[ $feature ] = true;
|
135 |
+
}
|
136 |
+
return $this;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Check if feature is required
|
141 |
+
* @param string $feature Feature to check for
|
142 |
+
* @return bool TRUE if feature required
|
143 |
+
*/
|
144 |
+
protected function _is_required( $feature ) {
|
145 |
+
return ( isset( $this->_required[ $feature ] ) ) ? true : false;
|
146 |
+
}
|
147 |
+
|
148 |
+
/* Property Methods */
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Retrieve ID (Formatted by default)
|
152 |
+
* @param bool $formatted (optional) Whether ID should be formatted for external use or not
|
153 |
+
* @return string ID
|
154 |
+
*/
|
155 |
+
public function get_id( $formatted = true ) {
|
156 |
+
$id = parent::get_id();
|
157 |
+
if ( $formatted ) {
|
158 |
+
$this->add_prefix_ref( $id );
|
159 |
+
}
|
160 |
+
return $id;
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Retrieve raw ID
|
165 |
+
* @return string Raw ID
|
166 |
+
*/
|
167 |
+
public function get_id_raw() {
|
168 |
+
return $this->get_id( false );
|
169 |
+
}
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Retrieve label
|
173 |
+
* Uses first label (or default if defined) if specified type does not exist
|
174 |
+
* @param string $type Label type to retrieve
|
175 |
+
* @param string $default (optional) Default value if label type does not exist
|
176 |
+
* @return string Label text
|
177 |
+
*/
|
178 |
+
public function get_label( $type, $default = null ) {
|
179 |
+
// Retrieve existing label type
|
180 |
+
if ( $this->has_label( $type ) ) {
|
181 |
+
return $this->labels[ $type ];
|
182 |
+
}
|
183 |
+
// Use default label if type is not set
|
184 |
+
if ( empty( $default ) && ! empty( $this->labels ) ) {
|
185 |
+
reset( $this->labels );
|
186 |
+
$default = current( $this->labels );
|
187 |
+
}
|
188 |
+
|
189 |
+
return ( empty( $default ) ) ? '' : $default;
|
190 |
+
}
|
191 |
+
|
192 |
+
/**
|
193 |
+
* Set text labels
|
194 |
+
* @param array|string $labels
|
195 |
+
* @return obj Current instance
|
196 |
+
*/
|
197 |
+
public function set_labels( $labels ) {
|
198 |
+
if ( empty( $labels ) ) {
|
199 |
+
return this;
|
200 |
+
}
|
201 |
+
// Single string
|
202 |
+
if ( is_string( $labels ) ) {
|
203 |
+
$labels = array( $labels );
|
204 |
+
}
|
205 |
+
|
206 |
+
// Array
|
207 |
+
if ( is_array( $labels ) ) {
|
208 |
+
// Merge with existing labels
|
209 |
+
if ( empty( $this->labels ) || ! is_array( $this->labels ) ) {
|
210 |
+
$this->labels = array();
|
211 |
+
}
|
212 |
+
$this->labels = array_merge( $this->labels, $labels );
|
213 |
+
}
|
214 |
+
return $this;
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Set single text label
|
219 |
+
* @uses this->set_labels()
|
220 |
+
* @param string $type Label type to set
|
221 |
+
* @param string $value Label value
|
222 |
+
* @return obj Current instance
|
223 |
+
*/
|
224 |
+
public function set_label( $type, $value ) {
|
225 |
+
if ( is_string( $type ) && is_string( $value ) ) {
|
226 |
+
$label = array( $type => $value );
|
227 |
+
$this->set_labels( $label );
|
228 |
+
}
|
229 |
+
return $this;
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Checks if specified label is set on view
|
234 |
+
* @param string $type Label type
|
235 |
+
* @return bool TRUE if label exists, FALSE otherwise
|
236 |
+
*/
|
237 |
+
public function has_label( $type ) {
|
238 |
+
return ( isset( $this->labels[ $type ] ) );
|
239 |
+
}
|
240 |
+
|
241 |
+
/* Content */
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Add content block to view
|
245 |
+
* Child classes define method functionality
|
246 |
+
* @param string $id Content block ID
|
247 |
+
* @param array $args Content arguments (Defined by child class), converted to an object
|
248 |
+
* @return obj Current View instance
|
249 |
+
*/
|
250 |
+
public function add_content( $id, $args ) {
|
251 |
+
// Save parameters
|
252 |
+
$this->content_raw[ $id ] = (object) $args;
|
253 |
+
// Clear parsed content
|
254 |
+
$this->content = array();
|
255 |
+
// Return instance reference
|
256 |
+
return $this;
|
257 |
+
}
|
258 |
+
|
259 |
+
/**
|
260 |
+
* Retrieve content
|
261 |
+
*/
|
262 |
+
protected function get_content( $parsed = true ) {
|
263 |
+
// Return raw content.
|
264 |
+
if ( ! $parsed ) {
|
265 |
+
return $this->content_raw;
|
266 |
+
}
|
267 |
+
|
268 |
+
// Return parsed content.
|
269 |
+
if ( empty( $this->content ) && ! empty( $this->content_raw ) ) {
|
270 |
+
$this->content = $this->parse_content();
|
271 |
+
}
|
272 |
+
|
273 |
+
return $this->content;
|
274 |
+
}
|
275 |
+
|
276 |
+
/**
|
277 |
+
* Parse content
|
278 |
+
* Child classes define functionality
|
279 |
+
* @return array Parsed content
|
280 |
+
*/
|
281 |
+
protected function parse_content() {
|
282 |
+
return $this->get_content( false );
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Check if content has been added to view
|
287 |
+
* @return bool TRUE if content added
|
288 |
+
*/
|
289 |
+
protected function has_content() {
|
290 |
+
$raw = $this->get_content( false );
|
291 |
+
return ! empty( $raw );
|
292 |
+
}
|
293 |
+
|
294 |
+
/**
|
295 |
+
* Render content
|
296 |
+
*/
|
297 |
+
protected function render_content( $context = 'default' ) {}
|
298 |
+
|
299 |
+
/**
|
300 |
+
* Retrieve view messages
|
301 |
+
* @return array Messages
|
302 |
+
*/
|
303 |
+
protected function &get_messages() {
|
304 |
+
if ( ! is_array( $this->messages ) ) {
|
305 |
+
$this->messages = array();
|
306 |
+
}
|
307 |
+
return $this->messages;
|
308 |
+
}
|
309 |
+
|
310 |
+
/**
|
311 |
+
* Save message
|
312 |
+
* @param string $text Message text
|
313 |
+
* @return obj Current instance
|
314 |
+
*/
|
315 |
+
public function set_message( $text ) {
|
316 |
+
$msgs =& $this->get_messages();
|
317 |
+
$text = trim( $text );
|
318 |
+
if ( empty( $msgs ) && ! empty( $text ) ) {
|
319 |
+
$this->util->add_filter( 'admin_messages', $this->m( 'do_messages' ), 10, 1, false );
|
320 |
+
}
|
321 |
+
$msgs[] = $text;
|
322 |
+
return $this;
|
323 |
+
}
|
324 |
+
|
325 |
+
/**
|
326 |
+
* Add messages to array
|
327 |
+
* Called by internal `admin_messages` filter hook
|
328 |
+
* @param array $msgs Aggregated messages
|
329 |
+
* @return array Merged messages array
|
330 |
+
*/
|
331 |
+
public function do_messages( $msgs = array() ) {
|
332 |
+
$m =& $this->get_messages();
|
333 |
+
if ( ! empty( $m ) ) {
|
334 |
+
$msgs = array_merge( $msgs, $m );
|
335 |
+
}
|
336 |
+
return $msgs;
|
337 |
+
}
|
338 |
+
|
339 |
+
/**
|
340 |
+
* Retrieve view callback
|
341 |
+
* @return callback Callback (Default: standard handler method)
|
342 |
+
*/
|
343 |
+
public function get_callback() {
|
344 |
+
return ( $this->has_callback() ) ? $this->callback : $this->m( 'handle' );
|
345 |
+
}
|
346 |
+
|
347 |
+
/**
|
348 |
+
* Set callback function for building item
|
349 |
+
* @param callback $callback Callback function to use
|
350 |
+
* @return obj Current instance
|
351 |
+
*/
|
352 |
+
public function set_callback( $callback ) {
|
353 |
+
$this->callback = ( is_callable( $callback ) ) ? $callback : null;
|
354 |
+
return $this;
|
355 |
+
}
|
356 |
+
|
357 |
+
/**
|
358 |
+
* Check if callback set
|
359 |
+
* @return bool TRUE if callback is set
|
360 |
+
*/
|
361 |
+
protected function has_callback() {
|
362 |
+
return ( ! empty( $this->callback ) ) ? true : false;
|
363 |
+
}
|
364 |
+
|
365 |
+
/**
|
366 |
+
* Run callback
|
367 |
+
*/
|
368 |
+
public function do_callback() {
|
369 |
+
call_user_func( $this->get_callback() );
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* Retrieve capability
|
374 |
+
* @return string Capability
|
375 |
+
*/
|
376 |
+
public function get_capability() {
|
377 |
+
return $this->capability;
|
378 |
+
}
|
379 |
+
|
380 |
+
/**
|
381 |
+
* Set capability for access control
|
382 |
+
* @param string $capability Capability
|
383 |
+
* @return obj Current instance
|
384 |
+
*/
|
385 |
+
public function set_capability( $capability ) {
|
386 |
+
if ( is_string( $capability ) && ! empty( $capability ) ) {
|
387 |
+
$this->capability = $capability;
|
388 |
+
}
|
389 |
+
return $this;
|
390 |
+
}
|
391 |
+
|
392 |
+
/**
|
393 |
+
* Set icon
|
394 |
+
* @param string $icon Icon URI
|
395 |
+
* @return obj Current instance
|
396 |
+
*/
|
397 |
+
public function set_icon( $icon ) {
|
398 |
+
if ( ! empty( $icon ) && is_string( $icon ) ) {
|
399 |
+
$this->icon = $icon;
|
400 |
+
}
|
401 |
+
return $this;
|
402 |
+
}
|
403 |
+
|
404 |
+
protected function get_hookname() {
|
405 |
+
return ( empty( $this->hookname ) ) ? '' : $this->hookname;
|
406 |
+
}
|
407 |
+
|
408 |
+
/**
|
409 |
+
* Set hookname
|
410 |
+
* @param string $hookname Hookname value
|
411 |
+
* @return obj Current instance
|
412 |
+
*/
|
413 |
+
public function set_hookname( $hookname ) {
|
414 |
+
if ( ! empty( $hookname ) && is_string( $hookname ) ) {
|
415 |
+
$this->hookname = $hookname;
|
416 |
+
}
|
417 |
+
return $this;
|
418 |
+
}
|
419 |
+
|
420 |
+
/**
|
421 |
+
* Retrieve parent
|
422 |
+
* Formats parent ID for custom parents
|
423 |
+
* @uses parent::get_parent()
|
424 |
+
* @return string Parent ID
|
425 |
+
*/
|
426 |
+
public function get_parent() {
|
427 |
+
$parent = parent::get_parent();
|
428 |
+
return ( $this->is_parent_custom() ) ? $this->add_prefix( $parent ) : $parent;
|
429 |
+
}
|
430 |
+
|
431 |
+
/**
|
432 |
+
* Set parent for view
|
433 |
+
* @param string $parent Parent ID
|
434 |
+
* @return obj Current instance
|
435 |
+
*/
|
436 |
+
public function set_parent( $parent ) {
|
437 |
+
if ( $this->parent_required ) {
|
438 |
+
if ( ! empty( $parent ) && is_string( $parent ) ) {
|
439 |
+
$this->parent = $parent;
|
440 |
+
}
|
441 |
+
} else {
|
442 |
+
$this->parent = null;
|
443 |
+
}
|
444 |
+
return $this;
|
445 |
+
}
|
446 |
+
|
447 |
+
/**
|
448 |
+
* Specify whether parent is a custom view or a WP view
|
449 |
+
* @param bool $custom (optional) TRUE if custom, FALSE if WP
|
450 |
+
* @return obj Current instance
|
451 |
+
*/
|
452 |
+
protected function set_parent_custom( $custom = true ) {
|
453 |
+
if ( $this->parent_required ) {
|
454 |
+
$this->parent_custom = ! ! $custom;
|
455 |
+
}
|
456 |
+
return $this;
|
457 |
+
}
|
458 |
+
|
459 |
+
/**
|
460 |
+
* Set parent as WP view
|
461 |
+
* @uses this->set_parent_custom()
|
462 |
+
* @return obj Current instance
|
463 |
+
*/
|
464 |
+
public function set_parent_wp() {
|
465 |
+
$this->set_parent_custom( false );
|
466 |
+
return $this;
|
467 |
+
}
|
468 |
+
|
469 |
+
/**
|
470 |
+
* Get view URI
|
471 |
+
* URI Structures:
|
472 |
+
* > Top Level Menus: admin.php?page={menu_id}
|
473 |
+
* > Pages: [parent_page_file.php|admin.php]?page={page_id}
|
474 |
+
* > Section: [parent_menu_uri]#{section_id}
|
475 |
+
*
|
476 |
+
* @uses $admin_page_hooks to determine if page is child of default WP page
|
477 |
+
* @param string $file (optional) Base file name
|
478 |
+
* @param string $format (optional) Format string for URI
|
479 |
+
* @return string Object URI
|
480 |
+
*/
|
481 |
+
public function get_uri( $file = null, $format = null ) {
|
482 |
+
static $page_hooks = null;
|
483 |
+
$uri = '';
|
484 |
+
if ( empty( $file ) ) {
|
485 |
+
$file = 'admin.php';
|
486 |
+
}
|
487 |
+
if ( $this->is_child() ) {
|
488 |
+
$parent = str_replace( '_page_' . $this->get_id(), '', $this->get_hookname() );
|
489 |
+
if ( is_null( $page_hooks ) ) {
|
490 |
+
$page_hooks = array_flip( $GLOBALS['admin_page_hooks'] );
|
491 |
+
}
|
492 |
+
if ( isset( $page_hooks[ $parent ] ) ) {
|
493 |
+
$file = $page_hooks[ $parent ];
|
494 |
+
}
|
495 |
+
}
|
496 |
+
|
497 |
+
if ( empty( $format ) ) {
|
498 |
+
$delim = ( strpos( $file, '?' ) === false ) ? '?' : '&';
|
499 |
+
$format = '%1$s' . $delim . 'page=%2$s';
|
500 |
+
}
|
501 |
+
$uri = sprintf( $format, $file, $this->get_id() );
|
502 |
+
|
503 |
+
return $uri;
|
504 |
+
}
|
505 |
+
|
506 |
+
/* Handlers */
|
507 |
+
|
508 |
+
/**
|
509 |
+
* Default View handler
|
510 |
+
* Used as callback when none set
|
511 |
+
*/
|
512 |
+
public function handle() {}
|
513 |
+
|
514 |
+
/* Validation */
|
515 |
+
|
516 |
+
/**
|
517 |
+
* Check if instance is valid based on required properties/data types
|
518 |
+
* @return bool TRUE if valid, FALSE if not valid
|
519 |
+
*/
|
520 |
+
public function is_valid() {
|
521 |
+
$invalid = false;
|
522 |
+
foreach ( $this->required as $prop => $type ) {
|
523 |
+
// Baseline validation.
|
524 |
+
if (
|
525 |
+
empty( $this->{$prop} )
|
526 |
+
|| empty( $type )
|
527 |
+
|| ! is_string( $type )
|
528 |
+
) {
|
529 |
+
return $invalid;
|
530 |
+
}
|
531 |
+
|
532 |
+
// Validate data type.
|
533 |
+
$f = 'is_' . $type;
|
534 |
+
if ( ! function_exists( $f ) || ! $f( $this->{$prop} ) ) {
|
535 |
+
return $invalid;
|
536 |
+
}
|
537 |
+
}
|
538 |
+
return true;
|
539 |
+
}
|
540 |
+
|
541 |
+
protected function is_child() {
|
542 |
+
return $this->parent_required;
|
543 |
+
}
|
544 |
+
|
545 |
+
protected function is_parent_custom() {
|
546 |
+
return ( $this->is_child() && $this->parent_custom ) ? true : false;
|
547 |
+
}
|
548 |
+
|
549 |
+
public function is_parent_wp() {
|
550 |
+
return ( $this->is_child() && ! $this->parent_custom ) ? true : false;
|
551 |
+
}
|
552 |
+
|
553 |
+
}
|
includes/class.base.php
CHANGED
@@ -1,555 +1,561 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* @package Simple Lightbox
|
5 |
-
* @subpackage Base
|
6 |
-
* @author Archetyped
|
7 |
-
*
|
8 |
-
*/
|
9 |
-
class SLB_Base {
|
10 |
-
/* Configuration */
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Class type
|
14 |
-
* Controls initialization, etc.
|
15 |
-
* > full - Fully-functional class
|
16 |
-
* > sub - Sub-class (attached to an instance)
|
17 |
-
* > object - Simple object class (no hooks, etc.)
|
18 |
-
* @var string
|
19 |
-
*/
|
20 |
-
protected $mode = 'full';
|
21 |
-
|
22 |
-
/**
|
23 |
-
* Indicates that instance is model (main controller)
|
24 |
-
* @var bool
|
25 |
-
*/
|
26 |
-
protected $model = false;
|
27 |
-
|
28 |
-
/* Properties */
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Variable name of base object in global scope
|
32 |
-
* @var string
|
33 |
-
*/
|
34 |
-
protected $base = 'slb';
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Prefix for plugin-related data (attributes, DB tables, etc.)
|
38 |
-
* @var string
|
39 |
-
*/
|
40 |
-
public $prefix = 'slb';
|
41 |
-
|
42 |
-
/**
|
43 |
-
* Prefix to be added when creating internal hook (action/filter) tags
|
44 |
-
* Used by Utilities
|
45 |
-
* @var string
|
46 |
-
*/
|
47 |
-
public $hook_prefix = '';
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Global data
|
51 |
-
* Facilitates sharing between decoupled objects
|
52 |
-
* @var array
|
53 |
-
*/
|
54 |
-
private static $globals = array();
|
55 |
-
|
56 |
-
protected $shared = array('options', 'admin');
|
57 |
-
|
58 |
-
/**
|
59 |
-
* Capabilities
|
60 |
-
* @var array
|
61 |
-
*/
|
62 |
-
protected $caps = null;
|
63 |
-
|
64 |
-
protected $_init = false;
|
65 |
-
|
66 |
-
private static $_init_passed = false;
|
67 |
-
|
68 |
-
/* Client */
|
69 |
-
|
70 |
-
/**
|
71 |
-
* Client files
|
72 |
-
* @var array
|
73 |
-
* Structure
|
74 |
-
* > Key: unique file ID
|
75 |
-
* > Properties
|
76 |
-
* > file (string) File path (Relative to plugin base)
|
77 |
-
* > deps (array) Script dependencies
|
78 |
-
*
|
79 |
-
* > context (string|array)
|
80 |
-
*
|
81 |
-
* > in_footer (bool) optional [Default: FALSE]
|
82 |
-
*
|
83 |
-
*
|
84 |
-
* Array is processed and converted to an object on init
|
85 |
-
*/
|
86 |
-
private $client_files = array
|
87 |
-
'scripts'
|
88 |
-
'styles'
|
89 |
-
);
|
90 |
-
|
91 |
-
/*-** Instances **-*/
|
92 |
-
|
93 |
-
/**
|
94 |
-
* Utilities
|
95 |
-
* @var SLB_Utilities
|
96 |
-
*/
|
97 |
-
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Options
|
101 |
-
* @var SLB_Options
|
102 |
-
*/
|
103 |
-
protected $options = null;
|
104 |
-
|
105 |
-
/**
|
106 |
-
* Admin
|
107 |
-
* @var SLB_Admin
|
108 |
-
*/
|
109 |
-
|
110 |
-
|
111 |
-
/*-** Initialization **-*/
|
112 |
-
|
113 |
-
/**
|
114 |
-
* Constructor
|
115 |
-
*/
|
116 |
-
function __construct() {
|
117 |
-
$this->util = new SLB_Utilities($this);
|
118 |
-
if ( $this->can('init') ) {
|
119 |
-
$hook = 'init';
|
120 |
-
if ( did_action($hook) || self::$_init_passed ) {
|
121 |
-
$this->_init();
|
122 |
-
} else {
|
123 |
-
add_action($hook, $this->m('_init'), 1);
|
124 |
-
}
|
125 |
-
}
|
126 |
-
}
|
127 |
-
|
128 |
-
/**
|
129 |
-
* Default initialization method
|
130 |
-
* @uses _init_passed
|
131 |
-
* @uses _env()
|
132 |
-
* @uses _options()
|
133 |
-
* @uses _admin()
|
134 |
-
* @uses _hooks()
|
135 |
-
* @uses _client_files()
|
136 |
-
*/
|
137 |
-
public function _init() {
|
138 |
-
self::$_init_passed = true;
|
139 |
-
if ( $this->_init || !isset($this) ||
|
140 |
-
return false;
|
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 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
}
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
}
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
$
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
if ( empty($
|
263 |
-
|
264 |
-
}
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
//
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
*
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
*
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
//
|
328 |
-
|
329 |
-
$
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
//
|
339 |
-
if (
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
//
|
352 |
-
if ( $
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
}
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
$
|
525 |
-
if (
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @package Simple Lightbox
|
5 |
+
* @subpackage Base
|
6 |
+
* @author Archetyped
|
7 |
+
*
|
8 |
+
*/
|
9 |
+
class SLB_Base {
|
10 |
+
/* Configuration */
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Class type
|
14 |
+
* Controls initialization, etc.
|
15 |
+
* > full - Fully-functional class
|
16 |
+
* > sub - Sub-class (attached to an instance)
|
17 |
+
* > object - Simple object class (no hooks, etc.)
|
18 |
+
* @var string
|
19 |
+
*/
|
20 |
+
protected $mode = 'full';
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Indicates that instance is model (main controller)
|
24 |
+
* @var bool
|
25 |
+
*/
|
26 |
+
protected $model = false;
|
27 |
+
|
28 |
+
/* Properties */
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Variable name of base object in global scope
|
32 |
+
* @var string
|
33 |
+
*/
|
34 |
+
protected $base = 'slb';
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Prefix for plugin-related data (attributes, DB tables, etc.)
|
38 |
+
* @var string
|
39 |
+
*/
|
40 |
+
public $prefix = 'slb';
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Prefix to be added when creating internal hook (action/filter) tags
|
44 |
+
* Used by Utilities
|
45 |
+
* @var string
|
46 |
+
*/
|
47 |
+
public $hook_prefix = '';
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Global data
|
51 |
+
* Facilitates sharing between decoupled objects
|
52 |
+
* @var array
|
53 |
+
*/
|
54 |
+
private static $globals = array();
|
55 |
+
|
56 |
+
protected $shared = array( 'options', 'admin' );
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Capabilities
|
60 |
+
* @var array
|
61 |
+
*/
|
62 |
+
protected $caps = null;
|
63 |
+
|
64 |
+
protected $_init = false;
|
65 |
+
|
66 |
+
private static $_init_passed = false;
|
67 |
+
|
68 |
+
/* Client */
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Client files
|
72 |
+
* @var array
|
73 |
+
* Structure
|
74 |
+
* > Key: unique file ID
|
75 |
+
* > Properties
|
76 |
+
* > file (string) File path (Relative to plugin base)
|
77 |
+
* > deps (array) Script dependencies
|
78 |
+
* > Internal dependencies are wrapped in square brackets ([])
|
79 |
+
* > context (string|array)
|
80 |
+
* > Context in which the script should be included
|
81 |
+
* > in_footer (bool) optional [Default: FALSE]
|
82 |
+
* > If TRUE, file will be included in footer of page, otherwise it will be included in the header
|
83 |
+
*
|
84 |
+
* Array is processed and converted to an object on init
|
85 |
+
*/
|
86 |
+
private $client_files = array(
|
87 |
+
'scripts' => array(),
|
88 |
+
'styles' => array(),
|
89 |
+
);
|
90 |
+
|
91 |
+
/*-** Instances **-*/
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Utilities
|
95 |
+
* @var SLB_Utilities
|
96 |
+
*/
|
97 |
+
public $util = null;
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Options
|
101 |
+
* @var SLB_Options
|
102 |
+
*/
|
103 |
+
protected $options = null;
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Admin
|
107 |
+
* @var SLB_Admin
|
108 |
+
*/
|
109 |
+
public $admin = null;
|
110 |
+
|
111 |
+
/*-** Initialization **-*/
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Constructor
|
115 |
+
*/
|
116 |
+
function __construct() {
|
117 |
+
$this->util = new SLB_Utilities( $this );
|
118 |
+
if ( $this->can( 'init' ) ) {
|
119 |
+
$hook = 'init';
|
120 |
+
if ( did_action( $hook ) || self::$_init_passed ) {
|
121 |
+
$this->_init();
|
122 |
+
} else {
|
123 |
+
add_action( $hook, $this->m( '_init' ), 1 );
|
124 |
+
}
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Default initialization method
|
130 |
+
* @uses _init_passed
|
131 |
+
* @uses _env()
|
132 |
+
* @uses _options()
|
133 |
+
* @uses _admin()
|
134 |
+
* @uses _hooks()
|
135 |
+
* @uses _client_files()
|
136 |
+
*/
|
137 |
+
public function _init() {
|
138 |
+
self::$_init_passed = true;
|
139 |
+
if ( $this->_init || ! isset( $this ) || ! $this->can( 'init' ) ) {
|
140 |
+
return false;
|
141 |
+
}
|
142 |
+
$this->_init = true;
|
143 |
+
// Environment
|
144 |
+
$this->_env();
|
145 |
+
|
146 |
+
if ( $this->can( 'control' ) ) {
|
147 |
+
// Options
|
148 |
+
$this->_options();
|
149 |
+
|
150 |
+
// Admin
|
151 |
+
if ( is_admin() ) {
|
152 |
+
$this->_admin();
|
153 |
+
}
|
154 |
+
}
|
155 |
+
|
156 |
+
// Hooks
|
157 |
+
$this->_hooks();
|
158 |
+
|
159 |
+
// Client files
|
160 |
+
$this->_client_files();
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Initialize environment (Localization, etc.)
|
165 |
+
*/
|
166 |
+
private function _env() {
|
167 |
+
if ( ! $this->can( 'singleton' ) ) {
|
168 |
+
return false;
|
169 |
+
}
|
170 |
+
// Localization
|
171 |
+
$ldir = 'l10n';
|
172 |
+
$lpath = $this->util->get_plugin_file_path( $ldir, array( false, false ) );
|
173 |
+
$lpath_abs = $this->util->get_file_path( $ldir );
|
174 |
+
if ( is_dir( $lpath_abs ) ) {
|
175 |
+
load_plugin_textdomain( 'simple-lightbox', false, $lpath );
|
176 |
+
}
|
177 |
+
|
178 |
+
// Context
|
179 |
+
add_action( ( is_admin() ) ? 'admin_print_footer_scripts' : 'wp_footer', $this->util->m( 'set_client_context' ), $this->util->priority( 'client_footer_output' ) );
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Initialize options
|
184 |
+
* To be implemented in child classes
|
185 |
+
*/
|
186 |
+
protected function _options() {}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Initialize options
|
190 |
+
* To be called by child class
|
191 |
+
*/
|
192 |
+
protected function _set_options( $options_config = null ) {
|
193 |
+
$class = $this->util->get_class( 'Options' );
|
194 |
+
$key = 'options';
|
195 |
+
if ( $this->shares( $key ) ) {
|
196 |
+
$opts = $this->gvar( $key );
|
197 |
+
// Setup options instance
|
198 |
+
if ( ! ( $opts instanceof $class ) ) {
|
199 |
+
$opts = $this->gvar( $key, new $class() );
|
200 |
+
}
|
201 |
+
} else {
|
202 |
+
$opts = new $class();
|
203 |
+
}
|
204 |
+
// Load options
|
205 |
+
if ( $this->is_options_valid( $options_config, false ) ) {
|
206 |
+
$opts->load( $options_config );
|
207 |
+
}
|
208 |
+
// Set instance property
|
209 |
+
$this->options = $opts;
|
210 |
+
}
|
211 |
+
|
212 |
+
/**
|
213 |
+
* Initialize admin
|
214 |
+
* To be called by child class
|
215 |
+
*/
|
216 |
+
private function _admin() {
|
217 |
+
if ( ! is_admin() ) {
|
218 |
+
return false;
|
219 |
+
}
|
220 |
+
$class = $this->util->get_class( 'Admin' );
|
221 |
+
$key = 'admin';
|
222 |
+
if ( $this->shares( $key ) ) {
|
223 |
+
$adm = $this->gvar( $key );
|
224 |
+
// Setup options instance
|
225 |
+
if ( ! ( $adm instanceof $class ) ) {
|
226 |
+
$adm = $this->gvar( $key, new $class( $this ) );
|
227 |
+
}
|
228 |
+
} else {
|
229 |
+
$adm = new $class( $this );
|
230 |
+
}
|
231 |
+
// Set instance property
|
232 |
+
$this->admin = $adm;
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Register default hooks
|
237 |
+
*/
|
238 |
+
protected function _hooks() {
|
239 |
+
$base = $this->util->get_plugin_base_file();
|
240 |
+
// Activation
|
241 |
+
$func_activate = '_activate';
|
242 |
+
if ( method_exists( $this, $func_activate ) ) {
|
243 |
+
register_activation_hook( $base, $this->m( $func_activate ) );
|
244 |
+
}
|
245 |
+
|
246 |
+
// Deactivation
|
247 |
+
$func_deactivate = '_deactivate';
|
248 |
+
if ( method_exists( $this, $func_deactivate ) ) {
|
249 |
+
register_deactivation_hook( $base, $this->m( $func_deactivate ) );
|
250 |
+
}
|
251 |
+
}
|
252 |
+
|
253 |
+
/**
|
254 |
+
* Initialize client files
|
255 |
+
*/
|
256 |
+
protected function _client_files( $files = null ) {
|
257 |
+
// Validation
|
258 |
+
if ( ! is_array( $files ) || empty( $files ) ) {
|
259 |
+
return false;
|
260 |
+
}
|
261 |
+
foreach ( $this->client_files as $key => $val ) {
|
262 |
+
if ( isset( $files[ $key ] ) && is_array( $files[ $key ] ) || ! empty( $files[ $key ] ) ) {
|
263 |
+
$this->client_files[ $key ] = $this->util->parse_client_files( $files[ $key ], $key );
|
264 |
+
}
|
265 |
+
// Remove empty file groups
|
266 |
+
if ( empty( $this->client_files[ $key ] ) ) {
|
267 |
+
unset( $this->client_files[ $key ] );
|
268 |
+
}
|
269 |
+
}
|
270 |
+
|
271 |
+
// Stop if no files are set for registration
|
272 |
+
if ( empty( $this->client_files ) ) {
|
273 |
+
return false;
|
274 |
+
}
|
275 |
+
|
276 |
+
// Register
|
277 |
+
add_action( 'init', $this->m( 'register_client_files' ) );
|
278 |
+
|
279 |
+
// Enqueue
|
280 |
+
$hk_prfx = ( ( is_admin() ) ? 'admin' : 'wp' );
|
281 |
+
$hk_enqueue = $hk_prfx . '_enqueue_scripts';
|
282 |
+
$hk_enqueue_ft = $hk_prfx . '_footer';
|
283 |
+
add_action( $hk_enqueue, $this->m( 'enqueue_client_files' ), 10, 0 );
|
284 |
+
add_action( $hk_enqueue_ft, $this->m( 'enqueue_client_files_footer' ), 1 );
|
285 |
+
}
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Register client files
|
289 |
+
* @see enqueue_client_files() for actual loading of files based on context
|
290 |
+
* @uses `init` Action hook for execution
|
291 |
+
* @return void
|
292 |
+
*/
|
293 |
+
public function register_client_files() {
|
294 |
+
$v = $this->util->get_plugin_version();
|
295 |
+
foreach ( $this->client_files as $type => $files ) {
|
296 |
+
$func = $this->get_client_files_handler( $type, 'register' );
|
297 |
+
if ( ! $func ) {
|
298 |
+
continue;
|
299 |
+
}
|
300 |
+
foreach ( $files as $f ) {
|
301 |
+
// Get file URI
|
302 |
+
$f->file = ( ! $this->util->is_file( $f->file ) && is_callable( $f->file ) ) ? call_user_func( $f->file ) : $this->util->get_file_url( $f->file, true );
|
303 |
+
$params = array( $f->id, $f->file, $f->deps, $v );
|
304 |
+
// Set additional parameters based on file type (script, style, etc.)
|
305 |
+
switch ( $type ) {
|
306 |
+
case 'scripts':
|
307 |
+
$params[] = $f->in_footer;
|
308 |
+
break;
|
309 |
+
case 'styles':
|
310 |
+
$params[] = $f->media;
|
311 |
+
break;
|
312 |
+
}
|
313 |
+
// Register file
|
314 |
+
call_user_func_array( $func, $params );
|
315 |
+
}
|
316 |
+
}
|
317 |
+
}
|
318 |
+
|
319 |
+
/**
|
320 |
+
* Enqueues files for client output (scripts/styles) based on context
|
321 |
+
* @uses `admin_enqueue_scripts` Action hook depending on context
|
322 |
+
* @uses `wp_enqueue_scripts` Action hook depending on context
|
323 |
+
* @param bool $footer (optional) Whether to enqueue footer files (Default: No)
|
324 |
+
* @return void
|
325 |
+
*/
|
326 |
+
function enqueue_client_files( $footer = false ) {
|
327 |
+
// Validate
|
328 |
+
if ( ! is_bool( $footer ) ) {
|
329 |
+
$footer = false;
|
330 |
+
}
|
331 |
+
// Enqueue files
|
332 |
+
foreach ( $this->client_files as $type => $files ) {
|
333 |
+
$func = $this->get_client_files_handler( $type, 'enqueue' );
|
334 |
+
if ( ! $func ) {
|
335 |
+
continue;
|
336 |
+
}
|
337 |
+
foreach ( $files as $fkey => $f ) {
|
338 |
+
// Skip previously-enqueued files and shadow files
|
339 |
+
if ( $f->enqueued || ! $f->enqueue ) {
|
340 |
+
continue;
|
341 |
+
}
|
342 |
+
// Enqueue files only for current location (header/footer)
|
343 |
+
if ( isset( $f->in_footer ) ) {
|
344 |
+
if ( $f->in_footer !== $footer ) {
|
345 |
+
continue;
|
346 |
+
}
|
347 |
+
} elseif ( $footer ) {
|
348 |
+
continue;
|
349 |
+
}
|
350 |
+
$load = true;
|
351 |
+
// Global Callback
|
352 |
+
if ( is_callable( $f->callback ) && ! call_user_func( $f->callback ) ) {
|
353 |
+
$load = false;
|
354 |
+
}
|
355 |
+
// Context
|
356 |
+
if ( $load && ! empty( $f->context ) ) {
|
357 |
+
// Reset $load before evaluating context
|
358 |
+
$load = false;
|
359 |
+
// Iterate through contexts
|
360 |
+
foreach ( $f->context as $ctx ) {
|
361 |
+
// Context + Callback
|
362 |
+
if ( is_array( $ctx ) ) {
|
363 |
+
// Stop checking context if callback is invalid
|
364 |
+
if ( ! is_callable( $ctx[1] ) || ! call_user_func( $ctx[1] ) ) {
|
365 |
+
continue;
|
366 |
+
}
|
367 |
+
$ctx = $ctx[0];
|
368 |
+
}
|
369 |
+
// Stop checking context if valid context found
|
370 |
+
if ( $this->util->is_context( $ctx ) ) {
|
371 |
+
$load = true;
|
372 |
+
break;
|
373 |
+
}
|
374 |
+
}
|
375 |
+
}
|
376 |
+
// Load valid file
|
377 |
+
if ( $load ) {
|
378 |
+
// Mark file as enqueued
|
379 |
+
$this->client_files[ $type ]->{$fkey}->enqueued = true;
|
380 |
+
$func( $f->id );
|
381 |
+
}
|
382 |
+
}
|
383 |
+
}
|
384 |
+
}
|
385 |
+
|
386 |
+
/**
|
387 |
+
* Enqueue client files in the footer
|
388 |
+
*/
|
389 |
+
public function enqueue_client_files_footer() {
|
390 |
+
$this->enqueue_client_files( true );
|
391 |
+
}
|
392 |
+
|
393 |
+
/**
|
394 |
+
* Build function name for handling client operations
|
395 |
+
*/
|
396 |
+
function get_client_files_handler( $type, $action ) {
|
397 |
+
$func = 'wp_' . $action . '_' . substr( $type, 0, -1 );
|
398 |
+
if ( ! function_exists( $func ) ) {
|
399 |
+
$func = false;
|
400 |
+
}
|
401 |
+
return $func;
|
402 |
+
}
|
403 |
+
|
404 |
+
/*-** Reflection **-*/
|
405 |
+
|
406 |
+
/**
|
407 |
+
* Retrieve base object
|
408 |
+
* @return object|bool Base object (FALSE if object does not exist)
|
409 |
+
*/
|
410 |
+
function &get_base() {
|
411 |
+
$base = false;
|
412 |
+
if ( isset( $GLOBALS[ $this->base ] ) ) {
|
413 |
+
$base =& $GLOBALS[ $this->base ];
|
414 |
+
}
|
415 |
+
return $base;
|
416 |
+
}
|
417 |
+
|
418 |
+
/*-** Method/Function calling **-*/
|
419 |
+
|
420 |
+
/**
|
421 |
+
* Returns callback to instance method
|
422 |
+
* @param string $method Method name
|
423 |
+
* @return array Callback array
|
424 |
+
*/
|
425 |
+
function m( $method ) {
|
426 |
+
return $this->util->m( $this, $method );
|
427 |
+
}
|
428 |
+
|
429 |
+
/*-** Prefix **-*/
|
430 |
+
|
431 |
+
/**
|
432 |
+
* Retrieve class prefix (with separator if set)
|
433 |
+
* @param bool|string $sep Separator to append to class prefix (Default: no separator)
|
434 |
+
* @return string Class prefix
|
435 |
+
*/
|
436 |
+
function get_prefix( $sep = null ) {
|
437 |
+
$args = func_get_args();
|
438 |
+
return call_user_func_array( $this->util->m( $this->util, 'get_prefix' ), $args );
|
439 |
+
}
|
440 |
+
|
441 |
+
/**
|
442 |
+
* Check if a string is prefixed
|
443 |
+
* @param string $text Text to check for prefix
|
444 |
+
* @param string $sep (optional) Separator used
|
445 |
+
*/
|
446 |
+
function has_prefix( $text, $sep = null ) {
|
447 |
+
$args = func_get_args();
|
448 |
+
return call_user_func_array( $this->util->m( $this->util, 'has_prefix' ), $args );
|
449 |
+
}
|
450 |
+
|
451 |
+
/**
|
452 |
+
* Prepend plugin prefix to some text
|
453 |
+
* @param string $text Text to add to prefix
|
454 |
+
* @param string $sep (optional) Text used to separate prefix and text
|
455 |
+
* @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not
|
456 |
+
* @return string Text with prefix prepended
|
457 |
+
*/
|
458 |
+
function add_prefix( $text, $sep = null, $once = true ) {
|
459 |
+
$args = func_get_args();
|
460 |
+
return call_user_func_array( $this->util->m( $this->util, 'add_prefix' ), $args );
|
461 |
+
}
|
462 |
+
|
463 |
+
/**
|
464 |
+
* Prepend uppercased plugin prefix to some text
|
465 |
+
* @param string $text Text to add to prefix
|
466 |
+
* @param string $sep (optional) Text used to separate prefix and text
|
467 |
+
* @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not
|
468 |
+
* @return string Text with prefix prepended
|
469 |
+
*/
|
470 |
+
function add_prefix_uc( $text, $sep = null, $once = true ) {
|
471 |
+
$args = func_get_args();
|
472 |
+
return call_user_func_array( $this->util->m( $this->util, 'add_prefix_uc' ), $args );
|
473 |
+
}
|
474 |
+
|
475 |
+
/**
|
476 |
+
* Add prefix to variable reference
|
477 |
+
* Updates actual variable rather than return value
|
478 |
+
* @uses SLB_Utilities::add_prefix_ref();
|
479 |
+
* @param string $var Variable to add prefix to
|
480 |
+
* @param string $sep (optional) Separator text
|
481 |
+
* @param bool $once (optional) Add prefix only once
|
482 |
+
* @return void
|
483 |
+
*/
|
484 |
+
function add_prefix_ref( &$var, $sep = null, $once = true ) {
|
485 |
+
$args = func_get_args();
|
486 |
+
$args[0] =& $var;
|
487 |
+
call_user_func_array( $this->util->m( $this->util, 'add_prefix_ref' ), $args );
|
488 |
+
}
|
489 |
+
|
490 |
+
/**
|
491 |
+
* Remove prefix from specified string
|
492 |
+
* @param string $text String to remove prefix from
|
493 |
+
* @param string $sep (optional) Separator used with prefix
|
494 |
+
*/
|
495 |
+
function remove_prefix( $text, $sep = null ) {
|
496 |
+
$args = func_get_args();
|
497 |
+
return call_user_func_array( $this->util->m( $this->util, 'remove_prefix' ), $args );
|
498 |
+
}
|
499 |
+
|
500 |
+
/*-** Capabilities **-*/
|
501 |
+
|
502 |
+
protected function can( $cap ) {
|
503 |
+
if ( is_null( $this->caps ) ) {
|
504 |
+
// Build capabilities based on instance properties
|
505 |
+
$this->caps = array(
|
506 |
+
'init' => ( 'object' !== $this->mode ) ? true : false,
|
507 |
+
'singleton' => ( ! ! $this->model ) ? true : false,
|
508 |
+
'control' => ( 'sub' === $this->mode || 'object' === $this->mode ) ? false : true,
|
509 |
+
);
|
510 |
+
}
|
511 |
+
return ( isset( $this->caps[ $cap ] ) ) ? $this->caps[ $cap ] : false;
|
512 |
+
}
|
513 |
+
|
514 |
+
/*-** Globals **-*/
|
515 |
+
|
516 |
+
/**
|
517 |
+
* Get/Set (internal) global variables
|
518 |
+
* @uses $globals to get/set global variables
|
519 |
+
* @param string $name Variable name - If no name is specified, entire globals array is returned
|
520 |
+
* @param mixed $val (optional) Set the value of a variable (Returns variable value if omitted)
|
521 |
+
* @return mixed Variable value
|
522 |
+
*/
|
523 |
+
private function gvar( $name = null, $val = null ) {
|
524 |
+
$g =& self::$globals;
|
525 |
+
if ( ! is_array( $g ) ) {
|
526 |
+
$g = array();
|
527 |
+
}
|
528 |
+
if ( ! is_string( $name ) || empty( $name ) ) {
|
529 |
+
return $g;
|
530 |
+
}
|
531 |
+
$ret = $val;
|
532 |
+
if ( null !== $val ) {
|
533 |
+
// Set Value
|
534 |
+
$g[ $name ] = $val;
|
535 |
+
} elseif ( isset( $g[ $name ] ) ) {
|
536 |
+
// Retrieve variable
|
537 |
+
$ret = $g[ $name ];
|
538 |
+
}
|
539 |
+
return $ret;
|
540 |
+
}
|
541 |
+
|
542 |
+
private function shares( $name ) {
|
543 |
+
return ( ! empty( $this->shared ) && in_array( $name, $this->shared, true ) ) ? true : false;
|
544 |
+
}
|
545 |
+
|
546 |
+
/*-** Options **-*/
|
547 |
+
|
548 |
+
/**
|
549 |
+
* Checks if options are valid
|
550 |
+
* @param array $data Data to be used on options
|
551 |
+
* @return bool TRUE if options are valid, FALSE otherwise
|
552 |
+
*/
|
553 |
+
function is_options_valid( $data, $check_var = true ) {
|
554 |
+
$class = $this->util->get_class( 'Options' );
|
555 |
+
$ret = ( empty( $data ) || ! is_array( $data ) || ! class_exists( $class ) ) ? false : true;
|
556 |
+
if ( $ret && $check_var && ! ( $this->options instanceof $class ) ) {
|
557 |
+
$ret = false;
|
558 |
+
}
|
559 |
+
return $ret;
|
560 |
+
}
|
561 |
+
}
|
includes/class.base_collection.php
CHANGED
@@ -1,369 +1,369 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Managed collection
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Base
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Base_Collection extends SLB_Base {
|
10 |
-
/* Configuration */
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Set object mode
|
14 |
-
* @var string
|
15 |
-
*/
|
16 |
-
protected $mode = 'object';
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Item type
|
20 |
-
* @var string
|
21 |
-
*/
|
22 |
-
protected $item_type = null;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Property to use for item key
|
26 |
-
* Example: A property or method of the item
|
27 |
-
* @var string
|
28 |
-
*/
|
29 |
-
protected $key_prop = null;
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Should $key_prop be called or retrieved?
|
33 |
-
* Default: Retrieved (FALSE)
|
34 |
-
* @var bool
|
35 |
-
*/
|
36 |
-
protected $key_call = false;
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Items in collection unique?
|
40 |
-
* Default: FALSE
|
41 |
-
* @var bool
|
42 |
-
*/
|
43 |
-
protected $unique = false;
|
44 |
-
|
45 |
-
/* Properties */
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Indexed array of items in collection
|
49 |
-
* @var array
|
50 |
-
*/
|
51 |
-
protected $items = null;
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Item metadata
|
55 |
-
* Indexed by item key
|
56 |
-
* @var array
|
57 |
-
*/
|
58 |
-
protected $items_meta = array();
|
59 |
-
|
60 |
-
/* Item Management */
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Initialize collections
|
64 |
-
* Calls `init` action if collection has a hook prefix
|
65 |
-
*/
|
66 |
-
private function init() {
|
67 |
-
// Initialize
|
68 |
-
if ( is_null($this->items) ) {
|
69 |
-
$this->items = array();
|
70 |
-
if ( !empty($this->hook_prefix) ) {
|
71 |
-
$this->util->do_action('init', $this);
|
72 |
-
}
|
73 |
-
}
|
74 |
-
}
|
75 |
-
|
76 |
-
/**
|
77 |
-
* Normalize/Validate item(s)
|
78 |
-
* TODO: If no items are specified, then collection is normalized
|
79 |
-
* Single items are wrapped in an array
|
80 |
-
* @param array|object $items Item(s) to validate
|
81 |
-
* @return array Validated items
|
82 |
-
*/
|
83 |
-
protected function normalize($items) {
|
84 |
-
if ( !is_array($items) ) {
|
85 |
-
$items = array($items);
|
86 |
-
}
|
87 |
-
// Validate item type
|
88 |
-
if ( !is_null($this->item_type) ) {
|
89 |
-
foreach ( $items as $idx => $item ) {
|
90 |
-
// Remove invalid items
|
91 |
-
if ( !( $item instanceof $this->item_type ) ) {
|
92 |
-
unset($items[$idx]);
|
93 |
-
}
|
94 |
-
}
|
95 |
-
}
|
96 |
-
if ( !empty($items) ) {
|
97 |
-
$items = array_values($items);
|
98 |
-
}
|
99 |
-
return $items;
|
100 |
-
}
|
101 |
-
|
102 |
-
protected function item_valid($item) {
|
103 |
-
// Validate item type
|
104 |
-
return ( empty($this->item_type) || ( $item instanceof $this->item_type ) ) ? true : false;
|
105 |
-
}
|
106 |
-
|
107 |
-
/**
|
108 |
-
* Validate item key
|
109 |
-
* Checks collection for existence of key as well
|
110 |
-
* @param string|int $key Key to check collection for
|
111 |
-
* @return bool TRUE if key is valid
|
112 |
-
*/
|
113 |
-
protected function key_valid($key) {
|
114 |
-
$this->init();
|
115 |
-
return ( ( ( is_string($key) && !empty($key) ) || is_int($key) ) && isset($this->items[$key]) ) ? true : false;
|
116 |
-
}
|
117 |
-
|
118 |
-
/**
|
119 |
-
* Generate key for item (for storing in collection, etc.)
|
120 |
-
* @param mixed $item Item to generate key for
|
121 |
-
* @return string|null Item key (NULL if no key generated)
|
122 |
-
*/
|
123 |
-
protected function get_key($item, $check_existing = false) {
|
124 |
-
$ret = null;
|
125 |
-
if ( $this->unique ||
|
126 |
-
// Check for item in collection
|
127 |
-
if ( $this->has($item) ) {
|
128 |
-
$ret = array_search($item, $this->items);
|
129 |
-
} elseif (
|
130 |
-
if (
|
131 |
-
$cb = $this->util->m($item, $this->key_prop);
|
132 |
-
if ( is_callable($cb) ) {
|
133 |
-
$ret = call_user_func($cb);
|
134 |
-
}
|
135 |
-
} elseif ( is_array($item) && isset($item[$this->key_prop]) ) {
|
136 |
-
$ret = $item[$this->key_prop];
|
137 |
-
} elseif ( is_object($item) && isset($item->{$this->key_prop}) ) {
|
138 |
-
$ret = $item->{$this->key_prop};
|
139 |
-
}
|
140 |
-
}
|
141 |
-
}
|
142 |
-
return $ret;
|
143 |
-
}
|
144 |
-
|
145 |
-
/**
|
146 |
-
* Add item to collection
|
147 |
-
* @param mixed $item Item to add to collection
|
148 |
-
* @param array $meta (optional) Item metadata
|
149 |
-
* @return Current instance
|
150 |
-
*/
|
151 |
-
public function add($item, $meta = null) {
|
152 |
-
$this->init();
|
153 |
-
// Validate
|
154 |
-
if ( $this->item_valid($item) ) {
|
155 |
-
// Add item to collection
|
156 |
-
$key = $this->get_key($item);
|
157 |
-
if (
|
158 |
-
$this->items[] = $item;
|
159 |
-
$key
|
160 |
-
} else {
|
161 |
-
$this->items[$key] = $item;
|
162 |
-
}
|
163 |
-
// Add metadata
|
164 |
-
if (
|
165 |
-
$this->add_meta($key, $meta);
|
166 |
-
}
|
167 |
-
}
|
168 |
-
return $this;
|
169 |
-
}
|
170 |
-
|
171 |
-
/**
|
172 |
-
* Remove item from collection
|
173 |
-
* @param int|string $item Key of item to remove
|
174 |
-
* @return Current instance
|
175 |
-
*/
|
176 |
-
public function remove($item) {
|
177 |
-
if ( $this->key_valid($item) ) {
|
178 |
-
unset($this->items[$item]);
|
179 |
-
}
|
180 |
-
return $this;
|
181 |
-
}
|
182 |
-
|
183 |
-
/**
|
184 |
-
* Clear collection
|
185 |
-
* @return Current instance
|
186 |
-
*/
|
187 |
-
public function clear() {
|
188 |
-
$this->items = array();
|
189 |
-
return $this;
|
190 |
-
}
|
191 |
-
|
192 |
-
/**
|
193 |
-
* Checks if item exists in the collection
|
194 |
-
* @param mixed $item Item(s) to check for
|
195 |
-
* @return bool TRUE if item(s) in collection
|
196 |
-
*/
|
197 |
-
public function has($items) {
|
198 |
-
// Attempt to locate item
|
199 |
-
return false;
|
200 |
-
}
|
201 |
-
|
202 |
-
/**
|
203 |
-
* Retrieve item(s) from collection
|
204 |
-
* If no items specified, entire collection returned
|
205 |
-
* @param array $args (optional) Query arguments
|
206 |
-
* @return object|array Specified item(s)
|
207 |
-
*/
|
208 |
-
public function get($args = null) {
|
209 |
-
$this->init();
|
210 |
-
// Parse args
|
211 |
-
$args_default = array(
|
212 |
-
'orderby'
|
213 |
-
'order'
|
214 |
-
'include'
|
215 |
-
'exclude'
|
216 |
-
);
|
217 |
-
$r
|
218 |
-
|
219 |
-
$items = $this->items;
|
220 |
-
|
221 |
-
/* Sort */
|
222 |
-
if ( !is_null($r['orderby']) ) {
|
223 |
-
// Validate
|
224 |
-
if ( !is_array($r['orderby']) ) {
|
225 |
-
$r['orderby'] = array('item' => $r['orderby']);
|
226 |
-
}
|
227 |
-
// Prep
|
228 |
-
$metas = ( isset($r['orderby']['meta']) ) ? $this->items_meta : array();
|
229 |
-
// Sort
|
230 |
-
foreach ( $r['orderby'] as $stype => $sval ) {
|
231 |
-
/* Meta sorting */
|
232 |
-
if ( 'meta'
|
233 |
-
// Build sorting buckets
|
234 |
-
$buckets = array();
|
235 |
-
foreach ( $metas as $item => $meta ) {
|
236 |
-
if ( !isset($meta[$sval]) ) {
|
237 |
-
continue;
|
238 |
-
}
|
239 |
-
// Create bucket
|
240 |
-
$idx = $meta[$sval];
|
241 |
-
if ( !isset($buckets[ $idx ]) ) {
|
242 |
-
$buckets[ $idx ] = array();
|
243 |
-
}
|
244 |
-
// Add item to bucket
|
245 |
-
$buckets[ $idx ][] = $item;
|
246 |
-
}
|
247 |
-
// Sort buckets
|
248 |
-
ksort($buckets, SORT_NUMERIC);
|
249 |
-
// Merge buckets
|
250 |
-
$pool = array();
|
251 |
-
foreach ( $buckets as $bucket ) {
|
252 |
-
$pool = array_merge($pool, $bucket);
|
253 |
-
}
|
254 |
-
// Fill with items
|
255 |
-
$items = array_merge( array_fill_keys($pool, null), $items);
|
256 |
-
}
|
257 |
-
}
|
258 |
-
// Clear workers
|
259 |
-
unset($stype, $sval, $buckets, $pool, $item, $metas, $meta, $idx);
|
260 |
-
}
|
261 |
-
return $items;
|
262 |
-
}
|
263 |
-
|
264 |
-
/* Metadata */
|
265 |
-
|
266 |
-
/**
|
267 |
-
* Add metadata for item
|
268 |
-
* @param string|int $item Item key
|
269 |
-
* @param string|array $meta_key Meta key to set (or array of metadata)
|
270 |
-
* @param mixed $meta_value (optional) Metadata value (if key set)
|
271 |
-
* @param bool $reset (optional) Whether to remove existing metadata first (Default: FALSE)
|
272 |
-
* @return object Current instance
|
273 |
-
*/
|
274 |
-
protected function add_meta($item, $meta_key, $meta_value = null, $reset = false) {
|
275 |
-
// Validate
|
276 |
-
if ( $this->key_valid($item) && ( is_array($meta_key) || is_string($meta_key) ) ) {
|
277 |
-
// Prepare metadata
|
278 |
-
$meta = ( is_string($meta_key) ) ? array($meta_key => $meta_value) : $meta_key;
|
279 |
-
// Reset existing meta (if necessary)
|
280 |
-
if ( is_array($meta_key) && func_num_args() > 2) {
|
281 |
-
$reset = func_get_arg(2);
|
282 |
-
}
|
283 |
-
if (
|
284 |
-
unset($this->items_meta[$item]);
|
285 |
-
}
|
286 |
-
// Add metadata
|
287 |
-
if ( !isset($this->items_meta[$item]) ) {
|
288 |
-
$this->items_meta[$item] = array();
|
289 |
-
}
|
290 |
-
$this->items_meta[$item] = array_merge($this->items_meta[$item], $meta);
|
291 |
-
}
|
292 |
-
return $this;
|
293 |
-
}
|
294 |
-
|
295 |
-
/**
|
296 |
-
* Remove item metadata
|
297 |
-
* @param string $item Item key
|
298 |
-
* @return object Current instance
|
299 |
-
*/
|
300 |
-
protected function remove_meta($item, $meta_key = null) {
|
301 |
-
if ( $this->key_valid($item) && isset($this->items_meta[$item]) ) {
|
302 |
-
if ( is_string($meta_key) ) {
|
303 |
-
// Remove specific meta value
|
304 |
-
unset($this->items_meta[$item][$meta_key]);
|
305 |
-
} else {
|
306 |
-
// Remove all metadata
|
307 |
-
unset($this->items_meta[$item]);
|
308 |
-
}
|
309 |
-
}
|
310 |
-
return $this;
|
311 |
-
}
|
312 |
-
|
313 |
-
/**
|
314 |
-
* Retrieve metadata
|
315 |
-
* @param string $item Item key
|
316 |
-
* @param string $meta_key (optional) Meta key (All metadata retrieved if no key specified)
|
317 |
-
* @return mixed|null Metadata value
|
318 |
-
*/
|
319 |
-
protected function get_meta($item, $meta_key = null) {
|
320 |
-
$ret = null;
|
321 |
-
if ( $this->key_valid($item) && isset($this->items_meta[$item]) ) {
|
322 |
-
if ( is_null($meta_key) ) {
|
323 |
-
$ret = $this->items_meta[$item];
|
324 |
-
} elseif ( is_string($meta_key) && isset($this->items_meta[$item][$meta_key]) ) {
|
325 |
-
$ret = $this->items_meta[$item][$meta_key];
|
326 |
-
}
|
327 |
-
}
|
328 |
-
return $ret;
|
329 |
-
}
|
330 |
-
|
331 |
-
/* Collection */
|
332 |
-
|
333 |
-
/**
|
334 |
-
* Build entire collection of items
|
335 |
-
* Prints output
|
336 |
-
*/
|
337 |
-
function build($build_vars = array()) {
|
338 |
-
// Parse vars
|
339 |
-
$this->parse_build_vars($build_vars);
|
340 |
-
$this->util->do_action_ref_array('build_init', array($this));
|
341 |
-
// Pre-build output
|
342 |
-
$this->util->do_action_ref_array('build_pre', array($this));
|
343 |
-
// Build groups
|
344 |
-
$this->build_groups();
|
345 |
-
// Post-build output
|
346 |
-
$this->util->do_action_ref_array('build_post', array($this));
|
347 |
-
}
|
348 |
-
|
349 |
-
/**
|
350 |
-
* Parses build variables prior to use
|
351 |
-
* @uses this->reset_build_vars() to reset build variables for each request
|
352 |
-
* @param array $build_vars Variables to use for current request
|
353 |
-
*/
|
354 |
-
function parse_build_vars($build_vars = array()) {
|
355 |
-
$this->reset_build_vars();
|
356 |
-
$this->build_vars = $this->util->apply_filters('parse_build_vars', wp_parse_args($build_vars, $this->build_vars), $this);
|
357 |
-
}
|
358 |
-
|
359 |
-
/**
|
360 |
-
* Reset build variables to defaults
|
361 |
-
* Default Variables
|
362 |
-
* > groups
|
363 |
-
* > context
|
364 |
-
* > layout
|
365 |
-
*/
|
366 |
-
function reset_build_vars() {
|
367 |
-
$this->build_vars = wp_parse_args($this->build_vars, $this->build_vars_default);
|
368 |
-
}
|
369 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Managed collection
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @subpackage Base
|
7 |
+
* @author Archetyped
|
8 |
+
*/
|
9 |
+
class SLB_Base_Collection extends SLB_Base {
|
10 |
+
/* Configuration */
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Set object mode
|
14 |
+
* @var string
|
15 |
+
*/
|
16 |
+
protected $mode = 'object';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Item type
|
20 |
+
* @var string
|
21 |
+
*/
|
22 |
+
protected $item_type = null;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Property to use for item key
|
26 |
+
* Example: A property or method of the item
|
27 |
+
* @var string
|
28 |
+
*/
|
29 |
+
protected $key_prop = null;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Should $key_prop be called or retrieved?
|
33 |
+
* Default: Retrieved (FALSE)
|
34 |
+
* @var bool
|
35 |
+
*/
|
36 |
+
protected $key_call = false;
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Items in collection unique?
|
40 |
+
* Default: FALSE
|
41 |
+
* @var bool
|
42 |
+
*/
|
43 |
+
protected $unique = false;
|
44 |
+
|
45 |
+
/* Properties */
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Indexed array of items in collection
|
49 |
+
* @var array
|
50 |
+
*/
|
51 |
+
protected $items = null;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Item metadata
|
55 |
+
* Indexed by item key
|
56 |
+
* @var array
|
57 |
+
*/
|
58 |
+
protected $items_meta = array();
|
59 |
+
|
60 |
+
/* Item Management */
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Initialize collections
|
64 |
+
* Calls `init` action if collection has a hook prefix
|
65 |
+
*/
|
66 |
+
private function init() {
|
67 |
+
// Initialize
|
68 |
+
if ( is_null( $this->items ) ) {
|
69 |
+
$this->items = array();
|
70 |
+
if ( ! empty( $this->hook_prefix ) ) {
|
71 |
+
$this->util->do_action( 'init', $this );
|
72 |
+
}
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Normalize/Validate item(s)
|
78 |
+
* TODO: If no items are specified, then collection is normalized
|
79 |
+
* Single items are wrapped in an array
|
80 |
+
* @param array|object $items Item(s) to validate
|
81 |
+
* @return array Validated items
|
82 |
+
*/
|
83 |
+
protected function normalize( $items ) {
|
84 |
+
if ( ! is_array( $items ) ) {
|
85 |
+
$items = array( $items );
|
86 |
+
}
|
87 |
+
// Validate item type
|
88 |
+
if ( ! is_null( $this->item_type ) ) {
|
89 |
+
foreach ( $items as $idx => $item ) {
|
90 |
+
// Remove invalid items
|
91 |
+
if ( ! ( $item instanceof $this->item_type ) ) {
|
92 |
+
unset( $items[ $idx ] );
|
93 |
+
}
|
94 |
+
}
|
95 |
+
}
|
96 |
+
if ( ! empty( $items ) ) {
|
97 |
+
$items = array_values( $items );
|
98 |
+
}
|
99 |
+
return $items;
|
100 |
+
}
|
101 |
+
|
102 |
+
protected function item_valid( $item ) {
|
103 |
+
// Validate item type
|
104 |
+
return ( empty( $this->item_type ) || ( $item instanceof $this->item_type ) ) ? true : false;
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Validate item key
|
109 |
+
* Checks collection for existence of key as well
|
110 |
+
* @param string|int $key Key to check collection for
|
111 |
+
* @return bool TRUE if key is valid
|
112 |
+
*/
|
113 |
+
protected function key_valid( $key ) {
|
114 |
+
$this->init();
|
115 |
+
return ( ( ( is_string( $key ) && ! empty( $key ) ) || is_int( $key ) ) && isset( $this->items[ $key ] ) ) ? true : false;
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Generate key for item (for storing in collection, etc.)
|
120 |
+
* @param mixed $item Item to generate key for
|
121 |
+
* @return string|null Item key (NULL if no key generated)
|
122 |
+
*/
|
123 |
+
protected function get_key( $item, $check_existing = false ) {
|
124 |
+
$ret = null;
|
125 |
+
if ( $this->unique || ! ! $check_existing ) {
|
126 |
+
// Check for item in collection
|
127 |
+
if ( $this->has( $item ) ) {
|
128 |
+
$ret = array_search( $item, $this->items, true );
|
129 |
+
} elseif ( ! ! $this->key_prop && ( is_object( $item ) || is_array( $item ) ) ) {
|
130 |
+
if ( ! ! $this->key_call ) {
|
131 |
+
$cb = $this->util->m( $item, $this->key_prop );
|
132 |
+
if ( is_callable( $cb ) ) {
|
133 |
+
$ret = call_user_func( $cb );
|
134 |
+
}
|
135 |
+
} elseif ( is_array( $item ) && isset( $item[ $this->key_prop ] ) ) {
|
136 |
+
$ret = $item[ $this->key_prop ];
|
137 |
+
} elseif ( is_object( $item ) && isset( $item->{$this->key_prop} ) ) {
|
138 |
+
$ret = $item->{$this->key_prop};
|
139 |
+
}
|
140 |
+
}
|
141 |
+
}
|
142 |
+
return $ret;
|
143 |
+
}
|
144 |
+
|
145 |
+
/**
|
146 |
+
* Add item to collection
|
147 |
+
* @param mixed $item Item to add to collection
|
148 |
+
* @param array $meta (optional) Item metadata
|
149 |
+
* @return Current instance
|
150 |
+
*/
|
151 |
+
public function add( $item, $meta = null ) {
|
152 |
+
$this->init();
|
153 |
+
// Validate
|
154 |
+
if ( $this->item_valid( $item ) ) {
|
155 |
+
// Add item to collection
|
156 |
+
$key = $this->get_key( $item );
|
157 |
+
if ( ! $key ) {
|
158 |
+
$this->items[] = $item;
|
159 |
+
$key = key( $this->items );
|
160 |
+
} else {
|
161 |
+
$this->items[ $key ] = $item;
|
162 |
+
}
|
163 |
+
// Add metadata
|
164 |
+
if ( ! ! $key && is_array( $meta ) ) {
|
165 |
+
$this->add_meta( $key, $meta );
|
166 |
+
}
|
167 |
+
}
|
168 |
+
return $this;
|
169 |
+
}
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Remove item from collection
|
173 |
+
* @param int|string $item Key of item to remove
|
174 |
+
* @return Current instance
|
175 |
+
*/
|
176 |
+
public function remove( $item ) {
|
177 |
+
if ( $this->key_valid( $item ) ) {
|
178 |
+
unset( $this->items[ $item ] );
|
179 |
+
}
|
180 |
+
return $this;
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* Clear collection
|
185 |
+
* @return Current instance
|
186 |
+
*/
|
187 |
+
public function clear() {
|
188 |
+
$this->items = array();
|
189 |
+
return $this;
|
190 |
+
}
|
191 |
+
|
192 |
+
/**
|
193 |
+
* Checks if item exists in the collection
|
194 |
+
* @param mixed $item Item(s) to check for
|
195 |
+
* @return bool TRUE if item(s) in collection
|
196 |
+
*/
|
197 |
+
public function has( $items ) {
|
198 |
+
// Attempt to locate item
|
199 |
+
return false;
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Retrieve item(s) from collection
|
204 |
+
* If no items specified, entire collection returned
|
205 |
+
* @param array $args (optional) Query arguments
|
206 |
+
* @return object|array Specified item(s)
|
207 |
+
*/
|
208 |
+
public function get( $args = null ) {
|
209 |
+
$this->init();
|
210 |
+
// Parse args
|
211 |
+
$args_default = array(
|
212 |
+
'orderby' => null,
|
213 |
+
'order' => 'DESC',
|
214 |
+
'include' => array(),
|
215 |
+
'exclude' => array(),
|
216 |
+
);
|
217 |
+
$r = wp_parse_args( $args, $args_default );
|
218 |
+
|
219 |
+
$items = $this->items;
|
220 |
+
|
221 |
+
/* Sort */
|
222 |
+
if ( ! is_null( $r['orderby'] ) ) {
|
223 |
+
// Validate
|
224 |
+
if ( ! is_array( $r['orderby'] ) ) {
|
225 |
+
$r['orderby'] = array( 'item' => $r['orderby'] );
|
226 |
+
}
|
227 |
+
// Prep
|
228 |
+
$metas = ( isset( $r['orderby']['meta'] ) ) ? $this->items_meta : array();
|
229 |
+
// Sort
|
230 |
+
foreach ( $r['orderby'] as $stype => $sval ) {
|
231 |
+
/* Meta sorting */
|
232 |
+
if ( 'meta' === $stype ) {
|
233 |
+
// Build sorting buckets
|
234 |
+
$buckets = array();
|
235 |
+
foreach ( $metas as $item => $meta ) {
|
236 |
+
if ( ! isset( $meta[ $sval ] ) ) {
|
237 |
+
continue;
|
238 |
+
}
|
239 |
+
// Create bucket
|
240 |
+
$idx = $meta[ $sval ];
|
241 |
+
if ( ! isset( $buckets[ $idx ] ) ) {
|
242 |
+
$buckets[ $idx ] = array();
|
243 |
+
}
|
244 |
+
// Add item to bucket
|
245 |
+
$buckets[ $idx ][] = $item;
|
246 |
+
}
|
247 |
+
// Sort buckets
|
248 |
+
ksort( $buckets, SORT_NUMERIC );
|
249 |
+
// Merge buckets
|
250 |
+
$pool = array();
|
251 |
+
foreach ( $buckets as $bucket ) {
|
252 |
+
$pool = array_merge( $pool, $bucket );
|
253 |
+
}
|
254 |
+
// Fill with items
|
255 |
+
$items = array_merge( array_fill_keys( $pool, null ), $items );
|
256 |
+
}
|
257 |
+
}
|
258 |
+
// Clear workers
|
259 |
+
unset( $stype, $sval, $buckets, $pool, $item, $metas, $meta, $idx );
|
260 |
+
}
|
261 |
+
return $items;
|
262 |
+
}
|
263 |
+
|
264 |
+
/* Metadata */
|
265 |
+
|
266 |
+
/**
|
267 |
+
* Add metadata for item
|
268 |
+
* @param string|int $item Item key
|
269 |
+
* @param string|array $meta_key Meta key to set (or array of metadata)
|
270 |
+
* @param mixed $meta_value (optional) Metadata value (if key set)
|
271 |
+
* @param bool $reset (optional) Whether to remove existing metadata first (Default: FALSE)
|
272 |
+
* @return object Current instance
|
273 |
+
*/
|
274 |
+
protected function add_meta( $item, $meta_key, $meta_value = null, $reset = false ) {
|
275 |
+
// Validate
|
276 |
+
if ( $this->key_valid( $item ) && ( is_array( $meta_key ) || is_string( $meta_key ) ) ) {
|
277 |
+
// Prepare metadata
|
278 |
+
$meta = ( is_string( $meta_key ) ) ? array( $meta_key => $meta_value ) : $meta_key;
|
279 |
+
// Reset existing meta (if necessary)
|
280 |
+
if ( is_array( $meta_key ) && func_num_args() > 2 ) {
|
281 |
+
$reset = func_get_arg( 2 );
|
282 |
+
}
|
283 |
+
if ( ! ! $reset ) {
|
284 |
+
unset( $this->items_meta[ $item ] );
|
285 |
+
}
|
286 |
+
// Add metadata
|
287 |
+
if ( ! isset( $this->items_meta[ $item ] ) ) {
|
288 |
+
$this->items_meta[ $item ] = array();
|
289 |
+
}
|
290 |
+
$this->items_meta[ $item ] = array_merge( $this->items_meta[ $item ], $meta );
|
291 |
+
}
|
292 |
+
return $this;
|
293 |
+
}
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Remove item metadata
|
297 |
+
* @param string $item Item key
|
298 |
+
* @return object Current instance
|
299 |
+
*/
|
300 |
+
protected function remove_meta( $item, $meta_key = null ) {
|
301 |
+
if ( $this->key_valid( $item ) && isset( $this->items_meta[ $item ] ) ) {
|
302 |
+
if ( is_string( $meta_key ) ) {
|
303 |
+
// Remove specific meta value
|
304 |
+
unset( $this->items_meta[ $item ][ $meta_key ] );
|
305 |
+
} else {
|
306 |
+
// Remove all metadata
|
307 |
+
unset( $this->items_meta[ $item ] );
|
308 |
+
}
|
309 |
+
}
|
310 |
+
return $this;
|
311 |
+
}
|
312 |
+
|
313 |
+
/**
|
314 |
+
* Retrieve metadata
|
315 |
+
* @param string $item Item key
|
316 |
+
* @param string $meta_key (optional) Meta key (All metadata retrieved if no key specified)
|
317 |
+
* @return mixed|null Metadata value
|
318 |
+
*/
|
319 |
+
protected function get_meta( $item, $meta_key = null ) {
|
320 |
+
$ret = null;
|
321 |
+
if ( $this->key_valid( $item ) && isset( $this->items_meta[ $item ] ) ) {
|
322 |
+
if ( is_null( $meta_key ) ) {
|
323 |
+
$ret = $this->items_meta[ $item ];
|
324 |
+
} elseif ( is_string( $meta_key ) && isset( $this->items_meta[ $item ][ $meta_key ] ) ) {
|
325 |
+
$ret = $this->items_meta[ $item ][ $meta_key ];
|
326 |
+
}
|
327 |
+
}
|
328 |
+
return $ret;
|
329 |
+
}
|
330 |
+
|
331 |
+
/* Collection */
|
332 |
+
|
333 |
+
/**
|
334 |
+
* Build entire collection of items
|
335 |
+
* Prints output
|
336 |
+
*/
|
337 |
+
function build( $build_vars = array() ) {
|
338 |
+
// Parse vars
|
339 |
+
$this->parse_build_vars( $build_vars );
|
340 |
+
$this->util->do_action_ref_array( 'build_init', array( $this ) );
|
341 |
+
// Pre-build output
|
342 |
+
$this->util->do_action_ref_array( 'build_pre', array( $this ) );
|
343 |
+
// Build groups
|
344 |
+
$this->build_groups();
|
345 |
+
// Post-build output
|
346 |
+
$this->util->do_action_ref_array( 'build_post', array( $this ) );
|
347 |
+
}
|
348 |
+
|
349 |
+
/**
|
350 |
+
* Parses build variables prior to use
|
351 |
+
* @uses this->reset_build_vars() to reset build variables for each request
|
352 |
+
* @param array $build_vars Variables to use for current request
|
353 |
+
*/
|
354 |
+
function parse_build_vars( $build_vars = array() ) {
|
355 |
+
$this->reset_build_vars();
|
356 |
+
$this->build_vars = $this->util->apply_filters( 'parse_build_vars', wp_parse_args( $build_vars, $this->build_vars ), $this );
|
357 |
+
}
|
358 |
+
|
359 |
+
/**
|
360 |
+
* Reset build variables to defaults
|
361 |
+
* Default Variables
|
362 |
+
* > groups - array - Names of groups to build
|
363 |
+
* > context - string - Context of current request
|
364 |
+
* > layout - string - Name of default layout to use
|
365 |
+
*/
|
366 |
+
function reset_build_vars() {
|
367 |
+
$this->build_vars = wp_parse_args( $this->build_vars, $this->build_vars_default );
|
368 |
+
}
|
369 |
+
}
|
includes/class.base_object.php
CHANGED
@@ -1,337 +1,343 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Base Object
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Base
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Base_Object extends SLB_Base {
|
10 |
-
/* Configuration */
|
11 |
-
|
12 |
-
/**
|
13 |
-
* @var string
|
14 |
-
* @see Base::$mode
|
15 |
-
*/
|
16 |
-
protected $mode = 'object';
|
17 |
-
|
18 |
-
/*-** Properties **-*/
|
19 |
-
|
20 |
-
/**
|
21 |
-
* Unique ID
|
22 |
-
* @var string
|
23 |
-
*/
|
24 |
-
protected $id = '';
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Parent object
|
28 |
-
* @var Base_Object
|
29 |
-
*/
|
30 |
-
protected $parent = null;
|
31 |
-
|
32 |
-
/**
|
33 |
-
* Attached files
|
34 |
-
* @var array
|
35 |
-
* > scripts
|
36 |
-
* > styles
|
37 |
-
*/
|
38 |
-
protected $files = array(
|
39 |
-
'scripts'
|
40 |
-
'styles'
|
41 |
-
);
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Properties that can be inherited from parent
|
45 |
-
* @var array
|
46 |
-
*/
|
47 |
-
protected $parent_props = array();
|
48 |
-
|
49 |
-
/*-** Methods **-*/
|
50 |
-
|
51 |
-
/**
|
52 |
-
* Constructor
|
53 |
-
* @param string $id Unique ID for content type
|
54 |
-
* @param array $props (optional) Type properties (optional because props can be set post-init)
|
55 |
-
*/
|
56 |
-
public function __construct($id, $props = null) {
|
57 |
-
parent::__construct();
|
58 |
-
$this
|
59 |
-
->set_id($id)
|
60 |
-
->set_props($props);
|
61 |
-
}
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Checks if object is valid
|
65 |
-
* To be overriden by child classes
|
66 |
-
*/
|
67 |
-
public function is_valid() {
|
68 |
-
return true;
|
69 |
-
}
|
70 |
-
|
71 |
-
/*-** Getters/Setters **-*/
|
72 |
-
|
73 |
-
/**
|
74 |
-
* Get ID
|
75 |
-
* @return string ID
|
76 |
-
*/
|
77 |
-
public function get_id() {
|
78 |
-
return $this->id;
|
79 |
-
}
|
80 |
-
|
81 |
-
/**
|
82 |
-
* Set ID
|
83 |
-
* @param string $id ID
|
84 |
-
* @return object Current instance
|
85 |
-
*/
|
86 |
-
public function set_id($id) {
|
87 |
-
$id = ( is_string($id) ) ? trim($id) : '';
|
88 |
-
if ( !empty($id) ) {
|
89 |
-
$this->id = $id;
|
90 |
-
}
|
91 |
-
return $this;
|
92 |
-
}
|
93 |
-
|
94 |
-
/**
|
95 |
-
* Set type properties
|
96 |
-
* @param array $props Type properties to set
|
97 |
-
*/
|
98 |
-
protected function set_props($props) {
|
99 |
-
if ( is_array($props) && !empty($props) ) {
|
100 |
-
foreach ( $props as $key => $val ) {
|
101 |
-
// Check for setter method
|
102 |
-
$m = 'set_' . $key;
|
103 |
-
if ( method_exists($this, $m) ) {
|
104 |
-
$this->{$m}($val);
|
105 |
-
}
|
106 |
-
}
|
107 |
-
}
|
108 |
-
return $this;
|
109 |
-
}
|
110 |
-
|
111 |
-
/**
|
112 |
-
* Get parent
|
113 |
-
* @return object|null Parent
|
114 |
-
*/
|
115 |
-
public function get_parent() {
|
116 |
-
return $this->parent;
|
117 |
-
}
|
118 |
-
|
119 |
-
/**
|
120 |
-
* Set parent
|
121 |
-
* @param object $parent Parent object
|
122 |
-
* @return object Current instance
|
123 |
-
*/
|
124 |
-
public function set_parent($parent) {
|
125 |
-
$this->parent = ( $parent instanceof $this ) ? $parent : null;
|
126 |
-
return $this;
|
127 |
-
}
|
128 |
-
|
129 |
-
/**
|
130 |
-
* Check if parent is set
|
131 |
-
* @return bool TRUE if parent is set
|
132 |
-
*/
|
133 |
-
public function has_parent() {
|
134 |
-
return ( is_null($this->parent) ) ? false : true;
|
135 |
-
}
|
136 |
-
|
137 |
-
/**
|
138 |
-
* Retrieve all ancestors
|
139 |
-
* @return array Ancestors
|
140 |
-
*/
|
141 |
-
public function get_ancestors() {
|
142 |
-
$ret
|
143 |
-
$curr = $this;
|
144 |
-
while ( $curr->has_parent() ) {
|
145 |
-
//
|
146 |
-
$
|
147 |
-
//
|
148 |
-
$
|
149 |
-
}
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
*
|
158 |
-
* @param string $
|
159 |
-
* @param string $
|
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 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
$ret
|
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 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Base Object
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @subpackage Base
|
7 |
+
* @author Archetyped
|
8 |
+
*/
|
9 |
+
class SLB_Base_Object extends SLB_Base {
|
10 |
+
/* Configuration */
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var string
|
14 |
+
* @see Base::$mode
|
15 |
+
*/
|
16 |
+
protected $mode = 'object';
|
17 |
+
|
18 |
+
/*-** Properties **-*/
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Unique ID
|
22 |
+
* @var string
|
23 |
+
*/
|
24 |
+
protected $id = '';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Parent object
|
28 |
+
* @var Base_Object
|
29 |
+
*/
|
30 |
+
protected $parent = null;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Attached files
|
34 |
+
* @var array
|
35 |
+
* > scripts array JS scripts
|
36 |
+
* > styles array Stylesheets
|
37 |
+
*/
|
38 |
+
protected $files = array(
|
39 |
+
'scripts' => array(),
|
40 |
+
'styles' => array(),
|
41 |
+
);
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Properties that can be inherited from parent
|
45 |
+
* @var array
|
46 |
+
*/
|
47 |
+
protected $parent_props = array();
|
48 |
+
|
49 |
+
/*-** Methods **-*/
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Constructor
|
53 |
+
* @param string $id Unique ID for content type
|
54 |
+
* @param array $props (optional) Type properties (optional because props can be set post-init)
|
55 |
+
*/
|
56 |
+
public function __construct( $id, $props = null ) {
|
57 |
+
parent::__construct();
|
58 |
+
$this
|
59 |
+
->set_id( $id )
|
60 |
+
->set_props( $props );
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Checks if object is valid
|
65 |
+
* To be overriden by child classes
|
66 |
+
*/
|
67 |
+
public function is_valid() {
|
68 |
+
return true;
|
69 |
+
}
|
70 |
+
|
71 |
+
/*-** Getters/Setters **-*/
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Get ID
|
75 |
+
* @return string ID
|
76 |
+
*/
|
77 |
+
public function get_id() {
|
78 |
+
return $this->id;
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Set ID
|
83 |
+
* @param string $id ID
|
84 |
+
* @return object Current instance
|
85 |
+
*/
|
86 |
+
public function set_id( $id ) {
|
87 |
+
$id = ( is_string( $id ) ) ? trim( $id ) : '';
|
88 |
+
if ( ! empty( $id ) ) {
|
89 |
+
$this->id = $id;
|
90 |
+
}
|
91 |
+
return $this;
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Set type properties
|
96 |
+
* @param array $props Type properties to set
|
97 |
+
*/
|
98 |
+
protected function set_props( $props ) {
|
99 |
+
if ( is_array( $props ) && ! empty( $props ) ) {
|
100 |
+
foreach ( $props as $key => $val ) {
|
101 |
+
// Check for setter method
|
102 |
+
$m = 'set_' . $key;
|
103 |
+
if ( method_exists( $this, $m ) ) {
|
104 |
+
$this->{$m}( $val );
|
105 |
+
}
|
106 |
+
}
|
107 |
+
}
|
108 |
+
return $this;
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Get parent
|
113 |
+
* @return object|null Parent
|
114 |
+
*/
|
115 |
+
public function get_parent() {
|
116 |
+
return $this->parent;
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Set parent
|
121 |
+
* @param object $parent Parent object
|
122 |
+
* @return object Current instance
|
123 |
+
*/
|
124 |
+
public function set_parent( $parent ) {
|
125 |
+
$this->parent = ( $parent instanceof $this ) ? $parent : null;
|
126 |
+
return $this;
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Check if parent is set
|
131 |
+
* @return bool TRUE if parent is set
|
132 |
+
*/
|
133 |
+
public function has_parent() {
|
134 |
+
return ( is_null( $this->parent ) ) ? false : true;
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Retrieve all ancestors
|
139 |
+
* @return array Ancestors
|
140 |
+
*/
|
141 |
+
public function get_ancestors() {
|
142 |
+
$ret = array();
|
143 |
+
$curr = $this;
|
144 |
+
while ( $curr->has_parent() ) {
|
145 |
+
// Get next ancestor.
|
146 |
+
$curr = $curr->get_parent();
|
147 |
+
// Add ancestor.
|
148 |
+
$ret[] = $curr;
|
149 |
+
}
|
150 |
+
|
151 |
+
return $ret;
|
152 |
+
}
|
153 |
+
|
154 |
+
/* Files */
|
155 |
+
|
156 |
+
/**
|
157 |
+
* Add file
|
158 |
+
* @param string $type Group to add file to
|
159 |
+
* @param string $handle Name for resource
|
160 |
+
* @param string $src File URI
|
161 |
+
* @return object Current instance
|
162 |
+
*/
|
163 |
+
protected function add_file( $type, $handle, $src, $deps = array() ) {
|
164 |
+
if ( is_string( $type ) && is_string( $handle ) && is_string( $src ) ) {
|
165 |
+
// Validate dependencies
|
166 |
+
if ( ! is_array( $deps ) ) {
|
167 |
+
$deps = array();
|
168 |
+
}
|
169 |
+
// Init file group
|
170 |
+
if ( ! isset( $this->files[ $type ] ) || ! is_array( $this->files[ $type ] ) ) {
|
171 |
+
$this->files[ $type ] = array();
|
172 |
+
}
|
173 |
+
// Add file to group
|
174 |
+
$this->files[ $type ][ $handle ] = array(
|
175 |
+
'handle' => $handle,
|
176 |
+
'uri' => $src,
|
177 |
+
'deps' => $deps,
|
178 |
+
);
|
179 |
+
}
|
180 |
+
return $this;
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* Add multiple files
|
185 |
+
* @param string $type Group to add files to
|
186 |
+
* @param array $files Files to add
|
187 |
+
* @see add_file() for file parameters
|
188 |
+
* @return object Current instance
|
189 |
+
*/
|
190 |
+
protected function add_files( $type, $files ) {
|
191 |
+
if ( ! is_array( $files ) || empty( $files ) ) {
|
192 |
+
return false;
|
193 |
+
}
|
194 |
+
$m = $this->m( 'add_file' );
|
195 |
+
foreach ( $files as $file ) {
|
196 |
+
if ( ! is_array( $file ) || empty( $file ) ) {
|
197 |
+
continue;
|
198 |
+
}
|
199 |
+
array_unshift( $file, $type );
|
200 |
+
call_user_func_array( $m, $file );
|
201 |
+
}
|
202 |
+
return $this;
|
203 |
+
}
|
204 |
+
|
205 |
+
/**
|
206 |
+
* Retrieve files
|
207 |
+
* All files or a specific group of files can be retrieved
|
208 |
+
* @param string $type (optional) File group to retrieve
|
209 |
+
* @return array Files
|
210 |
+
*/
|
211 |
+
protected function get_files( $type = null ) {
|
212 |
+
$ret = $this->files;
|
213 |
+
if ( is_string( $type ) ) {
|
214 |
+
$ret = ( isset( $ret[ $type ] ) ) ? $ret[ $type ] : array();
|
215 |
+
}
|
216 |
+
if ( ! is_array( $ret ) ) {
|
217 |
+
$ret = array();
|
218 |
+
}
|
219 |
+
return $ret;
|
220 |
+
}
|
221 |
+
|
222 |
+
/**
|
223 |
+
* Retrieve file
|
224 |
+
* @param string $type Group to retrieve file from
|
225 |
+
* @param string $handle
|
226 |
+
* @param string $format (optional) Format of return value (Default: array)
|
227 |
+
* @return array|null File properties (Default: NULL)
|
228 |
+
*/
|
229 |
+
protected function get_file( $type, $handle, $format = null ) {
|
230 |
+
// Get files
|
231 |
+
$files = $this->get_files( $type );
|
232 |
+
// Get specified file
|
233 |
+
$ret = ( is_string( $type ) && isset( $files[ $handle ] ) ) ? $files[ $handle ] : null;
|
234 |
+
// Format return value
|
235 |
+
if ( ! empty( $ret ) && ! ! $format ) {
|
236 |
+
switch ( $format ) {
|
237 |
+
case 'uri':
|
238 |
+
$ret = $ret['uri'];
|
239 |
+
// Normalize URI
|
240 |
+
if ( ! $this->util->is_uri( $ret ) ) {
|
241 |
+
$ret = $this->util->normalize_path( site_url(), $ret );
|
242 |
+
}
|
243 |
+
break;
|
244 |
+
case 'path':
|
245 |
+
$ret = $ret['uri'];
|
246 |
+
// Normalize path
|
247 |
+
if ( ! $this->util->is_uri( $ret ) ) {
|
248 |
+
$ret = $this->util->get_relative_path( $ret );
|
249 |
+
$ret = $this->util->normalize_path( ABSPATH, $ret );
|
250 |
+
}
|
251 |
+
break;
|
252 |
+
case 'object':
|
253 |
+
$ret = (object) $ret;
|
254 |
+
break;
|
255 |
+
case 'contents':
|
256 |
+
$ret = $ret['uri'];
|
257 |
+
if ( ! $this->util->is_uri( $ret ) ) {
|
258 |
+
$ret = $this->util->normalize_path( site_url(), $ret );
|
259 |
+
}
|
260 |
+
$get = wp_safe_remote_get( $ret );
|
261 |
+
$ret = ( ! is_wp_error( $get ) && 200 === $get['response']['code'] ) ? $get['body'] : '';
|
262 |
+
break;
|
263 |
+
}
|
264 |
+
}
|
265 |
+
return $ret;
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* Add stylesheet
|
270 |
+
* @param string $handle Name of the stylesheet
|
271 |
+
* @param string $src Stylesheet URI
|
272 |
+
* @return object Current instance
|
273 |
+
*/
|
274 |
+
public function add_style( $handle, $src, $deps = array() ) {
|
275 |
+
return $this->add_file( 'styles', $handle, $src, $deps );
|
276 |
+
}
|
277 |
+
|
278 |
+
/**
|
279 |
+
* Retrieve stylesheet files
|
280 |
+
* @return array Stylesheet files
|
281 |
+
*/
|
282 |
+
public function get_styles( $opts = null ) {
|
283 |
+
$files = $this->get_files( 'styles' );
|
284 |
+
if ( is_array( $opts ) ) {
|
285 |
+
$opts = (object) $opts;
|
286 |
+
}
|
287 |
+
if ( is_object( $opts ) && ! empty( $opts ) ) {
|
288 |
+
// Parse options
|
289 |
+
// URI Format
|
290 |
+
if ( isset( $opts->uri_format ) ) {
|
291 |
+
foreach ( $files as $hdl => $props ) {
|
292 |
+
switch ( $opts->uri_format ) {
|
293 |
+
case 'full':
|
294 |
+
if ( ! $this->util->is_uri( $props['uri'] ) ) {
|
295 |
+
$files[ $hdl ]['uri'] = $this->util->normalize_path( site_url(), $props['uri'] );
|
296 |
+
}
|
297 |
+
break;
|
298 |
+
}
|
299 |
+
}
|
300 |
+
}
|
301 |
+
}
|
302 |
+
return $files;
|
303 |
+
}
|
304 |
+
|
305 |
+
/**
|
306 |
+
* Retrieve stylesheet file
|
307 |
+
* @param string $handle Name of stylesheet
|
308 |
+
* @param string $format (optional) Format of return value (@see `get_file()`)
|
309 |
+
* @return array|null File properties (Default: NULL)
|
310 |
+
*/
|
311 |
+
public function get_style( $handle, $format = null ) {
|
312 |
+
return $this->get_file( 'styles', $handle, $format );
|
313 |
+
}
|
314 |
+
|
315 |
+
/**
|
316 |
+
* Add script
|
317 |
+
* @param string $handle Name of the script
|
318 |
+
* @param string $src Script URI
|
319 |
+
* @return object Current instance
|
320 |
+
*/
|
321 |
+
public function add_script( $handle, $src, $deps = array() ) {
|
322 |
+
return $this->add_file( 'scripts', $handle, $src, $deps );
|
323 |
+
}
|
324 |
+
|
325 |
+
/**
|
326 |
+
* Retrieve script files
|
327 |
+
* @return array Script files
|
328 |
+
*/
|
329 |
+
public function get_scripts() {
|
330 |
+
return $this->get_files( 'scripts' );
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
* Retrieve script file
|
335 |
+
* @param string $handle Name of script
|
336 |
+
* @param string $format (optional) Format of return value (@see `get_file()`)
|
337 |
+
* @return array|null File properties (Default: NULL)
|
338 |
+
*/
|
339 |
+
public function get_script( $handle, $format = null ) {
|
340 |
+
return $this->get_file( 'scripts', $handle, $format );
|
341 |
+
}
|
342 |
+
|
343 |
+
}
|
includes/class.collection_controller.php
CHANGED
@@ -1,57 +1,57 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Collection Controller
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Collection
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Collection_Controller extends SLB_Base_Collection {
|
10 |
-
/* Configuration */
|
11 |
-
|
12 |
-
protected $mode = 'full';
|
13 |
-
|
14 |
-
protected $unique = true;
|
15 |
-
|
16 |
-
/* Properties */
|
17 |
-
|
18 |
-
protected $parent = null;
|
19 |
-
|
20 |
-
/* Methods */
|
21 |
-
|
22 |
-
public function __construct($parent = null) {
|
23 |
-
$this->set_parent($parent);
|
24 |
-
parent::__construct();
|
25 |
-
}
|
26 |
-
|
27 |
-
/* Initialization */
|
28 |
-
|
29 |
-
/* Parent */
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Set parent instance
|
33 |
-
* @param SLB_Base $parent (optional) Parent instance
|
34 |
-
* @return obj Current instance
|
35 |
-
*/
|
36 |
-
protected function set_parent($parent = null) {
|
37 |
-
$this->parent = ( $parent instanceof SLB_Base ) ? $parent : null;
|
38 |
-
return $this;
|
39 |
-
}
|
40 |
-
|
41 |
-
/**
|
42 |
-
* Check if parent set
|
43 |
-
* @return bool TRUE if parent set
|
44 |
-
*/
|
45 |
-
protected function has_parent() {
|
46 |
-
return ( is_object($this->get_parent()) ) ? true : false;
|
47 |
-
}
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Retrieve parent
|
51 |
-
* @uses $parent
|
52 |
-
* @return null|obj Parent instance (NULL if no parent set)
|
53 |
-
*/
|
54 |
-
protected function get_parent() {
|
55 |
-
return $this->parent;
|
56 |
-
}
|
57 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Collection Controller
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @subpackage Collection
|
7 |
+
* @author Archetyped
|
8 |
+
*/
|
9 |
+
class SLB_Collection_Controller extends SLB_Base_Collection {
|
10 |
+
/* Configuration */
|
11 |
+
|
12 |
+
protected $mode = 'full';
|
13 |
+
|
14 |
+
protected $unique = true;
|
15 |
+
|
16 |
+
/* Properties */
|
17 |
+
|
18 |
+
protected $parent = null;
|
19 |
+
|
20 |
+
/* Methods */
|
21 |
+
|
22 |
+
public function __construct( $parent = null ) {
|
23 |
+
$this->set_parent( $parent );
|
24 |
+
parent::__construct();
|
25 |
+
}
|
26 |
+
|
27 |
+
/* Initialization */
|
28 |
+
|
29 |
+
/* Parent */
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Set parent instance
|
33 |
+
* @param SLB_Base $parent (optional) Parent instance
|
34 |
+
* @return obj Current instance
|
35 |
+
*/
|
36 |
+
protected function set_parent( $parent = null ) {
|
37 |
+
$this->parent = ( $parent instanceof SLB_Base ) ? $parent : null;
|
38 |
+
return $this;
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Check if parent set
|
43 |
+
* @return bool TRUE if parent set
|
44 |
+
*/
|
45 |
+
protected function has_parent() {
|
46 |
+
return ( is_object( $this->get_parent() ) ) ? true : false;
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Retrieve parent
|
51 |
+
* @uses $parent
|
52 |
+
* @return null|obj Parent instance (NULL if no parent set)
|
53 |
+
*/
|
54 |
+
protected function get_parent() {
|
55 |
+
return $this->parent;
|
56 |
+
}
|
57 |
+
}
|
includes/class.component.php
CHANGED
@@ -1,135 +1,135 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Component
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Base
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Component extends SLB_Base_Object {
|
10 |
-
/* Properties */
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Pretty name
|
14 |
-
* @var string
|
15 |
-
*/
|
16 |
-
protected $name = '';
|
17 |
-
|
18 |
-
protected $props_required = array();
|
19 |
-
|
20 |
-
private $props_required_base = array('id');
|
21 |
-
|
22 |
-
/* Get/Set */
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Set name
|
26 |
-
* @param string $name Name
|
27 |
-
* @return Current instance
|
28 |
-
*/
|
29 |
-
public function set_name($name) {
|
30 |
-
if ( is_string($name) ) {
|
31 |
-
$name = trim($name);
|
32 |
-
if ( !empty($name) ) {
|
33 |
-
$this->name = $name;
|
34 |
-
}
|
35 |
-
}
|
36 |
-
return $this;
|
37 |
-
}
|
38 |
-
|
39 |
-
public function get_name() {
|
40 |
-
return $this->name;
|
41 |
-
}
|
42 |
-
|
43 |
-
public function set_scripts($scripts) {
|
44 |
-
$this->add_files('scripts', $scripts);
|
45 |
-
}
|
46 |
-
|
47 |
-
public function set_styles($styles) {
|
48 |
-
$this->add_files('styles', $styles);
|
49 |
-
}
|
50 |
-
|
51 |
-
/* Assets */
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Get formatted handle for file
|
55 |
-
* @param string $base_handle Base handle to format
|
56 |
-
* @return string Formatted handle
|
57 |
-
*/
|
58 |
-
public function get_handle($base_handle) {
|
59 |
-
return $this->add_prefix( array('asset', $this->get_id(), $base_handle), '-');
|
60 |
-
}
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Enqueue files in client
|
64 |
-
* @param string $type (optional) Type of file to load (singular) (Default: All client file types)
|
65 |
-
*/
|
66 |
-
public function enqueue_client_files($type = null) {
|
67 |
-
if ( empty($type) ) {
|
68 |
-
$type = array
|
69 |
-
}
|
70 |
-
if ( !is_array($type) ) {
|
71 |
-
$type = array
|
72 |
-
}
|
73 |
-
foreach ( $type as $t ) {
|
74 |
-
$m
|
75 |
-
'get'
|
76 |
-
'enqueue'
|
77 |
-
);
|
78 |
-
$v
|
79 |
-
$files
|
80 |
-
$param_final = ( 'script'
|
81 |
-
foreach ( $files as $f ) {
|
82 |
-
$f = (object) $f;
|
83 |
-
// Format handle
|
84 |
-
$handle = $this->get_handle($f->handle);
|
85 |
-
|
86 |
-
// Format dependencies
|
87 |
-
$deps = array();
|
88 |
-
foreach ( $f->deps as $dep ) {
|
89 |
-
if ( $this->util->has_wrapper($dep) ) {
|
90 |
-
$dep = $this->get_handle( $this->util->remove_wrapper($dep) );
|
91 |
-
}
|
92 |
-
$deps[] = $dep;
|
93 |
-
}
|
94 |
-
call_user_func($m->enqueue, $handle, $f->uri, $deps, $v, $param_final);
|
95 |
-
}
|
96 |
-
unset($files, $f, $param_final, $handle, $deps, $dep);
|
97 |
-
}
|
98 |
-
}
|
99 |
-
|
100 |
-
/**
|
101 |
-
* Enqueue scripts
|
102 |
-
*/
|
103 |
-
public function enqueue_scripts() {
|
104 |
-
$this->enqueue_client_files('script');
|
105 |
-
}
|
106 |
-
|
107 |
-
/**
|
108 |
-
* Enqueue styles
|
109 |
-
*/
|
110 |
-
public function enqueue_styles() {
|
111 |
-
$this->enqueue_client_files('style');
|
112 |
-
}
|
113 |
-
|
114 |
-
/* Helpers */
|
115 |
-
|
116 |
-
/**
|
117 |
-
* Validate instance
|
118 |
-
* @see `Base_Object::is_valid()`
|
119 |
-
* @return bool Valid (TRUE) / Invalid (FALSE)
|
120 |
-
*/
|
121 |
-
public function is_valid() {
|
122 |
-
$ret = parent::is_valid();
|
123 |
-
if ( $ret ) {
|
124 |
-
// Check required component properties
|
125 |
-
$props = array_merge($this->props_required_base, $this->props_required);
|
126 |
-
foreach ( $props as $prop ) {
|
127 |
-
if ( !isset($this->{$prop}) || empty($this->{$prop}) ) {
|
128 |
-
$ret = false;
|
129 |
-
break;
|
130 |
-
}
|
131 |
-
}
|
132 |
-
}
|
133 |
-
return $ret;
|
134 |
-
}
|
135 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Component
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @subpackage Base
|
7 |
+
* @author Archetyped
|
8 |
+
*/
|
9 |
+
class SLB_Component extends SLB_Base_Object {
|
10 |
+
/* Properties */
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Pretty name
|
14 |
+
* @var string
|
15 |
+
*/
|
16 |
+
protected $name = '';
|
17 |
+
|
18 |
+
protected $props_required = array();
|
19 |
+
|
20 |
+
private $props_required_base = array( 'id' );
|
21 |
+
|
22 |
+
/* Get/Set */
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Set name
|
26 |
+
* @param string $name Name
|
27 |
+
* @return Current instance
|
28 |
+
*/
|
29 |
+
public function set_name( $name ) {
|
30 |
+
if ( is_string( $name ) ) {
|
31 |
+
$name = trim( $name );
|
32 |
+
if ( ! empty( $name ) ) {
|
33 |
+
$this->name = $name;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
return $this;
|
37 |
+
}
|
38 |
+
|
39 |
+
public function get_name() {
|
40 |
+
return $this->name;
|
41 |
+
}
|
42 |
+
|
43 |
+
public function set_scripts( $scripts ) {
|
44 |
+
$this->add_files( 'scripts', $scripts );
|
45 |
+
}
|
46 |
+
|
47 |
+
public function set_styles( $styles ) {
|
48 |
+
$this->add_files( 'styles', $styles );
|
49 |
+
}
|
50 |
+
|
51 |
+
/* Assets */
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Get formatted handle for file
|
55 |
+
* @param string $base_handle Base handle to format
|
56 |
+
* @return string Formatted handle
|
57 |
+
*/
|
58 |
+
public function get_handle( $base_handle ) {
|
59 |
+
return $this->add_prefix( array( 'asset', $this->get_id(), $base_handle ), '-' );
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Enqueue files in client
|
64 |
+
* @param string $type (optional) Type of file to load (singular) (Default: All client file types)
|
65 |
+
*/
|
66 |
+
public function enqueue_client_files( $type = null ) {
|
67 |
+
if ( empty( $type ) ) {
|
68 |
+
$type = array( 'script', 'style' );
|
69 |
+
}
|
70 |
+
if ( ! is_array( $type ) ) {
|
71 |
+
$type = array( $type );
|
72 |
+
}
|
73 |
+
foreach ( $type as $t ) {
|
74 |
+
$m = (object) array(
|
75 |
+
'get' => $this->m( 'get_' . $t . 's' ),
|
76 |
+
'enqueue' => 'wp_enqueue_' . $t,
|
77 |
+
);
|
78 |
+
$v = $this->util->get_plugin_version();
|
79 |
+
$files = call_user_func( $m->get );
|
80 |
+
$param_final = ( 'script' === $t ) ? true : 'all';
|
81 |
+
foreach ( $files as $f ) {
|
82 |
+
$f = (object) $f;
|
83 |
+
// Format handle
|
84 |
+
$handle = $this->get_handle( $f->handle );
|
85 |
+
|
86 |
+
// Format dependencies
|
87 |
+
$deps = array();
|
88 |
+
foreach ( $f->deps as $dep ) {
|
89 |
+
if ( $this->util->has_wrapper( $dep ) ) {
|
90 |
+
$dep = $this->get_handle( $this->util->remove_wrapper( $dep ) );
|
91 |
+
}
|
92 |
+
$deps[] = $dep;
|
93 |
+
}
|
94 |
+
call_user_func( $m->enqueue, $handle, $f->uri, $deps, $v, $param_final );
|
95 |
+
}
|
96 |
+
unset( $files, $f, $param_final, $handle, $deps, $dep );
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Enqueue scripts
|
102 |
+
*/
|
103 |
+
public function enqueue_scripts() {
|
104 |
+
$this->enqueue_client_files( 'script' );
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Enqueue styles
|
109 |
+
*/
|
110 |
+
public function enqueue_styles() {
|
111 |
+
$this->enqueue_client_files( 'style' );
|
112 |
+
}
|
113 |
+
|
114 |
+
/* Helpers */
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Validate instance
|
118 |
+
* @see `Base_Object::is_valid()`
|
119 |
+
* @return bool Valid (TRUE) / Invalid (FALSE)
|
120 |
+
*/
|
121 |
+
public function is_valid() {
|
122 |
+
$ret = parent::is_valid();
|
123 |
+
if ( $ret ) {
|
124 |
+
// Check required component properties
|
125 |
+
$props = array_merge( $this->props_required_base, $this->props_required );
|
126 |
+
foreach ( $props as $prop ) {
|
127 |
+
if ( ! isset( $this->{$prop} ) || empty( $this->{$prop} ) ) {
|
128 |
+
$ret = false;
|
129 |
+
break;
|
130 |
+
}
|
131 |
+
}
|
132 |
+
}
|
133 |
+
return $ret;
|
134 |
+
}
|
135 |
+
}
|
includes/class.content_handler.php
CHANGED
@@ -1,82 +1,82 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Content Handler
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Content Handlers
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Content_Handler extends SLB_Component {
|
10 |
-
/* Properties */
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Match handler
|
14 |
-
* @var callback
|
15 |
-
*/
|
16 |
-
protected $match;
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Custom attributes
|
20 |
-
* @var callback
|
21 |
-
*/
|
22 |
-
protected $attributes;
|
23 |
-
|
24 |
-
/* Matching */
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Set matching handler
|
28 |
-
* @param callback $callback Handler callback
|
29 |
-
* @return object Current instance
|
30 |
-
*/
|
31 |
-
public function set_match($callback) {
|
32 |
-
$this->match = ( is_callable($callback) ) ? $callback : null;
|
33 |
-
return $this;
|
34 |
-
}
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Retrieve match handler
|
38 |
-
* @return callback|null Match handler
|
39 |
-
*/
|
40 |
-
protected function get_match() {
|
41 |
-
return $this->match;
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Check if valid match set
|
46 |
-
*/
|
47 |
-
protected function has_match()
|
48 |
-
return ( is_null($this->match) ) ? false : true;
|
49 |
-
}
|
50 |
-
|
51 |
-
/**
|
52 |
-
* Match handler against URI
|
53 |
-
* @param string $uri URI to check for match
|
54 |
-
* @return bool TRUE if handler matches URI
|
55 |
-
*/
|
56 |
-
public function match($uri, $uri_raw = null) {
|
57 |
-
$ret = false;
|
58 |
-
if (
|
59 |
-
$ret = call_user_func($this->get_match(), $uri, $uri_raw);
|
60 |
-
}
|
61 |
-
return $ret;
|
62 |
-
}
|
63 |
-
|
64 |
-
/* Attributes */
|
65 |
-
|
66 |
-
public function set_attributes($callback) {
|
67 |
-
$this->attributes = ( is_callable($callback) ) ? $callback : null;
|
68 |
-
return $this;
|
69 |
-
}
|
70 |
-
|
71 |
-
public function get_attributes() {
|
72 |
-
$ret = array();
|
73 |
-
// Callback
|
74 |
-
if ( !is_null($this->attributes) ) {
|
75 |
-
$ret = call_user_func($this->attributes);
|
76 |
-
}
|
77 |
-
// Filter
|
78 |
-
$hook = sprintf('content_handler_%s_attributes', $this->get_id());
|
79 |
-
$ret
|
80 |
-
return ( is_array($ret) ) ? $ret : array();
|
81 |
-
}
|
82 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Content Handler
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @subpackage Content Handlers
|
7 |
+
* @author Archetyped
|
8 |
+
*/
|
9 |
+
class SLB_Content_Handler extends SLB_Component {
|
10 |
+
/* Properties */
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Match handler
|
14 |
+
* @var callback
|
15 |
+
*/
|
16 |
+
protected $match;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Custom attributes
|
20 |
+
* @var callback
|
21 |
+
*/
|
22 |
+
protected $attributes;
|
23 |
+
|
24 |
+
/* Matching */
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Set matching handler
|
28 |
+
* @param callback $callback Handler callback
|
29 |
+
* @return object Current instance
|
30 |
+
*/
|
31 |
+
public function set_match( $callback ) {
|
32 |
+
$this->match = ( is_callable( $callback ) ) ? $callback : null;
|
33 |
+
return $this;
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Retrieve match handler
|
38 |
+
* @return callback|null Match handler
|
39 |
+
*/
|
40 |
+
protected function get_match() {
|
41 |
+
return $this->match;
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Check if valid match set
|
46 |
+
*/
|
47 |
+
protected function has_match() {
|
48 |
+
return ( is_null( $this->match ) ) ? false : true;
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Match handler against URI
|
53 |
+
* @param string $uri URI to check for match
|
54 |
+
* @return bool TRUE if handler matches URI
|
55 |
+
*/
|
56 |
+
public function match( $uri, $uri_raw = null ) {
|
57 |
+
$ret = false;
|
58 |
+
if ( ! ! $uri && is_string( $uri ) && $this->has_match() ) {
|
59 |
+
$ret = call_user_func( $this->get_match(), $uri, $uri_raw );
|
60 |
+
}
|
61 |
+
return $ret;
|
62 |
+
}
|
63 |
+
|
64 |
+
/* Attributes */
|
65 |
+
|
66 |
+
public function set_attributes( $callback ) {
|
67 |
+
$this->attributes = ( is_callable( $callback ) ) ? $callback : null;
|
68 |
+
return $this;
|
69 |
+
}
|
70 |
+
|
71 |
+
public function get_attributes() {
|
72 |
+
$ret = array();
|
73 |
+
// Callback
|
74 |
+
if ( ! is_null( $this->attributes ) ) {
|
75 |
+
$ret = call_user_func( $this->attributes );
|
76 |
+
}
|
77 |
+
// Filter
|
78 |
+
$hook = sprintf( 'content_handler_%s_attributes', $this->get_id() );
|
79 |
+
$ret = $this->util->apply_filters( $hook, $ret );
|
80 |
+
return ( is_array( $ret ) ) ? $ret : array();
|
81 |
+
}
|
82 |
+
}
|
includes/class.content_handlers.php
CHANGED
@@ -1,277 +1,280 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Content Handler Collection
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Content Handler
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Content_Handlers extends SLB_Collection_Controller {
|
10 |
-
/* Configuration */
|
11 |
-
|
12 |
-
protected $item_type = 'SLB_Content_Handler';
|
13 |
-
|
14 |
-
public $hook_prefix = 'content_handlers';
|
15 |
-
|
16 |
-
protected $key_prop = 'get_id';
|
17 |
-
|
18 |
-
protected $key_call = true;
|
19 |
-
|
20 |
-
/* Properties */
|
21 |
-
|
22 |
-
protected $request_matches = array();
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Cache properties (key, group)
|
26 |
-
* @var object
|
27 |
-
*/
|
28 |
-
protected $cache_props = null;
|
29 |
-
|
30 |
-
/* Initialization */
|
31 |
-
|
32 |
-
protected function _hooks() {
|
33 |
-
parent::_hooks();
|
34 |
-
$this->util->add_action('init', $this->m('init_defaults'), 5);
|
35 |
-
$this->util->add_action('footer', $this->m('client_output'), 1, 0, false);
|
36 |
-
$this->util->add_filter('footer_script', $this->m('client_output_script'), $this->util->priority('client_footer_output'), 1, false);
|
37 |
-
}
|
38 |
-
|
39 |
-
/* Collection Management */
|
40 |
-
|
41 |
-
/**
|
42 |
-
* Add content type handler
|
43 |
-
* Accepts properties to create new handler OR previously-initialized handler instance
|
44 |
-
* @uses clear_cache()
|
45 |
-
* @see parent::add()
|
46 |
-
* @param string $id Handler ID
|
47 |
-
* @param array $props Handler properties
|
48 |
-
* @return object Current instance
|
49 |
-
*/
|
50 |
-
public function add($id, $props = array(), $priority = 10) {
|
51 |
-
$this->clear_cache();
|
52 |
-
if ( is_string($id) ) {
|
53 |
-
// Initialize new handler
|
54 |
-
$handler = new $this->item_type($id, $props);
|
55 |
-
} else {
|
56 |
-
// Remap parameters
|
57 |
-
$handler = func_get_arg(0);
|
58 |
-
if ( func_num_args()
|
59 |
-
$priority = func_get_arg(1);
|
60 |
-
}
|
61 |
-
}
|
62 |
-
if ( !is_int($priority) ) {
|
63 |
-
$priority = 10;
|
64 |
-
}
|
65 |
-
// Add to collection
|
66 |
-
return parent::add($handler, array('priority' => $priority));
|
67 |
-
}
|
68 |
-
|
69 |
-
/**
|
70 |
-
* Remove item
|
71 |
-
* @uses clear_cache()
|
72 |
-
* @see parent::remove()
|
73 |
-
* @return object Current instance
|
74 |
-
*/
|
75 |
-
public function remove($item) {
|
76 |
-
$this->clear_cache();
|
77 |
-
return parent::remove($item);
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* Clear collection
|
82 |
-
* @uses clear_cache()
|
83 |
-
* @see parent::clear()
|
84 |
-
* @return object Current instance
|
85 |
-
*/
|
86 |
-
public function clear() {
|
87 |
-
$this->clear_cache();
|
88 |
-
return parent::clear();
|
89 |
-
}
|
90 |
-
|
91 |
-
/**
|
92 |
-
* Retrieves handlers sorted by priority
|
93 |
-
* @see parent::get()
|
94 |
-
* @uses get_cache()
|
95 |
-
* @param mixed $args Unused
|
96 |
-
* @return array Handlers
|
97 |
-
*/
|
98 |
-
public function get($args = null) {
|
99 |
-
$items = $this->get_cache();
|
100 |
-
if ( empty($items) ) {
|
101 |
-
// Retrieve items
|
102 |
-
$items = parent::get( array( 'orderby' => array('meta' => 'priority') ) );
|
103 |
-
$this->update_cache($items);
|
104 |
-
}
|
105 |
-
return $items;
|
106 |
-
}
|
107 |
-
|
108 |
-
/**
|
109 |
-
* Get matching handler for URI
|
110 |
-
* @param string $uri URI to find match for
|
111 |
-
* @return object Handler package (FALSE if no match found)
|
112 |
-
* Package members
|
113 |
-
* > handler (Content_Handler) Matching handler instance (Default: NULL)
|
114 |
-
* > props (array) Properties returned from matching handler (May be empty depending on handler)
|
115 |
-
*/
|
116 |
-
public function match($uri) {
|
117 |
-
$ret = (object) array(
|
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 |
-
$
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
),
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
//
|
218 |
-
$
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
if ( empty($
|
261 |
-
|
262 |
-
}
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
$
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
}
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Content Handler Collection
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @subpackage Content Handler
|
7 |
+
* @author Archetyped
|
8 |
+
*/
|
9 |
+
class SLB_Content_Handlers extends SLB_Collection_Controller {
|
10 |
+
/* Configuration */
|
11 |
+
|
12 |
+
protected $item_type = 'SLB_Content_Handler';
|
13 |
+
|
14 |
+
public $hook_prefix = 'content_handlers';
|
15 |
+
|
16 |
+
protected $key_prop = 'get_id';
|
17 |
+
|
18 |
+
protected $key_call = true;
|
19 |
+
|
20 |
+
/* Properties */
|
21 |
+
|
22 |
+
protected $request_matches = array();
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Cache properties (key, group)
|
26 |
+
* @var object
|
27 |
+
*/
|
28 |
+
protected $cache_props = null;
|
29 |
+
|
30 |
+
/* Initialization */
|
31 |
+
|
32 |
+
protected function _hooks() {
|
33 |
+
parent::_hooks();
|
34 |
+
$this->util->add_action( 'init', $this->m( 'init_defaults' ), 5 );
|
35 |
+
$this->util->add_action( 'footer', $this->m( 'client_output' ), 1, 0, false );
|
36 |
+
$this->util->add_filter( 'footer_script', $this->m( 'client_output_script' ), $this->util->priority( 'client_footer_output' ), 1, false );
|
37 |
+
}
|
38 |
+
|
39 |
+
/* Collection Management */
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Add content type handler
|
43 |
+
* Accepts properties to create new handler OR previously-initialized handler instance
|
44 |
+
* @uses clear_cache()
|
45 |
+
* @see parent::add()
|
46 |
+
* @param string $id Handler ID
|
47 |
+
* @param array $props Handler properties
|
48 |
+
* @return object Current instance
|
49 |
+
*/
|
50 |
+
public function add( $id, $props = array(), $priority = 10 ) {
|
51 |
+
$this->clear_cache();
|
52 |
+
if ( is_string( $id ) ) {
|
53 |
+
// Initialize new handler
|
54 |
+
$handler = new $this->item_type( $id, $props );
|
55 |
+
} else {
|
56 |
+
// Remap parameters
|
57 |
+
$handler = func_get_arg( 0 );
|
58 |
+
if ( func_num_args() === 2 ) {
|
59 |
+
$priority = func_get_arg( 1 );
|
60 |
+
}
|
61 |
+
}
|
62 |
+
if ( ! is_int( $priority ) ) {
|
63 |
+
$priority = 10;
|
64 |
+
}
|
65 |
+
// Add to collection
|
66 |
+
return parent::add( $handler, array( 'priority' => $priority ) );
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Remove item
|
71 |
+
* @uses clear_cache()
|
72 |
+
* @see parent::remove()
|
73 |
+
* @return object Current instance
|
74 |
+
*/
|
75 |
+
public function remove( $item ) {
|
76 |
+
$this->clear_cache();
|
77 |
+
return parent::remove( $item );
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Clear collection
|
82 |
+
* @uses clear_cache()
|
83 |
+
* @see parent::clear()
|
84 |
+
* @return object Current instance
|
85 |
+
*/
|
86 |
+
public function clear() {
|
87 |
+
$this->clear_cache();
|
88 |
+
return parent::clear();
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Retrieves handlers sorted by priority
|
93 |
+
* @see parent::get()
|
94 |
+
* @uses get_cache()
|
95 |
+
* @param mixed $args Unused
|
96 |
+
* @return array Handlers
|
97 |
+
*/
|
98 |
+
public function get( $args = null ) {
|
99 |
+
$items = $this->get_cache();
|
100 |
+
if ( empty( $items ) ) {
|
101 |
+
// Retrieve items
|
102 |
+
$items = parent::get( array( 'orderby' => array( 'meta' => 'priority' ) ) );
|
103 |
+
$this->update_cache( $items );
|
104 |
+
}
|
105 |
+
return $items;
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* Get matching handler for URI
|
110 |
+
* @param string $uri URI to find match for
|
111 |
+
* @return object Handler package (FALSE if no match found)
|
112 |
+
* Package members
|
113 |
+
* > handler (Content_Handler) Matching handler instance (Default: NULL)
|
114 |
+
* > props (array) Properties returned from matching handler (May be empty depending on handler)
|
115 |
+
*/
|
116 |
+
public function match( $uri ) {
|
117 |
+
$ret = (object) array(
|
118 |
+
'handler' => null,
|
119 |
+
'props' => array(),
|
120 |
+
);
|
121 |
+
foreach ( $this->get() as $handler ) {
|
122 |
+
$props = $handler->match( $uri, $this );
|
123 |
+
if ( ! ! $props ) {
|
124 |
+
$ret->handler = $handler;
|
125 |
+
// Add handler props
|
126 |
+
if ( is_array( $props ) ) {
|
127 |
+
$ret->props = $props;
|
128 |
+
}
|
129 |
+
// Save match
|
130 |
+
$hid = $handler->get_id();
|
131 |
+
if ( ! isset( $this->request_matches[ $hid ] ) ) {
|
132 |
+
$this->request_matches[ $hid ] = $handler;
|
133 |
+
}
|
134 |
+
break;
|
135 |
+
}
|
136 |
+
}
|
137 |
+
return $ret;
|
138 |
+
}
|
139 |
+
|
140 |
+
/* Cache */
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Retrieve cached items
|
144 |
+
* @uses get_cache_props()
|
145 |
+
* @uses wp_cache_get()
|
146 |
+
* @return array Cached items (Default: empty array)
|
147 |
+
*/
|
148 |
+
protected function get_cache() {
|
149 |
+
$cprops = $this->get_cache_props();
|
150 |
+
$items = wp_cache_get( $cprops->key, $cprops->group );
|
151 |
+
return ( is_array( $items ) ) ? $items : array();
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Update cached items
|
156 |
+
* Cache is cleared if no items specified
|
157 |
+
* @uses get_cache_props()
|
158 |
+
* @uses wp_cache_get()
|
159 |
+
* @param array $data Item data to cache
|
160 |
+
*/
|
161 |
+
protected function update_cache( $data = null ) {
|
162 |
+
$props = $this->get_cache_props();
|
163 |
+
wp_cache_set( $props->key, $data, $props->group );
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* Clear cache
|
168 |
+
* @uses update_cache()
|
169 |
+
*/
|
170 |
+
protected function clear_cache() {
|
171 |
+
$this->update_cache();
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Retrieve cache properites (key, group)
|
176 |
+
* @return object Cache properties
|
177 |
+
*/
|
178 |
+
protected function get_cache_props() {
|
179 |
+
if ( ! is_object( $this->cache_props ) ) {
|
180 |
+
$this->cache_props = (object) array(
|
181 |
+
'key' => $this->hook_prefix . '_items',
|
182 |
+
'group' => $this->get_prefix(),
|
183 |
+
);
|
184 |
+
}
|
185 |
+
return $this->cache_props;
|
186 |
+
}
|
187 |
+
|
188 |
+
/* Handlers */
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Initialize default handlers
|
192 |
+
* @param SLB_Content_Handlers $handlers Handlers controller
|
193 |
+
*/
|
194 |
+
public function init_defaults( $handlers ) {
|
195 |
+
$src_base = $this->util->get_file_url( 'content-handlers', true );
|
196 |
+
$js_path = 'js/';
|
197 |
+
$js_path .= ( SLB_DEV ) ? 'dev' : 'prod';
|
198 |
+
$defaults = array(
|
199 |
+
'image' => array(
|
200 |
+
'match' => $this->m( 'match_image' ),
|
201 |
+
'scripts' => array(
|
202 |
+
array( 'base', "$src_base/image/$js_path/handler.image.js" ),
|
203 |
+
),
|
204 |
+
),
|
205 |
+
);
|
206 |
+
foreach ( $defaults as $id => $props ) {
|
207 |
+
$handlers->add( $id, $props );
|
208 |
+
}
|
209 |
+
}
|
210 |
+
|
211 |
+
/**
|
212 |
+
* Matches image URIs
|
213 |
+
* @param string $uri URI to match
|
214 |
+
* @return bool|array TRUE if URI is image (array is used if extra data needs to be sent)
|
215 |
+
*/
|
216 |
+
public function match_image( $uri, $handlers ) {
|
217 |
+
// Basic matching
|
218 |
+
$match = ( $this->util->has_file_extension( $uri, array( 'avif', 'jpg', 'jpeg', 'jpe', 'jfif', 'jif', 'gif', 'png', 'webp' ) ) ) ? true : false;
|
219 |
+
|
220 |
+
// Filter result
|
221 |
+
$extra = new stdClass();
|
222 |
+
$match = $this->util->apply_filters( 'image_match', $match, $uri, $extra );
|
223 |
+
|
224 |
+
// Handle extra data passed from filters
|
225 |
+
// Currently only `uri` supported
|
226 |
+
if ( $match && isset( $extra->uri ) && is_string( $extra->uri ) ) {
|
227 |
+
$match = array( 'uri' => $extra->uri );
|
228 |
+
}
|
229 |
+
|
230 |
+
return $match;
|
231 |
+
}
|
232 |
+
|
233 |
+
/* Output */
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Build client output
|
237 |
+
* Load handler files in client
|
238 |
+
*/
|
239 |
+
public function client_output() {
|
240 |
+
// Get handlers for current request
|
241 |
+
foreach ( $this->request_matches as $handler ) {
|
242 |
+
$handler->enqueue_scripts();
|
243 |
+
}
|
244 |
+
}
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Client output script
|
248 |
+
* @param array $commands Client script commands
|
249 |
+
* @return array Modified script commands
|
250 |
+
*/
|
251 |
+
public function client_output_script( $commands ) {
|
252 |
+
$out = array( '/* CHDL */' );
|
253 |
+
$code = array();
|
254 |
+
|
255 |
+
foreach ( $this->request_matches as $handler ) {
|
256 |
+
// Attributes
|
257 |
+
$attrs = $handler->get_attributes();
|
258 |
+
// Styles
|
259 |
+
$styles = $handler->get_styles( array( 'uri_format' => 'full' ) );
|
260 |
+
if ( ! empty( $styles ) ) {
|
261 |
+
$attrs['styles'] = array_values( $styles );
|
262 |
+
}
|
263 |
+
if ( empty( $attrs ) ) {
|
264 |
+
continue;
|
265 |
+
}
|
266 |
+
// Setup client parameters
|
267 |
+
$params = array(
|
268 |
+
sprintf( "'%s'", $handler->get_id() ),
|
269 |
+
wp_json_encode( $attrs ),
|
270 |
+
);
|
271 |
+
// Extend handler in client
|
272 |
+
$code[] = $this->util->call_client_method( 'View.extend_content_handler', $params, false );
|
273 |
+
}
|
274 |
+
if ( ! empty( $code ) ) {
|
275 |
+
$out[] = implode( '', $code );
|
276 |
+
$commands[] = implode( PHP_EOL, $out );
|
277 |
+
}
|
278 |
+
return $commands;
|
279 |
+
}
|
280 |
+
}
|
includes/class.field.php
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
-
<?php
|
2 |
-
class SLB_Field extends SLB_Field_Type {}
|
1 |
+
<?php
|
2 |
+
class SLB_Field extends SLB_Field_Type {}
|
includes/class.field_base.php
CHANGED
@@ -1,1118 +1,1202 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Fields - Base class
|
5 |
-
* Core properties/methods for fields
|
6 |
-
* @package Simple Lightbox
|
7 |
-
* @subpackage Fields
|
8 |
-
* @author Archetyped
|
9 |
-
*/
|
10 |
-
class SLB_Field_Base extends SLB_Base {
|
11 |
-
/*-** Config **-*/
|
12 |
-
protected $mode
|
13 |
-
protected $shared = false;
|
14 |
-
|
15 |
-
/*-** Properties **-*/
|
16 |
-
|
17 |
-
/**
|
18 |
-
* @var string Unique name
|
19 |
-
*/
|
20 |
-
|
21 |
-
|
22 |
-
/**
|
23 |
-
* ID formatting options.
|
24 |
-
*
|
25 |
-
* @var array $id_formats
|
26 |
-
*/
|
27 |
-
private $id_formats = [];
|
28 |
-
|
29 |
-
/**
|
30 |
-
* Flag for ID format initialization status.
|
31 |
-
*
|
32 |
-
* @var bool $id_formats_init
|
33 |
-
*/
|
34 |
-
private $id_formats_init = false;
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Special characters/phrases
|
38 |
-
* Used for preserving special characters during formatting
|
39 |
-
* Merged with $special_chars_default
|
40 |
-
* Array Structure
|
41 |
-
* > Key: Special character/phrase
|
42 |
-
* > Value: Placeholder for special character
|
43 |
-
* @var array
|
44 |
-
*/
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
'{'
|
49 |
-
'}'
|
50 |
-
);
|
51 |
-
|
52 |
-
/**
|
53 |
-
* Reference to parent object that current instance inherits from
|
54 |
-
* @var object
|
55 |
-
*/
|
56 |
-
|
57 |
-
|
58 |
-
/**
|
59 |
-
* Title
|
60 |
-
* @var string
|
61 |
-
*/
|
62 |
-
|
63 |
-
|
64 |
-
/**
|
65 |
-
* @var string Short description
|
66 |
-
*/
|
67 |
-
|
68 |
-
|
69 |
-
/**
|
70 |
-
* @var array Object Properties
|
71 |
-
*/
|
72 |
-
|
73 |
-
|
74 |
-
/**
|
75 |
-
* Initialization properties
|
76 |
-
* @var array
|
77 |
-
*/
|
78 |
-
protected $properties_init = null;
|
79 |
-
|
80 |
-
/**
|
81 |
-
* Structure: Property names stored as keys in group
|
82 |
-
* Root
|
83 |
-
* -> Group Name
|
84 |
-
* -> Property Name => Null
|
85 |
-
* Reason: Faster searching over large arrays
|
86 |
-
* @var array Groupings of Properties
|
87 |
-
*/
|
88 |
-
|
89 |
-
|
90 |
-
/**
|
91 |
-
* Keys to filter out of properties array before setting properties
|
92 |
-
* @var array
|
93 |
-
*/
|
94 |
-
|
95 |
-
|
96 |
-
/**
|
97 |
-
* Define order of properties
|
98 |
-
* Useful when processing order is important (e.g. one property depends on another)
|
99 |
-
* @var array
|
100 |
-
*/
|
101 |
-
|
102 |
-
|
103 |
-
/**
|
104 |
-
* Data for object
|
105 |
-
* May also contain data for nested objects
|
106 |
-
* @var mixed
|
107 |
-
*/
|
108 |
-
|
109 |
-
|
110 |
-
/**
|
111 |
-
* Whether data has been fetched or not
|
112 |
-
* @var bool
|
113 |
-
*/
|
114 |
-
protected $data_loaded = false;
|
115 |
-
|
116 |
-
/**
|
117 |
-
* @var array Script resources to include for object
|
118 |
-
*/
|
119 |
-
|
120 |
-
|
121 |
-
/**
|
122 |
-
* @var array CSS style resources to include for object
|
123 |
-
*/
|
124 |
-
|
125 |
-
|
126 |
-
/**
|
127 |
-
* Hooks (Filters/Actions) for object
|
128 |
-
* @var array
|
129 |
-
*/
|
130 |
-
|
131 |
-
|
132 |
-
/**
|
133 |
-
* Mapping of child properties to parent members
|
134 |
-
* Allows more flexibility when creating new instances of child objects using property arrays
|
135 |
-
* Associative array structure:
|
136 |
-
* > Key: Child property to map FROM
|
137 |
-
* > Val: Parent property to map TO
|
138 |
-
* @var array
|
139 |
-
*/
|
140 |
-
|
141 |
-
|
142 |
-
/**
|
143 |
-
* Options used when building collection (callbacks, etc.)
|
144 |
-
* Associative array
|
145 |
-
* > Key: Option name
|
146 |
-
* > Value: Option value
|
147 |
-
* @var array
|
148 |
-
*/
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
/**
|
154 |
-
* Constructor
|
155 |
-
*/
|
156 |
-
function __construct($id = '', $properties = null) {
|
157 |
-
parent::__construct();
|
158 |
-
// Normalize Properties
|
159 |
-
$args
|
160 |
-
$defaults
|
161 |
-
$properties = $this->make_properties($args, $defaults);
|
162 |
-
// Save init properties
|
163 |
-
$this->properties_init = $properties;
|
164 |
-
// Set Properties
|
165 |
-
$this->set_properties($properties);
|
166 |
-
}
|
167 |
-
|
168 |
-
/* Getters/Setters */
|
169 |
-
|
170 |
-
/**
|
171 |
-
* Checks if the specified path exists in the object
|
172 |
-
* @param array $path Path to check for
|
173 |
-
* @return bool TRUE if path exists in object, FALSE otherwise
|
174 |
-
*/
|
175 |
-
function path_isset($path = '') {
|
176 |
-
// Stop execution if no path is supplied
|
177 |
-
if ( empty($path) )
|
178 |
-
return false;
|
179 |
-
|
180 |
-
$
|
181 |
-
$
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
// $item
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
*
|
198 |
-
*
|
199 |
-
* @
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
$
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
*
|
233 |
-
*
|
234 |
-
*
|
235 |
-
*
|
236 |
-
*
|
237 |
-
*
|
238 |
-
*
|
239 |
-
*
|
240 |
-
* @
|
241 |
-
*
|
242 |
-
|
243 |
-
|
244 |
-
|
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 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
//
|
300 |
-
$
|
301 |
-
}
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
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 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
//
|
367 |
-
$
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
$
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
unset($
|
390 |
-
}
|
391 |
-
|
392 |
-
//
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
$
|
410 |
-
$
|
411 |
-
$
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
//
|
417 |
-
$
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
*
|
488 |
-
*
|
489 |
-
* @
|
490 |
-
*
|
491 |
-
* @
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
$
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
$
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
$
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
return $this->
|
651 |
-
}
|
652 |
-
|
653 |
-
/**
|
654 |
-
*
|
655 |
-
*
|
656 |
-
* @param
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
$
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
// Set
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
*
|
754 |
-
*
|
755 |
-
* @
|
756 |
-
* @
|
757 |
-
*/
|
758 |
-
function
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
$
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
*
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
//
|
804 |
-
$
|
805 |
-
|
806 |
-
|
807 |
-
$
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
*
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
|
865 |
-
|
866 |
-
*
|
867 |
-
* @
|
868 |
-
|
869 |
-
|
870 |
-
|
871 |
-
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
876 |
-
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
/**
|
887 |
-
*
|
888 |
-
* @
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
*
|
898 |
-
* @param $
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
*
|
950 |
-
*
|
951 |
-
*
|
952 |
-
* @
|
953 |
-
*/
|
954 |
-
function
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
973 |
-
*
|
974 |
-
* @param
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
-
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
|
994 |
-
|
995 |
-
|
996 |
-
|
997 |
-
|
998 |
-
*
|
999 |
-
* @param
|
1000 |
-
|
1001 |
-
|
1002 |
-
|
1003 |
-
|
1004 |
-
|
1005 |
-
|
1006 |
-
|
1007 |
-
|
1008 |
-
|
1009 |
-
|
1010 |
-
|
1011 |
-
|
1012 |
-
|
1013 |
-
|
1014 |
-
|
1015 |
-
|
1016 |
-
|
1017 |
-
|
1018 |
-
|
1019 |
-
|
1020 |
-
|
1021 |
-
|
1022 |
-
|
1023 |
-
|
1024 |
-
*
|
1025 |
-
* @param
|
1026 |
-
* @param
|
1027 |
-
* @
|
1028 |
-
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
|
1040 |
-
|
1041 |
-
|
1042 |
-
|
1043 |
-
|
1044 |
-
|
1045 |
-
|
1046 |
-
|
1047 |
-
|
1048 |
-
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
*
|
1061 |
-
*
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
|
1069 |
-
|
1070 |
-
|
1071 |
-
|
1072 |
-
|
1073 |
-
|
1074 |
-
|
1075 |
-
|
1076 |
-
|
1077 |
-
|
1078 |
-
|
1079 |
-
*
|
1080 |
-
* @
|
1081 |
-
* @
|
1082 |
-
* @param
|
1083 |
-
* @param
|
1084 |
-
* @
|
1085 |
-
|
1086 |
-
|
1087 |
-
|
1088 |
-
|
1089 |
-
|
1090 |
-
|
1091 |
-
|
1092 |
-
}
|
1093 |
-
|
1094 |
-
|
1095 |
-
|
1096 |
-
|
1097 |
-
|
1098 |
-
|
1099 |
-
|
1100 |
-
|
1101 |
-
|
1102 |
-
|
1103 |
-
|
1104 |
-
|
1105 |
-
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Fields - Base class
|
5 |
+
* Core properties/methods for fields
|
6 |
+
* @package Simple Lightbox
|
7 |
+
* @subpackage Fields
|
8 |
+
* @author Archetyped
|
9 |
+
*/
|
10 |
+
class SLB_Field_Base extends SLB_Base {
|
11 |
+
/*-** Config **-*/
|
12 |
+
protected $mode = 'object';
|
13 |
+
protected $shared = false;
|
14 |
+
|
15 |
+
/*-** Properties **-*/
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @var string Unique name
|
19 |
+
*/
|
20 |
+
public $id = '';
|
21 |
+
|
22 |
+
/**
|
23 |
+
* ID formatting options.
|
24 |
+
*
|
25 |
+
* @var array $id_formats
|
26 |
+
*/
|
27 |
+
private $id_formats = [];
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Flag for ID format initialization status.
|
31 |
+
*
|
32 |
+
* @var bool $id_formats_init
|
33 |
+
*/
|
34 |
+
private $id_formats_init = false;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Special characters/phrases
|
38 |
+
* Used for preserving special characters during formatting
|
39 |
+
* Merged with $special_chars_default
|
40 |
+
* Array Structure
|
41 |
+
* > Key: Special character/phrase
|
42 |
+
* > Value: Placeholder for special character
|
43 |
+
* @var array
|
44 |
+
*/
|
45 |
+
public $special_chars = null;
|
46 |
+
|
47 |
+
public $special_chars_default = array(
|
48 |
+
'{' => '%SQB_L%',
|
49 |
+
'}' => '%SQB_R%',
|
50 |
+
);
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Reference to parent object that current instance inherits from
|
54 |
+
* @var object
|
55 |
+
*/
|
56 |
+
public $parent = null;
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Title
|
60 |
+
* @var string
|
61 |
+
*/
|
62 |
+
public $title = '';
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @var string Short description
|
66 |
+
*/
|
67 |
+
public $description = '';
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @var array Object Properties
|
71 |
+
*/
|
72 |
+
public $properties = array();
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Initialization properties
|
76 |
+
* @var array
|
77 |
+
*/
|
78 |
+
protected $properties_init = null;
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Structure: Property names stored as keys in group
|
82 |
+
* Root
|
83 |
+
* -> Group Name
|
84 |
+
* -> Property Name => Null
|
85 |
+
* Reason: Faster searching over large arrays
|
86 |
+
* @var array Groupings of Properties
|
87 |
+
*/
|
88 |
+
public $property_groups = array();
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Keys to filter out of properties array before setting properties
|
92 |
+
* @var array
|
93 |
+
*/
|
94 |
+
public $property_filter = array( 'group' );
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Define order of properties
|
98 |
+
* Useful when processing order is important (e.g. one property depends on another)
|
99 |
+
* @var array
|
100 |
+
*/
|
101 |
+
public $property_priority = array();
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Data for object
|
105 |
+
* May also contain data for nested objects
|
106 |
+
* @var mixed
|
107 |
+
*/
|
108 |
+
public $data = null;
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Whether data has been fetched or not
|
112 |
+
* @var bool
|
113 |
+
*/
|
114 |
+
protected $data_loaded = false;
|
115 |
+
|
116 |
+
/**
|
117 |
+
* @var array Script resources to include for object
|
118 |
+
*/
|
119 |
+
public $scripts = array();
|
120 |
+
|
121 |
+
/**
|
122 |
+
* @var array CSS style resources to include for object
|
123 |
+
*/
|
124 |
+
public $styles = array();
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Hooks (Filters/Actions) for object
|
128 |
+
* @var array
|
129 |
+
*/
|
130 |
+
public $hooks = array();
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Mapping of child properties to parent members
|
134 |
+
* Allows more flexibility when creating new instances of child objects using property arrays
|
135 |
+
* Associative array structure:
|
136 |
+
* > Key: Child property to map FROM
|
137 |
+
* > Val: Parent property to map TO
|
138 |
+
* @var array
|
139 |
+
*/
|
140 |
+
public $map = null;
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Options used when building collection (callbacks, etc.)
|
144 |
+
* Associative array
|
145 |
+
* > Key: Option name
|
146 |
+
* > Value: Option value
|
147 |
+
* @var array
|
148 |
+
*/
|
149 |
+
public $build_vars = array();
|
150 |
+
|
151 |
+
public $build_vars_default = array();
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Constructor
|
155 |
+
*/
|
156 |
+
function __construct( $id = '', $properties = null ) {
|
157 |
+
parent::__construct();
|
158 |
+
// Normalize Properties
|
159 |
+
$args = func_get_args();
|
160 |
+
$defaults = $this->integrate_id( $id );
|
161 |
+
$properties = $this->make_properties( $args, $defaults );
|
162 |
+
// Save init properties
|
163 |
+
$this->properties_init = $properties;
|
164 |
+
// Set Properties
|
165 |
+
$this->set_properties( $properties );
|
166 |
+
}
|
167 |
+
|
168 |
+
/* Getters/Setters */
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Checks if the specified path exists in the object
|
172 |
+
* @param array $path Path to check for
|
173 |
+
* @return bool TRUE if path exists in object, FALSE otherwise
|
174 |
+
*/
|
175 |
+
function path_isset( $path = '' ) {
|
176 |
+
// Stop execution if no path is supplied
|
177 |
+
if ( empty( $path ) ) {
|
178 |
+
return false;
|
179 |
+
}
|
180 |
+
$args = func_get_args();
|
181 |
+
$path = $this->util->build_path( $args );
|
182 |
+
$item =& $this;
|
183 |
+
// Iterate over path and check if each level exists before moving on to the next
|
184 |
+
$path_size = count( $path );
|
185 |
+
for ( $x = 0; $x < $path_size; $x++ ) {
|
186 |
+
if ( $this->util->property_exists( $item, $path[ $x ] ) ) {
|
187 |
+
// Set $item as reference to next level in path for next iteration
|
188 |
+
$item =& $this->util->get_property( $item, $path[ $x ] );
|
189 |
+
} else {
|
190 |
+
return false;
|
191 |
+
}
|
192 |
+
}
|
193 |
+
return true;
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Retrieves a value from object using a specified path
|
198 |
+
* Checks to make sure path exists in object before retrieving value
|
199 |
+
* @param array $path Path to retrieve value from. Each item in array is a deeper dimension
|
200 |
+
* @return mixed Value at specified path
|
201 |
+
*/
|
202 |
+
function &get_path_value( $path = '' ) {
|
203 |
+
$ret = '';
|
204 |
+
$path = $this->util->build_path( func_get_args() );
|
205 |
+
if ( $this->path_isset( $path ) ) {
|
206 |
+
$ret =& $this;
|
207 |
+
|
208 |
+
$path_size = count( $path );
|
209 |
+
for ( $x = 0; $x < $path_size; $x++ ) {
|
210 |
+
if ( 0 === $x ) {
|
211 |
+
$ret =& $ret->{ $path[ $x ] };
|
212 |
+
} else {
|
213 |
+
$ret =& $ret[ $path[ $x ] ];
|
214 |
+
}
|
215 |
+
}
|
216 |
+
}
|
217 |
+
return $ret;
|
218 |
+
}
|
219 |
+
|
220 |
+
/**
|
221 |
+
* Search for specified member value in field type ancestors
|
222 |
+
* @param string $member Name of object member to search (e.g. properties, layout, etc.)
|
223 |
+
* @param string $name Value to retrieve from member
|
224 |
+
* @return mixed Member value if found (Default: empty string)
|
225 |
+
*/
|
226 |
+
function get_parent_value( $member, $name = '', $default = '' ) {
|
227 |
+
$parent = $this->get_parent();
|
228 |
+
return $this->get_object_value( $parent, $member, $name, $default, 'parent' );
|
229 |
+
}
|
230 |
+
|
231 |
+
/**
|
232 |
+
* Retrieves specified member value.
|
233 |
+
*
|
234 |
+
* Handles inherited values and merges corresponding parents
|
235 |
+
* if value is an array (e.g. for property groups).
|
236 |
+
*
|
237 |
+
* @param string|array $member Member to get value from.
|
238 |
+
* @param string|array $name Optional. Element/Path to Element to retrieve from member. Default none.
|
239 |
+
* @param mixed $default Optional. Default value to return if no data retrieved. Default empty string.
|
240 |
+
* @param string $dir Optional. Direction to move through hierarchy to find value.
|
241 |
+
* Possible Values:
|
242 |
+
* * parent (default) - Search through field parents.
|
243 |
+
* * current - Do not search through connected objects.
|
244 |
+
* * container - Search through field containers.
|
245 |
+
* * caller - Search through field callers.
|
246 |
+
* @return mixed Specified member value.
|
247 |
+
* @todo Return reference.
|
248 |
+
*/
|
249 |
+
function &get_member_value( $member, $name = '', $default = '', $dir = 'parent' ) {
|
250 |
+
// Check if path to member is supplied
|
251 |
+
$path = array();
|
252 |
+
if ( is_array( $member ) && isset( $member['tag'] ) ) {
|
253 |
+
if ( isset( $member['attributes']['ref_base'] ) ) {
|
254 |
+
if ( 'root' !== $member['attributes']['ref_base'] ) {
|
255 |
+
$path[] = $member['attributes']['ref_base'];
|
256 |
+
}
|
257 |
+
} else {
|
258 |
+
$path[] = 'properties';
|
259 |
+
}
|
260 |
+
|
261 |
+
$path[] = $member['tag'];
|
262 |
+
} else {
|
263 |
+
$path = $member;
|
264 |
+
}
|
265 |
+
// Prep name.
|
266 |
+
if ( is_string( $name ) ) {
|
267 |
+
$name = trim( $name );
|
268 |
+
}
|
269 |
+
$path = $this->util->build_path( $path, $name );
|
270 |
+
// Set defaults and prepare data
|
271 |
+
$val = $default;
|
272 |
+
$inherit = false;
|
273 |
+
$inherit_tag = '{inherit}';
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Determines whether the value must be retrieved from a parent/container object.
|
277 |
+
*
|
278 |
+
* Conditions:
|
279 |
+
*
|
280 |
+
* 1. Path does not exist in current field.
|
281 |
+
* 2. Path exists and is not an object, but at least one of the following is true:
|
282 |
+
* * Value at path is an array (e.g. properties, elements, etc. array):
|
283 |
+
* * - Parent/container values should be merged with retrieved array.
|
284 |
+
* * Value at path is a string that inherits from another field:
|
285 |
+
* * - Value from other field will be retrieved and will replace
|
286 |
+
* inheritance placeholder in retrieved value
|
287 |
+
* @var bool
|
288 |
+
*/
|
289 |
+
$deeper = false;
|
290 |
+
|
291 |
+
if ( ! $this->path_isset( $path ) ) {
|
292 |
+
$deeper = true;
|
293 |
+
} else {
|
294 |
+
$val = $this->get_path_value( $path );
|
295 |
+
if ( is_array( $val ) ) {
|
296 |
+
$deeper = true;
|
297 |
+
} elseif ( is_string( $val ) && false !== strpos( $val, $inherit_tag ) ) {
|
298 |
+
$deeper = true;
|
299 |
+
// Value inherits from another field.
|
300 |
+
$inherit = true;
|
301 |
+
}
|
302 |
+
}
|
303 |
+
|
304 |
+
if ( $deeper && 'current' !== $dir ) {
|
305 |
+
$ex_val = '';
|
306 |
+
// Get Parent value (recursive)
|
307 |
+
if ( 'parent' === $dir ) {
|
308 |
+
$ex_val = $this->get_parent_value( $member, $name, $default );
|
309 |
+
} elseif ( method_exists( $this, 'get_container_value' ) ) {
|
310 |
+
$ex_val = $this->get_container_value( $member, $name, $default );
|
311 |
+
}
|
312 |
+
// Handle inheritance
|
313 |
+
if ( is_array( $val ) ) {
|
314 |
+
// Combine Arrays
|
315 |
+
if ( is_array( $ex_val ) ) {
|
316 |
+
$val = array_merge( $ex_val, $val );
|
317 |
+
}
|
318 |
+
} elseif ( false !== $inherit ) {
|
319 |
+
// Replace placeholder with inherited string
|
320 |
+
$val = str_replace( $inherit_tag, $ex_val, $val );
|
321 |
+
} else {
|
322 |
+
// Default: Set parent value as value
|
323 |
+
$val = $ex_val;
|
324 |
+
}
|
325 |
+
}
|
326 |
+
|
327 |
+
return $val;
|
328 |
+
}
|
329 |
+
|
330 |
+
/**
|
331 |
+
* Search for specified member value in an object
|
332 |
+
* @param object $object Reference to object to retrieve value from
|
333 |
+
* @param string $member Name of object member to search (e.g. properties, layout, etc.)
|
334 |
+
* @param string $name (optional) Value to retrieve from member
|
335 |
+
* @param mixed $default (optional) Default value to use if no value found (Default: empty string)
|
336 |
+
* @param string $dir Direction to move through hierarchy to find value @see SLB_Field_Type::get_member_value() for possible values
|
337 |
+
* @return mixed Member value if found (Default: $default)
|
338 |
+
*/
|
339 |
+
function get_object_value( &$object, $member, $name = '', $default = '', $dir = 'parent' ) {
|
340 |
+
$ret = $default;
|
341 |
+
if ( is_object( $object ) && method_exists( $object, 'get_member_value' ) ) {
|
342 |
+
$ret = $object->get_member_value( $member, $name, $default, $dir );
|
343 |
+
}
|
344 |
+
return $ret;
|
345 |
+
}
|
346 |
+
|
347 |
+
/**
|
348 |
+
* Set item ID
|
349 |
+
* @param string $id Unique item ID
|
350 |
+
*/
|
351 |
+
function set_id( $id ) {
|
352 |
+
if ( empty( $id ) || ! is_string( $id ) ) {
|
353 |
+
return false;
|
354 |
+
}
|
355 |
+
$this->id = trim( $id );
|
356 |
+
}
|
357 |
+
|
358 |
+
/**
|
359 |
+
* Retrieves field ID
|
360 |
+
* @param array|string $options (optional) Options or ID of format to use
|
361 |
+
* @return string item ID
|
362 |
+
*/
|
363 |
+
function get_id( $options = array() ) {
|
364 |
+
$item_id = trim( $this->id );
|
365 |
+
$formats = $this->get_id_formats();
|
366 |
+
// Setup options
|
367 |
+
$wrap_default = array(
|
368 |
+
'open' => '',
|
369 |
+
'close' => '',
|
370 |
+
'segment_open' => '',
|
371 |
+
'segment_close' => '',
|
372 |
+
);
|
373 |
+
|
374 |
+
$options_default = array(
|
375 |
+
'format' => null,
|
376 |
+
'wrap' => array(),
|
377 |
+
'segments_pre' => null,
|
378 |
+
'prefix' => '',
|
379 |
+
'recursive' => false,
|
380 |
+
);
|
381 |
+
|
382 |
+
// Load options based on format
|
383 |
+
if ( ! is_array( $options ) ) {
|
384 |
+
$options = array( 'format' => $options );
|
385 |
+
}
|
386 |
+
if ( isset( $options['format'] ) && is_string( $options['format'] ) && isset( $formats[ $options['format'] ] ) ) {
|
387 |
+
$options_default = wp_parse_args( $formats[ $options['format'] ], $options_default );
|
388 |
+
} else {
|
389 |
+
unset( $options['format'] );
|
390 |
+
}
|
391 |
+
$options = wp_parse_args( $options, $options_default );
|
392 |
+
// Import options into function
|
393 |
+
extract( $options );
|
394 |
+
|
395 |
+
// Validate options
|
396 |
+
$wrap = wp_parse_args( $wrap, $wrap_default );
|
397 |
+
|
398 |
+
if ( ! is_array( $segments_pre ) ) {
|
399 |
+
$segments_pre = array( $segments_pre );
|
400 |
+
}
|
401 |
+
$segments_pre = array_reverse( $segments_pre );
|
402 |
+
|
403 |
+
// Format ID based on options
|
404 |
+
$item_id = array( $item_id );
|
405 |
+
|
406 |
+
// Add parent objects to ID
|
407 |
+
if ( ! ! $recursive ) {
|
408 |
+
// Create array of ID components
|
409 |
+
$m = 'get_caller';
|
410 |
+
$c = ( method_exists( $this, $m ) ) ? $this->{$m}() : null;
|
411 |
+
while ( ! ! $c ) {
|
412 |
+
// Add ID of current caller to array
|
413 |
+
if ( method_exists( $c, 'get_id' ) && ! strlen( $c->get_id() ) > 0 ) {
|
414 |
+
$item_id = $c->get_id();
|
415 |
+
}
|
416 |
+
// Get parent object
|
417 |
+
$c = ( method_exists( $c, $m ) ) ? $c->{$m}() : null;
|
418 |
+
}
|
419 |
+
unset( $c );
|
420 |
+
}
|
421 |
+
|
422 |
+
// Additional segments (Pre)
|
423 |
+
foreach ( $segments_pre as $seg ) {
|
424 |
+
if ( is_null( $seg ) ) {
|
425 |
+
continue;
|
426 |
+
}
|
427 |
+
if ( is_object( $seg ) ) {
|
428 |
+
$seg = (array) $seg;
|
429 |
+
}
|
430 |
+
if ( is_array( $seg ) ) {
|
431 |
+
$item_id = array_merge( $item_id, array_reverse( $seg ) );
|
432 |
+
} elseif ( '' !== strval( $seg ) ) {
|
433 |
+
$item_id[] = strval( $seg );
|
434 |
+
}
|
435 |
+
}
|
436 |
+
|
437 |
+
// Prefix
|
438 |
+
if ( is_array( $prefix ) ) {
|
439 |
+
// Array is sequence of instance methods to call on object
|
440 |
+
// Last array member can be an array of parameters to pass to methods
|
441 |
+
$count = count( $prefix );
|
442 |
+
$args = ( $count > 1 && is_array( $prefix[ $count - 1 ] ) ) ? array_pop( $prefix ) : array();
|
443 |
+
$p = $this;
|
444 |
+
$val = '';
|
445 |
+
// Iterate through methods
|
446 |
+
foreach ( $prefix as $m ) {
|
447 |
+
if ( ! method_exists( $p, $m ) ) {
|
448 |
+
continue;
|
449 |
+
}
|
450 |
+
// Build callback
|
451 |
+
$m = $this->util->m( $p, $m );
|
452 |
+
// Call callback
|
453 |
+
$val = call_user_func_array( $m, $args );
|
454 |
+
// Returned value may be an instance object
|
455 |
+
if ( is_object( $val ) ) {
|
456 |
+
$p = $val; // Use returned object in next round
|
457 |
+
} else {
|
458 |
+
array_unshift( $args, $val ); // Pass returned value as parameter to next method on using current object
|
459 |
+
}
|
460 |
+
}
|
461 |
+
$prefix = $val;
|
462 |
+
unset( $p, $val );
|
463 |
+
}
|
464 |
+
if ( is_numeric( $prefix ) ) {
|
465 |
+
$prefix = strval( $prefix );
|
466 |
+
}
|
467 |
+
if ( empty( $prefix ) || ! is_string( $prefix ) ) {
|
468 |
+
$prefix = '';
|
469 |
+
}
|
470 |
+
|
471 |
+
// Convert array to string
|
472 |
+
$item_id = $prefix . $wrap['open'] . implode( $wrap['segment_close'] . $wrap['segment_open'], array_reverse( $item_id ) ) . $wrap['close'];
|
473 |
+
return $item_id;
|
474 |
+
}
|
475 |
+
|
476 |
+
/**
|
477 |
+
* Retrieves ID formats.
|
478 |
+
*
|
479 |
+
* @return array ID formats.
|
480 |
+
*/
|
481 |
+
private function &get_id_formats() {
|
482 |
+
$this->init_id_formats();
|
483 |
+
return $this->id_formats;
|
484 |
+
}
|
485 |
+
|
486 |
+
/**
|
487 |
+
* Initializes default ID formats.
|
488 |
+
*
|
489 |
+
* @since 2.8.0
|
490 |
+
*
|
491 |
+
* @return void
|
492 |
+
*/
|
493 |
+
private function init_id_formats() {
|
494 |
+
if ( ! $this->id_formats_init ) {
|
495 |
+
$this->id_formats_init = true;
|
496 |
+
// Initilize default formats.
|
497 |
+
$this->add_id_format(
|
498 |
+
'attr_id',
|
499 |
+
[
|
500 |
+
'wrap' => [
|
501 |
+
'open' => '_',
|
502 |
+
'segment_open' => '_',
|
503 |
+
],
|
504 |
+
'prefix' => [ 'get_container', 'get_id', 'add_prefix' ],
|
505 |
+
'recursive' => true,
|
506 |
+
],
|
507 |
+
true
|
508 |
+
);
|
509 |
+
$this->add_id_format(
|
510 |
+
'attr_name',
|
511 |
+
[
|
512 |
+
'wrap' => [
|
513 |
+
'open' => '[',
|
514 |
+
'close' => ']',
|
515 |
+
'segment_open' => '[',
|
516 |
+
'segment_close' => ']',
|
517 |
+
],
|
518 |
+
'prefix' => [ 'get_container', 'get_id', 'add_prefix' ],
|
519 |
+
'recursive' => true,
|
520 |
+
],
|
521 |
+
true
|
522 |
+
);
|
523 |
+
|
524 |
+
}
|
525 |
+
}
|
526 |
+
|
527 |
+
/**
|
528 |
+
* Adds custom ID format.
|
529 |
+
*
|
530 |
+
* @since 2.8.0
|
531 |
+
*
|
532 |
+
* @param string $name Format name.
|
533 |
+
* @param array $wrap
|
534 |
+
* @param array $prefix
|
535 |
+
* @param bool $recursive Optional.
|
536 |
+
* @param bool $overwrite Optional. Overwrite existing format. Default false.
|
537 |
+
* @return void
|
538 |
+
*/
|
539 |
+
protected function add_id_format( $name, array $options, $overwrite = false ) {
|
540 |
+
// Init ID formats before adding new ones.
|
541 |
+
$this->init_id_formats();
|
542 |
+
// Validate args.
|
543 |
+
$name = trim( $name );
|
544 |
+
// Stop if name invalid.
|
545 |
+
if ( empty( $name ) ) {
|
546 |
+
return;
|
547 |
+
}
|
548 |
+
$overwrite = (bool) $overwrite;
|
549 |
+
// Do not add format if name matches existing format (when overwriting not allowed).
|
550 |
+
if ( ! $overwrite && in_array( $name, array_keys( $this->id_formats ), true ) ) {
|
551 |
+
return;
|
552 |
+
}
|
553 |
+
// Normlize options.
|
554 |
+
$options = wp_parse_args(
|
555 |
+
$options,
|
556 |
+
[
|
557 |
+
'wrap' => [],
|
558 |
+
'prefix' => [],
|
559 |
+
'recursive' => false,
|
560 |
+
]
|
561 |
+
);
|
562 |
+
// Add format.
|
563 |
+
$this->id_formats[ $name ] = $options;
|
564 |
+
}
|
565 |
+
|
566 |
+
/**
|
567 |
+
* Retrieve value from data member
|
568 |
+
* @param string $context Context to format data for
|
569 |
+
* @param bool $top (optional) Whether to traverse through the field hierarchy to get data for field (Default: TRUE)
|
570 |
+
* @return mixed Value at specified path
|
571 |
+
*/
|
572 |
+
function get_data( $context = '', $top = true ) {
|
573 |
+
$opt_d = array(
|
574 |
+
'context' => '',
|
575 |
+
'top' => true,
|
576 |
+
);
|
577 |
+
$args = func_get_args();
|
578 |
+
$a = false;
|
579 |
+
if ( count( $args ) === 1 && is_array( $args[0] ) && ! empty( $args[0] ) ) {
|
580 |
+
$a = true;
|
581 |
+
$args = wp_parse_args( $args[0], $opt_d );
|
582 |
+
extract( $args );
|
583 |
+
}
|
584 |
+
|
585 |
+
if ( is_string( $top ) ) {
|
586 |
+
if ( 'false' === $top ) {
|
587 |
+
$top = false;
|
588 |
+
} elseif ( 'true' === $top ) {
|
589 |
+
$top = true;
|
590 |
+
} elseif ( is_numeric( $top ) ) {
|
591 |
+
$top = intval( $top );
|
592 |
+
}
|
593 |
+
}
|
594 |
+
$top = ! ! $top;
|
595 |
+
$obj =& $this;
|
596 |
+
$obj_path = array( $this );
|
597 |
+
$path = array();
|
598 |
+
if ( $top ) {
|
599 |
+
// Iterate through hiearchy to get top-most object
|
600 |
+
while ( ! empty( $obj ) ) {
|
601 |
+
$new = null;
|
602 |
+
// Try to get caller first
|
603 |
+
if ( method_exists( $obj, 'get_caller' ) ) {
|
604 |
+
$checked = true;
|
605 |
+
$new =& $obj->get_caller();
|
606 |
+
}
|
607 |
+
// Try to get container if no caller found
|
608 |
+
if ( empty( $new ) && method_exists( $obj, 'get_container' ) ) {
|
609 |
+
$checked = true;
|
610 |
+
$new =& $obj->get_container();
|
611 |
+
// Load data
|
612 |
+
if ( method_exists( $new, 'load_data' ) ) {
|
613 |
+
$new->load_data();
|
614 |
+
}
|
615 |
+
}
|
616 |
+
|
617 |
+
$obj =& $new;
|
618 |
+
unset( $new );
|
619 |
+
// Stop iteration
|
620 |
+
if ( ! empty( $obj ) ) {
|
621 |
+
// Add object to path if it is valid
|
622 |
+
$obj_path[] =& $obj;
|
623 |
+
}
|
624 |
+
}
|
625 |
+
unset( $obj );
|
626 |
+
}
|
627 |
+
|
628 |
+
// Check each object (starting with top-most) for matching data for current field
|
629 |
+
|
630 |
+
// Reverse array
|
631 |
+
$obj_path = array_reverse( $obj_path );
|
632 |
+
// Build path for data location
|
633 |
+
foreach ( $obj_path as $obj ) {
|
634 |
+
if ( method_exists( $obj, 'get_id' ) ) {
|
635 |
+
$path[] = $obj->get_id();
|
636 |
+
}
|
637 |
+
}
|
638 |
+
// Iterate through objects
|
639 |
+
while ( ! empty( $obj_path ) ) {
|
640 |
+
// Get next object
|
641 |
+
$obj = array_shift( $obj_path );
|
642 |
+
// Shorten path
|
643 |
+
array_shift( $path );
|
644 |
+
// Check for value in object and stop iteration if matching data found
|
645 |
+
$val = $this->get_object_value( $obj, 'data', $path, null, 'current' );
|
646 |
+
if ( ! is_null( $val ) ) {
|
647 |
+
break;
|
648 |
+
}
|
649 |
+
}
|
650 |
+
return $this->format( $val, $context );
|
651 |
+
}
|
652 |
+
|
653 |
+
/**
|
654 |
+
* Sets value in data member
|
655 |
+
* Sets value to data member itself by default
|
656 |
+
* @param mixed $value Value to set
|
657 |
+
* @param string|array $name Name of value to set (Can also be path to value)
|
658 |
+
*/
|
659 |
+
function set_data( $value, $name = '' ) {
|
660 |
+
$ref =& $this->get_path_value( 'data', $name );
|
661 |
+
$ref = $value;
|
662 |
+
}
|
663 |
+
|
664 |
+
/**
|
665 |
+
* Sets parent object of current instance
|
666 |
+
* Parent objects must be the same object type as current instance
|
667 |
+
* @uses SLB to get field type definition
|
668 |
+
* @uses SLB_Fields::has() to check if field type exists
|
669 |
+
* @uses SLB_Fields::get() to retrieve field type object reference
|
670 |
+
* @param string|object $parent Parent ID or reference
|
671 |
+
*/
|
672 |
+
function set_parent( $parent = null ) {
|
673 |
+
// Stop processing if parent empty
|
674 |
+
if ( empty( $parent ) && ! is_string( $this->parent ) ) {
|
675 |
+
return false;
|
676 |
+
}
|
677 |
+
// Parent passed as object reference wrapped in array
|
678 |
+
if ( is_array( $parent ) && isset( $parent[0] ) && is_object( $parent[0] ) ) {
|
679 |
+
$parent = $parent[0];
|
680 |
+
}
|
681 |
+
|
682 |
+
// No parent set but parent ID (previously) set in object
|
683 |
+
if ( empty( $parent ) && is_string( $this->parent ) ) {
|
684 |
+
$parent = $this->parent;
|
685 |
+
}
|
686 |
+
|
687 |
+
// Retrieve reference object if ID was supplied
|
688 |
+
if ( is_string( $parent ) ) {
|
689 |
+
$parent = trim( $parent );
|
690 |
+
// Get parent object reference
|
691 |
+
/**
|
692 |
+
* @var SLB
|
693 |
+
*/
|
694 |
+
$b = $this->get_base();
|
695 |
+
if ( ! ! $b && isset( $b->fields ) && $b->fields->has( $parent ) ) {
|
696 |
+
$parent = $b->fields->get( $parent );
|
697 |
+
}
|
698 |
+
}
|
699 |
+
|
700 |
+
// Set parent value on object
|
701 |
+
if ( is_string( $parent ) || is_object( $parent ) ) {
|
702 |
+
$this->parent = $parent;
|
703 |
+
}
|
704 |
+
}
|
705 |
+
|
706 |
+
/**
|
707 |
+
* Retrieve field type parent
|
708 |
+
* @return SLB_Field_Type Parent field
|
709 |
+
*/
|
710 |
+
function get_parent() {
|
711 |
+
return $this->parent;
|
712 |
+
}
|
713 |
+
|
714 |
+
/**
|
715 |
+
* Set object title
|
716 |
+
* @param string $title Title for object
|
717 |
+
* @param string $plural Plural form of title
|
718 |
+
*/
|
719 |
+
function set_title( $title = '' ) {
|
720 |
+
if ( is_scalar( $title ) ) {
|
721 |
+
$this->title = wp_strip_all_tags( trim( $title ) );
|
722 |
+
}
|
723 |
+
}
|
724 |
+
|
725 |
+
/**
|
726 |
+
* Retrieve object title
|
727 |
+
*/
|
728 |
+
function get_title() {
|
729 |
+
return $this->get_member_value( 'title', '', '', 'current' );
|
730 |
+
}
|
731 |
+
|
732 |
+
/**
|
733 |
+
* Set object description
|
734 |
+
* @param string $description Description for object
|
735 |
+
*/
|
736 |
+
function set_description( $description = '' ) {
|
737 |
+
$this->description = wp_strip_all_tags( trim( $description ) );
|
738 |
+
}
|
739 |
+
|
740 |
+
/**
|
741 |
+
* Retrieve object description
|
742 |
+
* @return string Object description
|
743 |
+
*/
|
744 |
+
function get_description() {
|
745 |
+
$dir = 'current';
|
746 |
+
return $this->get_member_value( 'description', '', '', $dir );
|
747 |
+
}
|
748 |
+
|
749 |
+
/**
|
750 |
+
* Sets multiple properties on field type at once.
|
751 |
+
*
|
752 |
+
* @param array $properties Properties to set - each element is an
|
753 |
+
* array containing the arguments to set a
|
754 |
+
* new property.
|
755 |
+
* @return void
|
756 |
+
* @todo Test refactored code.
|
757 |
+
*/
|
758 |
+
function set_properties( $properties ) {
|
759 |
+
if ( ! is_array( $properties ) ) {
|
760 |
+
return;
|
761 |
+
}
|
762 |
+
// Normalize properties
|
763 |
+
$properties = $this->remap_properties( $properties );
|
764 |
+
$properties = $this->sort_properties( $properties );
|
765 |
+
|
766 |
+
// Set Member properties.
|
767 |
+
foreach ( $properties as $prop => $val ) {
|
768 |
+
$m = 'set_' . $prop;
|
769 |
+
if ( method_exists( $this, $m ) ) {
|
770 |
+
$this->{$m}( $val );
|
771 |
+
// Remove member property from array
|
772 |
+
unset( $properties[ $prop ] );
|
773 |
+
}
|
774 |
+
unset( $m );
|
775 |
+
}
|
776 |
+
|
777 |
+
// Filter properties
|
778 |
+
$properties = $this->filter_properties( $properties );
|
779 |
+
// Set additional instance properties
|
780 |
+
foreach ( $properties as $name => $val ) {
|
781 |
+
$this->set_property( $name, $val );
|
782 |
+
}
|
783 |
+
}
|
784 |
+
|
785 |
+
/**
|
786 |
+
* Remap properties based on $map
|
787 |
+
* @uses $map For determine how child properties should map to parent properties
|
788 |
+
* @uses SLB_Utlities::array_remap() to perform array remapping
|
789 |
+
* @param array $properties Associative array of properties
|
790 |
+
* @return array Remapped properties
|
791 |
+
*/
|
792 |
+
function remap_properties( $properties ) {
|
793 |
+
// Return remapped properties
|
794 |
+
return $this->util->array_remap( $properties, $this->map );
|
795 |
+
}
|
796 |
+
|
797 |
+
/**
|
798 |
+
* Sort properties based on priority
|
799 |
+
* @uses this::property_priority
|
800 |
+
* @return array Sorted priorities
|
801 |
+
*/
|
802 |
+
function sort_properties( $properties ) {
|
803 |
+
// Stop if sorting not necessary
|
804 |
+
if ( empty( $properties ) || ! is_array( $properties ) || empty( $this->property_priority ) || ! is_array( $this->property_priority ) ) {
|
805 |
+
return $properties;
|
806 |
+
}
|
807 |
+
$props = array();
|
808 |
+
foreach ( $this->property_priority as $prop ) {
|
809 |
+
if ( ! array_key_exists( $prop, $properties ) ) {
|
810 |
+
continue;
|
811 |
+
}
|
812 |
+
// Add to new array
|
813 |
+
$props[ $prop ] = $properties[ $prop ];
|
814 |
+
// Remove from old array
|
815 |
+
unset( $properties[ $prop ] );
|
816 |
+
}
|
817 |
+
// Append any remaining properties
|
818 |
+
$props = array_merge( $props, $properties );
|
819 |
+
return $props;
|
820 |
+
}
|
821 |
+
|
822 |
+
/**
|
823 |
+
* Build properties array
|
824 |
+
* @param array $props Instance properties
|
825 |
+
* @param array $signature (optional) Default properties
|
826 |
+
* @return array Normalized properties
|
827 |
+
*/
|
828 |
+
function make_properties( $props, $signature = array() ) {
|
829 |
+
$p = array();
|
830 |
+
if ( is_array( $props ) ) {
|
831 |
+
foreach ( $props as $prop ) {
|
832 |
+
if ( is_array( $prop ) ) {
|
833 |
+
$p = array_merge( $prop, $p );
|
834 |
+
}
|
835 |
+
}
|
836 |
+
}
|
837 |
+
$props = $p;
|
838 |
+
if ( is_array( $signature ) ) {
|
839 |
+
$props = array_merge( $signature, $props );
|
840 |
+
}
|
841 |
+
return $props;
|
842 |
+
}
|
843 |
+
|
844 |
+
function validate_id( $id ) {
|
845 |
+
return ( is_scalar( $id ) && ! empty( $id ) ) ? true : false;
|
846 |
+
}
|
847 |
+
|
848 |
+
function integrate_id( $id ) {
|
849 |
+
return ( $this->validate_id( $id ) ) ? array( 'id' => $id ) : array();
|
850 |
+
}
|
851 |
+
|
852 |
+
/**
|
853 |
+
* Filter property members
|
854 |
+
* @uses $property_filter to remove define members to remove from $properties
|
855 |
+
* @param array $props Properties
|
856 |
+
* @return array Filtered properties
|
857 |
+
*/
|
858 |
+
function filter_properties( $props = array() ) {
|
859 |
+
return $this->util->array_filter_keys( $props, $this->property_filter );
|
860 |
+
}
|
861 |
+
|
862 |
+
/**
|
863 |
+
* Add/Set a property on the field definition
|
864 |
+
* @param string $name Name of property
|
865 |
+
* @param mixed $value Default value for property
|
866 |
+
* @param string|array $group Group(s) property belongs to
|
867 |
+
* @return boolean TRUE if property is successfully added to field type, FALSE otherwise
|
868 |
+
*/
|
869 |
+
function set_property( $name, $value = '', $group = null ) {
|
870 |
+
// Do not add if property name is not a string
|
871 |
+
if ( ! is_string( $name ) ) {
|
872 |
+
return false;
|
873 |
+
}
|
874 |
+
// Create property array
|
875 |
+
$prop_arr = array();
|
876 |
+
$prop_arr['value'] = $value;
|
877 |
+
// Add to properties array
|
878 |
+
$this->properties[ $name ] = $value;
|
879 |
+
// Add property to specified groups
|
880 |
+
if ( ! empty( $group ) ) {
|
881 |
+
$this->set_group_property( $group, $name );
|
882 |
+
}
|
883 |
+
return true;
|
884 |
+
}
|
885 |
+
|
886 |
+
/**
|
887 |
+
* Retreives property from field type
|
888 |
+
* @param string $name Name of property to retrieve
|
889 |
+
* @return mixed Specified Property if exists (Default: Empty string)
|
890 |
+
*/
|
891 |
+
function get_property( $name ) {
|
892 |
+
$val = $this->get_member_value( 'properties', $name );
|
893 |
+
return $val;
|
894 |
+
}
|
895 |
+
|
896 |
+
/**
|
897 |
+
* Removes a property from item
|
898 |
+
* @param string $name Property ID
|
899 |
+
*/
|
900 |
+
function remove_property( $name ) {
|
901 |
+
// Remove property
|
902 |
+
if ( isset( $this->properties[ $name ] ) ) {
|
903 |
+
unset( $this->properties[ $name ] );
|
904 |
+
}
|
905 |
+
// Remove from group
|
906 |
+
foreach ( array_keys( $this->property_groups ) as $g ) {
|
907 |
+
if ( isset( $this->property_groups[ $g ][ $name ] ) ) {
|
908 |
+
unset( $this->property_groups[ $g ][ $name ] );
|
909 |
+
break;
|
910 |
+
}
|
911 |
+
}
|
912 |
+
}
|
913 |
+
|
914 |
+
/**
|
915 |
+
* Adds Specified Property to a Group
|
916 |
+
* @param string|array $group Group(s) to add property to
|
917 |
+
* @param string $property Property to add to group
|
918 |
+
*/
|
919 |
+
function set_group_property( $group, $property ) {
|
920 |
+
if ( is_string( $group ) && isset( $this->property_groups[ $group ][ $property ] ) ) {
|
921 |
+
return;
|
922 |
+
}
|
923 |
+
if ( ! is_array( $group ) ) {
|
924 |
+
$group = array( $group );
|
925 |
+
}
|
926 |
+
|
927 |
+
foreach ( $group as $g ) {
|
928 |
+
$g = trim( $g );
|
929 |
+
// Initialize group if it doesn't already exist
|
930 |
+
if ( ! isset( $this->property_groups[ $g ] ) ) {
|
931 |
+
$this->property_groups[ $g ] = array();
|
932 |
+
}
|
933 |
+
|
934 |
+
// Add property to group
|
935 |
+
$this->property_groups[ $g ][ $property ] = null;
|
936 |
+
}
|
937 |
+
}
|
938 |
+
|
939 |
+
/**
|
940 |
+
* Retrieve property group
|
941 |
+
* @param string $group Group to retrieve
|
942 |
+
* @return array Array of properties in specified group
|
943 |
+
*/
|
944 |
+
function get_group( $group ) {
|
945 |
+
return $this->get_member_value( 'property_groups', $group, array() );
|
946 |
+
}
|
947 |
+
|
948 |
+
/**
|
949 |
+
* Save field data
|
950 |
+
* Child classes will define their own
|
951 |
+
* functionality for this method
|
952 |
+
* @return bool TRUE if save was successful (FALSE otherwise)
|
953 |
+
*/
|
954 |
+
function save() {
|
955 |
+
return true;
|
956 |
+
}
|
957 |
+
|
958 |
+
/*-** Hooks **-*/
|
959 |
+
|
960 |
+
/**
|
961 |
+
* Retrieve hooks added to object
|
962 |
+
* @return array Hooks
|
963 |
+
*/
|
964 |
+
function get_hooks() {
|
965 |
+
return $this->get_member_value( 'hooks', '', array() );
|
966 |
+
}
|
967 |
+
|
968 |
+
/**
|
969 |
+
* Add hook for object
|
970 |
+
* @see add_filter() for parameter defaults
|
971 |
+
* @param $tag
|
972 |
+
* @param $function_to_add
|
973 |
+
* @param $priority
|
974 |
+
* @param $accepted_args
|
975 |
+
*/
|
976 |
+
function add_hook( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
|
977 |
+
// Create new array for tag (if not already set)
|
978 |
+
if ( ! isset( $this->hooks[ $tag ] ) ) {
|
979 |
+
$this->hooks[ $tag ] = array();
|
980 |
+
}
|
981 |
+
// Build Unique ID
|
982 |
+
if ( is_string( $function_to_add ) ) {
|
983 |
+
$id = $function_to_add;
|
984 |
+
} elseif ( is_array( $function_to_add ) && ! empty( $function_to_add ) ) {
|
985 |
+
$id = strval( $function_to_add[ count( $function_to_add ) - 1 ] );
|
986 |
+
} else {
|
987 |
+
$id = 'function_' . ( count( $this->hooks[ $tag ] ) + 1 );
|
988 |
+
}
|
989 |
+
// Add hook
|
990 |
+
$this->hooks[ $tag ][ $id ] = func_get_args();
|
991 |
+
}
|
992 |
+
|
993 |
+
/**
|
994 |
+
* Convenience method for adding an action for object
|
995 |
+
* @see add_filter() for parameter defaults
|
996 |
+
* @param $tag
|
997 |
+
* @param $function_to_add
|
998 |
+
* @param $priority
|
999 |
+
* @param $accepted_args
|
1000 |
+
*/
|
1001 |
+
function add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
|
1002 |
+
$this->add_hook( $tag, $function_to_add, $priority, $accepted_args );
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
/**
|
1006 |
+
* Convenience method for adding a filter for object
|
1007 |
+
* @see add_filter() for parameter defaults
|
1008 |
+
* @param $tag
|
1009 |
+
* @param $function_to_add
|
1010 |
+
* @param $priority
|
1011 |
+
* @param $accepted_args
|
1012 |
+
*/
|
1013 |
+
function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
|
1014 |
+
$this->add_hook( $tag, $function_to_add, $priority, $accepted_args );
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
/*-** Dependencies **-*/
|
1018 |
+
|
1019 |
+
/**
|
1020 |
+
* Adds dependency to object
|
1021 |
+
* @param string $type Type of dependency to add (script, style)
|
1022 |
+
* @param array|string $context When dependency will be added (@see SLB_Utilities::get_action() for possible contexts)
|
1023 |
+
* @see wp_enqueue_script for the following of the parameters
|
1024 |
+
* @param $handle
|
1025 |
+
* @param $src
|
1026 |
+
* @param $deps
|
1027 |
+
* @param $ver
|
1028 |
+
* @param $ex
|
1029 |
+
*/
|
1030 |
+
function add_dependency( $type, $context, $handle, $src = false, $deps = array(), $ver = false, $ex = false ) {
|
1031 |
+
$args = func_get_args();
|
1032 |
+
// Remove type/context from arguments
|
1033 |
+
$args = array_slice( $args, 2 );
|
1034 |
+
|
1035 |
+
// Set context
|
1036 |
+
if ( ! is_array( $context ) ) {
|
1037 |
+
// Wrap single contexts in an array
|
1038 |
+
if ( is_string( $context ) ) {
|
1039 |
+
$context = array( $context );
|
1040 |
+
} else {
|
1041 |
+
$context = array();
|
1042 |
+
}
|
1043 |
+
}
|
1044 |
+
// Add file to instance property
|
1045 |
+
if ( isset( $this->{$type} ) && is_array( $this->{$type} ) ) {
|
1046 |
+
$this->{$type}[ $handle ] = array(
|
1047 |
+
'context' => $context,
|
1048 |
+
'params' => $args,
|
1049 |
+
);
|
1050 |
+
}
|
1051 |
+
}
|
1052 |
+
|
1053 |
+
/**
|
1054 |
+
* Add script to object to be added in specified contexts
|
1055 |
+
* @param array|string $context Array of contexts to add script to page
|
1056 |
+
* @see wp_enqueue_script for the following of the parameters
|
1057 |
+
* @param $handle
|
1058 |
+
* @param $src
|
1059 |
+
* @param $deps
|
1060 |
+
* @param $ver
|
1061 |
+
* @param $in_footer
|
1062 |
+
*/
|
1063 |
+
function add_script( $context, $handle, $src = false, $deps = array(), $ver = false, $in_footer = false ) {
|
1064 |
+
$args = func_get_args();
|
1065 |
+
// Add file type to front of arguments array
|
1066 |
+
array_unshift( $args, 'scripts' );
|
1067 |
+
call_user_func_array( $this->m( 'add_dependency' ), $args );
|
1068 |
+
}
|
1069 |
+
|
1070 |
+
/**
|
1071 |
+
* Retrieve script dependencies for object
|
1072 |
+
* @return array Script dependencies
|
1073 |
+
*/
|
1074 |
+
function get_scripts() {
|
1075 |
+
return $this->get_member_value( 'scripts', '', array() );
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
/**
|
1079 |
+
* Add style to object to be added in specified contexts
|
1080 |
+
* @param array|string $context Array of contexts to add style to page
|
1081 |
+
* @see wp_enqueue_style for the following of the parameters
|
1082 |
+
* @param $handle
|
1083 |
+
* @param $src
|
1084 |
+
* @param $deps
|
1085 |
+
* @param $ver
|
1086 |
+
* @param $in_footer
|
1087 |
+
*/
|
1088 |
+
function add_style( $handle, $src = false, $deps = array(), $ver = false, $media = false ) {
|
1089 |
+
$args = func_get_args();
|
1090 |
+
array_unshift( $args, 'styles' );
|
1091 |
+
call_user_func_array( $this->m( 'add_dependency' ), $args );
|
1092 |
+
}
|
1093 |
+
|
1094 |
+
/**
|
1095 |
+
* Retrieve Style dependencies for object
|
1096 |
+
* @return array Style dependencies
|
1097 |
+
*/
|
1098 |
+
function get_styles() {
|
1099 |
+
return $this->get_member_value( 'styles', '', array() );
|
1100 |
+
}
|
1101 |
+
|
1102 |
+
/* Helpers */
|
1103 |
+
|
1104 |
+
/**
|
1105 |
+
* Format value based on specified context
|
1106 |
+
* @param mixed $value Value to format
|
1107 |
+
* @param string $context Current context
|
1108 |
+
* @return mixed Formatted value
|
1109 |
+
*/
|
1110 |
+
function format( $value, $context = '' ) {
|
1111 |
+
if ( is_scalar( $context ) && ! empty( $context ) ) {
|
1112 |
+
$handler = 'format_' . trim( strval( $context ) );
|
1113 |
+
// Only process if context is valid and has a handler
|
1114 |
+
if ( ! empty( $context ) && method_exists( $this, $handler ) ) {
|
1115 |
+
// Pass value to handler
|
1116 |
+
$value = $this->{$handler}( $value, $context );
|
1117 |
+
}
|
1118 |
+
}
|
1119 |
+
// Return formatted value
|
1120 |
+
return $value;
|
1121 |
+
}
|
1122 |
+
|
1123 |
+
/**
|
1124 |
+
* Format value for output as an attribute.
|
1125 |
+
*
|
1126 |
+
* Only strings are formatted.
|
1127 |
+
*
|
1128 |
+
* @since 2.8.0
|
1129 |
+
*
|
1130 |
+
* @param mixed $value Value to format.
|
1131 |
+
* @return mixed Formatted value.
|
1132 |
+
*/
|
1133 |
+
function format_attr( $value ) {
|
1134 |
+
if ( is_string( $value ) ) {
|
1135 |
+
$value = esc_attr( $value );
|
1136 |
+
}
|
1137 |
+
return $value;
|
1138 |
+
}
|
1139 |
+
|
1140 |
+
/**
|
1141 |
+
* Formats value for output as plain text.
|
1142 |
+
*
|
1143 |
+
* Escapes HTML, etc.
|
1144 |
+
* Only strings are formatted.
|
1145 |
+
*
|
1146 |
+
* @since 2.8.0
|
1147 |
+
*
|
1148 |
+
* @param mixed $value Value to format.
|
1149 |
+
* @return mixed Formatted value.
|
1150 |
+
*/
|
1151 |
+
function format_text( $value ) {
|
1152 |
+
if ( is_string( $value ) ) {
|
1153 |
+
$value = esc_html( $value );
|
1154 |
+
}
|
1155 |
+
return $value;
|
1156 |
+
}
|
1157 |
+
|
1158 |
+
/**
|
1159 |
+
* Final formatting before output
|
1160 |
+
* Restores special characters, etc.
|
1161 |
+
* @uses $special_chars
|
1162 |
+
* @uses $special_chars_default
|
1163 |
+
* @param mixed $value Pre-final field output
|
1164 |
+
* @param string $context (Optional) Formatting context
|
1165 |
+
* @return mixed Formatted value
|
1166 |
+
*/
|
1167 |
+
function format_final( $value, $context = '' ) {
|
1168 |
+
if ( ! is_string( $value ) ) {
|
1169 |
+
return $value;
|
1170 |
+
}
|
1171 |
+
|
1172 |
+
// Restore special chars
|
1173 |
+
return $this->restore_special_chars( $value, $context );
|
1174 |
+
}
|
1175 |
+
|
1176 |
+
function preserve_special_chars( $value, $context = '' ) {
|
1177 |
+
if ( ! is_string( $value ) ) {
|
1178 |
+
return $value;
|
1179 |
+
}
|
1180 |
+
$specials = $this->get_special_chars();
|
1181 |
+
return str_replace( array_keys( $specials ), $specials, $value );
|
1182 |
+
}
|
1183 |
+
|
1184 |
+
function restore_special_chars( $value, $context = '' ) {
|
1185 |
+
if ( ! is_string( $value ) ) {
|
1186 |
+
return $value;
|
1187 |
+
}
|
1188 |
+
$specials = $this->get_special_chars();
|
1189 |
+
return str_replace( $specials, array_keys( $specials ), $value );
|
1190 |
+
}
|
1191 |
+
|
1192 |
+
/**
|
1193 |
+
* Retrieve special characters/placeholders
|
1194 |
+
* Merges defaults with class-specific characters
|
1195 |
+
* @uses $special_chars
|
1196 |
+
* @uses $special_chars_default
|
1197 |
+
* @return array Special characters/placeholders
|
1198 |
+
*/
|
1199 |
+
function get_special_chars() {
|
1200 |
+
return wp_parse_args( $this->special_chars, $this->special_chars_default );
|
1201 |
+
}
|
1202 |
+
}
|
includes/class.field_collection.php
CHANGED
@@ -1,768 +1,842 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Managed collection of fields
|
4 |
-
* @package Simple Lightbox
|
5 |
-
* @subpackage Fields
|
6 |
-
* @author Archetyped
|
7 |
-
*/
|
8 |
-
class SLB_Field_Collection extends SLB_Field_Base {
|
9 |
-
|
10 |
-
/* Configuration */
|
11 |
-
|
12 |
-
protected $mode = 'sub';
|
13 |
-
|
14 |
-
/* Properties */
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Item type
|
18 |
-
* @var string
|
19 |
-
*/
|
20 |
-
|
21 |
-
|
22 |
-
/**
|
23 |
-
* Indexed array of items in collection
|
24 |
-
* @var array
|
25 |
-
*/
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
'groups'
|
30 |
-
'context'
|
31 |
-
'layout'
|
32 |
-
'build'
|
33 |
-
'build_groups'
|
34 |
-
);
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Associative array of groups in collection
|
38 |
-
* Key: Group ID
|
39 |
-
* Value: object of group properties
|
40 |
-
* > id
|
41 |
-
* > title
|
42 |
-
* > description string Group description
|
43 |
-
* > items array Items in group
|
44 |
-
* @var array
|
45 |
-
*/
|
46 |
-
|
47 |
-
|
48 |
-
protected $properties_init = null;
|
49 |
-
|
50 |
-
/* Constructors */
|
51 |
-
|
52 |
-
/**
|
53 |
-
* Class constructor
|
54 |
-
* @uses parent::__construct()
|
55 |
-
* @uses self::make_properties()
|
56 |
-
* @uses self::init()
|
57 |
-
* @uses self::add_groups()
|
58 |
-
* @uses self::add_items()
|
59 |
-
* @param string $id Collection ID
|
60 |
-
* @param array $properties (optional) Properties to set for collection (Default: none)
|
61 |
-
*/
|
62 |
-
public function __construct($id, $properties = null) {
|
63 |
-
$args
|
64 |
-
$properties = $this->make_properties($args);
|
65 |
-
// Parent constructor
|
66 |
-
parent::__construct($properties);
|
67 |
-
|
68 |
-
// Save initial properties
|
69 |
-
$this->properties_init = $properties;
|
70 |
-
}
|
71 |
-
|
72 |
-
public function _init() {
|
73 |
-
parent::_init();
|
74 |
-
|
75 |
-
// Load properties.
|
76 |
-
$this->load($this->properties_init, false);
|
77 |
-
|
78 |
-
// Add custom ID format(s).
|
79 |
-
$this->add_id_format(
|
80 |
-
'formatted',
|
81 |
-
[
|
82 |
-
'wrap' => [ 'open' => '_' ],
|
83 |
-
'prefix' => [ 'get_prefix' ],
|
84 |
-
'recursive' => false,
|
85 |
-
]
|
86 |
-
);
|
87 |
-
}
|
88 |
-
|
89 |
-
/*-** Getters/Setters **-*/
|
90 |
-
|
91 |
-
/* Setup */
|
92 |
-
|
93 |
-
/**
|
94 |
-
* Load collection with specified properties
|
95 |
-
* Updates existing properties
|
96 |
-
* @param array $properties Properties to load
|
97 |
-
* @param bool $update (optional) Update (TRUE) or overwrite (FALSE) items/groups (Default: TRUE)
|
98 |
-
* @return object Current instance
|
99 |
-
*/
|
100 |
-
public function load($properties, $update = true) {
|
101 |
-
$args
|
102 |
-
$properties = $this->make_properties($args);
|
103 |
-
if ( !empty($properties) ) {
|
104 |
-
// Groups
|
105 |
-
if ( isset($properties['groups']) ) {
|
106 |
-
$this->add_groups($properties['groups'], $update);
|
107 |
-
}
|
108 |
-
// Items
|
109 |
-
if ( isset($properties['items']) ) {
|
110 |
-
$this->add_items($properties['items'], $update);
|
111 |
-
}
|
112 |
-
}
|
113 |
-
return $this;
|
114 |
-
}
|
115 |
-
|
116 |
-
/* Data */
|
117 |
-
|
118 |
-
/**
|
119 |
-
* Retrieve external data for items in collection
|
120 |
-
* Retrieved data is saved to the collection's $data property
|
121 |
-
* Uses class properties to determine how data is retrieved
|
122 |
-
* Examples:
|
123 |
-
* > DB
|
124 |
-
* > XML
|
125 |
-
* > JSON
|
126 |
-
* @return void
|
127 |
-
*/
|
128 |
-
function load_data() {
|
129 |
-
$this->data_loaded = true;
|
130 |
-
}
|
131 |
-
|
132 |
-
/**
|
133 |
-
* Set data for an item
|
134 |
-
* @param mixed $item Field to set data for
|
135 |
-
* > string
|
136 |
-
* > object
|
137 |
-
* > array
|
138 |
-
* @param mixed $value Data to set
|
139 |
-
* @param bool $save (optional) Whether or not data should be saved to DB (Default: Yes)
|
140 |
-
*/
|
141 |
-
function set_data($item, $value = '', $save = true, $force_set = false) {
|
142 |
-
// Set data for entire collection
|
143 |
-
if ( is_array($item) ) {
|
144 |
-
$this->data = wp_parse_args($item, $this->data);
|
145 |
-
// Update save option
|
146 |
-
$args = func_get_args();
|
147 |
-
if ( 2
|
148 |
-
$save = $args[1];
|
149 |
-
}
|
150 |
-
}
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
// Set data
|
155 |
-
if ( is_string($item) && !empty($item) && ( isset($this->items[$item]) ||
|
156 |
-
$this->data[$item] = $value;
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
*
|
167 |
-
* @param
|
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 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
$
|
200 |
-
|
201 |
-
|
202 |
-
//
|
203 |
-
$
|
204 |
-
$item
|
205 |
-
}
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
}
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
$
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
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 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
$
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
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 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
}
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
}
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
}
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
*
|
419 |
-
*
|
420 |
-
* @param
|
421 |
-
* @
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
}
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
*
|
456 |
-
* @param string $
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
*
|
511 |
-
*
|
512 |
-
*
|
513 |
-
*
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
*
|
572 |
-
*
|
573 |
-
* @param string|object $
|
574 |
-
* @param
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
if (
|
581 |
-
return false;
|
582 |
-
|
583 |
-
//
|
584 |
-
if (
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
//
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
/**
|
704 |
-
*
|
705 |
-
*
|
706 |
-
*/
|
707 |
-
function
|
708 |
-
|
709 |
-
$
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
*
|
731 |
-
* @
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
$this->
|
767 |
-
|
768 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Managed collection of fields
|
4 |
+
* @package Simple Lightbox
|
5 |
+
* @subpackage Fields
|
6 |
+
* @author Archetyped
|
7 |
+
*/
|
8 |
+
class SLB_Field_Collection extends SLB_Field_Base {
|
9 |
+
|
10 |
+
/* Configuration */
|
11 |
+
|
12 |
+
protected $mode = 'sub';
|
13 |
+
|
14 |
+
/* Properties */
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Item type
|
18 |
+
* @var string
|
19 |
+
*/
|
20 |
+
public $item_type = 'SLB_Field';
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Indexed array of items in collection
|
24 |
+
* @var array
|
25 |
+
*/
|
26 |
+
public $items = array();
|
27 |
+
|
28 |
+
public $build_vars_default = array(
|
29 |
+
'groups' => array(),
|
30 |
+
'context' => '',
|
31 |
+
'layout' => 'form',
|
32 |
+
'build' => true,
|
33 |
+
'build_groups' => true,
|
34 |
+
);
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Associative array of groups in collection
|
38 |
+
* Key: Group ID
|
39 |
+
* Value: object of group properties
|
40 |
+
* > id
|
41 |
+
* > title
|
42 |
+
* > description string Group description
|
43 |
+
* > items array Items in group
|
44 |
+
* @var array
|
45 |
+
*/
|
46 |
+
public $groups = array();
|
47 |
+
|
48 |
+
protected $properties_init = null;
|
49 |
+
|
50 |
+
/* Constructors */
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Class constructor
|
54 |
+
* @uses parent::__construct()
|
55 |
+
* @uses self::make_properties()
|
56 |
+
* @uses self::init()
|
57 |
+
* @uses self::add_groups()
|
58 |
+
* @uses self::add_items()
|
59 |
+
* @param string $id Collection ID
|
60 |
+
* @param array $properties (optional) Properties to set for collection (Default: none)
|
61 |
+
*/
|
62 |
+
public function __construct( $id, $properties = null ) {
|
63 |
+
$args = func_get_args();
|
64 |
+
$properties = $this->make_properties( $args );
|
65 |
+
// Parent constructor
|
66 |
+
parent::__construct( $properties );
|
67 |
+
|
68 |
+
// Save initial properties
|
69 |
+
$this->properties_init = $properties;
|
70 |
+
}
|
71 |
+
|
72 |
+
public function _init() {
|
73 |
+
parent::_init();
|
74 |
+
|
75 |
+
// Load properties.
|
76 |
+
$this->load( $this->properties_init, false );
|
77 |
+
|
78 |
+
// Add custom ID format(s).
|
79 |
+
$this->add_id_format(
|
80 |
+
'formatted',
|
81 |
+
[
|
82 |
+
'wrap' => [ 'open' => '_' ],
|
83 |
+
'prefix' => [ 'get_prefix' ],
|
84 |
+
'recursive' => false,
|
85 |
+
]
|
86 |
+
);
|
87 |
+
}
|
88 |
+
|
89 |
+
/*-** Getters/Setters **-*/
|
90 |
+
|
91 |
+
/* Setup */
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Load collection with specified properties
|
95 |
+
* Updates existing properties
|
96 |
+
* @param array $properties Properties to load
|
97 |
+
* @param bool $update (optional) Update (TRUE) or overwrite (FALSE) items/groups (Default: TRUE)
|
98 |
+
* @return object Current instance
|
99 |
+
*/
|
100 |
+
public function load( $properties, $update = true ) {
|
101 |
+
$args = func_get_args();
|
102 |
+
$properties = $this->make_properties( $args );
|
103 |
+
if ( ! empty( $properties ) ) {
|
104 |
+
// Groups
|
105 |
+
if ( isset( $properties['groups'] ) ) {
|
106 |
+
$this->add_groups( $properties['groups'], $update );
|
107 |
+
}
|
108 |
+
// Items
|
109 |
+
if ( isset( $properties['items'] ) ) {
|
110 |
+
$this->add_items( $properties['items'], $update );
|
111 |
+
}
|
112 |
+
}
|
113 |
+
return $this;
|
114 |
+
}
|
115 |
+
|
116 |
+
/* Data */
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Retrieve external data for items in collection
|
120 |
+
* Retrieved data is saved to the collection's $data property
|
121 |
+
* Uses class properties to determine how data is retrieved
|
122 |
+
* Examples:
|
123 |
+
* > DB
|
124 |
+
* > XML
|
125 |
+
* > JSON
|
126 |
+
* @return void
|
127 |
+
*/
|
128 |
+
function load_data() {
|
129 |
+
$this->data_loaded = true;
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Set data for an item
|
134 |
+
* @param mixed $item Field to set data for
|
135 |
+
* > string Field ID
|
136 |
+
* > object Field Reference
|
137 |
+
* > array Data for multiple items (associative array [field ID => data])
|
138 |
+
* @param mixed $value Data to set
|
139 |
+
* @param bool $save (optional) Whether or not data should be saved to DB (Default: Yes)
|
140 |
+
*/
|
141 |
+
function set_data( $item, $value = '', $save = true, $force_set = false ) {
|
142 |
+
// Set data for entire collection
|
143 |
+
if ( is_array( $item ) ) {
|
144 |
+
$this->data = wp_parse_args( $item, $this->data );
|
145 |
+
// Update save option
|
146 |
+
$args = func_get_args();
|
147 |
+
if ( 2 === count( $args ) && is_bool( $args[1] ) ) {
|
148 |
+
$save = $args[1];
|
149 |
+
}
|
150 |
+
} elseif ( is_object( $item ) && method_exists( $item, 'get_id' ) ) {
|
151 |
+
// Get $item's ID
|
152 |
+
$item = $item->get_id();
|
153 |
+
}
|
154 |
+
// Set data
|
155 |
+
if ( is_string( $item ) && ! empty( $item ) && ( isset( $this->items[ $item ] ) || ! ! $force_set ) ) {
|
156 |
+
$this->data[ $item ] = $value;
|
157 |
+
}
|
158 |
+
if ( ! ! $save ) {
|
159 |
+
$this->save();
|
160 |
+
}
|
161 |
+
}
|
162 |
+
|
163 |
+
/* Item */
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Adds item to collection
|
167 |
+
* @param string|obj $id Unique name for item or item instance
|
168 |
+
* @param array $properties (optional) Item properties
|
169 |
+
* @param bool $update (optional) Update or overwrite existing item (Default: FALSE)
|
170 |
+
* @return object Newly-added item
|
171 |
+
*/
|
172 |
+
function add( $id, $properties = array(), $update = false ) {
|
173 |
+
$item = null;
|
174 |
+
$args = func_get_args();
|
175 |
+
// Get properties.
|
176 |
+
foreach ( array_reverse( $args ) as $arg ) {
|
177 |
+
if ( is_array( $arg ) ) {
|
178 |
+
$properties = $arg;
|
179 |
+
break;
|
180 |
+
}
|
181 |
+
}
|
182 |
+
if ( ! is_array( $properties ) ) {
|
183 |
+
$properties = array();
|
184 |
+
}
|
185 |
+
|
186 |
+
// Prep item.
|
187 |
+
if ( $id instanceof $this->item_type ) {
|
188 |
+
// Use existing item.
|
189 |
+
$item = $id;
|
190 |
+
$item->set_properties( $properties );
|
191 |
+
} elseif ( class_exists( $this->item_type ) ) {
|
192 |
+
// Create new item.
|
193 |
+
$defaults = array(
|
194 |
+
'parent' => null,
|
195 |
+
'group' => null,
|
196 |
+
);
|
197 |
+
$properties = array_merge( $defaults, $properties );
|
198 |
+
if ( is_string( $id ) ) {
|
199 |
+
$properties['id'] = $id;
|
200 |
+
}
|
201 |
+
if ( ! ! $update && $this->has( $properties['id'] ) ) {
|
202 |
+
// Update existing item
|
203 |
+
$item = $this->get( $properties['id'] );
|
204 |
+
$item->set_properties( $properties );
|
205 |
+
} else {
|
206 |
+
// Init item
|
207 |
+
$type = $this->item_type;
|
208 |
+
$item = new $type( $properties );
|
209 |
+
}
|
210 |
+
}
|
211 |
+
|
212 |
+
if ( empty( $item ) || strlen( $item->get_id() ) === 0 ) {
|
213 |
+
return false;
|
214 |
+
}
|
215 |
+
|
216 |
+
// Set container
|
217 |
+
$item->set_container( $this );
|
218 |
+
|
219 |
+
// Add item to collection
|
220 |
+
$this->items[ $item->get_id() ] = $item;
|
221 |
+
|
222 |
+
if ( isset( $properties['group'] ) ) {
|
223 |
+
$this->add_to_group( $properties['group'], $item->get_id() );
|
224 |
+
}
|
225 |
+
|
226 |
+
return $item;
|
227 |
+
}
|
228 |
+
|
229 |
+
/**
|
230 |
+
* Removes item from collection
|
231 |
+
* @param string|object $item Object or item ID to remove
|
232 |
+
* @param bool $save (optional) Whether to save the collection after removing item (Default: YES)
|
233 |
+
*/
|
234 |
+
function remove( $item, $save = true ) {
|
235 |
+
// Remove item
|
236 |
+
if ( $this->has( $item ) ) {
|
237 |
+
$item = $this->get( $item );
|
238 |
+
$item = $item->get_id();
|
239 |
+
// Remove from items array
|
240 |
+
unset( $this->items[ $item ] );
|
241 |
+
// Remove item from groups
|
242 |
+
$this->remove_from_group( $item );
|
243 |
+
}
|
244 |
+
// Remove item data from collection
|
245 |
+
$this->remove_data( $item, false );
|
246 |
+
|
247 |
+
if ( ! ! $save ) {
|
248 |
+
$this->save();
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Remove item data from collection
|
254 |
+
* @param string|object $item Object or item ID to remove
|
255 |
+
* @param bool $save (optional) Whether to save the collection after removing item (Default: YES)
|
256 |
+
*/
|
257 |
+
function remove_data( $item, $save = true ) {
|
258 |
+
// Get item ID from object
|
259 |
+
if ( $this->has( $item ) ) {
|
260 |
+
$item = $this->get( $item );
|
261 |
+
$item = $item->get_id();
|
262 |
+
}
|
263 |
+
|
264 |
+
// Remove data from data member
|
265 |
+
if ( is_string( $item ) && is_array( $this->data ) ) {
|
266 |
+
unset( $this->data[ $item ] );
|
267 |
+
if ( ! ! $save ) {
|
268 |
+
$this->save();
|
269 |
+
}
|
270 |
+
}
|
271 |
+
}
|
272 |
+
|
273 |
+
/**
|
274 |
+
* Checks if item exists in the collection.
|
275 |
+
*
|
276 |
+
* @param string|object $item Item ID or instance.
|
277 |
+
* @return bool True if item is in collection, False otherwise.
|
278 |
+
*/
|
279 |
+
function has( $item ) {
|
280 |
+
// Item ID.
|
281 |
+
if ( is_string( $item ) ) {
|
282 |
+
return in_array( $item, array_keys( $this->get_items() ), true );
|
283 |
+
}
|
284 |
+
// Item instance.
|
285 |
+
if ( $item instanceof $this->item_type ) {
|
286 |
+
$items = $this->get_items( null, false );
|
287 |
+
$id = $item->get_id();
|
288 |
+
return ( isset( $items[ $id ] ) && $item === $items[ $id ] );
|
289 |
+
}
|
290 |
+
return false;
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Retrieve specified item in collection.
|
295 |
+
*
|
296 |
+
* @param string|object $item Item ID or instance to retrieve.
|
297 |
+
* @return SLB_Field|null Specified item. Null if item is not in collection.
|
298 |
+
*/
|
299 |
+
function get( $item, $safe_mode = false ) {
|
300 |
+
$invalid = null;
|
301 |
+
// Stop processing if item is not in collection.
|
302 |
+
if ( ! $this->has( $item ) ) {
|
303 |
+
return $invalid;
|
304 |
+
}
|
305 |
+
// Get item instance from ID.
|
306 |
+
if ( is_string( $item ) ) {
|
307 |
+
$items = $this->get_items( null, false );
|
308 |
+
if ( isset( $items[ $item ] ) ) {
|
309 |
+
$item = $items[ $item ];
|
310 |
+
}
|
311 |
+
}
|
312 |
+
// Return valid item instance.
|
313 |
+
if ( $item instanceof $this->item_type ) {
|
314 |
+
return $item;
|
315 |
+
}
|
316 |
+
// Invalid item.
|
317 |
+
return $invalid;
|
318 |
+
}
|
319 |
+
|
320 |
+
/**
|
321 |
+
* Retrieve item data
|
322 |
+
* @param $item Item to get data for
|
323 |
+
* @param $context (optional) Context
|
324 |
+
* @param $top (optional) Iterate through ancestors to get data (Default: Yes)
|
325 |
+
* @return mixed|null Item data. Null if no data retrieved.
|
326 |
+
*/
|
327 |
+
function get_data( $item = null, $context = '', $top = true ) {
|
328 |
+
$this->load_data();
|
329 |
+
$ret = null;
|
330 |
+
if ( $this->has( $item ) ) {
|
331 |
+
$item = $this->get( $item );
|
332 |
+
$ret = $item->get_data( $context, $top );
|
333 |
+
} else {
|
334 |
+
$ret = parent::get_data( $context, $top );
|
335 |
+
}
|
336 |
+
|
337 |
+
if ( is_string( $item ) && is_array( $ret ) && isset( $ret[ $item ] ) ) {
|
338 |
+
$ret = $ret[ $item ];
|
339 |
+
}
|
340 |
+
return $ret;
|
341 |
+
}
|
342 |
+
|
343 |
+
/* Items (Collection) */
|
344 |
+
|
345 |
+
/**
|
346 |
+
* Add multiple items to collection
|
347 |
+
* @param array $items Items to add to collection
|
348 |
+
* Array Structure:
|
349 |
+
* > Key (string): Item ID
|
350 |
+
* > Val (array): Item properties
|
351 |
+
* @return void
|
352 |
+
*/
|
353 |
+
function add_items( $items = array(), $update = false ) {
|
354 |
+
// Validate
|
355 |
+
if ( ! is_array( $items ) || empty( $items ) ) {
|
356 |
+
return false;
|
357 |
+
}
|
358 |
+
// Add items
|
359 |
+
foreach ( $items as $id => $props ) {
|
360 |
+
$this->add( $id, $props, $update );
|
361 |
+
}
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Retrieve reference to items in collection
|
366 |
+
* @return array Collection items (reference)
|
367 |
+
*/
|
368 |
+
function &get_items( $group = null, $sort = 'priority' ) {
|
369 |
+
$gset = $this->group_exists( $group );
|
370 |
+
if ( $gset ) {
|
371 |
+
$items = $this->get_group_items( $group );
|
372 |
+
} elseif ( ! empty( $group ) ) {
|
373 |
+
$items = array();
|
374 |
+
} else {
|
375 |
+
$items = $this->items;
|
376 |
+
}
|
377 |
+
if ( ! empty( $items ) ) {
|
378 |
+
// Sort items
|
379 |
+
if ( ! empty( $sort ) && is_string( $sort ) ) {
|
380 |
+
if ( 'priority' === $sort ) {
|
381 |
+
if ( $gset ) {
|
382 |
+
// Sort by priority
|
383 |
+
ksort( $items, SORT_NUMERIC );
|
384 |
+
}
|
385 |
+
}
|
386 |
+
}
|
387 |
+
// Release from buckets
|
388 |
+
if ( $gset ) {
|
389 |
+
$items = call_user_func_array( 'array_merge', $items );
|
390 |
+
}
|
391 |
+
}
|
392 |
+
return $items;
|
393 |
+
}
|
394 |
+
|
395 |
+
/**
|
396 |
+
* Build output for items in specified group
|
397 |
+
* If no group specified, all items in collection are built
|
398 |
+
* @param string|object $group (optional) Group to build items for (ID or instance object)
|
399 |
+
*/
|
400 |
+
function build_items( $group = null ) {
|
401 |
+
// Get group items
|
402 |
+
$items =& $this->get_items( $group );
|
403 |
+
if ( empty( $items ) ) {
|
404 |
+
return false;
|
405 |
+
}
|
406 |
+
|
407 |
+
$this->util->do_action_ref_array( 'build_items_pre', array( $this ) );
|
408 |
+
foreach ( $items as $item ) {
|
409 |
+
$item->build();
|
410 |
+
}
|
411 |
+
$this->util->do_action_ref_array( 'build_items_post', array( $this ) );
|
412 |
+
}
|
413 |
+
|
414 |
+
/* Group */
|
415 |
+
|
416 |
+
/**
|
417 |
+
* Sanitizes group ID.
|
418 |
+
*
|
419 |
+
* @param string $id Group ID.
|
420 |
+
* @param bool $fallback Optional. Use fallback group if ID is invalid. Default true.
|
421 |
+
* @return string Sanitized group ID.
|
422 |
+
*/
|
423 |
+
protected function sanitize_group_id( $id, $fallback = true ) {
|
424 |
+
// Sanitize.
|
425 |
+
$id = sanitize_title_with_dashes( $id );
|
426 |
+
// Use default ID (fallback).
|
427 |
+
if ( strlen( $id ) === 0 && ! ! $fallback ) {
|
428 |
+
$id = 'default';
|
429 |
+
}
|
430 |
+
return $id;
|
431 |
+
}
|
432 |
+
|
433 |
+
/**
|
434 |
+
* Add groups to collection
|
435 |
+
* @param array $groups Associative array of group properties
|
436 |
+
* Array structure:
|
437 |
+
* > Key (string): group ID
|
438 |
+
* > Val (string): Group Title
|
439 |
+
*/
|
440 |
+
function add_groups( $groups = array(), $update = false ) {
|
441 |
+
// Validate
|
442 |
+
if ( ! is_array( $groups ) || empty( $groups ) ) {
|
443 |
+
return false;
|
444 |
+
}
|
445 |
+
// Iterate
|
446 |
+
foreach ( $groups as $id => $props ) {
|
447 |
+
$this->add_group( $id, $props, null, $update );
|
448 |
+
}
|
449 |
+
}
|
450 |
+
|
451 |
+
/**
|
452 |
+
* Adds group to collection
|
453 |
+
* Groups are used to display related items in the UI
|
454 |
+
* @param string $id Unique name for group
|
455 |
+
* @param string $title Group title
|
456 |
+
* @param string $description Short description of group's purpose
|
457 |
+
* @param array $items (optional) ID's of existing items to add to group
|
458 |
+
* @return object Group object
|
459 |
+
*/
|
460 |
+
function &add_group( $id, $properties = array(), $items = array(), $update = false ) {
|
461 |
+
// Create new group and set properties
|
462 |
+
$default = array(
|
463 |
+
'title' => '',
|
464 |
+
'description' => '',
|
465 |
+
'priority' => 10,
|
466 |
+
);
|
467 |
+
$p = ( is_array( $properties ) ) ? array_merge( $default, $properties ) : $default;
|
468 |
+
if ( ! is_int( $p['priority'] ) || $p['priority'] < 0 ) {
|
469 |
+
$p['priority'] = $default['priority'];
|
470 |
+
}
|
471 |
+
$id = $this->sanitize_group_id( $id );
|
472 |
+
// Retrieve or init group
|
473 |
+
if ( ! ! $update && $this->group_exists( $id ) ) {
|
474 |
+
$grp = $this->get_group( $id );
|
475 |
+
$grp->title = $p['title'];
|
476 |
+
$grp->description = $p['description'];
|
477 |
+
$grp->priority = $p['priority'];
|
478 |
+
} else {
|
479 |
+
$this->groups[ $id ] =& $this->create_group( $id, $p['title'], $p['description'], $p['priority'] );
|
480 |
+
}
|
481 |
+
// Add items to group (if supplied)
|
482 |
+
if ( ! empty( $items ) && is_array( $items ) ) {
|
483 |
+
$this->add_to_group( $id, $items );
|
484 |
+
}
|
485 |
+
return $this->groups[ $id ];
|
486 |
+
}
|
487 |
+
|
488 |
+
/**
|
489 |
+
* Remove specified group from collection
|
490 |
+
* @param string $id Group ID to remove
|
491 |
+
*/
|
492 |
+
function remove_group( $id ) {
|
493 |
+
$id = trim( $id );
|
494 |
+
if ( $this->group_exists( $id ) ) {
|
495 |
+
unset( $this->groups[ $id ] );
|
496 |
+
}
|
497 |
+
}
|
498 |
+
|
499 |
+
/**
|
500 |
+
* Creates a new item group.
|
501 |
+
*
|
502 |
+
* @param string $title Group title (used in meta boxes, etc.)
|
503 |
+
* @param string $description Short description of group's purpose
|
504 |
+
* @param int $priority (optional) Group priority (e.g. used to sort groups during output)
|
505 |
+
* @return object {
|
506 |
+
* Group object.
|
507 |
+
*
|
508 |
+
* @type string $id ID.
|
509 |
+
* @type string $title Title.
|
510 |
+
* @type string $description Description.
|
511 |
+
* @type int $priority Priority (relative to other groups in collection).
|
512 |
+
* @type array $items {
|
513 |
+
* Group items. Grouped by item priority.
|
514 |
+
* Items indexed by item ID.
|
515 |
+
* Example: `$items[10]['item_id'] = {item}
|
516 |
+
* }
|
517 |
+
* }
|
518 |
+
*/
|
519 |
+
function &create_group( $id = '', $title = '', $description = '', $priority = 10 ) {
|
520 |
+
// Create new group object
|
521 |
+
$group = new stdClass();
|
522 |
+
/* Set group properties */
|
523 |
+
// Set ID
|
524 |
+
$id = ( is_scalar( $id ) ) ? trim( $id ) : '';
|
525 |
+
$group->id = $id;
|
526 |
+
// Set Title
|
527 |
+
$title = ( is_scalar( $title ) ) ? trim( $title ) : '';
|
528 |
+
$group->title = $title;
|
529 |
+
// Set Description
|
530 |
+
$description = ( is_scalar( $description ) ) ? trim( $description ) : '';
|
531 |
+
$group->description = $description;
|
532 |
+
// Priority
|
533 |
+
$group->priority = ( is_int( $priority ) ) ? $priority : 10;
|
534 |
+
// Create array to hold items
|
535 |
+
$group->items = array();
|
536 |
+
return $group;
|
537 |
+
}
|
538 |
+
|
539 |
+
/**
|
540 |
+
* Checks if group exists in collection.
|
541 |
+
*
|
542 |
+
* @param string|object $id Group name or object.
|
543 |
+
* @return bool True if group exists, False otherwise.
|
544 |
+
*/
|
545 |
+
function group_exists( $group ) {
|
546 |
+
if ( is_object( $group ) ) {
|
547 |
+
return true;
|
548 |
+
}
|
549 |
+
if ( ! is_string( $group ) ) {
|
550 |
+
return false;
|
551 |
+
}
|
552 |
+
$group = $this->sanitize_group_id( $group );
|
553 |
+
if ( strlen( $group ) === 0 ) {
|
554 |
+
return false;
|
555 |
+
}
|
556 |
+
// Check if group exists
|
557 |
+
return ( ! is_null( $this->get_member_value( 'groups', $group, null ) ) );
|
558 |
+
}
|
559 |
+
|
560 |
+
/**
|
561 |
+
* Adds item to a group in the collection.
|
562 |
+
*
|
563 |
+
* Group is created if it does not already exist.
|
564 |
+
*
|
565 |
+
* @param string|array $group {
|
566 |
+
* Group ID (or parameters array) to add item to.
|
567 |
+
*
|
568 |
+
* Array structure:
|
569 |
+
*
|
570 |
+
* @type string $0 Group ID.
|
571 |
+
* @type int $1 Item priority in group.
|
572 |
+
* }
|
573 |
+
* @param string|object|array $items Item ID/Instance or array of items to add to group.
|
574 |
+
* @param int $priority Optional. Default priority to set for items in group. Default 10.
|
575 |
+
* @return bool True if item(s) successfully added to group.
|
576 |
+
* False if item(s) not added to group.
|
577 |
+
*/
|
578 |
+
function add_to_group( $group, $items, $priority = 10 ) {
|
579 |
+
// Validate.
|
580 |
+
if ( empty( $items ) || empty( $group ) || ( ! is_string( $group ) && ! is_array( $group ) ) ) {
|
581 |
+
return false;
|
582 |
+
}
|
583 |
+
// Parse group properties.
|
584 |
+
if ( is_string( $group ) ) {
|
585 |
+
$gid = $group;
|
586 |
+
} elseif ( is_array( $group ) ) {
|
587 |
+
$group = array_values( $group );
|
588 |
+
if ( count( $group ) < 2 ) {
|
589 |
+
$group[] = $priority;
|
590 |
+
}
|
591 |
+
list( $gid, $priority ) = $group;
|
592 |
+
}
|
593 |
+
|
594 |
+
// Format group ID.
|
595 |
+
$gid = $this->sanitize_group_id( $gid );
|
596 |
+
if ( strlen( $gid ) === 0 ) {
|
597 |
+
return false;
|
598 |
+
}
|
599 |
+
|
600 |
+
// Item priority.
|
601 |
+
$priority = (int) $priority;
|
602 |
+
|
603 |
+
// Prepare items
|
604 |
+
if ( ! is_array( $items ) ) {
|
605 |
+
$items = [ $items ];
|
606 |
+
}
|
607 |
+
|
608 |
+
// Add Items.
|
609 |
+
$items_skipped = [];
|
610 |
+
foreach ( $items as $item ) {
|
611 |
+
// Skip if item is not in current collection.
|
612 |
+
$itm_ref = $this->get( $item );
|
613 |
+
if ( ! $itm_ref ) {
|
614 |
+
$items_skipped[] = $item;
|
615 |
+
continue;
|
616 |
+
}
|
617 |
+
// Remove item from all groups (items can only be in one group).
|
618 |
+
$this->remove_from_group( $itm_ref );
|
619 |
+
// Add reference to item in group.
|
620 |
+
$items =& $this->get_group( $gid )->items;
|
621 |
+
// Ensure priority level exists for group.
|
622 |
+
if ( ! isset( $items[ $priority ] ) ) {
|
623 |
+
$items[ $priority ] = array();
|
624 |
+
}
|
625 |
+
// Add item to group.
|
626 |
+
$items[ $priority ][ $itm_ref->get_id() ] = $itm_ref;
|
627 |
+
}
|
628 |
+
unset( $itm_ref );
|
629 |
+
return ( count( $items_skipped ) < count( $items ) );
|
630 |
+
}
|
631 |
+
|
632 |
+
/**
|
633 |
+
* Removes item from a group.
|
634 |
+
*
|
635 |
+
* If group is not specified, item is removed from all groups.
|
636 |
+
*
|
637 |
+
* @param string|object $item ID or object of item to remove from group.
|
638 |
+
* @param string|object|array $groups Optional. Group(s) to remove item from. Default null.
|
639 |
+
* - @type string Group ID.
|
640 |
+
* - @type object Group object.
|
641 |
+
* - @type array Multiple groups (ID or object).
|
642 |
+
* @return void
|
643 |
+
*/
|
644 |
+
function remove_from_group( $item, $groups = null ) {
|
645 |
+
// Validate item.
|
646 |
+
$item = $this->get( $item );
|
647 |
+
if ( ! $item ) {
|
648 |
+
return;
|
649 |
+
}
|
650 |
+
// Get item ID.
|
651 |
+
$item = $item->get_id();
|
652 |
+
// Validate item ID.
|
653 |
+
if ( ! $item ) {
|
654 |
+
return;
|
655 |
+
}
|
656 |
+
|
657 |
+
// Setup groups.
|
658 |
+
if ( is_string( $groups ) || is_object( $groups ) ) {
|
659 |
+
$groups = [ $groups ];
|
660 |
+
} elseif ( ! is_array( $groups ) ) {
|
661 |
+
$groups = array_keys( $this->get_groups() );
|
662 |
+
}
|
663 |
+
|
664 |
+
// Remove item from group(s).
|
665 |
+
foreach ( $groups as $group ) {
|
666 |
+
$group = $this->get_group( $group );
|
667 |
+
foreach ( array_keys( $group->items ) as $priority ) {
|
668 |
+
unset( $group->items[ $priority ][ $item ] );
|
669 |
+
}
|
670 |
+
}
|
671 |
+
}
|
672 |
+
|
673 |
+
/**
|
674 |
+
* Retrieves specified group.
|
675 |
+
*
|
676 |
+
* @param string|object $group Group ID or object to retrieve.
|
677 |
+
* @return object Reference to specified group.
|
678 |
+
*/
|
679 |
+
function &get_group( $group ) {
|
680 |
+
if ( is_object( $group ) ) {
|
681 |
+
return $group;
|
682 |
+
}
|
683 |
+
// Create group if it doesn't already exist.
|
684 |
+
if ( ! $this->group_exists( $group ) ) {
|
685 |
+
return $this->add_group( $group );
|
686 |
+
}
|
687 |
+
// Get existing group.
|
688 |
+
$group = $this->sanitize_group_id( $group );
|
689 |
+
return $this->get_member_value( 'groups', $group );
|
690 |
+
}
|
691 |
+
|
692 |
+
/**
|
693 |
+
* Retrieve a group's items
|
694 |
+
* @uses SLB_Field_Collection::get_group() to retrieve group object
|
695 |
+
* @param object|string $group Group object or group ID
|
696 |
+
* @return array Group's items
|
697 |
+
*/
|
698 |
+
function &get_group_items( $group ) {
|
699 |
+
$group =& $this->get_group( $group );
|
700 |
+
return $group->items;
|
701 |
+
}
|
702 |
+
|
703 |
+
/**
|
704 |
+
* Retrieve all groups in collection
|
705 |
+
* @return object[] Reference to group objects
|
706 |
+
*/
|
707 |
+
function &get_groups( $opts = array() ) {
|
708 |
+
$groups =& $this->get_member_value( 'groups' );
|
709 |
+
if ( is_array( $opts ) && ! empty( $opts ) ) {
|
710 |
+
extract( $opts, EXTR_SKIP );
|
711 |
+
if ( ! empty( $groups ) && ! empty( $sort ) && is_string( $sort ) ) {
|
712 |
+
if ( property_exists( current( $groups ), $sort ) ) {
|
713 |
+
// Sort groups by property
|
714 |
+
$sfunc = function ( $a, $b ) use ( $sort ) {
|
715 |
+
$ap = $a->$sort;
|
716 |
+
$bp = $b->$sort;
|
717 |
+
if ( $ap === $bp ) {
|
718 |
+
return 0;
|
719 |
+
}
|
720 |
+
return ( $ap > $bp ) ? 1 : -1;
|
721 |
+
};
|
722 |
+
uasort( $groups, $sfunc );
|
723 |
+
}
|
724 |
+
}
|
725 |
+
}
|
726 |
+
return $groups;
|
727 |
+
}
|
728 |
+
|
729 |
+
/**
|
730 |
+
* Output groups
|
731 |
+
* @uses self::build_vars to determine groups to build
|
732 |
+
*/
|
733 |
+
function build_groups() {
|
734 |
+
$this->util->do_action_ref_array( 'build_groups_pre', array( $this ) );
|
735 |
+
|
736 |
+
// Get groups to build
|
737 |
+
$groups = ( ! empty( $this->build_vars['groups'] ) ) ? $this->build_vars['groups'] : array_keys( $this->get_groups( array( 'sort' => 'priority' ) ) );
|
738 |
+
// Check options
|
739 |
+
if ( is_callable( $this->build_vars['build_groups'] ) ) {
|
740 |
+
// Pass groups to callback to build output
|
741 |
+
call_user_func_array( $this->build_vars['build_groups'], array( $this, $groups ) );
|
742 |
+
} elseif ( ! ! $this->build_vars['build_groups'] ) {
|
743 |
+
// Build groups
|
744 |
+
foreach ( $groups as $group ) {
|
745 |
+
$this->build_group( $group );
|
746 |
+
}
|
747 |
+
}
|
748 |
+
|
749 |
+
$this->util->do_action_ref_array( 'build_groups_post', array( $this ) );
|
750 |
+
}
|
751 |
+
|
752 |
+
/**
|
753 |
+
* Build group
|
754 |
+
*/
|
755 |
+
function build_group( $group ) {
|
756 |
+
if ( ! $this->group_exists( $group ) ) {
|
757 |
+
return false;
|
758 |
+
}
|
759 |
+
$group =& $this->get_group( $group );
|
760 |
+
// Stop processing if group contains no items
|
761 |
+
if ( ! count( $this->get_items( $group ) ) ) {
|
762 |
+
return false;
|
763 |
+
}
|
764 |
+
|
765 |
+
// Pre action
|
766 |
+
$this->util->do_action_ref_array( 'build_group_pre', array( $this, $group ) );
|
767 |
+
|
768 |
+
// Build items
|
769 |
+
$this->build_items( $group );
|
770 |
+
|
771 |
+
// Post action
|
772 |
+
$this->util->do_action_ref_array( 'build_group_post', array( $this, $group ) );
|
773 |
+
}
|
774 |
+
|
775 |
+
/* Collection */
|
776 |
+
|
777 |
+
/**
|
778 |
+
* Build entire collection of items
|
779 |
+
* Prints output
|
780 |
+
*/
|
781 |
+
function build( $build_vars = array() ) {
|
782 |
+
// Parse vars
|
783 |
+
$this->parse_build_vars( $build_vars );
|
784 |
+
$this->util->do_action_ref_array( 'build_init', array( $this ) );
|
785 |
+
// Pre-build output
|
786 |
+
$this->util->do_action_ref_array( 'build_pre', array( $this ) );
|
787 |
+
// Build groups
|
788 |
+
$this->build_groups();
|
789 |
+
// Post-build output
|
790 |
+
$this->util->do_action_ref_array( 'build_post', array( $this ) );
|
791 |
+
}
|
792 |
+
|
793 |
+
/**
|
794 |
+
* Set build variable
|
795 |
+
* @param string $key Variable name
|
796 |
+
* @param mixed $val Variable value
|
797 |
+
*/
|
798 |
+
function set_build_var( $key, $val ) {
|
799 |
+
$this->build_vars[ $key ] = $val;
|
800 |
+
}
|
801 |
+
|
802 |
+
/**
|
803 |
+
* Retrieve build variable
|
804 |
+
* @param string $key Variable name
|
805 |
+
* @param mixed $default Value if variable is not set
|
806 |
+
* @return mixed Variable value
|
807 |
+
*/
|
808 |
+
function get_build_var( $key, $default = null ) {
|
809 |
+
return ( array_key_exists( $key, $this->build_vars ) ) ? $this->build_vars[ $key ] : $default;
|
810 |
+
}
|
811 |
+
|
812 |
+
/**
|
813 |
+
* Delete build variable
|
814 |
+
* @param string $key Variable name to delete
|
815 |
+
*/
|
816 |
+
function delete_build_var( $key ) {
|
817 |
+
if ( array_key_exists( $key, $this->build_vars ) ) {
|
818 |
+
unset( $this->build_vars[ $key ] );
|
819 |
+
}
|
820 |
+
}
|
821 |
+
|
822 |
+
/**
|
823 |
+
* Parses build variables prior to use
|
824 |
+
* @uses this->reset_build_vars() to reset build variables for each request
|
825 |
+
* @param array $build_vars Variables to use for current request
|
826 |
+
*/
|
827 |
+
function parse_build_vars( $build_vars = array() ) {
|
828 |
+
$this->reset_build_vars();
|
829 |
+
$this->build_vars = $this->util->apply_filters( 'parse_build_vars', wp_parse_args( $build_vars, $this->build_vars ), $this );
|
830 |
+
}
|
831 |
+
|
832 |
+
/**
|
833 |
+
* Reset build variables to defaults
|
834 |
+
* Default Variables
|
835 |
+
* > groups - array - Names of groups to build
|
836 |
+
* > context - string - Context of current request
|
837 |
+
* > layout - string - Name of default layout to use
|
838 |
+
*/
|
839 |
+
function reset_build_vars() {
|
840 |
+
$this->build_vars = wp_parse_args( $this->build_vars, $this->build_vars_default );
|
841 |
+
}
|
842 |
+
}
|
includes/class.field_type.php
CHANGED
@@ -1,445 +1,462 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Field Types
|
4 |
-
* Stores properties for a specific field
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Fields
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Field_Type extends SLB_Field_Base {
|
10 |
-
/* Properties */
|
11 |
-
|
12 |
-
/**
|
13 |
-
* @var array Array of Field types that make up current Field type
|
14 |
-
*/
|
15 |
-
|
16 |
-
|
17 |
-
/**
|
18 |
-
* @var array Field type layouts
|
19 |
-
*/
|
20 |
-
|
21 |
-
|
22 |
-
/**
|
23 |
-
* @var SLB_Field_Type Parent field type (reference)
|
24 |
-
*/
|
25 |
-
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Object that field is in
|
29 |
-
* @var SLB_Field|SLB_Field_Type|SLB_Field_Collection
|
30 |
-
*/
|
31 |
-
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Object that called field
|
35 |
-
* Used to determine field hierarchy/nesting
|
36 |
-
* @var SLB_Field|SLB_Field_Type|SLB_Field_Collection
|
37 |
-
*/
|
38 |
-
|
39 |
-
|
40 |
-
function __construct($id = '', $parent = null) {
|
41 |
-
$args
|
42 |
-
$defaults = $this->integrate_id($id);
|
43 |
-
if ( !is_array($parent) )
|
44 |
-
$defaults['parent'] = $parent;
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
*
|
55 |
-
* @param string $
|
56 |
-
* @
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
*
|
66 |
-
* @param string $
|
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 |
-
$this->
|
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 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
*
|
241 |
-
*
|
242 |
-
|
243 |
-
|
244 |
-
|
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 |
-
|
281 |
-
|
282 |
-
$
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
$
|
292 |
-
|
293 |
-
$
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
//
|
300 |
-
|
301 |
-
|
302 |
-
}
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
$
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
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 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
$
|
373 |
-
|
374 |
-
$
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
*
|
380 |
-
* @param
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
//
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Field Types
|
4 |
+
* Stores properties for a specific field
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @subpackage Fields
|
7 |
+
* @author Archetyped
|
8 |
+
*/
|
9 |
+
class SLB_Field_Type extends SLB_Field_Base {
|
10 |
+
/* Properties */
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var array Array of Field types that make up current Field type
|
14 |
+
*/
|
15 |
+
public $elements = array();
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @var array Field type layouts
|
19 |
+
*/
|
20 |
+
public $layout = array();
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var SLB_Field_Type Parent field type (reference)
|
24 |
+
*/
|
25 |
+
public $parent = null;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Object that field is in
|
29 |
+
* @var SLB_Field|SLB_Field_Type|SLB_Field_Collection
|
30 |
+
*/
|
31 |
+
public $container = null;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Object that called field
|
35 |
+
* Used to determine field hierarchy/nesting
|
36 |
+
* @var SLB_Field|SLB_Field_Type|SLB_Field_Collection
|
37 |
+
*/
|
38 |
+
public $caller = null;
|
39 |
+
|
40 |
+
function __construct( $id = '', $parent = null ) {
|
41 |
+
$args = func_get_args();
|
42 |
+
$defaults = $this->integrate_id( $id );
|
43 |
+
if ( ! is_array( $parent ) ) {
|
44 |
+
$defaults['parent'] = $parent;
|
45 |
+
}
|
46 |
+
|
47 |
+
$props = $this->make_properties( $args, $defaults );
|
48 |
+
parent::__construct( $props );
|
49 |
+
}
|
50 |
+
|
51 |
+
/* Getters/Setters */
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Search for specified member value in field's container object (if exists)
|
55 |
+
* @param string $member Name of object member to search (e.g. properties, layout, etc.)
|
56 |
+
* @param string $name Value to retrieve from member
|
57 |
+
* @return mixed Member value if found (Default: empty string)
|
58 |
+
*/
|
59 |
+
function get_container_value( $member, $name = '', $default = '' ) {
|
60 |
+
$container =& $this->get_container();
|
61 |
+
return $this->get_object_value( $container, $member, $name, $default, 'container' );
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Search for specified member value in field's container object (if exists)
|
66 |
+
* @param string $member Name of object member to search (e.g. properties, layout, etc.)
|
67 |
+
* @param string $name Value to retrieve from member
|
68 |
+
* @return mixed Member value if found (Default: empty string)
|
69 |
+
*/
|
70 |
+
function get_caller_value( $member, $name = '', $default = '' ) {
|
71 |
+
$caller =& $this->get_caller();
|
72 |
+
return $this->get_object_value( $caller, $member, $name, $default, 'caller' );
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Sets reference to container object of current field
|
77 |
+
* Reference is cleared if no valid object is passed to method
|
78 |
+
* @param object $container
|
79 |
+
*/
|
80 |
+
function set_container( &$container ) {
|
81 |
+
if ( ! empty( $container ) && is_object( $container ) ) {
|
82 |
+
// Set as param as container for current field
|
83 |
+
$this->container =& $container;
|
84 |
+
} else {
|
85 |
+
// Clear container member if argument is invalid
|
86 |
+
$this->clear_container();
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Clears reference to container object of current field
|
92 |
+
*/
|
93 |
+
function clear_container() {
|
94 |
+
$this->container = null;
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Retrieves reference to container object of current field
|
99 |
+
* @return object Reference to container object
|
100 |
+
*/
|
101 |
+
function &get_container() {
|
102 |
+
$ret = null;
|
103 |
+
if ( $this->has_container() ) {
|
104 |
+
$ret =& $this->container;
|
105 |
+
}
|
106 |
+
return $ret;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Checks if field has a container reference
|
111 |
+
* @return bool TRUE if field is contained, FALSE otherwise
|
112 |
+
*/
|
113 |
+
function has_container() {
|
114 |
+
return ! empty( $this->container );
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Sets reference to calling object of current field
|
119 |
+
* Any existing reference is cleared if no valid object is passed to method
|
120 |
+
* @param object $caller Calling object
|
121 |
+
*/
|
122 |
+
function set_caller( &$caller ) {
|
123 |
+
if ( ! empty( $caller ) && is_object( $caller ) ) {
|
124 |
+
$this->caller =& $caller;
|
125 |
+
} else {
|
126 |
+
$this->clear_caller();
|
127 |
+
}
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Clears reference to calling object of current field
|
132 |
+
*/
|
133 |
+
function clear_caller() {
|
134 |
+
unset( $this->caller );
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Retrieves reference to caller object of current field
|
139 |
+
* @return object Reference to caller object
|
140 |
+
*/
|
141 |
+
function &get_caller() {
|
142 |
+
$ret = null;
|
143 |
+
if ( $this->has_caller() ) {
|
144 |
+
$ret =& $this->caller;
|
145 |
+
}
|
146 |
+
return $ret;
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Checks if field has a caller reference
|
151 |
+
* @return bool TRUE if field is called by another field, FALSE otherwise
|
152 |
+
*/
|
153 |
+
function has_caller() {
|
154 |
+
return ! empty( $this->caller );
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Sets an element for the field type
|
159 |
+
* @param string $name Name of element
|
160 |
+
* @param SLB_Field_Type $type Reference of field type to use for element
|
161 |
+
* @param array $properties Properties for element (passed as keyed associative array)
|
162 |
+
* @param string $id_prop Name of property to set $name to (e.g. ID, etc.)
|
163 |
+
*/
|
164 |
+
function set_element( $name, $type, $properties = array(), $id_prop = 'id' ) {
|
165 |
+
$name = trim( strval( $name ) );
|
166 |
+
if ( empty( $name ) ) {
|
167 |
+
return false;
|
168 |
+
}
|
169 |
+
// Create new field for element
|
170 |
+
$el = new SLB_Field( $name, $type );
|
171 |
+
// Set container to current field instance
|
172 |
+
$el->set_container( $this );
|
173 |
+
// Add properties to element
|
174 |
+
$el->set_properties( $properties );
|
175 |
+
// Save element to current instance
|
176 |
+
$this->elements[ $name ] =& $el;
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Add a layout to the field
|
181 |
+
* @param string $name Name of layout
|
182 |
+
* @param string $value Layout text
|
183 |
+
*/
|
184 |
+
function set_layout( $name, $value = '' ) {
|
185 |
+
if ( ! is_string( $name ) ) {
|
186 |
+
return false;
|
187 |
+
}
|
188 |
+
$name = trim( $name );
|
189 |
+
$this->layout[ $name ] = $value;
|
190 |
+
return true;
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Retrieve specified layout
|
195 |
+
* @param string $name Layout name
|
196 |
+
* @param bool $parse_nested (optional) Whether nested layouts should be expanded in retreived layout or not (Default: TRUE)
|
197 |
+
* @return string Specified layout text
|
198 |
+
*/
|
199 |
+
function get_layout( $name = 'form', $parse_nested = true ) {
|
200 |
+
// Retrieve specified layout (use $name value if no layout by that name exists)
|
201 |
+
if ( empty( $name ) ) {
|
202 |
+
$name = $this->get_container_value( 'build_vars', 'layout', 'form' );
|
203 |
+
}
|
204 |
+
$layout = $this->get_member_value( 'layout', $name, $name );
|
205 |
+
|
206 |
+
// Find all nested layouts in current layout
|
207 |
+
if ( ! empty( $layout ) && ! ! $parse_nested ) {
|
208 |
+
$ph = $this->get_placeholder_defaults();
|
209 |
+
// Check layout for placeholders.
|
210 |
+
$ph->match = $this->parse_layout( $layout, $ph->pattern_layout );
|
211 |
+
while ( ! empty( $ph->match ) ) {
|
212 |
+
// Iterate through the different types of layout placeholders
|
213 |
+
foreach ( $ph->match as $tag => $instances ) {
|
214 |
+
// Iterate through instances of a specific type of layout placeholder
|
215 |
+
foreach ( $instances as $instance ) {
|
216 |
+
// Get nested layout
|
217 |
+
$nested_layout = $this->get_member_value( $instance );
|
218 |
+
|
219 |
+
if ( empty( $nested_layout ) ) {
|
220 |
+
continue;
|
221 |
+
}
|
222 |
+
|
223 |
+
// Replace layout placeholder with retrieved item data.
|
224 |
+
$layout = str_replace( $ph->start . $instance['match'] . $ph->end, $nested_layout, $layout );
|
225 |
+
}
|
226 |
+
}
|
227 |
+
// Check layout for placeholders.
|
228 |
+
$ph->match = $this->parse_layout( $layout, $ph->pattern_layout );
|
229 |
+
}
|
230 |
+
}
|
231 |
+
|
232 |
+
return $layout;
|
233 |
+
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Checks if specified layout exists.
|
237 |
+
*
|
238 |
+
* Finds layout if it exists in current object or any of its parents.
|
239 |
+
*
|
240 |
+
* @param string $layout Name of layout to check for.
|
241 |
+
* @return bool True if layout exists, False otherwise.
|
242 |
+
*/
|
243 |
+
function has_layout( $layout ) {
|
244 |
+
if ( is_string( $layout ) && ! empty( trim( $layout ) ) ) {
|
245 |
+
return false;
|
246 |
+
}
|
247 |
+
$layout = $this->get_member_value( 'layout', trim( $layout ), false );
|
248 |
+
return ( false !== $layout );
|
249 |
+
}
|
250 |
+
|
251 |
+
/**
|
252 |
+
* Checks if layout content is valid
|
253 |
+
* Layouts need to have placeholders to be valid
|
254 |
+
* @param string $layout_content Layout content (markup)
|
255 |
+
* @return bool TRUE if layout is valid, FALSE otherwise
|
256 |
+
*/
|
257 |
+
function is_valid_layout( $layout_content ) {
|
258 |
+
$ph = $this->get_placeholder_defaults();
|
259 |
+
return preg_match( $ph->pattern_general, $layout_content );
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Parse field layout with a regular expression
|
264 |
+
* @param string $layout Layout data
|
265 |
+
* @param string $search Regular expression pattern to search layout for
|
266 |
+
* @return array Associative array containing all of the regular expression matches in the layout data
|
267 |
+
* Array Structure:
|
268 |
+
* root => placeholder tags
|
269 |
+
* => Tag instances (array)
|
270 |
+
* 'tag' => (string) tag name
|
271 |
+
* 'match' => (string) placeholder match
|
272 |
+
* 'attributes' => (array) attributes
|
273 |
+
*/
|
274 |
+
function parse_layout( $layout, $search ) {
|
275 |
+
$parse_match = '';
|
276 |
+
$result = [];
|
277 |
+
|
278 |
+
// Find all nested layouts in layout.
|
279 |
+
$match_value = preg_match_all( $search, $layout, $parse_match, PREG_PATTERN_ORDER );
|
280 |
+
|
281 |
+
// Stop if no matches found.
|
282 |
+
if ( ! $match_value ) {
|
283 |
+
return $result;
|
284 |
+
}
|
285 |
+
|
286 |
+
/* Process matches */
|
287 |
+
|
288 |
+
$ph_xml = '';
|
289 |
+
$ph_root_tag = 'ph_root_element';
|
290 |
+
$ph_start_xml = '<';
|
291 |
+
$ph_end_xml = ' />';
|
292 |
+
$ph_wrap_start = '<' . $ph_root_tag . '>';
|
293 |
+
$ph_wrap_end = '</' . $ph_root_tag . '>';
|
294 |
+
$parse_result = [];
|
295 |
+
|
296 |
+
// Get all matched elements.
|
297 |
+
$parse_match = $parse_match[1];
|
298 |
+
|
299 |
+
// Build XML string from placeholders.
|
300 |
+
foreach ( $parse_match as $ph ) {
|
301 |
+
$ph_xml .= $ph_start_xml . $ph . $ph_end_xml . ' ';
|
302 |
+
}
|
303 |
+
$ph_xml = $ph_wrap_start . $ph_xml . $ph_wrap_end;
|
304 |
+
// Parse XML data.
|
305 |
+
$ph_prs = xml_parser_create();
|
306 |
+
xml_parser_set_option( $ph_prs, XML_OPTION_SKIP_WHITE, 1 );
|
307 |
+
xml_parser_set_option( $ph_prs, XML_OPTION_CASE_FOLDING, 0 );
|
308 |
+
$ph_parsed = xml_parse_into_struct( $ph_prs, $ph_xml, $parse_result['values'], $parse_result['index'] );
|
309 |
+
xml_parser_free( $ph_prs );
|
310 |
+
|
311 |
+
// Stop if placeholder parsing failed.
|
312 |
+
if ( ! $ph_parsed ) {
|
313 |
+
return $result;
|
314 |
+
}
|
315 |
+
|
316 |
+
unset( $parse_result['index'][ $ph_root_tag ] );
|
317 |
+
|
318 |
+
// Build structured array with all parsed data.
|
319 |
+
$ph_default = [
|
320 |
+
'tag' => '',
|
321 |
+
'match' => '',
|
322 |
+
'attributes' => [],
|
323 |
+
];
|
324 |
+
|
325 |
+
// Build structured array.
|
326 |
+
foreach ( $parse_result['index'] as $tag => $instances ) {
|
327 |
+
// Create container for instances of current placeholder.
|
328 |
+
$result[ $tag ] = [];
|
329 |
+
// Process placeholder instances.
|
330 |
+
foreach ( $instances as $instance ) {
|
331 |
+
// Skip instance if it doesn't exist in parse results.
|
332 |
+
if ( ! isset( $parse_result['values'][ $instance ] ) ) {
|
333 |
+
continue;
|
334 |
+
}
|
335 |
+
// Stop processing instance if a previously-saved instance with the same options already exists.
|
336 |
+
foreach ( $result[ $tag ] as $tag_match ) {
|
337 |
+
if ( $tag_match['match'] === $parse_match[ $instance - 1 ] ) {
|
338 |
+
continue 2;
|
339 |
+
}
|
340 |
+
}
|
341 |
+
$instance_parsed = $parse_result['values'][ $instance ];
|
342 |
+
// Init instance data array.
|
343 |
+
$instance_data = $ph_default;
|
344 |
+
|
345 |
+
// Set tag.
|
346 |
+
$instance_data['tag'] = $instance_parsed['tag'];
|
347 |
+
|
348 |
+
// Set attributes.
|
349 |
+
if ( isset( $instance_parsed['attributes'] ) && is_array( $instance_parsed['attributes'] ) ) {
|
350 |
+
$instance_data['attributes'] = $instance_parsed['attributes'];
|
351 |
+
}
|
352 |
+
|
353 |
+
// Add match to array.
|
354 |
+
$instance_data['match'] = $parse_match[ $instance - 1 ];
|
355 |
+
|
356 |
+
// Add to result array.
|
357 |
+
$result[ $tag ][] = $instance_data;
|
358 |
+
}
|
359 |
+
}
|
360 |
+
|
361 |
+
return $result;
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Retrieves default properties to use when evaluating layout placeholders
|
366 |
+
* @return object Object with properties for evaluating layout placeholders
|
367 |
+
*/
|
368 |
+
function get_placeholder_defaults() {
|
369 |
+
$ph = new stdClass();
|
370 |
+
$ph->start = '{';
|
371 |
+
$ph->end = '}';
|
372 |
+
$ph->reserved = array( 'ref' => 'ref_base' );
|
373 |
+
$ph->pattern_general = '/' . $ph->start . '([a-zA-Z0-9_].*?)' . $ph->end . '/i';
|
374 |
+
$ph->pattern_layout = '/' . $ph->start . '([a-zA-Z0-9].*?\s+' . $ph->reserved['ref'] . '="layout.*?".*?)' . $ph->end . '/i';
|
375 |
+
return $ph;
|
376 |
+
}
|
377 |
+
|
378 |
+
/**
|
379 |
+
* Build item output
|
380 |
+
* @param string $layout (optional) Layout to build
|
381 |
+
* @param string $data Data to pass to layout
|
382 |
+
*/
|
383 |
+
function build( $layout = null, $data = null ) {
|
384 |
+
$this->util->do_action_ref_array( 'build_pre', array( $this ) );
|
385 |
+
echo $this->build_layout( $layout, $data );
|
386 |
+
$this->util->do_action_ref_array( 'build_post', array( $this ) );
|
387 |
+
}
|
388 |
+
|
389 |
+
/**
|
390 |
+
* Builds HTML for a field based on its properties
|
391 |
+
* @param string $layout (optional) Name of layout to build
|
392 |
+
* @param array $data Additional data for current item
|
393 |
+
*/
|
394 |
+
function build_layout( $layout = 'form', $data = null ) {
|
395 |
+
$out_default = '';
|
396 |
+
// Get base layout
|
397 |
+
$out = $this->get_layout( $layout );
|
398 |
+
// Only parse valid layouts
|
399 |
+
if ( $this->is_valid_layout( $out ) ) {
|
400 |
+
$out = $this->process_placeholders( $out, $layout, $data );
|
401 |
+
} else {
|
402 |
+
$out = $out_default;
|
403 |
+
}
|
404 |
+
/* Return generated value */
|
405 |
+
$out = $this->format_final( $out );
|
406 |
+
return $out;
|
407 |
+
}
|
408 |
+
|
409 |
+
/**
|
410 |
+
* Processes placeholders in a string.
|
411 |
+
*
|
412 |
+
* Finds and replaces placeholders in a string to their full values.
|
413 |
+
*
|
414 |
+
* @since 2.8.0
|
415 |
+
*
|
416 |
+
* @param string $str String with placeholders to replace.
|
417 |
+
* @param string $layout Optional. Name of layout being built.
|
418 |
+
* @param array $data Optional. Additional data for current item.
|
419 |
+
* @return string Original text with placeholders converted to full values.
|
420 |
+
*/
|
421 |
+
public function process_placeholders( $str, $layout = 'form', $data = null ) {
|
422 |
+
// Parse Layout.
|
423 |
+
$ph = $this->get_placeholder_defaults();
|
424 |
+
|
425 |
+
// Check layout for placeholders.
|
426 |
+
$ph->match = $this->parse_layout( $str, $ph->pattern_general );
|
427 |
+
|
428 |
+
// Parse placeholders in layout.
|
429 |
+
while ( ! empty( $ph->match ) ) {
|
430 |
+
// Iterate through placeholders (tag, id, etc.)
|
431 |
+
foreach ( $ph->match as $tag => $instances ) {
|
432 |
+
// Iterate through instances of current placeholder
|
433 |
+
foreach ( $instances as $instance ) {
|
434 |
+
// Process value based on placeholder name.
|
435 |
+
$target_property = $this->util->apply_filters_ref_array( "process_placeholder_${tag}", [ '', $this, &$instance, $layout, $data ], false );
|
436 |
+
// Process value using default processors (if necessary).
|
437 |
+
if ( '' === $target_property ) {
|
438 |
+
$target_property = $this->util->apply_filters_ref_array( 'process_placeholder', [ $target_property, $this, &$instance, $layout, $data ], false );
|
439 |
+
}
|
440 |
+
// Format output.
|
441 |
+
if ( ! is_null( $target_property ) ) {
|
442 |
+
$context = ( isset( $instance['attributes']['context'] ) ) ? $instance['attributes']['context'] : '';
|
443 |
+
// Handle special characters.
|
444 |
+
$target_property = $this->preserve_special_chars( $target_property, $context );
|
445 |
+
// Context-specific formatting.
|
446 |
+
$target_property = $this->format( $target_property, $context );
|
447 |
+
}
|
448 |
+
|
449 |
+
// Clear value if value not a string
|
450 |
+
if ( ! is_scalar( $target_property ) ) {
|
451 |
+
$target_property = '';
|
452 |
+
}
|
453 |
+
// Replace layout placeholder with retrieved item data
|
454 |
+
$str = str_replace( $ph->start . $instance['match'] . $ph->end, $target_property, $str );
|
455 |
+
}
|
456 |
+
}
|
457 |
+
// Check layout for placeholders.
|
458 |
+
$ph->match = $this->parse_layout( $str, $ph->pattern_general );
|
459 |
+
}
|
460 |
+
return $str;
|
461 |
+
}
|
462 |
+
}
|
includes/class.fields.php
CHANGED
@@ -1,446 +1,518 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Collection of default system-wide fields
|
4 |
-
* @package Simple Lightbox
|
5 |
-
* @subpackage Fields
|
6 |
-
* @author Archetyped
|
7 |
-
*
|
8 |
-
*/
|
9 |
-
class SLB_Fields extends SLB_Field_Collection {
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Placeholder handlers
|
15 |
-
* @var array
|
16 |
-
*/
|
17 |
-
|
18 |
-
|
19 |
-
/* Constructor */
|
20 |
-
|
21 |
-
function __construct() {
|
22 |
-
parent::__construct('fields');
|
23 |
-
}
|
24 |
-
|
25 |
-
protected function _hooks() {
|
26 |
-
parent::_hooks();
|
27 |
-
// Init fields
|
28 |
-
add_action('init', $this->m('register_types'));
|
29 |
-
// Init placeholders
|
30 |
-
add_action('init', $this->m('register_placeholders'));
|
31 |
-
}
|
32 |
-
|
33 |
-
/* Field Types */
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Initialize fields
|
37 |
-
*/
|
38 |
-
function register_types() {
|
39 |
-
/* Field Types */
|
40 |
-
|
41 |
-
// Base
|
42 |
-
$base = new SLB_Field_Type('base');
|
43 |
-
$base->set_description(__('Default Element', 'simple-lightbox'));
|
44 |
-
$base->set_property('tag', 'span');
|
45 |
-
$base->set_property('class', '', 'attr');
|
46 |
-
$base->set_layout('form_attr', '{tag} name="{field_name}" id="{field_id}" {properties ref_base="root" group="attr"}');
|
47 |
-
$base->set_layout('form', '<{form_attr ref_base="layout"} />');
|
48 |
-
$base->set_layout('label', '<label for="{field_id}">{label}</label>');
|
49 |
-
$base->set_layout('display', '{data context="display"}');
|
50 |
-
$this->add($base);
|
51 |
-
|
52 |
-
// Base closed
|
53 |
-
$base_closed = new SLB_Field_Type('base_closed');
|
54 |
-
$base_closed->set_parent('base');
|
55 |
-
$base_closed->set_description(__('Default Element (Closed Tag)', 'simple-lightbox'));
|
56 |
-
$base_closed->set_layout('form_start', '<{tag} id="{field_id}" name="{field_name}" {properties ref_base="root" group="attr"}>');
|
57 |
-
$base_closed->set_layout('form_end', '</{tag}>');
|
58 |
-
$base_closed->set_layout('form', '{form_start ref_base="layout"}{data}{form_end ref_base="layout"}');
|
59 |
-
$this->add($base_closed);
|
60 |
-
|
61 |
-
// Input
|
62 |
-
$input = new SLB_Field_Type('input', 'base');
|
63 |
-
$input->set_description(__('Default Input Element', 'simple-lightbox'));
|
64 |
-
$input->set_property('tag', 'input');
|
65 |
-
$input->set_property('type', 'text', 'attr');
|
66 |
-
$input->set_property('value', '{data}', 'attr');
|
67 |
-
$this->add($input);
|
68 |
-
|
69 |
-
// Text input
|
70 |
-
$text = new SLB_Field_Type('text', 'input');
|
71 |
-
$text->set_description(__('Text Box', 'simple-lightbox'));
|
72 |
-
$text->set_property('size', 15, 'attr');
|
73 |
-
$text->set_property('label');
|
74 |
-
$text->set_layout('form', '{label ref_base="layout"} {inherit}');
|
75 |
-
$this->add($text);
|
76 |
-
|
77 |
-
// Checkbox
|
78 |
-
$cb = new SLB_Field_Type('checkbox', 'input');
|
79 |
-
$cb->set_property('type', 'checkbox');
|
80 |
-
$cb->set_property('value', null);
|
81 |
-
$cb->set_layout('form_attr', '{inherit} {checked}');
|
82 |
-
$cb->set_layout('form', '{label ref_base="layout"} <{form_attr ref_base="layout"} />');
|
83 |
-
$this->add($cb);
|
84 |
-
|
85 |
-
// Textarea
|
86 |
-
$ta = new SLB_Field_Type('textarea', 'base_closed');
|
87 |
-
$ta->set_property('tag', 'textarea');
|
88 |
-
$ta->set_property('cols', 40, 'attr');
|
89 |
-
$ta->set_property('rows', 3, 'attr');
|
90 |
-
$this->add($ta);
|
91 |
-
|
92 |
-
// Rich Text
|
93 |
-
$rt = new SLB_Field_Type('richtext', 'textarea');
|
94 |
-
$rt->set_property('class', 'theEditor {inherit}');
|
95 |
-
$rt->set_layout('form', '<div class="rt_container">{inherit}</div>');
|
96 |
-
$rt->add_action('admin_print_footer_scripts', 'wp_tiny_mce', 25);
|
97 |
-
$this->add($rt);
|
98 |
-
|
99 |
-
// Hidden
|
100 |
-
$hidden = new SLB_Field_Type('hidden');
|
101 |
-
$hidden->set_parent('input');
|
102 |
-
$hidden->set_description(__('Hidden Field', 'simple-lightbox'));
|
103 |
-
$hidden->set_property('type', 'hidden');
|
104 |
-
$this->add($hidden);
|
105 |
-
|
106 |
-
// Select
|
107 |
-
$select = new SLB_Field_Type('select', 'base_closed');
|
108 |
-
$select->set_description(__('Select tag', 'simple-lightbox'));
|
109 |
-
$select->set_property('tag', 'select');
|
110 |
-
$select->set_property('tag_option', 'option');
|
111 |
-
$select->set_property('options', array());
|
112 |
-
$select->set_layout('form', '{label ref_base="layout"} {form_start ref_base="layout"}{option_loop ref_base="layout"}{form_end ref_base="layout"}');
|
113 |
-
$select->set_layout('option_loop', '{loop data="properties.options" layout="option" layout_data="option_data"}');
|
114 |
-
$select->set_layout('option', '<{tag_option} value="{data_ext id="option_value" context="attr"}">{data_ext id="option_text" context="text"}</{tag_option}>');
|
115 |
-
$select->set_layout('option_data', '<{tag_option} value="{data_ext id="option_value" context="attr"}" selected="selected">{data_ext id="option_text" context="text"}</{tag_option}>');
|
116 |
-
$this->add($select);
|
117 |
-
|
118 |
-
// Span
|
119 |
-
$span = new SLB_Field_Type('span', 'base_closed');
|
120 |
-
$span->set_description(__('Inline wrapper', 'simple-lightbox'));
|
121 |
-
$span->set_property('tag', 'span');
|
122 |
-
$span->set_property('value', 'Hello there!');
|
123 |
-
$this->add($span);
|
124 |
-
|
125 |
-
// Enable plugins to modify (add, remove, etc.) field types
|
126 |
-
$this->util->do_action_ref_array('register_fields', array($this), false);
|
127 |
-
|
128 |
-
// Signal completion of field registration
|
129 |
-
$this->util->do_action_ref_array('fields_registered', array($this), false);
|
130 |
-
}
|
131 |
-
|
132 |
-
/* Placeholder handlers */
|
133 |
-
|
134 |
-
function register_placeholders() {
|
135 |
-
// Default placeholder handlers
|
136 |
-
$this->register_placeholder('all', $this->m('process_placeholder_default'), 11);
|
137 |
-
$this->register_placeholder('field_id', $this->m('process_placeholder_id'));
|
138 |
-
$this->register_placeholder('field_name', $this->m('process_placeholder_name'));
|
139 |
-
$this->register_placeholder('data', $this->m('process_placeholder_data'));
|
140 |
-
$this->register_placeholder('data_ext'
|
141 |
-
$this->register_placeholder('loop', $this->m('process_placeholder_loop'));
|
142 |
-
$this->register_placeholder('label', $this->m('process_placeholder_label'));
|
143 |
-
$this->register_placeholder('checked', $this->m('process_placeholder_checked'));
|
144 |
-
|
145 |
-
// Allow other code to register placeholders
|
146 |
-
$this->util->do_action_ref_array('register_field_placeholders', array($this), false);
|
147 |
-
|
148 |
-
// Signal completion of field placeholder registration
|
149 |
-
$this->util->do_action_ref_array('field_placeholders_registered', array($this), false);
|
150 |
-
}
|
151 |
-
|
152 |
-
/**
|
153 |
-
* Register a function to handle a placeholder
|
154 |
-
* Multiple handlers may be registered for a single placeholder
|
155 |
-
* Adds filter hook to WP for handling specified placeholder
|
156 |
-
* Placeholders are in layouts and are replaced with data at runtime
|
157 |
-
* @uses add_filter()
|
158 |
-
* @param string $placeholder Name of placeholder to add handler for (Using 'all' will set the function as a handler for all placeholders
|
159 |
-
* @param callback $callback Function to set as a handler
|
160 |
-
* @param int $priority (optional) Priority of handler
|
161 |
-
* @return void
|
162 |
-
*/
|
163 |
-
function register_placeholder($placeholder, $callback, $priority = 10) {
|
164 |
-
if ( 'all'
|
165 |
-
$placeholder = '';
|
166 |
-
else
|
167 |
-
$placeholder = '_' . $placeholder;
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
*
|
175 |
-
*
|
176 |
-
*
|
177 |
-
*
|
178 |
-
* @
|
179 |
-
* @param
|
180 |
-
* @param array $
|
181 |
-
* @
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
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 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
*
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
return $out;
|
330 |
-
}
|
331 |
-
|
332 |
-
/**
|
333 |
-
*
|
334 |
-
*
|
335 |
-
*
|
336 |
-
*
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
$
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
*
|
407 |
-
*
|
408 |
-
*
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
if ( $
|
420 |
-
$
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Collection of default system-wide fields
|
4 |
+
* @package Simple Lightbox
|
5 |
+
* @subpackage Fields
|
6 |
+
* @author Archetyped
|
7 |
+
*
|
8 |
+
*/
|
9 |
+
class SLB_Fields extends SLB_Field_Collection {
|
10 |
+
|
11 |
+
public $item_type = 'SLB_Field_Type';
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Placeholder handlers
|
15 |
+
* @var array
|
16 |
+
*/
|
17 |
+
public $placholders = null;
|
18 |
+
|
19 |
+
/* Constructor */
|
20 |
+
|
21 |
+
function __construct() {
|
22 |
+
parent::__construct( 'fields' );
|
23 |
+
}
|
24 |
+
|
25 |
+
protected function _hooks() {
|
26 |
+
parent::_hooks();
|
27 |
+
// Init fields
|
28 |
+
add_action( 'init', $this->m( 'register_types' ) );
|
29 |
+
// Init placeholders
|
30 |
+
add_action( 'init', $this->m( 'register_placeholders' ) );
|
31 |
+
}
|
32 |
+
|
33 |
+
/* Field Types */
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Initialize fields
|
37 |
+
*/
|
38 |
+
function register_types() {
|
39 |
+
/* Field Types */
|
40 |
+
|
41 |
+
// Base
|
42 |
+
$base = new SLB_Field_Type( 'base' );
|
43 |
+
$base->set_description( __( 'Default Element', 'simple-lightbox' ) );
|
44 |
+
$base->set_property( 'tag', 'span' );
|
45 |
+
$base->set_property( 'class', '', 'attr' );
|
46 |
+
$base->set_layout( 'form_attr', '{tag} name="{field_name}" id="{field_id}" {properties ref_base="root" group="attr"}' );
|
47 |
+
$base->set_layout( 'form', '<{form_attr ref_base="layout"} />' );
|
48 |
+
$base->set_layout( 'label', '<label for="{field_id}">{label}</label>' );
|
49 |
+
$base->set_layout( 'display', '{data context="display"}' );
|
50 |
+
$this->add( $base );
|
51 |
+
|
52 |
+
// Base closed
|
53 |
+
$base_closed = new SLB_Field_Type( 'base_closed' );
|
54 |
+
$base_closed->set_parent( 'base' );
|
55 |
+
$base_closed->set_description( __( 'Default Element (Closed Tag)', 'simple-lightbox' ) );
|
56 |
+
$base_closed->set_layout( 'form_start', '<{tag} id="{field_id}" name="{field_name}" {properties ref_base="root" group="attr"}>' );
|
57 |
+
$base_closed->set_layout( 'form_end', '</{tag}>' );
|
58 |
+
$base_closed->set_layout( 'form', '{form_start ref_base="layout"}{data}{form_end ref_base="layout"}' );
|
59 |
+
$this->add( $base_closed );
|
60 |
+
|
61 |
+
// Input
|
62 |
+
$input = new SLB_Field_Type( 'input', 'base' );
|
63 |
+
$input->set_description( __( 'Default Input Element', 'simple-lightbox' ) );
|
64 |
+
$input->set_property( 'tag', 'input' );
|
65 |
+
$input->set_property( 'type', 'text', 'attr' );
|
66 |
+
$input->set_property( 'value', '{data}', 'attr' );
|
67 |
+
$this->add( $input );
|
68 |
+
|
69 |
+
// Text input
|
70 |
+
$text = new SLB_Field_Type( 'text', 'input' );
|
71 |
+
$text->set_description( __( 'Text Box', 'simple-lightbox' ) );
|
72 |
+
$text->set_property( 'size', 15, 'attr' );
|
73 |
+
$text->set_property( 'label' );
|
74 |
+
$text->set_layout( 'form', '{label ref_base="layout"} {inherit}' );
|
75 |
+
$this->add( $text );
|
76 |
+
|
77 |
+
// Checkbox
|
78 |
+
$cb = new SLB_Field_Type( 'checkbox', 'input' );
|
79 |
+
$cb->set_property( 'type', 'checkbox' );
|
80 |
+
$cb->set_property( 'value', null );
|
81 |
+
$cb->set_layout( 'form_attr', '{inherit} {checked}' );
|
82 |
+
$cb->set_layout( 'form', '{label ref_base="layout"} <{form_attr ref_base="layout"} />' );
|
83 |
+
$this->add( $cb );
|
84 |
+
|
85 |
+
// Textarea
|
86 |
+
$ta = new SLB_Field_Type( 'textarea', 'base_closed' );
|
87 |
+
$ta->set_property( 'tag', 'textarea' );
|
88 |
+
$ta->set_property( 'cols', 40, 'attr' );
|
89 |
+
$ta->set_property( 'rows', 3, 'attr' );
|
90 |
+
$this->add( $ta );
|
91 |
+
|
92 |
+
// Rich Text
|
93 |
+
$rt = new SLB_Field_Type( 'richtext', 'textarea' );
|
94 |
+
$rt->set_property( 'class', 'theEditor {inherit}' );
|
95 |
+
$rt->set_layout( 'form', '<div class="rt_container">{inherit}</div>' );
|
96 |
+
$rt->add_action( 'admin_print_footer_scripts', 'wp_tiny_mce', 25 );
|
97 |
+
$this->add( $rt );
|
98 |
+
|
99 |
+
// Hidden
|
100 |
+
$hidden = new SLB_Field_Type( 'hidden' );
|
101 |
+
$hidden->set_parent( 'input' );
|
102 |
+
$hidden->set_description( __( 'Hidden Field', 'simple-lightbox' ) );
|
103 |
+
$hidden->set_property( 'type', 'hidden' );
|
104 |
+
$this->add( $hidden );
|
105 |
+
|
106 |
+
// Select
|
107 |
+
$select = new SLB_Field_Type( 'select', 'base_closed' );
|
108 |
+
$select->set_description( __( 'Select tag', 'simple-lightbox' ) );
|
109 |
+
$select->set_property( 'tag', 'select' );
|
110 |
+
$select->set_property( 'tag_option', 'option' );
|
111 |
+
$select->set_property( 'options', array() );
|
112 |
+
$select->set_layout( 'form', '{label ref_base="layout"} {form_start ref_base="layout"}{option_loop ref_base="layout"}{form_end ref_base="layout"}' );
|
113 |
+
$select->set_layout( 'option_loop', '{loop data="properties.options" layout="option" layout_data="option_data"}' );
|
114 |
+
$select->set_layout( 'option', '<{tag_option} value="{data_ext id="option_value" context="attr"}">{data_ext id="option_text" context="text"}</{tag_option}>' );
|
115 |
+
$select->set_layout( 'option_data', '<{tag_option} value="{data_ext id="option_value" context="attr"}" selected="selected">{data_ext id="option_text" context="text"}</{tag_option}>' );
|
116 |
+
$this->add( $select );
|
117 |
+
|
118 |
+
// Span
|
119 |
+
$span = new SLB_Field_Type( 'span', 'base_closed' );
|
120 |
+
$span->set_description( __( 'Inline wrapper', 'simple-lightbox' ) );
|
121 |
+
$span->set_property( 'tag', 'span' );
|
122 |
+
$span->set_property( 'value', 'Hello there!' );
|
123 |
+
$this->add( $span );
|
124 |
+
|
125 |
+
// Enable plugins to modify (add, remove, etc.) field types
|
126 |
+
$this->util->do_action_ref_array( 'register_fields', array( $this ), false );
|
127 |
+
|
128 |
+
// Signal completion of field registration
|
129 |
+
$this->util->do_action_ref_array( 'fields_registered', array( $this ), false );
|
130 |
+
}
|
131 |
+
|
132 |
+
/* Placeholder handlers */
|
133 |
+
|
134 |
+
function register_placeholders() {
|
135 |
+
// Default placeholder handlers
|
136 |
+
$this->register_placeholder( 'all', $this->m( 'process_placeholder_default' ), 11 );
|
137 |
+
$this->register_placeholder( 'field_id', $this->m( 'process_placeholder_id' ) );
|
138 |
+
$this->register_placeholder( 'field_name', $this->m( 'process_placeholder_name' ) );
|
139 |
+
$this->register_placeholder( 'data', $this->m( 'process_placeholder_data' ) );
|
140 |
+
$this->register_placeholder( 'data_ext', $this->m( 'process_placeholder_data_ext' ) );
|
141 |
+
$this->register_placeholder( 'loop', $this->m( 'process_placeholder_loop' ) );
|
142 |
+
$this->register_placeholder( 'label', $this->m( 'process_placeholder_label' ) );
|
143 |
+
$this->register_placeholder( 'checked', $this->m( 'process_placeholder_checked' ) );
|
144 |
+
|
145 |
+
// Allow other code to register placeholders
|
146 |
+
$this->util->do_action_ref_array( 'register_field_placeholders', array( $this ), false );
|
147 |
+
|
148 |
+
// Signal completion of field placeholder registration
|
149 |
+
$this->util->do_action_ref_array( 'field_placeholders_registered', array( $this ), false );
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Register a function to handle a placeholder
|
154 |
+
* Multiple handlers may be registered for a single placeholder
|
155 |
+
* Adds filter hook to WP for handling specified placeholder
|
156 |
+
* Placeholders are in layouts and are replaced with data at runtime
|
157 |
+
* @uses add_filter()
|
158 |
+
* @param string $placeholder Name of placeholder to add handler for (Using 'all' will set the function as a handler for all placeholders
|
159 |
+
* @param callback $callback Function to set as a handler
|
160 |
+
* @param int $priority (optional) Priority of handler
|
161 |
+
* @return void
|
162 |
+
*/
|
163 |
+
function register_placeholder( $placeholder, $callback, $priority = 10 ) {
|
164 |
+
if ( 'all' === $placeholder ) {
|
165 |
+
$placeholder = '';
|
166 |
+
} else {
|
167 |
+
$placeholder = '_' . $placeholder;
|
168 |
+
}
|
169 |
+
$hook = $this->add_prefix( 'process_placeholder' . $placeholder );
|
170 |
+
add_filter( $hook, $callback, $priority, 5 );
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Handles default placeholder processing.
|
175 |
+
*
|
176 |
+
* Processes placeholders that have not been processed by another handler.
|
177 |
+
*
|
178 |
+
* @param string $output Value to be used in place of placeholder. Should be empty.
|
179 |
+
* @param SLB_Field $item Field containing placeholder.
|
180 |
+
* @param array $placeholder Current placeholder.
|
181 |
+
* @see SLB_Field::parse_layout for structure of `$placeholder` array.
|
182 |
+
* @param string $layout Layout to build.
|
183 |
+
* @param array $data Extended data for item.
|
184 |
+
* @return string Value to use in place of current placeholder.
|
185 |
+
*/
|
186 |
+
function process_placeholder_default( $output, $item, $placeholder, $layout, $data ) {
|
187 |
+
// Validate parameters before processing.
|
188 |
+
if (
|
189 |
+
! empty( $output )
|
190 |
+
|| ( ! $item instanceof SLB_Field_Type )
|
191 |
+
|| ! is_array( $placeholder )
|
192 |
+
) {
|
193 |
+
return $output;
|
194 |
+
}
|
195 |
+
|
196 |
+
// Build path to replacement data.
|
197 |
+
$output = $item->get_member_value( $placeholder );
|
198 |
+
|
199 |
+
// Check if value is group (properties, etc.)
|
200 |
+
// All groups must have additional attributes (beyond reserved attributes) that define how items in group are used
|
201 |
+
if (
|
202 |
+
is_array( $output )
|
203 |
+
&& ! empty( $placeholder['attributes'] )
|
204 |
+
&& is_array( $placeholder['attributes'] )
|
205 |
+
&& 'properties' === $placeholder['tag']
|
206 |
+
) {
|
207 |
+
// Targeted property is an array.
|
208 |
+
// Placeholder contains additional options on how property is to be used.
|
209 |
+
|
210 |
+
// Find items matching criteria in $output
|
211 |
+
// Check for group criteria
|
212 |
+
$prop_group = $item->get_group( $placeholder['attributes']['group'] );
|
213 |
+
if ( ! empty( $prop_group ) ) {
|
214 |
+
/* Process group */
|
215 |
+
$group_out = array();
|
216 |
+
// Iterate through properties in group and build string.
|
217 |
+
foreach ( array_keys( $prop_group ) as $prop_key ) {
|
218 |
+
$prop_val = $item->get_property( $prop_key );
|
219 |
+
if ( is_null( $prop_val ) ) {
|
220 |
+
continue;
|
221 |
+
}
|
222 |
+
// Process placeholders.
|
223 |
+
$prop_val = $item->process_placeholders( $prop_val, $layout, $data );
|
224 |
+
// Add property to attribute string output.
|
225 |
+
$group_out[] = esc_attr( $prop_key ) . '="' . esc_attr( $prop_val ) . '"';
|
226 |
+
}
|
227 |
+
$output = implode( ' ', $group_out );
|
228 |
+
}
|
229 |
+
} elseif ( is_object( $output ) && ( $output instanceof $item->base_class ) ) {
|
230 |
+
/* Targeted property is actually a nested item */
|
231 |
+
// Set caller to current item
|
232 |
+
$output->set_caller( $item );
|
233 |
+
// Build layout for nested element
|
234 |
+
$output = $output->build_layout( $layout );
|
235 |
+
}
|
236 |
+
|
237 |
+
return $output;
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* Renders field ID formatted for a form field's `id` attribute.
|
242 |
+
*
|
243 |
+
* ID is formatted to be unique identifier for form field.
|
244 |
+
* Example: `options_field_id`.
|
245 |
+
* Registered as handler for `{field_id}` placeholder.
|
246 |
+
*
|
247 |
+
* @param string $output Placeholder's rendered value.
|
248 |
+
* @param SLB_Field $item Field containing placeholder.
|
249 |
+
* @param array &$placeholder Placeholder being processed.
|
250 |
+
* @param string $layout Name of layout being built.
|
251 |
+
* @param array $data Additional data for current field.
|
252 |
+
* @return string Field's ID (formatted for a form field's `id` attribute).
|
253 |
+
*/
|
254 |
+
function process_placeholder_id( $output, $item, &$placeholder, $layout, $data ) {
|
255 |
+
// Get attributes
|
256 |
+
$args = wp_parse_args( $placeholder['attributes'], array( 'format' => 'attr_id' ) );
|
257 |
+
$output = $item->get_id( $args );
|
258 |
+
// Set default placeholder context.
|
259 |
+
if ( ! isset( $placeholder['attributes']['context'] ) ) {
|
260 |
+
$placeholder['attributes']['context'] = 'attr';
|
261 |
+
}
|
262 |
+
return $output;
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Renders field ID formatted for a form field's `name` attribute.
|
267 |
+
*
|
268 |
+
* ID is formatted to be part of an associative array for processing form submission.
|
269 |
+
* Example: `options[field_id]`.
|
270 |
+
* Registered as handler for `{field_name}` placeholder.
|
271 |
+
*
|
272 |
+
* @param string $output Placeholder's rendered value.
|
273 |
+
* @param SLB_Field $item Field containing placeholder.
|
274 |
+
* @param array &$placeholder Placeholder being processed.
|
275 |
+
* @param string $layout Name of layout being built.
|
276 |
+
* @param array $data Additional data for current field.
|
277 |
+
* @return string Field's ID (formatted for a form field's `name` attribute).
|
278 |
+
*/
|
279 |
+
function process_placeholder_name( $output, $item, &$placeholder, $layout, $data ) {
|
280 |
+
// Get attributes
|
281 |
+
$args = wp_parse_args( $placeholder['attributes'], array( 'format' => 'attr_name' ) );
|
282 |
+
$output = $item->get_id( $args );
|
283 |
+
// Set default placeholder context.
|
284 |
+
if ( ! isset( $placeholder['attributes']['context'] ) ) {
|
285 |
+
$placeholder['attributes']['context'] = 'attr';
|
286 |
+
}
|
287 |
+
return $output;
|
288 |
+
}
|
289 |
+
|
290 |
+
/**
|
291 |
+
* Build item label
|
292 |
+
* @see SLB_Fields::process_placeholder_default for parameter descriptions
|
293 |
+
* @return string Field label
|
294 |
+
*/
|
295 |
+
function process_placeholder_label( $output, $item, $placeholder, $layout, $data ) {
|
296 |
+
// Check if item has label property (e.g. sub-elements)
|
297 |
+
$out = $item->get_property( 'label' );
|
298 |
+
// If property not set, use item title
|
299 |
+
if ( empty( $out ) ) {
|
300 |
+
$out = $item->get_title();
|
301 |
+
}
|
302 |
+
return $out;
|
303 |
+
}
|
304 |
+
|
305 |
+
/**
|
306 |
+
* Retrieve data for item
|
307 |
+
* @see SLB_Field_Type::process_placeholder_default for parameter descriptions
|
308 |
+
* @return string Placeholder output
|
309 |
+
*/
|
310 |
+
function process_placeholder_data( $output, $item, $placeholder, $layout ) {
|
311 |
+
$opts = $placeholder['attributes'];
|
312 |
+
// Strip context from data retrieval options (Formatting handled upstream).
|
313 |
+
if ( is_array( $opts ) ) {
|
314 |
+
unset( $opts['context'] );
|
315 |
+
}
|
316 |
+
// Get data
|
317 |
+
$out = $item->get_data( $opts );
|
318 |
+
// Get specific member in value (e.g. value from a specific item element).
|
319 |
+
if (
|
320 |
+
is_array( $out )
|
321 |
+
&& is_array( $opts )
|
322 |
+
&& isset( $opts['element'] )
|
323 |
+
&& isset( $out[ $opts['element'] ] )
|
324 |
+
) {
|
325 |
+
$out = $out[ $opts['element'] ];
|
326 |
+
}
|
327 |
+
|
328 |
+
// Return data
|
329 |
+
return $out;
|
330 |
+
}
|
331 |
+
|
332 |
+
/**
|
333 |
+
* Set checked attribute on item
|
334 |
+
* Evaluates item's data to see if item should be checked or not
|
335 |
+
* @see SLB_Fields::process_placeholder_default for parameter descriptions
|
336 |
+
* @return string Appropriate checkbox attribute
|
337 |
+
*/
|
338 |
+
function process_placeholder_checked( $output, $item, $placeholder, $layout, $data ) {
|
339 |
+
$out = '';
|
340 |
+
$c = $item->get_container();
|
341 |
+
$d = ( isset( $c->data[ $item->get_id() ] ) ) ? $c->data[ $item->get_id() ] : null;
|
342 |
+
$item->set_property( 'd', true );
|
343 |
+
if ( $item->get_data() ) {
|
344 |
+
$out = 'checked="checked"';
|
345 |
+
}
|
346 |
+
$item->set_property( 'd', false );
|
347 |
+
return $out;
|
348 |
+
}
|
349 |
+
|
350 |
+
/**
|
351 |
+
* Loops over data to build item output
|
352 |
+
* Options:
|
353 |
+
* data - Dot-delimited path in item that contains data to loop through
|
354 |
+
* layout - Name of layout to use for each data item in loop
|
355 |
+
* layout_data - Name of layout to use for data item that matches previously-saved item data
|
356 |
+
* @see SLB_Field_Type::process_placeholder_default for parameter descriptions
|
357 |
+
* @return string Placeholder output
|
358 |
+
*/
|
359 |
+
function process_placeholder_loop( $output, $item, $placeholder, $layout, $data ) {
|
360 |
+
// Setup loop options
|
361 |
+
$attr_defaults = array(
|
362 |
+
'layout' => '',
|
363 |
+
'layout_data' => null,
|
364 |
+
'data' => '',
|
365 |
+
);
|
366 |
+
$attr = wp_parse_args( $placeholder['attributes'], $attr_defaults );
|
367 |
+
if ( is_null( $attr['layout_data'] ) ) {
|
368 |
+
$attr['layout_data'] =& $attr['layout'];
|
369 |
+
}
|
370 |
+
// Get data for loop
|
371 |
+
$path = explode( '.', $attr['data'] );
|
372 |
+
$loop_data = $item->get_member_value( $path );
|
373 |
+
|
374 |
+
// Check if data is callback
|
375 |
+
if ( is_callable( $loop_data ) ) {
|
376 |
+
$loop_data = call_user_func( $loop_data );
|
377 |
+
}
|
378 |
+
|
379 |
+
// Get item data
|
380 |
+
$data = $item->get_data();
|
381 |
+
|
382 |
+
// Iterate over data and build output
|
383 |
+
$out = array();
|
384 |
+
if ( is_array( $loop_data ) && ! empty( $loop_data ) ) {
|
385 |
+
foreach ( $loop_data as $value => $label ) {
|
386 |
+
// Load appropriate layout based on item value
|
387 |
+
$layout = ( ( 0 === $data && $value === $data ) xor $data === $value ) ? $attr['layout_data'] : $attr['layout'];
|
388 |
+
// Stop processing if no valid layout is returned
|
389 |
+
if ( empty( $layout ) ) {
|
390 |
+
continue;
|
391 |
+
}
|
392 |
+
// Prep extended item data
|
393 |
+
$data_ext = array(
|
394 |
+
'option_value' => $value,
|
395 |
+
'option_text' => $label,
|
396 |
+
);
|
397 |
+
$out[] = $item->build_layout( $layout, $data_ext );
|
398 |
+
}
|
399 |
+
}
|
400 |
+
|
401 |
+
// Return output
|
402 |
+
return implode( $out );
|
403 |
+
}
|
404 |
+
|
405 |
+
/**
|
406 |
+
* Returns specified value from extended data array for item.
|
407 |
+
*
|
408 |
+
* @param string $output Value to be used in place of placeholder.
|
409 |
+
* @param SLB_Field $item Field containing placeholder.
|
410 |
+
* @param array $placeholder Current placeholder.
|
411 |
+
* @see SLB_Field::parse_layout for structure of `$placeholder` array.
|
412 |
+
* @param string $layout Name of layout being built.
|
413 |
+
* @param array $data Extended data for item.
|
414 |
+
*
|
415 |
+
* @return string Processed value.
|
416 |
+
*/
|
417 |
+
function process_placeholder_data_ext( $output, SLB_Field $item, array $placeholder, $layout, array $data ) {
|
418 |
+
$key = ( isset( $placeholder['attributes']['id'] ) ) ? $placeholder['attributes']['id'] : false;
|
419 |
+
if ( ! ! $key && isset( $data[ $key ] ) && is_scalar( $data[ $key ] ) ) {
|
420 |
+
$output = strval( $data[ $key ] );
|
421 |
+
}
|
422 |
+
|
423 |
+
return $output;
|
424 |
+
}
|
425 |
+
|
426 |
+
/* Build */
|
427 |
+
|
428 |
+
/**
|
429 |
+
* Outputs items in a group.
|
430 |
+
*
|
431 |
+
* @param string $group ID of Group to output.
|
432 |
+
* @return string Group output.
|
433 |
+
* @todo Make compatible with parent::build_group()
|
434 |
+
*/
|
435 |
+
function build_group( $group ) {
|
436 |
+
$out = array();
|
437 |
+
|
438 |
+
/**
|
439 |
+
* Renders group output as a string.
|
440 |
+
*
|
441 |
+
* @uses $out Array containing group output.
|
442 |
+
* @return string Group output.
|
443 |
+
*/
|
444 |
+
$render_output = function() use ( $out ) {
|
445 |
+
// Combine output.
|
446 |
+
return implode( '', $out );
|
447 |
+
};
|
448 |
+
|
449 |
+
// Stop if group does not exist.
|
450 |
+
if ( ! $this->group_exists( $group ) ) {
|
451 |
+
return $render_output();
|
452 |
+
}
|
453 |
+
|
454 |
+
// Classnames.
|
455 |
+
$cls = (object) [
|
456 |
+
'multi' => 'multi_field',
|
457 |
+
'single' => 'single_field',
|
458 |
+
'elements' => 'has_elements',
|
459 |
+
'group_desc' => $this->add_prefix( 'group_description' ),
|
460 |
+
'group_wrap' => $this->add_prefix( 'attributes_wrap' ),
|
461 |
+
'item_wrap' => $this->add_prefix( 'attribute_wrap' ),
|
462 |
+
];
|
463 |
+
// Templates.
|
464 |
+
$tpl = (object) [
|
465 |
+
'container_start' => '<div class="%s">',
|
466 |
+
'container_end' => '</div>',
|
467 |
+
'item_start' => '<div id="%1$s_wrap" class="%2$s">',
|
468 |
+
'item_end' => '</div>',
|
469 |
+
'text_block' => '<p class="%1$s">%2$s</p>',
|
470 |
+
];
|
471 |
+
|
472 |
+
// Process group.
|
473 |
+
$group = $this->get_group( $group );
|
474 |
+
$group_items = ( count( $group->items ) > 1 ) ? $cls->multi : $cls->single;
|
475 |
+
$fs = array_keys( $group->items );
|
476 |
+
$f =& $group->items[ $fs[0] ];
|
477 |
+
$els = $f->get_member_value( 'elements', '', null );
|
478 |
+
|
479 |
+
if ( ! empty( $els ) ) {
|
480 |
+
$group_items .= '_' . $cls->elements;
|
481 |
+
}
|
482 |
+
|
483 |
+
// Wrap items with container element.
|
484 |
+
$classname = array( $cls->group_wrap, $group_items );
|
485 |
+
$out[] = sprintf( $tpl->container_start, implode( ' ', $classname ) );
|
486 |
+
|
487 |
+
// Clear temp variables.
|
488 |
+
unset( $fs, $f, $els, $classname );
|
489 |
+
|
490 |
+
// Build layout for each item in group
|
491 |
+
foreach ( array_keys( $group->items ) as $item_id ) {
|
492 |
+
// Init item.
|
493 |
+
$item =& $group->items[ $item_id ];
|
494 |
+
$item->set_caller( $this );
|
495 |
+
|
496 |
+
// Start item output.
|
497 |
+
$id = $this->add_prefix( 'field_' . $item->get_id() );
|
498 |
+
$out[] = sprintf( $tpl->item_start, $id, $cls->item_wrap );
|
499 |
+
// Build item layout.
|
500 |
+
$out[] = $item->build_layout();
|
501 |
+
// End item output.
|
502 |
+
$out[] = $tpl->item_end;
|
503 |
+
|
504 |
+
// Cleanup.
|
505 |
+
$item->clear_caller();
|
506 |
+
unset( $item, $id );
|
507 |
+
}
|
508 |
+
// Close items container.
|
509 |
+
$out[] = $tpl->container_end;
|
510 |
+
|
511 |
+
// Add description if exists
|
512 |
+
if ( ! empty( $group->description ) ) {
|
513 |
+
$out[] = sprintf( $tpl->text_block, $cls->group_desc, $group->description );
|
514 |
+
}
|
515 |
+
// Render and return output.
|
516 |
+
return $render_output();
|
517 |
+
}
|
518 |
+
}
|
includes/class.option.php
CHANGED
@@ -1,179 +1,185 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Option object
|
4 |
-
* @package Simple Lightbox
|
5 |
-
* @subpackage Options
|
6 |
-
* @author Archetyped
|
7 |
-
*/
|
8 |
-
class SLB_Option extends SLB_Field {
|
9 |
-
|
10 |
-
/* Properties */
|
11 |
-
|
12 |
-
public $hook_prefix = 'option';
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Determines whether option will be sent to client
|
16 |
-
* @var bool
|
17 |
-
*/
|
18 |
-
|
19 |
-
|
20 |
-
/**
|
21 |
-
* Child mapping
|
22 |
-
* @see SLB_Field_Base::map
|
23 |
-
* @var array
|
24 |
-
*/
|
25 |
-
|
26 |
-
'default'
|
27 |
-
'attr'
|
28 |
-
);
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
/* Init */
|
33 |
-
|
34 |
-
/**
|
35 |
-
* @see SLB_Field::__construct()
|
36 |
-
* @uses parent::__construct() to initialize instance
|
37 |
-
* @param $id
|
38 |
-
* @param $title
|
39 |
-
* @param $default
|
40 |
-
*/
|
41 |
-
function __construct($id, $title = '', $default = '') {
|
42 |
-
// Normalize properties
|
43 |
-
$args
|
44 |
-
$defaults = array
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
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 |
-
$value
|
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 |
-
$value =
|
176 |
-
}
|
177 |
-
|
178 |
-
|
179 |
-
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Option object
|
4 |
+
* @package Simple Lightbox
|
5 |
+
* @subpackage Options
|
6 |
+
* @author Archetyped
|
7 |
+
*/
|
8 |
+
class SLB_Option extends SLB_Field {
|
9 |
+
|
10 |
+
/* Properties */
|
11 |
+
|
12 |
+
public $hook_prefix = 'option';
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Determines whether option will be sent to client
|
16 |
+
* @var bool
|
17 |
+
*/
|
18 |
+
public $in_client = false;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Child mapping
|
22 |
+
* @see SLB_Field_Base::map
|
23 |
+
* @var array
|
24 |
+
*/
|
25 |
+
public $map = array(
|
26 |
+
'default' => 'data',
|
27 |
+
'attr' => 'properties',
|
28 |
+
);
|
29 |
+
|
30 |
+
public $property_priority = array( 'id', 'data', 'parent' );
|
31 |
+
|
32 |
+
/* Init */
|
33 |
+
|
34 |
+
/**
|
35 |
+
* @see SLB_Field::__construct()
|
36 |
+
* @uses parent::__construct() to initialize instance
|
37 |
+
* @param $id
|
38 |
+
* @param $title
|
39 |
+
* @param $default
|
40 |
+
*/
|
41 |
+
function __construct( $id, $title = '', $default = '' ) {
|
42 |
+
// Normalize properties
|
43 |
+
$args = func_get_args();
|
44 |
+
$defaults = array(
|
45 |
+
'title' => '',
|
46 |
+
'default' => '',
|
47 |
+
);
|
48 |
+
$props = $this->make_properties( $args, $defaults );
|
49 |
+
// Validate
|
50 |
+
if ( is_scalar( $id ) ) {
|
51 |
+
$props['id'] = $id;
|
52 |
+
}
|
53 |
+
if ( ! is_string( $props['title'] ) ) {
|
54 |
+
$props['title'] = '';
|
55 |
+
}
|
56 |
+
// Send to parent constructor
|
57 |
+
parent::__construct( $props );
|
58 |
+
}
|
59 |
+
|
60 |
+
/* Getters/Setters */
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Retrieve default value for option
|
64 |
+
* @return mixed Default option value
|
65 |
+
*/
|
66 |
+
function get_default( $context = '' ) {
|
67 |
+
return $this->get_data( $context, false );
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Sets parent based on default value
|
72 |
+
*/
|
73 |
+
function set_parent( $parent = null ) {
|
74 |
+
$p = $this->get_parent();
|
75 |
+
if ( empty( $parent ) && empty( $p ) ) {
|
76 |
+
$parent = 'text';
|
77 |
+
$d = $this->get_default();
|
78 |
+
if ( is_bool( $d ) ) {
|
79 |
+
$parent = 'checkbox';
|
80 |
+
}
|
81 |
+
$parent = 'option_' . $parent;
|
82 |
+
} elseif ( ! empty( $p ) && ! is_object( $p ) ) {
|
83 |
+
$parent =& $p;
|
84 |
+
}
|
85 |
+
parent::set_parent( $parent );
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Set in_client property
|
90 |
+
* @uses this::in_client
|
91 |
+
* @param bool Whether or not option should be included in client output (Default: false)
|
92 |
+
* @return void
|
93 |
+
*/
|
94 |
+
function set_in_client( $in_client = false ) {
|
95 |
+
$this->in_client = ! ! $in_client;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Determines whether option should be included in client output
|
100 |
+
* @uses this::in_client
|
101 |
+
* @return bool TRUE if option is included in client output
|
102 |
+
*/
|
103 |
+
function get_in_client() {
|
104 |
+
return $this->in_client;
|
105 |
+
}
|
106 |
+
|
107 |
+
/* Formatting */
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Format data as string for browser output
|
111 |
+
* @see SLB_Field_Base::format()
|
112 |
+
* @param mixed $value Data to format
|
113 |
+
* @param string $context (optional) Current context
|
114 |
+
* @return string Formatted value
|
115 |
+
*/
|
116 |
+
function format_display( $value, $context = '' ) {
|
117 |
+
if ( ! is_string( $value ) ) {
|
118 |
+
if ( is_bool( $value ) ) {
|
119 |
+
$value = ( $value ) ? __( 'Enabled', 'simple-lightbox' ) : __( 'Disabled', 'simple-lightbox' );
|
120 |
+
} elseif ( is_null( $value ) ) {
|
121 |
+
$value = '';
|
122 |
+
} else {
|
123 |
+
$value = strval( $value );
|
124 |
+
}
|
125 |
+
} elseif ( empty( $value ) ) {
|
126 |
+
$value = 'empty';
|
127 |
+
}
|
128 |
+
return htmlentities( $value );
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Format data using same format as default value
|
133 |
+
* @see SLB_Field_Base::format()
|
134 |
+
* @param mixed $value Data to format
|
135 |
+
* @param string $context (optional) Current context
|
136 |
+
* @return mixed Formatted option value
|
137 |
+
*/
|
138 |
+
function format_default( $value, $context = '' ) {
|
139 |
+
// Get default value
|
140 |
+
$d = $this->get_default();
|
141 |
+
if ( empty( $d ) ) {
|
142 |
+
return $value;
|
143 |
+
}
|
144 |
+
if ( is_bool( $d ) ) {
|
145 |
+
$value = $this->format_bool( $value );
|
146 |
+
} elseif ( is_string( $d ) ) {
|
147 |
+
$value = $this->format_string( $value );
|
148 |
+
}
|
149 |
+
return $value;
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Format data as boolean (true/false)
|
154 |
+
* @see SLB_Field_Base::format()
|
155 |
+
* @param mixed $value Data to format
|
156 |
+
* @param string $context (optional) Current context
|
157 |
+
* @return bool Option value
|
158 |
+
*/
|
159 |
+
function format_bool( $value, $context = '' ) {
|
160 |
+
if ( ! is_bool( $value ) ) {
|
161 |
+
$value = ! ! $value;
|
162 |
+
}
|
163 |
+
return $value;
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* Format data as string
|
168 |
+
* @see SLB_Field_Base::format()
|
169 |
+
* @param mixed $value Data to format
|
170 |
+
* @param string $context (optional) Current context
|
171 |
+
* @return string Option string value
|
172 |
+
*/
|
173 |
+
function format_string( $value, $context = '' ) {
|
174 |
+
if ( is_bool( $value ) ) {
|
175 |
+
$value = ( $value ) ? 'true' : 'false';
|
176 |
+
} elseif ( is_object( $value ) ) {
|
177 |
+
$value = get_class( $value );
|
178 |
+
} elseif ( is_array( $value ) ) {
|
179 |
+
$value = implode( ' ', $value );
|
180 |
+
} else {
|
181 |
+
$value = strval( $value );
|
182 |
+
}
|
183 |
+
return $value;
|
184 |
+
}
|
185 |
+
}
|
includes/class.options.php
CHANGED
@@ -1,679 +1,696 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Options collection
|
4 |
-
* @package Simple Lightbox
|
5 |
-
* @subpackage Options
|
6 |
-
* @author Archetyped
|
7 |
-
* @uses SLB_Field_Collection
|
8 |
-
*/
|
9 |
-
class SLB_Options extends SLB_Field_Collection {
|
10 |
-
|
11 |
-
/* Properties */
|
12 |
-
|
13 |
-
public $hook_prefix = 'options';
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
/**
|
18 |
-
* Key for saving version to DB
|
19 |
-
* @var string
|
20 |
-
*/
|
21 |
-
private $version_key = 'version';
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Whether version has been checked
|
25 |
-
* @var bool
|
26 |
-
*/
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
'validate_pre'
|
33 |
-
'validate_post'
|
34 |
-
'save_pre'
|
35 |
-
'save_post'
|
36 |
-
);
|
37 |
-
|
38 |
-
/* Init */
|
39 |
-
|
40 |
-
function __construct($id = '', $props = array()) {
|
41 |
-
// Validate arguments
|
42 |
-
$args = func_get_args();
|
43 |
-
// Set default ID
|
44 |
-
if (
|
45 |
-
$id = 'options';
|
46 |
-
}
|
47 |
-
$defaults = $this->integrate_id($id);
|
48 |
-
$props
|
49 |
-
parent::__construct($props);
|
50 |
-
$this->add_prefix_ref($this->version_key);
|
51 |
-
}
|
52 |
-
|
53 |
-
protected function _hooks() {
|
54 |
-
parent::_hooks();
|
55 |
-
// Register fields
|
56 |
-
$this->util->add_action('register_fields', $this->m('register_fields'), 10, 1, false);
|
57 |
-
// Set option parents
|
58 |
-
$this->util->add_action('fields_registered', $this->m('set_parents'), 10, 1, false);
|
59 |
-
// Building
|
60 |
-
$this->util->add_action('build_init', $this->m('build_init'));
|
61 |
-
// Admin
|
62 |
-
$this->util->add_action('admin_page_render_content', $this->m('admin_page_render_content'), 10, 3, false);
|
63 |
-
$this->util->add_filter('admin_action_reset', $this->m('admin_action_reset'), 10, 3, false);
|
64 |
-
}
|
65 |
-
|
66 |
-
/* Legacy/Migration */
|
67 |
-
|
68 |
-
/**
|
69 |
-
* Checks whether new version has been installed and migrates necessary settings
|
70 |
-
* @uses $version_key as option name
|
71 |
-
* @uses get_option() to retrieve saved version number
|
72 |
-
* @uses SLB_Utilities::get_plugin_version() to retrieve current version
|
73 |
-
* @return bool TRUE if version has been changed
|
74 |
-
*/
|
75 |
-
function check_update() {
|
76 |
-
if (
|
77 |
-
$this->version_checked = true;
|
78 |
-
$version_changed
|
79 |
-
// Get version from DB
|
80 |
-
$vo = $this->get_version();
|
81 |
-
// Get current version
|
82 |
-
$vn = $this->util->get_plugin_version();
|
83 |
-
// Compare versions
|
84 |
-
if ( $vo
|
85 |
-
// Update saved version
|
86 |
-
$this->set_version($vn);
|
87 |
-
// Migrate old version to new version
|
88 |
-
if ( strcasecmp($vo, $vn) < 0 ) {
|
89 |
-
// Force full migration
|
90 |
-
$version_changed = true;
|
91 |
-
}
|
92 |
-
}
|
93 |
-
// Migrate
|
94 |
-
$this->migrate($version_changed);
|
95 |
-
}
|
96 |
-
|
97 |
-
return $this->version_checked;
|
98 |
-
}
|
99 |
-
|
100 |
-
/**
|
101 |
-
* Save plugin version to DB
|
102 |
-
* If no version supplied, will fetch plugin data to determine version
|
103 |
-
* @uses $version_key as option name
|
104 |
-
* @uses update_option() to save version to options table
|
105 |
-
* @param string $ver (optional) Plugin version
|
106 |
-
*/
|
107 |
-
function set_version($ver = null) {
|
108 |
-
if ( empty($ver) ) {
|
109 |
-
$ver = $this->util->get_plugin_version();
|
110 |
-
}
|
111 |
-
return update_option($this->version_key, $ver);
|
112 |
-
}
|
113 |
-
|
114 |
-
/**
|
115 |
-
* Retrieve saved version data
|
116 |
-
* @return string Saved version
|
117 |
-
*/
|
118 |
-
function get_version() {
|
119 |
-
return get_option($this->version_key, '');
|
120 |
-
}
|
121 |
-
|
122 |
-
/**
|
123 |
-
* Migrate options from old versions to current version
|
124 |
-
* @uses self::items_migrated to determine if simple migration has been performed in current request or not
|
125 |
-
* @uses self::save() to save data after migration
|
126 |
-
* @param bool $full Whether to perform a full migration or not (Default: No)
|
127 |
-
*/
|
128 |
-
function migrate($full = false) {
|
129 |
-
if (
|
130 |
-
return false;
|
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 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
//
|
201 |
-
$this->
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
$
|
216 |
-
|
217 |
-
$layout
|
218 |
-
$layout->
|
219 |
-
$layout->
|
220 |
-
$layout->
|
221 |
-
$layout->
|
222 |
-
$layout->
|
223 |
-
|
224 |
-
$
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
*
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
$
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
$otxt
|
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 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
*
|
306 |
-
*
|
307 |
-
*
|
308 |
-
*
|
309 |
-
*
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
/**
|
320 |
-
|
321 |
-
|
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 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
//
|
375 |
-
if (
|
376 |
-
|
377 |
-
}
|
378 |
-
//
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
elseif (
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
$val =
|
393 |
-
}
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
//
|
451 |
-
$
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
$
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
*
|
492 |
-
* @
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
*
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
function
|
523 |
-
return $this->get_value($option, '
|
524 |
-
}
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
*
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
$
|
580 |
-
$
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
$
|
585 |
-
|
586 |
-
|
587 |
-
)
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
$
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
//
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
$
|
676 |
-
}
|
677 |
-
return $
|
678 |
-
}
|
679 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Options collection
|
4 |
+
* @package Simple Lightbox
|
5 |
+
* @subpackage Options
|
6 |
+
* @author Archetyped
|
7 |
+
* @uses SLB_Field_Collection
|
8 |
+
*/
|
9 |
+
class SLB_Options extends SLB_Field_Collection {
|
10 |
+
|
11 |
+
/* Properties */
|
12 |
+
|
13 |
+
public $hook_prefix = 'options';
|
14 |
+
|
15 |
+
public $item_type = 'SLB_Option';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Key for saving version to DB
|
19 |
+
* @var string
|
20 |
+
*/
|
21 |
+
private $version_key = 'version';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Whether version has been checked
|
25 |
+
* @var bool
|
26 |
+
*/
|
27 |
+
public $version_checked = false;
|
28 |
+
|
29 |
+
public $items_migrated = false;
|
30 |
+
|
31 |
+
public $build_vars = array(
|
32 |
+
'validate_pre' => false,
|
33 |
+
'validate_post' => false,
|
34 |
+
'save_pre' => false,
|
35 |
+
'save_post' => false,
|
36 |
+
);
|
37 |
+
|
38 |
+
/* Init */
|
39 |
+
|
40 |
+
function __construct( $id = '', $props = array() ) {
|
41 |
+
// Validate arguments
|
42 |
+
$args = func_get_args();
|
43 |
+
// Set default ID
|
44 |
+
if ( ! $this->validate_id( $id ) ) {
|
45 |
+
$id = 'options';
|
46 |
+
}
|
47 |
+
$defaults = $this->integrate_id( $id );
|
48 |
+
$props = $this->make_properties( $args, $defaults );
|
49 |
+
parent::__construct( $props );
|
50 |
+
$this->add_prefix_ref( $this->version_key );
|
51 |
+
}
|
52 |
+
|
53 |
+
protected function _hooks() {
|
54 |
+
parent::_hooks();
|
55 |
+
// Register fields
|
56 |
+
$this->util->add_action( 'register_fields', $this->m( 'register_fields' ), 10, 1, false );
|
57 |
+
// Set option parents
|
58 |
+
$this->util->add_action( 'fields_registered', $this->m( 'set_parents' ), 10, 1, false );
|
59 |
+
// Building
|
60 |
+
$this->util->add_action( 'build_init', $this->m( 'build_init' ) );
|
61 |
+
// Admin
|
62 |
+
$this->util->add_action( 'admin_page_render_content', $this->m( 'admin_page_render_content' ), 10, 3, false );
|
63 |
+
$this->util->add_filter( 'admin_action_reset', $this->m( 'admin_action_reset' ), 10, 3, false );
|
64 |
+
}
|
65 |
+
|
66 |
+
/* Legacy/Migration */
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Checks whether new version has been installed and migrates necessary settings
|
70 |
+
* @uses $version_key as option name
|
71 |
+
* @uses get_option() to retrieve saved version number
|
72 |
+
* @uses SLB_Utilities::get_plugin_version() to retrieve current version
|
73 |
+
* @return bool TRUE if version has been changed
|
74 |
+
*/
|
75 |
+
function check_update() {
|
76 |
+
if ( ! $this->version_checked ) {
|
77 |
+
$this->version_checked = true;
|
78 |
+
$version_changed = false;
|
79 |
+
// Get version from DB
|
80 |
+
$vo = $this->get_version();
|
81 |
+
// Get current version
|
82 |
+
$vn = $this->util->get_plugin_version();
|
83 |
+
// Compare versions
|
84 |
+
if ( $vo !== $vn ) {
|
85 |
+
// Update saved version
|
86 |
+
$this->set_version( $vn );
|
87 |
+
// Migrate old version to new version
|
88 |
+
if ( strcasecmp( $vo, $vn ) < 0 ) {
|
89 |
+
// Force full migration
|
90 |
+
$version_changed = true;
|
91 |
+
}
|
92 |
+
}
|
93 |
+
// Migrate
|
94 |
+
$this->migrate( $version_changed );
|
95 |
+
}
|
96 |
+
|
97 |
+
return $this->version_checked;
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Save plugin version to DB
|
102 |
+
* If no version supplied, will fetch plugin data to determine version
|
103 |
+
* @uses $version_key as option name
|
104 |
+
* @uses update_option() to save version to options table
|
105 |
+
* @param string $ver (optional) Plugin version
|
106 |
+
*/
|
107 |
+
function set_version( $ver = null ) {
|
108 |
+
if ( empty( $ver ) ) {
|
109 |
+
$ver = $this->util->get_plugin_version();
|
110 |
+
}
|
111 |
+
return update_option( $this->version_key, $ver );
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Retrieve saved version data
|
116 |
+
* @return string Saved version
|
117 |
+
*/
|
118 |
+
function get_version() {
|
119 |
+
return get_option( $this->version_key, '' );
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Migrate options from old versions to current version
|
124 |
+
* @uses self::items_migrated to determine if simple migration has been performed in current request or not
|
125 |
+
* @uses self::save() to save data after migration
|
126 |
+
* @param bool $full Whether to perform a full migration or not (Default: No)
|
127 |
+
*/
|
128 |
+
function migrate( $full = false ) {
|
129 |
+
if ( ! $full && $this->items_migrated ) {
|
130 |
+
return false;
|
131 |
+
}
|
132 |
+
|
133 |
+
// Legacy options
|
134 |
+
$d = null;
|
135 |
+
$this->load_data();
|
136 |
+
|
137 |
+
$items = $this->get_items();
|
138 |
+
|
139 |
+
// Migrate separate options to unified option
|
140 |
+
if ( $full ) {
|
141 |
+
foreach ( $items as $opt => $props ) {
|
142 |
+
$oid = $this->add_prefix( $opt );
|
143 |
+
$o = get_option( $oid, $d );
|
144 |
+
if ( $o !== $d ) {
|
145 |
+
// Migrate value to data array
|
146 |
+
$this->set_data( $opt, $o, false );
|
147 |
+
// Delete legacy option
|
148 |
+
delete_option( $oid );
|
149 |
+
}
|
150 |
+
}
|
151 |
+
}
|
152 |
+
|
153 |
+
// Migrate legacy items
|
154 |
+
if ( is_array( $this->properties_init ) && isset( $this->properties_init['legacy'] ) && is_array( $this->properties_init['legacy'] ) ) {
|
155 |
+
$l =& $this->properties_init['legacy'];
|
156 |
+
// Normalize legacy map
|
157 |
+
foreach ( $l as $opt => $dest ) {
|
158 |
+
if ( ! is_array( $dest ) ) {
|
159 |
+
if ( is_string( $dest ) ) {
|
160 |
+
$l[ $opt ] = array( $dest );
|
161 |
+
} else {
|
162 |
+
unset( $l[ $opt ] );
|
163 |
+
}
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
/* Separate options */
|
168 |
+
if ( $full ) {
|
169 |
+
foreach ( $l as $opt => $dest ) {
|
170 |
+
$oid = $this->add_prefix( $opt );
|
171 |
+
$o = get_option( $oid, $d );
|
172 |
+
// Only migrate valid values
|
173 |
+
if ( $o !== $d ) {
|
174 |
+
// Process destinations
|
175 |
+
foreach ( $dest as $id ) {
|
176 |
+
$this->set_data( $id, $o, false, true );
|
177 |
+
}
|
178 |
+
}
|
179 |
+
// Remove legacy option
|
180 |
+
delete_option( $oid );
|
181 |
+
}
|
182 |
+
}
|
183 |
+
|
184 |
+
/* Simple Migration (Internal options only) */
|
185 |
+
|
186 |
+
// Get existing items that are also legacy items
|
187 |
+
$opts = array_intersect_key( $this->get_data(), $l );
|
188 |
+
foreach ( $opts as $opt => $val ) {
|
189 |
+
$d = $this->get_data( $opt );
|
190 |
+
// Migrate data from old option to new option
|
191 |
+
$dest = $l[ $opt ];
|
192 |
+
// Validate new options to send data to
|
193 |
+
foreach ( $dest as $id ) {
|
194 |
+
$this->set_data( $id, $d, false, true );
|
195 |
+
}
|
196 |
+
// Remove legacy option
|
197 |
+
$this->remove( $opt, false );
|
198 |
+
}
|
199 |
+
}
|
200 |
+
// Save changes
|
201 |
+
$this->save();
|
202 |
+
// Set flag
|
203 |
+
$this->items_migrated = true;
|
204 |
+
}
|
205 |
+
|
206 |
+
/* Option setup */
|
207 |
+
|
208 |
+
/**
|
209 |
+
* Get elements for creating fields
|
210 |
+
* @return obj
|
211 |
+
*/
|
212 |
+
function get_field_elements() {
|
213 |
+
static $o = null;
|
214 |
+
if ( empty( $o ) ) {
|
215 |
+
$o = new stdClass();
|
216 |
+
/* Layout */
|
217 |
+
$layout = new stdClass();
|
218 |
+
$layout->label = '<label for="{field_id}" class="title block">{label}</label>';
|
219 |
+
$layout->label_ref = '{label ref_base="layout"}';
|
220 |
+
$layout->field_pre = '<div class="input block">';
|
221 |
+
$layout->field_post = '</div>';
|
222 |
+
$layout->opt_pre = '<div class="' . $this->add_prefix( 'option_item' ) . '">';
|
223 |
+
$layout->opt_post = '</div>';
|
224 |
+
$layout->form = '<{form_attr ref_base="layout"} /> <span class="description">(' . __( 'Default', 'simple-lightbox' ) . ': {data context="display" top="0"})</span>';
|
225 |
+
/* Combine */
|
226 |
+
$o->layout =& $layout;
|
227 |
+
}
|
228 |
+
return $o;
|
229 |
+
}
|
230 |
+
|
231 |
+
/**
|
232 |
+
* Register option-specific fields
|
233 |
+
* @param SLB_Fields $fields Reference to global fields object
|
234 |
+
* @return void
|
235 |
+
*/
|
236 |
+
function register_fields( $fields ) {
|
237 |
+
// Layouts
|
238 |
+
$o = $this->get_field_elements();
|
239 |
+
$l =& $o->layout;
|
240 |
+
|
241 |
+
$form = implode(
|
242 |
+
'',
|
243 |
+
array(
|
244 |
+
$l->opt_pre,
|
245 |
+
$l->label_ref,
|
246 |
+
$l->field_pre,
|
247 |
+
$l->form,
|
248 |
+
$l->field_post,
|
249 |
+
$l->opt_post,
|
250 |
+
)
|
251 |
+
);
|
252 |
+
|
253 |
+
// Text input
|
254 |
+
$otxt = new SLB_Field_Type( 'option_text', 'text' );
|
255 |
+
$otxt->set_property( 'class', '{inherit} code' );
|
256 |
+
$otxt->set_property( 'size', null );
|
257 |
+
$otxt->set_property( 'value', '{data}' );
|
258 |
+
$otxt->set_layout( 'label', $l->label );
|
259 |
+
$otxt->set_layout( 'form', $form );
|
260 |
+
$fields->add( $otxt );
|
261 |
+
|
262 |
+
// Checkbox
|
263 |
+
$ocb = new SLB_Field_Type( 'option_checkbox', 'checkbox' );
|
264 |
+
$ocb->set_layout( 'label', $l->label );
|
265 |
+
$ocb->set_layout( 'field_reference', sprintf( '<input type="hidden" name="%s" value="{field_name format="raw"}" />', "{$this->get_id('formatted')}_items[]" ) );
|
266 |
+
$ocb->set_layout( 'form', '{field_reference ref_base="layout"}' . $form );
|
267 |
+
$fields->add( $ocb );
|
268 |
+
|
269 |
+
// Select
|
270 |
+
$othm = new SLB_Field_Type( 'option_select', 'select' );
|
271 |
+
$othm->set_layout( 'label', $l->label );
|
272 |
+
$othm->set_layout( 'form_start', $l->field_pre . '{inherit}' );
|
273 |
+
$othm->set_layout( 'form_end', '{inherit}' . $l->field_post );
|
274 |
+
$othm->set_layout( 'form', $l->opt_pre . '{inherit}' . $l->opt_post );
|
275 |
+
$fields->add( $othm );
|
276 |
+
}
|
277 |
+
|
278 |
+
/**
|
279 |
+
* Set parent field types for options
|
280 |
+
* Parent only set for Admin pages
|
281 |
+
* @uses SLB_Option::set_parent() to set parent field for each option item
|
282 |
+
* @uses is_admin() to determine if current request is admin page
|
283 |
+
* @param object $fields Collection of default field types
|
284 |
+
* @return void
|
285 |
+
*/
|
286 |
+
function set_parents( $fields ) {
|
287 |
+
if ( ! is_admin() ) {
|
288 |
+
return false;
|
289 |
+
}
|
290 |
+
$items = &$this->get_items();
|
291 |
+
foreach ( array_keys( $items ) as $opt ) {
|
292 |
+
$items[ $opt ]->set_parent();
|
293 |
+
}
|
294 |
+
foreach ( $this->items as $opt ) {
|
295 |
+
$p = $opt->parent;
|
296 |
+
if ( is_object( $p ) ) {
|
297 |
+
$p = 'o:' . $p->id;
|
298 |
+
}
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
/* Processing */
|
303 |
+
|
304 |
+
/**
|
305 |
+
* Validates option data.
|
306 |
+
*
|
307 |
+
* Validates option values (e.g. prior to saving to DB, after form submission, etc.).
|
308 |
+
* Values are formatted and sanitized according to corresponding option's data type
|
309 |
+
* (e.g. boolean, string, number, etc.).
|
310 |
+
*
|
311 |
+
* @since 1.5.5
|
312 |
+
*
|
313 |
+
* @param array<string,scalar> $values Optional. Option data to validate.
|
314 |
+
* Indexed by option ID.
|
315 |
+
* Default form-submission data used.
|
316 |
+
* @return array<string,scalar> Validated data. Indexed by option ID.
|
317 |
+
*/
|
318 |
+
function validate( $values = null ) {
|
319 |
+
/** @var array<string,scalar> $values_valid Validated option data. Indexed by option ID. */
|
320 |
+
$values_valid = [];
|
321 |
+
// Enforce values data type.
|
322 |
+
if ( ! is_array( $values ) ) {
|
323 |
+
/** @var array<string,scalar> $values */
|
324 |
+
$values = [];
|
325 |
+
}
|
326 |
+
/**
|
327 |
+
* Generates query variable using common base.
|
328 |
+
*
|
329 |
+
* @since 2.8.0
|
330 |
+
*
|
331 |
+
* @param string $text Optional. Text to append to base.
|
332 |
+
*
|
333 |
+
* @return string Query variable name. Format: "{base}_{text}". Default "{base}".
|
334 |
+
*/
|
335 |
+
$qv = function ( $text = '' ) {
|
336 |
+
static $base;
|
337 |
+
// Get base.
|
338 |
+
if ( empty( $base ) ) {
|
339 |
+
$base = $this->get_id( 'formatted' );
|
340 |
+
}
|
341 |
+
$out = $base;
|
342 |
+
// Append text to base.
|
343 |
+
if ( is_string( $text ) && ! empty( $text ) ) {
|
344 |
+
$out .= "_{$text}";
|
345 |
+
}
|
346 |
+
return $out;
|
347 |
+
};
|
348 |
+
// Get options form field group ID.
|
349 |
+
$qvar = $qv();
|
350 |
+
// Use form submission data when no values provided.
|
351 |
+
if ( empty( $values ) && isset( $_POST[ $qvar ] ) && check_admin_referer( $qvar, $qv( 'nonce' ) ) ) {
|
352 |
+
/** @var array<string,scalar> $values */
|
353 |
+
$values = $_POST[ $qvar ];
|
354 |
+
// Append non-submitted, but rendered fields (e.g. unchecked checkboxes)
|
355 |
+
$qvar_items = $qv( 'items' );
|
356 |
+
/** @var string[] $items_bool Boolean options rendered in submitted form. */
|
357 |
+
$items_bool = ( isset( $_POST[ $qvar_items ] ) ) ? $_POST[ $qvar_items ] : null;
|
358 |
+
if ( ! empty( $items_bool ) && is_array( $items_bool ) ) {
|
359 |
+
foreach ( $items_bool as $item_id ) {
|
360 |
+
// Add missing boolean options (false == unchecked).
|
361 |
+
if ( ! array_key_exists( $item_id, $values ) && $this->has( $item_id ) && is_bool( $this->get_default( $item_id ) ) ) {
|
362 |
+
$values_valid[ $item_id ] = false;
|
363 |
+
}
|
364 |
+
}
|
365 |
+
}
|
366 |
+
unset( $qvar, $qvar_items, $items_bool, $item_id );
|
367 |
+
}
|
368 |
+
// Process values.
|
369 |
+
/**
|
370 |
+
* @var string $id Option ID.
|
371 |
+
* @var mixed $val Option value (raw/unsanitized).
|
372 |
+
*/
|
373 |
+
foreach ( $values as $id => $val ) {
|
374 |
+
// Do not process invalid option IDs or invalid (non-scalar) data.
|
375 |
+
if ( ! $this->has( $id ) || ! is_scalar( $val ) ) {
|
376 |
+
continue;
|
377 |
+
}
|
378 |
+
// Conform to option's data type and sanitize.
|
379 |
+
/** @var scalar $d Option's default data. */
|
380 |
+
$d = $this->get_default( $id );
|
381 |
+
if ( is_bool( $d ) ) {
|
382 |
+
// Boolean.
|
383 |
+
$val = ! ! $val;
|
384 |
+
} elseif ( ( is_int( $d ) || is_float( $d ) ) && ! is_numeric( $val ) ) {
|
385 |
+
// Numeric - do not process non-numeric values for int/float fields.
|
386 |
+
continue;
|
387 |
+
} elseif ( is_int( $d ) ) {
|
388 |
+
// Integer.
|
389 |
+
$val = (int) $val;
|
390 |
+
} elseif ( is_float( $d ) ) {
|
391 |
+
// Float.
|
392 |
+
$val = (float) $val;
|
393 |
+
} else {
|
394 |
+
// Defaut: Handle as string.
|
395 |
+
$val = sanitize_text_field( wp_unslash( $val ) );
|
396 |
+
}
|
397 |
+
// Add to validated data.
|
398 |
+
$values_valid[ $id ] = $val;
|
399 |
+
}
|
400 |
+
unset( $id, $val );
|
401 |
+
|
402 |
+
// Return validated values.
|
403 |
+
return $values_valid;
|
404 |
+
}
|
405 |
+
|
406 |
+
/* Data */
|
407 |
+
|
408 |
+
/**
|
409 |
+
* Retrieve options from database
|
410 |
+
* @uses get_option to retrieve option data
|
411 |
+
* @return array Options data
|
412 |
+
*/
|
413 |
+
function fetch_data( $sanitize = true ) {
|
414 |
+
// Get data
|
415 |
+
$data = get_option( $this->get_key(), null );
|
416 |
+
if ( $sanitize && is_array( $data ) ) {
|
417 |
+
// Sanitize loaded data based on default values
|
418 |
+
foreach ( $data as $id => $val ) {
|
419 |
+
if ( $this->has( $id ) ) {
|
420 |
+
$opt = $this->get( $id );
|
421 |
+
if ( is_bool( $opt->get_default() ) ) {
|
422 |
+
$data[ $id ] = ! ! $val;
|
423 |
+
}
|
424 |
+
}
|
425 |
+
}
|
426 |
+
}
|
427 |
+
return $data;
|
428 |
+
}
|
429 |
+
|
430 |
+
/**
|
431 |
+
* Retrieves option data for collection
|
432 |
+
* @see SLB_Field_Collection::load_data()
|
433 |
+
*/
|
434 |
+
function load_data() {
|
435 |
+
if ( ! $this->data_loaded ) {
|
436 |
+
// Retrieve data
|
437 |
+
$this->data = $this->fetch_data();
|
438 |
+
parent::load_data();
|
439 |
+
// Check update
|
440 |
+
$this->check_update();
|
441 |
+
}
|
442 |
+
}
|
443 |
+
|
444 |
+
/**
|
445 |
+
* Resets option values to their default values
|
446 |
+
* @param bool $hard Reset all options if TRUE (default), Reset only unset options if FALSE
|
447 |
+
*/
|
448 |
+
function reset( $hard = true ) {
|
449 |
+
$this->load_data();
|
450 |
+
// Reset data
|
451 |
+
if ( $hard ) {
|
452 |
+
$this->data = null;
|
453 |
+
}
|
454 |
+
// Save
|
455 |
+
$this->save();
|
456 |
+
}
|
457 |
+
|
458 |
+
/**
|
459 |
+
* Save options data to database
|
460 |
+
*/
|
461 |
+
function save() {
|
462 |
+
$this->normalize_data();
|
463 |
+
update_option( $this->get_key(), $this->data );
|
464 |
+
}
|
465 |
+
|
466 |
+
/**
|
467 |
+
* Normalize data
|
468 |
+
* Assures that data in collection match items
|
469 |
+
* @uses self::data to reset and save collection data after normalization
|
470 |
+
*/
|
471 |
+
function normalize_data() {
|
472 |
+
$data = array();
|
473 |
+
foreach ( $this->get_items() as $id => $opt ) {
|
474 |
+
$data[ $id ] = $opt->get_data();
|
475 |
+
}
|
476 |
+
$this->data =& $data;
|
477 |
+
return $data;
|
478 |
+
}
|
479 |
+
|
480 |
+
/* Collection */
|
481 |
+
|
482 |
+
/**
|
483 |
+
* Build key for saving/retrieving data to options table
|
484 |
+
* @return string Key
|
485 |
+
*/
|
486 |
+
function get_key() {
|
487 |
+
return $this->add_prefix( $this->get_id() );
|
488 |
+
}
|
489 |
+
|
490 |
+
/**
|
491 |
+
* Add option to collection
|
492 |
+
* @uses SLB_Field_Collection::add() to add item
|
493 |
+
* @param string $id Unique item ID
|
494 |
+
* @param array $properties Item properties
|
495 |
+
* @param bool $update (optional) Should item be updated or overwritten (Default: FALSE)
|
496 |
+
* @return SLB_Option Option instance
|
497 |
+
*/
|
498 |
+
function &add( $id, $properties = array(), $update = false ) {
|
499 |
+
// Create item
|
500 |
+
$args = func_get_args();
|
501 |
+
$ret = call_user_func_array( array( 'parent', 'add' ), $args );
|
502 |
+
return $ret;
|
503 |
+
}
|
504 |
+
|
505 |
+
/**
|
506 |
+
* Retrieve option value
|
507 |
+
* @uses get_data() to retrieve option data
|
508 |
+
* @param string $option Option ID to retrieve value for
|
509 |
+
* @param string $context (optional) Context for formatting data
|
510 |
+
* @return mixed Option value
|
511 |
+
*/
|
512 |
+
function get_value( $option, $context = '' ) {
|
513 |
+
return $this->get_data( $option, $context );
|
514 |
+
}
|
515 |
+
|
516 |
+
/**
|
517 |
+
* Retrieve option value as boolean (true/false)
|
518 |
+
* @uses get_data() to retrieve option data
|
519 |
+
* @param string $option Option ID to retrieve value for
|
520 |
+
* @return bool Option value
|
521 |
+
*/
|
522 |
+
function get_bool( $option ) {
|
523 |
+
return $this->get_value( $option, 'bool' );
|
524 |
+
}
|
525 |
+
|
526 |
+
function get_string( $option ) {
|
527 |
+
return $this->get_value( $option, 'string' );
|
528 |
+
}
|
529 |
+
|
530 |
+
/**
|
531 |
+
* Retrieve option's default value
|
532 |
+
* @uses get_data() to retrieve option data
|
533 |
+
* @param string $option Option ID to retrieve value for
|
534 |
+
* @param string $context (optional) Context for formatting data
|
535 |
+
* @return mixed Option's default value
|
536 |
+
*/
|
537 |
+
function get_default( $option, $context = '' ) {
|
538 |
+
return $this->get_data( $option, $context, false );
|
539 |
+
}
|
540 |
+
|
541 |
+
/* Output */
|
542 |
+
|
543 |
+
function build_init() {
|
544 |
+
if ( $this->build_vars['validate_pre'] ) {
|
545 |
+
$values = $this->validate();
|
546 |
+
if ( $this->build_vars['save_pre'] ) {
|
547 |
+
$this->set_data( $values );
|
548 |
+
}
|
549 |
+
}
|
550 |
+
}
|
551 |
+
|
552 |
+
/**
|
553 |
+
* Build array of option values for client output
|
554 |
+
* @return array Associative array of options
|
555 |
+
*/
|
556 |
+
function build_client_output() {
|
557 |
+
$items = $this->get_items();
|
558 |
+
$out = array();
|
559 |
+
foreach ( $items as $option ) {
|
560 |
+
if ( ! $option->get_in_client() ) {
|
561 |
+
continue;
|
562 |
+
}
|
563 |
+
$out[ $option->get_id() ] = $option->get_data( 'default' );
|
564 |
+
}
|
565 |
+
return $out;
|
566 |
+
}
|
567 |
+
|
568 |
+
/* Admin */
|
569 |
+
|
570 |
+
/**
|
571 |
+
* Handles output building for options on admin pages
|
572 |
+
* @param obj|array $opts Options instance or Array of options instance and groups to build
|
573 |
+
* @param obj $page Admin Page instance
|
574 |
+
* @param obj $state Admin Page state properties
|
575 |
+
*/
|
576 |
+
public function admin_page_render_content( $opts, $page, $state ) {
|
577 |
+
$groups = null;
|
578 |
+
if ( is_array( $opts ) && count( $opts ) === 2 ) {
|
579 |
+
$groups = $opts[1];
|
580 |
+
$opts = $opts[0];
|
581 |
+
}
|
582 |
+
if ( $opts === $this ) {
|
583 |
+
// Set build variables and callbacks
|
584 |
+
$this->set_build_var( 'admin_page', $page );
|
585 |
+
$this->set_build_var( 'admin_state', $state );
|
586 |
+
if ( ! empty( $groups ) ) {
|
587 |
+
$this->set_build_var( 'groups', $groups );
|
588 |
+
}
|
589 |
+
$hooks = array(
|
590 |
+
'filter' => array(
|
591 |
+
'parse_build_vars' => array( $this->m( 'admin_parse_build_vars' ), 10, 2 ),
|
592 |
+
),
|
593 |
+
);
|
594 |
+
|
595 |
+
// Add hooks
|
596 |
+
foreach ( $hooks as $type => $hook ) {
|
597 |
+
$m = 'add_' . $type;
|
598 |
+
foreach ( $hook as $tag => $args ) {
|
599 |
+
array_unshift( $args, $tag );
|
600 |
+
call_user_func_array( $this->util->m( $m ), $args );
|
601 |
+
}
|
602 |
+
}
|
603 |
+
|
604 |
+
// Build output
|
605 |
+
$this->build( array( 'build_groups' => $this->m( 'admin_build_groups' ) ) );
|
606 |
+
|
607 |
+
// Remove hooks
|
608 |
+
foreach ( $hooks as $type => $hook ) {
|
609 |
+
$m = 'remove_' . $type;
|
610 |
+
foreach ( $hook as $tag => $args ) {
|
611 |
+
call_user_func( $this->util->m( $m ), $tag, $args[0] );
|
612 |
+
}
|
613 |
+
}
|
614 |
+
// Clear custom build vars
|
615 |
+
$this->delete_build_var( 'admin_page' );
|
616 |
+
$this->delete_build_var( 'admin_state' );
|
617 |
+
}
|
618 |
+
}
|
619 |
+
|
620 |
+
/**
|
621 |
+
* Builds option groups output
|
622 |
+
*/
|
623 |
+
public function admin_build_groups() {
|
624 |
+
$page = $this->get_build_var( 'admin_page' );
|
625 |
+
$state = $this->get_build_var( 'admin_state' );
|
626 |
+
$groups = $this->get_build_var( 'groups' );
|
627 |
+
|
628 |
+
// Get all groups
|
629 |
+
$groups_all = $this->get_groups();
|
630 |
+
if ( empty( $groups ) ) {
|
631 |
+
$groups = array_keys( $groups_all );
|
632 |
+
}
|
633 |
+
// Iterate through groups
|
634 |
+
foreach ( $groups as $gid ) {
|
635 |
+
// Validate
|
636 |
+
if ( ! isset( $groups_all[ $gid ] ) || ! count( $this->get_items( $gid ) ) ) {
|
637 |
+
continue;
|
638 |
+
}
|
639 |
+
// Add meta box for each group
|
640 |
+
$g = $groups_all[ $gid ];
|
641 |
+
add_meta_box(
|
642 |
+
$g->id,
|
643 |
+
$g->title,
|
644 |
+
$this->m( 'admin_build_group' ),
|
645 |
+
$state->screen,
|
646 |
+
$state->context,
|
647 |
+
$state->priority,
|
648 |
+
array(
|
649 |
+
'group' => $g->id,
|
650 |
+
'page' => $page,
|
651 |
+
)
|
652 |
+
);
|
653 |
+
}
|
654 |
+
}
|
655 |
+
|
656 |
+
/**
|
657 |
+
* Group output handler for admin pages
|
658 |
+
* @param obj $obj Object passed by `do_meta_boxes()` call (Default: NULL)
|
659 |
+
* @param array $box Meta box properties
|
660 |
+
*/
|
661 |
+
public function admin_build_group( $obj, $box ) {
|
662 |
+
$a = $box['args'];
|
663 |
+
$group = $a['group'];
|
664 |
+
$this->build_group( $group );
|
665 |
+
}
|
666 |
+
|
667 |
+
/**
|
668 |
+
* Parse build vars
|
669 |
+
* @uses `options_parse_build_vars` filter hook
|
670 |
+
*/
|
671 |
+
public function admin_parse_build_vars( $vars, $opts ) {
|
672 |
+
// Handle form submission
|
673 |
+
if ( isset( $_POST[ $opts->get_id( 'formatted' ) ] ) ) {
|
674 |
+
$vars['save_pre'] = true;
|
675 |
+
$vars['validate_pre'] = true;
|
676 |
+
}
|
677 |
+
return $vars;
|
678 |
+
}
|
679 |
+
|
680 |
+
/**
|
681 |
+
* Admin reset handler
|
682 |
+
* @param bool $res Current result
|
683 |
+
* @param obj $opts Options instance
|
684 |
+
* @param obj $reset Admin Reset instance
|
685 |
+
*/
|
686 |
+
public function admin_action_reset( $res, $opts, $reset ) {
|
687 |
+
// Only process matching options instance
|
688 |
+
if ( $opts === $this ) {
|
689 |
+
// Reset options
|
690 |
+
$this->reset();
|
691 |
+
// Set result
|
692 |
+
$res = true;
|
693 |
+
}
|
694 |
+
return $res;
|
695 |
+
}
|
696 |
+
}
|
includes/class.template_tag.php
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Template Tag
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Template
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Template_Tag extends SLB_Component { }
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Template Tag
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @subpackage Template
|
7 |
+
* @author Archetyped
|
8 |
+
*/
|
9 |
+
class SLB_Template_Tag extends SLB_Component { }
|
includes/class.template_tags.php
CHANGED
@@ -1,122 +1,122 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Content Handler Collection
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Content Handler
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Template_Tags extends SLB_Collection_Controller {
|
10 |
-
/* Configuration */
|
11 |
-
|
12 |
-
protected $item_type = 'SLB_Template_Tag';
|
13 |
-
|
14 |
-
public $hook_prefix = 'template_tags';
|
15 |
-
|
16 |
-
// Use tag ID as key
|
17 |
-
protected $key_prop = 'get_id';
|
18 |
-
|
19 |
-
// Call $key_prop is a method to be called
|
20 |
-
protected $key_call = true;
|
21 |
-
|
22 |
-
/* Properties */
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Cache properties (key, group)
|
26 |
-
* @var object
|
27 |
-
*/
|
28 |
-
protected $cache_props = null;
|
29 |
-
|
30 |
-
/* Initialization */
|
31 |
-
|
32 |
-
protected function _hooks() {
|
33 |
-
parent::_hooks();
|
34 |
-
$this->util->add_action('init', $this->m('init_defaults'));
|
35 |
-
$this->util->add_action('footer', $this->m('client_output'), 1, 0, false);
|
36 |
-
$this->util->add_filter('footer_script', $this->m('client_output_script'), $this->util->priority('client_footer_output'), 1, false);
|
37 |
-
}
|
38 |
-
|
39 |
-
/* Collection Management */
|
40 |
-
|
41 |
-
/**
|
42 |
-
* Add template tag
|
43 |
-
* Accepts properties to create new template tag OR previously-initialized tag instance
|
44 |
-
* @see parent::add()
|
45 |
-
* @param string $id Tag ID
|
46 |
-
* @param array $props Tag properties
|
47 |
-
* @return object Current instance
|
48 |
-
*/
|
49 |
-
public function add($id, $props = array()) {
|
50 |
-
$o = ( is_string($id) ) ? new $this->item_type($id, $props) : $id;
|
51 |
-
// Add to collection
|
52 |
-
return parent::add($o);
|
53 |
-
}
|
54 |
-
|
55 |
-
/* Defaults */
|
56 |
-
|
57 |
-
/**
|
58 |
-
* Initialize default template tags
|
59 |
-
* @param SLB_Template_Tags $tags Tags controller
|
60 |
-
*/
|
61 |
-
public function init_defaults($tags) {
|
62 |
-
$js_path
|
63 |
-
$js_path .= ( SLB_DEV ) ? 'dev' : 'prod';
|
64 |
-
$src_base = $this->util->get_file_url('template-tags', true);
|
65 |
-
$defaults = array
|
66 |
-
'item'
|
67 |
-
'scripts'
|
68 |
-
array
|
69 |
-
)
|
70 |
-
),
|
71 |
-
'ui'
|
72 |
-
'scripts'
|
73 |
-
array
|
74 |
-
)
|
75 |
-
),
|
76 |
-
);
|
77 |
-
foreach ( $defaults as $id => $props ) {
|
78 |
-
$tags->add($id, $props);
|
79 |
-
}
|
80 |
-
}
|
81 |
-
|
82 |
-
/* Output */
|
83 |
-
|
84 |
-
/**
|
85 |
-
* Build client output
|
86 |
-
*/
|
87 |
-
public function client_output() {
|
88 |
-
// Load matched handlers
|
89 |
-
foreach ( $this->get() as $tag ) {
|
90 |
-
$tag->enqueue_scripts();
|
91 |
-
}
|
92 |
-
}
|
93 |
-
|
94 |
-
/**
|
95 |
-
* Client output script
|
96 |
-
* @param array $commands Client script commands
|
97 |
-
* @return array Modified script commands
|
98 |
-
*/
|
99 |
-
public function client_output_script($commands) {
|
100 |
-
$out
|
101 |
-
$code = array();
|
102 |
-
|
103 |
-
foreach ( $this->get() as $tag ) {
|
104 |
-
$styles = $tag->get_styles(array('uri_format'=>'full'));
|
105 |
-
if ( empty($styles) ) {
|
106 |
-
continue;
|
107 |
-
}
|
108 |
-
// Setup client parameters
|
109 |
-
$params
|
110 |
-
sprintf("'%s'", $tag->get_id()),
|
111 |
-
);
|
112 |
-
$params[] =
|
113 |
-
// Extend handler in client
|
114 |
-
$code[] = $this->util->call_client_method('View.extend_template_tag_handler', $params, false);
|
115 |
-
}
|
116 |
-
if ( !empty($code) ) {
|
117 |
-
$out[]
|
118 |
-
$commands[] = implode(PHP_EOL, $out);
|
119 |
-
}
|
120 |
-
return $commands;
|
121 |
-
}
|
122 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Content Handler Collection
|
5 |
+
* @package Simple Lightbox
|
6 |
+
* @subpackage Content Handler
|
7 |
+
* @author Archetyped
|
8 |
+
*/
|
9 |
+
class SLB_Template_Tags extends SLB_Collection_Controller {
|
10 |
+
/* Configuration */
|
11 |
+
|
12 |
+
protected $item_type = 'SLB_Template_Tag';
|
13 |
+
|
14 |
+
public $hook_prefix = 'template_tags';
|
15 |
+
|
16 |
+
// Use tag ID as key
|
17 |
+
protected $key_prop = 'get_id';
|
18 |
+
|
19 |
+
// Call $key_prop is a method to be called
|
20 |
+
protected $key_call = true;
|
21 |
+
|
22 |
+
/* Properties */
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Cache properties (key, group)
|
26 |
+
* @var object
|
27 |
+
*/
|
28 |
+
protected $cache_props = null;
|
29 |
+
|
30 |
+
/* Initialization */
|
31 |
+
|
32 |
+
protected function _hooks() {
|
33 |
+
parent::_hooks();
|
34 |
+
$this->util->add_action( 'init', $this->m( 'init_defaults' ) );
|
35 |
+
$this->util->add_action( 'footer', $this->m( 'client_output' ), 1, 0, false );
|
36 |
+
$this->util->add_filter( 'footer_script', $this->m( 'client_output_script' ), $this->util->priority( 'client_footer_output' ), 1, false );
|
37 |
+
}
|
38 |
+
|
39 |
+
/* Collection Management */
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Add template tag
|
43 |
+
* Accepts properties to create new template tag OR previously-initialized tag instance
|
44 |
+
* @see parent::add()
|
45 |
+
* @param string $id Tag ID
|
46 |
+
* @param array $props Tag properties
|
47 |
+
* @return object Current instance
|
48 |
+
*/
|
49 |
+
public function add( $id, $props = array() ) {
|
50 |
+
$o = ( is_string( $id ) ) ? new $this->item_type( $id, $props ) : $id;
|
51 |
+
// Add to collection
|
52 |
+
return parent::add( $o );
|
53 |
+
}
|
54 |
+
|
55 |
+
/* Defaults */
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Initialize default template tags
|
59 |
+
* @param SLB_Template_Tags $tags Tags controller
|
60 |
+
*/
|
61 |
+
public function init_defaults( $tags ) {
|
62 |
+
$js_path = 'js/';
|
63 |
+
$js_path .= ( SLB_DEV ) ? 'dev' : 'prod';
|
64 |
+
$src_base = $this->util->get_file_url( 'template-tags', true );
|
65 |
+
$defaults = array(
|
66 |
+
'item' => array(
|
67 |
+
'scripts' => array(
|
68 |
+
array( 'base', "$src_base/item/$js_path/tag.item.js" ),
|
69 |
+
),
|
70 |
+
),
|
71 |
+
'ui' => array(
|
72 |
+
'scripts' => array(
|
73 |
+
array( 'base', "$src_base/ui/$js_path/tag.ui.js" ),
|
74 |
+
),
|
75 |
+
),
|
76 |
+
);
|
77 |
+
foreach ( $defaults as $id => $props ) {
|
78 |
+
$tags->add( $id, $props );
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
/* Output */
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Build client output
|
86 |
+
*/
|
87 |
+
public function client_output() {
|
88 |
+
// Load matched handlers
|
89 |
+
foreach ( $this->get() as $tag ) {
|
90 |
+
$tag->enqueue_scripts();
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Client output script
|
96 |
+
* @param array $commands Client script commands
|
97 |
+
* @return array Modified script commands
|
98 |
+
*/
|
99 |
+
public function client_output_script( $commands ) {
|
100 |
+
$out = array( '/* TPLT */' );
|
101 |
+
$code = array();
|
102 |
+
|
103 |
+
foreach ( $this->get() as $tag ) {
|
104 |
+
$styles = $tag->get_styles( array( 'uri_format' => 'full' ) );
|
105 |
+
if ( empty( $styles ) ) {
|
106 |
+
continue;
|
107 |
+
}
|
108 |
+
// Setup client parameters
|
109 |
+
$params = array(
|
110 |
+
sprintf( "'%s'", $tag->get_id() ),
|
111 |
+
);
|
112 |
+
$params[] = wp_json_encode( array( 'styles' => array_values( $styles ) ) );
|
113 |
+
// Extend handler in client
|
114 |
+
$code[] = $this->util->call_client_method( 'View.extend_template_tag_handler', $params, false );
|
115 |
+
}
|
116 |
+
if ( ! empty( $code ) ) {
|
117 |
+
$out[] = implode( '', $code );
|
118 |
+
$commands[] = implode( PHP_EOL, $out );
|
119 |
+
}
|
120 |
+
return $commands;
|
121 |
+
}
|
122 |
+
}
|
includes/class.theme.php
CHANGED
@@ -1,109 +1,109 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Theme
|
5 |
-
* @package Simple Lightbox
|
6 |
-
* @subpackage Themes
|
7 |
-
* @author Archetyped
|
8 |
-
*/
|
9 |
-
class SLB_Theme extends SLB_Component {
|
10 |
-
/* Properties */
|
11 |
-
|
12 |
-
protected $props_required = array('name');
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Public flag
|
16 |
-
* @var bool
|
17 |
-
*/
|
18 |
-
protected $public = true;
|
19 |
-
|
20 |
-
/* Get/Set */
|
21 |
-
|
22 |
-
/**
|
23 |
-
* Retrieve theme's ancestors
|
24 |
-
* @param bool $sort_topdown (optional) Ancestor sorting (Default: Nearest to Farthest)
|
25 |
-
* @return array Theme's ancestors (sorted by nearest to most distant ancestor)
|
26 |
-
*/
|
27 |
-
public function get_ancestors($sort_topdown = false) {
|
28 |
-
$ret = array();
|
29 |
-
/**
|
30 |
-
* @var SLB_Theme
|
31 |
-
*/
|
32 |
-
$thm = $this;
|
33 |
-
while ( $thm->has_parent() ) {
|
34 |
-
$par = $thm->get_parent();
|
35 |
-
// Add ancestor
|
36 |
-
if ( $par->is_valid() && !in_array($par, $ret, true) ) {
|
37 |
-
$ret[] = $par;
|
38 |
-
}
|
39 |
-
// Get next ancestor
|
40 |
-
$thm = $par;
|
41 |
-
}
|
42 |
-
// Sorting
|
43 |
-
if ( $sort_topdown ) {
|
44 |
-
$ret = array_reverse($ret);
|
45 |
-
}
|
46 |
-
return $ret;
|
47 |
-
}
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Set public flag
|
51 |
-
* @param bool $public
|
52 |
-
*/
|
53 |
-
public function set_public($public) {
|
54 |
-
$this->publ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|