first commit

This commit is contained in:
2026-03-05 13:07:40 +01:00
commit 64ba0721ee
25709 changed files with 4691006 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
.vscode
.sass-cache
node_modules/
vendor/

View File

@@ -0,0 +1,28 @@
# How to contribute
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.
## Getting Started
* Install the [latest version of SLB][latest]
* Get a [GitHub account][gh] if you don't already have one.
Now you're ready to contribute!
## Reporting Issues
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.
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.
## Additional Resources
* [Simple Lightbox's Official Page][slb]
* [Simple Lightbox on WordPress.org][slb-wp]
[slb]: http://archetyped.com/tools/simple-lightbox/ "Simple Lightbox"
[slb-wp]: http://wordpress.org/plugins/simple-lightbox
[latest]: https://github.com/archetyped/simple-lightbox "Simple Lightbox"
[gh]: https://github.com/signup/free "GitHub Signup"
[report-issue]: https://github.com/archetyped/simple-lightbox/wiki/Reporting-Issues "Reporting Issues"

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,11 @@
Simple Lightbox
===============
The highly customizable lightbox for WordPress
http://archetyped.com/tools/simple-lightbox/
## Support
Found a bug or otherwise experiencing an issue with Simple Lightbox? [Report the issue here][issue-report]
[issue-report]: https://github.com/archetyped/simple-lightbox/wiki/Reporting-Issues "Report an issue"

View File

@@ -0,0 +1,372 @@
= 2.9.3 =
* Hotfix: WordPress 6.1 `wp_rand()` bug (32-bit platforms) ([#974](https://github.com/archetyped/simple-lightbox/issues/974))
* Update: Confirm WordPress 6.1 compatibility
* Optimize: Media item cache key generation
* Optimize: Prune build tasks
= 2.9.2 =
* Optimize: Symbolic link handing for file/directory paths.
= 2.9.1 =
* Fix: Validate hook priority values (Let's Getz Prioritized)
= 2.9.0 =
* 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
= 2.8.1 =
* Update: PHP 5.6 Compatibility
* Add: PHPCS configuration
* Add: GitHub Issue templates
= 2.8.0 =
* Update: WordPress 5.3+ required.
* Update: PHP 7.2+ required.
* Optimize: Link detection up to 2x faster.
* Optimize: Options data handling.
* Optimize: Default title filtering.
* Optimize: Standardize media item data structure to avoid conflicts with third-party data.
* Optimize: Load only necessary media item properties in browser.
* Optimize: Filter all media items (instead of each individual item).
* Filter Removed: `media_item_properties` (single item).
* Filter Added: `media_items` (all items).
* Fix: `area` elements included in link detection (This is Jim's Area).
= 2.7.1 =
* Update: Confirm compatibility with WordPress 5.0+
* Optimize: Improved support for captions generated by Block Editor.
= 2.7.0 =
* Fix: Remove reference to deprecated `screen_icon()` function (The Icon of Finnegan Island)
* Add: Validate requirements before initialization.
* Optimize: PHP 7.2+ Compatibility
* Optimize: Internal code optimizations
* Themes
* Add: RTL Support
* Update: Load font locally
= 2.6.0 =
* Add: Activate links in native WordPress navigation menus (enable in admin settings)
* Add: Group menu links separately (enable in admin settings)
* Optimize: Fallback lightbox title text retrieval (link text)
* Fix: Undefined variable in `Utilities::get_plugin_base_file()` (The Lost Temple of Xavivars)
= 2.5.3 =
* Optimize: Entity handling in URIs for different server environments
= 2.5.2 =
* Fix: Activation when Home page set to static page (Lyra's Static Cling)
* Optimize: Prep for WordPress language packs
= 2.5.1 =
* Update: Client-side Utilities library
* Optimize: Request processing
= 2.5.0 =
* Fix: Query string removed from URI (A Stern Query)
* Optimize: Key-based asset data storage/retrieval
* Optimize: Improved cache usage when processing links
* Optimize: Refactor image URI detection
= 2.4.1 =
* Fix: Ungrouped items in empty group (Robert & The Lost Group)
* Fix: IE8 Support (S.Franzis' Legacy)
* Optimize: Widget support
* Optimize: Relative and internal URI handling
* Optimize: Link activation performance
= 2.4.0 =
* Update: WordPress version compatibility (v4.2.1)
* Optimize: Standardize code
* Optimize: Do not process excerpt content
* Optimize: Client-side libraries (Phase 1)
* Add: Set group via `slb_activate()`
* Add: Set group via `activate_links()`
* Add: `slb_is_enabled` filter
= 2.3.1 =
* Fix: WordPress version requirement
* Optimize: Field collection group parsing
= 2.3.0 =
[Full Release Notes](http://archetyped.com/lab/slb-2-3-0 "Simple Lightbox 2.3.0")
* Update: WordPress 3.9 support
* Update: Support URI, content
* Add: Enhanced grouping support
* Add: Shortcode: `[slb_group]`
* Add: Shortcode: `[slb_exclude]`
* Add: Filter: `slb_pre_process_links`
* Add: Filter: `slb_post_process_links`
* Add: Filter: `slb_process_link_attributes`
* Add: Filter: `slb_media_item_properties`
* Add: Filter: `slb_pre_exclude_content`
* Add: Filter: `slb_exclude_shortcodes`
* Add: Filter: `slb_group_shortcodes`
* Add: Template Tag: `slb_activate()` - Manually activate content
* Add: Option to enable/disable usage of WordPress-generated media title
* Add: Dev mode
* Add: Theme breakpoints
* Optimize: Remove deprecated code
* Optimize: Remove deprecated legacy support
* Optimize: Content exclusion performance
* Optimize: Content grouping performance
* Optimize: Harden code against third-party post query modifications
* Optimize: Utility code
* Optimize: Loading process
* Optimize: Client-side code
* Optimize: Client-side: Code loading
* Optimize: Client-side: Simplified dependency detection
* Optimize: Client-side: Default Theme transitions
* Optimize: Grunt: Cleanup
* Optimize: Grunt: Path abstraction
* Optimize: Grunt: Task loading
* Optimize: Grunt: Selective file compilation
= 2.2.2 =
* Optimize: Widget processing
* Optimize: Remove call-time-pass-by-references
= 2.2.1 =
* Fix: Enable/Disable lightbox on certain requests (Danny the Enabler)
* Fix: Widget links grouped with post links (Rafa's Widgetarian Adventure)
* Optimize: Client-side loading
* Optimize: Theme validation
* Optimize: Widget processing
= 2.2.0 =
* Update: WordPress 3.8 support
* Add: Add-on support
* Add: Load external data for item
* Add: Unloading process for viewer
* Add: Relative links marked as "internal"
* Add: Grunt build workflow
* Optimize: Initialization process
* Optimize: Client-side output (JavaScript, CSS)
* Optimize: Improved URI handling (variants, query strings, etc.)
* Optimize: Improved support for content types (video, etc.)
* Optimize: Improved File contents retrieval
* Optimize: Plugin metadata cleanup
* Optimize: Use absolute paths for file includes (props k3davis)
= 2.1.3 =
* Fix: PHP configuration issue on some web hosts (Tim's got (config) issues)
* Optimize: Hide overlapping elements when lightbox is displayed (e.g. Flash, etc.)
= 2.1.2 =
* Fix: Incorrect paths when WP in subdirectory (Kim's Van Repair)
= 2.1.1 =
* Fix: Automatic resizing
* Fix: Compatibility with non-standard wp-content location (On the Path of the Wijdemans)
* Optimize: jQuery dependency handling
* Optimize: Plugin initialization
* Optimize: Deferred component stylesheet loading
* Optimize: Code cleanup
= 2.1 =
* Update: Finalized Theme API
* Update: Finalized Content Handler API
* Update: Finalized Template Tag API
* Update: Administration framework
* Add: Baseline theme
* Add: Hook for extending image link matching
* Optimize: Link validation
* Optimize: Intelligent client-side loading
* Optimize: Server-side processing
* Optimize: Default theme display
* Fix: False positive link activation (What's eating Gilbert's links?)
* Fix: Gallery post format compatibility (Just Juan problem with galleries)
= 2.0 =
* Completely rewritten lightbox code
* Add: Automatically resize lightbox to fit window
* Add: APIs for third-party add-ons
* Add: Flexible theme support
* Add: Flexible content handler support
* Add: Mobile-optimized responsive themes (2)
* Optimize: PHP class autoloading
* Optimize: Improved performance and compatibility
* Optimize: Full internationalization support
= 1.6 =
* Add: Widget support
* Add: WordPress 3.3 support
* Add: Localization support
* Add: Option to group gallery links separately (supports WordPress & NextGen galleries)
* Add: Upgrade notice
* Optimize: WP 3.3 compatibility
* Optimize: Improved compatibility with URI case-sensitivity
* Optimize: Activation processing
* Optimize: Image grouping
* Optimize: Image metadata loading performance
* Optimize: File loading
* Optimize: Improved safeguards against interference by bugs in other plugins
* Optimize: Link processing performance
* Optimize: Lightbox styling isolated from site styles
* Optimize: Improved link processing performance
* Optimize: Improved image metadata support
* Optimize: Improved support for HTTP/HTTPS requests
* Fix: SLB is not defined in JS (Jezz Hands)
* Fix: Boolean case-sensitivity (78 Truths)
* Fix: YouTube embed using iFrame overlaps lightbox (Elena in Hiding)
* Fix: Issue when scanning links without valid URLs (McCloskey Iteration)
* Fix: Image activation is case-sensitive (Sensitive Tanya)
* Fix: Visible lightbox overlay edges when image larger than browser window (Chibi Overlay)
* Fix: Options availability for some users
* Fix: Inconsistent loading of image metadata
* Fix: Links not fully processed when group is set manually
= 1.5.6 =
* Add: Display image description in lightbox (with HTML support)
* Add: Support for W3 Total Cache plugin
* Add: Initial support for NextGEN galleries
* Update: **Important:** [System Requirements](http://wordpress.org/about/requirements/) aligned with WP 3.2.1
* Optimize: Improved support for small images in default template
* Optimize: Support for non-English text in user options
* Optimize: Improved IE compatibility
* Optimize: Improved data handling
* Optimize: Skin loading performance
* Optimize: Skin CSS Cleanup
* Optimize: Caption support for galleries
* Optimize: Options code cleanup (Juga Sweep)
* Fix: User-defined UI text not used (Ivan gets Even (cooler))
* Fix: Options reset after update (KRazy Donna)
= 1.5.5.1 =
* Fix: Disabled links not being disabled (Disabling Sascha)
= 1.5.5 =
* Add: Distinct link activation (will not affect other lightboxes)
* Add: Backwards compatibility with legacy lightbox links (optional)
* Add: Support for WordPress 3.2
* Add: Support for links added after page load (e.g. via AJAX, etc.)
* Add: Admin option to enable/disable attachment links
* Add: Support for image attachment links
* Update: Options management overhaul
* Update: Additional WordPress 3.2 support (Gallery)
* Update: Cache-management for enqueued files
* Update: Improved UI consistency
* Update: Improved compatibility for older versions of PHP
* Update: Internal optimizations
* Update: Improved URL handling
* Fix: Improved options migration from old versions (Hutchison Migration)
* Fix: XHTML Validation (Hajo Validation)
= 1.5.4 =
* Add: Optional Link validation
* Add: Keyboard Navigation
* Add: Option to enable/disable image caption
* Add: `rel` attribute supported again
* Add: Use `slb_off` in link's `rel` attribute to disable automatic activation for link
* Fix: HTTPS compatibility (J&uuml;rgen Protocol)
* Fix: Enabling SLB on Pages issue
* Fix: Zmanu is_single
* Fix: Image order is sometimes incorrect
* Optimize: Filter double clicks
* Optimize: Separate options to enable/disable SLB on Posts and Pages
* Optimize: Better grouping support
= 1.5.3 =
* Fix: Caption may not display under certain circumstances (Caption Erin)
* Fix: Images not grouped when "separate by post" option is activated (Logical Ross)
* Update: Lightbox will not be activated for links that already have `rel` attribute set
= 1.5.2 =
* Fix: Slideshow loops out of control (Mirage of Wallentin)
* Fix: Lightbox fails when group by posts disabled (Lange Find)
* Add: Option to use the image's URI as caption when link title not set (Under UI options)
= 1.5.1 =
* Add: WP Gallery support
* Fix: Navigation hidden when only one image
* Fix: Use user-defined UI text
= 1.5 =
* Add: Theme support
* Optimize: JavaScript cleanup and file size reductions
* Optimize: CSS cleanup
= 1.4 =
* Update: Integrated with jQuery
* Optimize: JavaScript file size 9x smaller
* Add: Close lightbox by clicking to left/right outside of image (an oft-requested feature)
= 1.3.2 =
* Add: Option to enable/disable lightbox resizing animation (thanks Maria!)
= 1.3.1 =
* Update: Utilities code (internal)
= 1.3 =
* Add: Customizable UI label text (close, next, and previous button images can be replaced in `images` directory)
* Add: Group image links by Post (separate slideshow for each post)
* Add: Reset settings link on plugin listings page
* Optimize: Organized settings page
= 1.2.1 =
* Fixed: Image title given higher precedence than Image alt (more compatible w/WP workflow)
= 1.2 =
* Added: Option to group automatically activated links
* Optimized: Lightbox caption retrieval
= 1.1 =
* Added: Enable/disable lightbox functionality by page type (Home, Pages/Posts, Archive, etc.)
* Added: Automatically activate lightbox functionality for image links
* Added: Link to settings menu on plugin listing page
* Optimized: Options menu field building
* Optimized: Loading of default values for plugin options
* Optimized: General code optimizations
= 1.0 =
* Initial release

View File

@@ -0,0 +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}

View File

@@ -0,0 +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}

View File

@@ -0,0 +1,27 @@
/**
* Admin
* @package Simple Lightbox
* @subpackage Admin
* @author Archetyped
*/
/* global SLB, postboxes, pagenow */
if ( !!window.SLB && !!SLB.attach ) { (function ($) {
SLB.attach('Admin', {
/**
* Initialization routines
*/
init: function() {
if ( postboxes ) {
postboxes.add_postbox_toggles(pagenow);
}
},
});
$(document).ready(function() {
SLB.Admin.init();
});
})(jQuery);}

View File

@@ -0,0 +1,934 @@
/**
* Core
* @package SLB
* @author Archetyped
*/
if ( window.jQuery ){(function($) {
'use strict';
/**
* Extendible class
* Adapted from John Resig
* @link http://ejohn.org/blog/simple-javascript-inheritance/
*/
var c_init = false;
var Class = function() {};
/**
* Create class that extends another class
* @param object members Child class' properties
* @return function New class
*/
Class.extend = function(members) {
var _super = this.prototype;
// Copy instance to prototype
c_init = true;
var proto = new this();
c_init = false;
var val, name;
// Scrub prototype objects (Decouple from super class)
for ( name in proto ) {
if ( $.isPlainObject(proto[name]) ) {
val = $.extend({}, proto[name]);
proto[name] = val;
}
}
/**
* Create class method with access to super class method
* @param string nm Method name
* @param function fn Class method
* @return function Class method with access to super class method
*/
var make_handler = function(nm, fn) {
return function() {
// Cache super variable
var tmp = this._super;
// Set variable to super class method
this._super = _super[nm];
// Call method
var ret = fn.apply(this, arguments);
// Restore super variable
this._super = tmp;
// Return value
return ret;
};
};
// Copy properties to Class
for ( name in members ) {
// Add access to super class method to methods
if ( 'function' === typeof members[name] && 'function' === typeof _super[name] ) {
proto[name] = make_handler(name, members[name]);
} else {
// Transfer properties
// Objects are copied, not referenced
proto[name] = ( $.isPlainObject(members[name]) ) ? $.extend({}, members[name]) : members[name];
}
}
/**
* Class constructor
* Supports pre-construction initilization (`Class._init()`)
* Supports passing constructor for new classes (`Class._c()`)
*/
function Class() {
if ( !c_init ) {
// Private initialization
if ( 'function' === typeof this._init ) {
this._init.apply(this, arguments);
}
// Main Constructor
if ( 'function' === typeof this._c ) {
this._c.apply(this, arguments);
}
}
}
// Populate new prototype
Class.prototype = proto;
// Set constructor
Class.prototype.constructor = Class;
// Set extender
Class.extend = this.extend;
// Return function
return Class;
};
/**
* Base Class
*/
var Base = {
/* Properties */
/**
* Base object flag
* @var bool
*/
base: false,
/**
* Instance parent
* @var object
*/
_parent: null,
/**
* Class prefix
* @var string
*/
prefix: 'slb',
/* Methods */
/**
* Constructor
* Sets instance parent
*/
_init: function() {
this._set_parent();
},
/**
* Set instance parent
* Set utilities parent to current instance
* @param obj p Parent instance
*/
_set_parent: function(p) {
if ( this.util.is_set(p) ) {
this._parent = p;
}
this.util._parent = this;
},
/**
* Attach new member to instance
* Member can be property (value) or method
* @param string name Member name
* @param object data Member data
* @param bool simple (optional) Save new member as data object or new class instance (Default: new instance)
* @return obj Attached object
*/
attach: function(member, data, simple) {
var ret = data;
// Validate
simple = ( typeof simple === 'undefined' ) ? false : !!simple;
// Add member to instance
if ( 'string' === $.type(member) ) {
// Prepare member value
if ( $.isPlainObject(data) && !simple ) {
// Set parent reference for attached instance
data['_parent'] = this;
// Define new class
data = this.Class.extend(data);
}
// Save member to current instance
// Initialize new instance if data is a class
this[member] = ( 'function' === $.type(data) ) ? new data() : data;
ret = this[member];
}
return ret;
},
/**
* Check for child object
* Child object can be multi-level (e.g. Child.Level2child.Level3child)
*
* @param string child Name of child object
*/
has_child: function(child) {
// Validate
if ( !this.util.is_string(child) ) {
return false;
}
var children = child.split('.');
child = null;
var o = this;
var x;
for ( x = 0; x < children.length; x++ ) {
child = children[x];
if ( "" === child ) {
continue;
}
if ( this.util.is_obj(o) && o[child] ) {
o = o[child];
} else {
return false;
}
}
return true;
},
/**
* Check if instance is set as a base
* @uses base
* @return bool TRUE if object is set as a base
*/
is_base: function() {
return !!this.base;
},
/**
* Get parent instance
* @uses `Base._parent` property
* @return obj Parent instance
*/
get_parent: function() {
var p = this._parent;
// Validate
if ( !p ) {
this._parent = {};
}
return this._parent;
}
};
/**
* Utility methods
*/
var Utilities = {
/* Properties */
_base: null,
_parent: null,
/* Methods */
/* Connections */
/**
* Get base ancestor
* @return obj Base ancestor
*/
get_base: function() {
if ( !this._base ) {
var p = this.get_parent();
var p_prev = null;
var methods = ['is_base', 'get_parent'];
// Find base ancestor
// Either oldest ancestor or object explicitly set as a base
while ( ( p_prev !== p ) && this.is_method(p, methods) && !p.is_base() ) {
// Save previous parent
p_prev = p;
// Get new parent
p = p.get_parent();
}
// Set base
this._base = p;
}
return this._base;
},
/**
* Get parent object or parent property value
* @param string prop (optional) Property to retrieve
* @return obj Parent object or property value
*/
get_parent: function(prop) {
var ret = this._parent;
// Validate
if ( !ret ) {
// Set default parent value
ret = this._parent = {};
}
// Get parent property
if ( this.is_string(prop) ) {
ret = ( this.in_obj(ret, prop) ) ? ret[prop] : null;
}
return ret;
},
/* Prefix */
/**
* Retrieve valid separator
* If supplied argument is not a valid separator, use default separator
* @param string (optional) sep Separator text
* @return string Separator text
*/
get_sep: function(sep) {
var sep_default = '_';
return ( this.is_string(sep, false) ) ? sep : sep_default;
},
/**
* Retrieve prefix
* @return string Prefix
*/
get_prefix: function() {
var p = this.get_parent('prefix');
return ( this.is_string(p, false) ) ? p : '';
},
/**
* Check if string is prefixed
*/
has_prefix: function(val, sep) {
return ( this.is_string(val) && 0 === val.indexOf(this.get_prefix() + this.get_sep(sep)) );
},
/**
* Add Prefix to a string
* @param string val Value to add prefix to
* @param string sep (optional) Separator (Default: `_`)
* @param bool (optional) once If text should only be prefixed once (Default: TRUE)
*/
add_prefix: function(val, sep, once) {
// Validate
if ( !this.is_string(val) ) {
// Return prefix if value to add prefix to is empty
return this.get_prefix();
}
sep = this.get_sep(sep);
if ( !this.is_bool(once) ) {
once = true;
}
return ( once && this.has_prefix(val, sep) ) ? val : [this.get_prefix(), val].join(sep);
},
/**
* Remove Prefix from a string
* @param string val Value to add prefix to
* @param string sep (optional) Separator (Default: `_`)
* @param bool (optional) once If text should only be prefixed once (Default: true)
* @return string Original value with prefix removed
*/
remove_prefix: function(val, sep, once) {
// Validate parameters
if ( !this.is_string(val, true) ) {
return '';
}
// Default values
sep = this.get_sep(sep);
if ( !this.is_bool(once) ) {
once = true;
}
// Check if string is prefixed
if ( this.has_prefix(val, sep) ) {
// Remove prefix
var prfx = this.get_prefix() + sep;
do {
val = val.substr(prfx.length);
} while ( !once && this.has_prefix(val, sep) );
}
return val;
},
/* Attributes */
/*
* Get attribute name
* @param string attr_base Attribute's base name
* @return string Fully-formed attribute name
*/
get_attribute: function(attr_base) {
// Setup
var sep = '-';
var top = 'data';
// Validate
var attr = [top, this.get_prefix()].join(sep);
// Process
if ( this.is_string(attr_base) && 0 !== attr_base.indexOf(attr + sep) ) {
attr = [attr, attr_base].join(sep);
}
return attr;
},
/* Request */
/**
* Retrieve valid context
* @return array Context
*/
get_context: function() {
// Validate
var b = this.get_base();
if ( !$.isArray(b.context) ) {
b.context = [];
}
// Return context
return b.context;
},
/**
* Check if a context exists in current request
* If multiple contexts are supplied, result will be TRUE if at least ONE context exists
*
* @param string|array ctx Context to check for
* @return bool TRUE if context exists, FALSE otherwise
*/
is_context: function(ctx) {
// Validate context
if ( this.is_string(ctx) ) {
ctx = [ctx];
}
return ( this.is_array(ctx) && this.arr_intersect(this.get_context(), ctx).length > 0 );
},
/* Helpers */
/**
* Check if value is set/defined
* @param mixed val Value to check
* @return bool TRUE if value is defined
*/
is_set: function(val) {
return ( typeof val !== 'undefined' );
},
/**
* Validate data type
* @param mixed val Value to validate
* @param mixed type Data type to compare with (function gets for instance, string checks data type)
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
* @return bool TRUE if Value matches specified data type
*/
is_type: function(val, type, nonempty) {
var ret = false;
if ( this.is_set(val) && null !== val && this.is_set(type) ) {
switch ( $.type(type) ) {
case 'function':
ret = ( val instanceof type ) ? true : false;
break;
case 'string':
ret = ( $.type(val) === type ) ? true : false;
break;
default:
ret = false;
break;
}
}
// Validate empty values
if ( ret && ( !this.is_set(nonempty) || !!nonempty ) ) {
ret = !this.is_empty(val);
}
return ret;
},
/**
* Check if value is a string
* @uses is_type()
* @param mixed value Value to check
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
* @return bool TRUE if value is a valid string
*/
is_string: function(value, nonempty) {
return this.is_type(value, 'string', nonempty);
},
/**
* Check if value is an array
* @uses is_type()
* @param mixed value Value to check
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
* @return bool TRUE if value is a valid array
*/
is_array: function(value, nonempty) {
return ( this.is_type(value, 'array', nonempty) );
},
/**
* Check if value is a boolean
* @uses is_type()
* @param mixed value Value to check
* @return bool TRUE if value is a valid boolean
*/
is_bool: function(value) {
return this.is_type(value, 'boolean', false);
},
/**
* Check if value is an object
* @uses is_type()
* @param mixed value Value to check
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
* @return bool TRUE if value is a valid object
*/
is_obj: function(value, nonempty) {
return this.is_type(value, 'object', nonempty);
},
/**
* Check if value is a function
* @uses is_type()
* @param mixed value Value to check
* @return bool TRUE if value is a valid function
*/
is_func: function(value) {
return this.is_type(value, 'function', false);
},
/**
* Checks if an object has a method
* @param obj obj Object to check
* @param string|array key Name(s) of methods to check for
* @return bool TRUE if method(s) exist, FALSE otherwise
*/
is_method: function(obj, key) {
var ret = false;
if ( this.is_string(key) ) {
key = [key];
}
if ( this.in_obj(obj, key) ) {
ret = true;
var x = 0;
while ( ret && x < key.length ) {
ret = this.is_func(obj[key[x]]);
x++;
}
}
return ret;
},
/**
* Check if object is instance of a class
* @param obj obj Instance object
* @param obj parent Class to compare with
* @return bool TRUE if object is instance of class
*/
is_instance: function(obj, parent) {
if ( !this.is_func(parent) ) {
return false;
}
return ( this.is_obj(obj) && ( obj instanceof parent ) );
},
/**
* Check if object is class
* Optionally check if class is sub-class of another class
* @param func cls Class to check
* @param func parent (optional) parent class
* @return bool TRUE if object is valid class (and sub-class if parent is specified)
*/
is_class: function(cls, parent) {
// Validate class
var ret = ( this.is_func(cls) && ( 'prototype' in cls ) );
// Check parent class
if ( ret && this.is_set(parent) ) {
ret = this.is_instance(cls.prototype, parent);
}
return ret;
},
/**
* Check if value is a number
* @uses is_type()
* @param mixed value Value to check
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
* @return bool TRUE if value is a valid number
*/
is_num: function(value, nonempty) {
var f = {
'nan': ( Number.isNaN ) ? Number.isNaN : isNaN,
'finite': ( Number.isFinite ) ? Number.isFinite : isFinite
};
return ( this.is_type(value, 'number', nonempty) && !f.nan(value) && f.finite(value) );
},
/**
* Check if value is a integer
* @uses is_type()
* @param mixed value Value to check
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
* @return bool TRUE if value is a valid integer
*/
is_int: function(value, nonempty) {
return ( this.is_num(value, nonempty) && Math.floor(value) === value );
},
/**
* Check if value is scalar (string, number, boolean)
* @uses is_type()
* @param mixed value Value to check
* @param bool nonempty (optional) Check for empty value? (Default: TRUE)
* @return bool TRUE if value is scalar
*/
is_scalar: function(value, nonempty) {
return ( this.is_num(value, nonempty) || this.is_string(value, nonempty) || this.is_bool(value) );
},
/**
* Checks if value is empty
* @param mixed value Value to check
* @param string type (optional) Data type
* @return bool TRUE if value is empty
*/
is_empty: function(value, type) {
var ret = false;
// Check Undefined
if ( !this.is_set(value) ) {
ret = true;
} else {
// Check standard values
var empties = [null, "", false, 0];
var x = 0;
while ( !ret && x < empties.length ) {
ret = ( empties[x] === value );
x++;
}
}
// Advanced check
if ( !ret ) {
// Validate type
if ( !this.is_set(type) ) {
type = $.type(value);
}
// Type-based check
if ( this.is_type(value, type, false) ) {
switch ( type ) {
case 'string':
case 'array':
ret = ( value.length === 0 );
break;
case 'number':
ret = ( value == 0 ); // jshint ignore:line
break;
case 'object':
if ( !$.isPlainObject(value) ) {
// Custom object. Unable to evaluate emptiness further
ret = false;
} else {
// Evaluate plain object
if ( Object.getOwnPropertyNames ) {
// Modern browser check
ret = ( Object.getOwnPropertyNames(value).length === 0 );
} else if ( value.hasOwnProperty ) {
// Legacy browser check
ret = true;
for ( var key in value ) {
if ( value.hasOwnProperty(key) ) {
ret = false;
break;
}
}
}
}
break;
}
} else {
ret = true;
}
}
return ret;
},
/**
* Check if object is a jQuery.Promise instance
* Will also match (but not guarantee) jQuery.Deferred instances
* @uses is_method()
* @param obj obj Object to check
* @return bool TRUE if object is Promise/Deferred
*/
is_promise: function(obj) {
return ( this.is_method(obj, ['then', 'done', 'always', 'fail', 'pipe']) );
},
/**
* Return formatted string
* @param string fmt Format template
* @param string val Replacement value (Multiple parameters may be set)
* @return string Formatted string
*/
format: function(fmt, val) {
// Validate format
if ( !this.is_string(fmt) ) {
return '';
}
var params = [];
var ph = '%s';
/**
* Clean string (remove placeholders)
*/
var strip = function(txt) {
return ( txt.indexOf(ph) !== -1 ) ? txt.replace(ph, '') : txt;
};
// Stop processing if no replacement values specified or format string contains no placeholders
if ( arguments.length < 2 || fmt.indexOf(ph) === -1 ) {
return strip(fmt);
}
// Get replacement values
params = Array.prototype.slice.call(arguments, 1);
val = null;
// Clean parameters
for ( var x = 0; x < params.length; x++ ) {
if ( !this.is_scalar(params[x], false) ) {
params[x] = '';
}
}
// Replace all placeholders at once if single parameter set
if ( params.length === 1 ) {
fmt = fmt.replace(ph, params[0].toString());
} else {
var idx = 0; // Current replacement index
var len = params.length; // Number of replacements
var rlen = ph.length; // Placeholder length
var pos = 0; // Current placeholder position (in format template)
while ( ( pos = fmt.indexOf(ph) ) && pos !== -1 && idx < len ) {
// Replace current placeholder with respective parameter
fmt = fmt.substr(0, pos) + params[idx].toString() + fmt.substr(pos + rlen);
idx++;
}
// Remove any remaining placeholders
fmt = strip(fmt);
}
return fmt;
},
/**
* Checks if key(s) exist in an object
* @param object obj Object to check
* @param string|array key Key(s) to check for in object
* @param bool all (optional) All keys must exist in object? (Default: TRUE)
* @return bool TRUE if key(s) exist in object
*/
in_obj: function(obj, key, all) {
// Validate
if ( !this.is_bool(all) ) {
all = true;
}
if ( this.is_string(key) ) {
key = [key];
}
// Check for keys
var ret = false;
if ( this.is_obj(obj) && this.is_array(key) ) {
var val;
for ( var x = 0; x < key.length; x++ ) {
val = key[x];
ret = ( this.is_string(val) && ( val in obj ) ) ? true : false;
// Stop processing if conditions have been met
if ( ( !all && ret ) || ( all && !ret ) ) {
break;
}
}
}
return ret;
},
/**
* Retrieve an object's keys
* @param obj Object to parse
* @return array List of object's keys
*/
obj_keys: function(obj) {
var keys = [];
// Validation
if ( !this.is_obj(obj) ) {
return keys;
}
if ( Object.keys ) {
keys = Object.keys(obj);
} else {
var prop;
for ( prop in obj ) {
if ( obj.hasOwnProperty(prop) ) {
keys.push(prop);
}
}
}
return keys;
},
/**
* Find common elements of 2 or more arrays
* @param array arr1 First array
* @param array arr2 Second array (additional arrays can be passed as well)
* @return array Elements common to all
*/
arr_intersect: function(arr1, arr2) {
var ret = [];
// Get arrays
var params = Array.prototype.slice.call(arguments);
// Clean arrays
var arrs = [];
var x;
for ( x = 0; x < params.length; x++ ) {
if ( this.is_array(params[x], false) ) {
arrs.push(params[x]);
}
}
// Stop processing if no valid arrays to compare
if ( arrs.length < 2 ) {
return ret;
}
params = arr1 = arr2 = null;
// Find common elements in arrays
var base = arrs.shift();
var add;
var sub;
for ( x = 0; x < base.length; x++ ) {
add = true;
// Check other arrays for element match
for ( sub = 0; sub < arrs.length; sub++ ) {
if ( arrs[sub].indexOf(base[x]) === -1 ) {
add = false;
break;
}
}
if ( add ) {
ret.push(base[x]);
}
}
// Return intersection results
return ret;
},
/**
* Generates a GUID string.
* @returns string The generated GUID.
* @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
* @author Slavik Meltser (slavik@meltser.info).
* @link http://slavik.meltser.info/?p=142
*/
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(true) + _p8(true) + _p8();
},
/**
* Parse URI
* @param string uri URI to parse
* @return obj URI components (DOM anchor element)
*/
parse_uri: function(uri) {
return $('<a href="' + uri + '"/>').get(0);
},
/**
* Parse URI query string
* @param string uri URI with query string to parse
* @return obj Query variables and values (empty if no query string)
*/
parse_query: function(uri) {
var delim = {
'vars': '&',
'val': '='
};
var query = {
'raw': [],
'parsed': {},
'string': ''
};
uri = this.parse_uri(uri);
if ( 0 === uri.search.indexOf('?') ) {
// Extract query string
query.raw = uri.search.substr(1).split(delim.vars);
var i, temp, key, val;
// Build query object
for ( i = 0; i < query.raw.length; i++ ) {
// Split var and value
temp = query.raw[i].split(delim.val);
key = temp.shift();
val = ( temp.length > 0 ) ? temp.join(delim.val) : null;
query.parsed[key] = val;
}
}
return query.parsed;
},
/**
* Build query string from object
* @param obj query Query data
* @return string Query data formatted as HTTP query string
*/
build_query: function(query) {
var q = [];
var delim = {
'vars': '&',
'val': '='
};
var val;
for ( var key in query ) {
val = ( null !== query[key] ) ? delim.val + query[key] : '';
q.push(key + val);
}
return q.join(delim.vars);
}
};
// Attach Utilities
Base.attach('util', Utilities, true);
/**
* SLB Base Class
*/
var SLB_Base = Class.extend(Base);
/**
* Core
*/
var Core = {
/* Properties */
base: true,
context: [],
/**
* New object initializer
* @var obj
*/
Class: SLB_Base,
/* Methods */
/**
* Init
* Set variables, DOM, etc.
*/
_init: function() {
this._super();
$('html').addClass(this.util.get_prefix());
}
};
var SLB_Core = SLB_Base.extend(Core);
window.SLB = new SLB_Core();
})(jQuery);}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
window.SLB&&SLB.attach&&!function($){SLB.attach("Admin",{init:function(){postboxes&&postboxes.add_postbox_toggles(pagenow)}}),$(document).ready(function(){SLB.Admin.init()})}(jQuery);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,54 @@
.slb_section_head {
display: block;
padding: 2em 0 0;
}
.slb_option_item {
.block {
display: inline-block;
}
label.title {
width: 200px;
padding: 10px;
}
.input {
font-size: 11px;
line-height: 20px;
margin-bottom: 9px;
padding: 8px 10px;
}
.input select {
min-width: 12em;
}
}
.slb_notice {
color: #f00;
font-weight: bold;
}
.slb {
.columns-2 {
margin-right: 300px;
.postbox-container {
float: left;
width: 100%;
}
.content-secondary {
margin-right: -300px;
width: 280px;
float: right;
}
}
}
.slb_admin_action_reset {
color: #a00;
&:hover {
color: #dc3232;
border: none;
}
}

View File

@@ -0,0 +1,10 @@
html.slb_overlay {
object,embed,iframe {
visibility: hidden;
}
#slb_viewer_wrap {
object,embed,iframe {
visibility: visible;
}
}
}

View File

@@ -0,0 +1,8 @@
{
"require-dev": {
"squizlabs/php_codesniffer": "^3.5",
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2",
"wp-coding-standards/wpcs": "^2.2",
"phpcompatibility/phpcompatibility-wp": "*"
}
}

View File

@@ -0,0 +1,342 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d58ae19bd7c4cf76ada3935405677c26",
"packages": [],
"packages-dev": [
{
"name": "dealerdirect/phpcodesniffer-composer-installer",
"version": "v0.6.2",
"source": {
"type": "git",
"url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
"reference": "8001af8eb107fbfcedc31a8b51e20b07d85b457a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/8001af8eb107fbfcedc31a8b51e20b07d85b457a",
"reference": "8001af8eb107fbfcedc31a8b51e20b07d85b457a",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0",
"php": "^5.3|^7",
"squizlabs/php_codesniffer": "^2|^3"
},
"require-dev": {
"composer/composer": "*",
"phpcompatibility/php-compatibility": "^9.0",
"sensiolabs/security-checker": "^4.1.0"
},
"type": "composer-plugin",
"extra": {
"class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
},
"autoload": {
"psr-4": {
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Franck Nijhof",
"email": "franck.nijhof@dealerdirect.com",
"homepage": "http://www.frenck.nl",
"role": "Developer / IT Manager"
}
],
"description": "PHP_CodeSniffer Standards Composer Installer Plugin",
"homepage": "http://www.dealerdirect.com",
"keywords": [
"PHPCodeSniffer",
"PHP_CodeSniffer",
"code quality",
"codesniffer",
"composer",
"installer",
"phpcs",
"plugin",
"qa",
"quality",
"standard",
"standards",
"style guide",
"stylecheck",
"tests"
],
"time": "2020-01-29T20:22:20+00:00"
},
{
"name": "phpcompatibility/php-compatibility",
"version": "9.3.5",
"source": {
"type": "git",
"url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243",
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243",
"shasum": ""
},
"require": {
"php": ">=5.3",
"squizlabs/php_codesniffer": "^2.3 || ^3.0.2"
},
"conflict": {
"squizlabs/php_codesniffer": "2.6.2"
},
"require-dev": {
"phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0"
},
"suggest": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.",
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
},
"type": "phpcodesniffer-standard",
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "Wim Godden",
"homepage": "https://github.com/wimg",
"role": "lead"
},
{
"name": "Juliette Reinders Folmer",
"homepage": "https://github.com/jrfnl",
"role": "lead"
},
{
"name": "Contributors",
"homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors"
}
],
"description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.",
"homepage": "http://techblog.wimgodden.be/tag/codesniffer/",
"keywords": [
"compatibility",
"phpcs",
"standards"
],
"time": "2019-12-27T09:44:58+00:00"
},
{
"name": "phpcompatibility/phpcompatibility-paragonie",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git",
"reference": "b862bc32f7e860d0b164b199bd995e690b4b191c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b862bc32f7e860d0b164b199bd995e690b4b191c",
"reference": "b862bc32f7e860d0b164b199bd995e690b4b191c",
"shasum": ""
},
"require": {
"phpcompatibility/php-compatibility": "^9.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5",
"paragonie/random_compat": "dev-master",
"paragonie/sodium_compat": "dev-master"
},
"suggest": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
},
"type": "phpcodesniffer-standard",
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "Wim Godden",
"role": "lead"
},
{
"name": "Juliette Reinders Folmer",
"role": "lead"
}
],
"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.",
"homepage": "http://phpcompatibility.com/",
"keywords": [
"compatibility",
"paragonie",
"phpcs",
"polyfill",
"standards"
],
"time": "2019-11-04T15:17:54+00:00"
},
{
"name": "phpcompatibility/phpcompatibility-wp",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git",
"reference": "41bef18ba688af638b7310666db28e1ea9158b2f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/41bef18ba688af638b7310666db28e1ea9158b2f",
"reference": "41bef18ba688af638b7310666db28e1ea9158b2f",
"shasum": ""
},
"require": {
"phpcompatibility/php-compatibility": "^9.0",
"phpcompatibility/phpcompatibility-paragonie": "^1.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5"
},
"suggest": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
"roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
},
"type": "phpcodesniffer-standard",
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "Wim Godden",
"role": "lead"
},
{
"name": "Juliette Reinders Folmer",
"role": "lead"
}
],
"description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.",
"homepage": "http://phpcompatibility.com/",
"keywords": [
"compatibility",
"phpcs",
"standards",
"wordpress"
],
"time": "2019-08-28T14:22:28+00:00"
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.5.5",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
"reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
"shasum": ""
},
"require": {
"ext-simplexml": "*",
"ext-tokenizer": "*",
"ext-xmlwriter": "*",
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"bin": [
"bin/phpcs",
"bin/phpcbf"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Greg Sherwood",
"role": "lead"
}
],
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
"keywords": [
"phpcs",
"standards"
],
"time": "2020-04-17T01:09:41+00:00"
},
{
"name": "wp-coding-standards/wpcs",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
"reference": "7da1894633f168fe244afc6de00d141f27517b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62",
"reference": "7da1894633f168fe244afc6de00d141f27517b62",
"shasum": ""
},
"require": {
"php": ">=5.4",
"squizlabs/php_codesniffer": "^3.3.1"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
"phpcompatibility/php-compatibility": "^9.0",
"phpcsstandards/phpcsdevtools": "^1.0",
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"suggest": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
},
"type": "phpcodesniffer-standard",
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Contributors",
"homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
}
],
"description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
"keywords": [
"phpcs",
"standards",
"wordpress"
],
"time": "2020-05-13T23:57:56+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "1.1.0"
}

View File

@@ -0,0 +1,33 @@
if ( !!window.SLB && SLB.has_child('View.extend_content_handler') ) {(function($) {
SLB.View.extend_content_handler('image', {
/**
* Render images
* @param obj item Content Item
* @param obj dfr Promise for rendering process
* @return obj Promise for rendering process (Resolved when content is loaded)
*/
render: function(item, dfr) {
// Create image object
var img = new Image();
// Set load event
var handler = function() {
// Save Data
item.set_data(img);
// Set attributes
item.set_attribute('dimensions', {'width': img.width, 'height': img.height});
// Build output
var out = $('<img />', {'src': item.get_uri()});
// Resolve deferred
dfr.resolve(out);
};
// Attach event handler
$(img).on('load', function(e) { handler(e); });
// Load image
img.src = item.get_uri();
// Return promise
return dfr.promise();
}
});
})(jQuery);
}

View File

@@ -0,0 +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);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
<?php
/**
* Functions
* Provides global access to specific functionality
* @package Simple Lightbox
* @author Archetyped
*/
/* Template Tags */
/**
* Activate links in user-defined content
* @param string $content
* @return string Updated content with activated links
*/
function slb_activate( $content, $group = null ) {
// Validate
if ( empty( $content ) ) {
return $content;
}
// Activate links
$content = $GLOBALS['slb']->activate_links( $content, $group );
return $content;
}

View File

@@ -0,0 +1,168 @@
<?php
/**
* Requirements Validation
*
* Used to ensure environment meets plugin requirements.
*
* @package Simple Lightbox
* @since 2.7.0
*/
/**
* Plugin Requirements Validation class
*
* @since 2.7.0
*/
class SLB_Requirements_Check {
/**
* Plugin name
*
* @var string
*/
private $name = '';
/**
* Plugin file
*
* @var string
*/
private $file = '';
/**
* Plugin dependencies
*
* @var array
*/
private $deps = array(
'php' => '5.6.20',
);
/**
* Dependency failures log
*
* @var array
*/
private $fail = array();
/**
* URIs for notices, etc.
*
* @var array
*/
private $uri = array();
/**
* Constructor
*
* @param array $args Requirements data.
* @return void
*/
public function __construct( $args ) {
$args = (array) $args;
// Set properties.
foreach ( array_keys( get_class_vars( get_class( $this ) ) ) as $prop ) {
if ( ! isset( $args[ $prop ] ) ) {
continue;
}
// Merge array properties.
if ( is_array( $this->$prop ) && is_array( $args[ $prop ] ) ) {
$this->$prop = array_merge( $this->$prop, $args[ $prop ] );
continue;
}
// Set string properties.
if ( is_string( $this->$prop ) && is_scalar( $args[ $prop ] ) ) {
$this->$prop = (string) $args[ $prop ];
continue;
}
}
}
/**
* Check if plugin passes all requirements
*
* @return bool Requirements check result.
*/
public function passes() {
$result = true;
foreach ( $this->deps as $dep => $req ) {
$m = $dep . '_passes';
if ( ! method_exists( $this, $m ) ) {
continue;
}
$passes = $this->$m();
if ( ! $passes ) {
// Requirements do not pass.
$result = $passes;
// Log dependency failures.
$this->fail[] = $dep;
}
}
// Handle requirements failure.
if ( ! $result ) {
add_action( 'load-plugins.php', array( $this, 'handle_failure' ) );
}
return $result;
}
/**
* Handle requirements failure
*
* @return void
*/
public function handle_failure() {
// Handle each failed dependency.
foreach ( $this->fail as $dep ) {
$m = $dep . '_handle_failure';
if ( method_exists( $this, $m ) ) {
$this->$m();
}
}
// Deactivate plugin.
deactivate_plugins( plugin_basename( $this->file ) );
}
/**
* Validates PHP version.
*
* @return bool PHP requirement passes.
*/
private function php_passes() {
return version_compare( PHP_VERSION, $this->deps['php'], '>=' );
}
/**
* Handle PHP requirement failure
*
* @return void
*/
private function php_handle_failure() {
// Clear activation query variable from request (stop UI notices).
unset( $_GET['activate'] );
// Display notice to user.
add_action( 'admin_notices', array( $this, 'php_notice' ) );
}
/**
* Display requirements failure notice and deactivate plugin.
*
* @return void
*/
public function php_notice() {
global $slb_requirements;
// Display message to user.
$link = (object) array(
/* translators: 1: Plugin name */
'title' => sprintf( __( 'Learn more about %1$s\'s requirements', 'simple-lightbox' ), $this->name ),
/* translators: Plugin requirements link text. */
'text' => __( 'Learn More', 'simple-lightbox' ),
);
// Full link.
$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 ) );
/* translators: 1: Plugin name. 2: PHP version requirement. 3: Plugin requirements link. */
$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 );
?>
<div class="error"><p><?php echo $err_msg; ?></p></div>
<?php
}
}

View File

@@ -0,0 +1,686 @@
<?php
/**
* Admin functionality
* @package Simple Lightbox
* @subpackage Admin
* @author Archetyped
*/
class SLB_Admin extends SLB_Base {
/* Configuration */
protected $mode = 'sub';
/* Properties */
/**
* Parent object
* Set on initialization
* @var obj
*/
protected $parent = null;
/**
* Messages
* @var array
*/
protected $messages = array(
'reset' => 'The settings have been reset',
'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.',
'access_denied' => 'You do not have sufficient permissions',
);
/* Views */
/**
* Custom admin top-level menus
* Associative Array
* > Key: Menu ID
* > Val: Menu properties
* @var array
*/
protected $menus = array();
/**
* Custom admin pages
* Associative Array
* > Key: Page ID
* > Val: Page properties
* @var array
*/
protected $pages = array();
/**
* Custom admin sections
* Associative Array
* > Key: Section ID
* > Val: Section properties
* @var array
*/
protected $sections = array();
/**
* Actions
* Index Array
* @var array
*/
protected $actions = array();
/* Constructor */
public function __construct( &$parent ) {
parent::__construct();
// Set parent
if ( is_object( $parent ) ) {
$this->parent = $parent;
}
}
/* Init */
protected function _hooks() {
parent::_hooks();
// Init
add_action( 'admin_menu', $this->m( 'init_menus' ), 11 );
// Plugin actions
add_action( 'admin_action_' . $this->add_prefix( 'admin' ), $this->m( 'handle_action' ) );
// Notices
add_action( 'admin_notices', $this->m( 'handle_notices' ) );
// Plugin listing
add_filter( 'plugin_action_links_' . $this->util->get_plugin_base_name(), $this->m( 'plugin_action_links' ), 10, 4 );
add_filter( 'plugin_row_meta', $this->m( 'plugin_row_meta' ), 10, 4 );
add_action( 'in_plugin_update_message-' . $this->util->get_plugin_base_name(), $this->m( 'plugin_update_message' ), 10, 2 );
add_filter( 'site_transient_update_plugins', $this->m( 'plugin_update_transient' ) );
}
/**
* Declare client files (scripts, styles)
* @uses parent::_client_files()
* @return void
*/
protected function _client_files( $files = null ) {
$js_path = 'client/js/';
$js_path .= ( SLB_DEV ) ? 'dev' : 'prod';
$pfx = $this->get_prefix();
$files = array(
'scripts' => array(
'admin' => array(
'file' => "$js_path/lib.admin.js",
'deps' => array( '[core]' ),
'context' => array( "admin_page_$pfx" ),
'in_footer' => true,
),
),
'styles' => array(
'admin' => array(
'file' => 'client/css/admin.css',
'context' => array( "admin_page_$pfx", 'admin_page_plugins' ),
),
),
);
parent::_client_files( $files );
}
/* Handlers */
/**
* Handles routing of internal action to appropriate handler.
*
* @return void
*/
public function handle_action() {
// Parse action
$t = 'type';
$g = 'group';
$o = 'obj';
$this->add_prefix_ref( $t );
$this->add_prefix_ref( $g );
$this->add_prefix_ref( $o );
$r =& $_REQUEST;
// Confirm request contains necessary parameters.
if (
! isset( $r[ $t ], $r[ $g ], $r[ $o ] )
|| 'view' !== $r[ $t ]
) {
return;
}
// Confirm specified view instance exists.
$prop = $r[ $g ] . 's';
if (
! property_exists( $this, $prop )
|| ! is_array( $this->{$prop} )
|| ! isset( $this->{$prop}[ $r[ $o ] ] )
) {
return;
}
// Get view instance.
$view =& $this->{$prop}[ $r[ $o ] ];
// Pass request to view instance.
if ( $view instanceof SLB_Admin_View ) {
$view->do_callback();
}
}
/**
* Display notices
* Messages are localized upon display
* @uses `admin_notices` action hook to display messages
*/
public function handle_notices() {
$msgs = $this->util->apply_filters( 'admin_messages', array() );
foreach ( $msgs as $mid => $msg ) {
// Filter out empty messages
if ( empty( $msg ) ) {
continue;
}
// Build and display message
$mid = $this->add_prefix( 'msg_' . $mid );
?>
<div id="<?php echo esc_attr( $mid ); ?>" class="updated fade">
<p>
<?php echo esc_html( $msg ); ?>
</p>
</div>
<?php
}
}
/* Views */
/**
* Adds settings section for plugin functionality
* Section is added to specified admin section/menu
* @uses `admin_init` hook
*/
public function init_menus() {
// Add top level menus (when necessary)
$menu;
foreach ( $this->menus as $menu ) {
// Register menu
$hook = add_menu_page( $menu->get_label( 'title' ), $menu->get_label( 'menu' ), $menu->get_capability(), $menu->get_id(), $menu->get_callback() );
// Add hook to menu object
$menu->set_hookname( $hook );
$this->menus[ $menu->get_id_raw() ] =& $menu;
}
$page;
// Add subpages
foreach ( $this->pages as $page ) {
// Build Arguments
$args = array( $page->get_label( 'header' ), $page->get_label( 'menu' ), $page->get_capability(), $page->get_id(), $page->get_callback() );
$f = null;
// Handle pages for default WP menus
if ( $page->is_parent_wp() ) {
$f = 'add_' . $page->get_parent() . '_page';
}
// Handle pages for custom menus
if ( ! function_exists( $f ) ) {
array_unshift( $args, $page->get_parent() );
$f = 'add_submenu_page';
}
// Add admin page
$hook = call_user_func_array( $f, $args );
// Save hook to page properties
$page->set_hookname( $hook );
$this->pages[ $page->get_id_raw() ] =& $page;
}
// Add sections
$section;
foreach ( $this->sections as $section ) {
add_settings_section( $section->get_id(), $section->get_title(), $section->get_callback(), $section->get_parent() );
}
}
/* Methods */
/**
* Add a new view
* @param string $type View type
* @param string $id Unique view ID
* @param array $args Arguments to pass to view constructor
* @return Admin_View|bool View instance (FALSE if view was not properly initialized)
*/
protected function add_view( $type, $id, $args ) {
// Validate request
$class = $this->add_prefix( 'admin_' . $type );
$collection = $type . 's';
if ( ! class_exists( $class ) ) {
$class = $this->add_prefix( 'admin_view' );
$collection = null;
}
// Create new instance
$r = new ReflectionClass( $class );
$view = $r->newInstanceArgs( $args );
if ( $view->is_valid() && ! empty( $collection ) && property_exists( $this, $collection ) && is_array( $this->{$collection} ) ) {
$this->{$collection}[ $id ] =& $view;
}
unset( $r );
return $view;
}
/**
* Add plugin action link
* @uses `add_view()` to init/attach action instance
* @param string $id Action ID
* @param array $labels Text for action
* > title - Link text (also title attribute value)
* > confirm - Confirmation message
* > success - Success message
* > failure - Failure message
* @param array $data Additional data for action
* @return obj Action instance
*/
public function add_action( $id, $labels, $data = null ) {
$args = func_get_args();
return $this->add_view( 'action', $id, $args );
}
/*-** Menus **-*/
/**
* Adds custom admin panel
* @param string $id Menu ID
* @param string|array $labels Text labels
* @param int $pos (optional) Menu position in navigation (index order)
* @return Admin_Menu Menu instance
*/
public function add_menu( $id, $labels, $position = null ) {
$args = array( $id, $labels, null, null, null, $position );
return $this->add_view( 'menu', $id, $args );
}
/* Page */
/**
* Add admin page
* @uses this->pages
* @param string $id Page ID (unique)
* @param string $parent Menu ID to add page to
* @param string|array $labels Text labels (Associative array for multiple labels)
* > menu: Menu title
* > header: Page header
* @param string $capability (optional) Custom capability for accessing page
* @return Admin_Page Page instance
*/
public function add_page( $id, $parent, $labels, $callback = null, $capability = null ) {
$args = func_get_args();
return $this->add_view( 'page', $id, $args );
}
/* WP Pages */
/**
* Add admin page to a standard WP menu
* @uses this->add_page()
* @param string $id Page ID (unique)
* @param string $parent Name of WP menu to add page to
* @param string|array $labels Text labels (Associative array for multiple labels)
* > menu: Menu title
* > header: Page header
* @param string $capability (optional) Custom capability for accessing page
* @return Admin_Page Page instance
*/
public function add_wp_page( $id, $parent, $labels, $callback = null, $capability = null ) {
// Add page
$pg = $this->add_page( $id, $parent, $labels, $capability );
// Set parent as WP
if ( $pg ) {
$pg->set_parent_wp();
}
return $pg;
}
/**
* Add admin page to Dashboard menu
* @see add_dashboard_page()
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return Admin_Page Page instance
*/
public function add_dashboard_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'dashboard', $labels, $capability );
}
/**
* Add admin page to Comments menu
* @see add_comments_page()
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return string Page ID
*/
public function add_comments_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'comments', $labels, $capability );
}
/**
* Add admin page to Links menu
* @see add_links_page()
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return string Page ID
*/
public function add_links_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'links', $labels, $capability );
}
/**
* Add admin page to Posts menu
* @see add_posts_page()
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return string Page ID
*/
public function add_posts_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'posts', $labels, $capability );
}
/**
* Add admin page to Pages menu
* @see add_pages_page()
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return string Page ID
*/
public function add_pages_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'pages', $labels, $capability );
}
/**
* Add admin page to Media menu
* @see add_media_page()
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return string Page ID
*/
public function add_media_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'media', $labels, $capability );
}
/**
* Add admin page to Themes menu
* @see add_theme_page()
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return string Page ID
*/
public function add_theme_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'theme', $labels, $capability );
}
/**
* Add admin page to Plugins menu
* @see add_plugins_page()
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return string Page ID
*/
public function add_plugins_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'plugins', $labels, $capability );
}
/**
* Add admin page to Options menu
* @see add_options_page()
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return string Page ID
*/
public function add_options_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'options', $labels, $capability );
}
/**
* Add admin page to Tools menu
* @see add_management_page()
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return string Page ID
*/
public function add_management_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'management', $labels, $capability );
}
/**
* Add admin page to Users menu
* @uses this->add_wp_page()
* @param string $id Page ID (unique)
* @param string|array $labels Text labels (Associative array for multiple labels)
* @param string $capability (optional) Custom capability for accessing page
* @return string Page ID
*/
public function add_users_page( $id, $labels, $callback = null, $capability = null ) {
return $this->add_wp_page( $id, 'users', $labels, $capability );
}
/* Section */
/**
* Add section
* @uses this->sections
* @param string $id Unique section ID
* @param string $page Page ID
* @param string $labels Label text
* @return obj Section instance
*/
public function add_section( $id, $parent, $labels ) {
$args = func_get_args();
$section = $this->add_view( 'section', $id, $args );
// Add Section
if ( $section->is_valid() ) {
$this->sections[ $id ] = $section;
}
return $section;
}
/* Operations */
/**
* Adds custom links below plugin on plugin listing page
* @uses `plugin_action_links_$plugin-name` Filter hook
* @param $actions
* @param $plugin_file
* @param $plugin_data
* @param $context
*/
public function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
global $admin_page_hooks;
// Add link to settings (only if active)
if ( is_plugin_active( $this->util->get_plugin_base_name() ) ) {
/* Get Actions */
$acts = array();
$type = 'plugin_action';
/* Get view links */
foreach ( array( 'menus', 'pages', 'sections' ) as $views ) {
foreach ( $this->{$views} as $view ) {
if ( ! $view->has_label( $type ) ) {
continue;
}
$acts[] = (object) array(
'id' => $views . '_' . $view->get_id(),
'label' => $view->get_label( $type ),
'uri' => $view->get_uri(),
'attributes' => array(),
);
}
}
/* Get action links */
$type = 'title';
foreach ( $this->actions as $a ) {
if ( ! $a->has_label( $type ) ) {
continue;
}
$id = 'action_' . $a->get_id();
$acts[] = (object) array(
'id' => $id,
'label' => $a->get_label( $type ),
'uri' => $a->get_uri(),
'attributes' => $a->get_link_attr(),
);
}
unset( $a );
// Add links
$links = array();
foreach ( $acts as $act ) {
$links[ $act->id ] = $this->util->build_html_link( $act->uri, $act->label, $act->attributes );
}
// Add links
$actions = array_merge( $links, $actions );
}
return $actions;
}
/**
* Update plugin listings metadata
* @param array $plugin_meta Plugin metadata
* @param string $plugin_file Plugin file
* @param array $plugin_data Plugin Data
* @param string $status Plugin status
* @return array Updated plugin metadata
*/
public function plugin_row_meta( $plugin_meta, $plugin_file, $plugin_data, $status ) {
$u = ( is_object( $this->parent ) && isset( $this->parent->util ) ) ? $this->parent->util : $this->util;
$hook_base = 'admin_plugin_row_meta_';
if ( $plugin_file === $u->get_plugin_base_name() ) {
// Add metadata
// Support
$l = $u->get_plugin_info( 'SupportURI' );
if ( ! empty( $l ) ) {
$t = __( 'Feedback &amp; Support', 'simple-lightbox' );
$plugin_meta[] = $u->build_html_link( $l, $t );
}
}
return $plugin_meta;
}
/**
* Adds additional message for plugin updates
* @uses `in_plugin_update_message-$plugin-name` Action hook
* @uses this->plugin_update_get_message()
* @var array $plugin_data Current plugin data
* @var object $r Update response data
*/
public function plugin_update_message( $plugin_data, $r ) {
if ( ! isset( $r->new_version ) ) {
return false;
}
if ( stripos( $r->new_version, 'beta' ) !== false ) {
$cls_notice = $this->add_prefix( 'notice' );
echo '<br />' . $this->plugin_update_get_message( $r );
}
}
/**
* Modify update plugins response data if necessary
* @uses `site_transient_update_plugins` Filter hook
* @uses this->plugin_update_get_message()
* @param obj $transient Transient data
* @return obj Modified transient data
*/
public function plugin_update_transient( $transient ) {
$n = $this->util->get_plugin_base_name();
if ( isset( $transient->response ) && isset( $transient->response[ $n ] ) && is_object( $transient->response[ $n ] ) && ! isset( $transient->response[ $n ]->upgrade_notice ) ) {
$r =& $transient->response[ $n ];
$r->upgrade_notice = $this->plugin_update_get_message( $r );
}
return $transient;
}
/**
* Retrieve custom update message
* @uses this->get_message()
* @param obj $r Response data from plugin update API
* @return string Message (Default: empty string)
*/
protected function plugin_update_get_message( $r ) {
$msg = '';
$cls_notice = $this->add_prefix( 'notice' );
if ( ! is_object( $r ) || ! isset( $r->new_version ) ) {
return $msg;
}
if ( stripos( $r->new_version, 'beta' ) !== false ) {
$msg = sprintf( $this->get_message( 'beta' ), $cls_notice );
}
return $msg;
}
/*-** Messages **-*/
/**
* Retrieve stored messages
* @param string $msg_id Message ID
* @return string Message text
*/
public function get_message( $msg_id ) {
$msg = '';
$msgs = $this->get_messages();
if ( is_string( $msg_id ) && isset( $msgs[ $msg_id ] ) ) {
$msg = $msgs[ $msg_id ];
}
return $msg;
}
/**
* Retrieve all messages
* Initializes messages if necessary
* @uses $messages
* @return array Messages
*/
function get_messages() {
if ( empty( $this->messages ) ) {
// Initialize messages if necessary
$this->messages = array(
'reset' => __( 'The settings have been reset', 'simple-lightbox' ),
/* translators: 1: Notice CSS class */
'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' ),
'access_denied' => __( 'Access Denied', 'simple-lightbox' ),
);
}
return $this->messages;
}
/**
* Set message text
* @uses this->messages
* @param string $id Message ID
* @param string $text Message text
*/
public function set_message( $id, $text ) {
$this->messages[ trim( $id ) ] = $text;
}
}

View File

@@ -0,0 +1,110 @@
<?php
/**
* Plugin action functionality
* Used for adding action links to plugin listing, etc.
* @package Simple Lightbox
* @subpackage Admin
* @author Archetyped
*/
class SLB_Admin_Action extends SLB_Admin_View {
/* Properties */
protected $parent_required = false;
public $hook_prefix = 'admin_action';
/* Init */
/**
* Init
* @param string $id ID
* @param array $labels Labels
* @param obj $data Action data
* @return obj Current instance
*/
function __construct( $id, $labels, $data = null ) {
parent::__construct( $id, $labels );
// Default options instance
if ( ! empty( $data ) ) {
$this->add_content( 'data', $data );
}
return $this;
}
/* Handlers */
/**
* Default handler
* Handles action
* @return string Status message (success, fail, etc.)
*/
public function handle() {
// Validate user
if ( ! current_user_can( 'activate_plugins' ) || ! check_admin_referer( $this->get_id() ) ) {
wp_die( __( 'Access Denied', 'simple-lightbox' ) );
}
// Get data
$content = $this->get_content();
$success = true;
// Iterate through data
$hook = $this->util->get_hook( $this->get_id_raw() );
foreach ( $content as $c ) {
// Trigger action
$res = apply_filters( $hook, $success, $c->data, $this );
// Set result
if ( ! ! $success ) {
$success = $res;
}
}
// Set Status Message
$lbl = ( $success ) ? 'success' : 'failure';
$this->set_message( $this->get_label( $lbl ) );
}
/**
* Get URI
* @see Admin_View::get_uri()
*/
public function get_uri( $file = null, $format = null ) {
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() );
}
protected function get_query_args() {
return array(
'action' => $this->add_prefix( 'admin' ),
$this->add_prefix( 'type' ) => 'view',
$this->add_prefix( 'group' ) => 'action',
$this->add_prefix( 'obj' ) => $this->get_id_raw(),
);
}
protected function get_query_args_remove() {
$args_r = array(
'_wpnonce',
$this->add_prefix( 'action' ),
);
return array_unique( array_merge( array_keys( $this->get_query_args() ), $args_r ) );
}
public function get_link_attr() {
return array(
'class' => $this->util->get_hook( $this->get_id_raw() ),
'onclick' => "return confirm('" . esc_js( $this->get_label( 'confirm' ) ) . "')",
);
}
/* Content */
/**
* Save options
*/
public function add_content( $id, $data ) {
return parent::add_content( $id, array( 'data' => $data ) );
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Admin Menu
* Menus are top-level views in the Admin UI
* @package Simple Lightbox
* @subpackage Admin
* @author Archetyped
*/
class SLB_Admin_Menu extends SLB_Admin_View {
/* Properties */
/**
* Menu position
* @var int
*/
protected $position = null;
/* Init */
public function __construct( $id, $labels, $callback = null, $capability = null, $icon = null, $position = null ) {
// Default
parent::__construct( $id, $labels, $callback, $capability, $icon );
// Class specific
$this->set_position( $position );
return $this;
}
/* Getters/Setters */
/**
* Set menu position
* @return obj Current instance
*/
public function set_position( $position ) {
if ( is_int( $position ) ) {
$this->position = $position;
}
return $this;
}
}

View File

@@ -0,0 +1,188 @@
<?php
/**
* Admin Page
* Pages are part of a Menu
* @package Simple Lightbox
* @subpackage Admin
* @author Archetyped
*/
class SLB_Admin_Page extends SLB_Admin_View {
/* Properties */
protected $parent_required = true;
public $hook_prefix = 'admin_page';
/**
* Required features/elements
*/
private $_required = array();
/* Init */
public function __construct( $id, $parent, $labels, $callback = null, $capability = null ) {
// Default
parent::__construct( $id, $labels, $callback, $capability );
// Class specific
$this->set_parent( $parent );
return $this;
}
/* Operations */
/**
* Add content to page
* @uses parent::add_content()
* @param string $id Module ID
* @param string $title Module title
* @param mixed $callback Callback method or other data for building module UI
* @param string $context (optional) Context to add module to (Default: primary)
* @param string $priority (optional) Controls module ordering (Default: default)
* @param array $callback_args (optional) Additional data to pass callback (Default: NULL)
* @return object Page instance reference
*/
public function add_content( $id, $title, $callback = null, $context = 'primary', $priority = 'default', $callback_args = null ) {
$opts = [
'id' => $id,
'title' => $title,
'callback' => $callback,
'context' => $context,
'priority' => $priority,
'callback_args' => $callback_args,
];
return parent::add_content( $id, $opts );
}
/**
* Parse content by parameters
* Sets content value
*/
protected function parse_content() {
// Get raw content
$raw = $this->get_content( false );
// Group by context
$content = array();
foreach ( $raw as $c ) {
// Add new context
if ( ! isset( $content[ $c->context ] ) ) {
$content[ $c->context ] = array();
}
// Add item to context
$content[ $c->context ][] = $c;
}
return $content;
}
/**
* Render content blocks
* @param string $context (optional) Context to render
*/
protected function render_content( $context = 'primary' ) {
// Get content
$content = $this->get_content();
// Check for context
if ( ! isset( $content[ $context ] ) ) {
return false;
}
$content = $content[ $context ];
$out = '';
// Render content
?>
<div class="content-wrap">
<?php
// Add meta boxes
$screen = get_current_screen();
foreach ( $content as $c ) {
$c->screen = $screen;
// Callback
if ( is_callable( $c->callback ) ) {
$callback = $c->callback;
add_meta_box( $c->id, $c->title, $c->callback, $c->screen, $c->context, $c->priority, $c->callback_args );
} else {
// Let handlers build output
$this->util->do_action( 'render_content', $c->callback, $this, $c );
}
}
// Output meta boxes
do_meta_boxes( $screen, $context, null );
?>
</div>
<?php
}
/**
* Require form submission support
* @return obj Page instance
*/
public function require_form() {
$this->_require( 'form_submit' );
return $this;
}
/**
* Check if form submission is required
* @return bool TRUE if form submission required
*/
private function is_required_form() {
return $this->_is_required( 'form_submit' );
}
/* Handlers */
/**
* Default Page handler
* Builds content blocks
* @see this->init_menus() Set as callback for custom admin pages
* @uses current_user_can() to check if user has access to current page
* @uses wp_die() to end execution when user does not have permission to access page
*/
public function handle() {
if ( ! current_user_can( $this->get_capability() ) ) {
wp_die( __( 'Access Denied', 'simple-lightbox' ) );
}
wp_enqueue_script( 'postbox' );
?>
<div class="wrap slb">
<h2><?php echo esc_html( $this->get_label( 'header' ) ); ?></h2>
<?php
// Form submission support
if ( $this->is_required_form() ) {
// Build form output
$form_id = $this->add_prefix( 'admin_form_' . $this->get_id_raw() );
$nonce = (object) [
'action' => $this->get_id(),
'name' => $this->get_id() . '_nonce',
];
?>
<form id="<?php echo esc_attr( $form_id ); ?>" name="<?php echo esc_attr( $form_id ); ?>" action="" method="post">
<?php
wp_nonce_field( $nonce->action, $nonce->name );
}
?>
<div class="metabox-holder columns-2">
<div class="content-primary postbox-container">
<?php
$this->render_content( 'primary' );
?>
</div>
<div class="content-secondary postbox-container">
<?php
$this->render_content( 'secondary' );
?>
</div>
</div>
<br class="clear" />
<?php
// Form submission support
if ( $this->is_required_form() ) {
submit_button();
?>
</form>
<?php
}
?>
</div>
<?php
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Admin Section
* Sections are part of a Page
* @package Simple Lightbox
* @subpackage Admin
* @author Archetyped
*/
class SLB_Admin_Section extends SLB_Admin_View {
/* Properties */
protected $parent_required = true;
protected $parent_custom = false;
/* Init */
public function __construct( $id, $parent, $labels, $callback = null, $capability = null ) {
// Default
parent::__construct( $id, $labels, $callback, $capability );
// Class specific
$this->set_parent( $parent );
return $this;
}
/* Getters/Setters */
/**
* Retrieve URI
* @uses Admin_View::get_uri()
* @param string $file (optional) Base file name
* @param string $format (optional) String format
* @return string Section URI
*/
public function get_uri( $file = null, $format = null ) {
if ( ! is_string( $file ) ) {
$file = 'options-' . $this->get_parent() . '.php';
}
if ( ! is_string( $format ) ) {
$format = '%1$s#%2$s';
}
return parent::get_uri( $file, $format );
}
/**
* Retrieve formatted title for section
* Wraps title text in element with anchor so that it can be linked to
* @return string Title
*/
public function get_title() {
return sprintf( '<div id="%1$s" class="%2$s">%3$s</div>', $this->get_id(), $this->add_prefix( 'section_head' ), $this->get_label( 'title' ) );
}
}

View File

@@ -0,0 +1,553 @@
<?php
/**
* Admin View Base
* Core functionality Admin UI components
* @package Simple Lightbox
* @subpackage Admin
* @author Archetyped
*/
class SLB_Admin_View extends SLB_Base_Object {
/* Properties */
/**
* Labels
* @var array (Associative)
*/
protected $labels = array();
/**
* Function to handle building UI
* @var callback
*/
protected $callback = null;
/**
* Capability for access control
* @var string
*/
protected $capability = 'manage_options';
/**
* Icon to use
* @var string
*/
protected $icon = null;
/**
* View parent ID/Slug
* @var string
*/
protected $parent = null;
/**
* Whether parent is a custom view or a default WP one
* @var bool
*/
protected $parent_custom = true;
/**
* If view requires a parent
* @var bool
*/
protected $parent_required = false;
/**
* WP-Generated hook name for view
* @var string
*/
protected $hookname = null;
/**
* Raw content parameters
* Stores pre-rendered content parameters
* Items stored by ID (key)
* @var array
*/
protected $content_raw = array();
/**
* Parsed content parameters
* @var array
*/
protected $content = array();
/**
* Messages to be displayed
* Indexed Array
* @var array
*/
protected $messages = array();
/**
* Required properties
* Associative array
* > Key: Property name
* > Value: Required data type
* @var array
*/
private $required = array();
/**
* Default required properties
* Merged into $required array with this->init_required()
* @see this->required for more information
* @var array
*/
private $_required = array(
'id' => 'string',
'labels' => 'array',
);
/* Init */
/**
* Constructor
* @return obj Current instance
*/
public function __construct( $id, $labels, $callback = null, $capability = null, $icon = null ) {
$props = array(
'labels' => $labels,
'callback' => $callback,
'capability' => $capability,
'icon' => $icon,
);
parent::__construct( $id, $props );
$this->init_required();
return $this;
}
protected function init_required() {
$this->required = array_merge( $this->_required, $this->required );
// Check for parent requirement
if ( $this->parent_required ) {
$this->required['parent'] = 'string';
}
}
/**
* Set required feature
* @param string $feature Required feature
*/
protected function _require( $feature ) {
if ( ! isset( $this->_required[ $feature ] ) ) {
$this->_required[ $feature ] = true;
}
return $this;
}
/**
* Check if feature is required
* @param string $feature Feature to check for
* @return bool TRUE if feature required
*/
protected function _is_required( $feature ) {
return ( isset( $this->_required[ $feature ] ) ) ? true : false;
}
/* Property Methods */
/**
* Retrieve ID (Formatted by default)
* @param bool $formatted (optional) Whether ID should be formatted for external use or not
* @return string ID
*/
public function get_id( $formatted = true ) {
$id = parent::get_id();
if ( $formatted ) {
$this->add_prefix_ref( $id );
}
return $id;
}
/**
* Retrieve raw ID
* @return string Raw ID
*/
public function get_id_raw() {
return $this->get_id( false );
}
/**
* Retrieve label
* Uses first label (or default if defined) if specified type does not exist
* @param string $type Label type to retrieve
* @param string $default (optional) Default value if label type does not exist
* @return string Label text
*/
public function get_label( $type, $default = null ) {
// Retrieve existing label type
if ( $this->has_label( $type ) ) {
return $this->labels[ $type ];
}
// Use default label if type is not set
if ( empty( $default ) && ! empty( $this->labels ) ) {
reset( $this->labels );
$default = current( $this->labels );
}
return ( empty( $default ) ) ? '' : $default;
}
/**
* Set text labels
* @param array|string $labels
* @return obj Current instance
*/
public function set_labels( $labels ) {
if ( empty( $labels ) ) {
return this;
}
// Single string
if ( is_string( $labels ) ) {
$labels = array( $labels );
}
// Array
if ( is_array( $labels ) ) {
// Merge with existing labels
if ( empty( $this->labels ) || ! is_array( $this->labels ) ) {
$this->labels = array();
}
$this->labels = array_merge( $this->labels, $labels );
}
return $this;
}
/**
* Set single text label
* @uses this->set_labels()
* @param string $type Label type to set
* @param string $value Label value
* @return obj Current instance
*/
public function set_label( $type, $value ) {
if ( is_string( $type ) && is_string( $value ) ) {
$label = array( $type => $value );
$this->set_labels( $label );
}
return $this;
}
/**
* Checks if specified label is set on view
* @param string $type Label type
* @return bool TRUE if label exists, FALSE otherwise
*/
public function has_label( $type ) {
return ( isset( $this->labels[ $type ] ) );
}
/* Content */
/**
* Add content block to view
* Child classes define method functionality
* @param string $id Content block ID
* @param array $args Content arguments (Defined by child class), converted to an object
* @return obj Current View instance
*/
public function add_content( $id, $args ) {
// Save parameters
$this->content_raw[ $id ] = (object) $args;
// Clear parsed content
$this->content = array();
// Return instance reference
return $this;
}
/**
* Retrieve content
*/
protected function get_content( $parsed = true ) {
// Return raw content.
if ( ! $parsed ) {
return $this->content_raw;
}
// Return parsed content.
if ( empty( $this->content ) && ! empty( $this->content_raw ) ) {
$this->content = $this->parse_content();
}
return $this->content;
}
/**
* Parse content
* Child classes define functionality
* @return array Parsed content
*/
protected function parse_content() {
return $this->get_content( false );
}
/**
* Check if content has been added to view
* @return bool TRUE if content added
*/
protected function has_content() {
$raw = $this->get_content( false );
return ! empty( $raw );
}
/**
* Render content
*/
protected function render_content( $context = 'default' ) {}
/**
* Retrieve view messages
* @return array Messages
*/
protected function &get_messages() {
if ( ! is_array( $this->messages ) ) {
$this->messages = array();
}
return $this->messages;
}
/**
* Save message
* @param string $text Message text
* @return obj Current instance
*/
public function set_message( $text ) {
$msgs =& $this->get_messages();
$text = trim( $text );
if ( empty( $msgs ) && ! empty( $text ) ) {
$this->util->add_filter( 'admin_messages', $this->m( 'do_messages' ), 10, 1, false );
}
$msgs[] = $text;
return $this;
}
/**
* Add messages to array
* Called by internal `admin_messages` filter hook
* @param array $msgs Aggregated messages
* @return array Merged messages array
*/
public function do_messages( $msgs = array() ) {
$m =& $this->get_messages();
if ( ! empty( $m ) ) {
$msgs = array_merge( $msgs, $m );
}
return $msgs;
}
/**
* Retrieve view callback
* @return callback Callback (Default: standard handler method)
*/
public function get_callback() {
return ( $this->has_callback() ) ? $this->callback : $this->m( 'handle' );
}
/**
* Set callback function for building item
* @param callback $callback Callback function to use
* @return obj Current instance
*/
public function set_callback( $callback ) {
$this->callback = ( is_callable( $callback ) ) ? $callback : null;
return $this;
}
/**
* Check if callback set
* @return bool TRUE if callback is set
*/
protected function has_callback() {
return ( ! empty( $this->callback ) ) ? true : false;
}
/**
* Run callback
*/
public function do_callback() {
call_user_func( $this->get_callback() );
}
/**
* Retrieve capability
* @return string Capability
*/
public function get_capability() {
return $this->capability;
}
/**
* Set capability for access control
* @param string $capability Capability
* @return obj Current instance
*/
public function set_capability( $capability ) {
if ( is_string( $capability ) && ! empty( $capability ) ) {
$this->capability = $capability;
}
return $this;
}
/**
* Set icon
* @param string $icon Icon URI
* @return obj Current instance
*/
public function set_icon( $icon ) {
if ( ! empty( $icon ) && is_string( $icon ) ) {
$this->icon = $icon;
}
return $this;
}
protected function get_hookname() {
return ( empty( $this->hookname ) ) ? '' : $this->hookname;
}
/**
* Set hookname
* @param string $hookname Hookname value
* @return obj Current instance
*/
public function set_hookname( $hookname ) {
if ( ! empty( $hookname ) && is_string( $hookname ) ) {
$this->hookname = $hookname;
}
return $this;
}
/**
* Retrieve parent
* Formats parent ID for custom parents
* @uses parent::get_parent()
* @return string Parent ID
*/
public function get_parent() {
$parent = parent::get_parent();
return ( $this->is_parent_custom() ) ? $this->add_prefix( $parent ) : $parent;
}
/**
* Set parent for view
* @param string $parent Parent ID
* @return obj Current instance
*/
public function set_parent( $parent ) {
if ( $this->parent_required ) {
if ( ! empty( $parent ) && is_string( $parent ) ) {
$this->parent = $parent;
}
} else {
$this->parent = null;
}
return $this;
}
/**
* Specify whether parent is a custom view or a WP view
* @param bool $custom (optional) TRUE if custom, FALSE if WP
* @return obj Current instance
*/
protected function set_parent_custom( $custom = true ) {
if ( $this->parent_required ) {
$this->parent_custom = ! ! $custom;
}
return $this;
}
/**
* Set parent as WP view
* @uses this->set_parent_custom()
* @return obj Current instance
*/
public function set_parent_wp() {
$this->set_parent_custom( false );
return $this;
}
/**
* Get view URI
* URI Structures:
* > Top Level Menus: admin.php?page={menu_id}
* > Pages: [parent_page_file.php|admin.php]?page={page_id}
* > Section: [parent_menu_uri]#{section_id}
*
* @uses $admin_page_hooks to determine if page is child of default WP page
* @param string $file (optional) Base file name
* @param string $format (optional) Format string for URI
* @return string Object URI
*/
public function get_uri( $file = null, $format = null ) {
static $page_hooks = null;
$uri = '';
if ( empty( $file ) ) {
$file = 'admin.php';
}
if ( $this->is_child() ) {
$parent = str_replace( '_page_' . $this->get_id(), '', $this->get_hookname() );
if ( is_null( $page_hooks ) ) {
$page_hooks = array_flip( $GLOBALS['admin_page_hooks'] );
}
if ( isset( $page_hooks[ $parent ] ) ) {
$file = $page_hooks[ $parent ];
}
}
if ( empty( $format ) ) {
$delim = ( strpos( $file, '?' ) === false ) ? '?' : '&amp;';
$format = '%1$s' . $delim . 'page=%2$s';
}
$uri = sprintf( $format, $file, $this->get_id() );
return $uri;
}
/* Handlers */
/**
* Default View handler
* Used as callback when none set
*/
public function handle() {}
/* Validation */
/**
* Check if instance is valid based on required properties/data types
* @return bool TRUE if valid, FALSE if not valid
*/
public function is_valid() {
$invalid = false;
foreach ( $this->required as $prop => $type ) {
// Baseline validation.
if (
empty( $this->{$prop} )
|| empty( $type )
|| ! is_string( $type )
) {
return $invalid;
}
// Validate data type.
$f = 'is_' . $type;
if ( ! function_exists( $f ) || ! $f( $this->{$prop} ) ) {
return $invalid;
}
}
return true;
}
protected function is_child() {
return $this->parent_required;
}
protected function is_parent_custom() {
return ( $this->is_child() && $this->parent_custom ) ? true : false;
}
public function is_parent_wp() {
return ( $this->is_child() && ! $this->parent_custom ) ? true : false;
}
}

View File

@@ -0,0 +1,561 @@
<?php
/**
* @package Simple Lightbox
* @subpackage Base
* @author Archetyped
*
*/
class SLB_Base {
/* Configuration */
/**
* Class type
* Controls initialization, etc.
* > full - Fully-functional class
* > sub - Sub-class (attached to an instance)
* > object - Simple object class (no hooks, etc.)
* @var string
*/
protected $mode = 'full';
/**
* Indicates that instance is model (main controller)
* @var bool
*/
protected $model = false;
/* Properties */
/**
* Variable name of base object in global scope
* @var string
*/
protected $base = 'slb';
/**
* Prefix for plugin-related data (attributes, DB tables, etc.)
* @var string
*/
public $prefix = 'slb';
/**
* Prefix to be added when creating internal hook (action/filter) tags
* Used by Utilities
* @var string
*/
public $hook_prefix = '';
/**
* Global data
* Facilitates sharing between decoupled objects
* @var array
*/
private static $globals = array();
protected $shared = array( 'options', 'admin' );
/**
* Capabilities
* @var array
*/
protected $caps = null;
protected $_init = false;
private static $_init_passed = false;
/* Client */
/**
* Client files
* @var array
* Structure
* > Key: unique file ID
* > Properties
* > file (string) File path (Relative to plugin base)
* > deps (array) Script dependencies
* > Internal dependencies are wrapped in square brackets ([])
* > context (string|array)
* > Context in which the script should be included
* > in_footer (bool) optional [Default: FALSE]
* > If TRUE, file will be included in footer of page, otherwise it will be included in the header
*
* Array is processed and converted to an object on init
*/
private $client_files = array(
'scripts' => array(),
'styles' => array(),
);
/*-** Instances **-*/
/**
* Utilities
* @var SLB_Utilities
*/
public $util = null;
/**
* Options
* @var SLB_Options
*/
protected $options = null;
/**
* Admin
* @var SLB_Admin
*/
public $admin = null;
/*-** Initialization **-*/
/**
* Constructor
*/
function __construct() {
$this->util = new SLB_Utilities( $this );
if ( $this->can( 'init' ) ) {
$hook = 'init';
if ( did_action( $hook ) || self::$_init_passed ) {
$this->_init();
} else {
add_action( $hook, $this->m( '_init' ), 1 );
}
}
}
/**
* Default initialization method
* @uses _init_passed
* @uses _env()
* @uses _options()
* @uses _admin()
* @uses _hooks()
* @uses _client_files()
*/
public function _init() {
self::$_init_passed = true;
if ( $this->_init || ! isset( $this ) || ! $this->can( 'init' ) ) {
return false;
}
$this->_init = true;
// Environment
$this->_env();
if ( $this->can( 'control' ) ) {
// Options
$this->_options();
// Admin
if ( is_admin() ) {
$this->_admin();
}
}
// Hooks
$this->_hooks();
// Client files
$this->_client_files();
}
/**
* Initialize environment (Localization, etc.)
*/
private function _env() {
if ( ! $this->can( 'singleton' ) ) {
return false;
}
// Localization
$ldir = 'l10n';
$lpath = $this->util->get_plugin_file_path( $ldir, array( false, false ) );
$lpath_abs = $this->util->get_file_path( $ldir );
if ( is_dir( $lpath_abs ) ) {
load_plugin_textdomain( 'simple-lightbox', false, $lpath );
}
// Context
add_action( ( is_admin() ) ? 'admin_print_footer_scripts' : 'wp_footer', $this->util->m( 'set_client_context' ), $this->util->priority( 'client_footer_output' ) );
}
/**
* Initialize options
* To be implemented in child classes
*/
protected function _options() {}
/**
* Initialize options
* To be called by child class
*/
protected function _set_options( $options_config = null ) {
$class = $this->util->get_class( 'Options' );
$key = 'options';
if ( $this->shares( $key ) ) {
$opts = $this->gvar( $key );
// Setup options instance
if ( ! ( $opts instanceof $class ) ) {
$opts = $this->gvar( $key, new $class() );
}
} else {
$opts = new $class();
}
// Load options
if ( $this->is_options_valid( $options_config, false ) ) {
$opts->load( $options_config );
}
// Set instance property
$this->options = $opts;
}
/**
* Initialize admin
* To be called by child class
*/
private function _admin() {
if ( ! is_admin() ) {
return false;
}
$class = $this->util->get_class( 'Admin' );
$key = 'admin';
if ( $this->shares( $key ) ) {
$adm = $this->gvar( $key );
// Setup options instance
if ( ! ( $adm instanceof $class ) ) {
$adm = $this->gvar( $key, new $class( $this ) );
}
} else {
$adm = new $class( $this );
}
// Set instance property
$this->admin = $adm;
}
/**
* Register default hooks
*/
protected function _hooks() {
$base = $this->util->get_plugin_base_file();
// Activation
$func_activate = '_activate';
if ( method_exists( $this, $func_activate ) ) {
register_activation_hook( $base, $this->m( $func_activate ) );
}
// Deactivation
$func_deactivate = '_deactivate';
if ( method_exists( $this, $func_deactivate ) ) {
register_deactivation_hook( $base, $this->m( $func_deactivate ) );
}
}
/**
* Initialize client files
*/
protected function _client_files( $files = null ) {
// Validation
if ( ! is_array( $files ) || empty( $files ) ) {
return false;
}
foreach ( $this->client_files as $key => $val ) {
if ( isset( $files[ $key ] ) && is_array( $files[ $key ] ) || ! empty( $files[ $key ] ) ) {
$this->client_files[ $key ] = $this->util->parse_client_files( $files[ $key ], $key );
}
// Remove empty file groups
if ( empty( $this->client_files[ $key ] ) ) {
unset( $this->client_files[ $key ] );
}
}
// Stop if no files are set for registration
if ( empty( $this->client_files ) ) {
return false;
}
// Register
add_action( 'init', $this->m( 'register_client_files' ) );
// Enqueue
$hk_prfx = ( ( is_admin() ) ? 'admin' : 'wp' );
$hk_enqueue = $hk_prfx . '_enqueue_scripts';
$hk_enqueue_ft = $hk_prfx . '_footer';
add_action( $hk_enqueue, $this->m( 'enqueue_client_files' ), 10, 0 );
add_action( $hk_enqueue_ft, $this->m( 'enqueue_client_files_footer' ), 1 );
}
/**
* Register client files
* @see enqueue_client_files() for actual loading of files based on context
* @uses `init` Action hook for execution
* @return void
*/
public function register_client_files() {
$v = $this->util->get_plugin_version();
foreach ( $this->client_files as $type => $files ) {
$func = $this->get_client_files_handler( $type, 'register' );
if ( ! $func ) {
continue;
}
foreach ( $files as $f ) {
// Get file URI
$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 );
$params = array( $f->id, $f->file, $f->deps, $v );
// Set additional parameters based on file type (script, style, etc.)
switch ( $type ) {
case 'scripts':
$params[] = $f->in_footer;
break;
case 'styles':
$params[] = $f->media;
break;
}
// Register file
call_user_func_array( $func, $params );
}
}
}
/**
* Enqueues files for client output (scripts/styles) based on context
* @uses `admin_enqueue_scripts` Action hook depending on context
* @uses `wp_enqueue_scripts` Action hook depending on context
* @param bool $footer (optional) Whether to enqueue footer files (Default: No)
* @return void
*/
function enqueue_client_files( $footer = false ) {
// Validate
if ( ! is_bool( $footer ) ) {
$footer = false;
}
// Enqueue files
foreach ( $this->client_files as $type => $files ) {
$func = $this->get_client_files_handler( $type, 'enqueue' );
if ( ! $func ) {
continue;
}
foreach ( $files as $fkey => $f ) {
// Skip previously-enqueued files and shadow files
if ( $f->enqueued || ! $f->enqueue ) {
continue;
}
// Enqueue files only for current location (header/footer)
if ( isset( $f->in_footer ) ) {
if ( $f->in_footer !== $footer ) {
continue;
}
} elseif ( $footer ) {
continue;
}
$load = true;
// Global Callback
if ( is_callable( $f->callback ) && ! call_user_func( $f->callback ) ) {
$load = false;
}
// Context
if ( $load && ! empty( $f->context ) ) {
// Reset $load before evaluating context
$load = false;
// Iterate through contexts
foreach ( $f->context as $ctx ) {
// Context + Callback
if ( is_array( $ctx ) ) {
// Stop checking context if callback is invalid
if ( ! is_callable( $ctx[1] ) || ! call_user_func( $ctx[1] ) ) {
continue;
}
$ctx = $ctx[0];
}
// Stop checking context if valid context found
if ( $this->util->is_context( $ctx ) ) {
$load = true;
break;
}
}
}
// Load valid file
if ( $load ) {
// Mark file as enqueued
$this->client_files[ $type ]->{$fkey}->enqueued = true;
$func( $f->id );
}
}
}
}
/**
* Enqueue client files in the footer
*/
public function enqueue_client_files_footer() {
$this->enqueue_client_files( true );
}
/**
* Build function name for handling client operations
*/
function get_client_files_handler( $type, $action ) {
$func = 'wp_' . $action . '_' . substr( $type, 0, -1 );
if ( ! function_exists( $func ) ) {
$func = false;
}
return $func;
}
/*-** Reflection **-*/
/**
* Retrieve base object
* @return object|bool Base object (FALSE if object does not exist)
*/
function &get_base() {
$base = false;
if ( isset( $GLOBALS[ $this->base ] ) ) {
$base =& $GLOBALS[ $this->base ];
}
return $base;
}
/*-** Method/Function calling **-*/
/**
* Returns callback to instance method
* @param string $method Method name
* @return array Callback array
*/
function m( $method ) {
return $this->util->m( $this, $method );
}
/*-** Prefix **-*/
/**
* Retrieve class prefix (with separator if set)
* @param bool|string $sep Separator to append to class prefix (Default: no separator)
* @return string Class prefix
*/
function get_prefix( $sep = null ) {
$args = func_get_args();
return call_user_func_array( $this->util->m( $this->util, 'get_prefix' ), $args );
}
/**
* Check if a string is prefixed
* @param string $text Text to check for prefix
* @param string $sep (optional) Separator used
*/
function has_prefix( $text, $sep = null ) {
$args = func_get_args();
return call_user_func_array( $this->util->m( $this->util, 'has_prefix' ), $args );
}
/**
* Prepend plugin prefix to some text
* @param string $text Text to add to prefix
* @param string $sep (optional) Text used to separate prefix and text
* @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not
* @return string Text with prefix prepended
*/
function add_prefix( $text, $sep = null, $once = true ) {
$args = func_get_args();
return call_user_func_array( $this->util->m( $this->util, 'add_prefix' ), $args );
}
/**
* Prepend uppercased plugin prefix to some text
* @param string $text Text to add to prefix
* @param string $sep (optional) Text used to separate prefix and text
* @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not
* @return string Text with prefix prepended
*/
function add_prefix_uc( $text, $sep = null, $once = true ) {
$args = func_get_args();
return call_user_func_array( $this->util->m( $this->util, 'add_prefix_uc' ), $args );
}
/**
* Add prefix to variable reference
* Updates actual variable rather than return value
* @uses SLB_Utilities::add_prefix_ref();
* @param string $var Variable to add prefix to
* @param string $sep (optional) Separator text
* @param bool $once (optional) Add prefix only once
* @return void
*/
function add_prefix_ref( &$var, $sep = null, $once = true ) {
$args = func_get_args();
$args[0] =& $var;
call_user_func_array( $this->util->m( $this->util, 'add_prefix_ref' ), $args );
}
/**
* Remove prefix from specified string
* @param string $text String to remove prefix from
* @param string $sep (optional) Separator used with prefix
*/
function remove_prefix( $text, $sep = null ) {
$args = func_get_args();
return call_user_func_array( $this->util->m( $this->util, 'remove_prefix' ), $args );
}
/*-** Capabilities **-*/
protected function can( $cap ) {
if ( is_null( $this->caps ) ) {
// Build capabilities based on instance properties
$this->caps = array(
'init' => ( 'object' !== $this->mode ) ? true : false,
'singleton' => ( ! ! $this->model ) ? true : false,
'control' => ( 'sub' === $this->mode || 'object' === $this->mode ) ? false : true,
);
}
return ( isset( $this->caps[ $cap ] ) ) ? $this->caps[ $cap ] : false;
}
/*-** Globals **-*/
/**
* Get/Set (internal) global variables
* @uses $globals to get/set global variables
* @param string $name Variable name - If no name is specified, entire globals array is returned
* @param mixed $val (optional) Set the value of a variable (Returns variable value if omitted)
* @return mixed Variable value
*/
private function gvar( $name = null, $val = null ) {
$g =& self::$globals;
if ( ! is_array( $g ) ) {
$g = array();
}
if ( ! is_string( $name ) || empty( $name ) ) {
return $g;
}
$ret = $val;
if ( null !== $val ) {
// Set Value
$g[ $name ] = $val;
} elseif ( isset( $g[ $name ] ) ) {
// Retrieve variable
$ret = $g[ $name ];
}
return $ret;
}
private function shares( $name ) {
return ( ! empty( $this->shared ) && in_array( $name, $this->shared, true ) ) ? true : false;
}
/*-** Options **-*/
/**
* Checks if options are valid
* @param array $data Data to be used on options
* @return bool TRUE if options are valid, FALSE otherwise
*/
function is_options_valid( $data, $check_var = true ) {
$class = $this->util->get_class( 'Options' );
$ret = ( empty( $data ) || ! is_array( $data ) || ! class_exists( $class ) ) ? false : true;
if ( $ret && $check_var && ! ( $this->options instanceof $class ) ) {
$ret = false;
}
return $ret;
}
}

View File

@@ -0,0 +1,369 @@
<?php
/**
* Managed collection
* @package Simple Lightbox
* @subpackage Base
* @author Archetyped
*/
class SLB_Base_Collection extends SLB_Base {
/* Configuration */
/**
* Set object mode
* @var string
*/
protected $mode = 'object';
/**
* Item type
* @var string
*/
protected $item_type = null;
/**
* Property to use for item key
* Example: A property or method of the item
* @var string
*/
protected $key_prop = null;
/**
* Should $key_prop be called or retrieved?
* Default: Retrieved (FALSE)
* @var bool
*/
protected $key_call = false;
/**
* Items in collection unique?
* Default: FALSE
* @var bool
*/
protected $unique = false;
/* Properties */
/**
* Indexed array of items in collection
* @var array
*/
protected $items = null;
/**
* Item metadata
* Indexed by item key
* @var array
*/
protected $items_meta = array();
/* Item Management */
/**
* Initialize collections
* Calls `init` action if collection has a hook prefix
*/
private function init() {
// Initialize
if ( is_null( $this->items ) ) {
$this->items = array();
if ( ! empty( $this->hook_prefix ) ) {
$this->util->do_action( 'init', $this );
}
}
}
/**
* Normalize/Validate item(s)
* TODO: If no items are specified, then collection is normalized
* Single items are wrapped in an array
* @param array|object $items Item(s) to validate
* @return array Validated items
*/
protected function normalize( $items ) {
if ( ! is_array( $items ) ) {
$items = array( $items );
}
// Validate item type
if ( ! is_null( $this->item_type ) ) {
foreach ( $items as $idx => $item ) {
// Remove invalid items
if ( ! ( $item instanceof $this->item_type ) ) {
unset( $items[ $idx ] );
}
}
}
if ( ! empty( $items ) ) {
$items = array_values( $items );
}
return $items;
}
protected function item_valid( $item ) {
// Validate item type
return ( empty( $this->item_type ) || ( $item instanceof $this->item_type ) ) ? true : false;
}
/**
* Validate item key
* Checks collection for existence of key as well
* @param string|int $key Key to check collection for
* @return bool TRUE if key is valid
*/
protected function key_valid( $key ) {
$this->init();
return ( ( ( is_string( $key ) && ! empty( $key ) ) || is_int( $key ) ) && isset( $this->items[ $key ] ) ) ? true : false;
}
/**
* Generate key for item (for storing in collection, etc.)
* @param mixed $item Item to generate key for
* @return string|null Item key (NULL if no key generated)
*/
protected function get_key( $item, $check_existing = false ) {
$ret = null;
if ( $this->unique || ! ! $check_existing ) {
// Check for item in collection
if ( $this->has( $item ) ) {
$ret = array_search( $item, $this->items, true );
} elseif ( ! ! $this->key_prop && ( is_object( $item ) || is_array( $item ) ) ) {
if ( ! ! $this->key_call ) {
$cb = $this->util->m( $item, $this->key_prop );
if ( is_callable( $cb ) ) {
$ret = call_user_func( $cb );
}
} elseif ( is_array( $item ) && isset( $item[ $this->key_prop ] ) ) {
$ret = $item[ $this->key_prop ];
} elseif ( is_object( $item ) && isset( $item->{$this->key_prop} ) ) {
$ret = $item->{$this->key_prop};
}
}
}
return $ret;
}
/**
* Add item to collection
* @param mixed $item Item to add to collection
* @param array $meta (optional) Item metadata
* @return Current instance
*/
public function add( $item, $meta = null ) {
$this->init();
// Validate
if ( $this->item_valid( $item ) ) {
// Add item to collection
$key = $this->get_key( $item );
if ( ! $key ) {
$this->items[] = $item;
$key = key( $this->items );
} else {
$this->items[ $key ] = $item;
}
// Add metadata
if ( ! ! $key && is_array( $meta ) ) {
$this->add_meta( $key, $meta );
}
}
return $this;
}
/**
* Remove item from collection
* @param int|string $item Key of item to remove
* @return Current instance
*/
public function remove( $item ) {
if ( $this->key_valid( $item ) ) {
unset( $this->items[ $item ] );
}
return $this;
}
/**
* Clear collection
* @return Current instance
*/
public function clear() {
$this->items = array();
return $this;
}
/**
* Checks if item exists in the collection
* @param mixed $item Item(s) to check for
* @return bool TRUE if item(s) in collection
*/
public function has( $items ) {
// Attempt to locate item
return false;
}
/**
* Retrieve item(s) from collection
* If no items specified, entire collection returned
* @param array $args (optional) Query arguments
* @return object|array Specified item(s)
*/
public function get( $args = null ) {
$this->init();
// Parse args
$args_default = array(
'orderby' => null,
'order' => 'DESC',
'include' => array(),
'exclude' => array(),
);
$r = wp_parse_args( $args, $args_default );
$items = $this->items;
/* Sort */
if ( ! is_null( $r['orderby'] ) ) {
// Validate
if ( ! is_array( $r['orderby'] ) ) {
$r['orderby'] = array( 'item' => $r['orderby'] );
}
// Prep
$metas = ( isset( $r['orderby']['meta'] ) ) ? $this->items_meta : array();
// Sort
foreach ( $r['orderby'] as $stype => $sval ) {
/* Meta sorting */
if ( 'meta' === $stype ) {
// Build sorting buckets
$buckets = array();
foreach ( $metas as $item => $meta ) {
if ( ! isset( $meta[ $sval ] ) ) {
continue;
}
// Create bucket
$idx = $meta[ $sval ];
if ( ! isset( $buckets[ $idx ] ) ) {
$buckets[ $idx ] = array();
}
// Add item to bucket
$buckets[ $idx ][] = $item;
}
// Sort buckets
ksort( $buckets, SORT_NUMERIC );
// Merge buckets
$pool = array();
foreach ( $buckets as $bucket ) {
$pool = array_merge( $pool, $bucket );
}
// Fill with items
$items = array_merge( array_fill_keys( $pool, null ), $items );
}
}
// Clear workers
unset( $stype, $sval, $buckets, $pool, $item, $metas, $meta, $idx );
}
return $items;
}
/* Metadata */
/**
* Add metadata for item
* @param string|int $item Item key
* @param string|array $meta_key Meta key to set (or array of metadata)
* @param mixed $meta_value (optional) Metadata value (if key set)
* @param bool $reset (optional) Whether to remove existing metadata first (Default: FALSE)
* @return object Current instance
*/
protected function add_meta( $item, $meta_key, $meta_value = null, $reset = false ) {
// Validate
if ( $this->key_valid( $item ) && ( is_array( $meta_key ) || is_string( $meta_key ) ) ) {
// Prepare metadata
$meta = ( is_string( $meta_key ) ) ? array( $meta_key => $meta_value ) : $meta_key;
// Reset existing meta (if necessary)
if ( is_array( $meta_key ) && func_num_args() > 2 ) {
$reset = func_get_arg( 2 );
}
if ( ! ! $reset ) {
unset( $this->items_meta[ $item ] );
}
// Add metadata
if ( ! isset( $this->items_meta[ $item ] ) ) {
$this->items_meta[ $item ] = array();
}
$this->items_meta[ $item ] = array_merge( $this->items_meta[ $item ], $meta );
}
return $this;
}
/**
* Remove item metadata
* @param string $item Item key
* @return object Current instance
*/
protected function remove_meta( $item, $meta_key = null ) {
if ( $this->key_valid( $item ) && isset( $this->items_meta[ $item ] ) ) {
if ( is_string( $meta_key ) ) {
// Remove specific meta value
unset( $this->items_meta[ $item ][ $meta_key ] );
} else {
// Remove all metadata
unset( $this->items_meta[ $item ] );
}
}
return $this;
}
/**
* Retrieve metadata
* @param string $item Item key
* @param string $meta_key (optional) Meta key (All metadata retrieved if no key specified)
* @return mixed|null Metadata value
*/
protected function get_meta( $item, $meta_key = null ) {
$ret = null;
if ( $this->key_valid( $item ) && isset( $this->items_meta[ $item ] ) ) {
if ( is_null( $meta_key ) ) {
$ret = $this->items_meta[ $item ];
} elseif ( is_string( $meta_key ) && isset( $this->items_meta[ $item ][ $meta_key ] ) ) {
$ret = $this->items_meta[ $item ][ $meta_key ];
}
}
return $ret;
}
/* Collection */
/**
* Build entire collection of items
* Prints output
*/
function build( $build_vars = array() ) {
// Parse vars
$this->parse_build_vars( $build_vars );
$this->util->do_action_ref_array( 'build_init', array( $this ) );
// Pre-build output
$this->util->do_action_ref_array( 'build_pre', array( $this ) );
// Build groups
$this->build_groups();
// Post-build output
$this->util->do_action_ref_array( 'build_post', array( $this ) );
}
/**
* Parses build variables prior to use
* @uses this->reset_build_vars() to reset build variables for each request
* @param array $build_vars Variables to use for current request
*/
function parse_build_vars( $build_vars = array() ) {
$this->reset_build_vars();
$this->build_vars = $this->util->apply_filters( 'parse_build_vars', wp_parse_args( $build_vars, $this->build_vars ), $this );
}
/**
* Reset build variables to defaults
* Default Variables
* > groups - array - Names of groups to build
* > context - string - Context of current request
* > layout - string - Name of default layout to use
*/
function reset_build_vars() {
$this->build_vars = wp_parse_args( $this->build_vars, $this->build_vars_default );
}
}

View File

@@ -0,0 +1,343 @@
<?php
/**
* Base Object
* @package Simple Lightbox
* @subpackage Base
* @author Archetyped
*/
class SLB_Base_Object extends SLB_Base {
/* Configuration */
/**
* @var string
* @see Base::$mode
*/
protected $mode = 'object';
/*-** Properties **-*/
/**
* Unique ID
* @var string
*/
protected $id = '';
/**
* Parent object
* @var Base_Object
*/
protected $parent = null;
/**
* Attached files
* @var array
* > scripts array JS scripts
* > styles array Stylesheets
*/
protected $files = array(
'scripts' => array(),
'styles' => array(),
);
/**
* Properties that can be inherited from parent
* @var array
*/
protected $parent_props = array();
/*-** Methods **-*/
/**
* Constructor
* @param string $id Unique ID for content type
* @param array $props (optional) Type properties (optional because props can be set post-init)
*/
public function __construct( $id, $props = null ) {
parent::__construct();
$this
->set_id( $id )
->set_props( $props );
}
/**
* Checks if object is valid
* To be overriden by child classes
*/
public function is_valid() {
return true;
}
/*-** Getters/Setters **-*/
/**
* Get ID
* @return string ID
*/
public function get_id() {
return $this->id;
}
/**
* Set ID
* @param string $id ID
* @return object Current instance
*/
public function set_id( $id ) {
$id = ( is_string( $id ) ) ? trim( $id ) : '';
if ( ! empty( $id ) ) {
$this->id = $id;
}
return $this;
}
/**
* Set type properties
* @param array $props Type properties to set
*/
protected function set_props( $props ) {
if ( is_array( $props ) && ! empty( $props ) ) {
foreach ( $props as $key => $val ) {
// Check for setter method
$m = 'set_' . $key;
if ( method_exists( $this, $m ) ) {
$this->{$m}( $val );
}
}
}
return $this;
}
/**
* Get parent
* @return object|null Parent
*/
public function get_parent() {
return $this->parent;
}
/**
* Set parent
* @param object $parent Parent object
* @return object Current instance
*/
public function set_parent( $parent ) {
$this->parent = ( $parent instanceof $this ) ? $parent : null;
return $this;
}
/**
* Check if parent is set
* @return bool TRUE if parent is set
*/
public function has_parent() {
return ( is_null( $this->parent ) ) ? false : true;
}
/**
* Retrieve all ancestors
* @return array Ancestors
*/
public function get_ancestors() {
$ret = array();
$curr = $this;
while ( $curr->has_parent() ) {
// Get next ancestor.
$curr = $curr->get_parent();
// Add ancestor.
$ret[] = $curr;
}
return $ret;
}
/* Files */
/**
* Add file
* @param string $type Group to add file to
* @param string $handle Name for resource
* @param string $src File URI
* @return object Current instance
*/
protected function add_file( $type, $handle, $src, $deps = array() ) {
if ( is_string( $type ) && is_string( $handle ) && is_string( $src ) ) {
// Validate dependencies
if ( ! is_array( $deps ) ) {
$deps = array();
}
// Init file group
if ( ! isset( $this->files[ $type ] ) || ! is_array( $this->files[ $type ] ) ) {
$this->files[ $type ] = array();
}
// Add file to group
$this->files[ $type ][ $handle ] = array(
'handle' => $handle,
'uri' => $src,
'deps' => $deps,
);
}
return $this;
}
/**
* Add multiple files
* @param string $type Group to add files to
* @param array $files Files to add
* @see add_file() for file parameters
* @return object Current instance
*/
protected function add_files( $type, $files ) {
if ( ! is_array( $files ) || empty( $files ) ) {
return false;
}
$m = $this->m( 'add_file' );
foreach ( $files as $file ) {
if ( ! is_array( $file ) || empty( $file ) ) {
continue;
}
array_unshift( $file, $type );
call_user_func_array( $m, $file );
}
return $this;
}
/**
* Retrieve files
* All files or a specific group of files can be retrieved
* @param string $type (optional) File group to retrieve
* @return array Files
*/
protected function get_files( $type = null ) {
$ret = $this->files;
if ( is_string( $type ) ) {
$ret = ( isset( $ret[ $type ] ) ) ? $ret[ $type ] : array();
}
if ( ! is_array( $ret ) ) {
$ret = array();
}
return $ret;
}
/**
* Retrieve file
* @param string $type Group to retrieve file from
* @param string $handle
* @param string $format (optional) Format of return value (Default: array)
* @return array|null File properties (Default: NULL)
*/
protected function get_file( $type, $handle, $format = null ) {
// Get files
$files = $this->get_files( $type );
// Get specified file
$ret = ( is_string( $type ) && isset( $files[ $handle ] ) ) ? $files[ $handle ] : null;
// Format return value
if ( ! empty( $ret ) && ! ! $format ) {
switch ( $format ) {
case 'uri':
$ret = $ret['uri'];
// Normalize URI
if ( ! $this->util->is_uri( $ret ) ) {
$ret = $this->util->normalize_path( site_url(), $ret );
}
break;
case 'path':
$ret = $ret['uri'];
// Normalize path
if ( ! $this->util->is_uri( $ret ) ) {
$ret = $this->util->get_relative_path( $ret );
$ret = $this->util->normalize_path( ABSPATH, $ret );
}
break;
case 'object':
$ret = (object) $ret;
break;
case 'contents':
$ret = $ret['uri'];
if ( ! $this->util->is_uri( $ret ) ) {
$ret = $this->util->normalize_path( site_url(), $ret );
}
$get = wp_safe_remote_get( $ret );
$ret = ( ! is_wp_error( $get ) && 200 === $get['response']['code'] ) ? $get['body'] : '';
break;
}
}
return $ret;
}
/**
* Add stylesheet
* @param string $handle Name of the stylesheet
* @param string $src Stylesheet URI
* @return object Current instance
*/
public function add_style( $handle, $src, $deps = array() ) {
return $this->add_file( 'styles', $handle, $src, $deps );
}
/**
* Retrieve stylesheet files
* @return array Stylesheet files
*/
public function get_styles( $opts = null ) {
$files = $this->get_files( 'styles' );
if ( is_array( $opts ) ) {
$opts = (object) $opts;
}
if ( is_object( $opts ) && ! empty( $opts ) ) {
// Parse options
// URI Format
if ( isset( $opts->uri_format ) ) {
foreach ( $files as $hdl => $props ) {
switch ( $opts->uri_format ) {
case 'full':
if ( ! $this->util->is_uri( $props['uri'] ) ) {
$files[ $hdl ]['uri'] = $this->util->normalize_path( site_url(), $props['uri'] );
}
break;
}
}
}
}
return $files;
}
/**
* Retrieve stylesheet file
* @param string $handle Name of stylesheet
* @param string $format (optional) Format of return value (@see `get_file()`)
* @return array|null File properties (Default: NULL)
*/
public function get_style( $handle, $format = null ) {
return $this->get_file( 'styles', $handle, $format );
}
/**
* Add script
* @param string $handle Name of the script
* @param string $src Script URI
* @return object Current instance
*/
public function add_script( $handle, $src, $deps = array() ) {
return $this->add_file( 'scripts', $handle, $src, $deps );
}
/**
* Retrieve script files
* @return array Script files
*/
public function get_scripts() {
return $this->get_files( 'scripts' );
}
/**
* Retrieve script file
* @param string $handle Name of script
* @param string $format (optional) Format of return value (@see `get_file()`)
* @return array|null File properties (Default: NULL)
*/
public function get_script( $handle, $format = null ) {
return $this->get_file( 'scripts', $handle, $format );
}
}

View File

@@ -0,0 +1,57 @@
<?php
/**
* Collection Controller
* @package Simple Lightbox
* @subpackage Collection
* @author Archetyped
*/
class SLB_Collection_Controller extends SLB_Base_Collection {
/* Configuration */
protected $mode = 'full';
protected $unique = true;
/* Properties */
protected $parent = null;
/* Methods */
public function __construct( $parent = null ) {
$this->set_parent( $parent );
parent::__construct();
}
/* Initialization */
/* Parent */
/**
* Set parent instance
* @param SLB_Base $parent (optional) Parent instance
* @return obj Current instance
*/
protected function set_parent( $parent = null ) {
$this->parent = ( $parent instanceof SLB_Base ) ? $parent : null;
return $this;
}
/**
* Check if parent set
* @return bool TRUE if parent set
*/
protected function has_parent() {
return ( is_object( $this->get_parent() ) ) ? true : false;
}
/**
* Retrieve parent
* @uses $parent
* @return null|obj Parent instance (NULL if no parent set)
*/
protected function get_parent() {
return $this->parent;
}
}

View File

@@ -0,0 +1,135 @@
<?php
/**
* Component
* @package Simple Lightbox
* @subpackage Base
* @author Archetyped
*/
class SLB_Component extends SLB_Base_Object {
/* Properties */
/**
* Pretty name
* @var string
*/
protected $name = '';
protected $props_required = array();
private $props_required_base = array( 'id' );
/* Get/Set */
/**
* Set name
* @param string $name Name
* @return Current instance
*/
public function set_name( $name ) {
if ( is_string( $name ) ) {
$name = trim( $name );
if ( ! empty( $name ) ) {
$this->name = $name;
}
}
return $this;
}
public function get_name() {
return $this->name;
}
public function set_scripts( $scripts ) {
$this->add_files( 'scripts', $scripts );
}
public function set_styles( $styles ) {
$this->add_files( 'styles', $styles );
}
/* Assets */
/**
* Get formatted handle for file
* @param string $base_handle Base handle to format
* @return string Formatted handle
*/
public function get_handle( $base_handle ) {
return $this->add_prefix( array( 'asset', $this->get_id(), $base_handle ), '-' );
}
/**
* Enqueue files in client
* @param string $type (optional) Type of file to load (singular) (Default: All client file types)
*/
public function enqueue_client_files( $type = null ) {
if ( empty( $type ) ) {
$type = array( 'script', 'style' );
}
if ( ! is_array( $type ) ) {
$type = array( $type );
}
foreach ( $type as $t ) {
$m = (object) array(
'get' => $this->m( 'get_' . $t . 's' ),
'enqueue' => 'wp_enqueue_' . $t,
);
$v = $this->util->get_plugin_version();
$files = call_user_func( $m->get );
$param_final = ( 'script' === $t ) ? true : 'all';
foreach ( $files as $f ) {
$f = (object) $f;
// Format handle
$handle = $this->get_handle( $f->handle );
// Format dependencies
$deps = array();
foreach ( $f->deps as $dep ) {
if ( $this->util->has_wrapper( $dep ) ) {
$dep = $this->get_handle( $this->util->remove_wrapper( $dep ) );
}
$deps[] = $dep;
}
call_user_func( $m->enqueue, $handle, $f->uri, $deps, $v, $param_final );
}
unset( $files, $f, $param_final, $handle, $deps, $dep );
}
}
/**
* Enqueue scripts
*/
public function enqueue_scripts() {
$this->enqueue_client_files( 'script' );
}
/**
* Enqueue styles
*/
public function enqueue_styles() {
$this->enqueue_client_files( 'style' );
}
/* Helpers */
/**
* Validate instance
* @see `Base_Object::is_valid()`
* @return bool Valid (TRUE) / Invalid (FALSE)
*/
public function is_valid() {
$ret = parent::is_valid();
if ( $ret ) {
// Check required component properties
$props = array_merge( $this->props_required_base, $this->props_required );
foreach ( $props as $prop ) {
if ( ! isset( $this->{$prop} ) || empty( $this->{$prop} ) ) {
$ret = false;
break;
}
}
}
return $ret;
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* Content Handler
* @package Simple Lightbox
* @subpackage Content Handlers
* @author Archetyped
*/
class SLB_Content_Handler extends SLB_Component {
/* Properties */
/**
* Match handler
* @var callback
*/
protected $match;
/**
* Custom attributes
* @var callback
*/
protected $attributes;
/* Matching */
/**
* Set matching handler
* @param callback $callback Handler callback
* @return object Current instance
*/
public function set_match( $callback ) {
$this->match = ( is_callable( $callback ) ) ? $callback : null;
return $this;
}
/**
* Retrieve match handler
* @return callback|null Match handler
*/
protected function get_match() {
return $this->match;
}
/**
* Check if valid match set
*/
protected function has_match() {
return ( is_null( $this->match ) ) ? false : true;
}
/**
* Match handler against URI
* @param string $uri URI to check for match
* @return bool TRUE if handler matches URI
*/
public function match( $uri, $uri_raw = null ) {
$ret = false;
if ( ! ! $uri && is_string( $uri ) && $this->has_match() ) {
$ret = call_user_func( $this->get_match(), $uri, $uri_raw );
}
return $ret;
}
/* Attributes */
public function set_attributes( $callback ) {
$this->attributes = ( is_callable( $callback ) ) ? $callback : null;
return $this;
}
public function get_attributes() {
$ret = array();
// Callback
if ( ! is_null( $this->attributes ) ) {
$ret = call_user_func( $this->attributes );
}
// Filter
$hook = sprintf( 'content_handler_%s_attributes', $this->get_id() );
$ret = $this->util->apply_filters( $hook, $ret );
return ( is_array( $ret ) ) ? $ret : array();
}
}

View File

@@ -0,0 +1,280 @@
<?php
/**
* Content Handler Collection
* @package Simple Lightbox
* @subpackage Content Handler
* @author Archetyped
*/
class SLB_Content_Handlers extends SLB_Collection_Controller {
/* Configuration */
protected $item_type = 'SLB_Content_Handler';
public $hook_prefix = 'content_handlers';
protected $key_prop = 'get_id';
protected $key_call = true;
/* Properties */
protected $request_matches = array();
/**
* Cache properties (key, group)
* @var object
*/
protected $cache_props = null;
/* Initialization */
protected function _hooks() {
parent::_hooks();
$this->util->add_action( 'init', $this->m( 'init_defaults' ), 5 );
$this->util->add_action( 'footer', $this->m( 'client_output' ), 1, 0, false );
$this->util->add_filter( 'footer_script', $this->m( 'client_output_script' ), $this->util->priority( 'client_footer_output' ), 1, false );
}
/* Collection Management */
/**
* Add content type handler
* Accepts properties to create new handler OR previously-initialized handler instance
* @uses clear_cache()
* @see parent::add()
* @param string $id Handler ID
* @param array $props Handler properties
* @return object Current instance
*/
public function add( $id, $props = array(), $priority = 10 ) {
$this->clear_cache();
if ( is_string( $id ) ) {
// Initialize new handler
$handler = new $this->item_type( $id, $props );
} else {
// Remap parameters
$handler = func_get_arg( 0 );
if ( func_num_args() === 2 ) {
$priority = func_get_arg( 1 );
}
}
if ( ! is_int( $priority ) ) {
$priority = 10;
}
// Add to collection
return parent::add( $handler, array( 'priority' => $priority ) );
}
/**
* Remove item
* @uses clear_cache()
* @see parent::remove()
* @return object Current instance
*/
public function remove( $item ) {
$this->clear_cache();
return parent::remove( $item );
}
/**
* Clear collection
* @uses clear_cache()
* @see parent::clear()
* @return object Current instance
*/
public function clear() {
$this->clear_cache();
return parent::clear();
}
/**
* Retrieves handlers sorted by priority
* @see parent::get()
* @uses get_cache()
* @param mixed $args Unused
* @return array Handlers
*/
public function get( $args = null ) {
$items = $this->get_cache();
if ( empty( $items ) ) {
// Retrieve items
$items = parent::get( array( 'orderby' => array( 'meta' => 'priority' ) ) );
$this->update_cache( $items );
}
return $items;
}
/**
* Get matching handler for URI
* @param string $uri URI to find match for
* @return object Handler package (FALSE if no match found)
* Package members
* > handler (Content_Handler) Matching handler instance (Default: NULL)
* > props (array) Properties returned from matching handler (May be empty depending on handler)
*/
public function match( $uri ) {
$ret = (object) array(
'handler' => null,
'props' => array(),
);
foreach ( $this->get() as $handler ) {
$props = $handler->match( $uri, $this );
if ( ! ! $props ) {
$ret->handler = $handler;
// Add handler props
if ( is_array( $props ) ) {
$ret->props = $props;
}
// Save match
$hid = $handler->get_id();
if ( ! isset( $this->request_matches[ $hid ] ) ) {
$this->request_matches[ $hid ] = $handler;
}
break;
}
}
return $ret;
}
/* Cache */
/**
* Retrieve cached items
* @uses get_cache_props()
* @uses wp_cache_get()
* @return array Cached items (Default: empty array)
*/
protected function get_cache() {
$cprops = $this->get_cache_props();
$items = wp_cache_get( $cprops->key, $cprops->group );
return ( is_array( $items ) ) ? $items : array();
}
/**
* Update cached items
* Cache is cleared if no items specified
* @uses get_cache_props()
* @uses wp_cache_get()
* @param array $data Item data to cache
*/
protected function update_cache( $data = null ) {
$props = $this->get_cache_props();
wp_cache_set( $props->key, $data, $props->group );
}
/**
* Clear cache
* @uses update_cache()
*/
protected function clear_cache() {
$this->update_cache();
}
/**
* Retrieve cache properites (key, group)
* @return object Cache properties
*/
protected function get_cache_props() {
if ( ! is_object( $this->cache_props ) ) {
$this->cache_props = (object) array(
'key' => $this->hook_prefix . '_items',
'group' => $this->get_prefix(),
);
}
return $this->cache_props;
}
/* Handlers */
/**
* Initialize default handlers
* @param SLB_Content_Handlers $handlers Handlers controller
*/
public function init_defaults( $handlers ) {
$src_base = $this->util->get_file_url( 'content-handlers', true );
$js_path = 'js/';
$js_path .= ( SLB_DEV ) ? 'dev' : 'prod';
$defaults = array(
'image' => array(
'match' => $this->m( 'match_image' ),
'scripts' => array(
array( 'base', "$src_base/image/$js_path/handler.image.js" ),
),
),
);
foreach ( $defaults as $id => $props ) {
$handlers->add( $id, $props );
}
}
/**
* Matches image URIs
* @param string $uri URI to match
* @return bool|array TRUE if URI is image (array is used if extra data needs to be sent)
*/
public function match_image( $uri, $handlers ) {
// Basic matching
$match = ( $this->util->has_file_extension( $uri, array( 'avif', 'jpg', 'jpeg', 'jpe', 'jfif', 'jif', 'gif', 'png', 'webp' ) ) ) ? true : false;
// Filter result
$extra = new stdClass();
$match = $this->util->apply_filters( 'image_match', $match, $uri, $extra );
// Handle extra data passed from filters
// Currently only `uri` supported
if ( $match && isset( $extra->uri ) && is_string( $extra->uri ) ) {
$match = array( 'uri' => $extra->uri );
}
return $match;
}
/* Output */
/**
* Build client output
* Load handler files in client
*/
public function client_output() {
// Get handlers for current request
foreach ( $this->request_matches as $handler ) {
$handler->enqueue_scripts();
}
}
/**
* Client output script
* @param array $commands Client script commands
* @return array Modified script commands
*/
public function client_output_script( $commands ) {
$out = array( '/* CHDL */' );
$code = array();
foreach ( $this->request_matches as $handler ) {
// Attributes
$attrs = $handler->get_attributes();
// Styles
$styles = $handler->get_styles( array( 'uri_format' => 'full' ) );
if ( ! empty( $styles ) ) {
$attrs['styles'] = array_values( $styles );
}
if ( empty( $attrs ) ) {
continue;
}
// Setup client parameters
$params = array(
sprintf( "'%s'", $handler->get_id() ),
wp_json_encode( $attrs ),
);
// Extend handler in client
$code[] = $this->util->call_client_method( 'View.extend_content_handler', $params, false );
}
if ( ! empty( $code ) ) {
$out[] = implode( '', $code );
$commands[] = implode( PHP_EOL, $out );
}
return $commands;
}
}

View File

@@ -0,0 +1,2 @@
<?php
class SLB_Field extends SLB_Field_Type {}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,842 @@
<?php
/**
* Managed collection of fields
* @package Simple Lightbox
* @subpackage Fields
* @author Archetyped
*/
class SLB_Field_Collection extends SLB_Field_Base {
/* Configuration */
protected $mode = 'sub';
/* Properties */
/**
* Item type
* @var string
*/
public $item_type = 'SLB_Field';
/**
* Indexed array of items in collection
* @var array
*/
public $items = array();
public $build_vars_default = array(
'groups' => array(),
'context' => '',
'layout' => 'form',
'build' => true,
'build_groups' => true,
);
/**
* Associative array of groups in collection
* Key: Group ID
* Value: object of group properties
* > id
* > title
* > description string Group description
* > items array Items in group
* @var array
*/
public $groups = array();
protected $properties_init = null;
/* Constructors */
/**
* Class constructor
* @uses parent::__construct()
* @uses self::make_properties()
* @uses self::init()
* @uses self::add_groups()
* @uses self::add_items()
* @param string $id Collection ID
* @param array $properties (optional) Properties to set for collection (Default: none)
*/
public function __construct( $id, $properties = null ) {
$args = func_get_args();
$properties = $this->make_properties( $args );
// Parent constructor
parent::__construct( $properties );
// Save initial properties
$this->properties_init = $properties;
}
public function _init() {
parent::_init();
// Load properties.
$this->load( $this->properties_init, false );
// Add custom ID format(s).
$this->add_id_format(
'formatted',
[
'wrap' => [ 'open' => '_' ],
'prefix' => [ 'get_prefix' ],
'recursive' => false,
]
);
}
/*-** Getters/Setters **-*/
/* Setup */
/**
* Load collection with specified properties
* Updates existing properties
* @param array $properties Properties to load
* @param bool $update (optional) Update (TRUE) or overwrite (FALSE) items/groups (Default: TRUE)
* @return object Current instance
*/
public function load( $properties, $update = true ) {
$args = func_get_args();
$properties = $this->make_properties( $args );
if ( ! empty( $properties ) ) {
// Groups
if ( isset( $properties['groups'] ) ) {
$this->add_groups( $properties['groups'], $update );
}
// Items
if ( isset( $properties['items'] ) ) {
$this->add_items( $properties['items'], $update );
}
}
return $this;
}
/* Data */
/**
* Retrieve external data for items in collection
* Retrieved data is saved to the collection's $data property
* Uses class properties to determine how data is retrieved
* Examples:
* > DB
* > XML
* > JSON
* @return void
*/
function load_data() {
$this->data_loaded = true;
}
/**
* Set data for an item
* @param mixed $item Field to set data for
* > string Field ID
* > object Field Reference
* > array Data for multiple items (associative array [field ID => data])
* @param mixed $value Data to set
* @param bool $save (optional) Whether or not data should be saved to DB (Default: Yes)
*/
function set_data( $item, $value = '', $save = true, $force_set = false ) {
// Set data for entire collection
if ( is_array( $item ) ) {
$this->data = wp_parse_args( $item, $this->data );
// Update save option
$args = func_get_args();
if ( 2 === count( $args ) && is_bool( $args[1] ) ) {
$save = $args[1];
}
} elseif ( is_object( $item ) && method_exists( $item, 'get_id' ) ) {
// Get $item's ID
$item = $item->get_id();
}
// Set data
if ( is_string( $item ) && ! empty( $item ) && ( isset( $this->items[ $item ] ) || ! ! $force_set ) ) {
$this->data[ $item ] = $value;
}
if ( ! ! $save ) {
$this->save();
}
}
/* Item */
/**
* Adds item to collection
* @param string|obj $id Unique name for item or item instance
* @param array $properties (optional) Item properties
* @param bool $update (optional) Update or overwrite existing item (Default: FALSE)
* @return object Newly-added item
*/
function add( $id, $properties = array(), $update = false ) {
$item = null;
$args = func_get_args();
// Get properties.
foreach ( array_reverse( $args ) as $arg ) {
if ( is_array( $arg ) ) {
$properties = $arg;
break;
}
}
if ( ! is_array( $properties ) ) {
$properties = array();
}
// Prep item.
if ( $id instanceof $this->item_type ) {
// Use existing item.
$item = $id;
$item->set_properties( $properties );
} elseif ( class_exists( $this->item_type ) ) {
// Create new item.
$defaults = array(
'parent' => null,
'group' => null,
);
$properties = array_merge( $defaults, $properties );
if ( is_string( $id ) ) {
$properties['id'] = $id;
}
if ( ! ! $update && $this->has( $properties['id'] ) ) {
// Update existing item
$item = $this->get( $properties['id'] );
$item->set_properties( $properties );
} else {
// Init item
$type = $this->item_type;
$item = new $type( $properties );
}
}
if ( empty( $item ) || strlen( $item->get_id() ) === 0 ) {
return false;
}
// Set container
$item->set_container( $this );
// Add item to collection
$this->items[ $item->get_id() ] = $item;
if ( isset( $properties['group'] ) ) {
$this->add_to_group( $properties['group'], $item->get_id() );
}
return $item;
}
/**
* Removes item from collection
* @param string|object $item Object or item ID to remove
* @param bool $save (optional) Whether to save the collection after removing item (Default: YES)
*/
function remove( $item, $save = true ) {
// Remove item
if ( $this->has( $item ) ) {
$item = $this->get( $item );
$item = $item->get_id();
// Remove from items array
unset( $this->items[ $item ] );
// Remove item from groups
$this->remove_from_group( $item );
}
// Remove item data from collection
$this->remove_data( $item, false );
if ( ! ! $save ) {
$this->save();
}
}
/**
* Remove item data from collection
* @param string|object $item Object or item ID to remove
* @param bool $save (optional) Whether to save the collection after removing item (Default: YES)
*/
function remove_data( $item, $save = true ) {
// Get item ID from object
if ( $this->has( $item ) ) {
$item = $this->get( $item );
$item = $item->get_id();
}
// Remove data from data member
if ( is_string( $item ) && is_array( $this->data ) ) {
unset( $this->data[ $item ] );
if ( ! ! $save ) {
$this->save();
}
}
}
/**
* Checks if item exists in the collection.
*
* @param string|object $item Item ID or instance.
* @return bool True if item is in collection, False otherwise.
*/
function has( $item ) {
// Item ID.
if ( is_string( $item ) ) {
return in_array( $item, array_keys( $this->get_items() ), true );
}
// Item instance.
if ( $item instanceof $this->item_type ) {
$items = $this->get_items( null, false );
$id = $item->get_id();
return ( isset( $items[ $id ] ) && $item === $items[ $id ] );
}
return false;
}
/**
* Retrieve specified item in collection.
*
* @param string|object $item Item ID or instance to retrieve.
* @return SLB_Field|null Specified item. Null if item is not in collection.
*/
function get( $item, $safe_mode = false ) {
$invalid = null;
// Stop processing if item is not in collection.
if ( ! $this->has( $item ) ) {
return $invalid;
}
// Get item instance from ID.
if ( is_string( $item ) ) {
$items = $this->get_items( null, false );
if ( isset( $items[ $item ] ) ) {
$item = $items[ $item ];
}
}
// Return valid item instance.
if ( $item instanceof $this->item_type ) {
return $item;
}
// Invalid item.
return $invalid;
}
/**
* Retrieve item data
* @param $item Item to get data for
* @param $context (optional) Context
* @param $top (optional) Iterate through ancestors to get data (Default: Yes)
* @return mixed|null Item data. Null if no data retrieved.
*/
function get_data( $item = null, $context = '', $top = true ) {
$this->load_data();
$ret = null;
if ( $this->has( $item ) ) {
$item = $this->get( $item );
$ret = $item->get_data( $context, $top );
} else {
$ret = parent::get_data( $context, $top );
}
if ( is_string( $item ) && is_array( $ret ) && isset( $ret[ $item ] ) ) {
$ret = $ret[ $item ];
}
return $ret;
}
/* Items (Collection) */
/**
* Add multiple items to collection
* @param array $items Items to add to collection
* Array Structure:
* > Key (string): Item ID
* > Val (array): Item properties
* @return void
*/
function add_items( $items = array(), $update = false ) {
// Validate
if ( ! is_array( $items ) || empty( $items ) ) {
return false;
}
// Add items
foreach ( $items as $id => $props ) {
$this->add( $id, $props, $update );
}
}
/**
* Retrieve reference to items in collection
* @return array Collection items (reference)
*/
function &get_items( $group = null, $sort = 'priority' ) {
$gset = $this->group_exists( $group );
if ( $gset ) {
$items = $this->get_group_items( $group );
} elseif ( ! empty( $group ) ) {
$items = array();
} else {
$items = $this->items;
}
if ( ! empty( $items ) ) {
// Sort items
if ( ! empty( $sort ) && is_string( $sort ) ) {
if ( 'priority' === $sort ) {
if ( $gset ) {
// Sort by priority
ksort( $items, SORT_NUMERIC );
}
}
}
// Release from buckets
if ( $gset ) {
$items = call_user_func_array( 'array_merge', $items );
}
}
return $items;
}
/**
* Build output for items in specified group
* If no group specified, all items in collection are built
* @param string|object $group (optional) Group to build items for (ID or instance object)
*/
function build_items( $group = null ) {
// Get group items
$items =& $this->get_items( $group );
if ( empty( $items ) ) {
return false;
}
$this->util->do_action_ref_array( 'build_items_pre', array( $this ) );
foreach ( $items as $item ) {
$item->build();
}
$this->util->do_action_ref_array( 'build_items_post', array( $this ) );
}
/* Group */
/**
* Sanitizes group ID.
*
* @param string $id Group ID.
* @param bool $fallback Optional. Use fallback group if ID is invalid. Default true.
* @return string Sanitized group ID.
*/
protected function sanitize_group_id( $id, $fallback = true ) {
// Sanitize.
$id = sanitize_title_with_dashes( $id );
// Use default ID (fallback).
if ( strlen( $id ) === 0 && ! ! $fallback ) {
$id = 'default';
}
return $id;
}
/**
* Add groups to collection
* @param array $groups Associative array of group properties
* Array structure:
* > Key (string): group ID
* > Val (string): Group Title
*/
function add_groups( $groups = array(), $update = false ) {
// Validate
if ( ! is_array( $groups ) || empty( $groups ) ) {
return false;
}
// Iterate
foreach ( $groups as $id => $props ) {
$this->add_group( $id, $props, null, $update );
}
}
/**
* Adds group to collection
* Groups are used to display related items in the UI
* @param string $id Unique name for group
* @param string $title Group title
* @param string $description Short description of group's purpose
* @param array $items (optional) ID's of existing items to add to group
* @return object Group object
*/
function &add_group( $id, $properties = array(), $items = array(), $update = false ) {
// Create new group and set properties
$default = array(
'title' => '',
'description' => '',
'priority' => 10,
);
$p = ( is_array( $properties ) ) ? array_merge( $default, $properties ) : $default;
if ( ! is_int( $p['priority'] ) || $p['priority'] < 0 ) {
$p['priority'] = $default['priority'];
}
$id = $this->sanitize_group_id( $id );
// Retrieve or init group
if ( ! ! $update && $this->group_exists( $id ) ) {
$grp = $this->get_group( $id );
$grp->title = $p['title'];
$grp->description = $p['description'];
$grp->priority = $p['priority'];
} else {
$this->groups[ $id ] =& $this->create_group( $id, $p['title'], $p['description'], $p['priority'] );
}
// Add items to group (if supplied)
if ( ! empty( $items ) && is_array( $items ) ) {
$this->add_to_group( $id, $items );
}
return $this->groups[ $id ];
}
/**
* Remove specified group from collection
* @param string $id Group ID to remove
*/
function remove_group( $id ) {
$id = trim( $id );
if ( $this->group_exists( $id ) ) {
unset( $this->groups[ $id ] );
}
}
/**
* Creates a new item group.
*
* @param string $title Group title (used in meta boxes, etc.)
* @param string $description Short description of group's purpose
* @param int $priority (optional) Group priority (e.g. used to sort groups during output)
* @return object {
* Group object.
*
* @type string $id ID.
* @type string $title Title.
* @type string $description Description.
* @type int $priority Priority (relative to other groups in collection).
* @type array $items {
* Group items. Grouped by item priority.
* Items indexed by item ID.
* Example: `$items[10]['item_id'] = {item}
* }
* }
*/
function &create_group( $id = '', $title = '', $description = '', $priority = 10 ) {
// Create new group object
$group = new stdClass();
/* Set group properties */
// Set ID
$id = ( is_scalar( $id ) ) ? trim( $id ) : '';
$group->id = $id;
// Set Title
$title = ( is_scalar( $title ) ) ? trim( $title ) : '';
$group->title = $title;
// Set Description
$description = ( is_scalar( $description ) ) ? trim( $description ) : '';
$group->description = $description;
// Priority
$group->priority = ( is_int( $priority ) ) ? $priority : 10;
// Create array to hold items
$group->items = array();
return $group;
}
/**
* Checks if group exists in collection.
*
* @param string|object $id Group name or object.
* @return bool True if group exists, False otherwise.
*/
function group_exists( $group ) {
if ( is_object( $group ) ) {
return true;
}
if ( ! is_string( $group ) ) {
return false;
}
$group = $this->sanitize_group_id( $group );
if ( strlen( $group ) === 0 ) {
return false;
}
// Check if group exists
return ( ! is_null( $this->get_member_value( 'groups', $group, null ) ) );
}
/**
* Adds item to a group in the collection.
*
* Group is created if it does not already exist.
*
* @param string|array $group {
* Group ID (or parameters array) to add item to.
*
* Array structure:
*
* @type string $0 Group ID.
* @type int $1 Item priority in group.
* }
* @param string|object|array $items Item ID/Instance or array of items to add to group.
* @param int $priority Optional. Default priority to set for items in group. Default 10.
* @return bool True if item(s) successfully added to group.
* False if item(s) not added to group.
*/
function add_to_group( $group, $items, $priority = 10 ) {
// Validate.
if ( empty( $items ) || empty( $group ) || ( ! is_string( $group ) && ! is_array( $group ) ) ) {
return false;
}
// Parse group properties.
if ( is_string( $group ) ) {
$gid = $group;
} elseif ( is_array( $group ) ) {
$group = array_values( $group );
if ( count( $group ) < 2 ) {
$group[] = $priority;
}
list( $gid, $priority ) = $group;
}
// Format group ID.
$gid = $this->sanitize_group_id( $gid );
if ( strlen( $gid ) === 0 ) {
return false;
}
// Item priority.
$priority = (int) $priority;
// Prepare items
if ( ! is_array( $items ) ) {
$items = [ $items ];
}
// Add Items.
$items_skipped = [];
foreach ( $items as $item ) {
// Skip if item is not in current collection.
$itm_ref = $this->get( $item );
if ( ! $itm_ref ) {
$items_skipped[] = $item;
continue;
}
// Remove item from all groups (items can only be in one group).
$this->remove_from_group( $itm_ref );
// Add reference to item in group.
$items =& $this->get_group( $gid )->items;
// Ensure priority level exists for group.
if ( ! isset( $items[ $priority ] ) ) {
$items[ $priority ] = array();
}
// Add item to group.
$items[ $priority ][ $itm_ref->get_id() ] = $itm_ref;
}
unset( $itm_ref );
return ( count( $items_skipped ) < count( $items ) );
}
/**
* Removes item from a group.
*
* If group is not specified, item is removed from all groups.
*
* @param string|object $item ID or object of item to remove from group.
* @param string|object|array $groups Optional. Group(s) to remove item from. Default null.
* - @type string Group ID.
* - @type object Group object.
* - @type array Multiple groups (ID or object).
* @return void
*/
function remove_from_group( $item, $groups = null ) {
// Validate item.
$item = $this->get( $item );
if ( ! $item ) {
return;
}
// Get item ID.
$item = $item->get_id();
// Validate item ID.
if ( ! $item ) {
return;
}
// Setup groups.
if ( is_string( $groups ) || is_object( $groups ) ) {
$groups = [ $groups ];
} elseif ( ! is_array( $groups ) ) {
$groups = array_keys( $this->get_groups() );
}
// Remove item from group(s).
foreach ( $groups as $group ) {
$group = $this->get_group( $group );
foreach ( array_keys( $group->items ) as $priority ) {
unset( $group->items[ $priority ][ $item ] );
}
}
}
/**
* Retrieves specified group.
*
* @param string|object $group Group ID or object to retrieve.
* @return object Reference to specified group.
*/
function &get_group( $group ) {
if ( is_object( $group ) ) {
return $group;
}
// Create group if it doesn't already exist.
if ( ! $this->group_exists( $group ) ) {
return $this->add_group( $group );
}
// Get existing group.
$group = $this->sanitize_group_id( $group );
return $this->get_member_value( 'groups', $group );
}
/**
* Retrieve a group's items
* @uses SLB_Field_Collection::get_group() to retrieve group object
* @param object|string $group Group object or group ID
* @return array Group's items
*/
function &get_group_items( $group ) {
$group =& $this->get_group( $group );
return $group->items;
}
/**
* Retrieve all groups in collection
* @return object[] Reference to group objects
*/
function &get_groups( $opts = array() ) {
$groups =& $this->get_member_value( 'groups' );
if ( is_array( $opts ) && ! empty( $opts ) ) {
extract( $opts, EXTR_SKIP );
if ( ! empty( $groups ) && ! empty( $sort ) && is_string( $sort ) ) {
if ( property_exists( current( $groups ), $sort ) ) {
// Sort groups by property
$sfunc = function ( $a, $b ) use ( $sort ) {
$ap = $a->$sort;
$bp = $b->$sort;
if ( $ap === $bp ) {
return 0;
}
return ( $ap > $bp ) ? 1 : -1;
};
uasort( $groups, $sfunc );
}
}
}
return $groups;
}
/**
* Output groups
* @uses self::build_vars to determine groups to build
*/
function build_groups() {
$this->util->do_action_ref_array( 'build_groups_pre', array( $this ) );
// Get groups to build
$groups = ( ! empty( $this->build_vars['groups'] ) ) ? $this->build_vars['groups'] : array_keys( $this->get_groups( array( 'sort' => 'priority' ) ) );
// Check options
if ( is_callable( $this->build_vars['build_groups'] ) ) {
// Pass groups to callback to build output
call_user_func_array( $this->build_vars['build_groups'], array( $this, $groups ) );
} elseif ( ! ! $this->build_vars['build_groups'] ) {
// Build groups
foreach ( $groups as $group ) {
$this->build_group( $group );
}
}
$this->util->do_action_ref_array( 'build_groups_post', array( $this ) );
}
/**
* Build group
*/
function build_group( $group ) {
if ( ! $this->group_exists( $group ) ) {
return false;
}
$group =& $this->get_group( $group );
// Stop processing if group contains no items
if ( ! count( $this->get_items( $group ) ) ) {
return false;
}
// Pre action
$this->util->do_action_ref_array( 'build_group_pre', array( $this, $group ) );
// Build items
$this->build_items( $group );
// Post action
$this->util->do_action_ref_array( 'build_group_post', array( $this, $group ) );
}
/* Collection */
/**
* Build entire collection of items
* Prints output
*/
function build( $build_vars = array() ) {
// Parse vars
$this->parse_build_vars( $build_vars );
$this->util->do_action_ref_array( 'build_init', array( $this ) );
// Pre-build output
$this->util->do_action_ref_array( 'build_pre', array( $this ) );
// Build groups
$this->build_groups();
// Post-build output
$this->util->do_action_ref_array( 'build_post', array( $this ) );
}
/**
* Set build variable
* @param string $key Variable name
* @param mixed $val Variable value
*/
function set_build_var( $key, $val ) {
$this->build_vars[ $key ] = $val;
}
/**
* Retrieve build variable
* @param string $key Variable name
* @param mixed $default Value if variable is not set
* @return mixed Variable value
*/
function get_build_var( $key, $default = null ) {
return ( array_key_exists( $key, $this->build_vars ) ) ? $this->build_vars[ $key ] : $default;
}
/**
* Delete build variable
* @param string $key Variable name to delete
*/
function delete_build_var( $key ) {
if ( array_key_exists( $key, $this->build_vars ) ) {
unset( $this->build_vars[ $key ] );
}
}
/**
* Parses build variables prior to use
* @uses this->reset_build_vars() to reset build variables for each request
* @param array $build_vars Variables to use for current request
*/
function parse_build_vars( $build_vars = array() ) {
$this->reset_build_vars();
$this->build_vars = $this->util->apply_filters( 'parse_build_vars', wp_parse_args( $build_vars, $this->build_vars ), $this );
}
/**
* Reset build variables to defaults
* Default Variables
* > groups - array - Names of groups to build
* > context - string - Context of current request
* > layout - string - Name of default layout to use
*/
function reset_build_vars() {
$this->build_vars = wp_parse_args( $this->build_vars, $this->build_vars_default );
}
}

View File

@@ -0,0 +1,462 @@
<?php
/**
* Field Types
* Stores properties for a specific field
* @package Simple Lightbox
* @subpackage Fields
* @author Archetyped
*/
class SLB_Field_Type extends SLB_Field_Base {
/* Properties */
/**
* @var array Array of Field types that make up current Field type
*/
public $elements = array();
/**
* @var array Field type layouts
*/
public $layout = array();
/**
* @var SLB_Field_Type Parent field type (reference)
*/
public $parent = null;
/**
* Object that field is in
* @var SLB_Field|SLB_Field_Type|SLB_Field_Collection
*/
public $container = null;
/**
* Object that called field
* Used to determine field hierarchy/nesting
* @var SLB_Field|SLB_Field_Type|SLB_Field_Collection
*/
public $caller = null;
function __construct( $id = '', $parent = null ) {
$args = func_get_args();
$defaults = $this->integrate_id( $id );
if ( ! is_array( $parent ) ) {
$defaults['parent'] = $parent;
}
$props = $this->make_properties( $args, $defaults );
parent::__construct( $props );
}
/* Getters/Setters */
/**
* Search for specified member value in field's container object (if exists)
* @param string $member Name of object member to search (e.g. properties, layout, etc.)
* @param string $name Value to retrieve from member
* @return mixed Member value if found (Default: empty string)
*/
function get_container_value( $member, $name = '', $default = '' ) {
$container =& $this->get_container();
return $this->get_object_value( $container, $member, $name, $default, 'container' );
}
/**
* Search for specified member value in field's container object (if exists)
* @param string $member Name of object member to search (e.g. properties, layout, etc.)
* @param string $name Value to retrieve from member
* @return mixed Member value if found (Default: empty string)
*/
function get_caller_value( $member, $name = '', $default = '' ) {
$caller =& $this->get_caller();
return $this->get_object_value( $caller, $member, $name, $default, 'caller' );
}
/**
* Sets reference to container object of current field
* Reference is cleared if no valid object is passed to method
* @param object $container
*/
function set_container( &$container ) {
if ( ! empty( $container ) && is_object( $container ) ) {
// Set as param as container for current field
$this->container =& $container;
} else {
// Clear container member if argument is invalid
$this->clear_container();
}
}
/**
* Clears reference to container object of current field
*/
function clear_container() {
$this->container = null;
}
/**
* Retrieves reference to container object of current field
* @return object Reference to container object
*/
function &get_container() {
$ret = null;
if ( $this->has_container() ) {
$ret =& $this->container;
}
return $ret;
}
/**
* Checks if field has a container reference
* @return bool TRUE if field is contained, FALSE otherwise
*/
function has_container() {
return ! empty( $this->container );
}
/**
* Sets reference to calling object of current field
* Any existing reference is cleared if no valid object is passed to method
* @param object $caller Calling object
*/
function set_caller( &$caller ) {
if ( ! empty( $caller ) && is_object( $caller ) ) {
$this->caller =& $caller;
} else {
$this->clear_caller();
}
}
/**
* Clears reference to calling object of current field
*/
function clear_caller() {
unset( $this->caller );
}
/**
* Retrieves reference to caller object of current field
* @return object Reference to caller object
*/
function &get_caller() {
$ret = null;
if ( $this->has_caller() ) {
$ret =& $this->caller;
}
return $ret;
}
/**
* Checks if field has a caller reference
* @return bool TRUE if field is called by another field, FALSE otherwise
*/
function has_caller() {
return ! empty( $this->caller );
}
/**
* Sets an element for the field type
* @param string $name Name of element
* @param SLB_Field_Type $type Reference of field type to use for element
* @param array $properties Properties for element (passed as keyed associative array)
* @param string $id_prop Name of property to set $name to (e.g. ID, etc.)
*/
function set_element( $name, $type, $properties = array(), $id_prop = 'id' ) {
$name = trim( strval( $name ) );
if ( empty( $name ) ) {
return false;
}
// Create new field for element
$el = new SLB_Field( $name, $type );
// Set container to current field instance
$el->set_container( $this );
// Add properties to element
$el->set_properties( $properties );
// Save element to current instance
$this->elements[ $name ] =& $el;
}
/**
* Add a layout to the field
* @param string $name Name of layout
* @param string $value Layout text
*/
function set_layout( $name, $value = '' ) {
if ( ! is_string( $name ) ) {
return false;
}
$name = trim( $name );
$this->layout[ $name ] = $value;
return true;
}
/**
* Retrieve specified layout
* @param string $name Layout name
* @param bool $parse_nested (optional) Whether nested layouts should be expanded in retreived layout or not (Default: TRUE)
* @return string Specified layout text
*/
function get_layout( $name = 'form', $parse_nested = true ) {
// Retrieve specified layout (use $name value if no layout by that name exists)
if ( empty( $name ) ) {
$name = $this->get_container_value( 'build_vars', 'layout', 'form' );
}
$layout = $this->get_member_value( 'layout', $name, $name );
// Find all nested layouts in current layout
if ( ! empty( $layout ) && ! ! $parse_nested ) {
$ph = $this->get_placeholder_defaults();
// Check layout for placeholders.
$ph->match = $this->parse_layout( $layout, $ph->pattern_layout );
while ( ! empty( $ph->match ) ) {
// Iterate through the different types of layout placeholders
foreach ( $ph->match as $tag => $instances ) {
// Iterate through instances of a specific type of layout placeholder
foreach ( $instances as $instance ) {
// Get nested layout
$nested_layout = $this->get_member_value( $instance );
if ( empty( $nested_layout ) ) {
continue;
}
// Replace layout placeholder with retrieved item data.
$layout = str_replace( $ph->start . $instance['match'] . $ph->end, $nested_layout, $layout );
}
}
// Check layout for placeholders.
$ph->match = $this->parse_layout( $layout, $ph->pattern_layout );
}
}
return $layout;
}
/**
* Checks if specified layout exists.
*
* Finds layout if it exists in current object or any of its parents.
*
* @param string $layout Name of layout to check for.
* @return bool True if layout exists, False otherwise.
*/
function has_layout( $layout ) {
if ( is_string( $layout ) && ! empty( trim( $layout ) ) ) {
return false;
}
$layout = $this->get_member_value( 'layout', trim( $layout ), false );
return ( false !== $layout );
}
/**
* Checks if layout content is valid
* Layouts need to have placeholders to be valid
* @param string $layout_content Layout content (markup)
* @return bool TRUE if layout is valid, FALSE otherwise
*/
function is_valid_layout( $layout_content ) {
$ph = $this->get_placeholder_defaults();
return preg_match( $ph->pattern_general, $layout_content );
}
/**
* Parse field layout with a regular expression
* @param string $layout Layout data
* @param string $search Regular expression pattern to search layout for
* @return array Associative array containing all of the regular expression matches in the layout data
* Array Structure:
* root => placeholder tags
* => Tag instances (array)
* 'tag' => (string) tag name
* 'match' => (string) placeholder match
* 'attributes' => (array) attributes
*/
function parse_layout( $layout, $search ) {
$parse_match = '';
$result = [];
// Find all nested layouts in layout.
$match_value = preg_match_all( $search, $layout, $parse_match, PREG_PATTERN_ORDER );
// Stop if no matches found.
if ( ! $match_value ) {
return $result;
}
/* Process matches */
$ph_xml = '';
$ph_root_tag = 'ph_root_element';
$ph_start_xml = '<';
$ph_end_xml = ' />';
$ph_wrap_start = '<' . $ph_root_tag . '>';
$ph_wrap_end = '</' . $ph_root_tag . '>';
$parse_result = [];
// Get all matched elements.
$parse_match = $parse_match[1];
// Build XML string from placeholders.
foreach ( $parse_match as $ph ) {
$ph_xml .= $ph_start_xml . $ph . $ph_end_xml . ' ';
}
$ph_xml = $ph_wrap_start . $ph_xml . $ph_wrap_end;
// Parse XML data.
$ph_prs = xml_parser_create();
xml_parser_set_option( $ph_prs, XML_OPTION_SKIP_WHITE, 1 );
xml_parser_set_option( $ph_prs, XML_OPTION_CASE_FOLDING, 0 );
$ph_parsed = xml_parse_into_struct( $ph_prs, $ph_xml, $parse_result['values'], $parse_result['index'] );
xml_parser_free( $ph_prs );
// Stop if placeholder parsing failed.
if ( ! $ph_parsed ) {
return $result;
}
unset( $parse_result['index'][ $ph_root_tag ] );
// Build structured array with all parsed data.
$ph_default = [
'tag' => '',
'match' => '',
'attributes' => [],
];
// Build structured array.
foreach ( $parse_result['index'] as $tag => $instances ) {
// Create container for instances of current placeholder.
$result[ $tag ] = [];
// Process placeholder instances.
foreach ( $instances as $instance ) {
// Skip instance if it doesn't exist in parse results.
if ( ! isset( $parse_result['values'][ $instance ] ) ) {
continue;
}
// Stop processing instance if a previously-saved instance with the same options already exists.
foreach ( $result[ $tag ] as $tag_match ) {
if ( $tag_match['match'] === $parse_match[ $instance - 1 ] ) {
continue 2;
}
}
$instance_parsed = $parse_result['values'][ $instance ];
// Init instance data array.
$instance_data = $ph_default;
// Set tag.
$instance_data['tag'] = $instance_parsed['tag'];
// Set attributes.
if ( isset( $instance_parsed['attributes'] ) && is_array( $instance_parsed['attributes'] ) ) {
$instance_data['attributes'] = $instance_parsed['attributes'];
}
// Add match to array.
$instance_data['match'] = $parse_match[ $instance - 1 ];
// Add to result array.
$result[ $tag ][] = $instance_data;
}
}
return $result;
}
/**
* Retrieves default properties to use when evaluating layout placeholders
* @return object Object with properties for evaluating layout placeholders
*/
function get_placeholder_defaults() {
$ph = new stdClass();
$ph->start = '{';
$ph->end = '}';
$ph->reserved = array( 'ref' => 'ref_base' );
$ph->pattern_general = '/' . $ph->start . '([a-zA-Z0-9_].*?)' . $ph->end . '/i';
$ph->pattern_layout = '/' . $ph->start . '([a-zA-Z0-9].*?\s+' . $ph->reserved['ref'] . '="layout.*?".*?)' . $ph->end . '/i';
return $ph;
}
/**
* Build item output
* @param string $layout (optional) Layout to build
* @param string $data Data to pass to layout
*/
function build( $layout = null, $data = null ) {
$this->util->do_action_ref_array( 'build_pre', array( $this ) );
echo $this->build_layout( $layout, $data );
$this->util->do_action_ref_array( 'build_post', array( $this ) );
}
/**
* Builds HTML for a field based on its properties
* @param string $layout (optional) Name of layout to build
* @param array $data Additional data for current item
*/
function build_layout( $layout = 'form', $data = null ) {
$out_default = '';
// Get base layout
$out = $this->get_layout( $layout );
// Only parse valid layouts
if ( $this->is_valid_layout( $out ) ) {
$out = $this->process_placeholders( $out, $layout, $data );
} else {
$out = $out_default;
}
/* Return generated value */
$out = $this->format_final( $out );
return $out;
}
/**
* Processes placeholders in a string.
*
* Finds and replaces placeholders in a string to their full values.
*
* @since 2.8.0
*
* @param string $str String with placeholders to replace.
* @param string $layout Optional. Name of layout being built.
* @param array $data Optional. Additional data for current item.
* @return string Original text with placeholders converted to full values.
*/
public function process_placeholders( $str, $layout = 'form', $data = null ) {
// Parse Layout.
$ph = $this->get_placeholder_defaults();
// Check layout for placeholders.
$ph->match = $this->parse_layout( $str, $ph->pattern_general );
// Parse placeholders in layout.
while ( ! empty( $ph->match ) ) {
// Iterate through placeholders (tag, id, etc.)
foreach ( $ph->match as $tag => $instances ) {
// Iterate through instances of current placeholder
foreach ( $instances as $instance ) {
// Process value based on placeholder name.
$target_property = $this->util->apply_filters_ref_array( "process_placeholder_${tag}", [ '', $this, &$instance, $layout, $data ], false );
// Process value using default processors (if necessary).
if ( '' === $target_property ) {
$target_property = $this->util->apply_filters_ref_array( 'process_placeholder', [ $target_property, $this, &$instance, $layout, $data ], false );
}
// Format output.
if ( ! is_null( $target_property ) ) {
$context = ( isset( $instance['attributes']['context'] ) ) ? $instance['attributes']['context'] : '';
// Handle special characters.
$target_property = $this->preserve_special_chars( $target_property, $context );
// Context-specific formatting.
$target_property = $this->format( $target_property, $context );
}
// Clear value if value not a string
if ( ! is_scalar( $target_property ) ) {
$target_property = '';
}
// Replace layout placeholder with retrieved item data
$str = str_replace( $ph->start . $instance['match'] . $ph->end, $target_property, $str );
}
}
// Check layout for placeholders.
$ph->match = $this->parse_layout( $str, $ph->pattern_general );
}
return $str;
}
}

View File

@@ -0,0 +1,518 @@
<?php
/**
* Collection of default system-wide fields
* @package Simple Lightbox
* @subpackage Fields
* @author Archetyped
*
*/
class SLB_Fields extends SLB_Field_Collection {
public $item_type = 'SLB_Field_Type';
/**
* Placeholder handlers
* @var array
*/
public $placholders = null;
/* Constructor */
function __construct() {
parent::__construct( 'fields' );
}
protected function _hooks() {
parent::_hooks();
// Init fields
add_action( 'init', $this->m( 'register_types' ) );
// Init placeholders
add_action( 'init', $this->m( 'register_placeholders' ) );
}
/* Field Types */
/**
* Initialize fields
*/
function register_types() {
/* Field Types */
// Base
$base = new SLB_Field_Type( 'base' );
$base->set_description( __( 'Default Element', 'simple-lightbox' ) );
$base->set_property( 'tag', 'span' );
$base->set_property( 'class', '', 'attr' );
$base->set_layout( 'form_attr', '{tag} name="{field_name}" id="{field_id}" {properties ref_base="root" group="attr"}' );
$base->set_layout( 'form', '<{form_attr ref_base="layout"} />' );
$base->set_layout( 'label', '<label for="{field_id}">{label}</label>' );
$base->set_layout( 'display', '{data context="display"}' );
$this->add( $base );
// Base closed
$base_closed = new SLB_Field_Type( 'base_closed' );
$base_closed->set_parent( 'base' );
$base_closed->set_description( __( 'Default Element (Closed Tag)', 'simple-lightbox' ) );
$base_closed->set_layout( 'form_start', '<{tag} id="{field_id}" name="{field_name}" {properties ref_base="root" group="attr"}>' );
$base_closed->set_layout( 'form_end', '</{tag}>' );
$base_closed->set_layout( 'form', '{form_start ref_base="layout"}{data}{form_end ref_base="layout"}' );
$this->add( $base_closed );
// Input
$input = new SLB_Field_Type( 'input', 'base' );
$input->set_description( __( 'Default Input Element', 'simple-lightbox' ) );
$input->set_property( 'tag', 'input' );
$input->set_property( 'type', 'text', 'attr' );
$input->set_property( 'value', '{data}', 'attr' );
$this->add( $input );
// Text input
$text = new SLB_Field_Type( 'text', 'input' );
$text->set_description( __( 'Text Box', 'simple-lightbox' ) );
$text->set_property( 'size', 15, 'attr' );
$text->set_property( 'label' );
$text->set_layout( 'form', '{label ref_base="layout"} {inherit}' );
$this->add( $text );
// Checkbox
$cb = new SLB_Field_Type( 'checkbox', 'input' );
$cb->set_property( 'type', 'checkbox' );
$cb->set_property( 'value', null );
$cb->set_layout( 'form_attr', '{inherit} {checked}' );
$cb->set_layout( 'form', '{label ref_base="layout"} <{form_attr ref_base="layout"} />' );
$this->add( $cb );
// Textarea
$ta = new SLB_Field_Type( 'textarea', 'base_closed' );
$ta->set_property( 'tag', 'textarea' );
$ta->set_property( 'cols', 40, 'attr' );
$ta->set_property( 'rows', 3, 'attr' );
$this->add( $ta );
// Rich Text
$rt = new SLB_Field_Type( 'richtext', 'textarea' );
$rt->set_property( 'class', 'theEditor {inherit}' );
$rt->set_layout( 'form', '<div class="rt_container">{inherit}</div>' );
$rt->add_action( 'admin_print_footer_scripts', 'wp_tiny_mce', 25 );
$this->add( $rt );
// Hidden
$hidden = new SLB_Field_Type( 'hidden' );
$hidden->set_parent( 'input' );
$hidden->set_description( __( 'Hidden Field', 'simple-lightbox' ) );
$hidden->set_property( 'type', 'hidden' );
$this->add( $hidden );
// Select
$select = new SLB_Field_Type( 'select', 'base_closed' );
$select->set_description( __( 'Select tag', 'simple-lightbox' ) );
$select->set_property( 'tag', 'select' );
$select->set_property( 'tag_option', 'option' );
$select->set_property( 'options', array() );
$select->set_layout( 'form', '{label ref_base="layout"} {form_start ref_base="layout"}{option_loop ref_base="layout"}{form_end ref_base="layout"}' );
$select->set_layout( 'option_loop', '{loop data="properties.options" layout="option" layout_data="option_data"}' );
$select->set_layout( 'option', '<{tag_option} value="{data_ext id="option_value" context="attr"}">{data_ext id="option_text" context="text"}</{tag_option}>' );
$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}>' );
$this->add( $select );
// Span
$span = new SLB_Field_Type( 'span', 'base_closed' );
$span->set_description( __( 'Inline wrapper', 'simple-lightbox' ) );
$span->set_property( 'tag', 'span' );
$span->set_property( 'value', 'Hello there!' );
$this->add( $span );
// Enable plugins to modify (add, remove, etc.) field types
$this->util->do_action_ref_array( 'register_fields', array( $this ), false );
// Signal completion of field registration
$this->util->do_action_ref_array( 'fields_registered', array( $this ), false );
}
/* Placeholder handlers */
function register_placeholders() {
// Default placeholder handlers
$this->register_placeholder( 'all', $this->m( 'process_placeholder_default' ), 11 );
$this->register_placeholder( 'field_id', $this->m( 'process_placeholder_id' ) );
$this->register_placeholder( 'field_name', $this->m( 'process_placeholder_name' ) );
$this->register_placeholder( 'data', $this->m( 'process_placeholder_data' ) );
$this->register_placeholder( 'data_ext', $this->m( 'process_placeholder_data_ext' ) );
$this->register_placeholder( 'loop', $this->m( 'process_placeholder_loop' ) );
$this->register_placeholder( 'label', $this->m( 'process_placeholder_label' ) );
$this->register_placeholder( 'checked', $this->m( 'process_placeholder_checked' ) );
// Allow other code to register placeholders
$this->util->do_action_ref_array( 'register_field_placeholders', array( $this ), false );
// Signal completion of field placeholder registration
$this->util->do_action_ref_array( 'field_placeholders_registered', array( $this ), false );
}
/**
* Register a function to handle a placeholder
* Multiple handlers may be registered for a single placeholder
* Adds filter hook to WP for handling specified placeholder
* Placeholders are in layouts and are replaced with data at runtime
* @uses add_filter()
* @param string $placeholder Name of placeholder to add handler for (Using 'all' will set the function as a handler for all placeholders
* @param callback $callback Function to set as a handler
* @param int $priority (optional) Priority of handler
* @return void
*/
function register_placeholder( $placeholder, $callback, $priority = 10 ) {
if ( 'all' === $placeholder ) {
$placeholder = '';
} else {
$placeholder = '_' . $placeholder;
}
$hook = $this->add_prefix( 'process_placeholder' . $placeholder );
add_filter( $hook, $callback, $priority, 5 );
}
/**
* Handles default placeholder processing.
*
* Processes placeholders that have not been processed by another handler.
*
* @param string $output Value to be used in place of placeholder. Should be empty.
* @param SLB_Field $item Field containing placeholder.
* @param array $placeholder Current placeholder.
* @see SLB_Field::parse_layout for structure of `$placeholder` array.
* @param string $layout Layout to build.
* @param array $data Extended data for item.
* @return string Value to use in place of current placeholder.
*/
function process_placeholder_default( $output, $item, $placeholder, $layout, $data ) {
// Validate parameters before processing.
if (
! empty( $output )
|| ( ! $item instanceof SLB_Field_Type )
|| ! is_array( $placeholder )
) {
return $output;
}
// Build path to replacement data.
$output = $item->get_member_value( $placeholder );
// Check if value is group (properties, etc.)
// All groups must have additional attributes (beyond reserved attributes) that define how items in group are used
if (
is_array( $output )
&& ! empty( $placeholder['attributes'] )
&& is_array( $placeholder['attributes'] )
&& 'properties' === $placeholder['tag']
) {
// Targeted property is an array.
// Placeholder contains additional options on how property is to be used.
// Find items matching criteria in $output
// Check for group criteria
$prop_group = $item->get_group( $placeholder['attributes']['group'] );
if ( ! empty( $prop_group ) ) {
/* Process group */
$group_out = array();
// Iterate through properties in group and build string.
foreach ( array_keys( $prop_group ) as $prop_key ) {
$prop_val = $item->get_property( $prop_key );
if ( is_null( $prop_val ) ) {
continue;
}
// Process placeholders.
$prop_val = $item->process_placeholders( $prop_val, $layout, $data );
// Add property to attribute string output.
$group_out[] = esc_attr( $prop_key ) . '="' . esc_attr( $prop_val ) . '"';
}
$output = implode( ' ', $group_out );
}
} elseif ( is_object( $output ) && ( $output instanceof $item->base_class ) ) {
/* Targeted property is actually a nested item */
// Set caller to current item
$output->set_caller( $item );
// Build layout for nested element
$output = $output->build_layout( $layout );
}
return $output;
}
/**
* Renders field ID formatted for a form field's `id` attribute.
*
* ID is formatted to be unique identifier for form field.
* Example: `options_field_id`.
* Registered as handler for `{field_id}` placeholder.
*
* @param string $output Placeholder's rendered value.
* @param SLB_Field $item Field containing placeholder.
* @param array &$placeholder Placeholder being processed.
* @param string $layout Name of layout being built.
* @param array $data Additional data for current field.
* @return string Field's ID (formatted for a form field's `id` attribute).
*/
function process_placeholder_id( $output, $item, &$placeholder, $layout, $data ) {
// Get attributes
$args = wp_parse_args( $placeholder['attributes'], array( 'format' => 'attr_id' ) );
$output = $item->get_id( $args );
// Set default placeholder context.
if ( ! isset( $placeholder['attributes']['context'] ) ) {
$placeholder['attributes']['context'] = 'attr';
}
return $output;
}
/**
* Renders field ID formatted for a form field's `name` attribute.
*
* ID is formatted to be part of an associative array for processing form submission.
* Example: `options[field_id]`.
* Registered as handler for `{field_name}` placeholder.
*
* @param string $output Placeholder's rendered value.
* @param SLB_Field $item Field containing placeholder.
* @param array &$placeholder Placeholder being processed.
* @param string $layout Name of layout being built.
* @param array $data Additional data for current field.
* @return string Field's ID (formatted for a form field's `name` attribute).
*/
function process_placeholder_name( $output, $item, &$placeholder, $layout, $data ) {
// Get attributes
$args = wp_parse_args( $placeholder['attributes'], array( 'format' => 'attr_name' ) );
$output = $item->get_id( $args );
// Set default placeholder context.
if ( ! isset( $placeholder['attributes']['context'] ) ) {
$placeholder['attributes']['context'] = 'attr';
}
return $output;
}
/**
* Build item label
* @see SLB_Fields::process_placeholder_default for parameter descriptions
* @return string Field label
*/
function process_placeholder_label( $output, $item, $placeholder, $layout, $data ) {
// Check if item has label property (e.g. sub-elements)
$out = $item->get_property( 'label' );
// If property not set, use item title
if ( empty( $out ) ) {
$out = $item->get_title();
}
return $out;
}
/**
* Retrieve data for item
* @see SLB_Field_Type::process_placeholder_default for parameter descriptions
* @return string Placeholder output
*/
function process_placeholder_data( $output, $item, $placeholder, $layout ) {
$opts = $placeholder['attributes'];
// Strip context from data retrieval options (Formatting handled upstream).
if ( is_array( $opts ) ) {
unset( $opts['context'] );
}
// Get data
$out = $item->get_data( $opts );
// Get specific member in value (e.g. value from a specific item element).
if (
is_array( $out )
&& is_array( $opts )
&& isset( $opts['element'] )
&& isset( $out[ $opts['element'] ] )
) {
$out = $out[ $opts['element'] ];
}
// Return data
return $out;
}
/**
* Set checked attribute on item
* Evaluates item's data to see if item should be checked or not
* @see SLB_Fields::process_placeholder_default for parameter descriptions
* @return string Appropriate checkbox attribute
*/
function process_placeholder_checked( $output, $item, $placeholder, $layout, $data ) {
$out = '';
$c = $item->get_container();
$d = ( isset( $c->data[ $item->get_id() ] ) ) ? $c->data[ $item->get_id() ] : null;
$item->set_property( 'd', true );
if ( $item->get_data() ) {
$out = 'checked="checked"';
}
$item->set_property( 'd', false );
return $out;
}
/**
* Loops over data to build item output
* Options:
* data - Dot-delimited path in item that contains data to loop through
* layout - Name of layout to use for each data item in loop
* layout_data - Name of layout to use for data item that matches previously-saved item data
* @see SLB_Field_Type::process_placeholder_default for parameter descriptions
* @return string Placeholder output
*/
function process_placeholder_loop( $output, $item, $placeholder, $layout, $data ) {
// Setup loop options
$attr_defaults = array(
'layout' => '',
'layout_data' => null,
'data' => '',
);
$attr = wp_parse_args( $placeholder['attributes'], $attr_defaults );
if ( is_null( $attr['layout_data'] ) ) {
$attr['layout_data'] =& $attr['layout'];
}
// Get data for loop
$path = explode( '.', $attr['data'] );
$loop_data = $item->get_member_value( $path );
// Check if data is callback
if ( is_callable( $loop_data ) ) {
$loop_data = call_user_func( $loop_data );
}
// Get item data
$data = $item->get_data();
// Iterate over data and build output
$out = array();
if ( is_array( $loop_data ) && ! empty( $loop_data ) ) {
foreach ( $loop_data as $value => $label ) {
// Load appropriate layout based on item value
$layout = ( ( 0 === $data && $value === $data ) xor $data === $value ) ? $attr['layout_data'] : $attr['layout'];
// Stop processing if no valid layout is returned
if ( empty( $layout ) ) {
continue;
}
// Prep extended item data
$data_ext = array(
'option_value' => $value,
'option_text' => $label,
);
$out[] = $item->build_layout( $layout, $data_ext );
}
}
// Return output
return implode( $out );
}
/**
* Returns specified value from extended data array for item.
*
* @param string $output Value to be used in place of placeholder.
* @param SLB_Field $item Field containing placeholder.
* @param array $placeholder Current placeholder.
* @see SLB_Field::parse_layout for structure of `$placeholder` array.
* @param string $layout Name of layout being built.
* @param array $data Extended data for item.
*
* @return string Processed value.
*/
function process_placeholder_data_ext( $output, SLB_Field $item, array $placeholder, $layout, array $data ) {
$key = ( isset( $placeholder['attributes']['id'] ) ) ? $placeholder['attributes']['id'] : false;
if ( ! ! $key && isset( $data[ $key ] ) && is_scalar( $data[ $key ] ) ) {
$output = strval( $data[ $key ] );
}
return $output;
}
/* Build */
/**
* Outputs items in a group.
*
* @param string $group ID of Group to output.
* @return string Group output.
* @todo Make compatible with parent::build_group()
*/
function build_group( $group ) {
$out = array();
/**
* Renders group output as a string.
*
* @uses $out Array containing group output.
* @return string Group output.
*/
$render_output = function() use ( $out ) {
// Combine output.
return implode( '', $out );
};
// Stop if group does not exist.
if ( ! $this->group_exists( $group ) ) {
return $render_output();
}
// Classnames.
$cls = (object) [
'multi' => 'multi_field',
'single' => 'single_field',
'elements' => 'has_elements',
'group_desc' => $this->add_prefix( 'group_description' ),
'group_wrap' => $this->add_prefix( 'attributes_wrap' ),
'item_wrap' => $this->add_prefix( 'attribute_wrap' ),
];
// Templates.
$tpl = (object) [
'container_start' => '<div class="%s">',
'container_end' => '</div>',
'item_start' => '<div id="%1$s_wrap" class="%2$s">',
'item_end' => '</div>',
'text_block' => '<p class="%1$s">%2$s</p>',
];
// Process group.
$group = $this->get_group( $group );
$group_items = ( count( $group->items ) > 1 ) ? $cls->multi : $cls->single;
$fs = array_keys( $group->items );
$f =& $group->items[ $fs[0] ];
$els = $f->get_member_value( 'elements', '', null );
if ( ! empty( $els ) ) {
$group_items .= '_' . $cls->elements;
}
// Wrap items with container element.
$classname = array( $cls->group_wrap, $group_items );
$out[] = sprintf( $tpl->container_start, implode( ' ', $classname ) );
// Clear temp variables.
unset( $fs, $f, $els, $classname );
// Build layout for each item in group
foreach ( array_keys( $group->items ) as $item_id ) {
// Init item.
$item =& $group->items[ $item_id ];
$item->set_caller( $this );
// Start item output.
$id = $this->add_prefix( 'field_' . $item->get_id() );
$out[] = sprintf( $tpl->item_start, $id, $cls->item_wrap );
// Build item layout.
$out[] = $item->build_layout();
// End item output.
$out[] = $tpl->item_end;
// Cleanup.
$item->clear_caller();
unset( $item, $id );
}
// Close items container.
$out[] = $tpl->container_end;
// Add description if exists
if ( ! empty( $group->description ) ) {
$out[] = sprintf( $tpl->text_block, $cls->group_desc, $group->description );
}
// Render and return output.
return $render_output();
}
}

View File

@@ -0,0 +1,185 @@
<?php
/**
* Option object
* @package Simple Lightbox
* @subpackage Options
* @author Archetyped
*/
class SLB_Option extends SLB_Field {
/* Properties */
public $hook_prefix = 'option';
/**
* Determines whether option will be sent to client
* @var bool
*/
public $in_client = false;
/**
* Child mapping
* @see SLB_Field_Base::map
* @var array
*/
public $map = array(
'default' => 'data',
'attr' => 'properties',
);
public $property_priority = array( 'id', 'data', 'parent' );
/* Init */
/**
* @see SLB_Field::__construct()
* @uses parent::__construct() to initialize instance
* @param $id
* @param $title
* @param $default
*/
function __construct( $id, $title = '', $default = '' ) {
// Normalize properties
$args = func_get_args();
$defaults = array(
'title' => '',
'default' => '',
);
$props = $this->make_properties( $args, $defaults );
// Validate
if ( is_scalar( $id ) ) {
$props['id'] = $id;
}
if ( ! is_string( $props['title'] ) ) {
$props['title'] = '';
}
// Send to parent constructor
parent::__construct( $props );
}
/* Getters/Setters */
/**
* Retrieve default value for option
* @return mixed Default option value
*/
function get_default( $context = '' ) {
return $this->get_data( $context, false );
}
/**
* Sets parent based on default value
*/
function set_parent( $parent = null ) {
$p = $this->get_parent();
if ( empty( $parent ) && empty( $p ) ) {
$parent = 'text';
$d = $this->get_default();
if ( is_bool( $d ) ) {
$parent = 'checkbox';
}
$parent = 'option_' . $parent;
} elseif ( ! empty( $p ) && ! is_object( $p ) ) {
$parent =& $p;
}
parent::set_parent( $parent );
}
/**
* Set in_client property
* @uses this::in_client
* @param bool Whether or not option should be included in client output (Default: false)
* @return void
*/
function set_in_client( $in_client = false ) {
$this->in_client = ! ! $in_client;
}
/**
* Determines whether option should be included in client output
* @uses this::in_client
* @return bool TRUE if option is included in client output
*/
function get_in_client() {
return $this->in_client;
}
/* Formatting */
/**
* Format data as string for browser output
* @see SLB_Field_Base::format()
* @param mixed $value Data to format
* @param string $context (optional) Current context
* @return string Formatted value
*/
function format_display( $value, $context = '' ) {
if ( ! is_string( $value ) ) {
if ( is_bool( $value ) ) {
$value = ( $value ) ? __( 'Enabled', 'simple-lightbox' ) : __( 'Disabled', 'simple-lightbox' );
} elseif ( is_null( $value ) ) {
$value = '';
} else {
$value = strval( $value );
}
} elseif ( empty( $value ) ) {
$value = 'empty';
}
return htmlentities( $value );
}
/**
* Format data using same format as default value
* @see SLB_Field_Base::format()
* @param mixed $value Data to format
* @param string $context (optional) Current context
* @return mixed Formatted option value
*/
function format_default( $value, $context = '' ) {
// Get default value
$d = $this->get_default();
if ( empty( $d ) ) {
return $value;
}
if ( is_bool( $d ) ) {
$value = $this->format_bool( $value );
} elseif ( is_string( $d ) ) {
$value = $this->format_string( $value );
}
return $value;
}
/**
* Format data as boolean (true/false)
* @see SLB_Field_Base::format()
* @param mixed $value Data to format
* @param string $context (optional) Current context
* @return bool Option value
*/
function format_bool( $value, $context = '' ) {
if ( ! is_bool( $value ) ) {
$value = ! ! $value;
}
return $value;
}
/**
* Format data as string
* @see SLB_Field_Base::format()
* @param mixed $value Data to format
* @param string $context (optional) Current context
* @return string Option string value
*/
function format_string( $value, $context = '' ) {
if ( is_bool( $value ) ) {
$value = ( $value ) ? 'true' : 'false';
} elseif ( is_object( $value ) ) {
$value = get_class( $value );
} elseif ( is_array( $value ) ) {
$value = implode( ' ', $value );
} else {
$value = strval( $value );
}
return $value;
}
}

View File

@@ -0,0 +1,696 @@
<?php
/**
* Options collection
* @package Simple Lightbox
* @subpackage Options
* @author Archetyped
* @uses SLB_Field_Collection
*/
class SLB_Options extends SLB_Field_Collection {
/* Properties */
public $hook_prefix = 'options';
public $item_type = 'SLB_Option';
/**
* Key for saving version to DB
* @var string
*/
private $version_key = 'version';
/**
* Whether version has been checked
* @var bool
*/
public $version_checked = false;
public $items_migrated = false;
public $build_vars = array(
'validate_pre' => false,
'validate_post' => false,
'save_pre' => false,
'save_post' => false,
);
/* Init */
function __construct( $id = '', $props = array() ) {
// Validate arguments
$args = func_get_args();
// Set default ID
if ( ! $this->validate_id( $id ) ) {
$id = 'options';
}
$defaults = $this->integrate_id( $id );
$props = $this->make_properties( $args, $defaults );
parent::__construct( $props );
$this->add_prefix_ref( $this->version_key );
}
protected function _hooks() {
parent::_hooks();
// Register fields
$this->util->add_action( 'register_fields', $this->m( 'register_fields' ), 10, 1, false );
// Set option parents
$this->util->add_action( 'fields_registered', $this->m( 'set_parents' ), 10, 1, false );
// Building
$this->util->add_action( 'build_init', $this->m( 'build_init' ) );
// Admin
$this->util->add_action( 'admin_page_render_content', $this->m( 'admin_page_render_content' ), 10, 3, false );
$this->util->add_filter( 'admin_action_reset', $this->m( 'admin_action_reset' ), 10, 3, false );
}
/* Legacy/Migration */
/**
* Checks whether new version has been installed and migrates necessary settings
* @uses $version_key as option name
* @uses get_option() to retrieve saved version number
* @uses SLB_Utilities::get_plugin_version() to retrieve current version
* @return bool TRUE if version has been changed
*/
function check_update() {
if ( ! $this->version_checked ) {
$this->version_checked = true;
$version_changed = false;
// Get version from DB
$vo = $this->get_version();
// Get current version
$vn = $this->util->get_plugin_version();
// Compare versions
if ( $vo !== $vn ) {
// Update saved version
$this->set_version( $vn );
// Migrate old version to new version
if ( strcasecmp( $vo, $vn ) < 0 ) {
// Force full migration
$version_changed = true;
}
}
// Migrate
$this->migrate( $version_changed );
}
return $this->version_checked;
}
/**
* Save plugin version to DB
* If no version supplied, will fetch plugin data to determine version
* @uses $version_key as option name
* @uses update_option() to save version to options table
* @param string $ver (optional) Plugin version
*/
function set_version( $ver = null ) {
if ( empty( $ver ) ) {
$ver = $this->util->get_plugin_version();
}
return update_option( $this->version_key, $ver );
}
/**
* Retrieve saved version data
* @return string Saved version
*/
function get_version() {
return get_option( $this->version_key, '' );
}
/**
* Migrate options from old versions to current version
* @uses self::items_migrated to determine if simple migration has been performed in current request or not
* @uses self::save() to save data after migration
* @param bool $full Whether to perform a full migration or not (Default: No)
*/
function migrate( $full = false ) {
if ( ! $full && $this->items_migrated ) {
return false;
}
// Legacy options
$d = null;
$this->load_data();
$items = $this->get_items();
// Migrate separate options to unified option
if ( $full ) {
foreach ( $items as $opt => $props ) {
$oid = $this->add_prefix( $opt );
$o = get_option( $oid, $d );
if ( $o !== $d ) {
// Migrate value to data array
$this->set_data( $opt, $o, false );
// Delete legacy option
delete_option( $oid );
}
}
}
// Migrate legacy items
if ( is_array( $this->properties_init ) && isset( $this->properties_init['legacy'] ) && is_array( $this->properties_init['legacy'] ) ) {
$l =& $this->properties_init['legacy'];
// Normalize legacy map
foreach ( $l as $opt => $dest ) {
if ( ! is_array( $dest ) ) {
if ( is_string( $dest ) ) {
$l[ $opt ] = array( $dest );
} else {
unset( $l[ $opt ] );
}
}
}
/* Separate options */
if ( $full ) {
foreach ( $l as $opt => $dest ) {
$oid = $this->add_prefix( $opt );
$o = get_option( $oid, $d );
// Only migrate valid values
if ( $o !== $d ) {
// Process destinations
foreach ( $dest as $id ) {
$this->set_data( $id, $o, false, true );
}
}
// Remove legacy option
delete_option( $oid );
}
}
/* Simple Migration (Internal options only) */
// Get existing items that are also legacy items
$opts = array_intersect_key( $this->get_data(), $l );
foreach ( $opts as $opt => $val ) {
$d = $this->get_data( $opt );
// Migrate data from old option to new option
$dest = $l[ $opt ];
// Validate new options to send data to
foreach ( $dest as $id ) {
$this->set_data( $id, $d, false, true );
}
// Remove legacy option
$this->remove( $opt, false );
}
}
// Save changes
$this->save();
// Set flag
$this->items_migrated = true;
}
/* Option setup */
/**
* Get elements for creating fields
* @return obj
*/
function get_field_elements() {
static $o = null;
if ( empty( $o ) ) {
$o = new stdClass();
/* Layout */
$layout = new stdClass();
$layout->label = '<label for="{field_id}" class="title block">{label}</label>';
$layout->label_ref = '{label ref_base="layout"}';
$layout->field_pre = '<div class="input block">';
$layout->field_post = '</div>';
$layout->opt_pre = '<div class="' . $this->add_prefix( 'option_item' ) . '">';
$layout->opt_post = '</div>';
$layout->form = '<{form_attr ref_base="layout"} /> <span class="description">(' . __( 'Default', 'simple-lightbox' ) . ': {data context="display" top="0"})</span>';
/* Combine */
$o->layout =& $layout;
}
return $o;
}
/**
* Register option-specific fields
* @param SLB_Fields $fields Reference to global fields object
* @return void
*/
function register_fields( $fields ) {
// Layouts
$o = $this->get_field_elements();
$l =& $o->layout;
$form = implode(
'',
array(
$l->opt_pre,
$l->label_ref,
$l->field_pre,
$l->form,
$l->field_post,
$l->opt_post,
)
);
// Text input
$otxt = new SLB_Field_Type( 'option_text', 'text' );
$otxt->set_property( 'class', '{inherit} code' );
$otxt->set_property( 'size', null );
$otxt->set_property( 'value', '{data}' );
$otxt->set_layout( 'label', $l->label );
$otxt->set_layout( 'form', $form );
$fields->add( $otxt );
// Checkbox
$ocb = new SLB_Field_Type( 'option_checkbox', 'checkbox' );
$ocb->set_layout( 'label', $l->label );
$ocb->set_layout( 'field_reference', sprintf( '<input type="hidden" name="%s" value="{field_name format="raw"}" />', "{$this->get_id('formatted')}_items[]" ) );
$ocb->set_layout( 'form', '{field_reference ref_base="layout"}' . $form );
$fields->add( $ocb );
// Select
$othm = new SLB_Field_Type( 'option_select', 'select' );
$othm->set_layout( 'label', $l->label );
$othm->set_layout( 'form_start', $l->field_pre . '{inherit}' );
$othm->set_layout( 'form_end', '{inherit}' . $l->field_post );
$othm->set_layout( 'form', $l->opt_pre . '{inherit}' . $l->opt_post );
$fields->add( $othm );
}
/**
* Set parent field types for options
* Parent only set for Admin pages
* @uses SLB_Option::set_parent() to set parent field for each option item
* @uses is_admin() to determine if current request is admin page
* @param object $fields Collection of default field types
* @return void
*/
function set_parents( $fields ) {
if ( ! is_admin() ) {
return false;
}
$items = &$this->get_items();
foreach ( array_keys( $items ) as $opt ) {
$items[ $opt ]->set_parent();
}
foreach ( $this->items as $opt ) {
$p = $opt->parent;
if ( is_object( $p ) ) {
$p = 'o:' . $p->id;
}
}
}
/* Processing */
/**
* Validates option data.
*
* Validates option values (e.g. prior to saving to DB, after form submission, etc.).
* Values are formatted and sanitized according to corresponding option's data type
* (e.g. boolean, string, number, etc.).
*
* @since 1.5.5
*
* @param array<string,scalar> $values Optional. Option data to validate.
* Indexed by option ID.
* Default form-submission data used.
* @return array<string,scalar> Validated data. Indexed by option ID.
*/
function validate( $values = null ) {
/** @var array<string,scalar> $values_valid Validated option data. Indexed by option ID. */
$values_valid = [];
// Enforce values data type.
if ( ! is_array( $values ) ) {
/** @var array<string,scalar> $values */
$values = [];
}
/**
* Generates query variable using common base.
*
* @since 2.8.0
*
* @param string $text Optional. Text to append to base.
*
* @return string Query variable name. Format: "{base}_{text}". Default "{base}".
*/
$qv = function ( $text = '' ) {
static $base;
// Get base.
if ( empty( $base ) ) {
$base = $this->get_id( 'formatted' );
}
$out = $base;
// Append text to base.
if ( is_string( $text ) && ! empty( $text ) ) {
$out .= "_{$text}";
}
return $out;
};
// Get options form field group ID.
$qvar = $qv();
// Use form submission data when no values provided.
if ( empty( $values ) && isset( $_POST[ $qvar ] ) && check_admin_referer( $qvar, $qv( 'nonce' ) ) ) {
/** @var array<string,scalar> $values */
$values = $_POST[ $qvar ];
// Append non-submitted, but rendered fields (e.g. unchecked checkboxes)
$qvar_items = $qv( 'items' );
/** @var string[] $items_bool Boolean options rendered in submitted form. */
$items_bool = ( isset( $_POST[ $qvar_items ] ) ) ? $_POST[ $qvar_items ] : null;
if ( ! empty( $items_bool ) && is_array( $items_bool ) ) {
foreach ( $items_bool as $item_id ) {
// Add missing boolean options (false == unchecked).
if ( ! array_key_exists( $item_id, $values ) && $this->has( $item_id ) && is_bool( $this->get_default( $item_id ) ) ) {
$values_valid[ $item_id ] = false;
}
}
}
unset( $qvar, $qvar_items, $items_bool, $item_id );
}
// Process values.
/**
* @var string $id Option ID.
* @var mixed $val Option value (raw/unsanitized).
*/
foreach ( $values as $id => $val ) {
// Do not process invalid option IDs or invalid (non-scalar) data.
if ( ! $this->has( $id ) || ! is_scalar( $val ) ) {
continue;
}
// Conform to option's data type and sanitize.
/** @var scalar $d Option's default data. */
$d = $this->get_default( $id );
if ( is_bool( $d ) ) {
// Boolean.
$val = ! ! $val;
} elseif ( ( is_int( $d ) || is_float( $d ) ) && ! is_numeric( $val ) ) {
// Numeric - do not process non-numeric values for int/float fields.
continue;
} elseif ( is_int( $d ) ) {
// Integer.
$val = (int) $val;
} elseif ( is_float( $d ) ) {
// Float.
$val = (float) $val;
} else {
// Defaut: Handle as string.
$val = sanitize_text_field( wp_unslash( $val ) );
}
// Add to validated data.
$values_valid[ $id ] = $val;
}
unset( $id, $val );
// Return validated values.
return $values_valid;
}
/* Data */
/**
* Retrieve options from database
* @uses get_option to retrieve option data
* @return array Options data
*/
function fetch_data( $sanitize = true ) {
// Get data
$data = get_option( $this->get_key(), null );
if ( $sanitize && is_array( $data ) ) {
// Sanitize loaded data based on default values
foreach ( $data as $id => $val ) {
if ( $this->has( $id ) ) {
$opt = $this->get( $id );
if ( is_bool( $opt->get_default() ) ) {
$data[ $id ] = ! ! $val;
}
}
}
}
return $data;
}
/**
* Retrieves option data for collection
* @see SLB_Field_Collection::load_data()
*/
function load_data() {
if ( ! $this->data_loaded ) {
// Retrieve data
$this->data = $this->fetch_data();
parent::load_data();
// Check update
$this->check_update();
}
}
/**
* Resets option values to their default values
* @param bool $hard Reset all options if TRUE (default), Reset only unset options if FALSE
*/
function reset( $hard = true ) {
$this->load_data();
// Reset data
if ( $hard ) {
$this->data = null;
}
// Save
$this->save();
}
/**
* Save options data to database
*/
function save() {
$this->normalize_data();
update_option( $this->get_key(), $this->data );
}
/**
* Normalize data
* Assures that data in collection match items
* @uses self::data to reset and save collection data after normalization
*/
function normalize_data() {
$data = array();
foreach ( $this->get_items() as $id => $opt ) {
$data[ $id ] = $opt->get_data();
}
$this->data =& $data;
return $data;
}
/* Collection */
/**
* Build key for saving/retrieving data to options table
* @return string Key
*/
function get_key() {
return $this->add_prefix( $this->get_id() );
}
/**
* Add option to collection
* @uses SLB_Field_Collection::add() to add item
* @param string $id Unique item ID
* @param array $properties Item properties
* @param bool $update (optional) Should item be updated or overwritten (Default: FALSE)
* @return SLB_Option Option instance
*/
function &add( $id, $properties = array(), $update = false ) {
// Create item
$args = func_get_args();
$ret = call_user_func_array( array( 'parent', 'add' ), $args );
return $ret;
}
/**
* Retrieve option value
* @uses get_data() to retrieve option data
* @param string $option Option ID to retrieve value for
* @param string $context (optional) Context for formatting data
* @return mixed Option value
*/
function get_value( $option, $context = '' ) {
return $this->get_data( $option, $context );
}
/**
* Retrieve option value as boolean (true/false)
* @uses get_data() to retrieve option data
* @param string $option Option ID to retrieve value for
* @return bool Option value
*/
function get_bool( $option ) {
return $this->get_value( $option, 'bool' );
}
function get_string( $option ) {
return $this->get_value( $option, 'string' );
}
/**
* Retrieve option's default value
* @uses get_data() to retrieve option data
* @param string $option Option ID to retrieve value for
* @param string $context (optional) Context for formatting data
* @return mixed Option's default value
*/
function get_default( $option, $context = '' ) {
return $this->get_data( $option, $context, false );
}
/* Output */
function build_init() {
if ( $this->build_vars['validate_pre'] ) {
$values = $this->validate();
if ( $this->build_vars['save_pre'] ) {
$this->set_data( $values );
}
}
}
/**
* Build array of option values for client output
* @return array Associative array of options
*/
function build_client_output() {
$items = $this->get_items();
$out = array();
foreach ( $items as $option ) {
if ( ! $option->get_in_client() ) {
continue;
}
$out[ $option->get_id() ] = $option->get_data( 'default' );
}
return $out;
}
/* Admin */
/**
* Handles output building for options on admin pages
* @param obj|array $opts Options instance or Array of options instance and groups to build
* @param obj $page Admin Page instance
* @param obj $state Admin Page state properties
*/
public function admin_page_render_content( $opts, $page, $state ) {
$groups = null;
if ( is_array( $opts ) && count( $opts ) === 2 ) {
$groups = $opts[1];
$opts = $opts[0];
}
if ( $opts === $this ) {
// Set build variables and callbacks
$this->set_build_var( 'admin_page', $page );
$this->set_build_var( 'admin_state', $state );
if ( ! empty( $groups ) ) {
$this->set_build_var( 'groups', $groups );
}
$hooks = array(
'filter' => array(
'parse_build_vars' => array( $this->m( 'admin_parse_build_vars' ), 10, 2 ),
),
);
// Add hooks
foreach ( $hooks as $type => $hook ) {
$m = 'add_' . $type;
foreach ( $hook as $tag => $args ) {
array_unshift( $args, $tag );
call_user_func_array( $this->util->m( $m ), $args );
}
}
// Build output
$this->build( array( 'build_groups' => $this->m( 'admin_build_groups' ) ) );
// Remove hooks
foreach ( $hooks as $type => $hook ) {
$m = 'remove_' . $type;
foreach ( $hook as $tag => $args ) {
call_user_func( $this->util->m( $m ), $tag, $args[0] );
}
}
// Clear custom build vars
$this->delete_build_var( 'admin_page' );
$this->delete_build_var( 'admin_state' );
}
}
/**
* Builds option groups output
*/
public function admin_build_groups() {
$page = $this->get_build_var( 'admin_page' );
$state = $this->get_build_var( 'admin_state' );
$groups = $this->get_build_var( 'groups' );
// Get all groups
$groups_all = $this->get_groups();
if ( empty( $groups ) ) {
$groups = array_keys( $groups_all );
}
// Iterate through groups
foreach ( $groups as $gid ) {
// Validate
if ( ! isset( $groups_all[ $gid ] ) || ! count( $this->get_items( $gid ) ) ) {
continue;
}
// Add meta box for each group
$g = $groups_all[ $gid ];
add_meta_box(
$g->id,
$g->title,
$this->m( 'admin_build_group' ),
$state->screen,
$state->context,
$state->priority,
array(
'group' => $g->id,
'page' => $page,
)
);
}
}
/**
* Group output handler for admin pages
* @param obj $obj Object passed by `do_meta_boxes()` call (Default: NULL)
* @param array $box Meta box properties
*/
public function admin_build_group( $obj, $box ) {
$a = $box['args'];
$group = $a['group'];
$this->build_group( $group );
}
/**
* Parse build vars
* @uses `options_parse_build_vars` filter hook
*/
public function admin_parse_build_vars( $vars, $opts ) {
// Handle form submission
if ( isset( $_POST[ $opts->get_id( 'formatted' ) ] ) ) {
$vars['save_pre'] = true;
$vars['validate_pre'] = true;
}
return $vars;
}
/**
* Admin reset handler
* @param bool $res Current result
* @param obj $opts Options instance
* @param obj $reset Admin Reset instance
*/
public function admin_action_reset( $res, $opts, $reset ) {
// Only process matching options instance
if ( $opts === $this ) {
// Reset options
$this->reset();
// Set result
$res = true;
}
return $res;
}
}

View File

@@ -0,0 +1,9 @@
<?php
/**
* Template Tag
* @package Simple Lightbox
* @subpackage Template
* @author Archetyped
*/
class SLB_Template_Tag extends SLB_Component { }

View File

@@ -0,0 +1,122 @@
<?php
/**
* Content Handler Collection
* @package Simple Lightbox
* @subpackage Content Handler
* @author Archetyped
*/
class SLB_Template_Tags extends SLB_Collection_Controller {
/* Configuration */
protected $item_type = 'SLB_Template_Tag';
public $hook_prefix = 'template_tags';
// Use tag ID as key
protected $key_prop = 'get_id';
// Call $key_prop is a method to be called
protected $key_call = true;
/* Properties */
/**
* Cache properties (key, group)
* @var object
*/
protected $cache_props = null;
/* Initialization */
protected function _hooks() {
parent::_hooks();
$this->util->add_action( 'init', $this->m( 'init_defaults' ) );
$this->util->add_action( 'footer', $this->m( 'client_output' ), 1, 0, false );
$this->util->add_filter( 'footer_script', $this->m( 'client_output_script' ), $this->util->priority( 'client_footer_output' ), 1, false );
}
/* Collection Management */
/**
* Add template tag
* Accepts properties to create new template tag OR previously-initialized tag instance
* @see parent::add()
* @param string $id Tag ID
* @param array $props Tag properties
* @return object Current instance
*/
public function add( $id, $props = array() ) {
$o = ( is_string( $id ) ) ? new $this->item_type( $id, $props ) : $id;
// Add to collection
return parent::add( $o );
}
/* Defaults */
/**
* Initialize default template tags
* @param SLB_Template_Tags $tags Tags controller
*/
public function init_defaults( $tags ) {
$js_path = 'js/';
$js_path .= ( SLB_DEV ) ? 'dev' : 'prod';
$src_base = $this->util->get_file_url( 'template-tags', true );
$defaults = array(
'item' => array(
'scripts' => array(
array( 'base', "$src_base/item/$js_path/tag.item.js" ),
),
),
'ui' => array(
'scripts' => array(
array( 'base', "$src_base/ui/$js_path/tag.ui.js" ),
),
),
);
foreach ( $defaults as $id => $props ) {
$tags->add( $id, $props );
}
}
/* Output */
/**
* Build client output
*/
public function client_output() {
// Load matched handlers
foreach ( $this->get() as $tag ) {
$tag->enqueue_scripts();
}
}
/**
* Client output script
* @param array $commands Client script commands
* @return array Modified script commands
*/
public function client_output_script( $commands ) {
$out = array( '/* TPLT */' );
$code = array();
foreach ( $this->get() as $tag ) {
$styles = $tag->get_styles( array( 'uri_format' => 'full' ) );
if ( empty( $styles ) ) {
continue;
}
// Setup client parameters
$params = array(
sprintf( "'%s'", $tag->get_id() ),
);
$params[] = wp_json_encode( array( 'styles' => array_values( $styles ) ) );
// Extend handler in client
$code[] = $this->util->call_client_method( 'View.extend_template_tag_handler', $params, false );
}
if ( ! empty( $code ) ) {
$out[] = implode( '', $code );
$commands[] = implode( PHP_EOL, $out );
}
return $commands;
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* Theme
* @package Simple Lightbox
* @subpackage Themes
* @author Archetyped
*/
class SLB_Theme extends SLB_Component {
/* Properties */
protected $props_required = array( 'name' );
/**
* Public flag
* @var bool
*/
protected $public = true;
/* Get/Set */
/**
* Retrieve theme's ancestors
* @param bool $sort_topdown (optional) Ancestor sorting (Default: Nearest to Farthest)
* @return array Theme's ancestors (sorted by nearest to most distant ancestor)
*/
public function get_ancestors( $sort_topdown = false ) {
$ret = array();
/**
* @var SLB_Theme
*/
$thm = $this;
while ( $thm->has_parent() ) {
$par = $thm->get_parent();
// Add ancestor
if ( $par->is_valid() && ! in_array( $par, $ret, true ) ) {
$ret[] = $par;
}
// Get next ancestor
$thm = $par;
}
// Sorting
if ( $sort_topdown ) {
$ret = array_reverse( $ret );
}
return $ret;
}
/**
* Set public flag
* @param bool $public
*/
public function set_public( $public ) {
$this->public = ! ! $public;
}
/**
* Get privacy state
* @return bool
*/
public function get_public() {
return ! ! $this->public;
}
/* Templates */
/**
* Add template file
* @see `add_file()`
* @param string $handle Template handle
* @param string $src Template URI
* @return obj Current instance
*/
protected function add_template( $handle, $src ) {
return $this->add_file( 'template', $handle, $src );
}
/**
* Retrieve template file
* @see `get_file()`
* @param string $handle Template handle
* @param string $format (optional) Return value format
* @return mixed Template file (Default: array of file properties @see `Base_Object::add_file()`)
*/
protected function get_template( $handle, $format = null ) {
return $this->get_file( 'template', $handle, $format );
}
/* Layout */
/**
* Set theme layout
* @uses `add_template()`
* @param string $src Layout file URI
* @return Current instance
*/
public function set_layout( $src ) {
return $this->add_template( 'layout', $src );
}
/**
* Get layout
* @param string $format (optional) Layout data format
* @return mixed Theme layout
*/
public function get_layout( $format = null ) {
return $this->get_template( 'layout', $format );
}
}

View File

@@ -0,0 +1,303 @@
<?php
/**
* Themes Collection
* @package Simple Lightbox
* @subpackage Themes
* @author Archetyped
*/
class SLB_Themes extends SLB_Collection_Controller {
/* Configuration */
protected $item_type = 'SLB_Theme';
public $hook_prefix = 'themes';
protected $key_prop = 'get_id';
protected $key_call = true;
/* Properties */
protected $id_default = null;
/* Initialization */
protected function _hooks() {
parent::_hooks();
// Register themes
$this->util->add_action( 'init', $this->m( 'init_defaults' ), 1 );
// Client output
$this->util->add_action( 'footer', $this->m( 'client_output' ), 1, 0, false );
$this->util->add_filter( 'footer_script', $this->m( 'client_output_script' ), $this->util->priority( 'client_footer_output' ), 1, false );
}
protected function _options() {
$opts = array(
'items' => array(
'theme_default' => array(
'title' => __( 'Theme', 'simple-lightbox' ),
'default' => $this->get_default_id(),
'group' => array( 'ui', 0 ),
'parent' => 'option_select',
'options' => $this->m( 'opt_get_field_values' ),
'in_client' => true,
),
),
);
parent::_set_options( $opts );
}
/**
* Add default themes
* @param SLB_Themes $themes Themes controller
*/
function init_defaults( $themes ) {
$js_path = 'js/';
$js_path .= ( SLB_DEV ) ? 'dev' : 'prod';
$scheme = is_ssl() ? 'https' : 'http';
$baseline = $this->add_prefix( 'baseline' );
$src_base = $this->util->get_file_url( 'themes', true );
$defaults = array(
$baseline => array(
'name' => __( 'Baseline', 'simple-lightbox' ),
'public' => false,
'layout' => "$src_base/baseline/layout.html",
'scripts' => array(
array( 'base', $src_base . "/baseline/$js_path/client.js" ),
),
'styles' => array(
array( 'base', "$src_base/baseline/css/style.css" ),
),
),
$this->get_default_id() => array(
'name' => __( 'Default (Light)', 'simple-lightbox' ),
'parent' => $baseline,
'scripts' => array(
array( 'base', $src_base . "/default/$js_path/client.js" ),
),
'styles' => array(
array( 'base', "$src_base/default/css/style.css" ),
),
),
$this->add_prefix( 'black' ) => array(
'name' => __( 'Default (Dark)', 'simple-lightbox' ),
'parent' => $this->get_default_id(),
'styles' => array(
array( 'base', "$src_base/black/css/style.css" ),
),
),
);
foreach ( $defaults as $id => $props ) {
$themes->add( $id, $props );
}
}
/* Collection management */
/**
* Add theme
* Accepts properties to create new theme or previously-created theme instance
* @uses parent::add()
* @param string|object $id Theme ID (or Theme object)
* @param array $props Theme properties
* @return object Current instance
*/
public function add( $id, $props = array() ) {
// Prepare parent
if ( isset( $props['parent'] ) && ! ( $props['parent'] instanceof $this->item_type ) ) {
$pid = $props['parent'];
$items = $this->get( array( 'include_private' => true ) );
if ( isset( $items[ $pid ] ) ) {
$props['parent'] = $items[ $pid ];
}
}
$o = ( is_string( $id ) ) ? new $this->item_type( $id, $props ) : $id;
// Add to collection
return parent::add( $o );
}
/**
* Get themes
* @param array $args (optional) Arguments
* @return array Themes
*/
public function get( $args = null ) {
// Normalize arguments
$args_default = array(
'include_public' => true,
'include_private' => false,
);
$r = wp_parse_args( $args, $args_default );
$r['include_public'] = ! ! $r['include_public'];
$r['include_private'] = ! ! $r['include_private'];
$items = parent::get( $args );
if ( empty( $items ) ) {
return $items;
}
/* Process custom arguments */
// Filter
$items_exclude = array();
// Identify excluded themes
$filter_props = array(
'include_public' => true,
'include_private' => false,
);
foreach ( $filter_props as $filter_prop => $filter_value ) {
if ( ! $r[ $filter_prop ] ) {
foreach ( $items as $id => $item ) {
if ( $item->get_public() === $filter_value ) {
$items_exclude[] = $id;
}
}
}
}
// Filter themes from collection
$items = array_diff_key( $items, array_fill_keys( $items_exclude, null ) );
return $items;
}
/* Helpers */
/**
* Retrieve default theme ID
* @uses `$id_default`
* @return string Default theme ID
*/
public function get_default_id() {
if ( ! $this->id_default ) {
$this->id_default = $this->add_prefix( 'default' );
}
return $this->id_default;
}
/**
* Retrieve currently-selected theme
* @return SLB_Theme Selected theme
*/
protected function get_selected() {
// Get themes
$thms = $this->get();
// Retrieve currently-selected theme
$id = $this->options->get_value( 'theme_default' );
if ( ! isset( $thms[ $id ] ) ) {
$id = $this->get_default_id();
}
return $thms[ $id ];
}
/* Output */
/**
* Build client output
*/
public function client_output() {
// Process active theme
$thm = $this->get_selected();
// Get theme ancestors
$thms = $thm->get_ancestors( true );
$thms[] = $thm;
foreach ( $thms as $thm ) {
// Load files
$thm->enqueue_scripts();
}
}
/**
* Client output script
*
* @param array $commands Client script commands
* @return array Modified script commands
*/
public function client_output_script( $commands ) {
// Theme
$thm = $this->get_selected();
// Process theme ancestors
$thms = $thm->get_ancestors( true );
$thms[] = $thm;
$out = array( '/* THM */' );
$code = array();
// Build output for each theme
foreach ( $thms as $thm ) {
// Setup client parameters
$params = array(
sprintf( "'%s'", $thm->get_id() ),
);
// Theme properties
$thm_props = array(
'name' => $thm->get_name(),
'parent' => ( $thm->has_parent() ) ? $thm->get_parent()->get_id() : '',
'styles' => array_values( $thm->get_styles( array( 'uri_format' => 'full' ) ) ),
);
/* Optional properties */
// Layout
$layout = $thm->get_layout( 'contents' );
if ( ! empty( $layout ) ) {
// Format
$layout = str_replace( array( "\n", "\r", "\t" ), '', $layout );
// Save
$thm_props['layout_raw'] = $layout;
}
// Add properties to parameters
$params[] = wp_json_encode( $thm_props );
// Add theme to client
$code[] = $this->util->call_client_method( 'View.extend_theme', $params, false );
}
if ( ! empty( $code ) ) {
$out[] = implode( '', $code );
$commands[] = implode( PHP_EOL, $out );
}
return $commands;
}
/* Options */
/**
* Retrieve themes for use in option field
* @uses self::theme_default
* @return array Theme options
*/
public function opt_get_field_values() {
// Get themes
$items = $this->get();
$d = $this->get_default_id();
// Pop out default theme
if ( isset( $items[ $d ] ) ) {
$itm_d = $items[ $d ];
unset( $items[ $d ] );
}
// Sort themes by name
uasort(
$items,
function( $a, $b ) {
return strcmp( $a->get_name(), $b->get_name() );
}
);
// Insert default theme at top of array
if ( isset( $itm_d ) ) {
$items = array( $d => $itm_d ) + $items;
}
// Build options
foreach ( $items as $item ) {
$items[ $item->get_id() ] = $item->get_name();
}
return $items;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
# Copyright (C) 2010
# This file is distributed under the same license as the package.
msgid ""
msgstr ""
"Project-Id-Version: Simple-Lightbox\n"
"Report-Msgid-Bugs-To: http://wordpress.org/tag/simple-lightbox\n"
"POT-Creation-Date: 2011-10-14 03:38:17+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2011-11-21 19:22-1000\n"
"Last-Translator: Archetyped <contact@archetyped.com>\n"
"Language-Team: <support@lettoblog.com>\n"
"X-Poedit-Country: Turkey\n"
#: model.php:88
msgid "Activation"
msgstr "Etkinleştirme"
#: model.php:89
msgid "Grouping"
msgstr "Gruplama"
#: model.php:90
msgid "UI"
msgstr "UI"
#: model.php:91
msgid "Labels"
msgstr "Etiketler"
#: model.php:94
msgid "Enable Lightbox Functionality"
msgstr "Lightbox Fonksiyonelliğini Etkinleştir"
#: model.php:95
msgid "Enable on Home page"
msgstr "Anasayfa'da etkin"
#: model.php:96
msgid "Enable on Posts"
msgstr "Gönderi Sayfasında Etkin"
#: model.php:97
msgid "Enable on Pages"
msgstr "Sayfalarda Etkin"
#: model.php:98
msgid "Enable on Archive Pages (tags, categories, etc.)"
msgstr "Arşiv Sayfalarında Etkin (etiketler, kategoriler, gibi.)"
#: model.php:99
msgid "Enable backwards-compatibility with legacy lightbox links"
msgstr "Eski lightbox bağlantılar ile geri- uyumluluk etkinleştir"
#: model.php:100
msgid "Activate image attachment links"
msgstr "Resimlerdeki bağlantıları etkinleştir"
#: model.php:101
msgid "Validate links"
msgstr "Bağlantı kontrolü"
#: model.php:102
msgid "Group image links (for displaying as a slideshow)"
msgstr "Grup resimleri bağlantıları (slayt gösterisi olarak yayınlamak için)"
#: model.php:103
msgid "Group image links by Post (e.g. on pages with multiple posts)"
msgstr "Grup resimleri linki (örneğin, birden fazla ileti ile sayfalarda)"
#: model.php:104
msgid "Group gallery links separately"
msgstr "Grup galeri linkleri (ayrı ayrı)"
#: model.php:105
msgid "Theme"
msgstr "Tema"
#: model.php:106
msgid "Animate lightbox resizing"
msgstr "Lightbox yeniden boyutlandırma efekti"
#: model.php:107
msgid "Automatically Start Slideshow"
msgstr "Otomatik olarak Slayt gösterisi"
#: model.php:108
msgid "Slide Duration (Seconds)"
msgstr "Slayt Süresi (Saniye)"
#: model.php:109
msgid "Loop through images"
msgstr "Döngü görüntüleri üzerinden"
#: model.php:110
msgid "Overlay Opacity (0 - 1)"
msgstr ""
#: model.php:111
msgid "Enable caption"
msgstr "Balığı etkinleştir"
#: model.php:112
msgid "Use image URI as caption when link title not set"
msgstr ""
#: model.php:113
msgid "Enable description"
msgstr "Açıklama etkin"
#: model.php:114
msgid "Close link (for accessibility only, image used for button)"
msgstr ""
#: model.php:115
msgid "Loading indicator"
msgstr "Yükleniyor göstergesi"
#: model.php:116
msgid "Next Image link"
msgstr "Sonraki Görselin linki"
#: model.php:117
msgid "Previous Image link"
msgstr "Önceki Resme bağlantı"
#: model.php:118
msgid "Start Slideshow link"
msgstr "Slay gösterisine başlama linki"
#: model.php:119
msgid "Stop Slideshow link"
msgstr "Slayt gösterisini durdurma linki"
#: model.php:120
msgid "Image number prefix (e.g. <strong>Image</strong> x of y)"
msgstr "Görsel numaraları öneki (örn. <strong>Image</strong> x of y)"
#: model.php:121
msgid "Image number separator (e.g. Image x <strong>of</strong> y)"
msgstr "Görsel numaralarını ayırıcı (örn. Image x <strong>of</strong> y)"
#: model.php:728
msgid "Settings"
msgstr "Ayarlar"
#: model.php:729
msgid "Reset"
msgstr "Sıfırla"
#: model.php:730
msgid "Are you sure you want to reset your settings?"
msgstr "Ayarlarınızı sıfırlamak istediğinizden emin misiniz?"
#: model.php:746
msgid "You do not have sufficient permissions to manage plugins for this blog."
msgstr "Bu blogun eklentileri yönetmek için yeterli izinlere sahip değilsiniz."
#: model.php:796
msgid "Lightbox Settings"
msgstr "Lightbox Ayarları"

View File

@@ -0,0 +1,260 @@
# Copyright (C) 2015 Simple Lightbox
# This file is distributed under the same license as the Simple Lightbox package.
msgid ""
msgstr ""
"Project-Id-Version: Simple Lightbox 2.5.1\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/simple-lightbox\n"
"POT-Creation-Date: 2015-09-24 03:20:40+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2015-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
#: controller.php:240
msgid "Activation"
msgstr ""
#: controller.php:241
msgid "Grouping"
msgstr ""
#: controller.php:242
msgid "UI"
msgstr ""
#: controller.php:243
msgid "Labels"
msgstr ""
#: controller.php:246
msgid "Enable Lightbox Functionality"
msgstr ""
#: controller.php:247
msgid "Enable on Home page"
msgstr ""
#: controller.php:248
msgid "Enable on Single Posts"
msgstr ""
#: controller.php:249
msgid "Enable on Pages"
msgstr ""
#: controller.php:250
msgid "Enable on Archive Pages (tags, categories, etc.)"
msgstr ""
#: controller.php:251
msgid "Enable for Widgets"
msgstr ""
#: controller.php:252
msgid "Group items (for displaying as a slideshow)"
msgstr ""
#: controller.php:253
msgid "Group items by Post (e.g. on pages with multiple posts)"
msgstr ""
#: controller.php:254
msgid "Group gallery items separately"
msgstr ""
#: controller.php:255
msgid "Group widget items separately"
msgstr ""
#: controller.php:256
msgid "Resize lightbox to fit in window"
msgstr ""
#: controller.php:257
msgid "Enable animations"
msgstr ""
#: controller.php:258
msgid "Start Slideshow Automatically"
msgstr ""
#: controller.php:259
msgid "Slide Duration (Seconds)"
msgstr ""
#: controller.php:260
msgid "Loop through items"
msgstr ""
#: controller.php:261
msgid "Overlay Opacity (0 - 1)"
msgstr ""
#: controller.php:262
msgid "Enable default title"
msgstr ""
#: controller.php:263
msgid "Loading indicator"
msgstr ""
#: controller.php:264
msgid "Close button"
msgstr ""
#: controller.php:265
msgid "Next Item button"
msgstr ""
#: controller.php:266
msgid "Previous Item button"
msgstr ""
#: controller.php:267
msgid "Start Slideshow button"
msgstr ""
#: controller.php:268
msgid "Stop Slideshow button"
msgstr ""
#: controller.php:269
msgid "Slideshow status format"
msgstr ""
#: controller.php:319
msgid "Lightbox"
msgstr ""
#: controller.php:320
msgid "Lightbox Settings"
msgstr ""
#: controller.php:321
msgid "Settings"
msgstr ""
#: controller.php:330
msgid "Feedback & Support"
msgstr ""
#: controller.php:335
msgid "Reset"
msgstr ""
#: controller.php:336
msgid "Are you sure you want to reset settings?"
msgstr ""
#: controller.php:337
msgid "Settings have been reset"
msgstr ""
#: controller.php:338
msgid "Settings were not reset"
msgstr ""
#: controller.php:348
msgid ""
"<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>"
msgstr ""
#: controller.php:352
msgid "Get Support &amp; Provide Feedback"
msgstr ""
#: includes/class.admin.php:644
msgid "The settings have been reset"
msgstr ""
#: includes/class.admin.php:645
msgid ""
"<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."
msgstr ""
#: includes/class.admin.php:646 includes/class.admin_action.php:45
#: includes/class.admin_page.php:146
msgid "Access Denied"
msgstr ""
#: includes/class.fields.php:43
msgid "Default Element"
msgstr ""
#: includes/class.fields.php:55
msgid "Default Element (Closed Tag)"
msgstr ""
#: includes/class.fields.php:63
msgid "Default Input Element"
msgstr ""
#: includes/class.fields.php:71
msgid "Text Box"
msgstr ""
#: includes/class.fields.php:102
msgid "Hidden Field"
msgstr ""
#: includes/class.fields.php:108
msgid "Select tag"
msgstr ""
#: includes/class.fields.php:120
msgid "Inline wrapper"
msgstr ""
#: includes/class.option.php:113
msgid "Enabled"
msgstr ""
#: includes/class.option.php:113
msgid "Disabled"
msgstr ""
#: includes/class.options.php:222
msgid "Default"
msgstr ""
#: includes/class.themes.php:40
msgid "Theme"
msgstr ""
#: includes/class.themes.php:65
msgid "Baseline"
msgstr ""
#: includes/class.themes.php:76
msgid "Default (Light)"
msgstr ""
#: includes/class.themes.php:87
msgid "Default (Dark)"
msgstr ""
#. Plugin Name of the plugin/theme
msgid "Simple Lightbox"
msgstr ""
#. Plugin URI of the plugin/theme
msgid "http://archetyped.com/tools/simple-lightbox/"
msgstr ""
#. Description of the plugin/theme
msgid "The highly customizable lightbox for WordPress"
msgstr ""
#. Author of the plugin/theme
msgid "Archetyped"
msgstr ""
#. Author URI of the plugin/theme
msgid "http://archetyped.com"
msgstr ""

View File

@@ -0,0 +1,38 @@
<?php
/* Constants */
if ( ! defined( 'SLB_DEV' ) ) {
define( 'SLB_DEV', ( isset( $_REQUEST['slb_dev'] ) && ! ! $_REQUEST['slb_dev'] ) );
}
/* Class Management */
/**
* Class loading handler
* @param string $classname Class to load
*/
function slb_autoload( $classname ) {
$prefix = 'slb_';
$cls = strtolower( $classname );
// Remove prefix
if ( 0 !== strpos( $cls, $prefix ) ) {
return false;
}
// Format class for filename
$fn = 'class.' . substr( $cls, strlen( $prefix ) ) . '.php';
// Build path
$path = dirname( __FILE__ ) . '/includes/' . $fn;
// Load file
if ( is_readable( $path ) ) {
require $path;
}
}
spl_autoload_register( 'slb_autoload' );
/* Load Assets */
$path = dirname( __FILE__ ) . '/';
require_once $path . 'controller.php';
$GLOBALS['slb'] = new SLB_Lightbox();
require_once $path . 'functions.php';

View File

@@ -0,0 +1,48 @@
<?php
/**
* Simple Lightbox
*
* @package Simple Lightbox
* @author Archetyped <support@archetyped.com>
* @copyright 2022 Archetyped
*
* Plugin Name: Simple Lightbox
* Plugin URI: http://archetyped.com/tools/simple-lightbox/
* Description: The highly customizable lightbox for WordPress
* Version: 2.9.3
* Requires at least: 5.3
* Requires PHP: 5.6.20
* Text Domain: simple-lightbox
* Domain Path: /l10n
* Author: Archetyped
* Author URI: http://archetyped.com
* Support URI: https://github.com/archetyped/simple-lightbox/wiki/Feedback-&-Support
*/
require_once dirname( __FILE__ ) . '/includes/class-requirements-check.php';
/* @var array Plugin Requirements */
$slb_requirements = new SLB_Requirements_Check(
array(
'name' => __( 'Simple Lightbox', 'simple-lightbox' ),
'file' => __FILE__,
'uri' => array(
'reference' => 'https://github.com/archetyped/simple-lightbox/wiki/Requirements',
),
)
);
// Check requirements before initializing plugin.
if ( $slb_requirements->passes() ) {
/**
* Initialize SLB
*
* @return void
*/
function slb_init() {
require_once dirname( __FILE__ ) . '/load.php';
}
add_action( 'init', 'slb_init', 1 );
}
unset( $slb_requirements );

View File

@@ -0,0 +1,19 @@
{
"name": "simple-lightbox",
"version": "2.9.3",
"title": "Simple Lightbox",
"description": "The highly-customizable lightbox for WordPress",
"author": "Archetyped <support@archetyped.com>",
"license": "GPLv2",
"private": true,
"devDependencies": {
"grunt": "^1.5.3",
"grunt-contrib-jshint": "^3.2.0",
"grunt-contrib-uglify": "^5.2.2",
"grunt-contrib-watch": "^1.1.0",
"grunt-sass": "^3.1.0",
"jshint-stylish": "^2.2.1",
"load-grunt-tasks": "^5.1.0",
"sass": "^1.55.0"
}
}

View File

@@ -0,0 +1,58 @@
<?xml version="1.0"?>
<ruleset name="AR/WP/Plugin ruleset">
<description>Custom ruleset for AR/WP/Plugins</description>
<!-- Show progress in all reports. -->
<arg value="p"/>
<!-- A path to strip from the front of file paths inside reports. -->
<arg name="basepath" value="."/>
<arg name="colors"/>
<arg name="extensions" value="php"/>
<!-- Exclude the Composer Vendor directory. -->
<exclude-pattern>/vendor/*</exclude-pattern>
<!-- Exclude the Node Modules directory. -->
<exclude-pattern>/node_modules/*</exclude-pattern>
<!-- Set minimum supported WordPress version -->
<config name="minimum_supported_wp_version" value="5.3"/>
<!-- Check for PHP cross-version compatibility. -->
<config name="testVersion" value="5.6-"/>
<rule ref="PHPCompatibilityWP"/>
<!-- Include the WordPress standard. -->
<rule ref="WordPress-Extra">
<!-- Use PSR-4 file naming standard instead -->
<exclude name="WordPress.Files.FileName"/>
<!-- Allow short array syntax -->
<exclude name="Generic.Arrays.DisallowShortArraySyntax"/>
<!-- Allow global variable override -->
<exclude name="WordPress.WP.GlobalVariablesOverride.Prohibited"/>
<!-- Temporarily exclude rules -->
<!-- ** Audit-usage ** -->
<exclude name="Squiz.PHP.Eval.Discouraged"/>
<exclude name="Squiz.Scope.MethodScope.Missing"/>
<exclude name="PSR2.Classes.PropertyDeclaration.Underscore"/>
<exclude name="PSR2.Methods.MethodDeclaration.Underscore"/>
<exclude name="PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.Changed"/>
<exclude name="PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection"/>
<exclude name="WordPress.Security.NonceVerification.Missing"/>
<exclude name="WordPress.Security.NonceVerification.Recommended"/>
<!-- ** WordPress-Specific ** -->
<exclude name="WordPress.DB.PreparedSQL.InterpolatedNotPrepared"/>
<exclude name="WordPress.DB.PreparedSQL.NotPrepared"/>
<exclude name="WordPress.PHP.DontExtract.extract_extract"/>
<exclude name="WordPress.Security.EscapeOutput.OutputNotEscaped"/>
</rule>
<!-- Add in some extra rules from other standards. -->
<!-- <rule ref="Generic.CodeAnalysis.UnusedFunctionParameter"/> -->
<!-- <rule ref="Generic.Commenting.Todo"/> -->
<rule ref="Squiz.Commenting.FunctionComment.SpacingAfter"/>
</ruleset>

View File

@@ -0,0 +1,116 @@
=== Simple Lightbox ===
Contributors: Archetyped
Donate link: http://gum.co/slb-donate
License: GPLv2
Tags: lightbox, gallery, photography, images, theme, template, style
Requires at least: 5.3
Tested up to: 6.2
Requires PHP: 5.6.20
Stable tag: trunk
The highly customizable lightbox for WordPress
== Description ==
Simple Lightbox is a very simple and customizable lightbox that is easy to add to your WordPress website.
#### Features
Options for customizing the lightbox behavior are located in the **Appearance > Lightbox** admin menu (or just click the **Settings** link below the plugin's name when viewing the list of installed plugins)
* Automatically activate links (no manual coding required)
* Automatically resize lightbox to fit in window
* Customize lightbox with **themes**
* Mobile-optimized responsive themes included
* Customizable lightbox animations
* Infinitely customizable with **add-ons**
* Supports WordPress **image attachment** links
* Supports links in **widgets**
* Keyboard Navigation
* Display media metadata (caption, description, etc.) in lightbox
* Enable Lightbox depending on Page Type (Home, Pages, Archive, etc.)
* Group image links (play as a slideshow)
* Group image links by Post (separate slideshow for each post on page)
#### Usage
1. Insert links to images/image attachments into your posts/pages
**That's it! The image will be displayed in a lightbox automatically.**
* For more usage tips, go to [Simple Lightbox's official page](http://archetyped.com/tools/simple-lightbox/)
* See [Simple Lightbox's documentation](https://github.com/archetyped/simple-lightbox/wiki) for in-depth information on using and customizing SLB.
== Installation ==
1. Install and activate SLB
2. Verify that your site's theme uses the `wp_head()`, `wp_footer()`, & `the_content()` template tags (standard in any professional theme)
== Upgrade Notice ==
= 2.8.0 =
Faster link processing & other optimizations (WordPress 5.3+ & PHP 7.2+ required).
= 2.7.0 =
Fixes & improvements. PHP 5.4+ Required.
== Frequently Asked Questions ==
Get more information on [Simple Lightbox's official page](http://archetyped.com/tools/simple-lightbox/)
== Screenshots ==
1. Lightbox Customization Options
2. Light Theme
3. Dark Theme
== Changelog ==
= 2.9.3 =
* Hotfix: WordPress 6.1 `wp_rand()` bug (32-bit platforms) ([#974](https://github.com/archetyped/simple-lightbox/issues/974))
* Update: Confirm WordPress 6.1 compatibility
* Optimize: Media item cache key generation
* Optimize: Prune build tasks
= 2.9.2 =
* Optimize: Symbolic link handing for file/directory paths.
= 2.9.1 =
* Fix: Validate hook priority values (Let's Getz Prioritized)
= 2.9.0 =
* 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
= 2.8.1 =
* Update: PHP 5.6 Compatibility
* Add: PHPCS configuration
* Add: GitHub Issue templates
= 2.8.0 =
* Update: WordPress 5.3+ required.
* Update: PHP 7.2+ required.
* Optimize: Link detection up to 2x faster.
* Optimize: Options data handling.
* Optimize: Default title filtering.
* Optimize: Standardize media item data structure to avoid conflicts with third-party data.
* Optimize: Load only necessary media item properties in browser.
* Optimize: Filter all media items (instead of each individual item).
* Filter Removed: `media_item_properties` (single item).
* Filter Added: `media_items` (all items).
* Fix: `area` elements included in link detection (This is Jim's Area).
[See full changelog](https://github.com/archetyped/simple-lightbox/releases)

View File

@@ -0,0 +1,26 @@
if ( !!window.SLB && SLB.has_child('View.extend_template_tag_handler') ) {(function() {
SLB.View.extend_template_tag_handler('item', {
/**
* Render Item tag
* @param obj item Content Item
* @param obj tag Tag instance
* @param obj dfr Promise to be resolved when tag is rendered
*/
render: function(item, tag, dfr) {
// Build method name
var m = 'get_' + tag.get_prop();
// Get data
var ret = ( this.util.is_method(item, m) ) ? item[m]() : item.get_attribute(tag.get_prop(), '');
// Handle response
if ( this.util.is_promise(ret) ) {
ret.done(function(output) {
dfr.resolve(output);
});
} else {
dfr.resolve(ret);
}
return dfr.promise();
}
});
})();
}

View File

@@ -0,0 +1 @@
window.SLB&&SLB.has_child("View.extend_template_tag_handler")&&SLB.View.extend_template_tag_handler("item",{render:function(item,tag,dfr){var m="get_"+tag.get_prop(),m=this.util.is_method(item,m)?item[m]():item.get_attribute(tag.get_prop(),"");return this.util.is_promise(m)?m.done(function(output){dfr.resolve(output)}):dfr.resolve(m),dfr.promise()}});

View File

@@ -0,0 +1,105 @@
if ( !!window.SLB && SLB.has_child('View.extend_template_tag_handler') ) {(function() {
SLB.View.extend_template_tag_handler('ui', {
_hooks : function() {
this.on('dom_init', function(ev) {
this.call_attribute('events_init', ev);
});
},
events_init: function(ev) {
var v = ev.data.template.get_theme().get_viewer();
var thm = v.get_theme();
// Add event handlers
v.on('events-complete', function(ev, v) {
// Register event handlers
/* Close */
// Close button
thm.dom_get_tag('ui', 'close').click(function() {
return v.close();
});
/* Navigation */
thm.dom_get_tag('ui', 'nav_next').click(function() {
v.item_next();
});
thm.dom_get_tag('ui', 'nav_prev').click(function() {
v.item_prev();
});
/* Slideshow */
thm.dom_get_tag('ui', 'slideshow_control').click(function() {
v.slideshow_toggle();
});
});
v.on('slideshow-toggle', function(ev, v) {
// Update slideshow control tag
var tags = thm.get_tags('ui', 'slideshow_control');
if ( tags.length ) {
// Renderer
var render_tag = function(tag) {
tag.render(v.get_item()).done(function(r) {
r.tag.dom_get().html(r.output);
});
};
// Process tags
for ( var x = 0; x < tags.length; x++ ) {
render_tag(tags[x]);
}
}
});
},
render: function(item, tag, dfr) {
// Process content
var ret = this.handle_prop(tag.get_prop(), item, tag);
if ( this.util.is_promise(ret) ) {
ret.done(function(output) {
dfr.resolve(output);
});
} else {
dfr.resolve(ret);
}
return dfr.promise();
},
props: {
'slideshow_control': function(item) {
// Get slideshow status
var v = item.get_viewer();
var prop = ( v.slideshow_active() ) ? 'slideshow_stop' : 'slideshow_start';
return v.get_label(prop);
},
'group_status': function(item) {
// Handle single items
if ( item.get_group().is_single() ) {
return '';
}
// Handle groups with multiple items
var out = item.get_viewer().get_label('group_status');
var key,
ph,
delim = '%',
handlers = {
current: function() {
return item.get_group(true).get_pos() + 1;
},
total: function() {
return item.get_group().get_size();
}
};
// Parse placeholders
for ( key in handlers ) {
// Build placeholder
ph = delim + key + delim;
// Replace placeholder
if ( -1 !== out.indexOf(ph) ) {
out = out.replace(new RegExp(ph, 'ig'), handlers[key]());
}
}
return out;
}
}
});
})();}

View File

@@ -0,0 +1 @@
window.SLB&&SLB.has_child("View.extend_template_tag_handler")&&SLB.View.extend_template_tag_handler("ui",{_hooks:function(){this.on("dom_init",function(ev){this.call_attribute("events_init",ev)})},events_init:function(ev){var ev=ev.data.template.get_theme().get_viewer(),thm=ev.get_theme();ev.on("events-complete",function(ev,v){thm.dom_get_tag("ui","close").click(function(){return v.close()}),thm.dom_get_tag("ui","nav_next").click(function(){v.item_next()}),thm.dom_get_tag("ui","nav_prev").click(function(){v.item_prev()}),thm.dom_get_tag("ui","slideshow_control").click(function(){v.slideshow_toggle()})}),ev.on("slideshow-toggle",function(ev,v){var tags=thm.get_tags("ui","slideshow_control");if(tags.length)for(var x=0;x<tags.length;x++)tags[x].render(v.get_item()).done(function(r){r.tag.dom_get().html(r.output)})})},render:function(item,tag,dfr){item=this.handle_prop(tag.get_prop(),item,tag);return this.util.is_promise(item)?item.done(function(output){dfr.resolve(output)}):dfr.resolve(item),dfr.promise()},props:{slideshow_control:function(item){var item=item.get_viewer(),prop=item.slideshow_active()?"slideshow_stop":"slideshow_start";return item.get_label(prop)},group_status:function(item){if(item.get_group().is_single())return"";var key,ph,out=item.get_viewer().get_label("group_status"),handlers={current:function(){return item.get_group(!0).get_pos()+1},total:function(){return item.get_group().get_size()}};for(key in handlers)-1!==out.indexOf(ph="%"+key+"%")&&(out=out.replace(new RegExp(ph,"ig"),handlers[key]()));return out}}});

View File

@@ -0,0 +1 @@
#slb_viewer_wrap .slb_theme_slb_baseline .slb_viewer_layout,#slb_viewer_wrap .slb_theme_slb_baseline .slb_container{box-sizing:border-box}#slb_viewer_wrap .slb_theme_slb_baseline{position:absolute;top:0;left:0;width:100%;z-index:99999;text-align:center;line-height:0;color:#000;font-family:arial, verdana, sans-serif;font-size:12px}#slb_viewer_wrap .slb_theme_slb_baseline *{margin:0;padding:0;line-height:1.4em;text-align:left;vertical-align:baseline;white-space:normal;outline:none;border:0px;background:none;opacity:1;width:auto;height:auto;position:static;float:none;clear:none}[dir="rtl"] #slb_viewer_wrap .slb_theme_slb_baseline *{text-align:right}#slb_viewer_wrap .slb_theme_slb_baseline a img{border:none}#slb_viewer_wrap .slb_theme_slb_baseline .slb_viewer_layout{z-index:2;position:absolute;width:100%;text-align:center}#slb_viewer_wrap .slb_theme_slb_baseline .slb_viewer_overlay{position:fixed;top:0;left:0;z-index:1;min-height:105%;min-width:100%;background-color:#000}#slb_viewer_wrap .slb_theme_slb_baseline .slb_container{position:relative;display:inline-block;background-color:#fff;margin:0 auto;padding:16px}#slb_viewer_wrap .slb_theme_slb_baseline .slb_loading{background:url("../images/loading.gif") center center no-repeat;position:absolute;left:0%;top:0;width:100%;height:100%;min-width:31px;min-height:31px;text-align:center;line-height:0;display:none}#slb_viewer_wrap .slb_theme_slb_baseline .slb_template_tag_ui{cursor:pointer}#slb_viewer_wrap .slb_theme_slb_baseline .slb_content{position:relative}#slb_viewer_wrap .slb_theme_slb_baseline .slb_details{margin:0 auto;text-align:left}#slb_viewer_wrap .slb_theme_slb_baseline .slb_details .inner{display:table;width:100%}#slb_viewer_wrap .slb_theme_slb_baseline .slb_details .slb_data{display:table-caption}#slb_viewer_wrap .slb_theme_slb_baseline .slb_template_tag_item_content>*{width:100%;height:100%}#slb_viewer_wrap .slb_theme_slb_baseline.item_single .slb_group_status,#slb_viewer_wrap .slb_theme_slb_baseline.item_single .slb_nav,#slb_viewer_wrap .slb_theme_slb_baseline.item_single .slb_slideshow{display:none}#slb_viewer_wrap .slb_theme_slb_baseline.loading .slb_loading{display:block}#slb_viewer_wrap .slb_theme_slb_baseline.loading .slb_template_tag_ui{opacity:0}@media screen and (max-width: 480px){#slb_viewer_wrap .slb_theme_slb_baseline .slb_theme_slb_baseline,#slb_viewer_wrap .slb_theme_slb_baseline .slb_viewer_layout,#slb_viewer_wrap .slb_theme_slb_baseline .slb_container{min-height:100%;min-width:320px;width:100%}#slb_viewer_wrap .slb_theme_slb_baseline .slb_viewer_layout{display:block}#slb_viewer_wrap .slb_theme_slb_baseline .slb_container{max-width:100%;margin:0;padding:5px;position:absolute;top:0;left:0}#slb_viewer_wrap .slb_theme_slb_baseline .slb_container .slb_content img,#slb_viewer_wrap .slb_theme_slb_baseline .slb_container .slb_content iframe,#slb_viewer_wrap .slb_theme_slb_baseline .slb_container .slb_content object,#slb_viewer_wrap .slb_theme_slb_baseline .slb_container .slb_content .slb_inner{max-width:100%}#slb_viewer_wrap .slb_theme_slb_baseline .slb_container .slb_content img{height:auto}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,37 @@
if ( !!window.SLB && SLB.has_child('View.extend_theme') ) {(function() {
SLB.View.extend_theme('slb_baseline', {
'breakpoints': {
'small': 480,
'large': 1024
},
/**
* Theme offsets
* Reports additional space required for theme UI
* @return obj Offset width/height values
*/
'offset': function() {
var o;
if ( document.documentElement.clientWidth > this.get_breakpoint('small') ) {
o = {'width': 32, 'height': 55};
} else {
o = {'width': 0, 'height': 0};
}
return o;
},
/**
* Theme margins
* Reports additional margins used for positioning viewer
* @return obj Margin width/height values
*/
'margin': function() {
var m;
if ( document.documentElement.clientWidth > this.get_breakpoint('small') ) {
m = {'height': 50, 'width': 20};
} else {
m = {'height': 0, 'width': 0};
}
return m;
}
});
})();
}

View File

@@ -0,0 +1 @@
window.SLB&&SLB.has_child("View.extend_theme")&&SLB.View.extend_theme("slb_baseline",{breakpoints:{small:480,large:1024},offset:function(){var o=document.documentElement.clientWidth>this.get_breakpoint("small")?{width:32,height:55}:{width:0,height:0};return o},margin:function(){var m=document.documentElement.clientWidth>this.get_breakpoint("small")?{height:50,width:20}:{height:0,width:0};return m}});

View File

@@ -0,0 +1,49 @@
<div class="slb_container">
<div class="slb_content">
{{item.content}}
<div class="slb_nav">
<span class="slb_prev">
{{ui.nav_prev}}
</span>
<span class="slb_next">
{{ui.nav_next}}
</span>
</div>
<div class="slb_controls">
<span class="slb_close">
{{ui.close}}
</span>
<span class="slb_slideshow">
{{ui.slideshow_control}}
</span>
</div>
<div class="slb_loading">
{{ui.loading}}
</div>
</div>
<div class="slb_details">
<div class="inner">
<div class="slb_data">
<div class="slb_data_content">
<span class="slb_data_title">
{{item.title}}
</span>
<span class="slb_group_status">
{{ui.group_status}}
</span>
<div class="slb_data_desc">
{{item.description}}
</div>
</div>
</div>
<div class="slb_nav">
<span class="slb_prev">
{{ui.nav_prev}}
</span>
<span class="slb_next">
{{ui.nav_next}}
</span>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,176 @@
//Imports
//Variables
//Mixins
%box-sizing-border-box {
box-sizing: border-box;
}
#slb_viewer_wrap {
.slb_theme_slb_baseline {
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: 99999;
text-align: center;
line-height: 0;
color:#000;
font: {
family: arial, verdana, sans-serif;
size: 12px;
}
//Reset
* {
margin: 0;
padding: 0;
line-height: 1.4em;
text-align: left;
vertical-align: baseline;
white-space: normal;
outline: none;
border: 0px;
background: none;
opacity: 1;
width: auto;
height: auto;
position: static;
float: none;
clear: none;
[dir="rtl"] & {
text-align: right;
}
}
//General
a img {
border: none;
}
.slb_viewer_layout {
@extend %box-sizing-border-box;
z-index: 2;
position: absolute;
width: 100%;
text-align: center;
}
.slb_viewer_overlay {
position: fixed;
top: 0;
left: 0;
z-index: 1;
min-height: 105%;
min-width: 100%;
background-color: #000;
}
.slb_container {
@extend %box-sizing-border-box;
position: relative;
display: inline-block;
background-color: #fff;
margin: 0 auto;
padding: 16px;
}
.slb_loading {
background: url('../images/loading.gif') center center no-repeat;
position: absolute;
left: 0%;
top: 0;
width: 100%;
height: 100%;
min-width: 31px;
min-height: 31px;
text-align: center;
line-height: 0;
display: none;
}
.slb_template_tag_ui {
cursor: pointer;
}
//UI
//Content
.slb_content {
position: relative;
}
.slb_details {
margin: 0 auto;
text-align: left;
.inner {
display: table;
width: 100%;
}
.slb_data {
display: table-caption;
}
}
.slb_template_tag_item_content > * {
width: 100%;
height: 100%;
}
/* Single */
&.item_single {
.slb_group_status,
.slb_nav,
.slb_slideshow {
display: none;
}
}
/* Loading */
&.loading {
.slb_loading {
display: block;
}
.slb_template_tag_ui {
opacity: 0;
}
}
//Media
//Small screen
@media screen and (max-width: 480px) {
%vsizing {
min-height: 100%;
min-width: 320px;
width: 100%;
}
@extend %vsizing;
.slb_viewer_layout {
@extend %vsizing;
display: block;
}
.slb_container {
@extend %vsizing;
max-width: 100%;
margin: 0;
padding: 5px;
position: absolute;
top: 0;
left: 0;
.slb_content {
img, iframe, object, .slb_inner {
max-width: 100%;
}
img {
height: auto;
}
}
}
}
}
}

View File

@@ -0,0 +1 @@
#slb_viewer_wrap .slb_theme_slb_black a,#slb_viewer_wrap .slb_theme_slb_black a:hover{color:#fff}#slb_viewer_wrap .slb_theme_slb_black .slb_loading{background-image:url("../images/loading.gif")}#slb_viewer_wrap .slb_theme_slb_black .slb_container{background-color:#151515}#slb_viewer_wrap .slb_theme_slb_black .slb_content .slb_prev .slb_template_tag,[dir="rtl"] #slb_viewer_wrap .slb_theme_slb_black .slb_content .slb_next .slb_template_tag{background-image:url("../images/nav_prev.png")}#slb_viewer_wrap .slb_theme_slb_black .slb_content .slb_next .slb_template_tag,[dir="rtl"] #slb_viewer_wrap .slb_theme_slb_black .slb_content .slb_prev .slb_template_tag{background-image:url("../images/nav_next.png")}#slb_viewer_wrap .slb_theme_slb_black .slb_data_title{color:#e3e3e3}#slb_viewer_wrap .slb_theme_slb_black .slb_data_desc{color:#cecece}#slb_viewer_wrap .slb_theme_slb_black .slb_group_status{color:#999}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

View File

@@ -0,0 +1,40 @@
#slb_viewer_wrap {
.slb_theme_slb_black {
a,
a:hover {
color: #fff;
}
.slb_loading {
background-image: url('../images/loading.gif');
}
.slb_container {
background-color: #151515;
}
.slb_content {
.slb_prev .slb_template_tag,
[dir="rtl"] & .slb_next .slb_template_tag {
background-image: url('../images/nav_prev.png');
}
.slb_next .slb_template_tag,
[dir="rtl"] & .slb_prev .slb_template_tag {
background-image: url('../images/nav_next.png');
}
}
.slb_data_title {
color: #e3e3e3;
}
.slb_data_desc {
color: #cecece;
}
.slb_group_status {
color: #999;
}
}
}

View File

@@ -0,0 +1 @@
@font-face{font-family:'Yanone Kaffeesatz';font-style:normal;font-weight:400;src:url("../fonts/yanone-kaffeesatz-v9-latin-regular.eot");src:local("Yanone Kaffeesatz Regular"),local("YanoneKaffeesatz-Regular"),url("../fonts/yanone-kaffeesatz-v9-latin-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/yanone-kaffeesatz-v9-latin-regular.woff2") format("woff2"),url("../fonts/yanone-kaffeesatz-v9-latin-regular.woff") format("woff"),url("../fonts/yanone-kaffeesatz-v9-latin-regular.ttf") format("truetype"),url("../fonts/yanone-kaffeesatz-v9-latin-regular.svg#YanoneKaffeesatz") format("svg")}#slb_viewer_wrap .slb_theme_slb_default .slb_loading,#slb_viewer_wrap .slb_theme_slb_default .slb_controls .slb_template_tag_ui,#slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_prev .slb_template_tag,#slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_next .slb_template_tag{text-indent:100%;white-space:nowrap;overflow:hidden}#slb_viewer_wrap .slb_theme_slb_default a,#slb_viewer_wrap .slb_theme_slb_default a:hover{border-bottom:none;color:#000;text-decoration:underline}#slb_viewer_wrap .slb_theme_slb_default .slb_viewer_layout{top:20px}#slb_viewer_wrap .slb_theme_slb_default .slb_container{box-shadow:0 0 64px -40px #fcfcfc;border-radius:5px}#slb_viewer_wrap .slb_theme_slb_default .slb_template_tag_ui{transition:opacity .5s}#slb_viewer_wrap .slb_theme_slb_default .slb_controls{position:absolute;top:8px;right:8px;width:75%;text-align:right}[dir="rtl"] #slb_viewer_wrap .slb_theme_slb_default .slb_controls{right:inherit;left:0px}#slb_viewer_wrap .slb_theme_slb_default .slb_controls .slb_template_tag_ui{width:25px;height:25px;float:right;margin-left:2px;opacity:0.5}[dir="rtl"] #slb_viewer_wrap .slb_theme_slb_default .slb_controls .slb_template_tag_ui{float:left}#slb_viewer_wrap .slb_theme_slb_default .slb_controls .slb_template_tag_ui:hover{opacity:0.8}#slb_viewer_wrap .slb_theme_slb_default .slb_controls .slb_slideshow .slb_template_tag{background:url("../images/ui_slideshow_play.png") 0 0 no-repeat}#slb_viewer_wrap .slb_theme_slb_default .slb_controls .slb_close .slb_template_tag{background:url("../images/ui_close.png") 0 0 no-repeat}#slb_viewer_wrap .slb_theme_slb_default.slideshow_active .slb_controls .slb_slideshow .slb_template_tag{background:url("../images/ui_slideshow_pause.png") 0 0 no-repeat}#slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_prev .slb_template_tag,#slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_next .slb_template_tag{position:absolute;top:20%;height:71%;width:45%;min-width:25px;min-height:33px;background-repeat:no-repeat;opacity:0.5}#slb_viewer_wrap .slb_theme_slb_default .slb_content{min-height:58px;min-width:50px}#slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_prev .slb_template_tag,[dir="rtl"] #slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_next .slb_template_tag{left:4px;right:inherit;background-image:url("../images/nav_prev.png");background-position:left 45%}#slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_next .slb_template_tag,[dir="rtl"] #slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_prev .slb_template_tag{right:4px;left:inherit;background-image:url("../images/nav_next.png");background-position:right 45%}#slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_prev .slb_template_tag:hover,#slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_next .slb_template_tag:hover{opacity:1}#slb_viewer_wrap .slb_theme_slb_default .slb_details{line-height:1.4em;overflow:hidden;position:relative}#slb_viewer_wrap .slb_theme_slb_default .slb_details .slb_data{caption-side:bottom}#slb_viewer_wrap .slb_theme_slb_default .slb_details .slb_nav{display:none}#slb_viewer_wrap .slb_theme_slb_default .slb_data_title,#slb_viewer_wrap .slb_theme_slb_default .slb_group_status{font-family:'Yanone Kaffeesatz', arial, sans-serif;font-size:23px;margin-right:.2em;display:inline-block}[dir="rtl"] #slb_viewer_wrap .slb_theme_slb_default .slb_data_title,[dir="rtl"] #slb_viewer_wrap .slb_theme_slb_default .slb_group_status{margin-left:.2em;margin-right:0px}#slb_viewer_wrap .slb_theme_slb_default .slb_group_status{color:#777;font-style:italic;font-size:18.4px}#slb_viewer_wrap .slb_theme_slb_default .slb_data_desc{display:block;margin-top:0.5em}@media screen and (max-width: 480px){#slb_viewer_wrap .slb_theme_slb_default .slb_container{box-shadow:none;border-radius:0}#slb_viewer_wrap .slb_theme_slb_default .slb_controls{top:3px;right:3px}#slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_prev .slb_template_tag,#slb_viewer_wrap .slb_theme_slb_default .slb_content .slb_next .slb_template_tag{top:17%;height:79%}}

View File

@@ -0,0 +1,97 @@
Copyright (c) <dates>, <Copyright Holder> (<URL|email>),
with Reserved Font Name <Reserved Font Name>.
Copyright (c) <dates>, <additional Copyright Holder> (<URL|email>),
with Reserved Font Name <additional Reserved Font Name>.
Copyright (c) <dates>, <additional Copyright Holder> (<URL|email>).
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@@ -0,0 +1,407 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<defs >
<font id="YanoneKaffeesatz" horiz-adv-x="384" ><font-face
font-family="Yanone Kaffeesatz"
units-per-em="1000"
panose-1="0 0 5 0 0 0 0 0 0 0"
ascent="957"
descent="-200"
alphabetic="0" />
<glyph unicode=" " glyph-name="space" horiz-adv-x="158" />
<glyph unicode="!" glyph-name="exclam" horiz-adv-x="195" d="M45 683Q45 694 53 699T83 705T155 706L139 251Q138 233 131 226T109 216T59 213L45 683ZM68 -7T55 7T42 50Q42 74 57 91T97 108Q153 108 153 50Q153 26 138 10T97 -7Q68 -7 55 7Z" />
<glyph unicode="&quot;" glyph-name="quotedbl" horiz-adv-x="263" d="M42 607T37 667T31 760Q31 781 34 782Q41 786 65 786Q95 786 110 783Q110 740 103 665T89 586Q82 585 67 584T45 583Q42 607 37 667ZM166 590T160 659T153 761Q153 781 156 782Q163 786 187
786Q218 786 233 783Q233 742 225 666T212 586Q205 585 190 584T168 583Q166 590 160 659Z" />
<glyph unicode="#" glyph-name="numbersign" horiz-adv-x="418" d="M323 254H390Q390 213 388 202T374 190H320L316 123Q315 112 302 110T245 107L249 190H154L150 123Q149 112 136 110T79 107L83 190H28Q28 232 30 243T44 254H87L92 360H28Q28 402 30 413T44
424H96L99 487Q100 498 114 500T170 503L166 424H262L265 487Q266 498 280 500T336 503L332 424H390Q390 383 388 372T374 360H328L323 254ZM157 254H253L258 360H162L157 254Z" />
<glyph unicode="$" glyph-name="dollar" horiz-adv-x="418" d="M363 20T237 -4V-91Q237 -110 221 -116T164 -122V-7Q128 -5 103 2T66 19T53 37Q53 46 59 68T74 102Q111 72 181 72Q228 72 251 94T274 158Q274 186 262 208T219 264L107 377Q53 434 53 488Q53 542
86 574T181 615V704Q181 724 198 730T254 737V616Q304 613 330 602T357 581Q357 569 352 553T337 525Q326 533 299 539T239 546Q142 546 142 489Q142 469 152 452T185 409L306 288Q336 258 349 227T363 157Q363 20 237 -4Z" />
<glyph unicode="%" glyph-name="percent" horiz-adv-x="692" d="M162 -7T150 -3T127 8T116 23L520 709Q523 708 534 703T555 691T565 674Q565 667 397 382T166 -8Q162 -7 150 -3ZM132 339T104 353T60 408T45 525Q45 618 81 663T186 708Q233 708 261 692T304 636T319
526Q319 339 180 339Q132 339 104 353ZM212 402T228 430T245 525Q245 574 239 600T220 636T186 646Q154 646 138 619T122 523Q122 473 128 447T148 412T182 402Q212 402 228 430ZM460 -9T431 5T387 60T372 177Q372 270 408 315T514 360Q561 360 589 344T632 288T647
178Q647 -9 508 -9Q460 -9 431 5ZM539 52T555 80T572 175Q572 224 566 250T548 286T513 296Q481 296 465 269T448 173Q448 123 454 97T474 62T509 52Q539 52 555 80Z" />
<glyph unicode="&amp;" glyph-name="ampersand" horiz-adv-x="502" d="M458 70T488 55Q485 31 468 11T435 -10Q420 -10 362 54Q306 -10 212 -10Q27 -10 27 170Q27 229 59 278T139 358Q61 494 61 568Q61 636 104 671T228 706Q293 706 335 692T377 659Q377 644 372
627T357 600Q330 619 301 627T237 635Q193 635 170 620T146 558Q146 508 205 405T343 201Q351 241 351 291Q351 423 291 496Q332 504 405 504Q447 504 483 501Q483 499 484 490T485 472Q485 453 477 444T443 435L394 436Q411 405 420 374T429 281Q429 194 404 129Q458
70 488 55ZM272 66T309 115Q242 196 174 300Q110 254 110 168Q110 124 133 95T207 66Q272 66 309 115Z" />
<glyph unicode="&apos;" glyph-name="quotesingle" horiz-adv-x="141" d="M42 607T37 667T31 760Q31 781 34 782Q41 786 65 786Q95 786 110 783Q110 740 103 665T89 586Q82 585 67 584T45 583Q42 607 37 667Z" />
<glyph unicode="(" glyph-name="parenleft" horiz-adv-x="292" d="M212 -196T172 -135T99 43T65 320Q65 470 98 578T172 744T226 803Q246 803 255 792T271 752Q218 680 183 573T147 318Q147 211 166 119T213 -38T271 -136Q265 -166 256 -181T227 -196Q212 -196 172 -135Z" />
<glyph unicode=")" glyph-name="parenright" horiz-adv-x="292" d="M47 -196T37 -181T21 -136Q71 -70 108 44T145 318Q145 460 110 573T21 752Q28 781 37 792T66 803Q79 803 119 746T193 581T227 320Q227 168 194 52T120 -130T65 -196Q47 -196 37 -181Z" />
<glyph unicode="*" glyph-name="asterisk" horiz-adv-x="470" d="M199 667Q198 678 206 683T229 688Q256 688 278 677L258 519Q256 510 252 506T239 501Q231 501 221 504L199 667ZM269 469T269 478Q269 489 282 495L431 575Q441 566 447 551T454 521Q454 498 439
494L280 455Q269 469 269 478ZM16 503Q15 532 29 551T60 570Q63 570 69 568L199 487Q200 470 194 463T175 459L16 503ZM249 404Q246 410 246 414Q246 424 271 434L386 299Q390 294 390 288Q390 274 370 261T327 245L249 404ZM130 250T120 250Q107 250 92 266T66
300L187 423Q195 431 202 431Q212 431 224 415L136 259Q130 250 120 250Z" />
<glyph unicode="+" glyph-name="plus" horiz-adv-x="418" d="M384 317Q384 275 382 261T368 247H245V123Q245 112 231 110T174 107V247H34Q34 290 36 303T51 317H174V441Q174 452 188 454T245 457V317H384Z" />
<glyph unicode="," glyph-name="comma" horiz-adv-x="183" d="M43 -103T38 -80Q54 -53 59 -36T67 5Q43 21 43 54Q43 77 57 91T94 106Q148 106 148 47Q148 13 133 -21T99 -79T70 -103Q43 -103 38 -80Z" />
<glyph unicode="-" glyph-name="hyphen" horiz-adv-x="278" d="M37 290T39 303T54 317H241Q241 275 239 261T225 247H37Q37 290 39 303Z" />
<glyph unicode="." glyph-name="period" horiz-adv-x="183" d="M63 -6T50 8T37 51Q37 75 52 91T93 108Q148 108 148 51Q148 26 133 10T93 -6Q63 -6 50 8Z" />
<glyph unicode="/" glyph-name="slash" horiz-adv-x="334" d="M235 743Q238 754 243 758T265 763T324 765L99 0Q96 -10 91 -14T69 -19T10 -20L235 743Z" />
<glyph unicode="0" glyph-name="zero" horiz-adv-x="418" d="M107 -9T68 65T29 296Q29 448 72 524T211 600Q306 600 347 532T389 320Q389 151 348 71T206 -9Q107 -9 68 65ZM260 64T282 124T305 321Q305 428 285 478T215 529Q160 529 138 469T116 290Q116 206 124
157T153 86T208 64Q260 64 282 124Z" />
<glyph unicode="1" glyph-name="one" horiz-adv-x="418" d="M28 32T28 56Q28 67 72 71T173 76L184 517Q163 516 123 509T70 499Q58 519 58 552Q58 558 97 569T183 590T247 600Q263 600 270 595L257 76H331Q353 76 368 77T389 79Q389 32 387 16T373 0H30Q28 32 28 56Z" />
<glyph unicode="2" glyph-name="two" horiz-adv-x="418" d="M29 11T29 25Q29 45 33 56T54 96Q76 133 102 167T167 247Q227 317 255 362T283 454Q283 523 206 523Q166 523 125 513T59 488Q49 511 49 547Q49 559 73 571T139 592T226 600Q309 600 341 567T374 464Q374
403 342 349T243 217Q171 131 136 76H271Q304 76 341 79T389 83Q389 34 386 17T372 0H33Q29 11 29 25Z" />
<glyph unicode="3" glyph-name="three" horiz-adv-x="418" d="M99 -100T72 -86T44 -51Q44 -27 49 -11T55 9Q90 -23 153 -23Q218 -23 254 25T291 150Q291 209 248 231T132 254L130 305Q194 336 228 376T263 458Q263 486 248 504T191 523Q111 523 53 487Q43 507
43 546Q43 559 64 571T125 592T216 600Q290 600 322 568T355 482Q355 380 245 301Q305 295 341 259T378 152Q378 71 349 15T269 -71T152 -100Q99 -100 72 -86Z" />
<glyph unicode="4" glyph-name="four" horiz-adv-x="418" d="M235 131H54Q28 157 28 202Q28 227 65 311T152 478T237 592Q254 606 273 606Q297 606 319 595L316 206Q344 206 364 207T390 209Q391 208 392 202T394 186Q394 162 388 147T367 131H316V26Q316 12 313
7T295 1T235 0V131ZM235 206L247 495Q208 450 161 361T98 206H235Z" />
<glyph unicode="5" glyph-name="five" horiz-adv-x="418" d="M111 -100T85 -93T47 -77T34 -59Q34 -19 43 7Q78 -25 141 -25Q218 -25 256 33T294 178Q294 259 255 289T139 319Q100 319 42 306L71 600H377Q377 568 375 554T363 534T335 528Q291 528 229 529T140
532L124 381Q159 386 187 386Q380 386 380 194Q380 56 322 -22T148 -100Q111 -100 85 -93Z" />
<glyph unicode="6" glyph-name="six" horiz-adv-x="418" d="M313 439T352 392T391 245Q391 -8 202 -8Q128 -8 91 29T43 132T31 308Q31 702 259 702Q306 702 336 694T367 668Q367 636 359 611Q317 626 265 626Q119 626 108 367Q132 403 165 421T246 439Q313 439
352 392ZM255 64T283 110T312 228Q312 295 289 330T223 365Q157 365 108 290V284Q106 169 129 117T205 64Q255 64 283 110Z" />
<glyph unicode="7" glyph-name="seven" horiz-adv-x="418" d="M115 -88T98 -84T80 -66Q93 35 128 149T208 365T294 531Q220 527 67 527Q45 527 45 600H405Q303 403 242 238T163 -88Q115 -88 98 -84Z" />
<glyph unicode="8" glyph-name="eight" horiz-adv-x="418" d="M362 293T377 259T392 182Q392 99 347 46T218 -8Q123 -8 78 45T32 183Q32 245 63 295T146 376Q101 407 81 429Q60 448 50 475T39 534Q39 617 87 661T210 706Q387 706 387 544Q387 485 358 444T279
369Q317 339 333 323Q362 293 377 259ZM176 630T148 608T119 539Q119 489 159 457Q180 438 219 411Q313 469 313 541Q313 585 286 607T220 630Q176 630 148 608ZM259 69T286 100T313 183Q313 220 302 243T268 286Q248 307 210 333Q163 309 135 272T107 188Q107
133 135 101T213 69Q259 69 286 100Z" />
<glyph unicode="9" glyph-name="nine" horiz-adv-x="418" d="M288 609T324 580T373 486T389 297Q387 92 327 -6T138 -104Q98 -104 74 -96T49 -71Q49 -58 51 -43T56 -17Q89 -27 129 -27Q220 -27 261 39T310 229Q286 193 254 175T174 157Q109 157 69 209T28 358Q28
485 75 547T217 609Q288 609 324 580ZM263 231T312 306V310Q312 392 305 439T278 512T218 537Q165 537 136 495T107 368Q107 302 131 267T198 231Q263 231 312 306Z" />
<glyph unicode=":" glyph-name="colon" horiz-adv-x="183" d="M63 329T51 343T38 386Q38 410 53 426T93 443Q149 443 149 386Q149 361 134 345T93 329Q63 329 51 343ZM63 -6T51 8T38 51Q38 75 53 91T93 108Q149 108 149 51Q149 26 134 10T93 -6Q63 -6 51 8Z" />
<glyph unicode=";" glyph-name="semicolon" horiz-adv-x="183" d="M61 329T49 343T36 386Q36 410 51 426T91 443Q147 443 147 386Q147 361 132 345T91 329Q61 329 49 343ZM39 -103T34 -80Q50 -54 55 -37T63 5Q39 21 39 54Q39 77 53 91T90 106Q144 106 144 47Q144
13 129 -21T95 -79T66 -103Q39 -103 34 -80Z" />
<glyph unicode="&lt;" glyph-name="less" horiz-adv-x="400" d="M318 96T297 103L52 211Q39 234 39 258Q39 289 65 302L329 430Q342 418 349 404T357 377Q357 359 343 353L144 255L360 159Q359 134 348 115T324 96Q318 96 297 103Z" />
<glyph unicode="=" glyph-name="equal" horiz-adv-x="418" d="M34 382T36 396T51 410H384Q384 367 382 353T368 339H34Q34 382 36 396ZM34 197T36 210T51 224H384Q384 182 382 168T368 154H34Q34 197 36 210Z" />
<glyph unicode="&gt;" glyph-name="greater" horiz-adv-x="400" d="M62 97T55 112T46 139Q46 157 60 164L260 261L43 358Q44 383 56 401T80 420Q90 420 107 413L351 305Q364 285 364 258Q364 227 338 214L74 85Q62 97 55 112Z" />
<glyph unicode="?" glyph-name="question" horiz-adv-x="295" d="M92 210T89 219T82 244T79 278Q79 319 97 351Q109 374 124 396T143 424Q171 465 184 491T197 552Q197 629 115 629Q66 629 31 603Q19 639 19 667Q19 684 58 697T144 710Q209 710 246 675T283 570Q283
512 264 473T209 384Q182 350 172 330Q160 309 160 283Q160 271 165 243Q167 234 168 227T166 217Q156 206 120 206Q109 206 93 208Q92 210 89 219ZM100 -6T88 8T75 51Q75 75 90 91T130 108Q186 108 186 51Q186 26 171 10T130 -6Q100 -6 88 8Z" />
<glyph unicode="@" glyph-name="at" horiz-adv-x="738" d="M442 -112T496 -101T602 -68Q623 -100 623 -126Q623 -141 592 -156T505 -180T375 -190Q268 -190 199 -159T89 -29T47 264Q47 479 139 581T394 683Q545 683 619 608T693 359Q693 145 644 74T533 2Q498
2 471 25Q459 15 429 8T358 1Q319 1 293 12T252 57T237 151Q237 318 365 318Q403 318 423 307Q423 313 424 330T425 368Q426 401 411 413T364 426Q333 426 310 421T264 402Q256 419 256 448Q256 459 265 468Q281 479 312 486T391 494Q448 494 475 468T501 378L496
177Q494 104 491 78Q508 72 524 72Q545 72 564 98T597 184T610 338Q610 441 590 500T523 585T393 611Q303 611 246 578T159 466T129 253Q129 106 155 27T233 -82T369 -112Q442 -112 496 -101ZM423 258Q402 261 388 261Q352 261 333 236T314 147Q314 98 327 80T368
62Q390 62 404 74T419 114L423 258Z" />
<glyph unicode="A" glyph-name="A" horiz-adv-x="437" d="M433 6T426 2T396 -2Q369 -2 348 0L306 178H132L93 14Q90 5 84 2T55 -2Q34 -2 5 1L184 689Q187 703 214 703Q237 703 252 700L431 15Q433 6 426 2ZM288 251L254 395Q225 517 219 588Q208 499 183 395L149
251H288Z" />
<glyph unicode="B" glyph-name="B" horiz-adv-x="377" d="M44 681Q44 691 49 695T70 700H169Q337 700 337 546Q337 470 308 430T242 384Q289 381 324 350T360 238Q360 118 307 59T170 0H44V681ZM175 414Q209 414 229 443T249 530Q249 629 175 629H125V414H175ZM171
71Q212 71 238 110T265 231Q265 280 254 305T223 337T172 345H125V71H171Z" />
<glyph unicode="C" glyph-name="C" horiz-adv-x="341" d="M142 -10T107 13T51 109T30 321Q30 480 59 566T130 681T227 710Q277 710 299 694T321 655Q321 628 308 606Q277 631 243 631Q206 631 178 608T133 517T115 325Q115 227 127 173T161 99T215 79Q243 79 268
88T308 111Q320 85 320 62Q320 32 285 11T196 -10Q142 -10 107 13Z" />
<glyph unicode="D" glyph-name="D" horiz-adv-x="388" d="M44 681Q44 691 50 695T71 700H169Q237 700 279 672T342 575T364 386Q364 242 342 158T276 37T169 0H44V681ZM171 77Q201 77 223 100T259 193T273 394Q273 485 262 535T229 606T171 626H125V77H171Z" />
<glyph unicode="E" glyph-name="E" horiz-adv-x="320" d="M125 73H297Q297 44 297 26T293 4T281 0H45V684Q45 688 48 694T61 700H301Q301 672 301 654T297 632T286 627H125V418H276Q276 391 276 373T272 350T261 344H125V73Z" />
<glyph unicode="F" glyph-name="F" horiz-adv-x="313" d="M301 700Q301 672 301 656T297 635T286 631H125V418H276Q276 391 276 373T272 350T261 344H125V16Q125 11 123 6T110 0H45V684Q45 688 48 694T61 700H301Z" />
<glyph unicode="G" glyph-name="G" horiz-adv-x="386" d="M148 -10T108 18T49 121T30 334Q30 485 55 567T127 679T245 710Q293 710 322 695T352 659Q352 635 341 607Q327 618 306 624T261 631Q208 631 177 605T131 515T116 340Q116 225 128 167T162 89T220 69Q244
69 259 77T280 94V343H205V394Q205 410 224 410H355V35Q301 -10 218 -10Q148 -10 108 18Z" />
<glyph unicode="H" glyph-name="H" horiz-adv-x="410" d="M365 7T362 4T339 1T285 0V339H125V16Q125 7 122 4T98 1T44 0V684Q44 693 47 696T71 699T125 700V415H285V684Q285 693 288 696T311 699T365 700V16Q365 7 362 4Z" />
<glyph unicode="I" glyph-name="I" horiz-adv-x="169" d="M44 663Q44 683 48 690T66 698T126 700V16Q126 7 122 4T98 1T44 0V663Z" />
<glyph unicode="J" glyph-name="J" horiz-adv-x="300" d="M63 -9T39 8T14 50Q14 64 17 73T26 96Q41 82 63 73T109 63Q138 63 151 76T169 114T174 183V663Q174 684 177 690T195 698T256 700V165Q256 82 226 37T119 -9Q63 -9 39 8Z" />
<glyph unicode="K" glyph-name="K" horiz-adv-x="389" d="M371 701T371 686Q371 682 368 677L206 398Q326 307 367 18Q368 6 362 2T334 -2Q308 -2 278 1Q254 128 229 201T164 318Q151 333 124 345V16Q124 7 121 4T97 1T42 0V684Q42 693 45 696T69 699T124 700V398L284
695Q313 701 335 701Q371 701 371 686Z" />
<glyph unicode="L" glyph-name="L" horiz-adv-x="314" d="M44 677Q44 690 48 694T66 699T125 700V76H297V16Q297 7 293 4T281 0H44V677Z" />
<glyph unicode="M" glyph-name="M" horiz-adv-x="489" d="M445 700V16Q445 7 442 4T418 1T363 0L366 245Q368 310 375 410T385 546L368 486Q329 342 319 315L266 161Q263 153 255 153H220L168 315Q155 354 104 541L103 540Q106 509 113 412T121 249L123 16Q123
7 119 4T95 1T44 0V684Q44 694 48 697T60 700H118L214 396Q225 362 234 330T246 285Q249 297 257 329T275 393L364 684Q367 693 370 696T380 700H445Z" />
<glyph unicode="N" glyph-name="N" horiz-adv-x="444" d="M320 693T324 696T348 699T401 700V16Q401 0 384 0H324L209 275Q185 339 114 560Q118 517 121 416T124 259V16Q124 7 121 4T97 1T44 0V684Q44 700 60 700H121L234 430Q247 395 308 211Q312 199 330 146V149Q325
188 323 290T320 448V684Q320 693 324 696Z" />
<glyph unicode="O" glyph-name="O" horiz-adv-x="429" d="M143 -10T105 21T48 131T30 354Q30 486 50 564T113 676T222 710Q288 710 326 678T381 569T399 357Q399 220 380 140T319 25T211 -10Q143 -10 105 21ZM251 73T272 101T302 190T312 355Q312 459 304 517T276
601T220 627Q184 627 163 599T131 507T121 334Q121 238 129 182T158 99T214 73Q251 73 272 101Z" />
<glyph unicode="P" glyph-name="P" horiz-adv-x="361" d="M254 700T298 653T343 503Q343 387 293 336T160 284H124V16Q124 7 121 4T97 1T44 0V684Q44 693 47 696T60 700H159Q254 700 298 653ZM212 359T233 394T254 512Q254 569 236 599T174 629H124V359H168Q212
359 233 394Z" />
<glyph unicode="Q" glyph-name="Q" horiz-adv-x="429" d="M404 -61T407 -74T410 -97Q410 -118 382 -127T320 -137Q269 -137 239 -107T190 -9Q131 -5 97 29T46 141T30 354Q30 486 50 564T113 676T222 710Q288 710 326 678T381 569T399 357Q399 194 371 111T282
2Q288 -37 300 -53T335 -70Q372 -70 398 -53Q404 -61 407 -74ZM121 238T129 182T158 99T214 73Q251 73 272 101T302 190T312 355Q312 459 304 517T276 601T220 627Q184 627 163 599T131 507T121 334Q121 238 129 182Z" />
<glyph unicode="R" glyph-name="R" horiz-adv-x="372" d="M288 264T315 192T350 18Q350 6 343 2T309 -2Q298 -2 262 0Q255 110 231 179T180 285Q173 284 160 284H124V16Q124 7 121 4T97 1T44 0V684Q44 688 47 694T60 700H159Q254 700 298 653T343 503Q343 356
256 306Q288 264 315 192ZM168 359Q212 359 233 393T254 506Q254 567 236 598T174 629H124V359H168Z" />
<glyph unicode="S" glyph-name="S" horiz-adv-x="358" d="M94 -10T60 8T25 49Q25 62 30 78T46 107Q85 72 149 72Q248 72 248 174Q248 210 235 238T189 306L89 423Q55 464 41 497T26 567Q26 632 71 671T198 710Q265 710 297 697T329 660Q329 635 309 614Q298 623
271 630T211 638Q166 638 140 620T113 569Q113 543 124 522T159 470L268 347Q306 302 320 264T335 178Q335 93 294 42T157 -10Q94 -10 60 8Z" />
<glyph unicode="T" glyph-name="T" horiz-adv-x="373" d="M365 700V641Q365 631 361 628T348 624H225V16Q225 7 221 4T197 1T144 0V624H8V684Q8 700 25 700H365Z" />
<glyph unicode="U" glyph-name="U" horiz-adv-x="437" d="M148 -10T109 18T57 91T44 205V683Q44 692 47 695T71 699T127 700V202Q127 133 146 99T224 65Q249 65 274 70T312 82V683Q312 692 316 695T340 699T394 700V26Q373 12 326 1T224 -10Q148 -10 109 18Z" />
<glyph unicode="V" glyph-name="V" horiz-adv-x="420" d="M176 -7T165 8T146 51Q122 153 73 377T7 676Q5 686 5 689Q5 695 9 697T24 700H90L174 312Q187 246 207 117L214 69Q232 215 250 312L325 676Q328 689 332 694T346 700H416L262 -3Q233 -7 194 -7Q176 -7 165 8Z" />
<glyph unicode="W" glyph-name="W" horiz-adv-x="654" d="M650 700L518 -3Q509 -4 492 -6T451 -8Q419 -8 408 49L356 276Q345 334 325 503Q306 341 296 277L241 -3Q208 -7 167 -7Q140 -7 126 54Q105 158 63 380T7 676Q6 680 6 687Q6 694 10 697T24 700H90L163
311Q178 220 193 88H198Q203 187 224 311L286 642Q289 656 292 661T307 666H364L435 311Q450 232 462 118L465 88H471Q482 220 496 311L561 676Q563 689 566 694T581 700H650Z" />
<glyph unicode="X" glyph-name="X" horiz-adv-x="424" d="M414 9T414 7Q414 0 403 0H315L261 135Q233 206 207 283Q178 198 151 135L97 10Q93 4 90 2T79 0H9L162 361L36 686Q33 694 37 696T66 699T131 700L172 586Q205 491 222 436Q248 520 271 586L310 687Q312
694 316 696T341 699T397 700L268 368L412 13Q414 9 414 7Z" />
<glyph unicode="Y" glyph-name="Y" horiz-adv-x="364" d="M225 16Q225 7 222 4T198 1T144 0V285L6 687Q4 694 8 696T35 699T97 700L137 563Q152 516 168 446T187 353Q189 375 206 445T238 563L273 685Q275 693 279 696T304 699T360 700L225 290V16Z" />
<glyph unicode="Z" glyph-name="Z" horiz-adv-x="385" d="M19 11T19 31Q19 50 27 67L267 628H80Q49 628 37 625V683Q37 691 41 695T54 700H352Q360 689 360 674Q360 656 352 637L108 72H302Q343 72 361 80V16Q361 0 345 0H32Q19 11 19 31Z" />
<glyph unicode="[" glyph-name="bracketleft" horiz-adv-x="386" d="M122 796Q122 808 125 812T140 819T184 821H377Q377 785 376 771T369 752T350 747H203V-123H376Q376 -161 374 -176T367 -195T349 -199H122V796Z" />
<glyph unicode="\" glyph-name="backslash" horiz-adv-x="329" d="M12 743L10 752Q10 761 25 763T91 765L317 -10L319 -18Q319 -26 304 -28T237 -30L12 743Z" />
<glyph unicode="]" glyph-name="bracketright" horiz-adv-x="386" d="M9 -164T10 -150T17 -131T36 -126H183V746H10Q10 784 12 799T19 818T37 822H264V-175Q264 -187 261 -191T246 -198T202 -200H9Q9 -164 10 -150Z" />
<glyph unicode="^" glyph-name="asciicircum" horiz-adv-x="430" d="M69 208T59 220T48 249L220 398L366 270Q380 259 380 244Q380 230 369 219T341 206L212 294L110 218Q94 208 85 208Q69 208 59 220Z" />
<glyph unicode="_" glyph-name="underscore" horiz-adv-x="377" d="M14 -66T16 -52T30 -38H364Q364 -81 362 -95T347 -109H14Q14 -66 16 -52Z" />
<glyph unicode="`" glyph-name="grave" horiz-adv-x="269" d="M162 568T111 604T49 655Q53 677 63 696T86 716Q93 716 141 675T220 598Q219 595 215 584T204 563T189 553Q162 568 111 604Z" />
<glyph unicode="a" glyph-name="a" horiz-adv-x="354" d="M102 -10T66 20T29 142Q29 237 65 271T163 306Q210 306 236 293V372Q236 406 221 419T174 432Q138 432 101 426T41 409Q30 430 30 456Q30 476 41 483Q56 493 99 501T194 510Q259 510 288 482T317 388V335Q317
115 311 24Q287 9 250 0T166 -10Q102 -10 66 20ZM196 58T211 63T233 74Q236 108 236 236Q217 246 189 246Q153 246 133 225T113 144Q113 93 129 76T180 58Q196 58 211 63Z" />
<glyph unicode="b" glyph-name="b" horiz-adv-x="385" d="M84 -10T48 20V698Q48 717 54 724T75 733T128 735V475Q173 510 235 510Q297 510 327 465T358 313Q358 120 303 55T164 -10Q84 -10 48 20ZM212 61T240 110T268 296Q268 374 251 405T198 437Q156 437 128
409V75Q144 61 175 61Q212 61 240 110Z" />
<glyph unicode="c" glyph-name="c" horiz-adv-x="313" d="M128 -10T96 9T48 83T31 239Q31 400 81 455T210 510Q246 510 270 497T294 465Q294 442 285 420Q251 439 214 439Q170 439 142 399T114 238Q114 169 123 131T152 77T204 62Q227 62 248 68T284 85Q292 56
292 41Q292 20 260 5T180 -10Q128 -10 96 9Z" />
<glyph unicode="d" glyph-name="d" horiz-adv-x="381" d="M142 -10T108 7T52 77T31 232Q31 373 73 441T184 510Q230 510 256 490V698Q256 717 262 724T284 733T337 735V20Q273 -10 193 -10Q142 -10 108 7ZM234 62T256 77V427Q239 440 210 440Q120 440 120 241Q120
168 129 129T154 76T196 62Q234 62 256 77Z" />
<glyph unicode="e" glyph-name="e" horiz-adv-x="361" d="M267 68T321 100Q328 78 328 45Q328 22 288 6T190 -10Q139 -10 105 9T50 79T30 224Q30 341 54 404T117 488T207 510Q334 510 334 350Q334 270 323 220Q279 211 221 208T113 204Q115 150 125 121T155 80T207
68Q267 68 321 100ZM162 439T140 402T114 268Q213 268 251 280Q256 303 256 340Q255 396 243 417T198 439Q162 439 140 402Z" />
<glyph unicode="f" glyph-name="f" horiz-adv-x="254" d="M82 432H13Q13 459 14 475T18 496T33 500H82V561Q82 665 129 702T249 739Q294 739 318 728T342 698Q342 675 333 654Q304 666 262 666Q215 666 189 646T162 567V500H252Q252 473 251 457T247 436T235 432H162V16Q162
11 159 6T145 0H82V432Z" />
<glyph unicode="g" glyph-name="g" horiz-adv-x="394" d="M308 72T341 47T375 -34Q375 -104 326 -150T183 -197Q91 -197 57 -167T23 -88Q23 -54 44 -23T100 33Q37 50 38 87Q38 127 101 177Q39 217 39 327Q39 422 83 466T206 510Q229 510 256 502H375Q383 488 383
464Q383 433 355 433Q342 433 319 438Q357 400 357 329Q357 246 318 200T195 154Q169 154 150 158Q123 131 123 114Q123 102 148 97T242 82Q308 72 341 47ZM167 451T146 422T124 329Q124 271 139 244T200 216Q239 216 257 249T276 348Q276 402 258 426T203 451Q167
451 146 422ZM240 -123T266 -99T293 -45Q293 -22 283 -10T249 9T180 19L160 21Q137 3 122 -21T106 -69Q106 -96 124 -109T190 -123Q240 -123 266 -99Z" />
<glyph unicode="h" glyph-name="h" horiz-adv-x="380" d="M45 698Q45 717 51 724T72 733T125 735V471Q147 490 177 500T238 510Q299 510 320 479T342 378V16Q342 7 338 4T313 1T260 0V356Q260 394 248 414T201 435Q182 435 162 429T125 408V16Q125 7 122 4T99
1T45 0V698Z" />
<glyph unicode="i" glyph-name="i" horiz-adv-x="175" d="M47 463Q47 482 53 489T75 498T128 500V16Q128 7 125 4T101 1T47 0V463ZM300 570T300 628Q300 692 346 692Q368 692 377 679T386 634Q386 604 374 587T340 570Q300 570 300 628Z" />
<glyph unicode="j" glyph-name="j" horiz-adv-x="184" d="M-50 -196T-76 -182T-103 -143Q-103 -117 -91 -102Q-53 -122 -6 -122Q31 -122 42 -101T54 -24V463Q54 482 60 489T81 498T134 500V-36Q134 -111 106 -153T4 -196Q-50 -196 -76 -182ZM306 570T306 628Q306
692 352 692Q374 692 383 679T392 634Q392 604 380 587T346 570Q306 570 306 628Z" />
<glyph unicode="k" glyph-name="k" horiz-adv-x="376" d="M46 698Q46 717 52 724T74 733T127 735V464Q153 485 187 497T253 510Q338 510 338 424Q338 369 312 331T254 269Q293 252 320 209T354 100Q355 90 355 67Q355 43 352 16Q351 7 347 4T321 1T261 0Q265 29
265 62Q265 93 260 123Q251 175 231 201T183 227Q176 227 172 226Q161 224 146 217T127 207V16Q127 7 124 4T101 1T46 0V698ZM249 314T249 397Q249 437 212 437Q166 437 127 389V265Q249 314 249 397Z" />
<glyph unicode="l" glyph-name="l" horiz-adv-x="173" d="M46 698Q46 717 52 724T74 733T127 735V16Q127 7 123 4T100 1T46 0V698Z" />
<glyph unicode="m" glyph-name="m" horiz-adv-x="564" d="M458 510T482 494T515 449T523 369V16Q523 7 519 4T495 1T442 0V370Q442 409 433 424T393 439Q356 439 325 420V16Q325 7 322 4T299 1T246 0H245V372Q245 400 242 413T229 433T195 440Q159 440 127 422V16Q127
7 123 4T99 1T46 0V477Q119 510 197 510Q259 510 288 479Q313 493 346 501T410 510Q458 510 482 494Z" />
<glyph unicode="n" glyph-name="n" horiz-adv-x="383" d="M45 476Q76 490 121 500T204 510Q282 510 313 480T344 376V16Q344 7 340 4T316 1T261 0V352Q261 402 249 421T201 440Q183 440 162 436T126 422V16Q126 7 122 4T98 1T45 0V476Z" />
<glyph unicode="o" glyph-name="o" horiz-adv-x="376" d="M128 -10T95 9T45 84T27 250Q27 510 194 510Q249 510 282 488T332 409T349 252Q349 116 308 53T184 -10Q128 -10 95 9ZM222 58T241 100T261 252Q261 330 254 371T231 427T191 442Q154 442 135 400T115
248Q115 168 123 127T146 72T186 58Q222 58 241 100Z" />
<glyph unicode="p" glyph-name="p" horiz-adv-x="382" d="M63 -197T55 -190T46 -162V470Q109 510 192 510Q272 510 313 464T355 302Q355 121 313 56T206 -10Q180 -10 160 -2T127 18V-191Q108 -197 85 -197Q63 -197 55 -190ZM266 62T266 293Q266 352 258 384T233
428T188 440Q154 440 127 421V95Q147 62 181 62Q266 62 266 293Z" />
<glyph unicode="q" glyph-name="q" horiz-adv-x="387" d="M276 -198T261 -195V34Q231 -10 165 -10Q107 -10 69 38T30 218Q30 373 86 441T235 510Q269 510 294 503T342 479V-163Q342 -186 334 -191T294 -198Q276 -198 261 -195ZM215 60T233 73T261 112V426Q243
440 215 440Q169 440 145 389T121 220Q121 127 141 94T195 61Q215 60 233 73Z" />
<glyph unicode="r" glyph-name="r" horiz-adv-x="263" d="M45 465Q109 510 181 510Q218 510 234 500T251 468Q251 443 242 421Q221 433 194 433Q155 433 128 410L127 16Q127 7 123 4T99 1T45 0V465Z" />
<glyph unicode="s" glyph-name="s" horiz-adv-x="346" d="M97 -10T64 3T30 40Q30 64 45 87Q86 63 144 63Q183 63 204 78T226 124Q226 146 217 165T186 203L89 286Q31 333 31 392Q31 447 72 478T195 510Q263 510 291 492T320 454Q320 445 315 434T303 413Q259 440
204 440Q168 440 147 427T125 391Q125 376 133 363T165 329L258 254Q291 222 304 194T318 129Q318 63 274 27T152 -10Q97 -10 64 3Z" />
<glyph unicode="t" glyph-name="t" horiz-adv-x="292" d="M141 -10T121 7T94 56T87 139V431H19Q19 458 20 474T24 495T36 500H87V652Q87 666 93 671T114 678T167 680V500H271Q271 473 270 456T266 435T254 431H167V139Q167 98 173 79T204 59Q220 59 232 62T262
74Q268 54 268 34Q268 10 243 0T182 -10Q141 -10 121 7Z" />
<glyph unicode="u" glyph-name="u" horiz-adv-x="389" d="M135 -10T103 8T58 61T45 156V484Q45 493 48 496T72 499T128 500V149Q128 98 141 79T196 60Q236 60 263 79V484Q263 493 267 496T290 499T344 500V26Q314 10 274 0T194 -10Q135 -10 103 8Z" />
<glyph unicode="v" glyph-name="v" horiz-adv-x="344" d="M143 -6T135 6T121 43L19 475Q17 485 17 487Q17 494 23 496T51 499T104 500L136 339Q150 274 161 193T176 86H178Q181 111 192 192T216 340L243 482Q245 492 249 495T273 499T328 500L213 -3Q198 -6 156
-6Q143 -6 135 6Z" />
<glyph unicode="w" glyph-name="w" horiz-adv-x="541" d="M448 492T452 495T476 499T526 500Q510 421 466 209T418 -3Q415 -4 401 -5T366 -6Q354 -6 342 7T324 46L311 114Q288 220 274 363Q256 205 237 113L214 -3Q207 -4 188 -5T147 -6Q123 -6 113 43Q95 120
61 276T16 483Q14 492 19 495T46 499T103 500L134 337Q146 267 156 191T169 93H175Q194 229 203 278L235 469Q237 480 241 483T261 486H314L353 276Q364 228 373 170T384 93H389Q393 140 402 210T421 337L446 482Q448 492 452 495Z" />
<glyph unicode="x" glyph-name="x" horiz-adv-x="411" d="M395 9T395 8Q395 3 384 2T337 0H302L265 66Q243 107 199 201Q164 121 136 65L107 16Q103 8 96 5T68 1T15 0L157 260L35 487Q32 494 35 496T60 499T120 500L157 431Q185 379 211 317Q244 390 266 432L297
486Q300 494 305 496T330 499T386 500L258 267L391 19Q395 9 395 8Z" />
<glyph unicode="y" glyph-name="y" horiz-adv-x="357" d="M-4 -193T-4 -154Q-4 -142 -1 -130T8 -109Q18 -116 35 -120T71 -124Q97 -124 115 -100T144 -16L24 478Q22 486 22 489Q22 497 35 498T102 500L157 260Q167 211 174 156T184 83Q186 99 192 154T208 261L253
477Q255 490 259 494T279 499T340 500L217 -27Q202 -91 184 -127T140 -178T77 -193Q-4 -193 -4 -154Z" />
<glyph unicode="z" glyph-name="z" horiz-adv-x="335" d="M33 1T30 5T24 19T21 40Q21 58 28 70L223 432H120Q63 432 28 427Q25 444 25 465Q25 483 31 491T51 500H306Q307 499 310 493T314 475Q314 456 305 436L115 75H204Q270 75 310 85Q312 77 312 50Q312 23
306 12T280 0H34Q33 1 30 5Z" />
<glyph unicode="{" glyph-name="braceleft" horiz-adv-x="277" d="M154 -150T122 -117T89 -15Q89 26 96 80Q97 89 100 120T103 182Q103 220 90 237T48 260Q41 275 41 293Q41 321 58 333Q74 343 83 352T97 378T103 427Q103 458 100 492T96 536Q89 590 89 626Q89
686 130 714T244 744Q260 722 260 694Q260 683 256 676T245 666Q208 663 190 644T171 585Q171 556 176 511Q182 445 182 403Q182 357 169 335T128 300Q155 289 168 268T182 205Q182 164 176 100Q171 53 171 22Q171 -15 180 -35T206 -63T253 -76Q255 -102 255 -106Q255
-126 248 -138T227 -150Q154 -150 122 -117Z" />
<glyph unicode="|" glyph-name="bar" horiz-adv-x="324" d="M122 793Q122 805 126 809T145 814T203 815V-180Q203 -191 199 -194T175 -199T122 -200V793Z" />
<glyph unicode="}" glyph-name="braceright" horiz-adv-x="277" d="M18 -128T18 -100Q18 -75 33 -72Q106 -66 106 8Q106 28 102 84Q96 148 96 191Q96 237 109 259T149 294Q122 305 109 326T96 389Q96 430 102 494Q106 550 106 573Q106 610 97 629T71 657T25 670Q21
686 21 701Q21 720 29 732T50 744Q123 744 155 711T188 609Q188 568 181 514Q180 505 177 474T174 412Q174 374 187 357T229 334Q236 317 236 301Q236 272 218 261Q201 250 193 242T180 216T174 167Q174 128 182 58Q188 -6 188 -32Q188 -92 146 -121T33 -150Q18
-128 18 -100Z" />
<glyph unicode="~" glyph-name="asciitilde" horiz-adv-x="400" d="M237 212T221 218T185 237Q169 247 158 251T132 256Q115 256 102 250T72 232Q58 221 46 218Q32 217 22 230T11 266Q26 289 61 309T140 329Q164 329 178 324T212 306Q228 296 240 291T270 286Q309
286 341 320Q347 325 357 325Q370 325 380 311T391 277Q373 252 340 232T263 212Q237 212 221 218Z" />
<glyph unicode="&#xa0;" glyph-name="uni00A0" horiz-adv-x="158" />
<glyph unicode="&#xa1;" glyph-name="exclamdown" horiz-adv-x="195" d="M46 394T46 451Q46 476 61 492T102 508Q132 508 144 494T157 451Q157 427 142 411T102 394Q46 394 46 451ZM61 256Q62 274 69 281T91 291T141 293L155 -174Q155 -185 147 -190T117 -196T45
-197L61 256Z" />
<glyph unicode="&#xa2;" glyph-name="cent" horiz-adv-x="418" d="M277 64T299 71T335 88Q343 68 343 37Q343 23 319 9T263 -9V-102Q263 -121 247 -127T190 -133V-7Q154 -1 131 20T96 91T83 228Q83 471 213 504V592Q213 611 230 618T286 626V508Q310 503 327 494T345
475Q345 437 337 417Q305 435 269 435Q239 435 217 421T179 362T164 231Q164 156 174 121T202 75T257 64Q277 64 299 71Z" />
<glyph unicode="&#xa3;" glyph-name="sterling" horiz-adv-x="366" d="M322 74Q329 54 329 37Q329 0 277 0H89Q80 121 78 277H15Q15 320 17 333T31 347H78Q82 480 122 537T238 595Q280 595 309 582T338 542Q338 530 335 518T327 493Q294 514 256 514Q210 514 185
479T158 347H288Q288 305 286 291T272 277H158Q160 146 165 80L322 74Z" />
<glyph unicode="&#xa4;" glyph-name="currency" horiz-adv-x="571" d="M560 49Q535 24 525 15T507 6Q504 6 498 10L417 91Q371 52 286 52Q201 52 154 90L62 -2Q39 21 30 32T20 51Q20 56 24 60L110 146Q87 198 87 276Q87 350 107 401L12 496Q37 521 47 530T65 539Q69
539 73 535L147 461Q198 506 291 506Q380 506 427 463L510 546Q534 522 543 512T552 493Q552 489 548 485L466 403Q484 357 484 286Q484 202 460 148L560 49ZM348 121T377 162T407 288Q407 365 380 402T295 439Q230 439 199 398T167 271Q167 195 196 158T288 121Q348
121 377 162Z" />
<glyph unicode="&#xa5;" glyph-name="yen" horiz-adv-x="418" d="M249 243H379Q379 205 373 191T347 176H249V16Q249 7 246 4T223 1T169 0V176H38Q38 215 44 229T70 243H169V284L149 341H38Q38 380 44 394T70 408H126L30 687Q28 694 32 696T59 699T122 700L161
563Q179 505 193 449T209 372Q211 392 226 451T259 563L297 685Q300 693 304 696T329 699T384 700L288 408H378Q378 370 372 356T347 341H266L249 290V243Z" />
<glyph unicode="&#xa6;" glyph-name="brokenbar" horiz-adv-x="227" d="M90 326T73 330V711Q73 729 82 736T115 743Q135 743 153 737V354Q153 337 146 332T112 326Q90 326 73 330ZM89 -198T73 -193V192Q73 210 82 217T115 225Q135 225 153 219V-169Q153 -187 146
-192T112 -198Q89 -198 73 -193Z" />
<glyph unicode="&#xa7;" glyph-name="section" horiz-adv-x="348" d="M264 201Q284 174 292 155T301 112Q301 58 259 27T150 -4Q106 -4 78 9T43 39Q40 44 40 55Q40 83 56 105Q90 81 137 81Q171 81 190 94T209 128Q209 142 202 154T179 185Q179 185 141 223Q94
268 72 296Q53 320 45 340T36 388Q36 415 49 442T91 489L83 499Q63 524 55 543T46 587Q46 641 88 672T198 703Q242 703 269 690T304 661Q307 652 307 644Q307 617 291 595Q259 618 209 618Q175 618 157 605T138 571Q138 557 144 546T167 515Q181 500 202 480Q221
462 242 441T275 404Q295 380 303 360T311 312Q311 286 297 259T255 212L264 201ZM151 300T171 284T196 264Q214 271 225 287T236 318Q236 335 229 350T207 384Q196 399 176 415T151 435Q133 429 122 413T111 382Q111 363 118 348T140 315Q151 300 171 284Z" />
<glyph unicode="&#xa8;" glyph-name="dieresis" horiz-adv-x="269" d="M53 573T44 586T34 632Q34 659 45 674T78 689Q100 689 108 677T117 634Q117 604 106 588T73 572Q53 573 44 586ZM173 573T163 585T153 628Q153 689 197 689Q219 689 227 677T236 634Q234 572
192 572Q173 573 163 585Z" />
<glyph unicode="&#xa9;" glyph-name="copyright" horiz-adv-x="471" d="M133 320T85 371T36 541Q36 652 89 706T242 760Q343 760 389 711T436 543Q436 435 384 378T234 320Q133 320 85 371ZM296 378T335 418T375 544Q375 628 342 666T241 705Q96 705 96 541Q96
452 129 415T232 378Q296 378 335 418ZM211 416T193 424T166 456T157 531Q157 613 183 640T249 668Q264 668 279 663T294 652Q294 644 288 620Q268 628 254 628Q231 628 218 609T204 529Q204 497 208 482T222 462T247 457Q266 457 286 467Q289 461 291 452T293
437Q293 430 277 423T243 416Q211 416 193 424Z" />
<glyph unicode="&#xaa;" glyph-name="ordfeminine" horiz-adv-x="323" d="M100 288T71 312T41 411Q41 478 69 506T150 534Q182 534 214 524V582Q214 615 198 627T152 639Q105 639 57 617Q47 630 47 652Q47 668 53 675Q85 710 176 710Q225 710 253 685T282 608V317Q259
306 224 297T154 288Q100 288 71 312ZM179 346T193 349T214 358V468Q206 472 194 474T172 476Q138 476 122 464T105 409Q105 373 120 360T165 346Q179 346 193 349Z" />
<glyph unicode="&#xab;" glyph-name="guillemotleft" horiz-adv-x="416" d="M156 16T120 70T51 181T18 253Q18 268 50 322T118 430T164 500Q178 500 188 491T205 472T212 459Q212 442 186 397T132 309T94 253Q103 240 132 198T187 109T214 47Q213 43 207 32T191
11T167 0Q156 16 120 70ZM326 38T291 86T223 185T190 251Q190 265 222 315T288 414T334 477Q347 477 357 469T374 451T381 439Q381 423 356 381T303 301T267 251Q276 240 303 203T357 125T383 69Q382 66 376 55T360 34T337 24Q326 38 291 86Z" />
<glyph unicode="&#xac;" glyph-name="logicalnot" horiz-adv-x="400" d="M358 111Q342 105 321 105Q304 105 293 111T282 131V232H40Q34 252 34 270Q34 287 40 297T60 308H358V111Z" />
<glyph unicode="&#xad;" glyph-name="uni00AD" horiz-adv-x="278" d="M37 290T39 303T54 317H241Q241 275 239 261T225 247H37Q37 290 39 303Z" />
<glyph unicode="&#xae;" glyph-name="registered" horiz-adv-x="471" d="M343 760T389 711T436 543Q436 435 384 378T234 320Q133 320 85 371T36 541Q36 652 89 706T242 760Q343 760 389 711ZM296 378T335 418T375 544Q375 628 342 666T241 705Q96 705 96 541Q96
452 129 415T232 378Q296 378 335 418ZM288 517T300 492T315 426Q315 420 312 418T299 416Q281 416 274 417Q268 491 239 518Q235 517 227 517H214V425Q214 419 208 418T176 417V665Q176 666 177 668T183 670H227Q308 670 308 598Q308 550 274 529Q288 517 300
492ZM219 551T230 551Q249 551 258 562T268 600Q268 618 260 627T232 637H214V552Q219 551 230 551Z" />
<glyph unicode="&#xaf;" glyph-name="overscore" horiz-adv-x="269" d="M1 601T1 624Q1 642 10 652T34 663H261Q268 646 268 629Q268 611 260 599T238 587H6Q1 601 1 624Z" />
<glyph unicode="&#xb0;" glyph-name="degree" horiz-adv-x="358" d="M129 553T107 573T84 649Q84 746 184 746Q233 746 254 725T276 650Q276 602 251 578T177 553Q129 553 107 573ZM223 604T223 650Q223 674 214 684T184 694Q161 694 150 684T138 648Q138 604
179 604Q223 604 223 650Z" />
<glyph unicode="&#xb1;" glyph-name="plusminus" horiz-adv-x="419" d="M385 359Q385 317 383 303T369 289H246V165Q246 154 232 152T175 149V289H35Q35 332 37 345T52 359H175V483Q175 494 189 496T246 499V359H385ZM34 58T36 71T51 85H384Q384 43 382 29T368
15H34Q34 58 36 71Z" />
<glyph unicode="&#xb2;" glyph-name="uni00B2" d="M41 301T41 315Q41 344 53 357Q77 385 138 444Q188 491 210 518T232 576Q232 600 219 614T168 628Q139 628 116 618T66 590Q57 606 54 616T51 639Q51 657 74 673T134 700T205 710Q274 710 302 683T330 604Q330
556 300 515T212 416Q170 373 162 365H339Q344 342 344 330Q344 289 318 289H47Q41 301 41 315Z" />
<glyph unicode="&#xb3;" glyph-name="uni00B3" d="M304 503T322 478T340 423Q340 352 292 316T165 279Q126 279 98 286T57 305Q45 314 45 335Q45 347 50 359T64 379Q103 353 161 353Q205 353 231 369T257 416Q257 438 242 452T199 470Q181 473 128 473Q126 476
123 489T119 510Q119 535 144 535Q171 535 197 532Q218 548 227 562T236 594Q236 612 221 625T171 638Q113 638 67 605Q51 622 51 645Q51 663 61 671Q79 688 116 699T204 710Q266 710 295 686T325 620Q325 592 312 565T273 516Q304 503 322 478Z" />
<glyph unicode="&#xb4;" glyph-name="acute" horiz-adv-x="271" d="M73 560T66 570T55 591T50 605Q82 641 129 681T184 722Q197 722 207 703T221 661Q209 648 158 611T81 560Q73 560 66 570Z" />
<glyph unicode="&#xb5;" glyph-name="uni00B5" horiz-adv-x="395" d="M70 -195T45 -190V470Q45 488 54 496T86 505Q110 505 125 500V131Q125 98 143 82T195 66Q237 66 269 81V470Q269 488 277 496T308 505Q334 505 349 500V24Q317 9 277 0T194 -10Q146 -10 125
15V-163Q125 -195 80 -195Q70 -195 45 -190Z" />
<glyph unicode="&#xb6;" glyph-name="paragraph" horiz-adv-x="541" d="M289 -3T271 3V205Q257 198 235 194T191 190Q121 190 78 242T34 420Q34 569 86 639T231 710Q298 710 352 682V26Q352 -3 312 -3Q289 -3 271 3ZM430 -3T414 2V658Q414 676 423 683T456 690Q477
690 495 684V26Q495 8 487 3T453 -3Q430 -3 414 2ZM226 255T243 258T271 269V630Q253 641 220 641Q169 641 143 588T116 428Q116 331 143 294T212 255Q226 255 243 258Z" />
<glyph unicode="&#xb7;" glyph-name="middot" horiz-adv-x="220" d="M79 212T66 226T53 269Q53 293 68 309T109 326Q165 326 165 269Q165 244 150 228T109 212Q79 212 66 226Z" />
<glyph unicode="&#xb8;" glyph-name="cedilla" horiz-adv-x="269" d="M177 -58T191 -74T206 -122Q206 -160 184 -183T126 -206Q107 -206 89 -200T70 -193Q71 -188 75 -172T83 -152Q86 -149 101 -156T128 -163Q159 -163 159 -129Q159 -95 129 -95Q113 -95 102 -97T88
-101L107 2H152L140 -59Q141 -58 157 -58Q177 -58 191 -74Z" />
<glyph unicode="&#xb9;" glyph-name="uni00B9" horiz-adv-x="382" d="M45 308T45 323Q45 345 50 355T72 365H166V622L58 600Q48 616 48 638Q48 666 74 676Q109 688 157 699T223 710Q241 710 247 707V365H334Q338 339 338 329Q338 307 333 298T313 289H49Q45 308 45 323Z" />
<glyph unicode="&#xba;" glyph-name="ordmasculine" horiz-adv-x="338" d="M121 289T93 307T50 372T35 499Q35 607 71 658T174 710Q220 710 247 692T289 628T303 501Q303 394 268 342T165 289Q121 289 93 307ZM200 356T217 389T235 499Q235 580 221 609T175 639Q139
639 121 606T103 494Q103 414 118 385T166 356Q200 356 217 389Z" />
<glyph unicode="&#xbb;" glyph-name="guillemotright" horiz-adv-x="414" d="M244 1T233 6T211 21T200 46Q200 62 227 108T283 197T321 253Q312 266 284 308T229 396T203 459Q203 471 213 480T235 494T251 500Q262 484 297 431T364 323T396 253Q396 237 363 181T295
71T248 0Q244 1 233 6ZM73 23T63 28T43 43T33 68Q33 84 59 124T112 202T149 250Q152 250 126 284Q84 343 60 382T35 439Q35 451 45 460T65 474T79 480Q90 465 125 416T192 316T224 250Q224 234 191 184T123 85T76 22Q73 23 63 28Z" />
<glyph unicode="&#xbc;" glyph-name="onequarter" horiz-adv-x="959" d="M41 307T41 323Q41 345 46 355T68 365H162V622L54 600Q44 616 44 638Q44 665 71 676Q105 688 153 699T219 710Q237 710 244 707V365H330Q334 348 334 329Q334 307 329 298T310 289H46Q41
307 41 323ZM324 -10T309 -2T281 19L617 691Q625 710 645 710Q658 710 673 703T700 682L361 5Q355 -10 337 -10Q324 -10 309 -2ZM808 -6T792 -2V70H621Q607 85 607 110Q607 125 614 143Q632 202 677 275T764 390Q780 409 796 415T834 421Q853 421 868 416V147H927Q934
130 934 109Q934 91 927 81T909 70H868V19Q868 -6 825 -6Q808 -6 792 -2ZM795 141L799 329Q766 303 731 247T682 141H795Z" />
<glyph unicode="&#xbd;" glyph-name="onehalf" horiz-adv-x="947" d="M41 307T41 323Q41 345 46 355T68 365H162V622L54 600Q44 616 44 638Q44 665 71 676Q105 688 153 699T219 710Q237 710 244 707V365H330Q334 348 334 329Q334 307 329 298T310 289H46Q41 307
41 323ZM324 -10T309 -2T281 19L617 691Q625 710 645 710Q658 710 673 703T700 682L361 5Q355 -10 337 -10Q324 -10 309 -2ZM607 12T607 26Q607 55 619 68Q643 96 704 155Q754 202 776 229T798 287Q798 311 785 325T734 339Q706 339 682 329T632 301Q623 317 621
327T618 350Q618 368 641 384T700 411T771 421Q840 421 868 394T896 315Q896 281 879 249T839 190T776 125Q735 84 728 76H905Q910 53 910 41Q910 0 884 0H613Q607 12 607 26Z" />
<glyph unicode="&#xbe;" glyph-name="threequarters" horiz-adv-x="961" d="M300 503T318 478T336 423Q336 352 288 316T161 279Q122 279 95 286T54 305Q41 314 41 335Q41 347 46 359T61 379Q98 353 158 353Q202 353 227 369T253 416Q253 438 238 452T196 470Q177
473 124 473Q122 476 119 489T115 510Q115 535 140 535Q169 535 194 532Q215 547 223 561T232 594Q232 612 217 625T168 638Q109 638 64 605Q48 622 48 646Q48 664 57 671Q75 688 112 699T201 710Q262 710 291 686T321 620Q321 592 308 565T269 516Q300 503 318
478ZM326 -10T311 -2T283 19L619 691Q627 710 647 710Q660 710 675 703T702 682L363 5Q357 -10 339 -10Q326 -10 311 -2ZM810 -6T794 -2V70H623Q609 85 609 110Q609 125 616 143Q634 202 679 275T766 390Q782 409 798 415T836 421Q855 421 870 416V147H929Q936
130 936 109Q936 91 929 81T911 70H870V19Q870 -6 827 -6Q810 -6 794 -2ZM797 141L801 329Q768 303 733 247T684 141H797Z" />
<glyph unicode="&#xbf;" glyph-name="questiondown" horiz-adv-x="306" d="M138 392T125 407T111 450Q111 474 126 490T167 506Q197 506 210 492T223 450Q223 426 208 409T167 392Q138 392 125 407ZM89 -195T52 -160T14 -56Q14 3 33 43T89 131Q117 170 125 184Q137
205 137 232Q137 242 132 272Q130 281 130 288T131 298Q141 308 176 308Q188 308 204 306Q205 304 208 295T215 270T219 236Q219 198 201 163Q186 135 156 93Q127 49 114 23T101 -37Q101 -114 182 -114Q228 -114 266 -89Q278 -119 278 -153Q278 -170 239 -182T153
-195Q89 -195 52 -160Z" />
<glyph unicode="&#xc0;" glyph-name="Agrave" horiz-adv-x="437" d="M433 6T426 2T396 -2Q369 -2 348 0L306 178H132L93 14Q90 5 84 2T55 -2Q34 -2 5 1L184 689Q187 703 214 703Q237 703 252 700L431 15Q433 6 426 2ZM288 251L254 395Q225 517 219 588Q208 499
183 395L149 251H288ZM253 768T202 804T140 855Q144 877 154 896T177 916Q184 916 232 875T311 798Q310 795 306 784T295 763T280 753Q253 768 202 804Z" />
<glyph unicode="&#xc1;" glyph-name="Aacute" horiz-adv-x="437" d="M433 6T426 2T396 -2Q369 -2 348 0L306 178H132L93 14Q90 5 84 2T55 -2Q34 -2 5 1L184 689Q187 703 214 703Q237 703 252 700L431 15Q433 6 426 2ZM288 251L254 395Q225 517 219 588Q208 499
183 395L149 251H288ZM163 760T156 770T145 791T140 805Q172 841 219 881T274 922Q287 922 297 903T311 861Q299 848 248 811T171 760Q163 760 156 770Z" />
<glyph unicode="&#xc2;" glyph-name="Acircumflex" horiz-adv-x="437" d="M433 6T426 2T396 -2Q369 -2 348 0L306 178H132L93 14Q90 5 84 2T55 -2Q34 -2 5 1L184 689Q187 703 214 703Q237 703 252 700L431 15Q433 6 426 2ZM288 251L254 395Q225 517 219 588Q208
499 183 395L149 251H288ZM279 770T255 796T222 838Q218 832 203 814T172 779T147 762Q111 762 92 785L206 908Q214 911 223 911Q237 911 248 899Q255 892 278 867T323 817T345 784Q345 774 328 768T288 761Q279 770 255 796Z" />
<glyph unicode="&#xc3;" glyph-name="Atilde" horiz-adv-x="437" d="M433 6T426 2T396 -2Q369 -2 348 0L306 178H132L93 14Q90 5 84 2T55 -2Q34 -2 5 1L184 689Q187 703 214 703Q237 703 252 700L431 15Q433 6 426 2ZM288 251L254 395Q225 517 219 588Q208 499
183 395L149 251H288ZM238 763T227 770T205 790Q195 801 188 806T170 811Q156 811 147 804T127 785T111 772Q101 772 93 781T79 799T72 812Q96 851 125 869T185 887Q200 887 209 881T230 863Q241 851 250 845T272 839Q292 839 302 846T322 866T337 878Q345 878
351 868T361 847T366 833Q362 824 347 808T309 777T258 763Q238 763 227 770Z" />
<glyph unicode="&#xc4;" glyph-name="Adieresis" horiz-adv-x="437" d="M433 6T426 2T396 -2Q369 -2 348 0L306 178H132L93 14Q90 5 84 2T55 -2Q34 -2 5 1L184 689Q187 703 214 703Q237 703 252 700L431 15Q433 6 426 2ZM288 251L254 395Q225 517 219 588Q208
499 183 395L149 251H288ZM137 773T128 786T118 832Q118 859 129 874T162 889Q184 889 192 877T201 834Q201 804 190 788T157 772Q137 773 128 786ZM257 773T247 785T237 828Q237 889 281 889Q303 889 311 877T320 834Q318 772 276 772Q257 773 247 785Z" />
<glyph unicode="&#xc5;" glyph-name="Aring" horiz-adv-x="437" d="M433 6T426 2T396 -2Q369 -2 348 0L306 178H132L93 14Q90 5 84 2T55 -2Q34 -2 5 1L184 689Q187 703 214 703Q237 703 252 700L431 15Q433 6 426 2ZM288 251L254 395Q225 517 219 588Q208 499
183 395L149 251H288ZM169 743T146 764T123 839Q123 888 149 912T223 937Q271 937 293 916T315 840Q315 792 290 768T216 743Q169 743 146 764ZM259 797T259 840Q259 862 250 871T223 881Q180 881 180 838Q180 818 189 808T218 797Q259 797 259 840Z" />
<glyph unicode="&#xc6;" glyph-name="AE" horiz-adv-x="615" d="M420 73H592Q592 44 592 26T588 4T576 0H340V178H174L105 14Q102 5 95 2T68 -2Q45 -2 17 1L311 686Q317 700 337 700H596Q596 672 596 654T592 632T581 627H420V418H571Q571 391 571 373T567 350T556
344H420V73ZM340 251V615Q304 490 264 392L205 251H340Z" />
<glyph unicode="&#xc7;" glyph-name="Ccedilla" horiz-adv-x="341" d="M243 79T268 88T308 111Q320 85 320 62Q320 35 293 15T220 -9L210 -59Q211 -58 227 -58Q247 -58 261 -74T276 -122Q276 -160 254 -183T196 -206Q177 -206 159 -200T140 -193Q141 -188 145
-172T153 -152Q156 -149 171 -156T198 -163Q229 -163 229 -129Q229 -95 199 -95Q183 -95 172 -97T158 -101L175 -9Q128 -6 97 21T48 120T30 321Q30 480 59 566T130 681T227 710Q277 710 299 694T321 655Q321 628 308 606Q277 631 243 631Q206 631 178 608T133 517T115
325Q115 227 127 173T161 99T215 79Q243 79 268 88Z" />
<glyph unicode="&#xc8;" glyph-name="Egrave" horiz-adv-x="320" d="M125 73H297Q297 44 297 26T293 4T281 0H45V684Q45 688 48 694T61 700H301Q301 672 301 654T297 632T286 627H125V418H276Q276 391 276 373T272 350T261 344H125V73ZM204 768T153 804T91 855Q95
877 105 896T128 916Q135 916 183 875T262 798Q261 795 257 784T246 763T231 753Q204 768 153 804Z" />
<glyph unicode="&#xc9;" glyph-name="Eacute" horiz-adv-x="320" d="M125 73H297Q297 44 297 26T293 4T281 0H45V684Q45 688 48 694T61 700H301Q301 672 301 654T297 632T286 627H125V418H276Q276 391 276 373T272 350T261 344H125V73ZM114 760T107 770T96 791T91
805Q123 841 170 881T225 922Q238 922 248 903T262 861Q250 848 199 811T122 760Q114 760 107 770Z" />
<glyph unicode="&#xca;" glyph-name="Ecircumflex" horiz-adv-x="320" d="M125 73H297Q297 44 297 26T293 4T281 0H45V684Q45 688 48 694T61 700H301Q301 672 301 654T297 632T286 627H125V418H276Q276 391 276 373T272 350T261 344H125V73ZM230 770T206 796T173
838Q169 832 154 814T123 779T98 762Q62 762 43 785L157 908Q165 911 174 911Q188 911 199 899Q206 892 229 867T274 817T296 784Q296 774 279 768T239 761Q230 770 206 796Z" />
<glyph unicode="&#xcb;" glyph-name="Edieresis" horiz-adv-x="320" d="M125 73H297Q297 44 297 26T293 4T281 0H45V684Q45 688 48 694T61 700H301Q301 672 301 654T297 632T286 627H125V418H276Q276 391 276 373T272 350T261 344H125V73ZM88 773T79 786T69 832Q69
859 80 874T113 889Q135 889 143 877T152 834Q152 804 141 788T108 772Q88 773 79 786ZM208 773T198 785T188 828Q188 889 232 889Q254 889 262 877T271 834Q269 772 227 772Q208 773 198 785Z" />
<glyph unicode="&#xcc;" glyph-name="Igrave" horiz-adv-x="169" d="M44 663Q44 683 48 690T66 698T126 700V16Q126 7 122 4T98 1T44 0V663ZM119 768T68 804T6 855Q10 877 20 896T43 916Q50 916 98 875T177 798Q176 795 172 784T161 763T146 753Q119 768 68 804Z" />
<glyph unicode="&#xcd;" glyph-name="Iacute" horiz-adv-x="169" d="M44 663Q44 683 48 690T66 698T126 700V16Q126 7 122 4T98 1T44 0V663ZM29 760T22 770T11 791T6 805Q38 841 85 881T140 922Q153 922 163 903T177 861Q165 848 114 811T37 760Q29 760 22 770Z" />
<glyph unicode="&#xce;" glyph-name="Icircumflex" horiz-adv-x="169" d="M44 663Q44 683 48 690T66 698T126 700V16Q126 7 122 4T98 1T44 0V663ZM145 770T121 796T88 838Q84 832 69 814T38 779T13 762Q-23 762 -42 785L72 908Q80 911 89 911Q103 911 114 899Q121
892 144 867T189 817T211 784Q211 774 194 768T154 761Q145 770 121 796Z" />
<glyph unicode="&#xcf;" glyph-name="Idieresis" horiz-adv-x="169" d="M44 663Q44 683 48 690T66 698T126 700V16Q126 7 122 4T98 1T44 0V663ZM3 773T-6 786T-16 832Q-16 859 -5 874T28 889Q50 889 58 877T67 834Q67 804 56 788T23 772Q3 773 -6 786ZM123 773T113
785T103 828Q103 889 147 889Q169 889 177 877T186 834Q184 772 142 772Q123 773 113 785Z" />
<glyph unicode="&#xd0;" glyph-name="Eth" horiz-adv-x="388" d="M237 700T279 672T342 577T364 394Q364 247 342 160T276 37T169 0H44V331H5Q5 374 7 387T21 401H44V681Q44 691 50 695T71 700H169Q237 700 279 672ZM201 77T223 100T259 193T273 394Q273 485 262
535T229 606T171 626H125V401H205Q205 359 203 345T188 331H125V77H171Q201 77 223 100Z" />
<glyph unicode="&#xd1;" glyph-name="Ntilde" horiz-adv-x="444" d="M320 693T324 696T348 699T401 700V16Q401 0 384 0H324L209 275Q185 339 114 560Q118 517 121 416T124 259V16Q124 7 121 4T97 1T44 0V684Q44 700 60 700H121L234 430Q247 395 308 211Q312 199
330 146V149Q325 188 323 290T320 448V684Q320 693 324 696ZM241 763T230 770T208 790Q198 801 191 806T173 811Q159 811 150 804T130 785T114 772Q104 772 96 781T82 799T75 812Q99 851 128 869T188 887Q203 887 212 881T233 863Q244 851 253 845T275 839Q295
839 305 846T325 866T340 878Q348 878 354 868T364 847T369 833Q365 824 350 808T312 777T261 763Q241 763 230 770Z" />
<glyph unicode="&#xd2;" glyph-name="Ograve" horiz-adv-x="429" d="M143 -10T105 21T48 131T30 354Q30 486 50 564T113 676T222 710Q288 710 326 678T381 569T399 357Q399 220 380 140T319 25T211 -10Q143 -10 105 21ZM251 73T272 101T302 190T312 355Q312 459
304 517T276 601T220 627Q184 627 163 599T131 507T121 334Q121 238 129 182T158 99T214 73Q251 73 272 101ZM249 768T198 804T136 855Q140 877 150 896T173 916Q180 916 228 875T307 798Q306 795 302 784T291 763T276 753Q249 768 198 804Z" />
<glyph unicode="&#xd3;" glyph-name="Oacute" horiz-adv-x="429" d="M143 -10T105 21T48 131T30 354Q30 486 50 564T113 676T222 710Q288 710 326 678T381 569T399 357Q399 220 380 140T319 25T211 -10Q143 -10 105 21ZM251 73T272 101T302 190T312 355Q312 459
304 517T276 601T220 627Q184 627 163 599T131 507T121 334Q121 238 129 182T158 99T214 73Q251 73 272 101ZM159 760T152 770T141 791T136 805Q168 841 215 881T270 922Q283 922 293 903T307 861Q295 848 244 811T167 760Q159 760 152 770Z" />
<glyph unicode="&#xd4;" glyph-name="Ocircumflex" horiz-adv-x="429" d="M143 -10T105 21T48 131T30 354Q30 486 50 564T113 676T222 710Q288 710 326 678T381 569T399 357Q399 220 380 140T319 25T211 -10Q143 -10 105 21ZM251 73T272 101T302 190T312 355Q312
459 304 517T276 601T220 627Q184 627 163 599T131 507T121 334Q121 238 129 182T158 99T214 73Q251 73 272 101ZM275 770T251 796T218 838Q214 832 199 814T168 779T143 762Q107 762 88 785L202 908Q210 911 219 911Q233 911 244 899Q251 892 274 867T319 817T341
784Q341 774 324 768T284 761Q275 770 251 796Z" />
<glyph unicode="&#xd5;" glyph-name="Otilde" horiz-adv-x="429" d="M143 -10T105 21T48 131T30 354Q30 486 50 564T113 676T222 710Q288 710 326 678T381 569T399 357Q399 220 380 140T319 25T211 -10Q143 -10 105 21ZM251 73T272 101T302 190T312 355Q312 459
304 517T276 601T220 627Q184 627 163 599T131 507T121 334Q121 238 129 182T158 99T214 73Q251 73 272 101ZM234 763T223 770T201 790Q191 801 184 806T166 811Q152 811 143 804T123 785T107 772Q97 772 89 781T75 799T68 812Q92 851 121 869T181 887Q196 887
205 881T226 863Q237 851 246 845T268 839Q288 839 298 846T318 866T333 878Q341 878 347 868T357 847T362 833Q358 824 343 808T305 777T254 763Q234 763 223 770Z" />
<glyph unicode="&#xd6;" glyph-name="Odieresis" horiz-adv-x="429" d="M143 -10T105 21T48 131T30 354Q30 486 50 564T113 676T222 710Q288 710 326 678T381 569T399 357Q399 220 380 140T319 25T211 -10Q143 -10 105 21ZM251 73T272 101T302 190T312 355Q312
459 304 517T276 601T220 627Q184 627 163 599T131 507T121 334Q121 238 129 182T158 99T214 73Q251 73 272 101ZM133 773T124 786T114 832Q114 859 125 874T158 889Q180 889 188 877T197 834Q197 804 186 788T153 772Q133 773 124 786ZM253 773T243 785T233 828Q233
889 277 889Q299 889 307 877T316 834Q314 772 272 772Q253 773 243 785Z" />
<glyph unicode="&#xd7;" glyph-name="multiply" horiz-adv-x="418" d="M257 281L345 183Q319 157 309 149T292 140Q290 140 284 144L209 228L133 144Q127 140 125 140Q118 140 108 148T72 183L160 281L71 381Q76 386 90 399T111 418T124 423Q129 423 133 419L209
335L284 419Q288 423 293 423Q300 423 308 416T329 398T346 381L257 281Z" />
<glyph unicode="&#xd8;" glyph-name="Oslash" horiz-adv-x="436" d="M415 685T381 585Q403 506 403 357Q403 220 383 140T322 25T214 -10Q174 -10 145 0T94 35Q81 -1 73 -16Q59 -16 43 -9T24 9Q23 12 35 44T59 102Q33 183 33 354Q33 486 53 564T114 676T222 710Q262
710 291 699T341 664Q359 712 363 719Q367 719 378 717T401 709T414 694Q415 685 381 585ZM186 628T165 600T134 507T124 334Q124 228 132 176L281 599Q261 628 222 628Q186 628 165 600ZM247 73T269 95T303 178T315 355Q315 463 307 516Q249 349 157 98Q176 73
211 73Q247 73 269 95Z" />
<glyph unicode="&#xd9;" glyph-name="Ugrave" horiz-adv-x="437" d="M148 -10T109 18T57 91T44 205V683Q44 692 47 695T71 699T127 700V202Q127 133 146 99T224 65Q249 65 274 70T312 82V683Q312 692 316 695T340 699T394 700V26Q373 12 326 1T224 -10Q148 -10
109 18ZM253 768T202 804T140 855Q144 877 154 896T177 916Q184 916 232 875T311 798Q310 795 306 784T295 763T280 753Q253 768 202 804Z" />
<glyph unicode="&#xda;" glyph-name="Uacute" horiz-adv-x="437" d="M148 -10T109 18T57 91T44 205V683Q44 692 47 695T71 699T127 700V202Q127 133 146 99T224 65Q249 65 274 70T312 82V683Q312 692 316 695T340 699T394 700V26Q373 12 326 1T224 -10Q148 -10
109 18ZM163 760T156 770T145 791T140 805Q172 841 219 881T274 922Q287 922 297 903T311 861Q299 848 248 811T171 760Q163 760 156 770Z" />
<glyph unicode="&#xdb;" glyph-name="Ucircumflex" horiz-adv-x="437" d="M148 -10T109 18T57 91T44 205V683Q44 692 47 695T71 699T127 700V202Q127 133 146 99T224 65Q249 65 274 70T312 82V683Q312 692 316 695T340 699T394 700V26Q373 12 326 1T224 -10Q148
-10 109 18ZM279 770T255 796T222 838Q218 832 203 814T172 779T147 762Q111 762 92 785L206 908Q214 911 223 911Q237 911 248 899Q255 892 278 867T323 817T345 784Q345 774 328 768T288 761Q279 770 255 796Z" />
<glyph unicode="&#xdc;" glyph-name="Udieresis" horiz-adv-x="437" d="M148 -10T109 18T57 91T44 205V683Q44 692 47 695T71 699T127 700V202Q127 133 146 99T224 65Q249 65 274 70T312 82V683Q312 692 316 695T340 699T394 700V26Q373 12 326 1T224 -10Q148
-10 109 18ZM137 773T128 786T118 832Q118 859 129 874T162 889Q184 889 192 877T201 834Q201 804 190 788T157 772Q137 773 128 786ZM257 773T247 785T237 828Q237 889 281 889Q303 889 311 877T320 834Q318 772 276 772Q257 773 247 785Z" />
<glyph unicode="&#xdd;" glyph-name="Yacute" horiz-adv-x="364" d="M225 16Q225 7 222 4T198 1T144 0V285L6 687Q4 694 8 696T35 699T97 700L137 563Q152 516 168 446T187 353Q189 375 206 445T238 563L273 685Q275 693 279 696T304 699T360 700L225 290V16ZM126
760T119 770T108 791T103 805Q135 841 182 881T237 922Q250 922 260 903T274 861Q262 848 211 811T134 760Q126 760 119 770Z" />
<glyph unicode="&#xde;" glyph-name="Thorn" horiz-adv-x="361" d="M44 680Q44 693 54 696T98 700H124V566H159Q254 566 298 519T343 369Q343 253 293 202T160 150H124V16Q124 7 120 4T96 1T44 0V680ZM212 225T233 260T254 378Q254 435 236 465T174 495Q139 495
124 493V228Q131 228 144 227T168 225Q212 225 233 260Z" />
<glyph unicode="&#xdf;" glyph-name="germandbls" horiz-adv-x="465" d="M65 -9T52 -4T39 2Q40 4 42 13T47 38T50 74L48 550Q48 629 90 667T208 705Q277 705 322 685T388 631T409 561Q409 529 394 510T348 467Q323 449 312 436T300 403Q300 385 313 368T355 325Q387
294 407 270T441 213T456 138Q456 70 416 31T306 -9Q269 -9 242 -2T201 15T187 36Q187 69 208 90Q217 81 238 72T288 63Q324 63 345 82T366 137Q366 172 347 201T288 270Q250 309 231 337T212 399Q212 432 228 452T276 497Q300 515 311 528T323 560Q323 589 295
609T214 630Q166 630 148 601T129 504L131 44Q131 14 122 3T84 -9Q65 -9 52 -4Z" />
<glyph unicode="&#xe0;" glyph-name="agrave" horiz-adv-x="354" d="M102 -10T66 20T29 142Q29 237 65 271T163 306Q210 306 236 293V372Q236 406 221 419T174 432Q138 432 101 426T41 409Q30 430 30 456Q30 476 41 483Q56 493 99 501T194 510Q259 510 288 482T317
388V335Q317 115 311 24Q287 9 250 0T166 -10Q102 -10 66 20ZM196 58T211 63T233 74Q236 108 236 236Q217 246 189 246Q153 246 133 225T113 144Q113 93 129 76T180 58Q196 58 211 63ZM209 568T158 604T96 655Q100 677 110 696T133 716Q140 716 188 675T267 598Q266
595 262 584T251 563T236 553Q209 568 158 604Z" />
<glyph unicode="&#xe1;" glyph-name="aacute" horiz-adv-x="354" d="M102 -10T66 20T29 142Q29 237 65 271T163 306Q210 306 236 293V372Q236 406 221 419T174 432Q138 432 101 426T41 409Q30 430 30 456Q30 476 41 483Q56 493 99 501T194 510Q259 510 288 482T317
388V335Q317 115 311 24Q287 9 250 0T166 -10Q102 -10 66 20ZM196 58T211 63T233 74Q236 108 236 236Q217 246 189 246Q153 246 133 225T113 144Q113 93 129 76T180 58Q196 58 211 63ZM119 560T112 570T101 591T96 605Q128 641 175 681T230 722Q243 722 253 703T267
661Q255 648 204 611T127 560Q119 560 112 570Z" />
<glyph unicode="&#xe2;" glyph-name="acircumflex" horiz-adv-x="354" d="M102 -10T66 20T29 142Q29 237 65 271T163 306Q210 306 236 293V372Q236 406 221 419T174 432Q138 432 101 426T41 409Q30 430 30 456Q30 476 41 483Q56 493 99 501T194 510Q259 510 288
482T317 388V335Q317 115 311 24Q287 9 250 0T166 -10Q102 -10 66 20ZM196 58T211 63T233 74Q236 108 236 236Q217 246 189 246Q153 246 133 225T113 144Q113 93 129 76T180 58Q196 58 211 63ZM235 570T211 596T178 638Q174 632 159 614T128 579T103 562Q67 562
48 585L162 708Q170 711 179 711Q193 711 204 699Q211 692 234 667T279 617T301 584Q301 574 284 568T244 561Q235 570 211 596Z" />
<glyph unicode="&#xe3;" glyph-name="atilde" horiz-adv-x="354" d="M102 -10T66 20T29 142Q29 237 65 271T163 306Q210 306 236 293V372Q236 406 221 419T174 432Q138 432 101 426T41 409Q30 430 30 456Q30 476 41 483Q56 493 99 501T194 510Q259 510 288 482T317
388V335Q317 115 311 24Q287 9 250 0T166 -10Q102 -10 66 20ZM196 58T211 63T233 74Q236 108 236 236Q217 246 189 246Q153 246 133 225T113 144Q113 93 129 76T180 58Q196 58 211 63ZM194 563T183 570T161 590Q151 601 144 606T126 611Q112 611 103 604T83 585T67
572Q57 572 49 581T35 599T28 612Q52 651 81 669T141 687Q156 687 165 681T186 663Q197 651 206 645T228 639Q248 639 258 646T278 666T293 678Q301 678 307 668T317 647T322 633Q318 624 303 608T265 577T214 563Q194 563 183 570Z" />
<glyph unicode="&#xe4;" glyph-name="adieresis" horiz-adv-x="354" d="M102 -10T66 20T29 142Q29 237 65 271T163 306Q210 306 236 293V372Q236 406 221 419T174 432Q138 432 101 426T41 409Q30 430 30 456Q30 476 41 483Q56 493 99 501T194 510Q259 510 288
482T317 388V335Q317 115 311 24Q287 9 250 0T166 -10Q102 -10 66 20ZM196 58T211 63T233 74Q236 108 236 236Q217 246 189 246Q153 246 133 225T113 144Q113 93 129 76T180 58Q196 58 211 63ZM93 573T84 586T74 632Q74 659 85 674T118 689Q140 689 148 677T157
634Q157 604 146 588T113 572Q93 573 84 586ZM213 573T203 585T193 628Q193 689 237 689Q259 689 267 677T276 634Q274 572 232 572Q213 573 203 585Z" />
<glyph unicode="&#xe5;" glyph-name="aring" horiz-adv-x="354" d="M102 -10T66 20T29 142Q29 237 65 271T163 306Q210 306 236 293V372Q236 406 221 419T174 432Q138 432 101 426T41 409Q30 430 30 456Q30 476 41 483Q56 493 99 501T194 510Q259 510 288 482T317
388V335Q317 115 311 24Q287 9 250 0T166 -10Q102 -10 66 20ZM196 58T211 63T233 74Q236 108 236 236Q217 246 189 246Q153 246 133 225T113 144Q113 93 129 76T180 58Q196 58 211 63ZM125 543T102 564T79 639Q79 688 105 712T179 737Q227 737 249 716T271 640Q271
592 246 568T172 543Q125 543 102 564ZM215 597T215 640Q215 662 206 671T179 681Q136 681 136 638Q136 618 145 608T174 597Q215 597 215 640Z" />
<glyph unicode="&#xe6;" glyph-name="ae" horiz-adv-x="583" d="M478 69T532 100Q539 79 539 28Q539 21 520 13T468 -2T401 -9Q367 -9 344 -3T302 20Q255 -9 164 -9Q122 -9 94 1T47 46T29 148Q29 319 160 319Q210 319 236 306V378Q236 412 218 425T168 438Q93
438 42 411Q32 429 32 459Q32 466 35 472T42 483Q58 494 98 502T197 510Q238 510 262 497T296 453Q317 487 346 498T418 510Q545 510 545 351Q545 270 534 220Q497 214 445 214Q383 214 324 225Q324 157 333 124T360 80T410 69Q478 69 532 100ZM376 439T354 406T326
289Q388 277 426 277Q446 277 462 280Q467 303 467 342Q466 397 454 418T409 439Q376 439 354 406ZM236 250Q217 258 189 258Q154 258 134 235T113 149Q113 110 121 90T142 64T178 58Q195 58 212 62T236 74V250Z" />
<glyph unicode="&#xe7;" glyph-name="ccedilla" horiz-adv-x="313" d="M227 62T248 68T284 85Q292 56 292 41Q292 20 262 6T184 -10L174 -59Q175 -58 191 -58Q211 -58 225 -74T240 -122Q240 -160 218 -183T160 -206Q141 -206 123 -200T104 -193Q105 -188 109 -172T117
-152Q120 -149 135 -156T162 -163Q193 -163 193 -129Q193 -95 163 -95Q147 -95 136 -97T122 -101L139 -7Q102 -1 79 23T43 99T31 239Q31 400 81 455T210 510Q246 510 270 497T294 465Q294 442 285 420Q251 439 214 439Q170 439 142 399T114 238Q114 169 123 131T152
77T204 62Q227 62 248 68Z" />
<glyph unicode="&#xe8;" glyph-name="egrave" horiz-adv-x="361" d="M267 68T321 100Q328 78 328 45Q328 22 288 6T190 -10Q139 -10 105 9T50 79T30 224Q30 341 54 404T117 488T207 510Q334 510 334 350Q334 270 323 220Q279 211 221 208T113 204Q115 150 125
121T155 80T207 68Q267 68 321 100ZM162 439T140 402T114 268Q213 268 251 280Q256 303 256 340Q255 396 243 417T198 439Q162 439 140 402ZM223 568T172 604T110 655Q114 677 124 696T147 716Q154 716 202 675T281 598Q280 595 276 584T265 563T250 553Q223 568
172 604Z" />
<glyph unicode="&#xe9;" glyph-name="eacute" horiz-adv-x="361" d="M267 68T321 100Q328 78 328 45Q328 22 288 6T190 -10Q139 -10 105 9T50 79T30 224Q30 341 54 404T117 488T207 510Q334 510 334 350Q334 270 323 220Q279 211 221 208T113 204Q115 150 125
121T155 80T207 68Q267 68 321 100ZM162 439T140 402T114 268Q213 268 251 280Q256 303 256 340Q255 396 243 417T198 439Q162 439 140 402ZM133 560T126 570T115 591T110 605Q142 641 189 681T244 722Q257 722 267 703T281 661Q269 648 218 611T141 560Q133 560
126 570Z" />
<glyph unicode="&#xea;" glyph-name="ecircumflex" horiz-adv-x="361" d="M267 68T321 100Q328 78 328 45Q328 22 288 6T190 -10Q139 -10 105 9T50 79T30 224Q30 341 54 404T117 488T207 510Q334 510 334 350Q334 270 323 220Q279 211 221 208T113 204Q115 150
125 121T155 80T207 68Q267 68 321 100ZM162 439T140 402T114 268Q213 268 251 280Q256 303 256 340Q255 396 243 417T198 439Q162 439 140 402ZM249 570T225 596T192 638Q188 632 173 614T142 579T117 562Q81 562 62 585L176 708Q184 711 193 711Q207 711 218
699Q225 692 248 667T293 617T315 584Q315 574 298 568T258 561Q249 570 225 596Z" />
<glyph unicode="&#xeb;" glyph-name="edieresis" horiz-adv-x="361" d="M267 68T321 100Q328 78 328 45Q328 22 288 6T190 -10Q139 -10 105 9T50 79T30 224Q30 341 54 404T117 488T207 510Q334 510 334 350Q334 270 323 220Q279 211 221 208T113 204Q115 150 125
121T155 80T207 68Q267 68 321 100ZM162 439T140 402T114 268Q213 268 251 280Q256 303 256 340Q255 396 243 417T198 439Q162 439 140 402ZM107 573T98 586T88 632Q88 659 99 674T132 689Q154 689 162 677T171 634Q171 604 160 588T127 572Q107 573 98 586ZM227
573T217 585T207 628Q207 689 251 689Q273 689 281 677T290 634Q288 572 246 572Q227 573 217 585Z" />
<glyph unicode="&#xec;" glyph-name="igrave" horiz-adv-x="175" d="M47 463Q47 482 53 489T75 498T128 500V16Q128 7 125 4T101 1T47 0V463ZM377 568T326 604T264 655Q268 677 278 696T301 716Q308 716 356 675T435 598Q434 595 430 584T419 563T404 553Q377
568 326 604Z" />
<glyph unicode="&#xed;" glyph-name="iacute" horiz-adv-x="175" d="M47 463Q47 482 53 489T75 498T128 500V16Q128 7 125 4T101 1T47 0V463ZM31 560T24 570T13 591T8 605Q40 641 87 681T142 722Q155 722 165 703T179 661Q167 648 116 611T39 560Q31 560 24 570Z" />
<glyph unicode="&#xee;" glyph-name="icircumflex" horiz-adv-x="175" d="M47 463Q47 482 53 489T75 498T128 500V16Q128 7 125 4T101 1T47 0V463ZM147 570T123 596T90 638Q86 632 71 614T40 579T15 562Q-21 562 -40 585L74 708Q82 711 91 711Q105 711 116 699Q123
692 146 667T191 617T213 584Q213 574 196 568T156 561Q147 570 123 596Z" />
<glyph unicode="&#xef;" glyph-name="idieresis" horiz-adv-x="175" d="M47 463Q47 482 53 489T75 498T128 500V16Q128 7 125 4T101 1T47 0V463ZM261 573T252 586T242 632Q242 659 253 674T286 689Q308 689 316 677T325 634Q325 604 314 588T281 572Q261 573 252
586ZM381 573T371 585T361 628Q361 689 405 689Q427 689 435 677T444 634Q442 572 400 572Q381 573 371 585Z" />
<glyph unicode="&#xf0;" glyph-name="eth" horiz-adv-x="408" d="M380 504T380 289Q380 149 344 70T209 -10Q116 -10 73 51T30 257Q30 378 73 443T190 509Q244 509 278 480Q260 547 224 602L129 565Q121 585 116 600T111 623Q111 633 119 637L177 659Q163 675
125 707Q134 724 150 734T183 744Q203 744 213 732Q233 716 257 690L326 717Q334 697 339 682T344 659Q344 649 336 646L300 632Q380 504 380 289ZM263 58T280 116T298 286Q298 349 293 388Q264 437 212 437Q163 437 138 383T112 244Q112 58 207 58Q263 58 280
116Z" />
<glyph unicode="&#xf1;" glyph-name="ntilde" horiz-adv-x="383" d="M45 476Q76 490 121 500T204 510Q282 510 313 480T344 376V16Q344 7 340 4T316 1T261 0V352Q261 402 249 421T201 440Q183 440 162 436T126 422V16Q126 7 122 4T98 1T45 0V476ZM211 563T200
570T178 590Q168 601 161 606T143 611Q129 611 120 604T100 585T84 572Q74 572 66 581T52 599T45 612Q69 651 98 669T158 687Q173 687 182 681T203 663Q214 651 223 645T245 639Q265 639 275 646T295 666T310 678Q318 678 324 668T334 647T339 633Q335 624 320
608T282 577T231 563Q211 563 200 570Z" />
<glyph unicode="&#xf2;" glyph-name="ograve" horiz-adv-x="376" d="M128 -10T95 9T45 84T27 250Q27 510 194 510Q249 510 282 488T332 409T349 252Q349 116 308 53T184 -10Q128 -10 95 9ZM222 58T241 100T261 252Q261 330 254 371T231 427T191 442Q154 442 135
400T115 248Q115 168 123 127T146 72T186 58Q222 58 241 100ZM224 568T173 604T111 655Q115 677 125 696T148 716Q155 716 203 675T282 598Q281 595 277 584T266 563T251 553Q224 568 173 604Z" />
<glyph unicode="&#xf3;" glyph-name="oacute" horiz-adv-x="376" d="M128 -10T95 9T45 84T27 250Q27 510 194 510Q249 510 282 488T332 409T349 252Q349 116 308 53T184 -10Q128 -10 95 9ZM222 58T241 100T261 252Q261 330 254 371T231 427T191 442Q154 442 135
400T115 248Q115 168 123 127T146 72T186 58Q222 58 241 100ZM134 560T127 570T116 591T111 605Q143 641 190 681T245 722Q258 722 268 703T282 661Q270 648 219 611T142 560Q134 560 127 570Z" />
<glyph unicode="&#xf4;" glyph-name="ocircumflex" horiz-adv-x="376" d="M128 -10T95 9T45 84T27 250Q27 510 194 510Q249 510 282 488T332 409T349 252Q349 116 308 53T184 -10Q128 -10 95 9ZM222 58T241 100T261 252Q261 330 254 371T231 427T191 442Q154 442
135 400T115 248Q115 168 123 127T146 72T186 58Q222 58 241 100ZM250 570T226 596T193 638Q189 632 174 614T143 579T118 562Q82 562 63 585L177 708Q185 711 194 711Q208 711 219 699Q226 692 249 667T294 617T316 584Q316 574 299 568T259 561Q250 570 226 596Z"
/>
<glyph unicode="&#xf5;" glyph-name="otilde" horiz-adv-x="376" d="M128 -10T95 9T45 84T27 250Q27 510 194 510Q249 510 282 488T332 409T349 252Q349 116 308 53T184 -10Q128 -10 95 9ZM222 58T241 100T261 252Q261 330 254 371T231 427T191 442Q154 442 135
400T115 248Q115 168 123 127T146 72T186 58Q222 58 241 100ZM209 563T198 570T176 590Q166 601 159 606T141 611Q127 611 118 604T98 585T82 572Q72 572 64 581T50 599T43 612Q67 651 96 669T156 687Q171 687 180 681T201 663Q212 651 221 645T243 639Q263 639
273 646T293 666T308 678Q316 678 322 668T332 647T337 633Q333 624 318 608T280 577T229 563Q209 563 198 570Z" />
<glyph unicode="&#xf6;" glyph-name="odieresis" horiz-adv-x="376" d="M128 -10T95 9T45 84T27 250Q27 510 194 510Q249 510 282 488T332 409T349 252Q349 116 308 53T184 -10Q128 -10 95 9ZM222 58T241 100T261 252Q261 330 254 371T231 427T191 442Q154 442
135 400T115 248Q115 168 123 127T146 72T186 58Q222 58 241 100ZM108 573T99 586T89 632Q89 659 100 674T133 689Q155 689 163 677T172 634Q172 604 161 588T128 572Q108 573 99 586ZM228 573T218 585T208 628Q208 689 252 689Q274 689 282 677T291 634Q289 572
247 572Q228 573 218 585Z" />
<glyph unicode="&#xf7;" glyph-name="divide" horiz-adv-x="418" d="M181 376T170 389T159 427Q159 448 172 463T208 478Q258 478 258 427Q258 405 245 391T208 376Q181 376 170 389ZM34 290T36 303T51 317H384Q384 275 382 261T368 247H34Q34 290 36 303ZM181
81T170 94T159 132Q159 153 172 168T208 183Q258 183 258 132Q258 110 245 96T208 81Q181 81 170 94Z" />
<glyph unicode="&#xf8;" glyph-name="oslash" horiz-adv-x="412" d="M403 484T388 454T356 395Q369 343 369 252Q369 116 329 53T207 -10Q167 -10 140 -2T93 29L62 -26Q46 -23 32 -14T17 8Q17 14 63 92Q48 149 48 250Q48 510 213 510Q250 510 277 501T323 468Q351
515 357 522Q360 521 371 517T393 506T403 489Q403 484 388 454ZM174 440T155 399T135 248Q135 216 137 176L266 404Q257 425 244 432T211 440Q174 440 155 399ZM243 58T262 100T282 252Q282 298 279 331Q275 323 194 179L150 101Q158 76 172 67T207 58Q243 58
262 100Z" />
<glyph unicode="&#xf9;" glyph-name="ugrave" horiz-adv-x="389" d="M135 -10T103 8T58 61T45 156V484Q45 493 48 496T72 499T128 500V149Q128 98 141 79T196 60Q236 60 263 79V484Q263 493 267 496T290 499T344 500V26Q314 10 274 0T194 -10Q135 -10 103 8ZM229
568T178 604T116 655Q120 677 130 696T153 716Q160 716 208 675T287 598Q286 595 282 584T271 563T256 553Q229 568 178 604Z" />
<glyph unicode="&#xfa;" glyph-name="uacute" horiz-adv-x="389" d="M135 -10T103 8T58 61T45 156V484Q45 493 48 496T72 499T128 500V149Q128 98 141 79T196 60Q236 60 263 79V484Q263 493 267 496T290 499T344 500V26Q314 10 274 0T194 -10Q135 -10 103 8ZM139
560T132 570T121 591T116 605Q148 641 195 681T250 722Q263 722 273 703T287 661Q275 648 224 611T147 560Q139 560 132 570Z" />
<glyph unicode="&#xfb;" glyph-name="ucircumflex" horiz-adv-x="389" d="M135 -10T103 8T58 61T45 156V484Q45 493 48 496T72 499T128 500V149Q128 98 141 79T196 60Q236 60 263 79V484Q263 493 267 496T290 499T344 500V26Q314 10 274 0T194 -10Q135 -10 103
8ZM255 570T231 596T198 638Q194 632 179 614T148 579T123 562Q87 562 68 585L182 708Q190 711 199 711Q213 711 224 699Q231 692 254 667T299 617T321 584Q321 574 304 568T264 561Q255 570 231 596Z" />
<glyph unicode="&#xfc;" glyph-name="udieresis" horiz-adv-x="389" d="M135 -10T103 8T58 61T45 156V484Q45 493 48 496T72 499T128 500V149Q128 98 141 79T196 60Q236 60 263 79V484Q263 493 267 496T290 499T344 500V26Q314 10 274 0T194 -10Q135 -10 103 8ZM113
573T104 586T94 632Q94 659 105 674T138 689Q160 689 168 677T177 634Q177 604 166 588T133 572Q113 573 104 586ZM233 573T223 585T213 628Q213 689 257 689Q279 689 287 677T296 634Q294 572 252 572Q233 573 223 585Z" />
<glyph unicode="&#xfd;" glyph-name="yacute" horiz-adv-x="357" d="M-4 -193T-4 -154Q-4 -142 -1 -130T8 -109Q18 -116 35 -120T71 -124Q97 -124 115 -100T144 -16L24 478Q22 486 22 489Q22 497 35 498T102 500L157 260Q167 211 174 156T184 83Q186 99 192 154T208
261L253 477Q255 490 259 494T279 499T340 500L217 -27Q202 -91 184 -127T140 -178T77 -193Q-4 -193 -4 -154ZM122 560T115 570T104 591T99 605Q131 641 178 681T233 722Q246 722 256 703T270 661Q258 648 207 611T130 560Q122 560 115 570Z" />
<glyph unicode="&#xfe;" glyph-name="thorn" d="M273 509T314 463T355 300Q355 123 309 57T203 -10Q153 -10 127 16V-194Q108 -200 79 -200Q58 -200 52 -194T46 -166V698Q46 717 52 724T74 733T127 735V502Q156 509 192 509Q273 509 314 463ZM212 60T239 109T266
293Q266 354 257 385T232 428T188 439Q154 439 127 418V88Q143 59 178 59Q212 60 239 109Z" />
<glyph unicode="&#xff;" glyph-name="ydieresis" horiz-adv-x="357" d="M-4 -193T-4 -154Q-4 -142 -1 -130T8 -109Q18 -116 35 -120T71 -124Q97 -124 115 -100T144 -16L24 478Q22 486 22 489Q22 497 35 498T102 500L157 260Q167 211 174 156T184 83Q186 99 192
154T208 261L253 477Q255 490 259 494T279 499T340 500L217 -27Q202 -91 184 -127T140 -178T77 -193Q-4 -193 -4 -154ZM96 573T87 586T77 632Q77 659 88 674T121 689Q143 689 151 677T160 634Q160 604 149 588T116 572Q96 573 87 586ZM216 573T206 585T196 628Q196
689 240 689Q262 689 270 677T279 634Q277 572 235 572Q216 573 206 585Z" />
<glyph unicode="&#x2013;" glyph-name="endash" horiz-adv-x="424" d="M37 290T39 303T54 317H387Q387 275 385 261T371 247H37Q37 290 39 303Z" />
<glyph unicode="&#x2014;" glyph-name="emdash" horiz-adv-x="700" d="M6 290T8 303T22 317H694Q694 275 692 261T678 247H6Q6 290 8 303Z" />
<glyph unicode="&#x2018;" glyph-name="quoteleft" horiz-adv-x="174" d="M34 575T34 634Q34 668 48 705T80 769T108 795Q135 795 140 772Q127 747 122 725T115 676Q138 661 138 627Q138 605 124 590T88 575Q34 575 34 634Z" />
<glyph unicode="&#x2019;" glyph-name="quoteright" horiz-adv-x="174" d="M41 572T34 595Q48 621 52 642T59 692Q36 706 36 740Q36 763 50 777T86 792Q141 792 141 733Q141 699 127 662T94 598T66 572Q41 572 34 595Z" />
<glyph unicode="&#x201a;" glyph-name="quotesinglbase" horiz-adv-x="170" d="M41 -114T34 -91Q48 -66 52 -45T59 5Q36 19 36 54Q36 76 50 91T86 106Q141 106 141 47Q141 13 127 -24T94 -88T66 -114Q41 -114 34 -91Z" />
<glyph unicode="&#x201c;" glyph-name="quotedblleft" horiz-adv-x="324" d="M34 575T34 634Q34 668 48 705T80 769T108 795Q135 795 140 772Q127 747 122 725T115 676Q138 661 138 627Q138 605 124 590T88 575Q34 575 34 634ZM184 575T184 634Q184 668 198 705T230
769T258 795Q285 795 290 772Q276 747 272 726T265 676Q288 661 288 627Q288 605 274 590T238 575Q184 575 184 634Z" />
<glyph unicode="&#x201d;" glyph-name="quotedblright" horiz-adv-x="324" d="M41 572T34 595Q48 621 52 642T59 692Q36 706 36 740Q36 763 50 777T86 792Q141 792 141 733Q141 699 127 662T94 598T66 572Q41 572 34 595ZM189 572T184 595Q198 621 202 642T209
692Q186 706 186 740Q186 763 200 777T236 792Q291 792 291 733Q291 699 277 662T244 598T216 572Q189 572 184 595Z" />
<glyph unicode="&#x201e;" glyph-name="quotedblbase" horiz-adv-x="321" d="M41 -114T34 -91Q48 -66 52 -45T59 5Q36 19 36 54Q36 76 50 91T86 106Q141 106 141 47Q141 13 127 -24T94 -88T66 -114Q41 -114 34 -91ZM189 -114T184 -91Q198 -66 202 -45T209 5Q186
19 186 54Q186 76 200 91T236 106Q291 106 291 47Q291 13 277 -24T244 -88T216 -114Q189 -114 184 -91Z" />
<glyph unicode="&#x2022;" glyph-name="bullet" horiz-adv-x="223" d="M75 208T58 227T41 284Q41 316 61 338T114 361Q153 361 171 341T189 284Q189 251 169 230T114 208Q75 208 58 227Z" />
<glyph unicode="&#x2039;" glyph-name="guilsinglleft" horiz-adv-x="247" d="M156 16T120 69T51 178T18 250Q18 265 50 320T118 430T164 500Q178 500 188 491T205 472T212 459Q212 442 186 396T132 306T94 250Q103 238 132 196T187 109T214 47Q213 43 207 32T191
11T167 0Q156 16 120 69Z" />
<glyph unicode="&#x203a;" glyph-name="guilsinglright" horiz-adv-x="247" d="M77 1T66 6T44 21T33 46Q33 62 59 107T115 195T153 250Q144 263 116 306T61 395T35 459Q35 471 45 480T67 494T83 500Q94 484 129 430T196 321T229 250Q229 234 196 179T128 70T81
0Q77 1 66 6Z" />
</font>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 913 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

View File

@@ -0,0 +1,184 @@
if ( !!window.SLB && SLB.has_child('View.extend_theme') ) {(function($) {
SLB.View.extend_theme('slb_default', {
/**
* Transition event handlers
*/
'transition': {
/**
* Open event
* @param View.Viewer v Viewer instance
* @param deferred dfr Resolved when transition is complete
* @return promise Resolved when transition is complete
*/
'open': function(v, dfr) {
// Reset layout and overlay state on open
var l = v.get_layout().hide(),
o = v.get_overlay().hide();
// Clean UI
var thm = this;
var d = v.dom_get();
d.find('.slb_content').css({width: '', height: ''}).find(this.get_tag_selector()).hide();
d.find('.slb_details').height(0);
// Show viewer DOM
d.show({'always': function() {
var pos = {'top_base': $(document).scrollTop()};
if ( document.documentElement.clientWidth > thm.get_breakpoint('small') ) {
/* Standard screen */
// Center vertically
pos.top = ( pos.top_base + $(window).height() / 2 ) - ( l.height() / 2 );
if ( pos.top < pos.top_base ) {
pos.top = pos.top_base;
}
} else {
/* Small screen */
// Position at top
pos.top = pos.top_base;
}
// Show overlay
o.fadeIn({'always': function() {
// Position lightbox
l.css(pos);
dfr.resolve();
}});
}});
return dfr.promise();
},
/**
* Close event
* @param View.Viewer v Viewer instance
* @param jQuery.Deferred dfr Deferred instance to be resolved when animation is complete
* @return jQuery.Promise Resolved when transition is complete
*/
'close': function(v, dfr) {
// Viewer elements
var l = v.get_layout(),
c = l.find('.slb_content');
// Reset procedure
var reset = function() {
// Reset state
c.width('').height('');
l.css('opacity', '');
dfr.resolve();
};
if ( v.animation_enabled() && document.documentElement.clientWidth > this.get_breakpoint('small') ) {
/* Standard */
var anims = {
'layout': { opacity: 0, top: $(document).scrollTop() + ( $(window).height() / 2 ) },
'content': { width: 0, height: 0 },
'speed': 'fast'
};
// Shrink & fade out viewer
var pos = l.animate(anims.layout, anims.speed).promise();
var size = c.animate(anims.content, anims.speed).promise();
$.when(pos, size).done(function() {
// Fade out overlay
v.get_overlay().fadeOut({'always': function() {
reset();
}});
});
} else {
l.css('opacity', 0);
reset();
}
return dfr.promise();
},
/**
* Item loading event
* @param View.Viewer v Viewer instance
* @param deferred dfr Resolved when animation is complete
* @return promise Resolved when transition is complete
*/
'load': function(v) {
v.get_layout().find('.slb_loading').show();
if ( document.documentElement.clientWidth > this.get_breakpoint('small') ) {
return v.get_layout().fadeIn().promise();
} else {
return v.get_layout().show().promise();
}
},
/**
* Item unloaded event
* @param View.Viewer v Viewer instance
* @param jQuery.Deferred dfr Deferred instance to be resolved when animation is complete
* @return jQuery.Promise Resolved when transition is complete
*/
'unload': function(v, dfr) {
var l = v.get_layout(),
det = l.find('.slb_details'),
cont = l.find('.slb_content ' + this.get_tag_selector());
var props = {height: 0};
// Hide details
det.css(props);
// Hide content
cont.hide();
// Finish
$.when(det.promise(), cont.promise()).done(function() {
dfr.resolve();
});
return dfr.promise();
},
/**
* Item loading completed event
* @param View.Viewer v Viewer instance
* @param jQuery.Deferred dfr Deferred instance to be resolved when animation is complete
* @return jQuery.Promise Resolved when transition is complete
*/
'complete': function(v, dfr) {
// Elements
var l = v.get_layout(),
loader = l.find('.slb_loading'),
det = l.find('.slb_details'),
det_data = det.find('.slb_data'),
c = l.find('.slb_content'),
c_tag = c.find( this.get_tag_selector() );
// Transition
if ( document.documentElement.clientWidth > this.get_breakpoint('small') ) {
var spd = 'fast';
// Resize viewer to fit item
var dims_item = this.get_item_dimensions();
// Determine details height
det.width(dims_item.width);
var dims_det = {'height': det_data.outerHeight()};
// Reset width
det.width('');
// Determine vertical positioning (centered)
var pos = { 'top_base': $(document).scrollTop() };
// Center vertically
pos.top = pos.top_base + ( $(window).height() / 2 ) - ( ( dims_det.height + dims_item.height ) / 2 );
if ( pos.top < pos.top_base ) {
pos.top = pos.top_base;
}
// Position/Resize viewer
pos = l.animate(pos, spd).promise();
dims_item = c.animate(dims_item, spd).promise();
// Display elements
var thm = this;
$.when(pos, dims_item).done(function() {
// Hide loading indicator
loader.fadeOut(spd, function() {
// Display content
c.find( thm.get_tag_selector('item', 'content') ).fadeIn(function() {
// Show UI
c_tag.show();
// Show details
det.animate({'height': det_data.outerHeight()}, 'slow').promise().done(function() {
det.height('');
dfr.resolve();
});
});
});
});
} else {
loader.hide();
c_tag.show();
det.height('');
dfr.resolve();
}
return dfr.promise();
}
}
});
})(jQuery);
}

View File

@@ -0,0 +1 @@
window.SLB&&SLB.has_child("View.extend_theme")&&!function($){SLB.View.extend_theme("slb_default",{transition:{open:function(v,dfr){var l=v.get_layout().hide(),o=v.get_overlay().hide(),thm=this,v=v.dom_get();return v.find(".slb_content").css({width:"",height:""}).find(this.get_tag_selector()).hide(),v.find(".slb_details").height(0),v.show({always:function(){var pos={top_base:$(document).scrollTop()};document.documentElement.clientWidth>thm.get_breakpoint("small")&&(pos.top=pos.top_base+$(window).height()/2-l.height()/2,!(pos.top<pos.top_base))||(pos.top=pos.top_base),o.fadeIn({always:function(){l.css(pos),dfr.resolve()}})}}),dfr.promise()},close:function(v,dfr){function reset(){c.width("").height(""),l.css("opacity",""),dfr.resolve()}var pos,anims,l=v.get_layout(),c=l.find(".slb_content");return v.animation_enabled()&&document.documentElement.clientWidth>this.get_breakpoint("small")?(anims={layout:{opacity:0,top:$(document).scrollTop()+$(window).height()/2},content:{width:0,height:0},speed:"fast"},pos=l.animate(anims.layout,anims.speed).promise(),anims=c.animate(anims.content,anims.speed).promise(),$.when(pos,anims).done(function(){v.get_overlay().fadeOut({always:function(){reset()}})})):(l.css("opacity",0),reset()),dfr.promise()},load:function(v){return v.get_layout().find(".slb_loading").show(),(document.documentElement.clientWidth>this.get_breakpoint("small")?v.get_layout().fadeIn():v.get_layout().show()).promise()},unload:function(v,dfr){var v=v.get_layout(),det=v.find(".slb_details"),v=v.find(".slb_content "+this.get_tag_selector());return det.css({height:0}),v.hide(),$.when(det.promise(),v.promise()).done(function(){dfr.resolve()}),dfr.promise()},complete:function(v,dfr){var dims_item,dims_det_height,pos,thm,v=v.get_layout(),loader=v.find(".slb_loading"),det=v.find(".slb_details"),det_data=det.find(".slb_data"),c=v.find(".slb_content"),c_tag=c.find(this.get_tag_selector());return document.documentElement.clientWidth>this.get_breakpoint("small")?(dims_item=this.get_item_dimensions(),det.width(dims_item.width),dims_det_height=det_data.outerHeight(),det.width(""),(pos={top_base:$(document).scrollTop()}).top=pos.top_base+$(window).height()/2-(dims_det_height+dims_item.height)/2,pos.top<pos.top_base&&(pos.top=pos.top_base),pos=v.animate(pos,"fast").promise(),dims_item=c.animate(dims_item,"fast").promise(),thm=this,$.when(pos,dims_item).done(function(){loader.fadeOut("fast",function(){c.find(thm.get_tag_selector("item","content")).fadeIn(function(){c_tag.show(),det.animate({height:det_data.outerHeight()},"slow").promise().done(function(){det.height(""),dfr.resolve()})})})})):(loader.hide(),c_tag.show(),det.height(""),dfr.resolve()),dfr.promise()}}})}(jQuery);

View File

@@ -0,0 +1,13 @@
/* yanone-kaffeesatz-regular - latin */
@font-face {
font-family: 'Yanone Kaffeesatz';
font-style: normal;
font-weight: 400;
src: url('../fonts/yanone-kaffeesatz-v9-latin-regular.eot'); /* IE9 Compat Modes */
src: local('Yanone Kaffeesatz Regular'), local('YanoneKaffeesatz-Regular'),
url('../fonts/yanone-kaffeesatz-v9-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../fonts/yanone-kaffeesatz-v9-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('../fonts/yanone-kaffeesatz-v9-latin-regular.woff') format('woff'), /* Modern Browsers */
url('../fonts/yanone-kaffeesatz-v9-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
url('../fonts/yanone-kaffeesatz-v9-latin-regular.svg#YanoneKaffeesatz') format('svg'); /* Legacy iOS */
}

View File

@@ -0,0 +1,191 @@
// Variables
$nav_width: 25px;
$nav_height: 33px;
$ui_controls_width: 25px;
$ui_controls_height: 25px;
// Fonts
@import "fonts";
// Placeholders
%hide-text {
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
}
#slb_viewer_wrap {
.slb_theme_slb_default {
//General
a,
a:hover {
border-bottom:none;
color:#000;
text-decoration:underline;
}
.slb_viewer_layout {
top: 20px;
}
.slb_container {
box-shadow: 0 0 64px -40px #fcfcfc;
border-radius: 5px;
}
.slb_loading {
@extend %hide-text;
}
.slb_template_tag_ui {
transition: opacity .5s;
}
//UI
.slb_controls {
position: absolute;
top: 8px;
right: 8px;
width: 75%;
text-align: right;
[dir="rtl"] & {
right: inherit;
left: 0px;
}
.slb_template_tag_ui {
@extend %hide-text;
width: $ui_controls_width;
height: $ui_controls_height;
float: right;
margin-left: 2px;
opacity: 0.5;
[dir="rtl"] & {
float: left;
}
}
.slb_template_tag_ui:hover {
opacity: 0.8;
}
.slb_slideshow .slb_template_tag {
background: url('../images/ui_slideshow_play.png') 0 0 no-repeat;
}
.slb_close .slb_template_tag {
background: url('../images/ui_close.png') 0 0 no-repeat;
}
}
&.slideshow_active .slb_controls .slb_slideshow .slb_template_tag {
background: url('../images/ui_slideshow_pause.png') 0 0 no-repeat;
}
//Navigation
$ui_nav_pos: 45%;
%ui_nav {
@extend %hide-text;
position: absolute;
top: 20%;
height: 71%;
width: 45%;
min-width: $nav_width;
min-height: $nav_height;
background-repeat: no-repeat;
opacity: 0.5;
}
//Content
.slb_content {
min-height: $nav_height + $ui_controls_height;
min-width: $nav_width * 2;
.slb_prev .slb_template_tag,
[dir="rtl"] & .slb_next .slb_template_tag {
left: 4px;
right: inherit;
background-image: url('../images/nav_prev.png');
background-position: left $ui_nav_pos;
}
.slb_next .slb_template_tag,
[dir="rtl"] & .slb_prev .slb_template_tag {
right: 4px;
left: inherit;
background-image: url('../images/nav_next.png');
background-position: right $ui_nav_pos;
}
.slb_prev, .slb_next {
.slb_template_tag {
@extend %ui_nav;
&:hover {
opacity: 1
}
}
}
}
.slb_details {
line-height: 1.4em;
overflow: hidden;
position: relative;
.slb_data {
caption-side: bottom;
}
.slb_nav {
display: none;
}
}
//Title
$title-size: 23px;
.slb_data_title, .slb_group_status {
font-family: 'Yanone Kaffeesatz', arial, sans-serif;
font-size: $title-size;
margin-right: .2em;
display: inline-block;
[dir="rtl"] & {
margin-left: .2em;
margin-right: 0px;
}
}
.slb_group_status {
color: #777;
font-style: italic;
font-size: $title-size * .8;
}
.slb_data_desc {
display: block;
margin-top: 0.5em;
}
//Media
//Small screen
@media screen and (max-width: 480px) {
.slb_container {
box-shadow: none;
border-radius: 0;
}
.slb_controls {
top: 3px;
right: 3px;
}
%ui_nav {
top: 17%;
height: 79%;
}
}
}
}