Version Description
- 19. May 2020. =
- Warning: 3.4 version is not backwards compatible! After installing this version, you won't be able to go back to 3.3.x.
- Smart Slider 3.4 no longer supports [Internet Explorer browser at all](https://www.zdnet.com/article/microsoft-security-chief-ie-is-not-a-browser-so-stop-using-it-as-your-default/!
- Feature: Content mode was renamed to Default and Canvas mode is now called Absolute.
- Feature: Completely redesigned UI
- Feature: Breakpoint system
- Feature: Nesting
- Feature: Layer list
- Feature: Focus selector for background images
- Feature: New Preview
- Feature: Contextual menu
- Feature: Orion theme updated for Slide Library
- Feature: More Slide Library templates are available for free users
- Feature: Block type available in Free version
- Feature: Slider trash
- Feature: Stop autoplay on added to the free version
- Feature: Hide controls on devices added to the free version
- Feature: Loading type options
- Feature: Sliders now render in Nimble Builder's editor when their shortcode is used in the builder's shortcode or rich text editor module
- Fix: WordPress Gutenberg editor language won't change to English on non-English sites
- Fix: PHP 7.4 fixes
- Fix: Sliders will no longer run on pages which are optimized by AMP on WordPress weeblrAMP CE
- Fix: Alias is removed from duplicated slider
- Fix: Compatibility with BuddyBoss theme
- Fix: Slider's inline JavaScript - Into the slider
- Fix: Scroll on older iPad devices
- Fix: SG Optimizer compatibility (?ver
Download this release
Release Info
Developer | nextendweb |
Plugin | Smart Slider 3 |
Version | 3.4.1.6 |
Comparing to | |
See all releases |
Code changes from version 3.3.28 to 3.4.1.6
- Defines.php +11 -0
- Nextend/Autoloader.php +203 -0
- Nextend/Framework/Acl/AbstractPlatformAcl.php +16 -0
- Nextend/Framework/Acl/Acl.php +31 -0
- Nextend/Framework/Acl/WordPress/WordPressAcl.php +13 -0
- Nextend/Framework/Api.php +168 -0
- Nextend/Framework/Application/AbstractApplication.php +28 -0
- Nextend/Framework/Application/AbstractApplicationType.php +158 -0
- Nextend/Framework/Asset/AbstractAsset.php +188 -0
- Nextend/Framework/Asset/AbstractCache.php +85 -0
- Nextend/Framework/Asset/AssetManager.php +180 -0
- Nextend/Framework/Asset/Css/Asset.php +78 -0
- Nextend/Framework/Asset/Css/Cache.php +51 -0
- Nextend/Framework/Asset/Css/Css.php +32 -0
- Nextend/Framework/Asset/Css/Less/Asset.php +27 -0
- Nextend/Framework/Asset/Css/Less/Cache.php +59 -0
- Nextend/Framework/Asset/Css/Less/Formatter/Classic.php +103 -0
- Nextend/Framework/Asset/Css/Less/Formatter/Compressed.php +19 -0
- Nextend/Framework/Asset/Css/Less/Formatter/Debug.php +13 -0
- Nextend/Framework/Asset/Css/Less/Less.php +32 -0
- Nextend/Framework/Asset/Css/Less/LessCompiler.php +2232 -0
- Nextend/Framework/Asset/Css/Less/LessParser.php +1522 -0
- Nextend/Framework/Asset/Fonts/Google/Asset.php +132 -0
- Nextend/Framework/Asset/Fonts/Google/Google.php +26 -0
- Nextend/Framework/Asset/Image/Asset.php +36 -0
- Nextend/Framework/Asset/Js/Asset.php +143 -0
- Nextend/Framework/Asset/Js/Cache.php +27 -0
- Nextend/Framework/Asset/Js/Js.php +80 -0
- Nextend/Framework/Asset/Predefined.php +78 -0
- Nextend/Framework/Browse/Block/BrowseManager/BlockBrowseManager.php +20 -0
- Nextend/Framework/Browse/BrowseManager.php +20 -0
- Nextend/Framework/Browse/BulletProof/BulletProof.php +385 -0
- Nextend/Framework/Browse/BulletProof/Exception.php +9 -0
- Nextend/Framework/Browse/ControllerAjaxBrowse.php +140 -0
- Nextend/Framework/Cache/AbstractCache.php +90 -0
- Nextend/Framework/Cache/CacheImage.php +130 -0
- Nextend/Framework/Cache/Combine.php +61 -0
- Nextend/Framework/Cache/Manifest.php +103 -0
- Nextend/Framework/Cache/Storage/AbstractStorage.php +28 -0
- Nextend/Framework/Cache/Storage/Database.php +56 -0
- Nextend/Framework/Cache/Storage/Filesystem.php +62 -0
- Nextend/Framework/Cache/StoreImage.php +44 -0
- Nextend/Framework/Cast.php +18 -0
- Nextend/Framework/Content/AbstractPlatformContent.php +33 -0
- Nextend/Framework/Content/Content.php +28 -0
- Nextend/Framework/Content/ControllerAjaxContent.php +25 -0
- Nextend/Framework/Content/WordPress/WordPressContent.php +69 -0
- Nextend/Framework/Controller/AbstractController.php +198 -0
- Nextend/Framework/Controller/Admin/AbstractAdminController.php +23 -0
- Nextend/Framework/Controller/Admin/AdminAjaxController.php +11 -0
- Nextend/Framework/Controller/Admin/AdminVisualManagerAjaxController.php +180 -0
- Nextend/Framework/Controller/AjaxController.php +66 -0
- Nextend/Framework/Data/Data.php +94 -0
- Nextend/Framework/Database/AbstractPlatformConnector.php +60 -0
- Nextend/Framework/Database/AbstractPlatformConnectorTable.php +90 -0
- Nextend/Framework/Database/Database.php +101 -0
- Nextend/Framework/Database/WordPress/WordPressConnector.php +126 -0
- Nextend/Framework/Database/WordPress/WordPressConnectorTable.php +118 -0
- Nextend/Framework/Filesystem/AbstractPlatformFilesystem.php +356 -0
- Nextend/Framework/Filesystem/Filesystem.php +275 -0
- Nextend/Framework/Filesystem/WordPress/WordPressFilesystem.php +83 -0
- Nextend/Framework/Font/AbstractFontSource.php +33 -0
- Nextend/Framework/Font/Block/FontManager/BlockFontManager.php +58 -0
- Nextend/Framework/Font/Block/FontManager/Index.phtml +26 -0
- Nextend/Framework/Font/ControllerAjaxFont.php +15 -0
- Nextend/Framework/Font/FontManager.php +17 -0
- Nextend/Framework/Font/FontParser.php +62 -0
- Nextend/Framework/Font/FontRenderer.php +275 -0
- Nextend/Framework/Font/FontSettings.php +138 -0
- Nextend/Framework/Font/FontSources.php +55 -0
- Nextend/Framework/Font/FontStorage.php +93 -0
- Nextend/Framework/Font/FontStyle.php +195 -0
- Nextend/Framework/Font/ModelFont.php +108 -0
- Nextend/Framework/Font/Sources/GoogleFonts/GoogleFonts.php +195 -0
- {nextend/library/applications/system/plugins/nextendfontservices/google → Nextend/Framework/Font/Sources/GoogleFonts}/families.csv +0 -0
- Nextend/Framework/Form/AbstractContainer.php +78 -0
- Nextend/Framework/Form/AbstractField.php +377 -0
- Nextend/Framework/Form/AbstractFieldset.php +147 -0
- Nextend/Framework/Form/AbstractFormManager.php +22 -0
- Nextend/Framework/Form/Base/PlatformFormBase.php +19 -0
- Nextend/Framework/Form/ContainedInterface.php +42 -0
- Nextend/Framework/Form/Container/ContainerAlternative.php +14 -0
- Nextend/Framework/Form/Container/ContainerRowGroup.php +35 -0
- Nextend/Framework/Form/Container/ContainerSubform.php +20 -0
- Nextend/Framework/Form/Container/ContainerTab.php +21 -0
- Nextend/Framework/Form/Container/ContainerTable.php +79 -0
- Nextend/Framework/Form/Container/LayerWindow/ContainerAnimation.php +41 -0
- Nextend/Framework/Form/Container/LayerWindow/ContainerAnimationTab.php +16 -0
- Nextend/Framework/Form/Container/LayerWindow/ContainerDesign.php +42 -0
- Nextend/Framework/Form/Container/LayerWindow/ContainerSettings.php +21 -0
- Nextend/Framework/Form/ContainerContainedInterface.php +9 -0
- Nextend/Framework/Form/ContainerGeneral.php +127 -0
- Nextend/Framework/Form/ContainerInterface.php +59 -0
- Nextend/Framework/Form/ContainerMain.php +88 -0
- Nextend/Framework/Form/Element/AbstractChooser.php +75 -0
- Nextend/Framework/Form/Element/AbstractChooserText.php +88 -0
- Nextend/Framework/Form/Element/AbstractFieldHidden.php +38 -0
- Nextend/Framework/Form/Element/Breakpoint.php +98 -0
- Nextend/Framework/Form/Element/Button.php +65 -0
- Nextend/Framework/Form/Element/Button/ButtonIcon.php +35 -0
- Nextend/Framework/Form/Element/Button/ButtonMoreLess.php +31 -0
- Nextend/Framework/Form/Element/Button/ButtonRecordViewer.php +30 -0
- Nextend/Framework/Form/Element/CheckboxOnOff.php +75 -0
- Nextend/Framework/Form/Element/Connected.php +27 -0
- Nextend/Framework/Form/Element/Decoration.php +77 -0
- Nextend/Framework/Form/Element/Devices.php +52 -0
- Nextend/Framework/Form/Element/EmptyArea.php +18 -0
- Nextend/Framework/Form/Element/FloatToPercent.php +69 -0
- Nextend/Framework/Form/Element/Font.php +76 -0
- Nextend/Framework/Form/Element/Group/GroupCheckboxOnOff.php +18 -0
- Nextend/Framework/Form/Element/Grouping.php +39 -0
- Nextend/Framework/Form/Element/Hidden.php +18 -0
- Nextend/Framework/Form/Element/Hidden/HiddenFont.php +33 -0
- Nextend/Framework/Form/Element/Hidden/HiddenOnOff.php +13 -0
- Nextend/Framework/Form/Element/Hidden/HiddenStyle.php +33 -0
- Nextend/Framework/Form/Element/IconTab.php +105 -0
- Nextend/Framework/Form/Element/LayerWindowFocus.php +64 -0
- Nextend/Framework/Form/Element/MarginPadding.php +81 -0
- Nextend/Framework/Form/Element/Message.php +23 -0
- Nextend/Framework/Form/Element/Message/Notice.php +15 -0
- Nextend/Framework/Form/Element/Message/Warning.php +20 -0
- Nextend/Framework/Form/Element/Mixed.php +80 -0
- Nextend/Framework/Form/Element/Mixed/Border.php +74 -0
- Nextend/Framework/Form/Element/Mixed/BoxShadow.php +45 -0
- Nextend/Framework/Form/Element/Mixed/FontSize.php +57 -0
- Nextend/Framework/Form/Element/Mixed/GeneratorOrder.php +40 -0
- Nextend/Framework/Form/Element/Mixed/TextShadow.php +45 -0
- Nextend/Framework/Form/Element/OnOff.php +89 -0
- Nextend/Framework/Form/Element/Radio.php +74 -0
- Nextend/Framework/Form/Element/Radio/AbstractRadioIcon.php +28 -0
- Nextend/Framework/Form/Element/Radio/ImageList.php +91 -0
- Nextend/Framework/Form/Element/Radio/ImageListFromFolder.php +115 -0
- Nextend/Framework/Form/Element/Radio/TextAlign.php +26 -0
- Nextend/Framework/Form/Element/RichTextarea.php +55 -0
- Nextend/Framework/Form/Element/Select.php +172 -0
- Nextend/Framework/Form/Element/Select/Easing.php +44 -0
- Nextend/Framework/Form/Element/Select/FillMode.php +39 -0
- Nextend/Framework/Form/Element/Select/Filter.php +22 -0
- Nextend/Framework/Form/Element/Select/FontWeight.php +27 -0
- Nextend/Framework/Form/Element/Select/Gradient.php +22 -0
- Nextend/Framework/Form/Element/Select/LinkTarget.php +21 -0
- Nextend/Framework/Form/Element/Select/SelectFile.php +42 -0
- Nextend/Framework/Form/Element/Select/Skin.php +42 -0
- Nextend/Framework/Form/Element/Select/SubFormIcon.php +107 -0
- Nextend/Framework/Form/Element/SelectIcon.php +57 -0
- Nextend/Framework/Form/Element/Style.php +103 -0
- Nextend/Framework/Form/Element/Tab.php +70 -0
- Nextend/Framework/Form/Element/Text.php +100 -0
- Nextend/Framework/Form/Element/Text/Color.php +42 -0
- Nextend/Framework/Form/Element/Text/Disabled.php +10 -0
- Nextend/Framework/Form/Element/Text/Family.php +21 -0
- Nextend/Framework/Form/Element/Text/FieldImage.php +63 -0
- Nextend/Framework/Form/Element/Text/FieldImageResponsive.php +19 -0
- Nextend/Framework/Form/Element/Text/Folder.php +44 -0
- Nextend/Framework/Form/Element/Text/HiddenText.php +16 -0
- Nextend/Framework/Form/Element/Text/Number.php +115 -0
- Nextend/Framework/Form/Element/Text/NumberAutoComplete.php +27 -0
- Nextend/Framework/Form/Element/Text/NumberSlider.php +52 -0
- Nextend/Framework/Form/Element/Text/TextAutoComplete.php +28 -0
- Nextend/Framework/Form/Element/Text/TextMultiAutoComplete.php +34 -0
- Nextend/Framework/Form/Element/Text/Url.php +52 -0
- Nextend/Framework/Form/Element/Text/Video.php +19 -0
- Nextend/Framework/Form/Element/Textarea.php +75 -0
- Nextend/Framework/Form/Element/Textarea/TextareaInline.php +19 -0
- Nextend/Framework/Form/Element/Token.php +14 -0
- Nextend/Framework/Form/Element/Unit.php +68 -0
- Nextend/Framework/Form/Element/Upload.php +36 -0
- Nextend/Framework/Form/Fieldset/FieldsetHidden.php +31 -0
- Nextend/Framework/Form/Fieldset/FieldsetRow.php +74 -0
- Nextend/Framework/Form/Fieldset/FieldsetRowPlain.php +37 -0
- Nextend/Framework/Form/Fieldset/FieldsetTableLabel.php +27 -0
- Nextend/Framework/Form/Fieldset/FieldsetVisualSet.php +52 -0
- Nextend/Framework/Form/Fieldset/LayerWindow/FieldsetDesign.php +50 -0
- Nextend/Framework/Form/Fieldset/LayerWindow/FieldsetInsideLabel.php +27 -0
- Nextend/Framework/Form/Fieldset/LayerWindow/FieldsetLayerWindow.php +97 -0
- Nextend/Framework/Form/Fieldset/LayerWindow/FieldsetLayerWindowLabelFields.php +39 -0
- Nextend/Framework/Form/Fieldset/LayerWindow/FieldsetLayerWindowStyleMode.php +28 -0
- Nextend/Framework/Form/Form.php +136 -0
- Nextend/Framework/Form/FormTabbed.php +75 -0
- Nextend/Framework/Form/Insert/AbstractInsert.php +31 -0
- Nextend/Framework/Form/Insert/InsertAfter.php +15 -0
- Nextend/Framework/Form/Insert/InsertBefore.php +15 -0
- Nextend/Framework/Form/TraitContainer.php +121 -0
- Nextend/Framework/Form/TraitFieldset.php +54 -0
- Nextend/Framework/Form/WordPress/PlatformForm.php +24 -0
- Nextend/Framework/Framework.php +23 -0
- Nextend/Framework/Image/AbstractPlatformImage.php +13 -0
- Nextend/Framework/Image/Block/ImageManager/BlockImageManager.php +59 -0
- Nextend/Framework/Image/Block/ImageManager/Index.phtml +26 -0
- Nextend/Framework/Image/ControllerAjaxImage.php +116 -0
- Nextend/Framework/Image/Image.php +65 -0
- Nextend/Framework/Image/ImageEdit.php +457 -0
- Nextend/Framework/Image/ImageManager.php +62 -0
- Nextend/Framework/Image/ImageStorage.php +161 -0
- Nextend/Framework/Image/ModelImage.php +96 -0
- Nextend/Framework/Image/WordPress/WordPressImage.php +50 -0
- Nextend/Framework/Localization/AbstractLocalization.php +10 -0
- Nextend/Framework/Localization/Functions.php +33 -0
- Nextend/Framework/Localization/Localization.php +84 -0
- Nextend/Framework/Localization/Pomo/entry.php +96 -0
- Nextend/Framework/Localization/Pomo/mo.php +338 -0
- Nextend/Framework/Localization/Pomo/plural-forms.php +366 -0
- Nextend/Framework/Localization/Pomo/streams.php +325 -0
- Nextend/Framework/Localization/Pomo/translations.php +392 -0
- Nextend/Framework/Localization/WordPress/WordPressLocalization.php +17 -0
- Nextend/Framework/Misc/Base64.php +22 -0
- Nextend/Framework/Misc/Base64/Decoder.php +47 -0
- Nextend/Framework/Misc/Base64/Encoder.php +52 -0
- Nextend/Framework/Misc/HttpClient.php +141 -0
- Nextend/Framework/Misc/OAuth/HTTP.php +1603 -0
- Nextend/Framework/Misc/OAuth/OAuth.php +2536 -0
- {nextend/library/libraries/oauth → Nextend/Framework/Misc/OAuth}/oauth_configuration.json +0 -0
- Nextend/Framework/Misc/Str.php +42 -0
- Nextend/Framework/Misc/String/MultiByte.php +18 -0
- Nextend/Framework/Misc/String/SingleByte.php +18 -0
- Nextend/Framework/Misc/String/StringInterface.php +14 -0
- Nextend/Framework/Misc/Zip/Creator.php +194 -0
- Nextend/Framework/Misc/Zip/Reader.php +20 -0
- Nextend/Framework/Misc/Zip/Reader/Custom.php +129 -0
- Nextend/Framework/Misc/Zip/Reader/ZipExtension.php +39 -0
- Nextend/Framework/Misc/Zip/ReaderInterface.php +9 -0
- {nextend/library → Nextend/Framework/Misc}/cacert.pem +0 -0
- Nextend/Framework/Model/AbstractModel.php +27 -0
- Nextend/Framework/Model/AbstractModelTable.php +28 -0
- Nextend/Framework/Model/ApplicationSection.php +85 -0
- Nextend/Framework/Model/Section.php +175 -0
- Nextend/Framework/Model/StorageSectionManager.php +25 -0
- Nextend/Framework/Notification/Notification.php +196 -0
- Nextend/Framework/PageFlow.php +28 -0
- Nextend/Framework/Parser/Color.php +138 -0
- Nextend/Framework/Parser/Common.php +24 -0
- Nextend/Framework/Parser/Font.php +214 -0
- Nextend/Framework/Parser/Link.php +56 -0
- Nextend/Framework/Parser/Link/ParserInterface.php +8 -0
- Nextend/Framework/Parser/Link/ScrollTo.php +48 -0
- Nextend/Framework/Parser/Link/ScrollToAlias.php +14 -0
- Nextend/Framework/Parser/Style.php +95 -0
- Nextend/Framework/Pattern/GetAssetsPathTrait.php +22 -0
- Nextend/Framework/Pattern/GetPathTrait.php +15 -0
- Nextend/Framework/Pattern/MVCHelperTrait.php +80 -0
- Nextend/Framework/Pattern/OrderableTrait.php +32 -0
- Nextend/Framework/Pattern/PluggableFactoryTrait.php +28 -0
- Nextend/Framework/Pattern/PluggableTrait.php +15 -0
- Nextend/Framework/Pattern/SingletonTrait.php +27 -0
- Nextend/Framework/Pattern/VisualManagerTrait.php +41 -0
- Nextend/Framework/Platform/AbstractPlatform.php +75 -0
- Nextend/Framework/Platform/Platform.php +85 -0
- Nextend/Framework/Platform/WordPress/PlatformWordPress.php +143 -0
- Nextend/Framework/Plugin.php +53 -0
- Nextend/Framework/Request/Parser/AbstractRequestParser.php +11 -0
- Nextend/Framework/Request/Parser/JoomlaRequestParser.php +10 -0
- Nextend/Framework/Request/Parser/WordPressRequestParser.php +22 -0
- Nextend/Framework/Request/Request.php +49 -0
- Nextend/Framework/Request/Storage.php +66 -0
- Nextend/Framework/ResourceTranslator/ResourceIdentifier.php +74 -0
- Nextend/Framework/ResourceTranslator/ResourceTranslator.php +171 -0
- Nextend/Framework/Response/ResponseAjax.php +73 -0
- Nextend/Framework/Router/Base/PlatformRouter.php +27 -0
- Nextend/Framework/Router/Router.php +151 -0
- Nextend/Framework/Router/WordPress/WordPressRouter.php +23 -0
- Nextend/Framework/Sanitize.php +609 -0
- Nextend/Framework/Session/AbstractStorage.php +79 -0
- Nextend/Framework/Session/Session.php +40 -0
- Nextend/Framework/Session/WordPress/WordPressStorage.php +39 -0
- Nextend/Framework/Settings.php +78 -0
- Nextend/Framework/Style/Block/StyleManager/BlockStyleManager.php +56 -0
- Nextend/Framework/Style/Block/StyleManager/Index.phtml +26 -0
- Nextend/Framework/Style/ControllerAjaxStyle.php +17 -0
- Nextend/Framework/Style/ModelCss.php +54 -0
- Nextend/Framework/Style/ModelStyle.php +102 -0
- Nextend/Framework/Style/Style.php +95 -0
- Nextend/Framework/Style/StyleManager.php +19 -0
- Nextend/Framework/Style/StyleParser.php +63 -0
- Nextend/Framework/Style/StyleRenderer.php +215 -0
- Nextend/Framework/Style/StyleStorage.php +93 -0
- Nextend/Framework/Translation/AbstractTranslation.php +14 -0
- Nextend/Framework/Translation/Translation.php +29 -0
- Nextend/Framework/Translation/WordPress/WordPressTranslation.php +23 -0
- Nextend/Framework/Url/AbstractPlatformUrl.php +95 -0
- Nextend/Framework/Url/Url.php +76 -0
- Nextend/Framework/Url/UrlHelper.php +278 -0
- Nextend/Framework/Url/WordPress/WordPressUrl.php +68 -0
- Nextend/Framework/View/AbstractBlock.php +51 -0
- Nextend/Framework/View/AbstractLayout.php +81 -0
- Nextend/Framework/View/AbstractView.php +49 -0
- Nextend/Framework/View/AbstractViewAjax.php +42 -0
- Nextend/Framework/View/Html.php +319 -0
- Nextend/Framework/Visual/AbstractBlockVisual.php +12 -0
- Nextend/Framework/Visual/ModelVisual.php +117 -0
- Nextend/Framework/WordPress/AssetInjector.php +174 -0
- Nextend/Languages/de_DE.mo +0 -0
- Nextend/Languages/de_DE.po +1179 -0
Defines.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if (!defined('NEXTEND_SMARTSLIDER_3_URL_PATH')) {
|
4 |
+
define('NEXTEND_SMARTSLIDER_3_URL_PATH', 'smart-slider3');
|
5 |
+
}
|
6 |
+
|
7 |
+
define('N2WORDPRESS', 1);
|
8 |
+
define('N2JOOMLA', 0);
|
9 |
+
|
10 |
+
define('N2GSAP', 0);
|
11 |
+
define('N2SSPRO', 0);
|
Nextend/Autoloader.php
ADDED
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend;
|
4 |
+
|
5 |
+
class Autoloader {
|
6 |
+
|
7 |
+
private static $instance = null;
|
8 |
+
|
9 |
+
private $aliases = array(
|
10 |
+
'N2Data' => '\\Nextend\\Framework\\Data\\Data',
|
11 |
+
'N2SmartSliderBackup' => '\\Nextend\\SmartSlider3\\BackupSlider\\BackupData',
|
12 |
+
'N2SmartSliderImport' => '\\Nextend\\SmartSlider3\\BackupSlider\\ImportSlider',
|
13 |
+
'N2SmartSliderExport' => '\\Nextend\\SmartSlider3\\BackupSlider\\ExportSlider',
|
14 |
+
);
|
15 |
+
|
16 |
+
/**
|
17 |
+
* An associative array where the key is a namespace prefix and the value
|
18 |
+
* is an array of base directories for classes in that namespace.
|
19 |
+
*
|
20 |
+
* @var array
|
21 |
+
*/
|
22 |
+
protected $prefixes = array();
|
23 |
+
|
24 |
+
public function __construct() {
|
25 |
+
$this->addNamespace('Nextend\\', dirname(__FILE__));
|
26 |
+
|
27 |
+
|
28 |
+
$this->register();
|
29 |
+
|
30 |
+
$currentPath = dirname(__FILE__) . '/';
|
31 |
+
foreach (scandir($currentPath) as $file) {
|
32 |
+
if ($file == '.' || $file == '..') continue;
|
33 |
+
$path = $currentPath . $file;
|
34 |
+
if (is_dir($path)) {
|
35 |
+
|
36 |
+
$className = '\\Nextend\\' . $file . '\\' . $file;
|
37 |
+
|
38 |
+
if (class_exists($className) && is_callable(array(
|
39 |
+
$className,
|
40 |
+
'getInstance'
|
41 |
+
))) {
|
42 |
+
call_user_func_array(array(
|
43 |
+
$className,
|
44 |
+
'getInstance'
|
45 |
+
), array());
|
46 |
+
}
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
Nextend::getInstance();
|
51 |
+
}
|
52 |
+
|
53 |
+
public static function getInstance() {
|
54 |
+
if (self::$instance == null) {
|
55 |
+
self::$instance = new Autoloader();
|
56 |
+
}
|
57 |
+
|
58 |
+
return self::$instance;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Register loader with SPL autoloader stack.
|
63 |
+
*
|
64 |
+
* @return void
|
65 |
+
*/
|
66 |
+
public function register() {
|
67 |
+
spl_autoload_register(array(
|
68 |
+
$this,
|
69 |
+
'loadClass'
|
70 |
+
));
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Adds a base directory for a namespace prefix.
|
75 |
+
*
|
76 |
+
* @param string $prefix The namespace prefix.
|
77 |
+
* @param string $base_dir A base directory for class files in the
|
78 |
+
* namespace.
|
79 |
+
* @param bool $prepend If true, prepend the base directory to the stack
|
80 |
+
* instead of appending it; this causes it to be searched first rather
|
81 |
+
* than last.
|
82 |
+
*
|
83 |
+
* @return void
|
84 |
+
*/
|
85 |
+
public function addNamespace($prefix, $base_dir, $prepend = false) {
|
86 |
+
// normalize namespace prefix
|
87 |
+
$prefix = trim($prefix, '\\') . '\\';
|
88 |
+
|
89 |
+
// normalize the base directory with a trailing separator
|
90 |
+
$base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';
|
91 |
+
|
92 |
+
// initialize the namespace prefix array
|
93 |
+
if (isset($this->prefixes[$prefix]) === false) {
|
94 |
+
$this->prefixes[$prefix] = array();
|
95 |
+
}
|
96 |
+
|
97 |
+
// retain the base directory for the namespace prefix
|
98 |
+
if ($prepend) {
|
99 |
+
array_unshift($this->prefixes[$prefix], $base_dir);
|
100 |
+
} else {
|
101 |
+
array_push($this->prefixes[$prefix], $base_dir);
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Loads the class file for a given class name.
|
107 |
+
*
|
108 |
+
* @param string $class The fully-qualified class name.
|
109 |
+
*
|
110 |
+
* @return mixed The mapped file name on success, or boolean false on
|
111 |
+
* failure.
|
112 |
+
*/
|
113 |
+
public function loadClass($class) {
|
114 |
+
// the current namespace prefix
|
115 |
+
$prefix = $class;
|
116 |
+
|
117 |
+
// work backwards through the namespace names of the fully-qualified
|
118 |
+
// class name to find a mapped file name
|
119 |
+
while (false !== $pos = strrpos($prefix, '\\')) {
|
120 |
+
|
121 |
+
// retain the trailing namespace separator in the prefix
|
122 |
+
$prefix = substr($class, 0, $pos + 1);
|
123 |
+
|
124 |
+
// the rest is the relative class name
|
125 |
+
$relative_class = substr($class, $pos + 1);
|
126 |
+
|
127 |
+
// try to load a mapped file for the prefix and relative class
|
128 |
+
$mapped_file = $this->loadMappedFile($prefix, $relative_class);
|
129 |
+
if ($mapped_file) {
|
130 |
+
return $mapped_file;
|
131 |
+
}
|
132 |
+
|
133 |
+
// remove the trailing namespace separator for the next iteration
|
134 |
+
// of strrpos()
|
135 |
+
$prefix = rtrim($prefix, '\\');
|
136 |
+
}
|
137 |
+
|
138 |
+
if (isset($this->aliases[$class]) && class_exists($this->aliases[$class])) {
|
139 |
+
/**
|
140 |
+
* Create class alias for old class names
|
141 |
+
*/
|
142 |
+
class_alias($this->aliases[$class], $class);
|
143 |
+
|
144 |
+
return true;
|
145 |
+
}
|
146 |
+
|
147 |
+
// never found a mapped file
|
148 |
+
return false;
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Load the mapped file for a namespace prefix and relative class.
|
153 |
+
*
|
154 |
+
* @param string $prefix The namespace prefix.
|
155 |
+
* @param string $relative_class The relative class name.
|
156 |
+
*
|
157 |
+
* @return mixed Boolean false if no mapped file can be loaded, or the
|
158 |
+
* name of the mapped file that was loaded.
|
159 |
+
*/
|
160 |
+
protected function loadMappedFile($prefix, $relative_class) {
|
161 |
+
// are there any base directories for this namespace prefix?
|
162 |
+
if (isset($this->prefixes[$prefix]) === false) {
|
163 |
+
return false;
|
164 |
+
}
|
165 |
+
|
166 |
+
// look through base directories for this namespace prefix
|
167 |
+
foreach ($this->prefixes[$prefix] as $base_dir) {
|
168 |
+
|
169 |
+
// replace the namespace prefix with the base directory,
|
170 |
+
// replace namespace separators with directory separators
|
171 |
+
// in the relative class name, append with .php
|
172 |
+
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
|
173 |
+
|
174 |
+
// if the mapped file exists, require it
|
175 |
+
if ($this->requireFile($file)) {
|
176 |
+
// yes, we're done
|
177 |
+
return $file;
|
178 |
+
}
|
179 |
+
}
|
180 |
+
|
181 |
+
// never found it
|
182 |
+
return false;
|
183 |
+
}
|
184 |
+
|
185 |
+
/**
|
186 |
+
* If a file exists, require it from the file system.
|
187 |
+
*
|
188 |
+
* @param string $file The file to require.
|
189 |
+
*
|
190 |
+
* @return bool True if the file exists, false if not.
|
191 |
+
*/
|
192 |
+
protected function requireFile($file) {
|
193 |
+
if (file_exists($file)) {
|
194 |
+
require $file;
|
195 |
+
|
196 |
+
return true;
|
197 |
+
}
|
198 |
+
|
199 |
+
return false;
|
200 |
+
}
|
201 |
+
}
|
202 |
+
|
203 |
+
Autoloader::getInstance();
|
Nextend/Framework/Acl/AbstractPlatformAcl.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Acl;
|
4 |
+
|
5 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
6 |
+
|
7 |
+
abstract class AbstractPlatformAcl {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @param $action
|
11 |
+
* @param MVCHelperTrait $MVCHelper
|
12 |
+
*
|
13 |
+
* @return bool
|
14 |
+
*/
|
15 |
+
abstract public function authorise($action, $MVCHelper);
|
16 |
+
}
|
Nextend/Framework/Acl/Acl.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Acl;
|
4 |
+
|
5 |
+
use Nextend\Framework\Acl\Joomla\JoomlaAcl;
|
6 |
+
use Nextend\Framework\Acl\WordPress\WordPressAcl;
|
7 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
8 |
+
|
9 |
+
class Acl {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var AbstractPlatformAcl
|
13 |
+
*/
|
14 |
+
private static $instance;
|
15 |
+
|
16 |
+
public function __construct() {
|
17 |
+
self::$instance = new WordPressAcl();
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @param $action
|
22 |
+
* @param MVCHelperTrait $MVCHelper
|
23 |
+
*
|
24 |
+
* @return bool
|
25 |
+
*/
|
26 |
+
public static function canDo($action, $MVCHelper) {
|
27 |
+
return self::$instance->authorise($action, $MVCHelper);
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
new Acl();
|
Nextend/Framework/Acl/WordPress/WordPressAcl.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Acl\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Acl\AbstractPlatformAcl;
|
6 |
+
use function current_user_can;
|
7 |
+
|
8 |
+
class WordPressAcl extends AbstractPlatformAcl {
|
9 |
+
|
10 |
+
public function authorise($action, $MVCHelper) {
|
11 |
+
return current_user_can($action);
|
12 |
+
}
|
13 |
+
}
|
Nextend/Framework/Api.php
ADDED
@@ -0,0 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework;
|
5 |
+
|
6 |
+
|
7 |
+
use Exception;
|
8 |
+
use JHttp;
|
9 |
+
use Nextend\Framework\Misc\Base64;
|
10 |
+
use Nextend\Framework\Misc\HttpClient;
|
11 |
+
use Nextend\Framework\Notification\Notification;
|
12 |
+
use Nextend\Framework\Platform\Platform;
|
13 |
+
use Nextend\Framework\Url\Url;
|
14 |
+
use Nextend\Framework\View\Html;
|
15 |
+
use Nextend\SmartSlider3\Application\ApplicationSmartSlider3;
|
16 |
+
|
17 |
+
class Api {
|
18 |
+
|
19 |
+
private static $api = 'https://api.nextendweb.com/v1/';
|
20 |
+
|
21 |
+
public static function getApiUrl() {
|
22 |
+
|
23 |
+
return self::$api;
|
24 |
+
}
|
25 |
+
|
26 |
+
public static function api($posts, $returnUrl = false) {
|
27 |
+
|
28 |
+
$api = self::getApiUrl();
|
29 |
+
|
30 |
+
$posts_default = array(
|
31 |
+
'platform' => Platform::getName()
|
32 |
+
);
|
33 |
+
|
34 |
+
$posts = $posts + $posts_default;
|
35 |
+
|
36 |
+
if ($returnUrl) {
|
37 |
+
return $api . '?' . http_build_query($posts, '', '&');
|
38 |
+
}
|
39 |
+
|
40 |
+
if (!isset($data)) {
|
41 |
+
if (function_exists('curl_init') && function_exists('curl_exec') && Settings::get('curl', 1)) {
|
42 |
+
$ch = curl_init();
|
43 |
+
curl_setopt($ch, CURLOPT_URL, $api);
|
44 |
+
|
45 |
+
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($posts, '', '&'));
|
46 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
47 |
+
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
|
48 |
+
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
49 |
+
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)');
|
50 |
+
curl_setopt($ch, CURLOPT_REFERER, $_SERVER['REQUEST_URI']);
|
51 |
+
$proxy = new \WP_HTTP_Proxy();
|
52 |
+
|
53 |
+
if ($proxy->is_enabled() && $proxy->send_through_proxy($api)) {
|
54 |
+
|
55 |
+
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
56 |
+
|
57 |
+
curl_setopt($ch, CURLOPT_PROXY, $proxy->host());
|
58 |
+
|
59 |
+
curl_setopt($ch, CURLOPT_PROXYPORT, $proxy->port());
|
60 |
+
|
61 |
+
|
62 |
+
if ($proxy->use_authentication()) {
|
63 |
+
|
64 |
+
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
65 |
+
|
66 |
+
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxy->authentication());
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
|
71 |
+
if (Settings::get('curl-clean-proxy', 0)) {
|
72 |
+
curl_setopt($ch, CURLOPT_PROXY, '');
|
73 |
+
}
|
74 |
+
$data = curl_exec($ch);
|
75 |
+
$errorNumber = curl_errno($ch);
|
76 |
+
if ($errorNumber == 60 || $errorNumber == 77) {
|
77 |
+
curl_setopt($ch, CURLOPT_CAINFO, HttpClient::getCacertPath());
|
78 |
+
$data = curl_exec($ch);
|
79 |
+
}
|
80 |
+
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
|
81 |
+
$error = curl_error($ch);
|
82 |
+
$curlErrorNumber = curl_errno($ch);
|
83 |
+
curl_close($ch);
|
84 |
+
|
85 |
+
if ($curlErrorNumber) {
|
86 |
+
$href = ApplicationSmartSlider3::getInstance()
|
87 |
+
->getApplicationTypeAdmin()
|
88 |
+
->getUrlHelpCurl();
|
89 |
+
Notification::error(Html::tag('a', array(
|
90 |
+
'href' => $href . '#support-form'
|
91 |
+
), n2_('Debug error')));
|
92 |
+
|
93 |
+
Notification::error($curlErrorNumber . $error);
|
94 |
+
|
95 |
+
return array(
|
96 |
+
'status' => 'ERROR_HANDLED'
|
97 |
+
);
|
98 |
+
}
|
99 |
+
} else {
|
100 |
+
$opts = array(
|
101 |
+
'http' => array(
|
102 |
+
'method' => 'POST',
|
103 |
+
'header' => 'Content-type: application/x-www-form-urlencoded',
|
104 |
+
'content' => http_build_query($posts, '', '&')
|
105 |
+
)
|
106 |
+
);
|
107 |
+
$context = stream_context_create($opts);
|
108 |
+
$data = file_get_contents($api, false, $context);
|
109 |
+
if ($data === false) {
|
110 |
+
Notification::error(n2_('CURL disabled in your php.ini configuration. Please enable it!'));
|
111 |
+
|
112 |
+
return array(
|
113 |
+
'status' => 'ERROR_HANDLED'
|
114 |
+
);
|
115 |
+
}
|
116 |
+
$headers = self::parseHeaders($http_response_header);
|
117 |
+
if ($headers['status'] != '200') {
|
118 |
+
Notification::error(n2_('Unable to contact with the licensing server, please try again later!'));
|
119 |
+
|
120 |
+
return array(
|
121 |
+
'status' => 'ERROR_HANDLED'
|
122 |
+
);
|
123 |
+
}
|
124 |
+
if (isset($headers['content-type'])) {
|
125 |
+
$contentType = $headers['content-type'];
|
126 |
+
}
|
127 |
+
}
|
128 |
+
}
|
129 |
+
|
130 |
+
switch ($contentType) {
|
131 |
+
case 'text/html; charset=UTF-8':
|
132 |
+
|
133 |
+
Notification::error(sprintf('Unexpected response from the API.<br>Contact us (support@nextendweb.com) with the following log:') . '<br><textarea style="width: 100%;height:200px;font-size:8px;">' . Base64::encode($data) . '</textarea>');
|
134 |
+
|
135 |
+
return array(
|
136 |
+
'status' => 'ERROR_HANDLED'
|
137 |
+
);
|
138 |
+
break;
|
139 |
+
case 'application/json':
|
140 |
+
return json_decode($data, true);
|
141 |
+
}
|
142 |
+
|
143 |
+
return $data;
|
144 |
+
}
|
145 |
+
|
146 |
+
private static function parseHeaders(array $headers, $header = null) {
|
147 |
+
$output = array();
|
148 |
+
if ('HTTP' === substr($headers[0], 0, 4)) {
|
149 |
+
list(, $output['status'], $output['status_text']) = explode(' ', $headers[0]);
|
150 |
+
unset($headers[0]);
|
151 |
+
}
|
152 |
+
foreach ($headers as $v) {
|
153 |
+
$h = preg_split('/:\s*/', $v);
|
154 |
+
if (count($h) >= 2) {
|
155 |
+
$output[strtolower($h[0])] = $h[1];
|
156 |
+
}
|
157 |
+
}
|
158 |
+
if (null !== $header) {
|
159 |
+
if (isset($output[strtolower($header)])) {
|
160 |
+
return $output[strtolower($header)];
|
161 |
+
}
|
162 |
+
|
163 |
+
return null;
|
164 |
+
}
|
165 |
+
|
166 |
+
return $output;
|
167 |
+
}
|
168 |
+
}
|
Nextend/Framework/Application/AbstractApplication.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Application;
|
5 |
+
|
6 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
7 |
+
use Nextend\Framework\Plugin;
|
8 |
+
|
9 |
+
abstract class AbstractApplication {
|
10 |
+
|
11 |
+
use SingletonTrait;
|
12 |
+
|
13 |
+
protected $key = '';
|
14 |
+
|
15 |
+
protected function init() {
|
16 |
+
|
17 |
+
//PluggableApplication\Nextend\SmartSlider3\Application\ApplicationSmartSlider3
|
18 |
+
Plugin::doAction('PluggableApplication\\' . get_class($this), array($this));
|
19 |
+
}
|
20 |
+
|
21 |
+
public function getKey() {
|
22 |
+
return $this->key;
|
23 |
+
}
|
24 |
+
|
25 |
+
public function enqueueAssets() {
|
26 |
+
|
27 |
+
}
|
28 |
+
}
|
Nextend/Framework/Application/AbstractApplicationType.php
ADDED
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Application;
|
5 |
+
|
6 |
+
|
7 |
+
use Exception;
|
8 |
+
use Nextend\Framework\Controller\AbstractController;
|
9 |
+
use Nextend\Framework\Pattern\GetAssetsPathTrait;
|
10 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
11 |
+
use Nextend\Framework\Plugin;
|
12 |
+
use Nextend\Framework\Request\Request;
|
13 |
+
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
|
14 |
+
use Nextend\Framework\Router\Router;
|
15 |
+
use Nextend\Framework\View\AbstractLayout;
|
16 |
+
|
17 |
+
abstract class AbstractApplicationType {
|
18 |
+
|
19 |
+
Use GetAssetsPathTrait, MVCHelperTrait;
|
20 |
+
|
21 |
+
/** @var AbstractApplication */
|
22 |
+
protected $application;
|
23 |
+
|
24 |
+
/** @var Router */
|
25 |
+
protected $router;
|
26 |
+
|
27 |
+
protected $key = '';
|
28 |
+
|
29 |
+
/** @var AbstractLayout */
|
30 |
+
protected $layout;
|
31 |
+
|
32 |
+
protected $externalControllers = array();
|
33 |
+
|
34 |
+
/**
|
35 |
+
* AbstractApplicationType constructor.
|
36 |
+
*
|
37 |
+
* @param AbstractApplication $application
|
38 |
+
*
|
39 |
+
* @throws Exception
|
40 |
+
*/
|
41 |
+
public function __construct($application) {
|
42 |
+
|
43 |
+
$this->setMVCHelper($this);
|
44 |
+
|
45 |
+
$this->application = $application;
|
46 |
+
|
47 |
+
ResourceTranslator::createResource('$' . $this->getKey() . '$', self::getAssetsPath(), self::getAssetsUri());
|
48 |
+
|
49 |
+
$this->createRouter();
|
50 |
+
|
51 |
+
|
52 |
+
//PluggableApplicationType\Nextend\SmartSlider3\Application\Admin\ApplicationTypeAdmin
|
53 |
+
Plugin::doAction('PluggableApplicationType\\' . get_class($this), array($this));
|
54 |
+
}
|
55 |
+
|
56 |
+
public function getKey() {
|
57 |
+
return $this->application->getKey() . '-' . $this->key;
|
58 |
+
}
|
59 |
+
|
60 |
+
protected function createRouter() {
|
61 |
+
|
62 |
+
}
|
63 |
+
|
64 |
+
public function processRequest($defaultControllerName, $defaultActionName, $ajax = false, $args = array()) {
|
65 |
+
|
66 |
+
$controllerName = trim(Request::$REQUEST->getCmd("nextendcontroller"));
|
67 |
+
if (empty($controllerName)) {
|
68 |
+
$controllerName = $defaultControllerName;
|
69 |
+
}
|
70 |
+
|
71 |
+
$actionName = trim(Request::$REQUEST->getCmd("nextendaction"));
|
72 |
+
if (empty($actionName)) {
|
73 |
+
$actionName = $defaultActionName;
|
74 |
+
}
|
75 |
+
|
76 |
+
$this->process($controllerName, $actionName, $ajax, $args);
|
77 |
+
}
|
78 |
+
|
79 |
+
public function process($controllerName, $actionName, $ajax = false, $args = array()) {
|
80 |
+
|
81 |
+
if ($ajax) {
|
82 |
+
Request::$isAjax = true;
|
83 |
+
}
|
84 |
+
|
85 |
+
/** @var AbstractController $controller */
|
86 |
+
$controller = $this->getController($controllerName, $ajax);
|
87 |
+
|
88 |
+
$controller->doAction($actionName, $args);
|
89 |
+
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* @param $controllerName
|
94 |
+
* @param bool $ajax
|
95 |
+
*
|
96 |
+
* @return AbstractController
|
97 |
+
*/
|
98 |
+
protected function getController($controllerName, $ajax = false) {
|
99 |
+
|
100 |
+
$methodName = 'getController' . ($ajax ? 'Ajax' : '') . $controllerName;
|
101 |
+
|
102 |
+
if (method_exists($this, $methodName)) {
|
103 |
+
|
104 |
+
return call_user_func(array(
|
105 |
+
$this,
|
106 |
+
$methodName
|
107 |
+
));
|
108 |
+
} else if (isset($this->externalControllers[$controllerName])) {
|
109 |
+
|
110 |
+
return call_user_func(array(
|
111 |
+
$this->externalControllers[$controllerName],
|
112 |
+
$methodName
|
113 |
+
));
|
114 |
+
}
|
115 |
+
|
116 |
+
return $this->getDefaultController($controllerName, $ajax);
|
117 |
+
}
|
118 |
+
|
119 |
+
protected abstract function getDefaultController($controllerName, $ajax = false);
|
120 |
+
|
121 |
+
public function getApplication() {
|
122 |
+
|
123 |
+
return $this->application;
|
124 |
+
}
|
125 |
+
|
126 |
+
public function getApplicationType() {
|
127 |
+
return $this;
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* @return Router
|
132 |
+
*/
|
133 |
+
public function getRouter() {
|
134 |
+
return $this->router;
|
135 |
+
}
|
136 |
+
|
137 |
+
public function enqueueAssets() {
|
138 |
+
|
139 |
+
$this->application->enqueueAssets();
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* @param AbstractLayout $layout
|
144 |
+
*/
|
145 |
+
public function setLayout($layout) {
|
146 |
+
$this->layout = $layout;
|
147 |
+
}
|
148 |
+
|
149 |
+
public function addExternalController($name, $source) {
|
150 |
+
|
151 |
+
$this->externalControllers[$name] = $source;
|
152 |
+
}
|
153 |
+
|
154 |
+
public function getLogo() {
|
155 |
+
|
156 |
+
return file_get_contents(self::getAssetsPath() . '/images/logo.svg');
|
157 |
+
}
|
158 |
+
}
|
Nextend/Framework/Asset/AbstractAsset.php
ADDED
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset;
|
4 |
+
|
5 |
+
use Nextend\Framework\Misc\Base64;
|
6 |
+
|
7 |
+
class AbstractAsset {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @var AbstractCache
|
11 |
+
*/
|
12 |
+
protected $cache;
|
13 |
+
|
14 |
+
protected $files = array();
|
15 |
+
protected $urls = array();
|
16 |
+
protected $codes = array();
|
17 |
+
protected $globalInline = array();
|
18 |
+
protected $firstCodes = array();
|
19 |
+
protected $inline = array();
|
20 |
+
protected $staticGroup = array();
|
21 |
+
|
22 |
+
protected $groups = array();
|
23 |
+
|
24 |
+
public function addFile($pathToFile, $group) {
|
25 |
+
$this->addGroup($group);
|
26 |
+
$this->files[$group][] = $pathToFile;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function addFiles($path, $files, $group) {
|
30 |
+
$this->addGroup($group);
|
31 |
+
foreach ($files AS $file) {
|
32 |
+
$this->files[$group][] = $path . DIRECTORY_SEPARATOR . $file;
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
public function addStaticGroup($file, $group) {
|
37 |
+
$this->staticGroup[$group] = $file;
|
38 |
+
}
|
39 |
+
|
40 |
+
private function addGroup($group) {
|
41 |
+
if (!isset($this->files[$group])) {
|
42 |
+
$this->files[$group] = array();
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
public function addCode($code, $group, $unshift = false) {
|
47 |
+
if (!isset($this->codes[$group])) {
|
48 |
+
$this->codes[$group] = array();
|
49 |
+
}
|
50 |
+
if (!$unshift) {
|
51 |
+
$this->codes[$group][] = $code;
|
52 |
+
} else {
|
53 |
+
array_unshift($this->codes[$group], $code);
|
54 |
+
}
|
55 |
+
}
|
56 |
+
|
57 |
+
public function addUrl($url) {
|
58 |
+
$this->urls[] = $url;
|
59 |
+
}
|
60 |
+
|
61 |
+
public function addFirstCode($code, $unshift = false) {
|
62 |
+
if ($unshift) {
|
63 |
+
array_unshift($this->firstCodes, $code);
|
64 |
+
} else {
|
65 |
+
$this->firstCodes[] = $code;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
|
69 |
+
public function addInline($code, $unshift = false) {
|
70 |
+
if ($unshift) {
|
71 |
+
array_unshift($this->inline, $code);
|
72 |
+
|
73 |
+
} else {
|
74 |
+
$this->inline[] = $code;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
public function addGlobalInline($code, $unshift = false) {
|
79 |
+
if ($unshift) {
|
80 |
+
array_unshift($this->globalInline, $code);
|
81 |
+
} else {
|
82 |
+
$this->globalInline[] = $code;
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
public function loadedFilesEncoded() {
|
87 |
+
return Base64::encode(json_encode(call_user_func_array('array_merge', $this->files) + $this->urls));
|
88 |
+
}
|
89 |
+
|
90 |
+
protected function uniqueFiles() {
|
91 |
+
foreach ($this->files AS $group => &$files) {
|
92 |
+
$this->files[$group] = array_values(array_unique($files));
|
93 |
+
}
|
94 |
+
$this->initGroups();
|
95 |
+
}
|
96 |
+
|
97 |
+
public function removeFiles($notNeededFiles) {
|
98 |
+
foreach ($this->files AS $group => &$files) {
|
99 |
+
$this->files[$group] = array_diff($files, $notNeededFiles);
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
public function initGroups() {
|
104 |
+
$this->groups = array_unique(array_merge(array_keys($this->files), array_keys($this->codes)));
|
105 |
+
|
106 |
+
$skeleton = array_map(array(
|
107 |
+
AbstractAsset::class,
|
108 |
+
'emptyArray'
|
109 |
+
), array_flip($this->groups));
|
110 |
+
|
111 |
+
$this->files += $skeleton;
|
112 |
+
$this->codes += $skeleton;
|
113 |
+
}
|
114 |
+
|
115 |
+
private static function emptyArray() {
|
116 |
+
return array();
|
117 |
+
}
|
118 |
+
|
119 |
+
public function getFiles() {
|
120 |
+
$this->uniqueFiles();
|
121 |
+
|
122 |
+
$files = array();
|
123 |
+
|
124 |
+
if (AssetManager::$cacheAll) {
|
125 |
+
foreach ($this->groups AS $group) {
|
126 |
+
if (isset($this->staticGroup[$group])) continue;
|
127 |
+
$files[$group] = $this->cache->getAssetFile($group, $this->files[$group], $this->codes[$group]);
|
128 |
+
}
|
129 |
+
} else {
|
130 |
+
foreach ($this->groups AS $group) {
|
131 |
+
if (isset($this->staticGroup[$group])) continue;
|
132 |
+
if (in_array($group, AssetManager::$cachedGroups)) {
|
133 |
+
$files[$group] = $this->cache->getAssetFile($group, $this->files[$group], $this->codes[$group]);
|
134 |
+
} else {
|
135 |
+
foreach ($this->files[$group] AS $file) {
|
136 |
+
$files[] = $file;
|
137 |
+
}
|
138 |
+
foreach ($this->codes[$group] AS $code) {
|
139 |
+
array_unshift($this->inline, $code);
|
140 |
+
}
|
141 |
+
}
|
142 |
+
}
|
143 |
+
}
|
144 |
+
|
145 |
+
if (isset($files['n2'])) {
|
146 |
+
return array('n2' => $files['n2']) + $this->staticGroup + $files;
|
147 |
+
}
|
148 |
+
|
149 |
+
return array_merge($files, $this->staticGroup);
|
150 |
+
}
|
151 |
+
|
152 |
+
public function serialize() {
|
153 |
+
return array(
|
154 |
+
'staticGroup' => $this->staticGroup,
|
155 |
+
'files' => $this->files,
|
156 |
+
'urls' => $this->urls,
|
157 |
+
'codes' => $this->codes,
|
158 |
+
'firstCodes' => $this->firstCodes,
|
159 |
+
'inline' => $this->inline,
|
160 |
+
'globalInline' => $this->globalInline
|
161 |
+
);
|
162 |
+
}
|
163 |
+
|
164 |
+
public function unSerialize($array) {
|
165 |
+
$this->staticGroup = array_merge($this->staticGroup, $array['staticGroup']);
|
166 |
+
|
167 |
+
foreach ($array['files'] AS $group => $files) {
|
168 |
+
if (!isset($this->files[$group])) {
|
169 |
+
$this->files[$group] = $files;
|
170 |
+
} else {
|
171 |
+
$this->files[$group] = array_merge($this->files[$group], $files);
|
172 |
+
}
|
173 |
+
}
|
174 |
+
$this->urls = array_merge($this->urls, $array['urls']);
|
175 |
+
|
176 |
+
foreach ($array['codes'] AS $group => $codes) {
|
177 |
+
if (!isset($this->codes[$group])) {
|
178 |
+
$this->codes[$group] = $codes;
|
179 |
+
} else {
|
180 |
+
$this->codes[$group] = array_merge($this->codes[$group], $codes);
|
181 |
+
}
|
182 |
+
}
|
183 |
+
|
184 |
+
$this->firstCodes = array_merge($this->firstCodes, $array['firstCodes']);
|
185 |
+
$this->inline = array_merge($this->inline, $array['inline']);
|
186 |
+
$this->globalInline = array_merge($this->globalInline, $array['globalInline']);
|
187 |
+
}
|
188 |
+
}
|
Nextend/Framework/Asset/AbstractCache.php
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset;
|
4 |
+
|
5 |
+
use Nextend\Framework\Cache\Manifest;
|
6 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
7 |
+
|
8 |
+
abstract class AbstractCache {
|
9 |
+
|
10 |
+
public $outputFileType;
|
11 |
+
|
12 |
+
protected $group, $files, $codes;
|
13 |
+
|
14 |
+
public function getAssetFile($group, &$files = array(), &$codes = array()) {
|
15 |
+
$this->group = $group;
|
16 |
+
$this->files = $files;
|
17 |
+
$this->codes = $codes;
|
18 |
+
|
19 |
+
$cache = new Manifest($group, true, true);
|
20 |
+
$hash = $this->getHash();
|
21 |
+
|
22 |
+
return $cache->makeCache($group . "." . $this->outputFileType, $hash, array(
|
23 |
+
$this,
|
24 |
+
'getCachedContent'
|
25 |
+
));
|
26 |
+
}
|
27 |
+
|
28 |
+
protected function getHash() {
|
29 |
+
$hash = '';
|
30 |
+
foreach ($this->files AS $file) {
|
31 |
+
$hash .= $this->makeFileHash($file);
|
32 |
+
}
|
33 |
+
foreach ($this->codes AS $code) {
|
34 |
+
$hash .= $code;
|
35 |
+
}
|
36 |
+
|
37 |
+
return md5($hash);
|
38 |
+
}
|
39 |
+
|
40 |
+
protected function getCacheFileName() {
|
41 |
+
$hash = '';
|
42 |
+
foreach ($this->files AS $file) {
|
43 |
+
$hash .= $this->makeFileHash($file);
|
44 |
+
}
|
45 |
+
foreach ($this->codes AS $code) {
|
46 |
+
$hash .= $code;
|
47 |
+
}
|
48 |
+
|
49 |
+
return md5($hash) . "." . $this->outputFileType;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @param Manifest $cache
|
54 |
+
*
|
55 |
+
* @return string
|
56 |
+
*/
|
57 |
+
public function getCachedContent($cache) {
|
58 |
+
$fileContents = '';
|
59 |
+
foreach ($this->files AS $file) {
|
60 |
+
$fileContents .= $this->parseFile($cache, Filesystem::readFile($file), $file) . "\n";
|
61 |
+
}
|
62 |
+
|
63 |
+
foreach ($this->codes AS $code) {
|
64 |
+
$fileContents .= $code . "\n";
|
65 |
+
}
|
66 |
+
|
67 |
+
return $fileContents;
|
68 |
+
}
|
69 |
+
|
70 |
+
protected function makeFileHash($file) {
|
71 |
+
return $file . filemtime($file);
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* @param Manifest $cache
|
76 |
+
* @param $content
|
77 |
+
* @param $originalFilePath
|
78 |
+
*
|
79 |
+
* @return mixed
|
80 |
+
*/
|
81 |
+
protected function parseFile($cache, $content, $originalFilePath) {
|
82 |
+
return $content;
|
83 |
+
}
|
84 |
+
|
85 |
+
}
|
Nextend/Framework/Asset/AssetManager.php
ADDED
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset;
|
4 |
+
|
5 |
+
use Nextend\Framework\PageFlow;
|
6 |
+
use Nextend\Framework\Plugin;
|
7 |
+
use Nextend\Framework\View\Html;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Class Manager
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
class AssetManager {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @var CSS\Asset
|
17 |
+
*/
|
18 |
+
public static $css;
|
19 |
+
|
20 |
+
private static $cssStack = array();
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var Css\Less\Asset
|
24 |
+
*/
|
25 |
+
public static $less;
|
26 |
+
|
27 |
+
private static $lessStack = array();
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @var Js\Asset
|
31 |
+
*/
|
32 |
+
public static $js;
|
33 |
+
|
34 |
+
private static $jsStack = array();
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @var Fonts\Google\Asset
|
38 |
+
*/
|
39 |
+
public static $googleFonts;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @var Image\Asset
|
43 |
+
*/
|
44 |
+
public static $image;
|
45 |
+
|
46 |
+
private static $imageStack = array();
|
47 |
+
|
48 |
+
private static $googleFontsStack = array();
|
49 |
+
|
50 |
+
public static $cacheAll = true;
|
51 |
+
|
52 |
+
public static $cachedGroups = array();
|
53 |
+
|
54 |
+
public static function getInstance() {
|
55 |
+
static $instance = null;
|
56 |
+
if (null === $instance) {
|
57 |
+
$instance = new self();
|
58 |
+
self::createStack();
|
59 |
+
|
60 |
+
Plugin::doAction('n2_assets_manager_started');
|
61 |
+
}
|
62 |
+
|
63 |
+
return $instance;
|
64 |
+
}
|
65 |
+
|
66 |
+
public static function createStack() {
|
67 |
+
|
68 |
+
self::$css = new Css\Asset();
|
69 |
+
array_unshift(self::$cssStack, self::$css);
|
70 |
+
|
71 |
+
self::$less = new Css\Less\Asset();
|
72 |
+
array_unshift(self::$lessStack, self::$less);
|
73 |
+
|
74 |
+
self::$js = new Js\Asset();
|
75 |
+
array_unshift(self::$jsStack, self::$js);
|
76 |
+
|
77 |
+
self::$googleFonts = new Fonts\Google\Asset();
|
78 |
+
array_unshift(self::$googleFontsStack, self::$googleFonts);
|
79 |
+
|
80 |
+
self::$image = new Image\Asset();
|
81 |
+
array_unshift(self::$imageStack, self::$image);
|
82 |
+
}
|
83 |
+
|
84 |
+
public static function removeStack() {
|
85 |
+
if (count(self::$cssStack) > 0) {
|
86 |
+
/**
|
87 |
+
* @var $previousCSS Css\Asset
|
88 |
+
* @var $previousLESS Css\Less\Asset
|
89 |
+
* @var $previousJS Js\Asset
|
90 |
+
* @var $previousGoogleFons Fonts\Google\Asset
|
91 |
+
* @var $previousImage Image\Asset
|
92 |
+
*/
|
93 |
+
$previousCSS = array_shift(self::$cssStack);
|
94 |
+
self::$css = self::$cssStack[0];
|
95 |
+
|
96 |
+
$previousLESS = array_shift(self::$lessStack);
|
97 |
+
self::$less = self::$lessStack[0];
|
98 |
+
|
99 |
+
$previousJS = array_shift(self::$jsStack);
|
100 |
+
self::$js = self::$jsStack[0];
|
101 |
+
|
102 |
+
$previousGoogleFons = array_shift(self::$googleFontsStack);
|
103 |
+
self::$googleFonts = self::$googleFontsStack[0];
|
104 |
+
|
105 |
+
$previousImage = array_shift(self::$imageStack);
|
106 |
+
self::$image = self::$imageStack[0];
|
107 |
+
|
108 |
+
return array(
|
109 |
+
'css' => $previousCSS->serialize(),
|
110 |
+
'less' => $previousLESS->serialize(),
|
111 |
+
'js' => $previousJS->serialize(),
|
112 |
+
'googleFonts' => $previousGoogleFons->serialize(),
|
113 |
+
'image' => $previousImage->serialize()
|
114 |
+
);
|
115 |
+
}
|
116 |
+
|
117 |
+
echo "Too much remove stack on the asset manager...";
|
118 |
+
PageFlow::exitApplication();
|
119 |
+
|
120 |
+
}
|
121 |
+
|
122 |
+
public static function enableCacheAll() {
|
123 |
+
self::$cacheAll = true;
|
124 |
+
}
|
125 |
+
|
126 |
+
public static function disableCacheAll() {
|
127 |
+
self::$cacheAll = false;
|
128 |
+
}
|
129 |
+
|
130 |
+
public static function addCachedGroup($group) {
|
131 |
+
if (!in_array($group, self::$cachedGroups)) {
|
132 |
+
self::$cachedGroups[] = $group;
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
public static function loadFromArray($array) {
|
137 |
+
|
138 |
+
self::$css->unSerialize($array['css']);
|
139 |
+
self::$less->unSerialize($array['less']);
|
140 |
+
self::$js->unSerialize($array['js']);
|
141 |
+
self::$googleFonts->unSerialize($array['googleFonts']);
|
142 |
+
self::$image->unSerialize($array['image']);
|
143 |
+
}
|
144 |
+
|
145 |
+
public static function getCSS($path = false) {
|
146 |
+
if (self::$css) {
|
147 |
+
if ($path) {
|
148 |
+
return self::$css->get();
|
149 |
+
}
|
150 |
+
|
151 |
+
return self::$css->getOutput();
|
152 |
+
}
|
153 |
+
|
154 |
+
return '';
|
155 |
+
}
|
156 |
+
|
157 |
+
public static function getJs($path = false) {
|
158 |
+
if (self::$js) {
|
159 |
+
if ($path) {
|
160 |
+
return self::$js->get();
|
161 |
+
}
|
162 |
+
|
163 |
+
return self::$js->getOutput();
|
164 |
+
}
|
165 |
+
|
166 |
+
return '';
|
167 |
+
}
|
168 |
+
|
169 |
+
public static function generateAjaxCSS() {
|
170 |
+
|
171 |
+
return Html::style(self::$css->getAjaxOutput());
|
172 |
+
}
|
173 |
+
|
174 |
+
|
175 |
+
public static function generateAjaxJS() {
|
176 |
+
|
177 |
+
return self::$js->getAjaxOutput();
|
178 |
+
}
|
179 |
+
|
180 |
+
}
|
Nextend/Framework/Asset/Css/Asset.php
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset\Css;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\AbstractAsset;
|
6 |
+
use Nextend\Framework\Asset\Fonts\Google\Google;
|
7 |
+
use Nextend\Framework\Plugin;
|
8 |
+
use Nextend\Framework\Settings;
|
9 |
+
use Nextend\Framework\Url\Url;
|
10 |
+
use Nextend\Framework\View\Html;
|
11 |
+
use Nextend\SmartSlider3\SmartSlider3Info;
|
12 |
+
|
13 |
+
class Asset extends AbstractAsset {
|
14 |
+
|
15 |
+
public function __construct() {
|
16 |
+
$this->cache = new Cache();
|
17 |
+
}
|
18 |
+
|
19 |
+
public function getOutput() {
|
20 |
+
|
21 |
+
Google::build();
|
22 |
+
|
23 |
+
Less\Less::build();
|
24 |
+
|
25 |
+
$output = "";
|
26 |
+
|
27 |
+
$this->urls = array_unique($this->urls);
|
28 |
+
|
29 |
+
foreach ($this->urls as $url) {
|
30 |
+
$output .= Html::style($this->filterSrc($url), true, array(
|
31 |
+
'media' => 'all'
|
32 |
+
)) . "\n";
|
33 |
+
}
|
34 |
+
|
35 |
+
$needProtocol = !Settings::get('protocol-relative', '1');
|
36 |
+
|
37 |
+
foreach ($this->getFiles() as $file) {
|
38 |
+
if (substr($file, 0, 2) == '//') {
|
39 |
+
$output .= Html::style($this->filterSrc($file), true, array(
|
40 |
+
'media' => 'all'
|
41 |
+
)) . "\n";
|
42 |
+
} else {
|
43 |
+
$output .= Html::style($this->filterSrc(Url::pathToUri($file, $needProtocol) . '?ver=' . SmartSlider3Info::$revisionShort), true, array(
|
44 |
+
'media' => 'all'
|
45 |
+
)) . "\n";
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
$inline = implode("\n", $this->inline);
|
50 |
+
if (!empty($inline)) {
|
51 |
+
$output .= Html::style($inline);
|
52 |
+
}
|
53 |
+
|
54 |
+
return $output;
|
55 |
+
}
|
56 |
+
|
57 |
+
private function filterSrc($src) {
|
58 |
+
return Plugin::applyFilters('n2_style_loader_src', $src);
|
59 |
+
}
|
60 |
+
|
61 |
+
public function get() {
|
62 |
+
Google::build();
|
63 |
+
Less\Less::build();
|
64 |
+
|
65 |
+
return array(
|
66 |
+
'url' => $this->urls,
|
67 |
+
'files' => $this->getFiles(),
|
68 |
+
'inline' => implode("\n", $this->inline)
|
69 |
+
);
|
70 |
+
}
|
71 |
+
|
72 |
+
public function getAjaxOutput() {
|
73 |
+
|
74 |
+
$output = implode("\n", $this->inline);
|
75 |
+
|
76 |
+
return $output;
|
77 |
+
}
|
78 |
+
}
|
Nextend/Framework/Asset/Css/Cache.php
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset\Css;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\AbstractCache;
|
6 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
7 |
+
use Nextend\Framework\Url\Url;
|
8 |
+
|
9 |
+
class Cache extends AbstractCache {
|
10 |
+
|
11 |
+
public $outputFileType = "css";
|
12 |
+
|
13 |
+
private $baseUrl = '';
|
14 |
+
|
15 |
+
private $basePath = '';
|
16 |
+
|
17 |
+
public function getAssetFileFolder() {
|
18 |
+
return Filesystem::getWebCachePath() . DIRECTORY_SEPARATOR . $this->group . DIRECTORY_SEPARATOR;
|
19 |
+
}
|
20 |
+
|
21 |
+
protected function parseFile($cache, $content, $originalFilePath) {
|
22 |
+
|
23 |
+
$this->basePath = dirname($originalFilePath);
|
24 |
+
$this->baseUrl = Filesystem::pathToAbsoluteURL($this->basePath);
|
25 |
+
|
26 |
+
return preg_replace_callback('#url\([\'"]?([^"\'\)]+)[\'"]?\)#', array(
|
27 |
+
$this,
|
28 |
+
'makeAbsoluteUrl'
|
29 |
+
), $content);
|
30 |
+
}
|
31 |
+
|
32 |
+
private function makeAbsoluteUrl($matches) {
|
33 |
+
if (substr($matches[1], 0, 5) == 'data:') return $matches[0];
|
34 |
+
if (substr($matches[1], 0, 4) == 'http') return $matches[0];
|
35 |
+
if (substr($matches[1], 0, 2) == '//') return $matches[0];
|
36 |
+
|
37 |
+
$exploded = explode('?', $matches[1]);
|
38 |
+
|
39 |
+
$realPath = realpath($this->basePath . '/' . $exploded[0]);
|
40 |
+
if ($realPath === false) {
|
41 |
+
return 'url(' . str_replace(array(
|
42 |
+
'http://',
|
43 |
+
'https://'
|
44 |
+
), '//', $this->baseUrl) . '/' . $matches[1] . ')';
|
45 |
+
}
|
46 |
+
|
47 |
+
$realPath = Filesystem::convertToRealDirectorySeparator($realPath);
|
48 |
+
|
49 |
+
return 'url(' . Url::pathToUri($realPath, false) . (isset($exploded[1]) ? '?' . $exploded[1] : '') . ')';
|
50 |
+
}
|
51 |
+
}
|
Nextend/Framework/Asset/Css/Css.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset\Css;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\AssetManager;
|
6 |
+
|
7 |
+
class Css {
|
8 |
+
|
9 |
+
public static function addFile($pathToFile, $group) {
|
10 |
+
AssetManager::$css->addFile($pathToFile, $group);
|
11 |
+
}
|
12 |
+
|
13 |
+
public static function addFiles($path, $files, $group) {
|
14 |
+
AssetManager::$css->addFiles($path, $files, $group);
|
15 |
+
}
|
16 |
+
|
17 |
+
public static function addStaticGroup($file, $group) {
|
18 |
+
AssetManager::$css->addStaticGroup($file, $group);
|
19 |
+
}
|
20 |
+
|
21 |
+
public static function addCode($code, $group, $unshift = false) {
|
22 |
+
AssetManager::$css->addCode($code, $group, $unshift);
|
23 |
+
}
|
24 |
+
|
25 |
+
public static function addUrl($url) {
|
26 |
+
AssetManager::$css->addUrl($url);
|
27 |
+
}
|
28 |
+
|
29 |
+
public static function addInline($code) {
|
30 |
+
AssetManager::$css->addInline($code);
|
31 |
+
}
|
32 |
+
}
|
Nextend/Framework/Asset/Css/Less/Asset.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset\Css\Less;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\AbstractAsset;
|
6 |
+
|
7 |
+
class Asset extends AbstractAsset {
|
8 |
+
|
9 |
+
public function __construct() {
|
10 |
+
$this->cache = new Cache();
|
11 |
+
}
|
12 |
+
|
13 |
+
protected function uniqueFiles() {
|
14 |
+
$this->initGroups();
|
15 |
+
}
|
16 |
+
|
17 |
+
public function getFiles() {
|
18 |
+
$this->uniqueFiles();
|
19 |
+
|
20 |
+
$files = array();
|
21 |
+
foreach ($this->groups AS $group) {
|
22 |
+
$files[$group] = $this->cache->getAssetFile($group, $this->files[$group], $this->codes[$group]);
|
23 |
+
}
|
24 |
+
|
25 |
+
return $files;
|
26 |
+
}
|
27 |
+
}
|
Nextend/Framework/Asset/Css/Less/Cache.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset\Css\Less;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
use Nextend\Framework\Cache\Manifest;
|
7 |
+
|
8 |
+
class Cache extends \Nextend\Framework\Asset\Css\Cache {
|
9 |
+
|
10 |
+
|
11 |
+
public $outputFileType = "less.css";
|
12 |
+
|
13 |
+
public function getAssetFile($group, &$files = array(), &$codes = array()) {
|
14 |
+
$this->group = $group;
|
15 |
+
$this->files = $files;
|
16 |
+
$this->codes = $codes;
|
17 |
+
|
18 |
+
$cache = new Manifest($group, false, true);
|
19 |
+
$hash = $this->getHash();
|
20 |
+
|
21 |
+
return $cache->makeCache($group . "." . $this->outputFileType, $hash, array(
|
22 |
+
$this,
|
23 |
+
'getCachedContent'
|
24 |
+
));
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @param Manifest $cache
|
29 |
+
*
|
30 |
+
* @return string
|
31 |
+
* @throws Exception
|
32 |
+
*/
|
33 |
+
public function getCachedContent($cache) {
|
34 |
+
|
35 |
+
$fileContents = '';
|
36 |
+
|
37 |
+
foreach ($this->files AS $parameters) {
|
38 |
+
$compiler = new LessCompiler();
|
39 |
+
|
40 |
+
if (!empty($parameters['importDir'])) {
|
41 |
+
$compiler->addImportDir($parameters['importDir']);
|
42 |
+
}
|
43 |
+
|
44 |
+
$compiler->setVariables($parameters['context']);
|
45 |
+
$fileContents .= $compiler->compileFile($parameters['file']);
|
46 |
+
}
|
47 |
+
|
48 |
+
return $fileContents;
|
49 |
+
}
|
50 |
+
|
51 |
+
protected function makeFileHash($parameters) {
|
52 |
+
return json_encode($parameters) . filemtime($parameters['file']);
|
53 |
+
}
|
54 |
+
|
55 |
+
protected function parseFile($cache, $content, $lessParameters) {
|
56 |
+
|
57 |
+
return parent::parseFile($cache, $content, $lessParameters['file']);
|
58 |
+
}
|
59 |
+
}
|
Nextend/Framework/Asset/Css/Less/Formatter/Classic.php
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Asset\Css\Less\Formatter;
|
5 |
+
|
6 |
+
|
7 |
+
class Classic {
|
8 |
+
|
9 |
+
public $indentChar = " ";
|
10 |
+
|
11 |
+
public $break = "\n";
|
12 |
+
public $open = " {";
|
13 |
+
public $close = "}";
|
14 |
+
public $selectorSeparator = ", ";
|
15 |
+
public $assignSeparator = ":";
|
16 |
+
|
17 |
+
public $openSingle = " { ";
|
18 |
+
public $closeSingle = " }";
|
19 |
+
|
20 |
+
public $disableSingle = false;
|
21 |
+
public $breakSelectors = false;
|
22 |
+
|
23 |
+
public $compressColors = false;
|
24 |
+
|
25 |
+
public function __construct() {
|
26 |
+
$this->indentLevel = 0;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function indentStr($n = 0) {
|
30 |
+
return str_repeat($this->indentChar, max($this->indentLevel + $n, 0));
|
31 |
+
}
|
32 |
+
|
33 |
+
public function property($name, $value) {
|
34 |
+
return $name . $this->assignSeparator . $value . ";";
|
35 |
+
}
|
36 |
+
|
37 |
+
protected function isEmpty($block) {
|
38 |
+
if (empty($block->lines)) {
|
39 |
+
foreach ($block->children as $child) {
|
40 |
+
if (!$this->isEmpty($child)) return false;
|
41 |
+
}
|
42 |
+
|
43 |
+
return true;
|
44 |
+
}
|
45 |
+
|
46 |
+
return false;
|
47 |
+
}
|
48 |
+
|
49 |
+
public function block($block) {
|
50 |
+
$ret = '';
|
51 |
+
if ($this->isEmpty($block)) return $ret;
|
52 |
+
|
53 |
+
$inner = $pre = $this->indentStr();
|
54 |
+
|
55 |
+
$isSingle = !$this->disableSingle && is_null($block->type) && count($block->lines) == 1;
|
56 |
+
|
57 |
+
if (!empty($block->selectors)) {
|
58 |
+
$this->indentLevel++;
|
59 |
+
|
60 |
+
if ($this->breakSelectors) {
|
61 |
+
$selectorSeparator = $this->selectorSeparator . $this->break . $pre;
|
62 |
+
} else {
|
63 |
+
$selectorSeparator = $this->selectorSeparator;
|
64 |
+
}
|
65 |
+
|
66 |
+
$ret .= $pre . implode($selectorSeparator, $block->selectors);
|
67 |
+
if ($isSingle) {
|
68 |
+
$ret .= $this->openSingle;
|
69 |
+
$inner = "";
|
70 |
+
} else {
|
71 |
+
$ret .= $this->open . $this->break;
|
72 |
+
$inner = $this->indentStr();
|
73 |
+
}
|
74 |
+
|
75 |
+
}
|
76 |
+
|
77 |
+
if (!empty($block->lines)) {
|
78 |
+
$glue = $this->break . $inner;
|
79 |
+
$ret .= $inner . implode($glue, $block->lines);
|
80 |
+
if (!$isSingle && !empty($block->children)) {
|
81 |
+
$ret .= $this->break;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
foreach ($block->children as $child) {
|
86 |
+
$ret .= $this->block($child);
|
87 |
+
}
|
88 |
+
|
89 |
+
if (!empty($block->selectors)) {
|
90 |
+
if (!$isSingle && empty($block->children)) $ret .= $this->break;
|
91 |
+
|
92 |
+
if ($isSingle) {
|
93 |
+
$ret .= $this->closeSingle . $this->break;
|
94 |
+
} else {
|
95 |
+
$ret .= $pre . $this->close . $this->break;
|
96 |
+
}
|
97 |
+
|
98 |
+
$this->indentLevel--;
|
99 |
+
}
|
100 |
+
|
101 |
+
return $ret;
|
102 |
+
}
|
103 |
+
}
|
Nextend/Framework/Asset/Css/Less/Formatter/Compressed.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Asset\Css\Less\Formatter;
|
5 |
+
|
6 |
+
|
7 |
+
class Compressed extends Classic {
|
8 |
+
|
9 |
+
public $disableSingle = true;
|
10 |
+
public $open = "{";
|
11 |
+
public $selectorSeparator = ",";
|
12 |
+
public $assignSeparator = ":";
|
13 |
+
public $break = "";
|
14 |
+
public $compressColors = true;
|
15 |
+
|
16 |
+
public function indentStr($n = 0) {
|
17 |
+
return "";
|
18 |
+
}
|
19 |
+
}
|
Nextend/Framework/Asset/Css/Less/Formatter/Debug.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Asset\Css\Less\Formatter;
|
5 |
+
|
6 |
+
|
7 |
+
class Debug extends Classic {
|
8 |
+
|
9 |
+
public $disableSingle = true;
|
10 |
+
public $breakSelectors = true;
|
11 |
+
public $assignSeparator = ": ";
|
12 |
+
public $selectorSeparator = ",";
|
13 |
+
}
|
Nextend/Framework/Asset/Css/Less/Less.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Asset\Css\Less;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\AssetManager;
|
8 |
+
use Nextend\Framework\Asset\Css\Css;
|
9 |
+
|
10 |
+
class Less {
|
11 |
+
|
12 |
+
public static function addFile($pathToFile, $group, $context = array(), $importDir = null) {
|
13 |
+
AssetManager::$less->addFile(array(
|
14 |
+
'file' => $pathToFile,
|
15 |
+
'context' => $context,
|
16 |
+
'importDir' => $importDir
|
17 |
+
), $group);
|
18 |
+
}
|
19 |
+
|
20 |
+
public static function build() {
|
21 |
+
foreach (AssetManager::$less->getFiles() AS $group => $file) {
|
22 |
+
if (substr($file, 0, 2) == '//') {
|
23 |
+
Css::addUrl($file);
|
24 |
+
} else if (!realpath($file)) {
|
25 |
+
// For database cache the $file contains the content of the generated CSS file
|
26 |
+
Css::addCode($file, $group, true);
|
27 |
+
} else {
|
28 |
+
Css::addFile($file, $group);
|
29 |
+
}
|
30 |
+
}
|
31 |
+
}
|
32 |
+
}
|
Nextend/Framework/Asset/Css/Less/LessCompiler.php
ADDED
@@ -0,0 +1,2232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset\Css\Less;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
use Nextend\Framework\Asset\Css\Less\Formatter\Classic;
|
7 |
+
use Nextend\Framework\Asset\Css\Less\Formatter\Compressed;
|
8 |
+
use Nextend\Framework\Asset\Css\Less\Formatter\Debug;
|
9 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
10 |
+
use stdClass;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* The less compiler and parser.
|
14 |
+
*
|
15 |
+
* Converting LESS to CSS is a three stage process. The incoming file is parsed
|
16 |
+
* by `lessc_parser` into a syntax tree, then it is compiled into another tree
|
17 |
+
* representing the CSS structure by `lessc`. The CSS tree is fed into a
|
18 |
+
* formatter, like `lessc_formatter` which then outputs CSS as a string.
|
19 |
+
*
|
20 |
+
* During the first compile, all values are *reduced*, which means that their
|
21 |
+
* types are brought to the lowest form before being dump as strings. This
|
22 |
+
* handles math equations, variable dereferences, and the like.
|
23 |
+
*
|
24 |
+
* The `parse` function of `lessc` is the entry point.
|
25 |
+
*
|
26 |
+
* In summary:
|
27 |
+
*
|
28 |
+
* The `lessc` class creates an intstance of the parser, feeds it LESS code,
|
29 |
+
* then transforms the resulting tree to a CSS tree. This class also holds the
|
30 |
+
* evaluation context, such as all available mixins and variables at any given
|
31 |
+
* time.
|
32 |
+
*
|
33 |
+
* The `lessc_parser` class is only concerned with parsing its input.
|
34 |
+
*
|
35 |
+
* The `lessc_formatter` takes a CSS tree, and dumps it to a formatted string,
|
36 |
+
* handling things like indentation.
|
37 |
+
*/
|
38 |
+
class LessCompiler {
|
39 |
+
|
40 |
+
static public $VERSION = "v0.3.8";
|
41 |
+
static protected $TRUE = array(
|
42 |
+
"keyword",
|
43 |
+
"true"
|
44 |
+
);
|
45 |
+
static protected $FALSE = array(
|
46 |
+
"keyword",
|
47 |
+
"false"
|
48 |
+
);
|
49 |
+
|
50 |
+
protected $libFunctions = array();
|
51 |
+
protected $registeredVars = array();
|
52 |
+
protected $preserveComments = false;
|
53 |
+
|
54 |
+
public $vPrefix = '@'; // prefix of abstract properties
|
55 |
+
public $mPrefix = '$'; // prefix of abstract blocks
|
56 |
+
public $parentSelector = '&';
|
57 |
+
|
58 |
+
public $importDisabled = false;
|
59 |
+
public $importDir = '';
|
60 |
+
|
61 |
+
protected $numberPrecision = null;
|
62 |
+
|
63 |
+
// set to the parser that generated the current line when compiling
|
64 |
+
// so we know how to create error messages
|
65 |
+
public $sourceParser = null;
|
66 |
+
protected $sourceLoc = null;
|
67 |
+
|
68 |
+
static public $defaultValue = array(
|
69 |
+
"keyword",
|
70 |
+
""
|
71 |
+
);
|
72 |
+
|
73 |
+
static protected $nextImportId = 0; // uniquely identify imports
|
74 |
+
|
75 |
+
// attempts to find the path of an import url, returns null for css files
|
76 |
+
protected function findImport($url) {
|
77 |
+
foreach ((array)$this->importDir as $dir) {
|
78 |
+
$full = $dir . (substr($dir, -1) != '/' ? '/' : '') . $url;
|
79 |
+
if ($this->fileExists($file = $full . '.n2less') || $this->fileExists($file = $full)) {
|
80 |
+
return $file;
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
return null;
|
85 |
+
}
|
86 |
+
|
87 |
+
protected function fileExists($name) {
|
88 |
+
return @is_file($name);
|
89 |
+
}
|
90 |
+
|
91 |
+
static public function compressList($items, $delim) {
|
92 |
+
if (!isset($items[1]) && isset($items[0])) return $items[0]; else return array(
|
93 |
+
'list',
|
94 |
+
$delim,
|
95 |
+
$items
|
96 |
+
);
|
97 |
+
}
|
98 |
+
|
99 |
+
static public function preg_quote($what) {
|
100 |
+
return preg_quote($what, '/');
|
101 |
+
}
|
102 |
+
|
103 |
+
protected function tryImport($importPath, $parentBlock, $out) {
|
104 |
+
if ($importPath[0] == "function" && $importPath[1] == "url") {
|
105 |
+
$importPath = $this->flattenList($importPath[2]);
|
106 |
+
}
|
107 |
+
|
108 |
+
$str = $this->coerceString($importPath);
|
109 |
+
if ($str === null) return false;
|
110 |
+
|
111 |
+
$url = $this->compileValue($this->lib_e($str));
|
112 |
+
|
113 |
+
if (isset($this->registeredVars[$url])) {
|
114 |
+
$url = $this->registeredVars[$url];
|
115 |
+
}
|
116 |
+
|
117 |
+
// don't import if it ends in css
|
118 |
+
if (strlen($url) >= 4 && substr_compare($url, '.css', -4, 4) === 0) return false;
|
119 |
+
|
120 |
+
$realPath = $this->findImport($url);
|
121 |
+
if ($realPath === null) return false;
|
122 |
+
|
123 |
+
if ($this->importDisabled) {
|
124 |
+
return array(
|
125 |
+
false,
|
126 |
+
"/* import disabled */"
|
127 |
+
);
|
128 |
+
}
|
129 |
+
|
130 |
+
$this->addParsedFile($realPath);
|
131 |
+
$parser = $this->makeParser($realPath);
|
132 |
+
$root = $parser->parse(file_get_contents($realPath));
|
133 |
+
|
134 |
+
// set the parents of all the block props
|
135 |
+
foreach ($root->props as $prop) {
|
136 |
+
if ($prop[0] == "block") {
|
137 |
+
$prop[1]->parent = $parentBlock;
|
138 |
+
}
|
139 |
+
}
|
140 |
+
|
141 |
+
// copy mixins into scope, set their parents
|
142 |
+
// bring blocks from import into current block
|
143 |
+
// TODO: need to mark the source parser these came from this file
|
144 |
+
foreach ($root->children as $childName => $child) {
|
145 |
+
if (isset($parentBlock->children[$childName])) {
|
146 |
+
$parentBlock->children[$childName] = array_merge($parentBlock->children[$childName], $child);
|
147 |
+
} else {
|
148 |
+
$parentBlock->children[$childName] = $child;
|
149 |
+
}
|
150 |
+
}
|
151 |
+
|
152 |
+
$pi = pathinfo($realPath);
|
153 |
+
$dir = $pi["dirname"];
|
154 |
+
|
155 |
+
list($top, $bottom) = $this->sortProps($root->props, true);
|
156 |
+
$this->compileImportedProps($top, $parentBlock, $out, $parser, $dir);
|
157 |
+
|
158 |
+
return array(
|
159 |
+
true,
|
160 |
+
$bottom,
|
161 |
+
$parser,
|
162 |
+
$dir
|
163 |
+
);
|
164 |
+
}
|
165 |
+
|
166 |
+
protected function compileImportedProps($props, $block, $out, $sourceParser, $importDir) {
|
167 |
+
$oldSourceParser = $this->sourceParser;
|
168 |
+
|
169 |
+
$oldImport = $this->importDir;
|
170 |
+
|
171 |
+
// TODO: this is because the importDir api is stupid
|
172 |
+
$this->importDir = (array)$this->importDir;
|
173 |
+
array_unshift($this->importDir, $importDir);
|
174 |
+
|
175 |
+
foreach ($props as $prop) {
|
176 |
+
$this->compileProp($prop, $block, $out);
|
177 |
+
}
|
178 |
+
|
179 |
+
$this->importDir = $oldImport;
|
180 |
+
$this->sourceParser = $oldSourceParser;
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* Recursively compiles a block.
|
185 |
+
*
|
186 |
+
* A block is analogous to a CSS block in most cases. A single LESS document
|
187 |
+
* is encapsulated in a block when parsed, but it does not have parent tags
|
188 |
+
* so all of it's children appear on the root level when compiled.
|
189 |
+
*
|
190 |
+
* Blocks are made up of props and children.
|
191 |
+
*
|
192 |
+
* Props are property instructions, array tuples which describe an action
|
193 |
+
* to be taken, eg. write a property, set a variable, mixin a block.
|
194 |
+
*
|
195 |
+
* The children of a block are just all the blocks that are defined within.
|
196 |
+
* This is used to look up mixins when performing a mixin.
|
197 |
+
*
|
198 |
+
* Compiling the block involves pushing a fresh environment on the stack,
|
199 |
+
* and iterating through the props, compiling each one.
|
200 |
+
*
|
201 |
+
* See lessc::compileProp()
|
202 |
+
*
|
203 |
+
*/
|
204 |
+
protected function compileBlock($block) {
|
205 |
+
switch ($block->type) {
|
206 |
+
case "root":
|
207 |
+
$this->compileRoot($block);
|
208 |
+
break;
|
209 |
+
case null:
|
210 |
+
$this->compileCSSBlock($block);
|
211 |
+
break;
|
212 |
+
case "media":
|
213 |
+
$this->compileMedia($block);
|
214 |
+
break;
|
215 |
+
case "directive":
|
216 |
+
$name = "@" . $block->name;
|
217 |
+
if (!empty($block->value)) {
|
218 |
+
$name .= " " . $this->compileValue($this->reduce($block->value));
|
219 |
+
}
|
220 |
+
|
221 |
+
$this->compileNestedBlock($block, array($name));
|
222 |
+
break;
|
223 |
+
default:
|
224 |
+
$this->throwError("unknown block type: $block->type\n");
|
225 |
+
}
|
226 |
+
}
|
227 |
+
|
228 |
+
protected function compileCSSBlock($block) {
|
229 |
+
$env = $this->pushEnv();
|
230 |
+
|
231 |
+
$selectors = $this->compileSelectors($block->tags);
|
232 |
+
$env->selectors = $this->multiplySelectors($selectors);
|
233 |
+
$out = $this->makeOutputBlock(null, $env->selectors);
|
234 |
+
|
235 |
+
$this->scope->children[] = $out;
|
236 |
+
$this->compileProps($block, $out);
|
237 |
+
|
238 |
+
$block->scope = $env; // mixins carry scope with them!
|
239 |
+
$this->popEnv();
|
240 |
+
}
|
241 |
+
|
242 |
+
protected function compileMedia($media) {
|
243 |
+
$env = $this->pushEnv($media);
|
244 |
+
$parentScope = $this->mediaParent($this->scope);
|
245 |
+
|
246 |
+
$query = $this->compileMediaQuery($this->multiplyMedia($env));
|
247 |
+
|
248 |
+
$this->scope = $this->makeOutputBlock($media->type, array($query));
|
249 |
+
$parentScope->children[] = $this->scope;
|
250 |
+
|
251 |
+
$this->compileProps($media, $this->scope);
|
252 |
+
|
253 |
+
if (count($this->scope->lines) > 0) {
|
254 |
+
$orphanSelelectors = $this->findClosestSelectors();
|
255 |
+
if (!is_null($orphanSelelectors)) {
|
256 |
+
$orphan = $this->makeOutputBlock(null, $orphanSelelectors);
|
257 |
+
$orphan->lines = $this->scope->lines;
|
258 |
+
array_unshift($this->scope->children, $orphan);
|
259 |
+
$this->scope->lines = array();
|
260 |
+
}
|
261 |
+
}
|
262 |
+
|
263 |
+
$this->scope = $this->scope->parent;
|
264 |
+
$this->popEnv();
|
265 |
+
}
|
266 |
+
|
267 |
+
protected function mediaParent($scope) {
|
268 |
+
while (!empty($scope->parent)) {
|
269 |
+
if (!empty($scope->type) && $scope->type != "media") {
|
270 |
+
break;
|
271 |
+
}
|
272 |
+
$scope = $scope->parent;
|
273 |
+
}
|
274 |
+
|
275 |
+
return $scope;
|
276 |
+
}
|
277 |
+
|
278 |
+
protected function compileNestedBlock($block, $selectors) {
|
279 |
+
$this->pushEnv($block);
|
280 |
+
$this->scope = $this->makeOutputBlock($block->type, $selectors);
|
281 |
+
$this->scope->parent->children[] = $this->scope;
|
282 |
+
|
283 |
+
$this->compileProps($block, $this->scope);
|
284 |
+
|
285 |
+
$this->scope = $this->scope->parent;
|
286 |
+
$this->popEnv();
|
287 |
+
}
|
288 |
+
|
289 |
+
protected function compileRoot($root) {
|
290 |
+
$this->pushEnv();
|
291 |
+
$this->scope = $this->makeOutputBlock($root->type);
|
292 |
+
$this->compileProps($root, $this->scope);
|
293 |
+
$this->popEnv();
|
294 |
+
}
|
295 |
+
|
296 |
+
protected function compileProps($block, $out) {
|
297 |
+
foreach ($this->sortProps($block->props) as $prop) {
|
298 |
+
$this->compileProp($prop, $block, $out);
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
protected function sortProps($props, $split = false) {
|
303 |
+
$vars = array();
|
304 |
+
$imports = array();
|
305 |
+
$other = array();
|
306 |
+
|
307 |
+
foreach ($props as $prop) {
|
308 |
+
switch ($prop[0]) {
|
309 |
+
case "assign":
|
310 |
+
if (isset($prop[1][0]) && $prop[1][0] == $this->vPrefix) {
|
311 |
+
$vars[] = $prop;
|
312 |
+
} else {
|
313 |
+
$other[] = $prop;
|
314 |
+
}
|
315 |
+
break;
|
316 |
+
case "import":
|
317 |
+
$id = self::$nextImportId++;
|
318 |
+
$prop[] = $id;
|
319 |
+
$imports[] = $prop;
|
320 |
+
$other[] = array(
|
321 |
+
"import_mixin",
|
322 |
+
$id
|
323 |
+
);
|
324 |
+
break;
|
325 |
+
default:
|
326 |
+
$other[] = $prop;
|
327 |
+
}
|
328 |
+
}
|
329 |
+
|
330 |
+
if ($split) {
|
331 |
+
return array(
|
332 |
+
array_merge($vars, $imports),
|
333 |
+
$other
|
334 |
+
);
|
335 |
+
} else {
|
336 |
+
return array_merge($vars, $imports, $other);
|
337 |
+
}
|
338 |
+
}
|
339 |
+
|
340 |
+
protected function compileMediaQuery($queries) {
|
341 |
+
$compiledQueries = array();
|
342 |
+
foreach ($queries as $query) {
|
343 |
+
$parts = array();
|
344 |
+
foreach ($query as $q) {
|
345 |
+
switch ($q[0]) {
|
346 |
+
case "mediaType":
|
347 |
+
$parts[] = implode(" ", array_slice($q, 1));
|
348 |
+
break;
|
349 |
+
case "mediaExp":
|
350 |
+
if (isset($q[2])) {
|
351 |
+
$parts[] = "($q[1]: " . $this->compileValue($this->reduce($q[2])) . ")";
|
352 |
+
} else {
|
353 |
+
$parts[] = "($q[1])";
|
354 |
+
}
|
355 |
+
break;
|
356 |
+
case "variable":
|
357 |
+
$parts[] = $this->compileValue($this->reduce($q));
|
358 |
+
break;
|
359 |
+
}
|
360 |
+
}
|
361 |
+
|
362 |
+
if (count($parts) > 0) {
|
363 |
+
$compiledQueries[] = implode(" and ", $parts);
|
364 |
+
}
|
365 |
+
}
|
366 |
+
|
367 |
+
$out = "@media";
|
368 |
+
if (!empty($parts)) {
|
369 |
+
$out .= " " . implode($this->formatter->selectorSeparator, $compiledQueries);
|
370 |
+
}
|
371 |
+
|
372 |
+
return $out;
|
373 |
+
}
|
374 |
+
|
375 |
+
protected function multiplyMedia($env, $childQueries = null) {
|
376 |
+
if (is_null($env) || !empty($env->block->type) && $env->block->type != "media") {
|
377 |
+
return $childQueries;
|
378 |
+
}
|
379 |
+
|
380 |
+
// plain old block, skip
|
381 |
+
if (empty($env->block->type)) {
|
382 |
+
return $this->multiplyMedia($env->parent, $childQueries);
|
383 |
+
}
|
384 |
+
|
385 |
+
$out = array();
|
386 |
+
$queries = $env->block->queries;
|
387 |
+
if (is_null($childQueries)) {
|
388 |
+
$out = $queries;
|
389 |
+
} else {
|
390 |
+
foreach ($queries as $parent) {
|
391 |
+
foreach ($childQueries as $child) {
|
392 |
+
$out[] = array_merge($parent, $child);
|
393 |
+
}
|
394 |
+
}
|
395 |
+
}
|
396 |
+
|
397 |
+
return $this->multiplyMedia($env->parent, $out);
|
398 |
+
}
|
399 |
+
|
400 |
+
protected function expandParentSelectors(&$tag, $replace) {
|
401 |
+
$parts = explode("$&$", $tag);
|
402 |
+
$count = 0;
|
403 |
+
foreach ($parts as &$part) {
|
404 |
+
$part = str_replace($this->parentSelector, $replace, $part, $c);
|
405 |
+
$count += $c;
|
406 |
+
}
|
407 |
+
$tag = implode($this->parentSelector, $parts);
|
408 |
+
|
409 |
+
return $count;
|
410 |
+
}
|
411 |
+
|
412 |
+
protected function findClosestSelectors() {
|
413 |
+
$env = $this->env;
|
414 |
+
$selectors = null;
|
415 |
+
while ($env !== null) {
|
416 |
+
if (isset($env->selectors)) {
|
417 |
+
$selectors = $env->selectors;
|
418 |
+
break;
|
419 |
+
}
|
420 |
+
$env = $env->parent;
|
421 |
+
}
|
422 |
+
|
423 |
+
return $selectors;
|
424 |
+
}
|
425 |
+
|
426 |
+
|
427 |
+
// multiply $selectors against the nearest selectors in env
|
428 |
+
protected function multiplySelectors($selectors) {
|
429 |
+
// find parent selectors
|
430 |
+
|
431 |
+
$parentSelectors = $this->findClosestSelectors();
|
432 |
+
if (is_null($parentSelectors)) {
|
433 |
+
// kill parent reference in top level selector
|
434 |
+
foreach ($selectors as &$s) {
|
435 |
+
$this->expandParentSelectors($s, "");
|
436 |
+
}
|
437 |
+
|
438 |
+
return $selectors;
|
439 |
+
}
|
440 |
+
|
441 |
+
$out = array();
|
442 |
+
foreach ($parentSelectors as $parent) {
|
443 |
+
foreach ($selectors as $child) {
|
444 |
+
$count = $this->expandParentSelectors($child, $parent);
|
445 |
+
|
446 |
+
// don't prepend the parent tag if & was used
|
447 |
+
if ($count > 0) {
|
448 |
+
$out[] = trim($child);
|
449 |
+
} else {
|
450 |
+
$out[] = trim($parent . ' ' . $child);
|
451 |
+
}
|
452 |
+
}
|
453 |
+
}
|
454 |
+
|
455 |
+
return $out;
|
456 |
+
}
|
457 |
+
|
458 |
+
// reduces selector expressions
|
459 |
+
protected function compileSelectors($selectors) {
|
460 |
+
$out = array();
|
461 |
+
|
462 |
+
foreach ($selectors as $s) {
|
463 |
+
if (is_array($s)) {
|
464 |
+
list(, $value) = $s;
|
465 |
+
$out[] = trim($this->compileValue($this->reduce($value)));
|
466 |
+
} else {
|
467 |
+
$out[] = $s;
|
468 |
+
}
|
469 |
+
}
|
470 |
+
|
471 |
+
return $out;
|
472 |
+
}
|
473 |
+
|
474 |
+
protected function eq($left, $right) {
|
475 |
+
return $left == $right;
|
476 |
+
}
|
477 |
+
|
478 |
+
protected function patternMatch($block, $callingArgs) {
|
479 |
+
// match the guards if it has them
|
480 |
+
// any one of the groups must have all its guards pass for a match
|
481 |
+
if (!empty($block->guards)) {
|
482 |
+
$groupPassed = false;
|
483 |
+
foreach ($block->guards as $guardGroup) {
|
484 |
+
foreach ($guardGroup as $guard) {
|
485 |
+
$this->pushEnv();
|
486 |
+
$this->zipSetArgs($block->args, $callingArgs);
|
487 |
+
|
488 |
+
$negate = false;
|
489 |
+
if ($guard[0] == "negate") {
|
490 |
+
$guard = $guard[1];
|
491 |
+
$negate = true;
|
492 |
+
}
|
493 |
+
|
494 |
+
$passed = $this->reduce($guard) == self::$TRUE;
|
495 |
+
if ($negate) $passed = !$passed;
|
496 |
+
|
497 |
+
$this->popEnv();
|
498 |
+
|
499 |
+
if ($passed) {
|
500 |
+
$groupPassed = true;
|
501 |
+
} else {
|
502 |
+
$groupPassed = false;
|
503 |
+
break;
|
504 |
+
}
|
505 |
+
}
|
506 |
+
|
507 |
+
if ($groupPassed) break;
|
508 |
+
}
|
509 |
+
|
510 |
+
if (!$groupPassed) {
|
511 |
+
return false;
|
512 |
+
}
|
513 |
+
}
|
514 |
+
|
515 |
+
$numCalling = count($callingArgs);
|
516 |
+
|
517 |
+
if (empty($block->args)) {
|
518 |
+
return $block->isVararg || $numCalling == 0;
|
519 |
+
}
|
520 |
+
|
521 |
+
$i = -1; // no args
|
522 |
+
// try to match by arity or by argument literal
|
523 |
+
foreach ($block->args as $i => $arg) {
|
524 |
+
switch ($arg[0]) {
|
525 |
+
case "lit":
|
526 |
+
if (empty($callingArgs[$i]) || !$this->eq($arg[1], $callingArgs[$i])) {
|
527 |
+
return false;
|
528 |
+
}
|
529 |
+
break;
|
530 |
+
case "arg":
|
531 |
+
// no arg and no default value
|
532 |
+
if (!isset($callingArgs[$i]) && !isset($arg[2])) {
|
533 |
+
return false;
|
534 |
+
}
|
535 |
+
break;
|
536 |
+
case "rest":
|
537 |
+
$i--; // rest can be empty
|
538 |
+
break 2;
|
539 |
+
}
|
540 |
+
}
|
541 |
+
|
542 |
+
if ($block->isVararg) {
|
543 |
+
return true; // not having enough is handled above
|
544 |
+
} else {
|
545 |
+
$numMatched = $i + 1;
|
546 |
+
|
547 |
+
// greater than becuase default values always match
|
548 |
+
return $numMatched >= $numCalling;
|
549 |
+
}
|
550 |
+
}
|
551 |
+
|
552 |
+
protected function patternMatchAll($blocks, $callingArgs) {
|
553 |
+
$matches = null;
|
554 |
+
foreach ($blocks as $block) {
|
555 |
+
if ($this->patternMatch($block, $callingArgs)) {
|
556 |
+
$matches[] = $block;
|
557 |
+
}
|
558 |
+
}
|
559 |
+
|
560 |
+
return $matches;
|
561 |
+
}
|
562 |
+
|
563 |
+
// attempt to find blocks matched by path and args
|
564 |
+
protected function findBlocks($searchIn, $path, $args, $seen = array()) {
|
565 |
+
if ($searchIn == null) return null;
|
566 |
+
if (isset($seen[$searchIn->id])) return null;
|
567 |
+
$seen[$searchIn->id] = true;
|
568 |
+
|
569 |
+
$name = $path[0];
|
570 |
+
|
571 |
+
if (isset($searchIn->children[$name])) {
|
572 |
+
$blocks = $searchIn->children[$name];
|
573 |
+
if (count($path) == 1) {
|
574 |
+
$matches = $this->patternMatchAll($blocks, $args);
|
575 |
+
if (!empty($matches)) {
|
576 |
+
// This will return all blocks that match in the closest
|
577 |
+
// scope that has any matching block, like lessjs
|
578 |
+
return $matches;
|
579 |
+
}
|
580 |
+
} else {
|
581 |
+
$matches = array();
|
582 |
+
foreach ($blocks as $subBlock) {
|
583 |
+
$subMatches = $this->findBlocks($subBlock, array_slice($path, 1), $args, $seen);
|
584 |
+
|
585 |
+
if (!is_null($subMatches)) {
|
586 |
+
foreach ($subMatches as $sm) {
|
587 |
+
$matches[] = $sm;
|
588 |
+
}
|
589 |
+
}
|
590 |
+
}
|
591 |
+
|
592 |
+
return count($matches) > 0 ? $matches : null;
|
593 |
+
}
|
594 |
+
}
|
595 |
+
|
596 |
+
if ($searchIn->parent === $searchIn) return null;
|
597 |
+
|
598 |
+
return $this->findBlocks($searchIn->parent, $path, $args, $seen);
|
599 |
+
}
|
600 |
+
|
601 |
+
// sets all argument names in $args to either the default value
|
602 |
+
// or the one passed in through $values
|
603 |
+
protected function zipSetArgs($args, $values) {
|
604 |
+
$i = 0;
|
605 |
+
$assignedValues = array();
|
606 |
+
foreach ($args as $a) {
|
607 |
+
if ($a[0] == "arg") {
|
608 |
+
if ($i < count($values) && !is_null($values[$i])) {
|
609 |
+
$value = $values[$i];
|
610 |
+
} elseif (isset($a[2])) {
|
611 |
+
$value = $a[2];
|
612 |
+
} else $value = null;
|
613 |
+
|
614 |
+
$value = $this->reduce($value);
|
615 |
+
$this->set($a[1], $value);
|
616 |
+
$assignedValues[] = $value;
|
617 |
+
}
|
618 |
+
$i++;
|
619 |
+
}
|
620 |
+
|
621 |
+
// check for a rest
|
622 |
+
$last = end($args);
|
623 |
+
if (!empty($last) && $last[0] == "rest") {
|
624 |
+
$rest = array_slice($values, count($args) - 1);
|
625 |
+
$this->set($last[1], $this->reduce(array(
|
626 |
+
"list",
|
627 |
+
" ",
|
628 |
+
$rest
|
629 |
+
)));
|
630 |
+
}
|
631 |
+
|
632 |
+
$this->env->arguments = $assignedValues;
|
633 |
+
}
|
634 |
+
|
635 |
+
// compile a prop and update $lines or $blocks appropriately
|
636 |
+
protected function compileProp($prop, $block, $out) {
|
637 |
+
// set error position context
|
638 |
+
$this->sourceLoc = isset($prop[-1]) ? $prop[-1] : -1;
|
639 |
+
|
640 |
+
switch ($prop[0]) {
|
641 |
+
case 'assign':
|
642 |
+
list(, $name, $value) = $prop;
|
643 |
+
if ($name[0] == $this->vPrefix) {
|
644 |
+
$this->set($name, $value);
|
645 |
+
} else {
|
646 |
+
$out->lines[] = $this->formatter->property($name, $this->compileValue($this->reduce($value)));
|
647 |
+
}
|
648 |
+
break;
|
649 |
+
case 'block':
|
650 |
+
list(, $child) = $prop;
|
651 |
+
$this->compileBlock($child);
|
652 |
+
break;
|
653 |
+
case 'mixin':
|
654 |
+
list(, $path, $args, $suffix) = $prop;
|
655 |
+
|
656 |
+
$args = array_map(array(
|
657 |
+
$this,
|
658 |
+
"reduce"
|
659 |
+
), (array)$args);
|
660 |
+
$mixins = $this->findBlocks($block, $path, $args);
|
661 |
+
|
662 |
+
if ($mixins === null) {
|
663 |
+
// fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n");
|
664 |
+
break; // throw error here??
|
665 |
+
}
|
666 |
+
|
667 |
+
foreach ($mixins as $mixin) {
|
668 |
+
$haveScope = false;
|
669 |
+
if (isset($mixin->parent->scope)) {
|
670 |
+
$haveScope = true;
|
671 |
+
$mixinParentEnv = $this->pushEnv();
|
672 |
+
$mixinParentEnv->storeParent = $mixin->parent->scope;
|
673 |
+
}
|
674 |
+
|
675 |
+
$haveArgs = false;
|
676 |
+
if (isset($mixin->args)) {
|
677 |
+
$haveArgs = true;
|
678 |
+
$this->pushEnv();
|
679 |
+
$this->zipSetArgs($mixin->args, $args);
|
680 |
+
}
|
681 |
+
|
682 |
+
$oldParent = $mixin->parent;
|
683 |
+
if ($mixin != $block) $mixin->parent = $block;
|
684 |
+
|
685 |
+
foreach ($this->sortProps($mixin->props) as $subProp) {
|
686 |
+
if ($suffix !== null && $subProp[0] == "assign" && is_string($subProp[1]) && $subProp[1][0] != $this->vPrefix) {
|
687 |
+
$subProp[2] = array(
|
688 |
+
'list',
|
689 |
+
' ',
|
690 |
+
array(
|
691 |
+
$subProp[2],
|
692 |
+
array(
|
693 |
+
'keyword',
|
694 |
+
$suffix
|
695 |
+
)
|
696 |
+
)
|
697 |
+
);
|
698 |
+
}
|
699 |
+
|
700 |
+
$this->compileProp($subProp, $mixin, $out);
|
701 |
+
}
|
702 |
+
|
703 |
+
$mixin->parent = $oldParent;
|
704 |
+
|
705 |
+
if ($haveArgs) $this->popEnv();
|
706 |
+
if ($haveScope) $this->popEnv();
|
707 |
+
}
|
708 |
+
|
709 |
+
break;
|
710 |
+
case 'raw':
|
711 |
+
$out->lines[] = $prop[1];
|
712 |
+
break;
|
713 |
+
case "directive":
|
714 |
+
list(, $name, $value) = $prop;
|
715 |
+
$out->lines[] = "@$name " . $this->compileValue($this->reduce($value)) . ';';
|
716 |
+
break;
|
717 |
+
case "comment":
|
718 |
+
$out->lines[] = $prop[1];
|
719 |
+
break;
|
720 |
+
case "import";
|
721 |
+
list(, $importPath, $importId) = $prop;
|
722 |
+
$importPath = $this->reduce($importPath);
|
723 |
+
|
724 |
+
if (!isset($this->env->imports)) {
|
725 |
+
$this->env->imports = array();
|
726 |
+
}
|
727 |
+
|
728 |
+
$result = $this->tryImport($importPath, $block, $out);
|
729 |
+
|
730 |
+
$this->env->imports[$importId] = $result === false ? array(
|
731 |
+
false,
|
732 |
+
"@import " . $this->compileValue($importPath) . ";"
|
733 |
+
) : $result;
|
734 |
+
|
735 |
+
break;
|
736 |
+
case "import_mixin":
|
737 |
+
list(, $importId) = $prop;
|
738 |
+
$import = $this->env->imports[$importId];
|
739 |
+
if ($import[0] === false) {
|
740 |
+
$out->lines[] = $import[1];
|
741 |
+
} else {
|
742 |
+
list(, $bottom, $parser, $importDir) = $import;
|
743 |
+
$this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
|
744 |
+
}
|
745 |
+
|
746 |
+
break;
|
747 |
+
default:
|
748 |
+
$this->throwError("unknown op: {$prop[0]}\n");
|
749 |
+
}
|
750 |
+
}
|
751 |
+
|
752 |
+
|
753 |
+
/**
|
754 |
+
* Compiles a primitive value into a CSS property value.
|
755 |
+
*
|
756 |
+
* Values in lessphp are typed by being wrapped in arrays, their format is
|
757 |
+
* typically:
|
758 |
+
*
|
759 |
+
* array(type, contents [, additional_contents]*)
|
760 |
+
*
|
761 |
+
* The input is expected to be reduced. This function will not work on
|
762 |
+
* things like expressions and variables.
|
763 |
+
*/
|
764 |
+
protected function compileValue($value) {
|
765 |
+
switch ($value[0]) {
|
766 |
+
case 'list':
|
767 |
+
// [1] - delimiter
|
768 |
+
// [2] - array of values
|
769 |
+
return implode($value[1], array_map(array(
|
770 |
+
$this,
|
771 |
+
'compileValue'
|
772 |
+
), $value[2]));
|
773 |
+
case 'raw_color':
|
774 |
+
if (!empty($this->formatter->compressColors)) {
|
775 |
+
return $this->compileValue($this->coerceColor($value));
|
776 |
+
}
|
777 |
+
|
778 |
+
return $value[1];
|
779 |
+
case 'keyword':
|
780 |
+
// [1] - the keyword
|
781 |
+
return $value[1];
|
782 |
+
case 'number':
|
783 |
+
list(, $num, $unit) = $value;
|
784 |
+
// [1] - the number
|
785 |
+
// [2] - the unit
|
786 |
+
if ($this->numberPrecision !== null) {
|
787 |
+
$num = round($num, $this->numberPrecision);
|
788 |
+
}
|
789 |
+
|
790 |
+
return $num . $unit;
|
791 |
+
case 'string':
|
792 |
+
// [1] - contents of string (includes quotes)
|
793 |
+
list(, $delim, $content) = $value;
|
794 |
+
foreach ($content as &$part) {
|
795 |
+
if (is_array($part)) {
|
796 |
+
$part = $this->compileValue($part);
|
797 |
+
}
|
798 |
+
}
|
799 |
+
|
800 |
+
return $delim . implode($content) . $delim;
|
801 |
+
case 'color':
|
802 |
+
// [1] - red component (either number or a %)
|
803 |
+
// [2] - green component
|
804 |
+
// [3] - blue component
|
805 |
+
// [4] - optional alpha component
|
806 |
+
list(, $r, $g, $b) = $value;
|
807 |
+
$r = round($r);
|
808 |
+
$g = round($g);
|
809 |
+
$b = round($b);
|
810 |
+
|
811 |
+
if (count($value) == 5 && $value[4] != 1) { // rgba
|
812 |
+
return 'rgba(' . $r . ',' . $g . ',' . $b . ',' . $value[4] . ')';
|
813 |
+
}
|
814 |
+
|
815 |
+
$h = sprintf("#%02x%02x%02x", $r, $g, $b);
|
816 |
+
|
817 |
+
if (!empty($this->formatter->compressColors)) {
|
818 |
+
// Converting hex color to short notation (e.g. #003399 to #039)
|
819 |
+
if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) {
|
820 |
+
$h = '#' . $h[1] . $h[3] . $h[5];
|
821 |
+
}
|
822 |
+
}
|
823 |
+
|
824 |
+
return $h;
|
825 |
+
|
826 |
+
case 'function':
|
827 |
+
list(, $name, $args) = $value;
|
828 |
+
|
829 |
+
return $name . '(' . $this->compileValue($args) . ')';
|
830 |
+
default: // assumed to be unit
|
831 |
+
$this->throwError("unknown value type: $value[0]");
|
832 |
+
}
|
833 |
+
}
|
834 |
+
|
835 |
+
protected function lib_isnumber($value) {
|
836 |
+
return $this->toBool($value[0] == "number");
|
837 |
+
}
|
838 |
+
|
839 |
+
protected function lib_isstring($value) {
|
840 |
+
return $this->toBool($value[0] == "string");
|
841 |
+
}
|
842 |
+
|
843 |
+
protected function lib_iscolor($value) {
|
844 |
+
return $this->toBool($this->coerceColor($value));
|
845 |
+
}
|
846 |
+
|
847 |
+
protected function lib_iskeyword($value) {
|
848 |
+
return $this->toBool($value[0] == "keyword");
|
849 |
+
}
|
850 |
+
|
851 |
+
protected function lib_ispixel($value) {
|
852 |
+
return $this->toBool($value[0] == "number" && $value[2] == "px");
|
853 |
+
}
|
854 |
+
|
855 |
+
protected function lib_ispercentage($value) {
|
856 |
+
return $this->toBool($value[0] == "number" && $value[2] == "%");
|
857 |
+
}
|
858 |
+
|
859 |
+
protected function lib_isem($value) {
|
860 |
+
return $this->toBool($value[0] == "number" && $value[2] == "em");
|
861 |
+
}
|
862 |
+
|
863 |
+
protected function lib_isrem($value) {
|
864 |
+
return $this->toBool($value[0] == "number" && $value[2] == "rem");
|
865 |
+
}
|
866 |
+
|
867 |
+
protected function lib_rgbahex($color) {
|
868 |
+
$color = $this->coerceColor($color);
|
869 |
+
if (is_null($color)) $this->throwError("color expected for rgbahex");
|
870 |
+
|
871 |
+
return sprintf("#%02x%02x%02x%02x", isset($color[4]) ? $color[4] * 255 : 255, $color[1], $color[2], $color[3]);
|
872 |
+
}
|
873 |
+
|
874 |
+
protected function lib_argb($color) {
|
875 |
+
return $this->lib_rgbahex($color);
|
876 |
+
}
|
877 |
+
|
878 |
+
// utility func to unquote a string
|
879 |
+
protected function lib_e($arg) {
|
880 |
+
switch ($arg[0]) {
|
881 |
+
case "list":
|
882 |
+
$items = $arg[2];
|
883 |
+
if (isset($items[0])) {
|
884 |
+
return $this->lib_e($items[0]);
|
885 |
+
}
|
886 |
+
|
887 |
+
return self::$defaultValue;
|
888 |
+
case "string":
|
889 |
+
$arg[1] = "";
|
890 |
+
|
891 |
+
return $arg;
|
892 |
+
case "keyword":
|
893 |
+
return $arg;
|
894 |
+
default:
|
895 |
+
return array(
|
896 |
+
"keyword",
|
897 |
+
$this->compileValue($arg)
|
898 |
+
);
|
899 |
+
}
|
900 |
+
}
|
901 |
+
|
902 |
+
protected function lib__sprintf($args) {
|
903 |
+
if ($args[0] != "list") return $args;
|
904 |
+
$values = $args[2];
|
905 |
+
$string = array_shift($values);
|
906 |
+
$template = $this->compileValue($this->lib_e($string));
|
907 |
+
|
908 |
+
$i = 0;
|
909 |
+
if (preg_match_all('/%[dsa]/', $template, $m)) {
|
910 |
+
foreach ($m[0] as $match) {
|
911 |
+
$val = isset($values[$i]) ? $this->reduce($values[$i]) : array(
|
912 |
+
'keyword',
|
913 |
+
''
|
914 |
+
);
|
915 |
+
|
916 |
+
// lessjs compat, renders fully expanded color, not raw color
|
917 |
+
if ($color = $this->coerceColor($val)) {
|
918 |
+
$val = $color;
|
919 |
+
}
|
920 |
+
|
921 |
+
$i++;
|
922 |
+
$rep = $this->compileValue($this->lib_e($val));
|
923 |
+
$template = preg_replace('/' . self::preg_quote($match) . '/', $rep, $template, 1);
|
924 |
+
}
|
925 |
+
}
|
926 |
+
|
927 |
+
$d = $string[0] == "string" ? $string[1] : '"';
|
928 |
+
|
929 |
+
return array(
|
930 |
+
"string",
|
931 |
+
$d,
|
932 |
+
array($template)
|
933 |
+
);
|
934 |
+
}
|
935 |
+
|
936 |
+
protected function lib_floor($arg) {
|
937 |
+
$value = $this->assertNumber($arg);
|
938 |
+
|
939 |
+
return array(
|
940 |
+
"number",
|
941 |
+
floor($value),
|
942 |
+
$arg[2]
|
943 |
+
);
|
944 |
+
}
|
945 |
+
|
946 |
+
protected function lib_ceil($arg) {
|
947 |
+
$value = $this->assertNumber($arg);
|
948 |
+
|
949 |
+
return array(
|
950 |
+
"number",
|
951 |
+
ceil($value),
|
952 |
+
$arg[2]
|
953 |
+
);
|
954 |
+
}
|
955 |
+
|
956 |
+
protected function lib_round($arg) {
|
957 |
+
$value = $this->assertNumber($arg);
|
958 |
+
|
959 |
+
return array(
|
960 |
+
"number",
|
961 |
+
round($value),
|
962 |
+
$arg[2]
|
963 |
+
);
|
964 |
+
}
|
965 |
+
|
966 |
+
protected function lib_unit($arg) {
|
967 |
+
if ($arg[0] == "list") {
|
968 |
+
list($number, $newUnit) = $arg[2];
|
969 |
+
|
970 |
+
return array(
|
971 |
+
"number",
|
972 |
+
$this->assertNumber($number),
|
973 |
+
$this->compileValue($this->lib_e($newUnit))
|
974 |
+
);
|
975 |
+
} else {
|
976 |
+
return array(
|
977 |
+
"number",
|
978 |
+
$this->assertNumber($arg),
|
979 |
+
""
|
980 |
+
);
|
981 |
+
}
|
982 |
+
}
|
983 |
+
|
984 |
+
/**
|
985 |
+
* Helper function to get arguments for color manipulation functions.
|
986 |
+
* takes a list that contains a color like thing and a percentage
|
987 |
+
*/
|
988 |
+
protected function colorArgs($args) {
|
989 |
+
if ($args[0] != 'list' || count($args[2]) < 2) {
|
990 |
+
return array(
|
991 |
+
array(
|
992 |
+
'color',
|
993 |
+
0,
|
994 |
+
0,
|
995 |
+
0
|
996 |
+
),
|
997 |
+
0
|
998 |
+
);
|
999 |
+
}
|
1000 |
+
list($color, $delta) = $args[2];
|
1001 |
+
$color = $this->assertColor($color);
|
1002 |
+
$delta = floatval($delta[1]);
|
1003 |
+
|
1004 |
+
return array(
|
1005 |
+
$color,
|
1006 |
+
$delta
|
1007 |
+
);
|
1008 |
+
}
|
1009 |
+
|
1010 |
+
protected function lib_darken($args) {
|
1011 |
+
list($color, $delta) = $this->colorArgs($args);
|
1012 |
+
|
1013 |
+
$hsl = $this->toHSL($color);
|
1014 |
+
$hsl[3] = $this->clamp($hsl[3] - $delta, 100);
|
1015 |
+
|
1016 |
+
return $this->toRGB($hsl);
|
1017 |
+
}
|
1018 |
+
|
1019 |
+
protected function lib_lighten($args) {
|
1020 |
+
list($color, $delta) = $this->colorArgs($args);
|
1021 |
+
|
1022 |
+
$hsl = $this->toHSL($color);
|
1023 |
+
$hsl[3] = $this->clamp($hsl[3] + $delta, 100);
|
1024 |
+
|
1025 |
+
return $this->toRGB($hsl);
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
protected function lib_saturate($args) {
|
1029 |
+
list($color, $delta) = $this->colorArgs($args);
|
1030 |
+
|
1031 |
+
$hsl = $this->toHSL($color);
|
1032 |
+
$hsl[2] = $this->clamp($hsl[2] + $delta, 100);
|
1033 |
+
|
1034 |
+
return $this->toRGB($hsl);
|
1035 |
+
}
|
1036 |
+
|
1037 |
+
protected function lib_desaturate($args) {
|
1038 |
+
list($color, $delta) = $this->colorArgs($args);
|
1039 |
+
|
1040 |
+
$hsl = $this->toHSL($color);
|
1041 |
+
$hsl[2] = $this->clamp($hsl[2] - $delta, 100);
|
1042 |
+
|
1043 |
+
return $this->toRGB($hsl);
|
1044 |
+
}
|
1045 |
+
|
1046 |
+
protected function lib_spin($args) {
|
1047 |
+
list($color, $delta) = $this->colorArgs($args);
|
1048 |
+
|
1049 |
+
$hsl = $this->toHSL($color);
|
1050 |
+
|
1051 |
+
$hsl[1] = $hsl[1] + $delta % 360;
|
1052 |
+
if ($hsl[1] < 0) $hsl[1] += 360;
|
1053 |
+
|
1054 |
+
return $this->toRGB($hsl);
|
1055 |
+
}
|
1056 |
+
|
1057 |
+
protected function lib_fadeout($args) {
|
1058 |
+
list($color, $delta) = $this->colorArgs($args);
|
1059 |
+
$color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) - $delta / 100);
|
1060 |
+
|
1061 |
+
return $color;
|
1062 |
+
}
|
1063 |
+
|
1064 |
+
protected function lib_fadein($args) {
|
1065 |
+
list($color, $delta) = $this->colorArgs($args);
|
1066 |
+
$color[4] = $this->clamp((isset($color[4]) ? $color[4] : 1) + $delta / 100);
|
1067 |
+
|
1068 |
+
return $color;
|
1069 |
+
}
|
1070 |
+
|
1071 |
+
protected function lib_hue($color) {
|
1072 |
+
$hsl = $this->toHSL($this->assertColor($color));
|
1073 |
+
|
1074 |
+
return round($hsl[1]);
|
1075 |
+
}
|
1076 |
+
|
1077 |
+
protected function lib_saturation($color) {
|
1078 |
+
$hsl = $this->toHSL($this->assertColor($color));
|
1079 |
+
|
1080 |
+
return round($hsl[2]);
|
1081 |
+
}
|
1082 |
+
|
1083 |
+
protected function lib_lightness($color) {
|
1084 |
+
$hsl = $this->toHSL($this->assertColor($color));
|
1085 |
+
|
1086 |
+
return round($hsl[3]);
|
1087 |
+
}
|
1088 |
+
|
1089 |
+
// get the alpha of a color
|
1090 |
+
// defaults to 1 for non-colors or colors without an alpha
|
1091 |
+
protected function lib_alpha($value) {
|
1092 |
+
if (!is_null($color = $this->coerceColor($value))) {
|
1093 |
+
return isset($color[4]) ? $color[4] : 1;
|
1094 |
+
}
|
1095 |
+
}
|
1096 |
+
|
1097 |
+
// set the alpha of the color
|
1098 |
+
protected function lib_fade($args) {
|
1099 |
+
list($color, $alpha) = $this->colorArgs($args);
|
1100 |
+
$color[4] = $this->clamp($alpha / 100.0);
|
1101 |
+
|
1102 |
+
return $color;
|
1103 |
+
}
|
1104 |
+
|
1105 |
+
protected function lib_percentage($arg) {
|
1106 |
+
$num = $this->assertNumber($arg);
|
1107 |
+
|
1108 |
+
return array(
|
1109 |
+
"number",
|
1110 |
+
$num * 100,
|
1111 |
+
"%"
|
1112 |
+
);
|
1113 |
+
}
|
1114 |
+
|
1115 |
+
// mixes two colors by weight
|
1116 |
+
// mix(@color1, @color2, @weight);
|
1117 |
+
// http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
|
1118 |
+
protected function lib_mix($args) {
|
1119 |
+
if ($args[0] != "list" || count($args[2]) < 3) $this->throwError("mix expects (color1, color2, weight)");
|
1120 |
+
|
1121 |
+
list($first, $second, $weight) = $args[2];
|
1122 |
+
$first = $this->assertColor($first);
|
1123 |
+
$second = $this->assertColor($second);
|
1124 |
+
|
1125 |
+
$first_a = $this->lib_alpha($first);
|
1126 |
+
$second_a = $this->lib_alpha($second);
|
1127 |
+
$weight = $weight[1] / 100.0;
|
1128 |
+
|
1129 |
+
$w = $weight * 2 - 1;
|
1130 |
+
$a = $first_a - $second_a;
|
1131 |
+
|
1132 |
+
$w1 = (($w * $a == -1 ? $w : ($w + $a) / (1 + $w * $a)) + 1) / 2.0;
|
1133 |
+
$w2 = 1.0 - $w1;
|
1134 |
+
|
1135 |
+
$new = array(
|
1136 |
+
'color',
|
1137 |
+
$w1 * $first[1] + $w2 * $second[1],
|
1138 |
+
$w1 * $first[2] + $w2 * $second[2],
|
1139 |
+
$w1 * $first[3] + $w2 * $second[3],
|
1140 |
+
);
|
1141 |
+
|
1142 |
+
if ($first_a != 1.0 || $second_a != 1.0) {
|
1143 |
+
$new[] = $first_a * $weight + $second_a * ($weight - 1);
|
1144 |
+
}
|
1145 |
+
|
1146 |
+
return $this->fixColor($new);
|
1147 |
+
}
|
1148 |
+
|
1149 |
+
protected function lib_contrast($args) {
|
1150 |
+
if ($args[0] != 'list' || count($args[2]) < 3) {
|
1151 |
+
return array(
|
1152 |
+
array(
|
1153 |
+
'color',
|
1154 |
+
0,
|
1155 |
+
0,
|
1156 |
+
0
|
1157 |
+
),
|
1158 |
+
0
|
1159 |
+
);
|
1160 |
+
}
|
1161 |
+
|
1162 |
+
list($inputColor, $darkColor, $lightColor) = $args[2];
|
1163 |
+
|
1164 |
+
$inputColor = $this->assertColor($inputColor);
|
1165 |
+
$darkColor = $this->assertColor($darkColor);
|
1166 |
+
$lightColor = $this->assertColor($lightColor);
|
1167 |
+
$hsl = $this->toHSL($inputColor);
|
1168 |
+
|
1169 |
+
if ($hsl[3] > 50) {
|
1170 |
+
return $darkColor;
|
1171 |
+
}
|
1172 |
+
|
1173 |
+
return $lightColor;
|
1174 |
+
}
|
1175 |
+
|
1176 |
+
protected function assertColor($value, $error = "expected color value") {
|
1177 |
+
$color = $this->coerceColor($value);
|
1178 |
+
if (is_null($color)) $this->throwError($error);
|
1179 |
+
|
1180 |
+
return $color;
|
1181 |
+
}
|
1182 |
+
|
1183 |
+
protected function assertNumber($value, $error = "expecting number") {
|
1184 |
+
if ($value[0] == "number") return $value[1];
|
1185 |
+
$this->throwError($error);
|
1186 |
+
}
|
1187 |
+
|
1188 |
+
protected function toHSL($color) {
|
1189 |
+
if ($color[0] == 'hsl') return $color;
|
1190 |
+
|
1191 |
+
$r = $color[1] / 255;
|
1192 |
+
$g = $color[2] / 255;
|
1193 |
+
$b = $color[3] / 255;
|
1194 |
+
|
1195 |
+
$min = min($r, $g, $b);
|
1196 |
+
$max = max($r, $g, $b);
|
1197 |
+
|
1198 |
+
$L = ($min + $max) / 2;
|
1199 |
+
if ($min == $max) {
|
1200 |
+
$S = $H = 0;
|
1201 |
+
} else {
|
1202 |
+
if ($L < 0.5) $S = ($max - $min) / ($max + $min); else
|
1203 |
+
$S = ($max - $min) / (2.0 - $max - $min);
|
1204 |
+
|
1205 |
+
if ($r == $max) $H = ($g - $b) / ($max - $min); elseif ($g == $max) $H = 2.0 + ($b - $r) / ($max - $min);
|
1206 |
+
elseif ($b == $max) $H = 4.0 + ($r - $g) / ($max - $min);
|
1207 |
+
|
1208 |
+
}
|
1209 |
+
|
1210 |
+
$out = array(
|
1211 |
+
'hsl',
|
1212 |
+
($H < 0 ? $H + 6 : $H) * 60,
|
1213 |
+
$S * 100,
|
1214 |
+
$L * 100,
|
1215 |
+
);
|
1216 |
+
|
1217 |
+
if (count($color) > 4) $out[] = $color[4]; // copy alpha
|
1218 |
+
|
1219 |
+
return $out;
|
1220 |
+
}
|
1221 |
+
|
1222 |
+
protected function toRGB_helper($comp, $temp1, $temp2) {
|
1223 |
+
if ($comp < 0) $comp += 1.0; elseif ($comp > 1) $comp -= 1.0;
|
1224 |
+
|
1225 |
+
if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp;
|
1226 |
+
if (2 * $comp < 1) return $temp2;
|
1227 |
+
if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1) * ((2 / 3) - $comp) * 6;
|
1228 |
+
|
1229 |
+
return $temp1;
|
1230 |
+
}
|
1231 |
+
|
1232 |
+
/**
|
1233 |
+
* Converts a hsl array into a color value in rgb.
|
1234 |
+
* Expects H to be in range of 0 to 360, S and L in 0 to 100
|
1235 |
+
*/
|
1236 |
+
protected function toRGB($color) {
|
1237 |
+
if ($color == 'color') return $color;
|
1238 |
+
|
1239 |
+
$H = $color[1] / 360;
|
1240 |
+
$S = $color[2] / 100;
|
1241 |
+
$L = $color[3] / 100;
|
1242 |
+
|
1243 |
+
if ($S == 0) {
|
1244 |
+
$r = $g = $b = $L;
|
1245 |
+
} else {
|
1246 |
+
$temp2 = $L < 0.5 ? $L * (1.0 + $S) : $L + $S - $L * $S;
|
1247 |
+
|
1248 |
+
$temp1 = 2.0 * $L - $temp2;
|
1249 |
+
|
1250 |
+
$r = $this->toRGB_helper($H + 1 / 3, $temp1, $temp2);
|
1251 |
+
$g = $this->toRGB_helper($H, $temp1, $temp2);
|
1252 |
+
$b = $this->toRGB_helper($H - 1 / 3, $temp1, $temp2);
|
1253 |
+
}
|
1254 |
+
|
1255 |
+
// $out = array('color', round($r*255), round($g*255), round($b*255));
|
1256 |
+
$out = array(
|
1257 |
+
'color',
|
1258 |
+
$r * 255,
|
1259 |
+
$g * 255,
|
1260 |
+
$b * 255
|
1261 |
+
);
|
1262 |
+
if (count($color) > 4) $out[] = $color[4]; // copy alpha
|
1263 |
+
|
1264 |
+
return $out;
|
1265 |
+
}
|
1266 |
+
|
1267 |
+
protected function clamp($v, $max = 1, $min = 0) {
|
1268 |
+
return min($max, max($min, $v));
|
1269 |
+
}
|
1270 |
+
|
1271 |
+
/**
|
1272 |
+
* Convert the rgb, rgba, hsl color literals of function type
|
1273 |
+
* as returned by the parser into values of color type.
|
1274 |
+
*/
|
1275 |
+
protected function funcToColor($func) {
|
1276 |
+
$fname = $func[1];
|
1277 |
+
if ($func[2][0] != 'list') return false; // need a list of arguments
|
1278 |
+
$rawComponents = $func[2][2];
|
1279 |
+
|
1280 |
+
if ($fname == 'hsl' || $fname == 'hsla') {
|
1281 |
+
$hsl = array('hsl');
|
1282 |
+
$i = 0;
|
1283 |
+
foreach ($rawComponents as $c) {
|
1284 |
+
$val = $this->reduce($c);
|
1285 |
+
$val = isset($val[1]) ? floatval($val[1]) : 0;
|
1286 |
+
|
1287 |
+
if ($i == 0) $clamp = 360; elseif ($i < 3) $clamp = 100;
|
1288 |
+
else $clamp = 1;
|
1289 |
+
|
1290 |
+
$hsl[] = $this->clamp($val, $clamp);
|
1291 |
+
$i++;
|
1292 |
+
}
|
1293 |
+
|
1294 |
+
while (count($hsl) < 4) $hsl[] = 0;
|
1295 |
+
|
1296 |
+
return $this->toRGB($hsl);
|
1297 |
+
|
1298 |
+
} elseif ($fname == 'rgb' || $fname == 'rgba') {
|
1299 |
+
$components = array();
|
1300 |
+
$i = 1;
|
1301 |
+
foreach ($rawComponents as $c) {
|
1302 |
+
$c = $this->reduce($c);
|
1303 |
+
if ($i < 4) {
|
1304 |
+
if ($c[0] == "number" && $c[2] == "%") {
|
1305 |
+
$components[] = 255 * ($c[1] / 100);
|
1306 |
+
} else {
|
1307 |
+
$components[] = floatval($c[1]);
|
1308 |
+
}
|
1309 |
+
} elseif ($i == 4) {
|
1310 |
+
if ($c[0] == "number" && $c[2] == "%") {
|
1311 |
+
$components[] = 1.0 * ($c[1] / 100);
|
1312 |
+
} else {
|
1313 |
+
$components[] = floatval($c[1]);
|
1314 |
+
}
|
1315 |
+
} else break;
|
1316 |
+
|
1317 |
+
$i++;
|
1318 |
+
}
|
1319 |
+
while (count($components) < 3) $components[] = 0;
|
1320 |
+
array_unshift($components, 'color');
|
1321 |
+
|
1322 |
+
return $this->fixColor($components);
|
1323 |
+
}
|
1324 |
+
|
1325 |
+
return false;
|
1326 |
+
}
|
1327 |
+
|
1328 |
+
protected function reduce($value, $forExpression = false) {
|
1329 |
+
switch ($value[0]) {
|
1330 |
+
case "interpolate":
|
1331 |
+
$reduced = $this->reduce($value[1]);
|
1332 |
+
$var = $this->compileValue($reduced);
|
1333 |
+
$res = $this->reduce(array(
|
1334 |
+
"variable",
|
1335 |
+
$this->vPrefix . $var
|
1336 |
+
));
|
1337 |
+
|
1338 |
+
if (empty($value[2])) $res = $this->lib_e($res);
|
1339 |
+
|
1340 |
+
return $res;
|
1341 |
+
case "variable":
|
1342 |
+
$key = $value[1];
|
1343 |
+
if (is_array($key)) {
|
1344 |
+
$key = $this->reduce($key);
|
1345 |
+
$key = $this->vPrefix . $this->compileValue($this->lib_e($key));
|
1346 |
+
}
|
1347 |
+
|
1348 |
+
$seen =& $this->env->seenNames;
|
1349 |
+
|
1350 |
+
if (!empty($seen[$key])) {
|
1351 |
+
$this->throwError("infinite loop detected: $key");
|
1352 |
+
}
|
1353 |
+
|
1354 |
+
$seen[$key] = true;
|
1355 |
+
$out = $this->reduce($this->get($key, self::$defaultValue));
|
1356 |
+
$seen[$key] = false;
|
1357 |
+
|
1358 |
+
return $out;
|
1359 |
+
case "list":
|
1360 |
+
foreach ($value[2] as &$item) {
|
1361 |
+
$item = $this->reduce($item, $forExpression);
|
1362 |
+
}
|
1363 |
+
|
1364 |
+
return $value;
|
1365 |
+
case "expression":
|
1366 |
+
return $this->evaluate($value);
|
1367 |
+
case "string":
|
1368 |
+
foreach ($value[2] as &$part) {
|
1369 |
+
if (is_array($part)) {
|
1370 |
+
$strip = $part[0] == "variable";
|
1371 |
+
$part = $this->reduce($part);
|
1372 |
+
if ($strip) $part = $this->lib_e($part);
|
1373 |
+
}
|
1374 |
+
}
|
1375 |
+
|
1376 |
+
return $value;
|
1377 |
+
case "escape":
|
1378 |
+
list(, $inner) = $value;
|
1379 |
+
|
1380 |
+
return $this->lib_e($this->reduce($inner));
|
1381 |
+
case "function":
|
1382 |
+
$color = $this->funcToColor($value);
|
1383 |
+
if ($color) return $color;
|
1384 |
+
|
1385 |
+
list(, $name, $args) = $value;
|
1386 |
+
if ($name == "%") $name = "_sprintf";
|
1387 |
+
$f = isset($this->libFunctions[$name]) ? $this->libFunctions[$name] : array(
|
1388 |
+
$this,
|
1389 |
+
'lib_' . $name
|
1390 |
+
);
|
1391 |
+
|
1392 |
+
if (is_callable($f)) {
|
1393 |
+
if ($args[0] == 'list') $args = self::compressList($args[2], $args[1]);
|
1394 |
+
|
1395 |
+
$ret = call_user_func($f, $this->reduce($args, true), $this);
|
1396 |
+
|
1397 |
+
if (is_null($ret)) {
|
1398 |
+
return array(
|
1399 |
+
"string",
|
1400 |
+
"",
|
1401 |
+
array(
|
1402 |
+
$name,
|
1403 |
+
"(",
|
1404 |
+
$args,
|
1405 |
+
")"
|
1406 |
+
)
|
1407 |
+
);
|
1408 |
+
}
|
1409 |
+
|
1410 |
+
// convert to a typed value if the result is a php primitive
|
1411 |
+
if (is_numeric($ret)) $ret = array(
|
1412 |
+
'number',
|
1413 |
+
$ret,
|
1414 |
+
""
|
1415 |
+
); elseif (!is_array($ret)) $ret = array(
|
1416 |
+
'keyword',
|
1417 |
+
$ret
|
1418 |
+
);
|
1419 |
+
|
1420 |
+
return $ret;
|
1421 |
+
}
|
1422 |
+
|
1423 |
+
// plain function, reduce args
|
1424 |
+
$value[2] = $this->reduce($value[2]);
|
1425 |
+
|
1426 |
+
return $value;
|
1427 |
+
case "unary":
|
1428 |
+
list(, $op, $exp) = $value;
|
1429 |
+
$exp = $this->reduce($exp);
|
1430 |
+
|
1431 |
+
if ($exp[0] == "number") {
|
1432 |
+
switch ($op) {
|
1433 |
+
case "+":
|
1434 |
+
return $exp;
|
1435 |
+
case "-":
|
1436 |
+
$exp[1] *= -1;
|
1437 |
+
|
1438 |
+
return $exp;
|
1439 |
+
}
|
1440 |
+
}
|
1441 |
+
|
1442 |
+
return array(
|
1443 |
+
"string",
|
1444 |
+
"",
|
1445 |
+
array(
|
1446 |
+
$op,
|
1447 |
+
$exp
|
1448 |
+
)
|
1449 |
+
);
|
1450 |
+
}
|
1451 |
+
|
1452 |
+
if ($forExpression) {
|
1453 |
+
switch ($value[0]) {
|
1454 |
+
case "keyword":
|
1455 |
+
if ($color = $this->coerceColor($value)) {
|
1456 |
+
return $color;
|
1457 |
+
}
|
1458 |
+
break;
|
1459 |
+
case "raw_color":
|
1460 |
+
return $this->coerceColor($value);
|
1461 |
+
}
|
1462 |
+
}
|
1463 |
+
|
1464 |
+
return $value;
|
1465 |
+
}
|
1466 |
+
|
1467 |
+
|
1468 |
+
// coerce a value for use in color operation
|
1469 |
+
protected function coerceColor($value) {
|
1470 |
+
switch ($value[0]) {
|
1471 |
+
case 'color':
|
1472 |
+
return $value;
|
1473 |
+
case 'raw_color':
|
1474 |
+
$c = array(
|
1475 |
+
"color",
|
1476 |
+
0,
|
1477 |
+
0,
|
1478 |
+
0
|
1479 |
+
);
|
1480 |
+
$colorStr = substr($value[1], 1);
|
1481 |
+
$num = hexdec($colorStr);
|
1482 |
+
$width = strlen($colorStr) == 3 ? 16 : 256;
|
1483 |
+
|
1484 |
+
for ($i = 3; $i > 0; $i--) { // 3 2 1
|
1485 |
+
$t = $num % $width;
|
1486 |
+
$num /= $width;
|
1487 |
+
|
1488 |
+
$c[$i] = $t * (256 / $width) + $t * floor(16 / $width);
|
1489 |
+
}
|
1490 |
+
|
1491 |
+
return $c;
|
1492 |
+
case 'keyword':
|
1493 |
+
$name = $value[1];
|
1494 |
+
if (isset(self::$cssColors[$name])) {
|
1495 |
+
$rgba = explode(',', self::$cssColors[$name]);
|
1496 |
+
|
1497 |
+
if (isset($rgba[3])) return array(
|
1498 |
+
'color',
|
1499 |
+
$rgba[0],
|
1500 |
+
$rgba[1],
|
1501 |
+
$rgba[2],
|
1502 |
+
$rgba[3]
|
1503 |
+
);
|
1504 |
+
|
1505 |
+
return array(
|
1506 |
+
'color',
|
1507 |
+
$rgba[0],
|
1508 |
+
$rgba[1],
|
1509 |
+
$rgba[2]
|
1510 |
+
);
|
1511 |
+
}
|
1512 |
+
|
1513 |
+
return null;
|
1514 |
+
}
|
1515 |
+
}
|
1516 |
+
|
1517 |
+
// make something string like into a string
|
1518 |
+
protected function coerceString($value) {
|
1519 |
+
switch ($value[0]) {
|
1520 |
+
case "string":
|
1521 |
+
return $value;
|
1522 |
+
case "keyword":
|
1523 |
+
return array(
|
1524 |
+
"string",
|
1525 |
+
"",
|
1526 |
+
array($value[1])
|
1527 |
+
);
|
1528 |
+
}
|
1529 |
+
|
1530 |
+
return null;
|
1531 |
+
}
|
1532 |
+
|
1533 |
+
// turn list of length 1 into value type
|
1534 |
+
protected function flattenList($value) {
|
1535 |
+
if ($value[0] == "list" && count($value[2]) == 1) {
|
1536 |
+
return $this->flattenList($value[2][0]);
|
1537 |
+
}
|
1538 |
+
|
1539 |
+
return $value;
|
1540 |
+
}
|
1541 |
+
|
1542 |
+
protected function toBool($a) {
|
1543 |
+
if ($a) return self::$TRUE; else return self::$FALSE;
|
1544 |
+
}
|
1545 |
+
|
1546 |
+
// evaluate an expression
|
1547 |
+
protected function evaluate($exp) {
|
1548 |
+
list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp;
|
1549 |
+
|
1550 |
+
$left = $this->reduce($left, true);
|
1551 |
+
$right = $this->reduce($right, true);
|
1552 |
+
|
1553 |
+
if ($leftColor = $this->coerceColor($left)) {
|
1554 |
+
$left = $leftColor;
|
1555 |
+
}
|
1556 |
+
|
1557 |
+
if ($rightColor = $this->coerceColor($right)) {
|
1558 |
+
$right = $rightColor;
|
1559 |
+
}
|
1560 |
+
|
1561 |
+
$ltype = $left[0];
|
1562 |
+
$rtype = $right[0];
|
1563 |
+
|
1564 |
+
// operators that work on all types
|
1565 |
+
if ($op == "and") {
|
1566 |
+
return $this->toBool($left == self::$TRUE && $right == self::$TRUE);
|
1567 |
+
}
|
1568 |
+
|
1569 |
+
if ($op == "=") {
|
1570 |
+
return $this->toBool($this->eq($left, $right));
|
1571 |
+
}
|
1572 |
+
|
1573 |
+
if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) {
|
1574 |
+
return $str;
|
1575 |
+
}
|
1576 |
+
|
1577 |
+
// type based operators
|
1578 |
+
$fname = "op_${ltype}_${rtype}";
|
1579 |
+
if (is_callable(array(
|
1580 |
+
$this,
|
1581 |
+
$fname
|
1582 |
+
))) {
|
1583 |
+
$out = $this->$fname($op, $left, $right);
|
1584 |
+
if (!is_null($out)) return $out;
|
1585 |
+
}
|
1586 |
+
|
1587 |
+
// make the expression look it did before being parsed
|
1588 |
+
$paddedOp = $op;
|
1589 |
+
if ($whiteBefore) $paddedOp = " " . $paddedOp;
|
1590 |
+
if ($whiteAfter) $paddedOp .= " ";
|
1591 |
+
|
1592 |
+
return array(
|
1593 |
+
"string",
|
1594 |
+
"",
|
1595 |
+
array(
|
1596 |
+
$left,
|
1597 |
+
$paddedOp,
|
1598 |
+
$right
|
1599 |
+
)
|
1600 |
+
);
|
1601 |
+
}
|
1602 |
+
|
1603 |
+
protected function stringConcatenate($left, $right) {
|
1604 |
+
if ($strLeft = $this->coerceString($left)) {
|
1605 |
+
if ($right[0] == "string") {
|
1606 |
+
$right[1] = "";
|
1607 |
+
}
|
1608 |
+
$strLeft[2][] = $right;
|
1609 |
+
|
1610 |
+
return $strLeft;
|
1611 |
+
}
|
1612 |
+
|
1613 |
+
if ($strRight = $this->coerceString($right)) {
|
1614 |
+
array_unshift($strRight[2], $left);
|
1615 |
+
|
1616 |
+
return $strRight;
|
1617 |
+
}
|
1618 |
+
}
|
1619 |
+
|
1620 |
+
|
1621 |
+
// make sure a color's components don't go out of bounds
|
1622 |
+
protected function fixColor($c) {
|
1623 |
+
foreach (range(1, 3) as $i) {
|
1624 |
+
if ($c[$i] < 0) $c[$i] = 0;
|
1625 |
+
if ($c[$i] > 255) $c[$i] = 255;
|
1626 |
+
}
|
1627 |
+
|
1628 |
+
return $c;
|
1629 |
+
}
|
1630 |
+
|
1631 |
+
protected function op_number_color($op, $lft, $rgt) {
|
1632 |
+
if ($op == '+' || $op == '*') {
|
1633 |
+
return $this->op_color_number($op, $rgt, $lft);
|
1634 |
+
}
|
1635 |
+
}
|
1636 |
+
|
1637 |
+
protected function op_color_number($op, $lft, $rgt) {
|
1638 |
+
if ($rgt[0] == '%') $rgt[1] /= 100;
|
1639 |
+
|
1640 |
+
return $this->op_color_color($op, $lft, array_fill(1, count($lft) - 1, $rgt[1]));
|
1641 |
+
}
|
1642 |
+
|
1643 |
+
protected function op_color_color($op, $left, $right) {
|
1644 |
+
$out = array('color');
|
1645 |
+
$max = count($left) > count($right) ? count($left) : count($right);
|
1646 |
+
foreach (range(1, $max - 1) as $i) {
|
1647 |
+
$lval = isset($left[$i]) ? $left[$i] : 0;
|
1648 |
+
$rval = isset($right[$i]) ? $right[$i] : 0;
|
1649 |
+
switch ($op) {
|
1650 |
+
case '+':
|
1651 |
+
$out[] = $lval + $rval;
|
1652 |
+
break;
|
1653 |
+
case '-':
|
1654 |
+
$out[] = $lval - $rval;
|
1655 |
+
break;
|
1656 |
+
case '*':
|
1657 |
+
$out[] = $lval * $rval;
|
1658 |
+
break;
|
1659 |
+
case '%':
|
1660 |
+
$out[] = $lval % $rval;
|
1661 |
+
break;
|
1662 |
+
case '/':
|
1663 |
+
if ($rval == 0) $this->throwError("evaluate error: can't divide by zero");
|
1664 |
+
$out[] = $lval / $rval;
|
1665 |
+
break;
|
1666 |
+
default:
|
1667 |
+
$this->throwError('evaluate error: color op number failed on op ' . $op);
|
1668 |
+
}
|
1669 |
+
}
|
1670 |
+
|
1671 |
+
return $this->fixColor($out);
|
1672 |
+
}
|
1673 |
+
|
1674 |
+
function lib_red($color) {
|
1675 |
+
$color = $this->coerceColor($color);
|
1676 |
+
if (is_null($color)) {
|
1677 |
+
$this->throwError('color expected for red()');
|
1678 |
+
}
|
1679 |
+
|
1680 |
+
return $color[1];
|
1681 |
+
}
|
1682 |
+
|
1683 |
+
function lib_green($color) {
|
1684 |
+
$color = $this->coerceColor($color);
|
1685 |
+
if (is_null($color)) {
|
1686 |
+
$this->throwError('color expected for green()');
|
1687 |
+
}
|
1688 |
+
|
1689 |
+
return $color[2];
|
1690 |
+
}
|
1691 |
+
|
1692 |
+
function lib_blue($color) {
|
1693 |
+
$color = $this->coerceColor($color);
|
1694 |
+
if (is_null($color)) {
|
1695 |
+
$this->throwError('color expected for blue()');
|
1696 |
+
}
|
1697 |
+
|
1698 |
+
return $color[3];
|
1699 |
+
}
|
1700 |
+
|
1701 |
+
|
1702 |
+
// operator on two numbers
|
1703 |
+
protected function op_number_number($op, $left, $right) {
|
1704 |
+
$unit = empty($left[2]) ? $right[2] : $left[2];
|
1705 |
+
|
1706 |
+
$value = 0;
|
1707 |
+
switch ($op) {
|
1708 |
+
case '+':
|
1709 |
+
$value = $left[1] + $right[1];
|
1710 |
+
break;
|
1711 |
+
case '*':
|
1712 |
+
$value = $left[1] * $right[1];
|
1713 |
+
break;
|
1714 |
+
case '-':
|
1715 |
+
$value = $left[1] - $right[1];
|
1716 |
+
break;
|
1717 |
+
case '%':
|
1718 |
+
$value = $left[1] % $right[1];
|
1719 |
+
break;
|
1720 |
+
case '/':
|
1721 |
+
if ($right[1] == 0) $this->throwError('parse error: divide by zero');
|
1722 |
+
$value = $left[1] / $right[1];
|
1723 |
+
break;
|
1724 |
+
case '<':
|
1725 |
+
return $this->toBool($left[1] < $right[1]);
|
1726 |
+
case '>':
|
1727 |
+
return $this->toBool($left[1] > $right[1]);
|
1728 |
+
case '>=':
|
1729 |
+
return $this->toBool($left[1] >= $right[1]);
|
1730 |
+
case '=<':
|
1731 |
+
return $this->toBool($left[1] <= $right[1]);
|
1732 |
+
default:
|
1733 |
+
$this->throwError('parse error: unknown number operator: ' . $op);
|
1734 |
+
}
|
1735 |
+
|
1736 |
+
return array(
|
1737 |
+
"number",
|
1738 |
+
$value,
|
1739 |
+
$unit
|
1740 |
+
);
|
1741 |
+
}
|
1742 |
+
|
1743 |
+
|
1744 |
+
/* environment functions */
|
1745 |
+
|
1746 |
+
protected function makeOutputBlock($type, $selectors = null) {
|
1747 |
+
$b = new stdClass;
|
1748 |
+
$b->lines = array();
|
1749 |
+
$b->children = array();
|
1750 |
+
$b->selectors = $selectors;
|
1751 |
+
$b->type = $type;
|
1752 |
+
$b->parent = $this->scope;
|
1753 |
+
|
1754 |
+
return $b;
|
1755 |
+
}
|
1756 |
+
|
1757 |
+
// the state of execution
|
1758 |
+
protected function pushEnv($block = null) {
|
1759 |
+
$e = new stdclass;
|
1760 |
+
$e->parent = $this->env;
|
1761 |
+
$e->store = array();
|
1762 |
+
$e->block = $block;
|
1763 |
+
|
1764 |
+
$this->env = $e;
|
1765 |
+
|
1766 |
+
return $e;
|
1767 |
+
}
|
1768 |
+
|
1769 |
+
// pop something off the stack
|
1770 |
+
protected function popEnv() {
|
1771 |
+
$old = $this->env;
|
1772 |
+
$this->env = $this->env->parent;
|
1773 |
+
|
1774 |
+
return $old;
|
1775 |
+
}
|
1776 |
+
|
1777 |
+
// set something in the current env
|
1778 |
+
protected function set($name, $value) {
|
1779 |
+
$this->env->store[$name] = $value;
|
1780 |
+
}
|
1781 |
+
|
1782 |
+
|
1783 |
+
// get the highest occurrence entry for a name
|
1784 |
+
protected function get($name, $default = null) {
|
1785 |
+
$current = $this->env;
|
1786 |
+
|
1787 |
+
$isArguments = $name == $this->vPrefix . 'arguments';
|
1788 |
+
while ($current) {
|
1789 |
+
if ($isArguments && isset($current->arguments)) {
|
1790 |
+
return array(
|
1791 |
+
'list',
|
1792 |
+
' ',
|
1793 |
+
$current->arguments
|
1794 |
+
);
|
1795 |
+
}
|
1796 |
+
|
1797 |
+
if (isset($current->store[$name])) return $current->store[$name]; else {
|
1798 |
+
$current = isset($current->storeParent) ? $current->storeParent : $current->parent;
|
1799 |
+
}
|
1800 |
+
}
|
1801 |
+
|
1802 |
+
return $default;
|
1803 |
+
}
|
1804 |
+
|
1805 |
+
// inject array of unparsed strings into environment as variables
|
1806 |
+
protected function injectVariables($args) {
|
1807 |
+
$this->pushEnv();
|
1808 |
+
$parser = new LessParser($this, __METHOD__);
|
1809 |
+
foreach ($args as $name => $strValue) {
|
1810 |
+
if ($name[0] != '@') $name = '@' . $name;
|
1811 |
+
$parser->count = 0;
|
1812 |
+
$parser->buffer = (string)$strValue;
|
1813 |
+
if (!$parser->propertyValue($value)) {
|
1814 |
+
throw new Exception("failed to parse passed in variable $name: $strValue");
|
1815 |
+
}
|
1816 |
+
|
1817 |
+
$this->set($name, $value);
|
1818 |
+
}
|
1819 |
+
}
|
1820 |
+
|
1821 |
+
/**
|
1822 |
+
* Initialize any static state, can initialize parser for a file
|
1823 |
+
* $opts isn't used yet
|
1824 |
+
*/
|
1825 |
+
public function __construct($fname = null) {
|
1826 |
+
if ($fname !== null) {
|
1827 |
+
// used for deprecated parse method
|
1828 |
+
$this->_parseFile = $fname;
|
1829 |
+
}
|
1830 |
+
}
|
1831 |
+
|
1832 |
+
public function compile($string, $name = null) {
|
1833 |
+
$locale = setlocale(LC_NUMERIC, 0);
|
1834 |
+
setlocale(LC_NUMERIC, "C");
|
1835 |
+
|
1836 |
+
$this->parser = $this->makeParser($name);
|
1837 |
+
$root = $this->parser->parse($string);
|
1838 |
+
|
1839 |
+
$this->env = null;
|
1840 |
+
$this->scope = null;
|
1841 |
+
|
1842 |
+
$this->formatter = $this->newFormatter();
|
1843 |
+
|
1844 |
+
if (!empty($this->registeredVars)) {
|
1845 |
+
$this->injectVariables($this->registeredVars);
|
1846 |
+
}
|
1847 |
+
|
1848 |
+
$this->sourceParser = $this->parser; // used for error messages
|
1849 |
+
$this->compileBlock($root);
|
1850 |
+
|
1851 |
+
$out = $this->formatter->block($this->scope);
|
1852 |
+
|
1853 |
+
setlocale(LC_NUMERIC, $locale);
|
1854 |
+
|
1855 |
+
return $out;
|
1856 |
+
}
|
1857 |
+
|
1858 |
+
public function compileFile($fname, $outFname = null) {
|
1859 |
+
if (!is_readable($fname)) {
|
1860 |
+
throw new Exception('load error: failed to find ' . $fname);
|
1861 |
+
}
|
1862 |
+
|
1863 |
+
$pi = pathinfo($fname);
|
1864 |
+
|
1865 |
+
$oldImport = $this->importDir;
|
1866 |
+
|
1867 |
+
$this->importDir = (array)$this->importDir;
|
1868 |
+
$this->importDir[] = $pi['dirname'] . '/';
|
1869 |
+
|
1870 |
+
$this->allParsedFiles = array();
|
1871 |
+
$this->addParsedFile($fname);
|
1872 |
+
|
1873 |
+
$out = $this->compile(file_get_contents($fname), $fname);
|
1874 |
+
|
1875 |
+
$this->importDir = $oldImport;
|
1876 |
+
|
1877 |
+
if ($outFname !== null) {
|
1878 |
+
return file_put_contents($outFname, $out);
|
1879 |
+
}
|
1880 |
+
|
1881 |
+
return $out;
|
1882 |
+
}
|
1883 |
+
|
1884 |
+
// compile only if changed input has changed or output doesn't exist
|
1885 |
+
public function checkedCompile($in, $out) {
|
1886 |
+
if (!is_file($out) || filemtime($in) > filemtime($out)) {
|
1887 |
+
$this->compileFile($in, $out);
|
1888 |
+
|
1889 |
+
return true;
|
1890 |
+
}
|
1891 |
+
|
1892 |
+
return false;
|
1893 |
+
}
|
1894 |
+
|
1895 |
+
/**
|
1896 |
+
* Execute lessphp on a .less file or a lessphp cache structure
|
1897 |
+
*
|
1898 |
+
* The lessphp cache structure contains information about a specific
|
1899 |
+
* less file having been parsed. It can be used as a hint for future
|
1900 |
+
* calls to determine whether or not a rebuild is required.
|
1901 |
+
*
|
1902 |
+
* The cache structure contains two important keys that may be used
|
1903 |
+
* externally:
|
1904 |
+
*
|
1905 |
+
* compiled: The final compiled CSS
|
1906 |
+
* updated: The time (in seconds) the CSS was last compiled
|
1907 |
+
*
|
1908 |
+
* The cache structure is a plain-ol' PHP associative array and can
|
1909 |
+
* be serialized and unserialized without a hitch.
|
1910 |
+
*
|
1911 |
+
* @param mixed $in Input
|
1912 |
+
* @param bool $force Force rebuild?
|
1913 |
+
*
|
1914 |
+
* @return array lessphp cache structure
|
1915 |
+
*/
|
1916 |
+
public function cachedCompile($in, $force = false) {
|
1917 |
+
// assume no root
|
1918 |
+
$root = null;
|
1919 |
+
|
1920 |
+
if (is_string($in)) {
|
1921 |
+
$root = $in;
|
1922 |
+
} elseif (is_array($in) and isset($in['root'])) {
|
1923 |
+
if ($force or !isset($in['files'])) {
|
1924 |
+
// If we are forcing a recompile or if for some reason the
|
1925 |
+
// structure does not contain any file information we should
|
1926 |
+
// specify the root to trigger a rebuild.
|
1927 |
+
$root = $in['root'];
|
1928 |
+
} elseif (isset($in['files']) and is_array($in['files'])) {
|
1929 |
+
foreach ($in['files'] as $fname => $ftime) {
|
1930 |
+
if (!file_exists($fname) or filemtime($fname) > $ftime) {
|
1931 |
+
// One of the files we knew about previously has changed
|
1932 |
+
// so we should look at our incoming root again.
|
1933 |
+
$root = $in['root'];
|
1934 |
+
break;
|
1935 |
+
}
|
1936 |
+
}
|
1937 |
+
}
|
1938 |
+
} else {
|
1939 |
+
// TODO: Throw an exception? We got neither a string nor something
|
1940 |
+
// that looks like a compatible lessphp cache structure.
|
1941 |
+
return null;
|
1942 |
+
}
|
1943 |
+
|
1944 |
+
if ($root !== null) {
|
1945 |
+
// If we have a root value which means we should rebuild.
|
1946 |
+
$out = array();
|
1947 |
+
$out['root'] = $root;
|
1948 |
+
$out['compiled'] = $this->compileFile($root);
|
1949 |
+
$out['files'] = $this->allParsedFiles();
|
1950 |
+
$out['updated'] = time();
|
1951 |
+
|
1952 |
+
return $out;
|
1953 |
+
} else {
|
1954 |
+
// No changes, pass back the structure
|
1955 |
+
// we were given initially.
|
1956 |
+
return $in;
|
1957 |
+
}
|
1958 |
+
|
1959 |
+
}
|
1960 |
+
|
1961 |
+
// parse and compile buffer
|
1962 |
+
// This is deprecated
|
1963 |
+
public function parse($str = null, $initialVariables = null) {
|
1964 |
+
if (is_array($str)) {
|
1965 |
+
$initialVariables = $str;
|
1966 |
+
$str = null;
|
1967 |
+
}
|
1968 |
+
|
1969 |
+
$oldVars = $this->registeredVars;
|
1970 |
+
if ($initialVariables !== null) {
|
1971 |
+
$this->setVariables($initialVariables);
|
1972 |
+
}
|
1973 |
+
|
1974 |
+
if ($str == null) {
|
1975 |
+
if (empty($this->_parseFile)) {
|
1976 |
+
throw new Exception("nothing to parse");
|
1977 |
+
}
|
1978 |
+
|
1979 |
+
$out = $this->compileFile($this->_parseFile);
|
1980 |
+
} else {
|
1981 |
+
$out = $this->compile($str);
|
1982 |
+
}
|
1983 |
+
|
1984 |
+
$this->registeredVars = $oldVars;
|
1985 |
+
|
1986 |
+
return $out;
|
1987 |
+
}
|
1988 |
+
|
1989 |
+
protected function makeParser($name) {
|
1990 |
+
$parser = new LessParser($this, $name);
|
1991 |
+
$parser->writeComments = $this->preserveComments;
|
1992 |
+
|
1993 |
+
return $parser;
|
1994 |
+
}
|
1995 |
+
|
1996 |
+
public function setFormatter($name) {
|
1997 |
+
$this->formatterName = $name;
|
1998 |
+
}
|
1999 |
+
|
2000 |
+
/**
|
2001 |
+
* @return Classic
|
2002 |
+
*/
|
2003 |
+
protected function newFormatter() {
|
2004 |
+
return new Compressed();
|
2005 |
+
}
|
2006 |
+
|
2007 |
+
public function setPreserveComments($preserve) {
|
2008 |
+
$this->preserveComments = $preserve;
|
2009 |
+
}
|
2010 |
+
|
2011 |
+
public function registerFunction($name, $func) {
|
2012 |
+
$this->libFunctions[$name] = $func;
|
2013 |
+
}
|
2014 |
+
|
2015 |
+
public function unregisterFunction($name) {
|
2016 |
+
unset($this->libFunctions[$name]);
|
2017 |
+
}
|
2018 |
+
|
2019 |
+
public function setVariables($variables) {
|
2020 |
+
$this->registeredVars = array_merge($this->registeredVars, $variables);
|
2021 |
+
}
|
2022 |
+
|
2023 |
+
/**
|
2024 |
+
* @return array
|
2025 |
+
*/
|
2026 |
+
public function getVariables() {
|
2027 |
+
return $this->registeredVars;
|
2028 |
+
}
|
2029 |
+
|
2030 |
+
public function unsetVariable($name) {
|
2031 |
+
unset($this->registeredVars[$name]);
|
2032 |
+
}
|
2033 |
+
|
2034 |
+
public function setImportDir($dirs) {
|
2035 |
+
$this->importDir = (array)$dirs;
|
2036 |
+
}
|
2037 |
+
|
2038 |
+
public function addImportDir($dir) {
|
2039 |
+
$this->importDir = (array)$this->importDir;
|
2040 |
+
$this->importDir[] = $dir;
|
2041 |
+
}
|
2042 |
+
|
2043 |
+
public function allParsedFiles() {
|
2044 |
+
return $this->allParsedFiles;
|
2045 |
+
}
|
2046 |
+
|
2047 |
+
protected function addParsedFile($file) {
|
2048 |
+
$this->allParsedFiles[Filesystem::realpath($file)] = filemtime($file);
|
2049 |
+
}
|
2050 |
+
|
2051 |
+
/**
|
2052 |
+
* Uses the current value of $this->count to show line and line number
|
2053 |
+
*/
|
2054 |
+
protected function throwError($msg = null) {
|
2055 |
+
if ($this->sourceLoc >= 0) {
|
2056 |
+
$this->sourceParser->throwError($msg, $this->sourceLoc);
|
2057 |
+
}
|
2058 |
+
throw new Exception($msg);
|
2059 |
+
}
|
2060 |
+
|
2061 |
+
// compile file $in to file $out if $in is newer than $out
|
2062 |
+
// returns true when it compiles, false otherwise
|
2063 |
+
public static function ccompile($in, $out, $less = null) {
|
2064 |
+
if ($less === null) {
|
2065 |
+
$less = new self;
|
2066 |
+
}
|
2067 |
+
|
2068 |
+
return $less->checkedCompile($in, $out);
|
2069 |
+
}
|
2070 |
+
|
2071 |
+
public static function cexecute($in, $force = false, $less = null) {
|
2072 |
+
if ($less === null) {
|
2073 |
+
$less = new self;
|
2074 |
+
}
|
2075 |
+
|
2076 |
+
return $less->cachedCompile($in, $force);
|
2077 |
+
}
|
2078 |
+
|
2079 |
+
static protected $cssColors = array(
|
2080 |
+
'aliceblue' => '240,248,255',
|
2081 |
+
'antiquewhite' => '250,235,215',
|
2082 |
+
'aqua' => '0,255,255',
|
2083 |
+
'aquamarine' => '127,255,212',
|
2084 |
+
'azure' => '240,255,255',
|
2085 |
+
'beige' => '245,245,220',
|
2086 |
+
'bisque' => '255,228,196',
|
2087 |
+
'black' => '0,0,0',
|
2088 |
+
'blanchedalmond' => '255,235,205',
|
2089 |
+
'blue' => '0,0,255',
|
2090 |
+
'blueviolet' => '138,43,226',
|
2091 |
+
'brown' => '165,42,42',
|
2092 |
+
'burlywood' => '222,184,135',
|
2093 |
+
'cadetblue' => '95,158,160',
|
2094 |
+
'chartreuse' => '127,255,0',
|
2095 |
+
'chocolate' => '210,105,30',
|
2096 |
+
'coral' => '255,127,80',
|
2097 |
+
'cornflowerblue' => '100,149,237',
|
2098 |
+
'cornsilk' => '255,248,220',
|
2099 |
+
'crimson' => '220,20,60',
|
2100 |
+
'cyan' => '0,255,255',
|
2101 |
+
'darkblue' => '0,0,139',
|
2102 |
+
'darkcyan' => '0,139,139',
|
2103 |
+
'darkgoldenrod' => '184,134,11',
|
2104 |
+
'darkgray' => '169,169,169',
|
2105 |
+
'darkgreen' => '0,100,0',
|
2106 |
+
'darkgrey' => '169,169,169',
|
2107 |
+
'darkkhaki' => '189,183,107',
|
2108 |
+
'darkmagenta' => '139,0,139',
|
2109 |
+
'darkolivegreen' => '85,107,47',
|
2110 |
+
'darkorange' => '255,140,0',
|
2111 |
+
'darkorchid' => '153,50,204',
|
2112 |
+
'darkred' => '139,0,0',
|
2113 |
+
'darksalmon' => '233,150,122',
|
2114 |
+
'darkseagreen' => '143,188,143',
|
2115 |
+
'darkslateblue' => '72,61,139',
|
2116 |
+
'darkslategray' => '47,79,79',
|
2117 |
+
'darkslategrey' => '47,79,79',
|
2118 |
+
'darkturquoise' => '0,206,209',
|
2119 |
+
'darkviolet' => '148,0,211',
|
2120 |
+
'deeppink' => '255,20,147',
|
2121 |
+
'deepskyblue' => '0,191,255',
|
2122 |
+
'dimgray' => '105,105,105',
|
2123 |
+
'dimgrey' => '105,105,105',
|
2124 |
+
'dodgerblue' => '30,144,255',
|
2125 |
+
'firebrick' => '178,34,34',
|
2126 |
+
'floralwhite' => '255,250,240',
|
2127 |
+
'forestgreen' => '34,139,34',
|
2128 |
+
'fuchsia' => '255,0,255',
|
2129 |
+
'gainsboro' => '220,220,220',
|
2130 |
+
'ghostwhite' => '248,248,255',
|
2131 |
+
'gold' => '255,215,0',
|
2132 |
+
'goldenrod' => '218,165,32',
|
2133 |
+
'gray' => '128,128,128',
|
2134 |
+
'green' => '0,128,0',
|
2135 |
+
'greenyellow' => '173,255,47',
|
2136 |
+
'grey' => '128,128,128',
|
2137 |
+
'honeydew' => '240,255,240',
|
2138 |
+
'hotpink' => '255,105,180',
|
2139 |
+
'indianred' => '205,92,92',
|
2140 |
+
'indigo' => '75,0,130',
|
2141 |
+
'ivory' => '255,255,240',
|
2142 |
+
'khaki' => '240,230,140',
|
2143 |
+
'lavender' => '230,230,250',
|
2144 |
+
'lavenderblush' => '255,240,245',
|
2145 |
+
'lawngreen' => '124,252,0',
|
2146 |
+
'lemonchiffon' => '255,250,205',
|
2147 |
+
'lightblue' => '173,216,230',
|
2148 |
+
'lightcoral' => '240,128,128',
|
2149 |
+
'lightcyan' => '224,255,255',
|
2150 |
+
'lightgoldenrodyellow' => '250,250,210',
|
2151 |
+
'lightgray' => '211,211,211',
|
2152 |
+
'lightgreen' => '144,238,144',
|
2153 |
+
'lightgrey' => '211,211,211',
|
2154 |
+
'lightpink' => '255,182,193',
|
2155 |
+
'lightsalmon' => '255,160,122',
|
2156 |
+
'lightseagreen' => '32,178,170',
|
2157 |
+
'lightskyblue' => '135,206,250',
|
2158 |
+
'lightslategray' => '119,136,153',
|
2159 |
+
'lightslategrey' => '119,136,153',
|
2160 |
+
'lightsteelblue' => '176,196,222',
|
2161 |
+
'lightyellow' => '255,255,224',
|
2162 |
+
'lime' => '0,255,0',
|
2163 |
+
'limegreen' => '50,205,50',
|
2164 |
+
'linen' => '250,240,230',
|
2165 |
+
'magenta' => '255,0,255',
|
2166 |
+
'maroon' => '128,0,0',
|
2167 |
+
'mediumaquamarine' => '102,205,170',
|
2168 |
+
'mediumblue' => '0,0,205',
|
2169 |
+
'mediumorchid' => '186,85,211',
|
2170 |
+
'mediumpurple' => '147,112,219',
|
2171 |
+
'mediumseagreen' => '60,179,113',
|
2172 |
+
'mediumslateblue' => '123,104,238',
|
2173 |
+
'mediumspringgreen' => '0,250,154',
|
2174 |
+
'mediumturquoise' => '72,209,204',
|
2175 |
+
'mediumvioletred' => '199,21,133',
|
2176 |
+
'midnightblue' => '25,25,112',
|
2177 |
+
'mintcream' => '245,255,250',
|
2178 |
+
'mistyrose' => '255,228,225',
|
2179 |
+
'moccasin' => '255,228,181',
|
2180 |
+
'navajowhite' => '255,222,173',
|
2181 |
+
'navy' => '0,0,128',
|
2182 |
+
'oldlace' => '253,245,230',
|
2183 |
+
'olive' => '128,128,0',
|
2184 |
+
'olivedrab' => '107,142,35',
|
2185 |
+
'orange' => '255,165,0',
|
2186 |
+
'orangered' => '255,69,0',
|
2187 |
+
'orchid' => '218,112,214',
|
2188 |
+
'palegoldenrod' => '238,232,170',
|
2189 |
+
'palegreen' => '152,251,152',
|
2190 |
+
'paleturquoise' => '175,238,238',
|
2191 |
+
'palevioletred' => '219,112,147',
|
2192 |
+
'papayawhip' => '255,239,213',
|
2193 |
+
'peachpuff' => '255,218,185',
|
2194 |
+
'peru' => '205,133,63',
|
2195 |
+
'pink' => '255,192,203',
|
2196 |
+
'plum' => '221,160,221',
|
2197 |
+
'powderblue' => '176,224,230',
|
2198 |
+
'purple' => '128,0,128',
|
2199 |
+
'red' => '255,0,0',
|
2200 |
+
'rosybrown' => '188,143,143',
|
2201 |
+
'royalblue' => '65,105,225',
|
2202 |
+
'saddlebrown' => '139,69,19',
|
2203 |
+
'salmon' => '250,128,114',
|
2204 |
+
'sandybrown' => '244,164,96',
|
2205 |
+
'seagreen' => '46,139,87',
|
2206 |
+
'seashell' => '255,245,238',
|
2207 |
+
'sienna' => '160,82,45',
|
2208 |
+
'silver' => '192,192,192',
|
2209 |
+
'skyblue' => '135,206,235',
|
2210 |
+
'slateblue' => '106,90,205',
|
2211 |
+
'slategray' => '112,128,144',
|
2212 |
+
'slategrey' => '112,128,144',
|
2213 |
+
'snow' => '255,250,250',
|
2214 |
+
'springgreen' => '0,255,127',
|
2215 |
+
'steelblue' => '70,130,180',
|
2216 |
+
'tan' => '210,180,140',
|
2217 |
+
'teal' => '0,128,128',
|
2218 |
+
'thistle' => '216,191,216',
|
2219 |
+
'tomato' => '255,99,71',
|
2220 |
+
'transparent' => '0,0,0,0',
|
2221 |
+
'turquoise' => '64,224,208',
|
2222 |
+
'violet' => '238,130,238',
|
2223 |
+
'wheat' => '245,222,179',
|
2224 |
+
'white' => '255,255,255',
|
2225 |
+
'whitesmoke' => '245,245,245',
|
2226 |
+
'yellow' => '255,255,0',
|
2227 |
+
'yellowgreen' => '154,205,50'
|
2228 |
+
);
|
2229 |
+
}
|
2230 |
+
|
2231 |
+
|
2232 |
+
|
Nextend/Framework/Asset/Css/Less/LessParser.php
ADDED
@@ -0,0 +1,1522 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Asset\Css\Less;
|
5 |
+
|
6 |
+
use Exception;
|
7 |
+
use stdClass;
|
8 |
+
|
9 |
+
class LessParser {
|
10 |
+
|
11 |
+
static protected $nextBlockId = 0; // used to uniquely identify blocks
|
12 |
+
|
13 |
+
static protected $precedence = array(
|
14 |
+
'=<' => 0,
|
15 |
+
'>=' => 0,
|
16 |
+
'=' => 0,
|
17 |
+
'<' => 0,
|
18 |
+
'>' => 0,
|
19 |
+
|
20 |
+
'+' => 1,
|
21 |
+
'-' => 1,
|
22 |
+
'*' => 2,
|
23 |
+
'/' => 2,
|
24 |
+
'%' => 2,
|
25 |
+
);
|
26 |
+
|
27 |
+
static protected $whitePattern;
|
28 |
+
static protected $commentMulti;
|
29 |
+
|
30 |
+
static protected $commentSingle = "//";
|
31 |
+
static protected $commentMultiLeft = "/*";
|
32 |
+
static protected $commentMultiRight = "*/";
|
33 |
+
|
34 |
+
// regex string to match any of the operators
|
35 |
+
static protected $operatorString;
|
36 |
+
|
37 |
+
// these properties will supress division unless it's inside parenthases
|
38 |
+
static protected $supressDivisionProps = array(
|
39 |
+
'/border-radius$/i',
|
40 |
+
'/^font$/i'
|
41 |
+
);
|
42 |
+
|
43 |
+
protected $blockDirectives = array(
|
44 |
+
"font-face",
|
45 |
+
"keyframes",
|
46 |
+
"page",
|
47 |
+
"-moz-document"
|
48 |
+
);
|
49 |
+
protected $lineDirectives = array("charset");
|
50 |
+
|
51 |
+
/**
|
52 |
+
* if we are in parens we can be more liberal with whitespace around
|
53 |
+
* operators because it must evaluate to a single value and thus is less
|
54 |
+
* ambiguous.
|
55 |
+
*
|
56 |
+
* Consider:
|
57 |
+
* property1: 10 -5; // is two numbers, 10 and -5
|
58 |
+
* property2: (10 -5); // should evaluate to 5
|
59 |
+
*/
|
60 |
+
protected $inParens = false;
|
61 |
+
|
62 |
+
// caches preg escaped literals
|
63 |
+
static protected $literalCache = array();
|
64 |
+
|
65 |
+
public function __construct($lessc, $sourceName = null) {
|
66 |
+
$this->eatWhiteDefault = true;
|
67 |
+
// reference to less needed for vPrefix, mPrefix, and parentSelector
|
68 |
+
$this->lessc = $lessc;
|
69 |
+
|
70 |
+
$this->sourceName = $sourceName; // name used for error messages
|
71 |
+
|
72 |
+
$this->writeComments = false;
|
73 |
+
|
74 |
+
if (!self::$operatorString) {
|
75 |
+
self::$operatorString = '(' . implode('|', array_map(array(
|
76 |
+
LessCompiler::class,
|
77 |
+
'preg_quote'
|
78 |
+
), array_keys(self::$precedence))) . ')';
|
79 |
+
|
80 |
+
$commentSingle = LessCompiler::preg_quote(self::$commentSingle);
|
81 |
+
$commentMultiLeft = LessCompiler::preg_quote(self::$commentMultiLeft);
|
82 |
+
$commentMultiRight = LessCompiler::preg_quote(self::$commentMultiRight);
|
83 |
+
|
84 |
+
self::$commentMulti = $commentMultiLeft . '.*?' . $commentMultiRight;
|
85 |
+
self::$whitePattern = '/' . $commentSingle . '[^\n]*\s*|(' . self::$commentMulti . ')\s*|\s+/Ais';
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
public function parse($buffer) {
|
90 |
+
$this->count = 0;
|
91 |
+
$this->line = 1;
|
92 |
+
|
93 |
+
$this->env = null; // block stack
|
94 |
+
$this->buffer = $this->writeComments ? $buffer : $this->removeComments($buffer);
|
95 |
+
$this->pushSpecialBlock("root");
|
96 |
+
$this->eatWhiteDefault = true;
|
97 |
+
$this->seenComments = array();
|
98 |
+
|
99 |
+
// trim whitespace on head
|
100 |
+
// if (preg_match('/^\s+/', $this->buffer, $m)) {
|
101 |
+
// $this->line += substr_count($m[0], "\n");
|
102 |
+
// $this->buffer = ltrim($this->buffer);
|
103 |
+
// }
|
104 |
+
$this->whitespace();
|
105 |
+
|
106 |
+
// parse the entire file
|
107 |
+
$lastCount = $this->count;
|
108 |
+
while (false !== $this->parseChunk()) ;
|
109 |
+
|
110 |
+
if ($this->count != strlen($this->buffer)) $this->throwError();
|
111 |
+
|
112 |
+
// TODO report where the block was opened
|
113 |
+
if (!is_null($this->env->parent)) throw new Exception('parse error: unclosed block');
|
114 |
+
|
115 |
+
return $this->env;
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Parse a single chunk off the head of the buffer and append it to the
|
120 |
+
* current parse environment.
|
121 |
+
* Returns false when the buffer is empty, or when there is an error.
|
122 |
+
*
|
123 |
+
* This function is called repeatedly until the entire document is
|
124 |
+
* parsed.
|
125 |
+
*
|
126 |
+
* This parser is most similar to a recursive descent parser. Single
|
127 |
+
* functions represent discrete grammatical rules for the language, and
|
128 |
+
* they are able to capture the text that represents those rules.
|
129 |
+
*
|
130 |
+
* Consider the function lessc::keyword(). (all parse functions are
|
131 |
+
* structured the same)
|
132 |
+
*
|
133 |
+
* The function takes a single reference argument. When calling the
|
134 |
+
* function it will attempt to match a keyword on the head of the buffer.
|
135 |
+
* If it is successful, it will place the keyword in the referenced
|
136 |
+
* argument, advance the position in the buffer, and return true. If it
|
137 |
+
* fails then it won't advance the buffer and it will return false.
|
138 |
+
*
|
139 |
+
* All of these parse functions are powered by lessc::match(), which behaves
|
140 |
+
* the same way, but takes a literal regular expression. Sometimes it is
|
141 |
+
* more convenient to use match instead of creating a new function.
|
142 |
+
*
|
143 |
+
* Because of the format of the functions, to parse an entire string of
|
144 |
+
* grammatical rules, you can chain them together using &&.
|
145 |
+
*
|
146 |
+
* But, if some of the rules in the chain succeed before one fails, then
|
147 |
+
* the buffer position will be left at an invalid state. In order to
|
148 |
+
* avoid this, lessc::seek() is used to remember and set buffer positions.
|
149 |
+
*
|
150 |
+
* Before parsing a chain, use $s = $this->seek() to remember the current
|
151 |
+
* position into $s. Then if a chain fails, use $this->seek($s) to
|
152 |
+
* go back where we started.
|
153 |
+
*/
|
154 |
+
protected function parseChunk() {
|
155 |
+
if (empty($this->buffer)) return false;
|
156 |
+
$s = $this->seek();
|
157 |
+
|
158 |
+
// setting a property
|
159 |
+
if ($this->keyword($key) && $this->assign() && $this->propertyValue($value, $key) && $this->end()) {
|
160 |
+
$this->append(array(
|
161 |
+
'assign',
|
162 |
+
$key,
|
163 |
+
$value
|
164 |
+
), $s);
|
165 |
+
|
166 |
+
return true;
|
167 |
+
} else {
|
168 |
+
$this->seek($s);
|
169 |
+
}
|
170 |
+
|
171 |
+
|
172 |
+
// look for special css blocks
|
173 |
+
if ($this->literal('@', false)) {
|
174 |
+
$this->count--;
|
175 |
+
|
176 |
+
// media
|
177 |
+
if ($this->literal('@media')) {
|
178 |
+
if (($this->mediaQueryList($mediaQueries) || true) && $this->literal('{')) {
|
179 |
+
$media = $this->pushSpecialBlock("media");
|
180 |
+
$media->queries = is_null($mediaQueries) ? array() : $mediaQueries;
|
181 |
+
|
182 |
+
return true;
|
183 |
+
} else {
|
184 |
+
$this->seek($s);
|
185 |
+
|
186 |
+
return false;
|
187 |
+
}
|
188 |
+
}
|
189 |
+
|
190 |
+
if ($this->literal("@", false) && $this->keyword($dirName)) {
|
191 |
+
if ($this->isDirective($dirName, $this->blockDirectives)) {
|
192 |
+
if (($this->openString("{", $dirValue, null, array(";")) || true) && $this->literal("{")) {
|
193 |
+
$dir = $this->pushSpecialBlock("directive");
|
194 |
+
$dir->name = $dirName;
|
195 |
+
if (isset($dirValue)) $dir->value = $dirValue;
|
196 |
+
|
197 |
+
return true;
|
198 |
+
}
|
199 |
+
} elseif ($this->isDirective($dirName, $this->lineDirectives)) {
|
200 |
+
if ($this->propertyValue($dirValue) && $this->end()) {
|
201 |
+
$this->append(array(
|
202 |
+
"directive",
|
203 |
+
$dirName,
|
204 |
+
$dirValue
|
205 |
+
));
|
206 |
+
|
207 |
+
return true;
|
208 |
+
}
|
209 |
+
}
|
210 |
+
}
|
211 |
+
|
212 |
+
$this->seek($s);
|
213 |
+
}
|
214 |
+
|
215 |
+
// setting a variable
|
216 |
+
if ($this->variable($var) && $this->assign() && $this->propertyValue($value) && $this->end()) {
|
217 |
+
$this->append(array(
|
218 |
+
'assign',
|
219 |
+
$var,
|
220 |
+
$value
|
221 |
+
), $s);
|
222 |
+
|
223 |
+
return true;
|
224 |
+
} else {
|
225 |
+
$this->seek($s);
|
226 |
+
}
|
227 |
+
|
228 |
+
if ($this->import($importValue)) {
|
229 |
+
$this->append($importValue, $s);
|
230 |
+
|
231 |
+
return true;
|
232 |
+
}
|
233 |
+
|
234 |
+
// opening parametric mixin
|
235 |
+
if ($this->tag($tag, true) && $this->argumentDef($args, $isVararg) && ($this->guards($guards) || true) && $this->literal('{')) {
|
236 |
+
$block = $this->pushBlock($this->fixTags(array($tag)));
|
237 |
+
$block->args = $args;
|
238 |
+
$block->isVararg = $isVararg;
|
239 |
+
if (!empty($guards)) $block->guards = $guards;
|
240 |
+
|
241 |
+
return true;
|
242 |
+
} else {
|
243 |
+
$this->seek($s);
|
244 |
+
}
|
245 |
+
|
246 |
+
// opening a simple block
|
247 |
+
if ($this->tags($tags) && $this->literal('{')) {
|
248 |
+
$tags = $this->fixTags($tags);
|
249 |
+
$this->pushBlock($tags);
|
250 |
+
|
251 |
+
return true;
|
252 |
+
} else {
|
253 |
+
$this->seek($s);
|
254 |
+
}
|
255 |
+
|
256 |
+
// closing a block
|
257 |
+
if ($this->literal('}', false)) {
|
258 |
+
try {
|
259 |
+
$block = $this->pop();
|
260 |
+
} catch (Exception $e) {
|
261 |
+
$this->seek($s);
|
262 |
+
$this->throwError($e->getMessage());
|
263 |
+
}
|
264 |
+
|
265 |
+
$hidden = false;
|
266 |
+
if (is_null($block->type)) {
|
267 |
+
$hidden = true;
|
268 |
+
if (!isset($block->args)) {
|
269 |
+
foreach ($block->tags as $tag) {
|
270 |
+
if (!is_string($tag) || $tag[0] != $this->lessc->mPrefix) {
|
271 |
+
$hidden = false;
|
272 |
+
break;
|
273 |
+
}
|
274 |
+
}
|
275 |
+
}
|
276 |
+
|
277 |
+
foreach ($block->tags as $tag) {
|
278 |
+
if (is_string($tag)) {
|
279 |
+
$this->env->children[$tag][] = $block;
|
280 |
+
}
|
281 |
+
}
|
282 |
+
}
|
283 |
+
|
284 |
+
if (!$hidden) {
|
285 |
+
$this->append(array(
|
286 |
+
'block',
|
287 |
+
$block
|
288 |
+
), $s);
|
289 |
+
}
|
290 |
+
|
291 |
+
// this is done here so comments aren't bundled into he block that
|
292 |
+
// was just closed
|
293 |
+
$this->whitespace();
|
294 |
+
|
295 |
+
return true;
|
296 |
+
}
|
297 |
+
|
298 |
+
// mixin
|
299 |
+
if ($this->mixinTags($tags) && ($this->argumentValues($argv) || true) && ($this->keyword($suffix) || true) && $this->end()) {
|
300 |
+
$tags = $this->fixTags($tags);
|
301 |
+
$this->append(array(
|
302 |
+
'mixin',
|
303 |
+
$tags,
|
304 |
+
$argv,
|
305 |
+
$suffix
|
306 |
+
), $s);
|
307 |
+
|
308 |
+
return true;
|
309 |
+
} else {
|
310 |
+
$this->seek($s);
|
311 |
+
}
|
312 |
+
|
313 |
+
// spare ;
|
314 |
+
if ($this->literal(';')) return true;
|
315 |
+
|
316 |
+
return false; // got nothing, throw error
|
317 |
+
}
|
318 |
+
|
319 |
+
protected function isDirective($dirname, $directives) {
|
320 |
+
// TODO: cache pattern in parser
|
321 |
+
$pattern = implode("|", array_map(array(
|
322 |
+
LessCompiler::class,
|
323 |
+
"preg_quote"
|
324 |
+
), $directives));
|
325 |
+
$pattern = '/^(-[a-z-]+-)?(' . $pattern . ')$/i';
|
326 |
+
|
327 |
+
return preg_match($pattern, $dirname);
|
328 |
+
}
|
329 |
+
|
330 |
+
protected function fixTags($tags) {
|
331 |
+
// move @ tags out of variable namespace
|
332 |
+
foreach ($tags as &$tag) {
|
333 |
+
if ($tag[0] == $this->lessc->vPrefix) $tag[0] = $this->lessc->mPrefix;
|
334 |
+
}
|
335 |
+
|
336 |
+
return $tags;
|
337 |
+
}
|
338 |
+
|
339 |
+
// a list of expressions
|
340 |
+
protected function expressionList(&$exps) {
|
341 |
+
$values = array();
|
342 |
+
|
343 |
+
while ($this->expression($exp)) {
|
344 |
+
$values[] = $exp;
|
345 |
+
}
|
346 |
+
|
347 |
+
if (count($values) == 0) return false;
|
348 |
+
|
349 |
+
$exps = LessCompiler::compressList($values, ' ');
|
350 |
+
|
351 |
+
return true;
|
352 |
+
}
|
353 |
+
|
354 |
+
/**
|
355 |
+
* Attempt to consume an expression.
|
356 |
+
*
|
357 |
+
* @link http://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudo-code
|
358 |
+
*/
|
359 |
+
protected function expression(&$out) {
|
360 |
+
if ($this->value($lhs)) {
|
361 |
+
$out = $this->expHelper($lhs, 0);
|
362 |
+
|
363 |
+
// look for / shorthand
|
364 |
+
if (!empty($this->env->supressedDivision)) {
|
365 |
+
unset($this->env->supressedDivision);
|
366 |
+
$s = $this->seek();
|
367 |
+
if ($this->literal("/") && $this->value($rhs)) {
|
368 |
+
$out = array(
|
369 |
+
"list",
|
370 |
+
"",
|
371 |
+
array(
|
372 |
+
$out,
|
373 |
+
array(
|
374 |
+
"keyword",
|
375 |
+
"/"
|
376 |
+
),
|
377 |
+
$rhs
|
378 |
+
)
|
379 |
+
);
|
380 |
+
} else {
|
381 |
+
$this->seek($s);
|
382 |
+
}
|
383 |
+
}
|
384 |
+
|
385 |
+
return true;
|
386 |
+
}
|
387 |
+
|
388 |
+
return false;
|
389 |
+
}
|
390 |
+
|
391 |
+
/**
|
392 |
+
* recursively parse infix equation with $lhs at precedence $minP
|
393 |
+
*/
|
394 |
+
protected function expHelper($lhs, $minP) {
|
395 |
+
$this->inExp = true;
|
396 |
+
$ss = $this->seek();
|
397 |
+
|
398 |
+
while (true) {
|
399 |
+
$whiteBefore = isset($this->buffer[$this->count - 1]) && ctype_space($this->buffer[$this->count - 1]);
|
400 |
+
|
401 |
+
// If there is whitespace before the operator, then we require
|
402 |
+
// whitespace after the operator for it to be an expression
|
403 |
+
$needWhite = $whiteBefore && !$this->inParens;
|
404 |
+
|
405 |
+
if ($this->match(self::$operatorString . ($needWhite ? '\s' : ''), $m) && self::$precedence[$m[1]] >= $minP) {
|
406 |
+
if (!$this->inParens && isset($this->env->currentProperty) && $m[1] == "/" && empty($this->env->supressedDivision)) {
|
407 |
+
foreach (self::$supressDivisionProps as $pattern) {
|
408 |
+
if (preg_match($pattern, $this->env->currentProperty)) {
|
409 |
+
$this->env->supressedDivision = true;
|
410 |
+
break 2;
|
411 |
+
}
|
412 |
+
}
|
413 |
+
}
|
414 |
+
|
415 |
+
|
416 |
+
$whiteAfter = isset($this->buffer[$this->count - 1]) && ctype_space($this->buffer[$this->count - 1]);
|
417 |
+
|
418 |
+
if (!$this->value($rhs)) break;
|
419 |
+
|
420 |
+
// peek for next operator to see what to do with rhs
|
421 |
+
if ($this->peek(self::$operatorString, $next) && self::$precedence[$next[1]] > self::$precedence[$m[1]]) {
|
422 |
+
$rhs = $this->expHelper($rhs, self::$precedence[$next[1]]);
|
423 |
+
}
|
424 |
+
|
425 |
+
$lhs = array(
|
426 |
+
'expression',
|
427 |
+
$m[1],
|
428 |
+
$lhs,
|
429 |
+
$rhs,
|
430 |
+
$whiteBefore,
|
431 |
+
$whiteAfter
|
432 |
+
);
|
433 |
+
$ss = $this->seek();
|
434 |
+
|
435 |
+
continue;
|
436 |
+
}
|
437 |
+
|
438 |
+
break;
|
439 |
+
}
|
440 |
+
|
441 |
+
$this->seek($ss);
|
442 |
+
|
443 |
+
return $lhs;
|
444 |
+
}
|
445 |
+
|
446 |
+
// consume a list of values for a property
|
447 |
+
public function propertyValue(&$value, $keyName = null) {
|
448 |
+
$values = array();
|
449 |
+
|
450 |
+
if ($keyName !== null) $this->env->currentProperty = $keyName;
|
451 |
+
|
452 |
+
$s = null;
|
453 |
+
while ($this->expressionList($v)) {
|
454 |
+
$values[] = $v;
|
455 |
+
$s = $this->seek();
|
456 |
+
if (!$this->literal(',')) break;
|
457 |
+
}
|
458 |
+
|
459 |
+
if ($s) $this->seek($s);
|
460 |
+
|
461 |
+
if ($keyName !== null) unset($this->env->currentProperty);
|
462 |
+
|
463 |
+
if (count($values) == 0) return false;
|
464 |
+
|
465 |
+
$value = LessCompiler::compressList($values, ', ');
|
466 |
+
|
467 |
+
return true;
|
468 |
+
}
|
469 |
+
|
470 |
+
protected function parenValue(&$out) {
|
471 |
+
$s = $this->seek();
|
472 |
+
|
473 |
+
// speed shortcut
|
474 |
+
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "(") {
|
475 |
+
return false;
|
476 |
+
}
|
477 |
+
|
478 |
+
$inParens = $this->inParens;
|
479 |
+
if ($this->literal("(") && ($this->inParens = true) && $this->expression($exp) && $this->literal(")")) {
|
480 |
+
$out = $exp;
|
481 |
+
$this->inParens = $inParens;
|
482 |
+
|
483 |
+
return true;
|
484 |
+
} else {
|
485 |
+
$this->inParens = $inParens;
|
486 |
+
$this->seek($s);
|
487 |
+
}
|
488 |
+
|
489 |
+
return false;
|
490 |
+
}
|
491 |
+
|
492 |
+
// a single value
|
493 |
+
protected function value(&$value) {
|
494 |
+
$s = $this->seek();
|
495 |
+
|
496 |
+
// speed shortcut
|
497 |
+
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "-") {
|
498 |
+
// negation
|
499 |
+
if ($this->literal("-", false) && (($this->variable($inner) && $inner = array(
|
500 |
+
"variable",
|
501 |
+
$inner
|
502 |
+
)) || $this->unit($inner) || $this->parenValue($inner))) {
|
503 |
+
$value = array(
|
504 |
+
"unary",
|
505 |
+
"-",
|
506 |
+
$inner
|
507 |
+
);
|
508 |
+
|
509 |
+
return true;
|
510 |
+
} else {
|
511 |
+
$this->seek($s);
|
512 |
+
}
|
513 |
+
}
|
514 |
+
|
515 |
+
if ($this->parenValue($value)) return true;
|
516 |
+
if ($this->unit($value)) return true;
|
517 |
+
if ($this->color($value)) return true;
|
518 |
+
if ($this->func($value)) return true;
|
519 |
+
if ($this->_string($value)) return true;
|
520 |
+
|
521 |
+
if ($this->keyword($word)) {
|
522 |
+
$value = array(
|
523 |
+
'keyword',
|
524 |
+
$word
|
525 |
+
);
|
526 |
+
|
527 |
+
return true;
|
528 |
+
}
|
529 |
+
|
530 |
+
// try a variable
|
531 |
+
if ($this->variable($var)) {
|
532 |
+
$value = array(
|
533 |
+
'variable',
|
534 |
+
$var
|
535 |
+
);
|
536 |
+
|
537 |
+
return true;
|
538 |
+
}
|
539 |
+
|
540 |
+
// unquote string (should this work on any type?
|
541 |
+
if ($this->literal("~") && $this->_string($str)) {
|
542 |
+
$value = array(
|
543 |
+
"escape",
|
544 |
+
$str
|
545 |
+
);
|
546 |
+
|
547 |
+
return true;
|
548 |
+
} else {
|
549 |
+
$this->seek($s);
|
550 |
+
}
|
551 |
+
|
552 |
+
// css hack: \0
|
553 |
+
if ($this->literal('\\') && $this->match('([0-9]+)', $m)) {
|
554 |
+
$value = array(
|
555 |
+
'keyword',
|
556 |
+
'\\' . $m[1]
|
557 |
+
);
|
558 |
+
|
559 |
+
return true;
|
560 |
+
} else {
|
561 |
+
$this->seek($s);
|
562 |
+
}
|
563 |
+
|
564 |
+
return false;
|
565 |
+
}
|
566 |
+
|
567 |
+
// an import statement
|
568 |
+
protected function import(&$out) {
|
569 |
+
$s = $this->seek();
|
570 |
+
if (!$this->literal('@import')) return false;
|
571 |
+
|
572 |
+
// @import "something.css" media;
|
573 |
+
// @import url("something.css") media;
|
574 |
+
// @import url(something.css) media;
|
575 |
+
|
576 |
+
if ($this->propertyValue($value)) {
|
577 |
+
$out = array(
|
578 |
+
"import",
|
579 |
+
$value
|
580 |
+
);
|
581 |
+
|
582 |
+
return true;
|
583 |
+
}
|
584 |
+
}
|
585 |
+
|
586 |
+
protected function mediaQueryList(&$out) {
|
587 |
+
if ($this->genericList($list, "mediaQuery", ",", false)) {
|
588 |
+
$out = $list[2];
|
589 |
+
|
590 |
+
return true;
|
591 |
+
}
|
592 |
+
|
593 |
+
return false;
|
594 |
+
}
|
595 |
+
|
596 |
+
protected function mediaQuery(&$out) {
|
597 |
+
$s = $this->seek();
|
598 |
+
|
599 |
+
$expressions = null;
|
600 |
+
$parts = array();
|
601 |
+
|
602 |
+
if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) {
|
603 |
+
$prop = array("mediaType");
|
604 |
+
if (isset($only)) $prop[] = "only";
|
605 |
+
if (isset($not)) $prop[] = "not";
|
606 |
+
$prop[] = $mediaType;
|
607 |
+
$parts[] = $prop;
|
608 |
+
} else {
|
609 |
+
$this->seek($s);
|
610 |
+
}
|
611 |
+
|
612 |
+
|
613 |
+
if (!empty($mediaType) && !$this->literal("and")) {
|
614 |
+
// ~
|
615 |
+
} else {
|
616 |
+
$this->genericList($expressions, "mediaExpression", "and", false);
|
617 |
+
if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]);
|
618 |
+
}
|
619 |
+
|
620 |
+
if (count($parts) == 0) {
|
621 |
+
$this->seek($s);
|
622 |
+
|
623 |
+
return false;
|
624 |
+
}
|
625 |
+
|
626 |
+
$out = $parts;
|
627 |
+
|
628 |
+
return true;
|
629 |
+
}
|
630 |
+
|
631 |
+
protected function mediaExpression(&$out) {
|
632 |
+
$s = $this->seek();
|
633 |
+
$value = null;
|
634 |
+
if ($this->literal("(") && $this->keyword($feature) && ($this->literal(":") && $this->expression($value) || true) && $this->literal(")")) {
|
635 |
+
$out = array(
|
636 |
+
"mediaExp",
|
637 |
+
$feature
|
638 |
+
);
|
639 |
+
if ($value) $out[] = $value;
|
640 |
+
|
641 |
+
return true;
|
642 |
+
} elseif ($this->variable($variable)) {
|
643 |
+
$out = array(
|
644 |
+
'variable',
|
645 |
+
$variable
|
646 |
+
);
|
647 |
+
|
648 |
+
return true;
|
649 |
+
}
|
650 |
+
|
651 |
+
$this->seek($s);
|
652 |
+
|
653 |
+
return false;
|
654 |
+
}
|
655 |
+
|
656 |
+
// an unbounded string stopped by $end
|
657 |
+
protected function openString($end, &$out, $nestingOpen = null, $rejectStrs = null) {
|
658 |
+
$oldWhite = $this->eatWhiteDefault;
|
659 |
+
$this->eatWhiteDefault = false;
|
660 |
+
|
661 |
+
$stop = array(
|
662 |
+
"'",
|
663 |
+
'"',
|
664 |
+
"@{",
|
665 |
+
$end
|
666 |
+
);
|
667 |
+
$stop = array_map(array(
|
668 |
+
LessCompiler::class,
|
669 |
+
"preg_quote"
|
670 |
+
), $stop);
|
671 |
+
// $stop[] = self::$commentMulti;
|
672 |
+
|
673 |
+
if (!is_null($rejectStrs)) {
|
674 |
+
$stop = array_merge($stop, $rejectStrs);
|
675 |
+
}
|
676 |
+
|
677 |
+
$patt = '(.*?)(' . implode("|", $stop) . ')';
|
678 |
+
|
679 |
+
$nestingLevel = 0;
|
680 |
+
|
681 |
+
$content = array();
|
682 |
+
while ($this->match($patt, $m, false)) {
|
683 |
+
if (!empty($m[1])) {
|
684 |
+
$content[] = $m[1];
|
685 |
+
if ($nestingOpen) {
|
686 |
+
$nestingLevel += substr_count($m[1], $nestingOpen);
|
687 |
+
}
|
688 |
+
}
|
689 |
+
|
690 |
+
$tok = $m[2];
|
691 |
+
|
692 |
+
$this->count -= strlen($tok);
|
693 |
+
if ($tok == $end) {
|
694 |
+
if ($nestingLevel == 0) {
|
695 |
+
break;
|
696 |
+
} else {
|
697 |
+
$nestingLevel--;
|
698 |
+
}
|
699 |
+
}
|
700 |
+
|
701 |
+
if (($tok == "'" || $tok == '"') && $this->_string($str)) {
|
702 |
+
$content[] = $str;
|
703 |
+
continue;
|
704 |
+
}
|
705 |
+
|
706 |
+
if ($tok == "@{" && $this->interpolation($inter)) {
|
707 |
+
$content[] = $inter;
|
708 |
+
continue;
|
709 |
+
}
|
710 |
+
|
711 |
+
if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {
|
712 |
+
$ount = null;
|
713 |
+
break;
|
714 |
+
}
|
715 |
+
|
716 |
+
$content[] = $tok;
|
717 |
+
$this->count += strlen($tok);
|
718 |
+
}
|
719 |
+
|
720 |
+
$this->eatWhiteDefault = $oldWhite;
|
721 |
+
|
722 |
+
if (count($content) == 0) return false;
|
723 |
+
|
724 |
+
// trim the end
|
725 |
+
if (is_string(end($content))) {
|
726 |
+
$content[count($content) - 1] = rtrim(end($content));
|
727 |
+
}
|
728 |
+
|
729 |
+
$out = array(
|
730 |
+
"string",
|
731 |
+
"",
|
732 |
+
$content
|
733 |
+
);
|
734 |
+
|
735 |
+
return true;
|
736 |
+
}
|
737 |
+
|
738 |
+
protected function _string(&$out) {
|
739 |
+
$s = $this->seek();
|
740 |
+
if ($this->literal('"', false)) {
|
741 |
+
$delim = '"';
|
742 |
+
} elseif ($this->literal("'", false)) {
|
743 |
+
$delim = "'";
|
744 |
+
} else {
|
745 |
+
return false;
|
746 |
+
}
|
747 |
+
|
748 |
+
$content = array();
|
749 |
+
|
750 |
+
// look for either ending delim , escape, or string interpolation
|
751 |
+
$patt = '([^\n]*?)(@\{|\\\\|' . LessCompiler::preg_quote($delim) . ')';
|
752 |
+
|
753 |
+
$oldWhite = $this->eatWhiteDefault;
|
754 |
+
$this->eatWhiteDefault = false;
|
755 |
+
|
756 |
+
while ($this->match($patt, $m, false)) {
|
757 |
+
$content[] = $m[1];
|
758 |
+
if ($m[2] == "@{") {
|
759 |
+
$this->count -= strlen($m[2]);
|
760 |
+
if ($this->interpolation($inter)) {
|
761 |
+
$content[] = $inter;
|
762 |
+
} else {
|
763 |
+
$this->count += strlen($m[2]);
|
764 |
+
$content[] = "@{"; // ignore it
|
765 |
+
}
|
766 |
+
} elseif ($m[2] == '\\') {
|
767 |
+
$content[] = $m[2];
|
768 |
+
if ($this->literal($delim, false)) {
|
769 |
+
$content[] = $delim;
|
770 |
+
}
|
771 |
+
} else {
|
772 |
+
$this->count -= strlen($delim);
|
773 |
+
break; // delim
|
774 |
+
}
|
775 |
+
}
|
776 |
+
|
777 |
+
$this->eatWhiteDefault = $oldWhite;
|
778 |
+
|
779 |
+
if ($this->literal($delim)) {
|
780 |
+
$out = array(
|
781 |
+
"string",
|
782 |
+
$delim,
|
783 |
+
$content
|
784 |
+
);
|
785 |
+
|
786 |
+
return true;
|
787 |
+
}
|
788 |
+
|
789 |
+
$this->seek($s);
|
790 |
+
|
791 |
+
return false;
|
792 |
+
}
|
793 |
+
|
794 |
+
protected function interpolation(&$out) {
|
795 |
+
$oldWhite = $this->eatWhiteDefault;
|
796 |
+
$this->eatWhiteDefault = true;
|
797 |
+
|
798 |
+
$s = $this->seek();
|
799 |
+
if ($this->literal("@{") && $this->openString("}", $interp, null, array(
|
800 |
+
"'",
|
801 |
+
'"',
|
802 |
+
";"
|
803 |
+
)) && $this->literal("}", false)) {
|
804 |
+
$out = array(
|
805 |
+
"interpolate",
|
806 |
+
$interp
|
807 |
+
);
|
808 |
+
$this->eatWhiteDefault = $oldWhite;
|
809 |
+
if ($this->eatWhiteDefault) $this->whitespace();
|
810 |
+
|
811 |
+
return true;
|
812 |
+
}
|
813 |
+
|
814 |
+
$this->eatWhiteDefault = $oldWhite;
|
815 |
+
$this->seek($s);
|
816 |
+
|
817 |
+
return false;
|
818 |
+
}
|
819 |
+
|
820 |
+
protected function unit(&$unit) {
|
821 |
+
// speed shortcut
|
822 |
+
if (isset($this->buffer[$this->count])) {
|
823 |
+
$char = $this->buffer[$this->count];
|
824 |
+
if (!ctype_digit($char) && $char != ".") return false;
|
825 |
+
}
|
826 |
+
|
827 |
+
if ($this->match('([0-9]+(?:\.[0-9]*)?|\.[0-9]+)([%a-zA-Z]+)?', $m)) {
|
828 |
+
$unit = array(
|
829 |
+
"number",
|
830 |
+
$m[1],
|
831 |
+
empty($m[2]) ? "" : $m[2]
|
832 |
+
);
|
833 |
+
|
834 |
+
return true;
|
835 |
+
}
|
836 |
+
|
837 |
+
return false;
|
838 |
+
}
|
839 |
+
|
840 |
+
// a # color
|
841 |
+
protected function color(&$out) {
|
842 |
+
if ($this->match('(#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3}))', $m)) {
|
843 |
+
if (strlen($m[1]) > 7) {
|
844 |
+
$out = array(
|
845 |
+
"string",
|
846 |
+
"",
|
847 |
+
array($m[1])
|
848 |
+
);
|
849 |
+
} else {
|
850 |
+
$out = array(
|
851 |
+
"raw_color",
|
852 |
+
$m[1]
|
853 |
+
);
|
854 |
+
}
|
855 |
+
|
856 |
+
return true;
|
857 |
+
}
|
858 |
+
|
859 |
+
return false;
|
860 |
+
}
|
861 |
+
|
862 |
+
// consume a list of property values delimited by ; and wrapped in ()
|
863 |
+
protected function argumentValues(&$args, $delim = ',') {
|
864 |
+
$s = $this->seek();
|
865 |
+
if (!$this->literal('(')) return false;
|
866 |
+
|
867 |
+
$values = array();
|
868 |
+
while (true) {
|
869 |
+
if ($this->expressionList($value)) $values[] = $value;
|
870 |
+
if (!$this->literal($delim)) break; else {
|
871 |
+
if ($value == null) $values[] = null;
|
872 |
+
$value = null;
|
873 |
+
}
|
874 |
+
}
|
875 |
+
|
876 |
+
if (!$this->literal(')')) {
|
877 |
+
$this->seek($s);
|
878 |
+
|
879 |
+
return false;
|
880 |
+
}
|
881 |
+
|
882 |
+
$args = $values;
|
883 |
+
|
884 |
+
return true;
|
885 |
+
}
|
886 |
+
|
887 |
+
// consume an argument definition list surrounded by ()
|
888 |
+
// each argument is a variable name with optional value
|
889 |
+
// or at the end a ... or a variable named followed by ...
|
890 |
+
protected function argumentDef(&$args, &$isVararg, $delim = ',') {
|
891 |
+
$s = $this->seek();
|
892 |
+
if (!$this->literal('(')) return false;
|
893 |
+
|
894 |
+
$values = array();
|
895 |
+
|
896 |
+
$isVararg = false;
|
897 |
+
while (true) {
|
898 |
+
if ($this->literal("...")) {
|
899 |
+
$isVararg = true;
|
900 |
+
break;
|
901 |
+
}
|
902 |
+
|
903 |
+
if ($this->variable($vname)) {
|
904 |
+
$arg = array(
|
905 |
+
"arg",
|
906 |
+
$vname
|
907 |
+
);
|
908 |
+
$ss = $this->seek();
|
909 |
+
if ($this->assign() && $this->expressionList($value)) {
|
910 |
+
$arg[] = $value;
|
911 |
+
} else {
|
912 |
+
$this->seek($ss);
|
913 |
+
if ($this->literal("...")) {
|
914 |
+
$arg[0] = "rest";
|
915 |
+
$isVararg = true;
|
916 |
+
}
|
917 |
+
}
|
918 |
+
$values[] = $arg;
|
919 |
+
if ($isVararg) break;
|
920 |
+
continue;
|
921 |
+
}
|
922 |
+
|
923 |
+
if ($this->value($literal)) {
|
924 |
+
$values[] = array(
|
925 |
+
"lit",
|
926 |
+
$literal
|
927 |
+
);
|
928 |
+
}
|
929 |
+
|
930 |
+
if (!$this->literal($delim)) break;
|
931 |
+
}
|
932 |
+
|
933 |
+
if (!$this->literal(')')) {
|
934 |
+
$this->seek($s);
|
935 |
+
|
936 |
+
return false;
|
937 |
+
}
|
938 |
+
|
939 |
+
$args = $values;
|
940 |
+
|
941 |
+
return true;
|
942 |
+
}
|
943 |
+
|
944 |
+
// consume a list of tags
|
945 |
+
// this accepts a hanging delimiter
|
946 |
+
protected function tags(&$tags, $simple = false, $delim = ',') {
|
947 |
+
$tags = array();
|
948 |
+
while ($this->tag($tt, $simple)) {
|
949 |
+
$tags[] = $tt;
|
950 |
+
if (!$this->literal($delim)) break;
|
951 |
+
}
|
952 |
+
if (count($tags) == 0) return false;
|
953 |
+
|
954 |
+
return true;
|
955 |
+
}
|
956 |
+
|
957 |
+
// list of tags of specifying mixin path
|
958 |
+
// optionally separated by > (lazy, accepts extra >)
|
959 |
+
protected function mixinTags(&$tags) {
|
960 |
+
$s = $this->seek();
|
961 |
+
$tags = array();
|
962 |
+
while ($this->tag($tt, true)) {
|
963 |
+
$tags[] = $tt;
|
964 |
+
$this->literal(">");
|
965 |
+
}
|
966 |
+
|
967 |
+
if (count($tags) == 0) return false;
|
968 |
+
|
969 |
+
return true;
|
970 |
+
}
|
971 |
+
|
972 |
+
// a bracketed value (contained within in a tag definition)
|
973 |
+
protected function tagBracket(&$value) {
|
974 |
+
// speed shortcut
|
975 |
+
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") {
|
976 |
+
return false;
|
977 |
+
}
|
978 |
+
|
979 |
+
$s = $this->seek();
|
980 |
+
if ($this->literal('[') && $this->to(']', $c, true) && $this->literal(']', false)) {
|
981 |
+
$value = '[' . $c . ']';
|
982 |
+
// whitespace?
|
983 |
+
if ($this->whitespace()) $value .= " ";
|
984 |
+
|
985 |
+
// escape parent selector, (yuck)
|
986 |
+
$value = str_replace($this->lessc->parentSelector, "$&$", $value);
|
987 |
+
|
988 |
+
return true;
|
989 |
+
}
|
990 |
+
|
991 |
+
$this->seek($s);
|
992 |
+
|
993 |
+
return false;
|
994 |
+
}
|
995 |
+
|
996 |
+
protected function tagExpression(&$value) {
|
997 |
+
$s = $this->seek();
|
998 |
+
if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
|
999 |
+
$value = array(
|
1000 |
+
'exp',
|
1001 |
+
$exp
|
1002 |
+
);
|
1003 |
+
|
1004 |
+
return true;
|
1005 |
+
}
|
1006 |
+
|
1007 |
+
$this->seek($s);
|
1008 |
+
|
1009 |
+
return false;
|
1010 |
+
}
|
1011 |
+
|
1012 |
+
// a space separated list of selectors
|
1013 |
+
protected function tag(&$tag, $simple = false) {
|
1014 |
+
if ($simple) $chars = '^@,:;{}\][>\(\) "\''; else
|
1015 |
+
$chars = '^@,;{}["\'';
|
1016 |
+
|
1017 |
+
$s = $this->seek();
|
1018 |
+
|
1019 |
+
if (!$simple && $this->tagExpression($tag)) {
|
1020 |
+
return true;
|
1021 |
+
}
|
1022 |
+
|
1023 |
+
$hasExpression = false;
|
1024 |
+
$parts = array();
|
1025 |
+
while ($this->tagBracket($first)) $parts[] = $first;
|
1026 |
+
|
1027 |
+
$oldWhite = $this->eatWhiteDefault;
|
1028 |
+
$this->eatWhiteDefault = false;
|
1029 |
+
|
1030 |
+
while (true) {
|
1031 |
+
if ($this->match('([' . $chars . '0-9][' . $chars . ']*)', $m)) {
|
1032 |
+
$parts[] = $m[1];
|
1033 |
+
if ($simple) break;
|
1034 |
+
|
1035 |
+
while ($this->tagBracket($brack)) {
|
1036 |
+
$parts[] = $brack;
|
1037 |
+
}
|
1038 |
+
continue;
|
1039 |
+
}
|
1040 |
+
|
1041 |
+
if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@") {
|
1042 |
+
if ($this->interpolation($interp)) {
|
1043 |
+
$hasExpression = true;
|
1044 |
+
$interp[2] = true; // don't unescape
|
1045 |
+
$parts[] = $interp;
|
1046 |
+
continue;
|
1047 |
+
}
|
1048 |
+
|
1049 |
+
if ($this->literal("@")) {
|
1050 |
+
$parts[] = "@";
|
1051 |
+
continue;
|
1052 |
+
}
|
1053 |
+
}
|
1054 |
+
|
1055 |
+
if ($this->unit($unit)) { // for keyframes
|
1056 |
+
$parts[] = $unit[1];
|
1057 |
+
$parts[] = $unit[2];
|
1058 |
+
continue;
|
1059 |
+
}
|
1060 |
+
|
1061 |
+
break;
|
1062 |
+
}
|
1063 |
+
|
1064 |
+
$this->eatWhiteDefault = $oldWhite;
|
1065 |
+
if (!$parts) {
|
1066 |
+
$this->seek($s);
|
1067 |
+
|
1068 |
+
return false;
|
1069 |
+
}
|
1070 |
+
|
1071 |
+
if ($hasExpression) {
|
1072 |
+
$tag = array(
|
1073 |
+
"exp",
|
1074 |
+
array(
|
1075 |
+
"string",
|
1076 |
+
"",
|
1077 |
+
$parts
|
1078 |
+
)
|
1079 |
+
);
|
1080 |
+
} else {
|
1081 |
+
$tag = trim(implode($parts));
|
1082 |
+
}
|
1083 |
+
|
1084 |
+
$this->whitespace();
|
1085 |
+
|
1086 |
+
return true;
|
1087 |
+
}
|
1088 |
+
|
1089 |
+
// a css function
|
1090 |
+
protected function func(&$func) {
|
1091 |
+
$s = $this->seek();
|
1092 |
+
|
1093 |
+
if ($this->match('(%|[\w\-_][\w\-_:\.]+|[\w_])', $m) && $this->literal('(')) {
|
1094 |
+
$fname = $m[1];
|
1095 |
+
|
1096 |
+
$sPreArgs = $this->seek();
|
1097 |
+
|
1098 |
+
$args = array();
|
1099 |
+
while (true) {
|
1100 |
+
$ss = $this->seek();
|
1101 |
+
// this ugly nonsense is for ie filter properties
|
1102 |
+
if ($this->keyword($name) && $this->literal('=') && $this->expressionList($value)) {
|
1103 |
+
$args[] = array(
|
1104 |
+
"string",
|
1105 |
+
"",
|
1106 |
+
array(
|
1107 |
+
$name,
|
1108 |
+
"=",
|
1109 |
+
$value
|
1110 |
+
)
|
1111 |
+
);
|
1112 |
+
} else {
|
1113 |
+
$this->seek($ss);
|
1114 |
+
if ($this->expressionList($value)) {
|
1115 |
+
$args[] = $value;
|
1116 |
+
}
|
1117 |
+
}
|
1118 |
+
|
1119 |
+
if (!$this->literal(',')) break;
|
1120 |
+
}
|
1121 |
+
$args = array(
|
1122 |
+
'list',
|
1123 |
+
',',
|
1124 |
+
$args
|
1125 |
+
);
|
1126 |
+
|
1127 |
+
if ($this->literal(')')) {
|
1128 |
+
$func = array(
|
1129 |
+
'function',
|
1130 |
+
$fname,
|
1131 |
+
$args
|
1132 |
+
);
|
1133 |
+
|
1134 |
+
return true;
|
1135 |
+
} elseif ($fname == 'url') {
|
1136 |
+
// couldn't parse and in url? treat as string
|
1137 |
+
$this->seek($sPreArgs);
|
1138 |
+
if ($this->openString(")", $string) && $this->literal(")")) {
|
1139 |
+
$func = array(
|
1140 |
+
'function',
|
1141 |
+
$fname,
|
1142 |
+
$string
|
1143 |
+
);
|
1144 |
+
|
1145 |
+
return true;
|
1146 |
+
}
|
1147 |
+
}
|
1148 |
+
}
|
1149 |
+
|
1150 |
+
$this->seek($s);
|
1151 |
+
|
1152 |
+
return false;
|
1153 |
+
}
|
1154 |
+
|
1155 |
+
// consume a less variable
|
1156 |
+
protected function variable(&$name) {
|
1157 |
+
$s = $this->seek();
|
1158 |
+
if ($this->literal($this->lessc->vPrefix, false) && ($this->variable($sub) || $this->keyword($name))) {
|
1159 |
+
if (!empty($sub)) {
|
1160 |
+
$name = array(
|
1161 |
+
'variable',
|
1162 |
+
$sub
|
1163 |
+
);
|
1164 |
+
} else {
|
1165 |
+
$name = $this->lessc->vPrefix . $name;
|
1166 |
+
}
|
1167 |
+
|
1168 |
+
return true;
|
1169 |
+
}
|
1170 |
+
|
1171 |
+
$name = null;
|
1172 |
+
$this->seek($s);
|
1173 |
+
|
1174 |
+
return false;
|
1175 |
+
}
|
1176 |
+
|
1177 |
+
/**
|
1178 |
+
* Consume an assignment operator
|
1179 |
+
* Can optionally take a name that will be set to the current property name
|
1180 |
+
*/
|
1181 |
+
protected function assign($name = null) {
|
1182 |
+
if ($name) $this->currentProperty = $name;
|
1183 |
+
|
1184 |
+
return $this->literal(':') || $this->literal('=');
|
1185 |
+
}
|
1186 |
+
|
1187 |
+
// consume a keyword
|
1188 |
+
protected function keyword(&$word) {
|
1189 |
+
if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) {
|
1190 |
+
$word = $m[1];
|
1191 |
+
|
1192 |
+
return true;
|
1193 |
+
}
|
1194 |
+
|
1195 |
+
return false;
|
1196 |
+
}
|
1197 |
+
|
1198 |
+
// consume an end of statement delimiter
|
1199 |
+
protected function end() {
|
1200 |
+
if ($this->literal(';')) {
|
1201 |
+
return true;
|
1202 |
+
} elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') {
|
1203 |
+
// if there is end of file or a closing block next then we don't need a ;
|
1204 |
+
return true;
|
1205 |
+
}
|
1206 |
+
|
1207 |
+
return false;
|
1208 |
+
}
|
1209 |
+
|
1210 |
+
protected function guards(&$guards) {
|
1211 |
+
$s = $this->seek();
|
1212 |
+
|
1213 |
+
if (!$this->literal("when")) {
|
1214 |
+
$this->seek($s);
|
1215 |
+
|
1216 |
+
return false;
|
1217 |
+
}
|
1218 |
+
|
1219 |
+
$guards = array();
|
1220 |
+
|
1221 |
+
while ($this->guardGroup($g)) {
|
1222 |
+
$guards[] = $g;
|
1223 |
+
if (!$this->literal(",")) break;
|
1224 |
+
}
|
1225 |
+
|
1226 |
+
if (count($guards) == 0) {
|
1227 |
+
$guards = null;
|
1228 |
+
$this->seek($s);
|
1229 |
+
|
1230 |
+
return false;
|
1231 |
+
}
|
1232 |
+
|
1233 |
+
return true;
|
1234 |
+
}
|
1235 |
+
|
1236 |
+
// a bunch of guards that are and'd together
|
1237 |
+
// TODO rename to guardGroup
|
1238 |
+
protected function guardGroup(&$guardGroup) {
|
1239 |
+
$s = $this->seek();
|
1240 |
+
$guardGroup = array();
|
1241 |
+
while ($this->guard($guard)) {
|
1242 |
+
$guardGroup[] = $guard;
|
1243 |
+
if (!$this->literal("and")) break;
|
1244 |
+
}
|
1245 |
+
|
1246 |
+
if (count($guardGroup) == 0) {
|
1247 |
+
$guardGroup = null;
|
1248 |
+
$this->seek($s);
|
1249 |
+
|
1250 |
+
return false;
|
1251 |
+
}
|
1252 |
+
|
1253 |
+
return true;
|
1254 |
+
}
|
1255 |
+
|
1256 |
+
protected function guard(&$guard) {
|
1257 |
+
$s = $this->seek();
|
1258 |
+
$negate = $this->literal("not");
|
1259 |
+
|
1260 |
+
if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
|
1261 |
+
$guard = $exp;
|
1262 |
+
if ($negate) $guard = array(
|
1263 |
+
"negate",
|
1264 |
+
$guard
|
1265 |
+
);
|
1266 |
+
|
1267 |
+
return true;
|
1268 |
+
}
|
1269 |
+
|
1270 |
+
$this->seek($s);
|
1271 |
+
|
1272 |
+
return false;
|
1273 |
+
}
|
1274 |
+
|
1275 |
+
/* raw parsing functions */
|
1276 |
+
|
1277 |
+
protected function literal($what, $eatWhitespace = null) {
|
1278 |
+
if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
|
1279 |
+
|
1280 |
+
// shortcut on single letter
|
1281 |
+
if (!isset($what[1]) && isset($this->buffer[$this->count])) {
|
1282 |
+
if ($this->buffer[$this->count] == $what) {
|
1283 |
+
if (!$eatWhitespace) {
|
1284 |
+
$this->count++;
|
1285 |
+
|
1286 |
+
return true;
|
1287 |
+
}
|
1288 |
+
// goes below...
|
1289 |
+
} else {
|
1290 |
+
return false;
|
1291 |
+
}
|
1292 |
+
}
|
1293 |
+
|
1294 |
+
if (!isset(self::$literalCache[$what])) {
|
1295 |
+
self::$literalCache[$what] = LessCompiler::preg_quote($what);
|
1296 |
+
}
|
1297 |
+
|
1298 |
+
return $this->match(self::$literalCache[$what], $m, $eatWhitespace);
|
1299 |
+
}
|
1300 |
+
|
1301 |
+
protected function genericList(&$out, $parseItem, $delim = "", $flatten = true) {
|
1302 |
+
$s = $this->seek();
|
1303 |
+
$items = array();
|
1304 |
+
while ($this->$parseItem($value)) {
|
1305 |
+
$items[] = $value;
|
1306 |
+
if ($delim) {
|
1307 |
+
if (!$this->literal($delim)) break;
|
1308 |
+
}
|
1309 |
+
}
|
1310 |
+
|
1311 |
+
if (count($items) == 0) {
|
1312 |
+
$this->seek($s);
|
1313 |
+
|
1314 |
+
return false;
|
1315 |
+
}
|
1316 |
+
|
1317 |
+
if ($flatten && count($items) == 1) {
|
1318 |
+
$out = $items[0];
|
1319 |
+
} else {
|
1320 |
+
$out = array(
|
1321 |
+
"list",
|
1322 |
+
$delim,
|
1323 |
+
$items
|
1324 |
+
);
|
1325 |
+
}
|
1326 |
+
|
1327 |
+
return true;
|
1328 |
+
}
|
1329 |
+
|
1330 |
+
|
1331 |
+
// advance counter to next occurrence of $what
|
1332 |
+
// $until - don't include $what in advance
|
1333 |
+
// $allowNewline, if string, will be used as valid char set
|
1334 |
+
protected function to($what, &$out, $until = false, $allowNewline = false) {
|
1335 |
+
if (is_string($allowNewline)) {
|
1336 |
+
$validChars = $allowNewline;
|
1337 |
+
} else {
|
1338 |
+
$validChars = $allowNewline ? "." : "[^\n]";
|
1339 |
+
}
|
1340 |
+
if (!$this->match('(' . $validChars . '*?)' . LessCompiler::preg_quote($what), $m, !$until)) return false;
|
1341 |
+
if ($until) $this->count -= strlen($what); // give back $what
|
1342 |
+
$out = $m[1];
|
1343 |
+
|
1344 |
+
return true;
|
1345 |
+
}
|
1346 |
+
|
1347 |
+
// try to match something on head of buffer
|
1348 |
+
protected function match($regex, &$out, $eatWhitespace = null) {
|
1349 |
+
if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
|
1350 |
+
|
1351 |
+
$r = '/' . $regex . ($eatWhitespace && !$this->writeComments ? '\s*' : '') . '/Ais';
|
1352 |
+
if (preg_match($r, $this->buffer, $out, null, $this->count)) {
|
1353 |
+
$this->count += strlen($out[0]);
|
1354 |
+
if ($eatWhitespace && $this->writeComments) $this->whitespace();
|
1355 |
+
|
1356 |
+
return true;
|
1357 |
+
}
|
1358 |
+
|
1359 |
+
return false;
|
1360 |
+
}
|
1361 |
+
|
1362 |
+
// match some whitespace
|
1363 |
+
protected function whitespace() {
|
1364 |
+
if ($this->writeComments) {
|
1365 |
+
$gotWhite = false;
|
1366 |
+
while (preg_match(self::$whitePattern, $this->buffer, $m, null, $this->count)) {
|
1367 |
+
if (isset($m[1]) && empty($this->commentsSeen[$this->count])) {
|
1368 |
+
$this->append(array(
|
1369 |
+
"comment",
|
1370 |
+
$m[1]
|
1371 |
+
));
|
1372 |
+
$this->commentsSeen[$this->count] = true;
|
1373 |
+
}
|
1374 |
+
$this->count += strlen($m[0]);
|
1375 |
+
$gotWhite = true;
|
1376 |
+
}
|
1377 |
+
|
1378 |
+
return $gotWhite;
|
1379 |
+
} else {
|
1380 |
+
$this->match("", $m);
|
1381 |
+
|
1382 |
+
return strlen($m[0]) > 0;
|
1383 |
+
}
|
1384 |
+
}
|
1385 |
+
|
1386 |
+
// match something without consuming it
|
1387 |
+
protected function peek($regex, &$out = null, $from = null) {
|
1388 |
+
if (is_null($from)) $from = $this->count;
|
1389 |
+
$r = '/' . $regex . '/Ais';
|
1390 |
+
$result = preg_match($r, $this->buffer, $out, null, $from);
|
1391 |
+
|
1392 |
+
return $result;
|
1393 |
+
}
|
1394 |
+
|
1395 |
+
// seek to a spot in the buffer or return where we are on no argument
|
1396 |
+
protected function seek($where = null) {
|
1397 |
+
if ($where === null) return $this->count; else $this->count = $where;
|
1398 |
+
|
1399 |
+
return true;
|
1400 |
+
}
|
1401 |
+
|
1402 |
+
/* misc functions */
|
1403 |
+
|
1404 |
+
public function throwError($msg = "parse error", $count = null) {
|
1405 |
+
$count = is_null($count) ? $this->count : $count;
|
1406 |
+
|
1407 |
+
$line = $this->line + substr_count(substr($this->buffer, 0, $count), "\n");
|
1408 |
+
|
1409 |
+
if (!empty($this->sourceName)) {
|
1410 |
+
$loc = "$this->sourceName on line $line";
|
1411 |
+
} else {
|
1412 |
+
$loc = "line: $line";
|
1413 |
+
}
|
1414 |
+
|
1415 |
+
// TODO this depends on $this->count
|
1416 |
+
if ($this->peek("(.*?)(\n|$)", $m, $count)) {
|
1417 |
+
throw new Exception("$msg: failed at `$m[1]` $loc<br />FILE: <strong>{$this->lessc->sourceParser->sourceName}</strong>");
|
1418 |
+
} else {
|
1419 |
+
throw new Exception("$msg: $loc<br />FILE: <strong>{$this->lessc->sourceParser->sourceName}</strong>");
|
1420 |
+
}
|
1421 |
+
}
|
1422 |
+
|
1423 |
+
protected function pushBlock($selectors = null, $type = null) {
|
1424 |
+
$b = new stdclass;
|
1425 |
+
$b->parent = $this->env;
|
1426 |
+
|
1427 |
+
$b->type = $type;
|
1428 |
+
$b->id = self::$nextBlockId++;
|
1429 |
+
|
1430 |
+
$b->isVararg = false; // TODO: kill me from here
|
1431 |
+
$b->tags = $selectors;
|
1432 |
+
|
1433 |
+
$b->props = array();
|
1434 |
+
$b->children = array();
|
1435 |
+
|
1436 |
+
$this->env = $b;
|
1437 |
+
|
1438 |
+
return $b;
|
1439 |
+
}
|
1440 |
+
|
1441 |
+
// push a block that doesn't multiply tags
|
1442 |
+
protected function pushSpecialBlock($type) {
|
1443 |
+
return $this->pushBlock(null, $type);
|
1444 |
+
}
|
1445 |
+
|
1446 |
+
// append a property to the current block
|
1447 |
+
protected function append($prop, $pos = null) {
|
1448 |
+
if ($pos !== null) $prop[-1] = $pos;
|
1449 |
+
$this->env->props[] = $prop;
|
1450 |
+
}
|
1451 |
+
|
1452 |
+
// pop something off the stack
|
1453 |
+
protected function pop() {
|
1454 |
+
$old = $this->env;
|
1455 |
+
$this->env = $this->env->parent;
|
1456 |
+
|
1457 |
+
return $old;
|
1458 |
+
}
|
1459 |
+
|
1460 |
+
// remove comments from $text
|
1461 |
+
// todo: make it work for all functions, not just url
|
1462 |
+
protected function removeComments($text) {
|
1463 |
+
$look = array(
|
1464 |
+
'url(',
|
1465 |
+
'//',
|
1466 |
+
'/*',
|
1467 |
+
'"',
|
1468 |
+
"'"
|
1469 |
+
);
|
1470 |
+
|
1471 |
+
$out = '';
|
1472 |
+
$min = null;
|
1473 |
+
while (true) {
|
1474 |
+
// find the next item
|
1475 |
+
foreach ($look as $token) {
|
1476 |
+
$pos = strpos($text, $token);
|
1477 |
+
if ($pos !== false) {
|
1478 |
+
if (!isset($min) || $pos < $min[1]) $min = array(
|
1479 |
+
$token,
|
1480 |
+
$pos
|
1481 |
+
);
|
1482 |
+
}
|
1483 |
+
}
|
1484 |
+
|
1485 |
+
if (is_null($min)) break;
|
1486 |
+
|
1487 |
+
$count = $min[1];
|
1488 |
+
$skip = 0;
|
1489 |
+
$newlines = 0;
|
1490 |
+
switch ($min[0]) {
|
1491 |
+
case 'url(':
|
1492 |
+
if (preg_match('/url\(.*?\)/', $text, $m, 0, $count)) $count += strlen($m[0]) - strlen($min[0]);
|
1493 |
+
break;
|
1494 |
+
case '"':
|
1495 |
+
case "'":
|
1496 |
+
if (preg_match('/' . $min[0] . '.*?' . $min[0] . '/', $text, $m, 0, $count)) $count += strlen($m[0]) - 1;
|
1497 |
+
break;
|
1498 |
+
case '//':
|
1499 |
+
$skip = strpos($text, "\n", $count);
|
1500 |
+
if ($skip === false) $skip = strlen($text) - $count; else $skip -= $count;
|
1501 |
+
break;
|
1502 |
+
case '/*':
|
1503 |
+
if (preg_match('/\/\*.*?\*\//s', $text, $m, 0, $count)) {
|
1504 |
+
$skip = strlen($m[0]);
|
1505 |
+
$newlines = substr_count($m[0], "\n");
|
1506 |
+
}
|
1507 |
+
break;
|
1508 |
+
}
|
1509 |
+
|
1510 |
+
if ($skip == 0) $count += strlen($min[0]);
|
1511 |
+
|
1512 |
+
$out .= substr($text, 0, $count) . str_repeat("\n", $newlines);
|
1513 |
+
$text = substr($text, $count + $skip);
|
1514 |
+
|
1515 |
+
$min = null;
|
1516 |
+
}
|
1517 |
+
|
1518 |
+
return $out . $text;
|
1519 |
+
}
|
1520 |
+
|
1521 |
+
|
1522 |
+
}
|
Nextend/Framework/Asset/Fonts/Google/Asset.php
ADDED
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Asset\Fonts\Google;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\AbstractAsset;
|
8 |
+
use Nextend\Framework\Asset\Js\Js;
|
9 |
+
use Nextend\SmartSlider3\Application\Frontend\ApplicationTypeFrontend;
|
10 |
+
|
11 |
+
class Asset extends AbstractAsset {
|
12 |
+
|
13 |
+
public static $hasWebFontLoader = false;
|
14 |
+
|
15 |
+
public function getLoadedFamilies() {
|
16 |
+
return array_keys($this->files);
|
17 |
+
}
|
18 |
+
|
19 |
+
function addSubset($subset = 'latin') {
|
20 |
+
if (!in_array($subset, $this->inline)) {
|
21 |
+
$this->inline[] = $subset;
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
function addFont($family, $style = '400') {
|
26 |
+
$style = (string)$style;
|
27 |
+
if (!isset($this->files[$family])) {
|
28 |
+
$this->files[$family] = array();
|
29 |
+
}
|
30 |
+
if (!in_array($style, $this->files[$family])) {
|
31 |
+
$this->files[$family][] = $style;
|
32 |
+
}
|
33 |
+
}
|
34 |
+
|
35 |
+
public function loadFonts() {
|
36 |
+
$familyQuery = array();
|
37 |
+
$names = array();
|
38 |
+
if (count($this->files)) {
|
39 |
+
foreach ($this->files AS $family => $styles) {
|
40 |
+
if (count($styles)) {
|
41 |
+
$familyQuery[] = $family . ':' . implode(',', $styles);
|
42 |
+
foreach ($styles AS $style) {
|
43 |
+
$names[] = $family . ':' . (substr($style, -6) == 'italic' ? 'i' : 'n') . $style[0];
|
44 |
+
}
|
45 |
+
}
|
46 |
+
}
|
47 |
+
}
|
48 |
+
if (empty($familyQuery)) {
|
49 |
+
return false;
|
50 |
+
}
|
51 |
+
$subsets = array_unique($this->inline);
|
52 |
+
$familyQuery[count($familyQuery) - 1] .= ':' . implode(',', $subsets);
|
53 |
+
|
54 |
+
self::$hasWebFontLoader = true;
|
55 |
+
|
56 |
+
Js::addStaticGroup(ApplicationTypeFrontend::getAssetsPath() . "/dist/nextend-webfontloader.min.js", "nextend-webfontloader");
|
57 |
+
|
58 |
+
Js::addGlobalInline("
|
59 |
+
nextend.fontsLoaded = false;
|
60 |
+
nextend.fontsLoadedActive = function () {nextend.fontsLoaded = true;};
|
61 |
+
var requiredFonts = " . json_encode($names) . ",
|
62 |
+
fontData = {
|
63 |
+
google: {
|
64 |
+
families: " . json_encode($familyQuery) . "
|
65 |
+
},
|
66 |
+
active: function(){nextend.fontsLoadedActive()},
|
67 |
+
inactive: function(){nextend.fontsLoadedActive()},
|
68 |
+
fontactive: function(f,s){fontData.resolveFont(f+':'+s);},
|
69 |
+
fontinactive: function(f,s){fontData.resolveFont(f+':'+s);},
|
70 |
+
resolveFont: function(n){
|
71 |
+
for(var i = requiredFonts.length - 1; i >= 0; i--) {
|
72 |
+
if(requiredFonts[i] === n) {
|
73 |
+
requiredFonts.splice(i, 1);
|
74 |
+
break;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
if(!requiredFonts.length) nextend.fontsLoadedActive();
|
78 |
+
}
|
79 |
+
};
|
80 |
+
if(typeof WebFontConfig !== 'undefined' && typeof WebFont === 'undefined'){
|
81 |
+
var _WebFontConfig = WebFontConfig;
|
82 |
+
for(var k in WebFontConfig){
|
83 |
+
if(k == 'active'){
|
84 |
+
fontData.active = function(){nextend.fontsLoadedActive();_WebFontConfig.active();}
|
85 |
+
}else if(k == 'inactive'){
|
86 |
+
fontData.inactive = function(){nextend.fontsLoadedActive();_WebFontConfig.inactive();}
|
87 |
+
}else if(k == 'fontactive'){
|
88 |
+
fontData.fontactive = function(f,s){fontData.resolveFont(f+':'+s);_WebFontConfig.fontactive.apply(this,arguments);}
|
89 |
+
}else if(k == 'fontinactive'){
|
90 |
+
fontData.fontinactive = function(f,s){fontData.resolveFont(f+':'+s);_WebFontConfig.fontinactive.apply(this,arguments);}
|
91 |
+
}else if(k == 'google'){
|
92 |
+
if(typeof WebFontConfig.google.families !== 'undefined'){
|
93 |
+
for(var i = 0; i < WebFontConfig.google.families.length; i++){
|
94 |
+
fontData.google.families.push(WebFontConfig.google.families[i]);
|
95 |
+
}
|
96 |
+
}
|
97 |
+
}else{
|
98 |
+
fontData[k] = WebFontConfig[k];
|
99 |
+
}
|
100 |
+
}
|
101 |
+
}
|
102 |
+
fontData.classes=true;
|
103 |
+
fontData.events=true;
|
104 |
+
|
105 |
+
if(typeof WebFont === 'undefined'){
|
106 |
+
window.WebFontConfig = fontData;
|
107 |
+
}else{
|
108 |
+
WebFont.load(fontData);
|
109 |
+
}");
|
110 |
+
|
111 |
+
Js::addFirstCode("
|
112 |
+
nextend.fontsDeferred = $.Deferred();
|
113 |
+
if(nextend.fontsLoaded){
|
114 |
+
nextend.fontsDeferred.resolve();
|
115 |
+
}else{
|
116 |
+
nextend.fontsLoadedActive = function () {
|
117 |
+
nextend.fontsLoaded = true;
|
118 |
+
nextend.fontsDeferred.resolve();
|
119 |
+
};
|
120 |
+
var intercalCounter = 0;
|
121 |
+
nextend.fontInterval = setInterval(function(){
|
122 |
+
if(intercalCounter > 3 || document.documentElement.className.indexOf('wf-active') !== -1){
|
123 |
+
nextend.fontsLoadedActive();
|
124 |
+
clearInterval(nextend.fontInterval);
|
125 |
+
}
|
126 |
+
intercalCounter++;
|
127 |
+
}, 1000);
|
128 |
+
}", true);
|
129 |
+
|
130 |
+
return true;
|
131 |
+
}
|
132 |
+
}
|
Nextend/Framework/Asset/Fonts/Google/Google.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Asset\Fonts\Google;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\AssetManager;
|
8 |
+
|
9 |
+
class Google {
|
10 |
+
|
11 |
+
public static $enabled = false;
|
12 |
+
|
13 |
+
public static function addSubset($subset = 'latin') {
|
14 |
+
AssetManager::$googleFonts->addSubset($subset);
|
15 |
+
}
|
16 |
+
|
17 |
+
public static function addFont($family, $style = '400') {
|
18 |
+
AssetManager::$googleFonts->addFont($family, $style);
|
19 |
+
}
|
20 |
+
|
21 |
+
public static function build() {
|
22 |
+
if (self::$enabled) {
|
23 |
+
AssetManager::$googleFonts->loadFonts();
|
24 |
+
}
|
25 |
+
}
|
26 |
+
}
|
Nextend/Framework/Asset/Image/Asset.php
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset\Image;
|
4 |
+
|
5 |
+
class Asset {
|
6 |
+
|
7 |
+
protected $images = array();
|
8 |
+
|
9 |
+
public function add($images) {
|
10 |
+
if (!is_array($images)) {
|
11 |
+
$images = array($images);
|
12 |
+
}
|
13 |
+
|
14 |
+
$this->images = array_unique(array_merge($this->images, $images));
|
15 |
+
}
|
16 |
+
|
17 |
+
public function get() {
|
18 |
+
return $this->images;
|
19 |
+
}
|
20 |
+
|
21 |
+
public function match($url) {
|
22 |
+
return in_array($url, $this->images);
|
23 |
+
}
|
24 |
+
|
25 |
+
public function serialize() {
|
26 |
+
return array(
|
27 |
+
'images' => $this->images
|
28 |
+
);
|
29 |
+
}
|
30 |
+
|
31 |
+
public function unSerialize($array) {
|
32 |
+
if (!empty($array['images'])) {
|
33 |
+
$this->add($array['images']);
|
34 |
+
}
|
35 |
+
}
|
36 |
+
}
|
Nextend/Framework/Asset/Js/Asset.php
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Asset\Js;
|
5 |
+
|
6 |
+
use Nextend\Framework\Asset\AbstractAsset;
|
7 |
+
use Nextend\Framework\Cache\Combine;
|
8 |
+
use Nextend\Framework\Localization\Localization;
|
9 |
+
use Nextend\Framework\Platform\Platform;
|
10 |
+
use Nextend\Framework\Plugin;
|
11 |
+
use Nextend\Framework\Settings;
|
12 |
+
use Nextend\Framework\Url\Url;
|
13 |
+
use Nextend\Framework\View\Html;
|
14 |
+
use Nextend\SmartSlider3\SmartSlider3Info;
|
15 |
+
|
16 |
+
class Asset extends AbstractAsset {
|
17 |
+
|
18 |
+
public function __construct() {
|
19 |
+
$this->cache = new Cache();
|
20 |
+
}
|
21 |
+
|
22 |
+
public function getOutput() {
|
23 |
+
|
24 |
+
$output = "";
|
25 |
+
|
26 |
+
$needProtocol = !Settings::get('protocol-relative', '1');
|
27 |
+
|
28 |
+
$globalInline = $this->getGlobalInlineScripts();
|
29 |
+
if (!empty($globalInline)) {
|
30 |
+
$output .= Html::script(self::minify_js($globalInline . "\n"));
|
31 |
+
}
|
32 |
+
|
33 |
+
$async = !!Settings::get('async', '0') && !Platform::isAdmin();
|
34 |
+
$scriptAttributes = array();
|
35 |
+
if ($async) {
|
36 |
+
$scriptAttributes['defer'] = 1;
|
37 |
+
$scriptAttributes['async'] = 1;
|
38 |
+
}
|
39 |
+
|
40 |
+
foreach ($this->urls as $url) {
|
41 |
+
$output .= Html::scriptFile($this->filterSrc($url), $scriptAttributes) . "\n";
|
42 |
+
}
|
43 |
+
|
44 |
+
if (!Platform::isAdmin() && Settings::get('combine-js', '0')) {
|
45 |
+
$jsCombined = new Combine('js', false);
|
46 |
+
foreach ($this->getFiles() as $file) {
|
47 |
+
$jsCombined->add($file);
|
48 |
+
}
|
49 |
+
$combinedFile = $jsCombined->make();
|
50 |
+
|
51 |
+
if (substr($combinedFile, 0, 2) == '//') {
|
52 |
+
$output .= Html::scriptFile($this->filterSrc($combinedFile), $scriptAttributes) . "\n";
|
53 |
+
} else {
|
54 |
+
$output .= Html::scriptFile($this->filterSrc(Url::pathToUri($combinedFile, $needProtocol)), $scriptAttributes) . "\n";
|
55 |
+
}
|
56 |
+
} else {
|
57 |
+
foreach ($this->getFiles() as $file) {
|
58 |
+
if (substr($file, 0, 2) == '//') {
|
59 |
+
$output .= Html::scriptFile($this->filterSrc($file), $scriptAttributes) . "\n";
|
60 |
+
} else {
|
61 |
+
$output .= Html::scriptFile($this->filterSrc(Url::pathToUri($file, $needProtocol) . '?ver=' . SmartSlider3Info::$revisionShort), $scriptAttributes) . "\n";
|
62 |
+
}
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
|
67 |
+
$output .= Html::script(self::minify_js(Localization::toJS() . "\n" . $this->getInlineScripts() . "\n"));
|
68 |
+
|
69 |
+
return $output;
|
70 |
+
}
|
71 |
+
|
72 |
+
private function filterSrc($src) {
|
73 |
+
return Plugin::applyFilters('n2_script_loader_src', $src);
|
74 |
+
}
|
75 |
+
|
76 |
+
public function get() {
|
77 |
+
return array(
|
78 |
+
'url' => $this->urls,
|
79 |
+
'files' => $this->getFiles(),
|
80 |
+
'inline' => $this->getInlineScripts(),
|
81 |
+
'globalInline' => $this->getGlobalInlineScripts()
|
82 |
+
);
|
83 |
+
}
|
84 |
+
|
85 |
+
public function getAjaxOutput() {
|
86 |
+
|
87 |
+
$output = $this->getInlineScripts();
|
88 |
+
|
89 |
+
return $output;
|
90 |
+
}
|
91 |
+
|
92 |
+
private function getGlobalInlineScripts() {
|
93 |
+
return implode('', $this->globalInline);
|
94 |
+
}
|
95 |
+
|
96 |
+
private function getInlineScripts() {
|
97 |
+
$scripts = '';
|
98 |
+
|
99 |
+
foreach ($this->firstCodes as $script) {
|
100 |
+
$scripts .= $script . "\n";
|
101 |
+
}
|
102 |
+
|
103 |
+
foreach ($this->inline as $script) {
|
104 |
+
$scripts .= $script . "\n";
|
105 |
+
}
|
106 |
+
|
107 |
+
return $this->serveJquery($scripts);
|
108 |
+
}
|
109 |
+
|
110 |
+
public static function serveJquery($script) {
|
111 |
+
if (empty($script)) {
|
112 |
+
return "";
|
113 |
+
}
|
114 |
+
$inline = "N2R('documentReady', function($){\n";
|
115 |
+
$inline .= $script;
|
116 |
+
$inline .= "});\n";
|
117 |
+
|
118 |
+
return $inline;
|
119 |
+
}
|
120 |
+
|
121 |
+
public static function minify_js($input) {
|
122 |
+
if (trim($input) === "") return $input;
|
123 |
+
|
124 |
+
return preg_replace(array(
|
125 |
+
// Remove comment(s)
|
126 |
+
'#\s*("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')\s*|\s*\/\*(?!\!|@cc_on)(?>[\s\S]*?\*\/)\s*|\s*(?<![\:\=])\/\/.*(?=[\n\r]|$)|^\s*|\s*$#',
|
127 |
+
// Remove white-space(s) outside the string and regex
|
128 |
+
'#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/)|\/(?!\/)[^\n\r]*?\/(?=[\s.,;]|[gimuy]|$))|\s*([!%&*\(\)\-=+\[\]\{\}|;:,.<>?\/])\s*#s',
|
129 |
+
// Remove the last semicolon
|
130 |
+
'#;+\}#',
|
131 |
+
// Minify object attribute(s) except JSON attribute(s). From `{'foo':'bar'}` to `{foo:'bar'}`
|
132 |
+
'#([\{,])([\'])(\d+|[a-z_][a-z0-9_]*)\2(?=\:)#i',
|
133 |
+
// --ibid. From `foo['bar']` to `foo.bar`
|
134 |
+
'#([a-z0-9_\)\]])\[([\'"])([a-z_][a-z0-9_]*)\2\]#i'
|
135 |
+
), array(
|
136 |
+
'$1',
|
137 |
+
'$1$2',
|
138 |
+
'}',
|
139 |
+
'$1$3',
|
140 |
+
'$1.$3'
|
141 |
+
), $input);
|
142 |
+
}
|
143 |
+
}
|
Nextend/Framework/Asset/Js/Cache.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset\Js;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\AbstractCache;
|
6 |
+
use Nextend\Framework\Cache\Manifest;
|
7 |
+
|
8 |
+
class Cache extends AbstractCache {
|
9 |
+
|
10 |
+
public $outputFileType = "js";
|
11 |
+
|
12 |
+
protected $initialContent = '(function(){var N=this;N.N2_=N.N2_||{r:[],d:[]},N.N2R=N.N2R||function(){N.N2_.r.push(arguments)},N.N2D=N.N2D||function(){N.N2_.d.push(arguments)}}).call(window);';
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @param Manifest $cache
|
16 |
+
*
|
17 |
+
* @return string
|
18 |
+
*/
|
19 |
+
public function getCachedContent($cache) {
|
20 |
+
|
21 |
+
$content = '(function(){var N=this;N.N2_=N.N2_||{r:[],d:[]},N.N2R=N.N2R||function(){N.N2_.r.push(arguments)},N.N2D=N.N2D||function(){N.N2_.d.push(arguments)}}).call(window);';
|
22 |
+
$content .= parent::getCachedContent($cache);
|
23 |
+
$content .= "N2D('" . $this->group . "');";
|
24 |
+
|
25 |
+
return $content;
|
26 |
+
}
|
27 |
+
}
|
Nextend/Framework/Asset/Js/Js.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset\Js;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\AssetManager;
|
6 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
7 |
+
use Nextend\Framework\Platform\Platform;
|
8 |
+
use Nextend\Framework\Settings;
|
9 |
+
use Nextend\SmartSlider3\Application\Frontend\ApplicationTypeFrontend;
|
10 |
+
|
11 |
+
class Js {
|
12 |
+
|
13 |
+
public static function addFile($pathToFile, $group) {
|
14 |
+
AssetManager::$js->addFile($pathToFile, $group);
|
15 |
+
}
|
16 |
+
|
17 |
+
public static function addFiles($path, $files, $group) {
|
18 |
+
AssetManager::$js->addFiles($path, $files, $group);
|
19 |
+
}
|
20 |
+
|
21 |
+
public static function addStaticGroup($file, $group) {
|
22 |
+
AssetManager::$js->addStaticGroup($file, $group);
|
23 |
+
}
|
24 |
+
|
25 |
+
public static function addCode($code, $group) {
|
26 |
+
AssetManager::$js->addCode($code, $group);
|
27 |
+
}
|
28 |
+
|
29 |
+
public static function addUrl($url) {
|
30 |
+
AssetManager::$js->addUrl($url);
|
31 |
+
}
|
32 |
+
|
33 |
+
public static function addFirstCode($code, $unshift = false) {
|
34 |
+
AssetManager::$js->addFirstCode($code, $unshift);
|
35 |
+
}
|
36 |
+
|
37 |
+
public static function addInline($code, $unshift = false) {
|
38 |
+
AssetManager::$js->addInline($code, $unshift);
|
39 |
+
}
|
40 |
+
|
41 |
+
public static function addGlobalInline($code, $unshift = false) {
|
42 |
+
AssetManager::$js->addGlobalInline($code, $unshift);
|
43 |
+
}
|
44 |
+
|
45 |
+
public static function addInlineFile($path, $unshift = false) {
|
46 |
+
static $loaded = array();
|
47 |
+
if (!isset($loaded[$path])) {
|
48 |
+
AssetManager::$js->addInline(Filesystem::readFile($path), $unshift);
|
49 |
+
$loaded[$path] = 1;
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
public static function addGlobalInlineFile($path, $unshift = false) {
|
54 |
+
static $loaded = array();
|
55 |
+
if (!isset($loaded[$path])) {
|
56 |
+
AssetManager::$js->addGlobalInline(Filesystem::readFile($path), $unshift);
|
57 |
+
$loaded[$path] = 1;
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
public static function jQuery($force = false, $overrideJQuerySetting = false) {
|
62 |
+
$loadJQuery = Settings::get('jquery');
|
63 |
+
|
64 |
+
if (!$loadJQuery) {
|
65 |
+
wp_enqueue_script('jquery');
|
66 |
+
}
|
67 |
+
// WordPress FREE only
|
68 |
+
if ($force) {
|
69 |
+
if ($overrideJQuerySetting || $loadJQuery) {
|
70 |
+
self::addStaticGroup(ApplicationTypeFrontend::getAssetsPath() . "/dist/n2-j.min.js", 'n2');
|
71 |
+
} else {
|
72 |
+
self::addStaticGroup(ApplicationTypeFrontend::getAssetsPath() . "/dist/n2.min.js", 'n2');
|
73 |
+
}
|
74 |
+
} else {
|
75 |
+
self::addStaticGroup(ApplicationTypeFrontend::getAssetsPath() . "/dist/n2.min.js", 'n2');
|
76 |
+
}
|
77 |
+
|
78 |
+
}
|
79 |
+
|
80 |
+
}
|
Nextend/Framework/Asset/Predefined.php
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Asset;
|
4 |
+
|
5 |
+
|
6 |
+
use Nextend\Framework\Asset\Builder\BuilderJs;
|
7 |
+
use Nextend\Framework\Asset\Css\Css;
|
8 |
+
use Nextend\Framework\Asset\Fonts\Google\Google;
|
9 |
+
use Nextend\Framework\Asset\Js\Js;
|
10 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
11 |
+
use Nextend\Framework\Font\FontSources;
|
12 |
+
use Nextend\Framework\Form\Form;
|
13 |
+
use Nextend\Framework\Platform\Platform;
|
14 |
+
use Nextend\Framework\Plugin;
|
15 |
+
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
|
16 |
+
use Nextend\Framework\Url\Url;
|
17 |
+
use Nextend\SmartSlider3\Application\Frontend\ApplicationTypeFrontend;
|
18 |
+
use Nextend\SmartSlider3\Settings;
|
19 |
+
|
20 |
+
class Predefined {
|
21 |
+
|
22 |
+
public static function backend($force = false) {
|
23 |
+
static $once;
|
24 |
+
if ($once != null && !$force) {
|
25 |
+
return;
|
26 |
+
}
|
27 |
+
$once = true;
|
28 |
+
$family = n2_x('Montserrat', 'Default Google font family for admin');
|
29 |
+
foreach (explode(',', n2_x('latin', 'Default Google font charset for admin')) as $subset) {
|
30 |
+
Google::addSubset($subset);
|
31 |
+
}
|
32 |
+
Google::addFont($family);
|
33 |
+
|
34 |
+
Js::addFirstCode("N2R(['AjaxHelper'],function(){N2Classes.AjaxHelper.addAjaxArray(" . json_encode(Form::tokenizeUrl()) . ");});");
|
35 |
+
|
36 |
+
Plugin::addAction('afterApplicationContent', array(
|
37 |
+
FontSources::class,
|
38 |
+
'onFontManagerLoadBackend'
|
39 |
+
));
|
40 |
+
}
|
41 |
+
|
42 |
+
public static function frontend($force = false) {
|
43 |
+
static $once;
|
44 |
+
if ($once != null && !$force) {
|
45 |
+
return;
|
46 |
+
}
|
47 |
+
$once = true;
|
48 |
+
AssetManager::getInstance();
|
49 |
+
if (Platform::isAdmin()) {
|
50 |
+
Js::addGlobalInline('window.N2GSAP=' . N2GSAP . ';');
|
51 |
+
Js::addGlobalInline('window.N2PLATFORM="' . Platform::getName() . '";');
|
52 |
+
}
|
53 |
+
|
54 |
+
|
55 |
+
Js::addGlobalInline('(function(){var N=this;N.N2_=N.N2_||{r:[],d:[]},N.N2R=N.N2R||function(){N.N2_.r.push(arguments)},N.N2D=N.N2D||function(){N.N2_.d.push(arguments)}}).call(window);');
|
56 |
+
Js::addGlobalInline('if(!window.n2jQuery){window.n2jQuery={ready:function(cb){console.error(\'n2jQuery will be deprecated!\');N2R([\'$\'],cb);}}}');
|
57 |
+
|
58 |
+
Js::addGlobalInline('window.nextend={localization: {}, ready: function(cb){console.error(\'nextend.ready will be deprecated!\');N2R(\'documentReady\', function($){cb.call(window,$)})}};');
|
59 |
+
|
60 |
+
Js::jQuery($force);
|
61 |
+
|
62 |
+
|
63 |
+
self::animation($force);
|
64 |
+
|
65 |
+
FontSources::onFontManagerLoad($force);
|
66 |
+
}
|
67 |
+
|
68 |
+
private static function animation($force = false) {
|
69 |
+
static $once;
|
70 |
+
if ($once != null && !$force) {
|
71 |
+
return;
|
72 |
+
}
|
73 |
+
$once = true;
|
74 |
+
}
|
75 |
+
|
76 |
+
public static function loadLiteBox() {
|
77 |
+
}
|
78 |
+
}
|
Nextend/Framework/Browse/Block/BrowseManager/BlockBrowseManager.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Browse\Block\BrowseManager;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Localization\Localization;
|
9 |
+
use Nextend\Framework\View\AbstractBlock;
|
10 |
+
use Nextend\SmartSlider3\Application\Admin\TraitAdminUrl;
|
11 |
+
|
12 |
+
class BlockBrowseManager extends AbstractBlock {
|
13 |
+
|
14 |
+
use TraitAdminUrl;
|
15 |
+
|
16 |
+
public function display() {
|
17 |
+
|
18 |
+
Js::addFirstCode("new N2Classes.NextendBrowse('" . $this->getAjaxUrlBrowse() . "', " . (defined('N2_IMAGE_UPLOAD_DISABLE') ? 0 : 1) . ");");
|
19 |
+
}
|
20 |
+
}
|
Nextend/Framework/Browse/BrowseManager.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Browse;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Browse\Block\BrowseManager\BlockBrowseManager;
|
8 |
+
use Nextend\Framework\Pattern\VisualManagerTrait;
|
9 |
+
|
10 |
+
class BrowseManager {
|
11 |
+
|
12 |
+
use VisualManagerTrait;
|
13 |
+
|
14 |
+
public function display() {
|
15 |
+
|
16 |
+
$fontManagerBlock = new BlockBrowseManager($this->MVCHelper);
|
17 |
+
$fontManagerBlock->display();
|
18 |
+
}
|
19 |
+
|
20 |
+
}
|
Nextend/Framework/Browse/BulletProof/BulletProof.php
ADDED
@@ -0,0 +1,385 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Browse\BulletProof;
|
4 |
+
|
5 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
6 |
+
use Nextend\Framework\Image\ImageEdit;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* BULLETPROOF,
|
10 |
+
*
|
11 |
+
* This is a one-file solution for a quick and safe way of
|
12 |
+
* uploading, watermarking, cropping and resizing images
|
13 |
+
* during and after uploads with PHP with best security.
|
14 |
+
*
|
15 |
+
* This class is heavily commented, to be as much friendly as possible.
|
16 |
+
* Please help out by posting out some bugs/flaws if you encounter any. Thanks!
|
17 |
+
*
|
18 |
+
* @category Image uploader
|
19 |
+
* @package BulletProof
|
20 |
+
* @version 1.4.0
|
21 |
+
* @author samayo
|
22 |
+
* @link https://github.com/samayo/BulletProof
|
23 |
+
* @license Luke 3:11 ( Free )
|
24 |
+
*/
|
25 |
+
class BulletProof {
|
26 |
+
|
27 |
+
/*
|
28 |
+
|--------------------------------------------------------------------------
|
29 |
+
| Image Upload Properties
|
30 |
+
\--------------------------------------------------------------------------*/
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Set a group of default image types to upload.
|
34 |
+
*
|
35 |
+
* @var array
|
36 |
+
*/
|
37 |
+
protected $imageType = array(
|
38 |
+
"jpg",
|
39 |
+
"jpeg",
|
40 |
+
"png",
|
41 |
+
"gif",
|
42 |
+
"webp",
|
43 |
+
"svg"
|
44 |
+
);
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Set a default file size to upload. Values are in bytes. Remember: 1kb ~ 1000 bytes.
|
48 |
+
*
|
49 |
+
* @var array
|
50 |
+
*/
|
51 |
+
protected $imageSize = array(
|
52 |
+
"min" => 1,
|
53 |
+
"max" => 20000000
|
54 |
+
);
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Set a default min & maximum height & width for image to upload.
|
58 |
+
*
|
59 |
+
* @var array
|
60 |
+
*/
|
61 |
+
protected $imageDimension = array(
|
62 |
+
"height" => 10000,
|
63 |
+
"width" => 10000
|
64 |
+
);
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Set a default folder to upload images, if it does not exist, it will be created.
|
68 |
+
*
|
69 |
+
* @var string
|
70 |
+
*/
|
71 |
+
protected $uploadDir = "uploads";
|
72 |
+
|
73 |
+
/**
|
74 |
+
* To get the real image/mime type. i.e gif, jpeg, png, ....
|
75 |
+
*
|
76 |
+
* @var string
|
77 |
+
*/
|
78 |
+
protected $getMimeType;
|
79 |
+
|
80 |
+
/*
|
81 |
+
|--------------------------------------------------------------------------
|
82 |
+
| Image Upload Methods
|
83 |
+
\--------------------------------------------------------------------------*/
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Stores image types to upload
|
87 |
+
*
|
88 |
+
* @param array $fileTypes - ex: ['jpg', 'doc', 'txt'].
|
89 |
+
*
|
90 |
+
* @return $this
|
91 |
+
*/
|
92 |
+
public function fileTypes(array $fileTypes) {
|
93 |
+
$this->imageType = $fileTypes;
|
94 |
+
|
95 |
+
return $this;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Minimum and Maximum allowed image size for upload (in bytes),
|
100 |
+
*
|
101 |
+
* @param array $fileSize - ex: ['min'=>500, 'max'=>1000]
|
102 |
+
*
|
103 |
+
* @return $this
|
104 |
+
*/
|
105 |
+
public function limitSize(array $fileSize) {
|
106 |
+
$this->imageSize = $fileSize;
|
107 |
+
|
108 |
+
return $this;
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Default & maximum allowed height and width image to download.
|
113 |
+
*
|
114 |
+
* @param array $dimensions
|
115 |
+
*
|
116 |
+
* @return $this
|
117 |
+
*/
|
118 |
+
public function limitDimension(array $dimensions) {
|
119 |
+
$this->imageDimension = $dimensions;
|
120 |
+
|
121 |
+
return $this;
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Get the real image's Extension/mime type
|
126 |
+
*
|
127 |
+
* @param $imageName
|
128 |
+
*
|
129 |
+
* @return mixed
|
130 |
+
* @throws Exception
|
131 |
+
*/
|
132 |
+
protected function getMimeType($imageName) {
|
133 |
+
if (!file_exists($imageName)) {
|
134 |
+
throw new Exception("Image " . $imageName . " does not exist");
|
135 |
+
}
|
136 |
+
|
137 |
+
$listOfMimeTypes = array(
|
138 |
+
1 => "gif",
|
139 |
+
"jpeg",
|
140 |
+
"png",
|
141 |
+
"swf",
|
142 |
+
"psd",
|
143 |
+
"bmp",
|
144 |
+
"tiff",
|
145 |
+
"tiff",
|
146 |
+
"jpc",
|
147 |
+
"jp2",
|
148 |
+
"jpx",
|
149 |
+
"jb2",
|
150 |
+
"swc",
|
151 |
+
"iff",
|
152 |
+
"wbmp",
|
153 |
+
"xmb",
|
154 |
+
"ico",
|
155 |
+
"webp",
|
156 |
+
"svg"
|
157 |
+
);
|
158 |
+
|
159 |
+
$imageType = ImageEdit::exif_imagetype($imageName);
|
160 |
+
if (isset($listOfMimeTypes[$imageType])) {
|
161 |
+
return $listOfMimeTypes[$imageType];
|
162 |
+
}
|
163 |
+
|
164 |
+
return false;
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Handy method for getting image dimensions (W & H) in pixels.
|
169 |
+
*
|
170 |
+
* @param $getImage - The image name
|
171 |
+
*
|
172 |
+
* @return array
|
173 |
+
*/
|
174 |
+
protected function getPixels($getImage) {
|
175 |
+
list($width, $height) = getImageSize($getImage);
|
176 |
+
|
177 |
+
return array(
|
178 |
+
"width" => $width,
|
179 |
+
"height" => $height
|
180 |
+
);
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* Rename file either from method or by generating a random one.
|
185 |
+
*
|
186 |
+
* @param $isNameProvided - A new name for the file.
|
187 |
+
*
|
188 |
+
* @return string
|
189 |
+
*/
|
190 |
+
protected function imageRename($isNameProvided) {
|
191 |
+
if ($isNameProvided) {
|
192 |
+
return $isNameProvided . "." . $this->getMimeType;
|
193 |
+
}
|
194 |
+
|
195 |
+
return uniqid(true) . "_" . str_shuffle(implode(range("E", "Q"))) . "." . $this->getMimeType;
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Get the specified upload dir, if it does not exist, create a new one.
|
200 |
+
*
|
201 |
+
* @param $directoryName - directory name where you want your files to be uploaded
|
202 |
+
*
|
203 |
+
* @return $this
|
204 |
+
* @throws Exception
|
205 |
+
*/
|
206 |
+
public function uploadDir($directoryName) {
|
207 |
+
if (!file_exists($directoryName) && !is_dir($directoryName)) {
|
208 |
+
|
209 |
+
$createFolder = Filesystem::createFolder("" . $directoryName);
|
210 |
+
if (!$createFolder) {
|
211 |
+
throw new Exception("Folder " . $directoryName . " could not be created");
|
212 |
+
}
|
213 |
+
}
|
214 |
+
$this->uploadDir = $directoryName;
|
215 |
+
|
216 |
+
return $this;
|
217 |
+
}
|
218 |
+
|
219 |
+
/**
|
220 |
+
* For getting common error messages from FILES[] array during upload.
|
221 |
+
*
|
222 |
+
* @return array
|
223 |
+
*/
|
224 |
+
protected function commonUploadErrors($key) {
|
225 |
+
$uploadErrors = array(
|
226 |
+
UPLOAD_ERR_OK => "...",
|
227 |
+
UPLOAD_ERR_INI_SIZE => "File is larger than the specified amount set by the server",
|
228 |
+
UPLOAD_ERR_FORM_SIZE => "File is larger than the specified amount specified by browser",
|
229 |
+
UPLOAD_ERR_PARTIAL => "File could not be fully uploaded. Please try again later",
|
230 |
+
UPLOAD_ERR_NO_FILE => "File is not found",
|
231 |
+
UPLOAD_ERR_NO_TMP_DIR => "Can't write to disk, due to server configuration ( No tmp dir found )",
|
232 |
+
UPLOAD_ERR_CANT_WRITE => "Failed to write file to disk. Please check you file permissions",
|
233 |
+
UPLOAD_ERR_EXTENSION => "A PHP extension has halted this file upload process"
|
234 |
+
);
|
235 |
+
|
236 |
+
return $uploadErrors[$key];
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* Simple file check and delete wrapper.
|
241 |
+
*
|
242 |
+
* @param $fileToDelete
|
243 |
+
*
|
244 |
+
* @return bool
|
245 |
+
* @throws Exception
|
246 |
+
*/
|
247 |
+
public function deleteFile($fileToDelete) {
|
248 |
+
if (file_exists($fileToDelete) && !unlink($fileToDelete)) {
|
249 |
+
throw new Exception("File may have been deleted or does not exist");
|
250 |
+
}
|
251 |
+
|
252 |
+
return true;
|
253 |
+
}
|
254 |
+
|
255 |
+
/**
|
256 |
+
* Final image uploader method, to check for errors and upload
|
257 |
+
*
|
258 |
+
* @param $fileToUpload
|
259 |
+
* @param null $isNameProvided
|
260 |
+
*
|
261 |
+
* @return string
|
262 |
+
* @throws Exception
|
263 |
+
*/
|
264 |
+
public function upload($fileToUpload, $isNameProvided = null) {
|
265 |
+
|
266 |
+
$isMedia = false;
|
267 |
+
// Check if any errors are thrown by the FILES[] array
|
268 |
+
if ($fileToUpload["error"]) {
|
269 |
+
throw new Exception($this->commonUploadErrors($fileToUpload["error"]));
|
270 |
+
}
|
271 |
+
|
272 |
+
if (function_exists("mime_content_type")) {
|
273 |
+
$rawMime = mime_content_type($fileToUpload["tmp_name"]);
|
274 |
+
} else {
|
275 |
+
$path_parts = pathinfo($_FILES["image"]["name"]);
|
276 |
+
switch ($path_parts['extension']) {
|
277 |
+
case 'mp4':
|
278 |
+
$rawMime = 'video/mp4';
|
279 |
+
break;
|
280 |
+
case 'mp3':
|
281 |
+
$rawMime = 'audio/mpeg';
|
282 |
+
break;
|
283 |
+
default:
|
284 |
+
$rawMime = '';
|
285 |
+
break;
|
286 |
+
}
|
287 |
+
}
|
288 |
+
|
289 |
+
switch ($rawMime) {
|
290 |
+
case 'video/mp4':
|
291 |
+
$this->getMimeType = 'mp4';
|
292 |
+
$isMedia = true;
|
293 |
+
break;
|
294 |
+
case 'audio/mpeg':
|
295 |
+
$this->getMimeType = 'mp3';
|
296 |
+
$isMedia = true;
|
297 |
+
break;
|
298 |
+
}
|
299 |
+
|
300 |
+
if (!$isMedia) {
|
301 |
+
// First get the real file extension
|
302 |
+
$this->getMimeType = $this->getMimeType($fileToUpload["tmp_name"]);
|
303 |
+
|
304 |
+
$specialImage = false;
|
305 |
+
if ($this->getMimeType === false) {
|
306 |
+
if (isset($fileToUpload["type"]) && strpos($fileToUpload["type"], 'image/') !== false) {
|
307 |
+
$this->getMimeType = str_replace(array(
|
308 |
+
'image/',
|
309 |
+
'svg+xml'
|
310 |
+
), array(
|
311 |
+
'',
|
312 |
+
'svg'
|
313 |
+
), $fileToUpload["type"]);
|
314 |
+
$specialImage = true;
|
315 |
+
}
|
316 |
+
}
|
317 |
+
|
318 |
+
// Check if this file type is allowed for upload
|
319 |
+
if (!in_array($this->getMimeType, $this->imageType)) {
|
320 |
+
throw new Exception(" This is not allowed file type!
|
321 |
+
Please only upload ( " . implode(", ", $this->imageType) . " ) file types");
|
322 |
+
}
|
323 |
+
|
324 |
+
//Check if size (in bytes) of the image are above or below of defined in 'limitSize()'
|
325 |
+
if ($fileToUpload["size"] < $this->imageSize["min"] || $fileToUpload["size"] > $this->imageSize["max"]) {
|
326 |
+
throw new Exception("File sizes must be between " . implode(" to ", $this->imageSize) . " bytes");
|
327 |
+
}
|
328 |
+
|
329 |
+
// check if image is valid pixel-wise.
|
330 |
+
if (!$specialImage) {
|
331 |
+
$pixel = $this->getPixels($fileToUpload["tmp_name"]);
|
332 |
+
|
333 |
+
if ($pixel["width"] < 4 || $pixel["height"] < 4) {
|
334 |
+
throw new Exception("This file is either too small or corrupted to be an image");
|
335 |
+
}
|
336 |
+
|
337 |
+
if ($pixel["height"] > $this->imageDimension["height"] || $pixel["width"] > $this->imageDimension["width"]) {
|
338 |
+
throw new Exception("Image pixels/size must be below " . implode(", ", $this->imageDimension) . " pixels");
|
339 |
+
}
|
340 |
+
}
|
341 |
+
}
|
342 |
+
|
343 |
+
// create upload directory if it does not exist
|
344 |
+
$this->uploadDir($this->uploadDir);
|
345 |
+
|
346 |
+
$i = '';
|
347 |
+
$newFileName = $this->imageRename($isNameProvided);
|
348 |
+
|
349 |
+
while (file_exists($this->uploadDir . "/" . $newFileName)) {
|
350 |
+
// The file already uploaded, nothing to do here
|
351 |
+
if (self::isFilesIdentical($this->uploadDir . "/" . $newFileName, $fileToUpload["tmp_name"])) {
|
352 |
+
return $this->uploadDir . "/" . $newFileName;
|
353 |
+
}
|
354 |
+
$i++;
|
355 |
+
$newFileName = $this->imageRename($isNameProvided . $i);
|
356 |
+
}
|
357 |
+
|
358 |
+
// Upload the file
|
359 |
+
$moveUploadedFile = $this->moveUploadedFile($fileToUpload["tmp_name"], $this->uploadDir . "/" . $newFileName);
|
360 |
+
|
361 |
+
if ($moveUploadedFile) {
|
362 |
+
return $this->uploadDir . "/" . $newFileName;
|
363 |
+
} else {
|
364 |
+
throw new Exception(" File could not be uploaded. Unknown error occurred. ");
|
365 |
+
}
|
366 |
+
}
|
367 |
+
|
368 |
+
public function moveUploadedFile($uploaded_file, $new_file) {
|
369 |
+
if (!is_uploaded_file($uploaded_file)) {
|
370 |
+
return copy($uploaded_file, $new_file);
|
371 |
+
}
|
372 |
+
|
373 |
+
return move_uploaded_file($uploaded_file, $new_file);
|
374 |
+
}
|
375 |
+
|
376 |
+
private static function isFilesIdentical($fn1, $fn2) {
|
377 |
+
if (filetype($fn1) !== filetype($fn2)) return FALSE;
|
378 |
+
|
379 |
+
if (filesize($fn1) !== filesize($fn2)) return FALSE;
|
380 |
+
|
381 |
+
if (sha1_file($fn1) != sha1_file($fn2)) return false;
|
382 |
+
|
383 |
+
return true;
|
384 |
+
}
|
385 |
+
}
|
Nextend/Framework/Browse/BulletProof/Exception.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Browse\BulletProof;
|
5 |
+
|
6 |
+
|
7 |
+
class Exception extends \Exception {
|
8 |
+
|
9 |
+
}
|
Nextend/Framework/Browse/ControllerAjaxBrowse.php
ADDED
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Browse;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
use Nextend\Framework\Browse\BulletProof\BulletProof;
|
7 |
+
use Nextend\Framework\Controller\Admin\AdminAjaxController;
|
8 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
9 |
+
use Nextend\Framework\Image\Image;
|
10 |
+
use Nextend\Framework\Notification\Notification;
|
11 |
+
use Nextend\Framework\Request\Request;
|
12 |
+
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
|
13 |
+
|
14 |
+
class ControllerAjaxBrowse extends AdminAjaxController {
|
15 |
+
|
16 |
+
public function actionIndex() {
|
17 |
+
$this->validateToken();
|
18 |
+
$root = Filesystem::convertToRealDirectorySeparator(Filesystem::getImagesFolder());
|
19 |
+
$path = Filesystem::realpath($root . '/' . ltrim(rtrim(Request::$REQUEST->getVar('path', ''), '/'), '/'));
|
20 |
+
if (strpos($path, $root) !== 0) {
|
21 |
+
$path = $root;
|
22 |
+
}
|
23 |
+
$_directories = glob($path . '/*', GLOB_ONLYDIR);
|
24 |
+
$directories = array();
|
25 |
+
for ($i = 0; $i < count($_directories); $i++) {
|
26 |
+
$directories[basename($_directories[$i])] = Filesystem::toLinux($this->relative($_directories[$i], $root));
|
27 |
+
}
|
28 |
+
|
29 |
+
$extensions = array(
|
30 |
+
'jpg',
|
31 |
+
'jpeg',
|
32 |
+
'png',
|
33 |
+
'gif',
|
34 |
+
'mp4',
|
35 |
+
'mp3',
|
36 |
+
'svg',
|
37 |
+
'webp'
|
38 |
+
);
|
39 |
+
$_files = scandir($path);
|
40 |
+
$files = array();
|
41 |
+
for ($i = 0; $i < count($_files); $i++) {
|
42 |
+
$_files[$i] = $path . DIRECTORY_SEPARATOR . $_files[$i];
|
43 |
+
$ext = strtolower(pathinfo($_files[$i], PATHINFO_EXTENSION));
|
44 |
+
if (self::check_utf8($_files[$i]) && in_array($ext, $extensions)) {
|
45 |
+
$files[basename($_files[$i])] = ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($_files[$i]));
|
46 |
+
}
|
47 |
+
}
|
48 |
+
$relativePath = Filesystem::toLinux($this->relative($path, $root));
|
49 |
+
if (!$relativePath) {
|
50 |
+
$relativePath = '';
|
51 |
+
}
|
52 |
+
$this->response->respond(array(
|
53 |
+
'fullPath' => $path,
|
54 |
+
'path' => $relativePath,
|
55 |
+
'directories' => (object)$directories,
|
56 |
+
'files' => (object)$files
|
57 |
+
));
|
58 |
+
}
|
59 |
+
|
60 |
+
private static function check_utf8($str) {
|
61 |
+
$len = strlen($str);
|
62 |
+
for ($i = 0; $i < $len; $i++) {
|
63 |
+
$c = ord($str[$i]);
|
64 |
+
if ($c > 128) {
|
65 |
+
if (($c > 247)) return false; elseif ($c > 239) $bytes = 4;
|
66 |
+
elseif ($c > 223) $bytes = 3;
|
67 |
+
elseif ($c > 191) $bytes = 2;
|
68 |
+
else return false;
|
69 |
+
if (($i + $bytes) > $len) return false;
|
70 |
+
while ($bytes > 1) {
|
71 |
+
$i++;
|
72 |
+
$b = ord($str[$i]);
|
73 |
+
if ($b < 128 || $b > 191) return false;
|
74 |
+
$bytes--;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
return true;
|
80 |
+
}
|
81 |
+
|
82 |
+
public function actionUpload() {
|
83 |
+
if (defined('N2_IMAGE_UPLOAD_DISABLE')) {
|
84 |
+
Notification::error(n2_('You are not allowed to upload!'));
|
85 |
+
$this->response->error();
|
86 |
+
}
|
87 |
+
|
88 |
+
$this->validateToken();
|
89 |
+
|
90 |
+
$root = Filesystem::getImagesFolder();
|
91 |
+
$folder = ltrim(rtrim(Request::$REQUEST->getVar('path', ''), '/'), '/');
|
92 |
+
$path = Filesystem::realpath($root . '/' . $folder);
|
93 |
+
|
94 |
+
if ($path === false || $path == '') {
|
95 |
+
$folder = preg_replace("/[^A-Za-z0-9]/", '', $folder);
|
96 |
+
if (empty($folder)) {
|
97 |
+
Notification::error(n2_('Folder is missing!'));
|
98 |
+
$this->response->error();
|
99 |
+
} else {
|
100 |
+
Filesystem::createFolder($root . '/' . $folder);
|
101 |
+
$path = Filesystem::realpath($root . '/' . $folder);
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
$relativePath = Filesystem::toLinux($this->relative($path, $root));
|
106 |
+
if (!$relativePath) {
|
107 |
+
$relativePath = '';
|
108 |
+
}
|
109 |
+
$response = array(
|
110 |
+
'path' => $relativePath
|
111 |
+
);
|
112 |
+
try {
|
113 |
+
if (isset($_FILES) && isset($_FILES['image']) && isset($_FILES['image']['name'])) {
|
114 |
+
$info = pathinfo($_FILES['image']['name']);
|
115 |
+
$fileName = preg_replace('/[^a-zA-Z0-9_-]/', '', $info['filename']);
|
116 |
+
if (strlen($fileName) == 0) {
|
117 |
+
$fileName = '';
|
118 |
+
}
|
119 |
+
|
120 |
+
$upload = new BulletProof();
|
121 |
+
$file = $upload->uploadDir($path)
|
122 |
+
->upload($_FILES['image'], $fileName);
|
123 |
+
$response['name'] = basename($file);
|
124 |
+
$response['url'] = ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($file));
|
125 |
+
|
126 |
+
Image::onImageUploaded($file);
|
127 |
+
}
|
128 |
+
} catch (Exception $e) {
|
129 |
+
Notification::error($e->getMessage());
|
130 |
+
$this->response->error();
|
131 |
+
}
|
132 |
+
|
133 |
+
|
134 |
+
$this->response->respond($response);
|
135 |
+
}
|
136 |
+
|
137 |
+
private function relative($path, $root) {
|
138 |
+
return substr(Filesystem::convertToRealDirectorySeparator($path), strlen($root));
|
139 |
+
}
|
140 |
+
}
|
Nextend/Framework/Cache/AbstractCache.php
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Cache;
|
4 |
+
|
5 |
+
|
6 |
+
use Nextend\Framework\Cache\Storage\AbstractStorage;
|
7 |
+
|
8 |
+
abstract class AbstractCache {
|
9 |
+
|
10 |
+
protected $group = '';
|
11 |
+
protected $isAccessible = false;
|
12 |
+
|
13 |
+
/** @var AbstractStorage */
|
14 |
+
public $storage;
|
15 |
+
|
16 |
+
protected $_storageEngine = 'filesystem';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @param string $engine
|
20 |
+
*
|
21 |
+
* @return AbstractStorage
|
22 |
+
*/
|
23 |
+
public static function getStorage($engine = "filesystem") {
|
24 |
+
static $storage = null;
|
25 |
+
if ($storage === null) {
|
26 |
+
$storage = array(
|
27 |
+
'filesystem' => new Storage\Filesystem(),
|
28 |
+
'database' => new Storage\Database()
|
29 |
+
);
|
30 |
+
}
|
31 |
+
|
32 |
+
return $storage[$engine];
|
33 |
+
}
|
34 |
+
|
35 |
+
public static function clearAll() {
|
36 |
+
self::getStorage('filesystem')
|
37 |
+
->clearAll();
|
38 |
+
self::getStorage('filesystem')
|
39 |
+
->clearAll('web');
|
40 |
+
}
|
41 |
+
|
42 |
+
public static function clearGroup($group) {
|
43 |
+
self::getStorage('filesystem')
|
44 |
+
->clear($group);
|
45 |
+
self::getStorage('filesystem')
|
46 |
+
->clear($group, 'web');
|
47 |
+
self::getStorage('database')
|
48 |
+
->clear($group);
|
49 |
+
self::getStorage('database')
|
50 |
+
->clear($group, 'web');
|
51 |
+
}
|
52 |
+
|
53 |
+
public function __construct($group, $isAccessible = false) {
|
54 |
+
$this->group = $group;
|
55 |
+
$this->isAccessible = $isAccessible;
|
56 |
+
$this->storage = self::getStorage($this->_storageEngine);
|
57 |
+
}
|
58 |
+
|
59 |
+
protected function clearCurrentGroup() {
|
60 |
+
$this->storage->clear($this->group, $this->getScope());
|
61 |
+
}
|
62 |
+
|
63 |
+
protected function getScope() {
|
64 |
+
if ($this->isAccessible) {
|
65 |
+
return 'web';
|
66 |
+
}
|
67 |
+
|
68 |
+
return 'notweb';
|
69 |
+
}
|
70 |
+
|
71 |
+
protected function exists($key) {
|
72 |
+
return $this->storage->exists($this->group, $key, $this->getScope());
|
73 |
+
}
|
74 |
+
|
75 |
+
protected function get($key) {
|
76 |
+
return $this->storage->get($this->group, $key, $this->getScope());
|
77 |
+
}
|
78 |
+
|
79 |
+
protected function set($key, $value) {
|
80 |
+
$this->storage->set($this->group, $key, $value, $this->getScope());
|
81 |
+
}
|
82 |
+
|
83 |
+
protected function getPath($key) {
|
84 |
+
return $this->storage->getPath($this->group, $key, $this->getScope());
|
85 |
+
}
|
86 |
+
|
87 |
+
protected function remove($key) {
|
88 |
+
return $this->storage->remove($this->group, $key, $this->getScope());
|
89 |
+
}
|
90 |
+
}
|
Nextend/Framework/Cache/CacheImage.php
ADDED
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Cache;
|
4 |
+
|
5 |
+
use DateTime;
|
6 |
+
|
7 |
+
class CacheImage extends AbstractCache {
|
8 |
+
|
9 |
+
protected $_storageEngine = 'filesystem';
|
10 |
+
|
11 |
+
protected $lazy = false;
|
12 |
+
|
13 |
+
public function __construct($group) {
|
14 |
+
parent::__construct($group, true);
|
15 |
+
}
|
16 |
+
|
17 |
+
protected function getScope() {
|
18 |
+
return 'image';
|
19 |
+
}
|
20 |
+
|
21 |
+
public function setLazy($lazy) {
|
22 |
+
$this->lazy = $lazy;
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @param $fileExtension
|
27 |
+
* @param callable $callable
|
28 |
+
* @param array $parameters
|
29 |
+
* @param bool $hash
|
30 |
+
*
|
31 |
+
* @return mixed
|
32 |
+
*/
|
33 |
+
public function makeCache($fileExtension, $callable, $parameters = array(), $hash = false) {
|
34 |
+
|
35 |
+
if (!$hash) {
|
36 |
+
$hash = $this->generateHash($fileExtension, $callable, $parameters);
|
37 |
+
}
|
38 |
+
|
39 |
+
if (strpos($parameters[1], '?') !== false) {
|
40 |
+
$fileNameParts = explode('?', $parameters[1]);
|
41 |
+
$keepFileName = pathinfo($fileNameParts[0], PATHINFO_FILENAME);
|
42 |
+
} else {
|
43 |
+
$keepFileName = pathinfo($parameters[1], PATHINFO_FILENAME);
|
44 |
+
}
|
45 |
+
|
46 |
+
$fileName = $hash . (!empty($keepFileName) ? '/' . $keepFileName : '');
|
47 |
+
$fileNameWithExtension = $fileName . '.' . $fileExtension;
|
48 |
+
|
49 |
+
$isCached = $this->exists($fileNameWithExtension);
|
50 |
+
if ($isCached) {
|
51 |
+
if (!$this->testManifestFile($fileName, $parameters[1])) {
|
52 |
+
$isCached = false;
|
53 |
+
}
|
54 |
+
}
|
55 |
+
|
56 |
+
if (!$isCached) {
|
57 |
+
if ($this->lazy) {
|
58 |
+
return $parameters[1];
|
59 |
+
}
|
60 |
+
|
61 |
+
array_unshift($parameters, $this->getPath($fileNameWithExtension));
|
62 |
+
call_user_func_array($callable, $parameters);
|
63 |
+
|
64 |
+
$this->createManifestFile($fileName, $parameters[2]);
|
65 |
+
}
|
66 |
+
|
67 |
+
return $this->getPath($fileNameWithExtension);
|
68 |
+
}
|
69 |
+
|
70 |
+
private function generateHash($fileExtension, $callable, $parameters) {
|
71 |
+
return md5(json_encode(array(
|
72 |
+
$fileExtension,
|
73 |
+
$callable,
|
74 |
+
$parameters
|
75 |
+
)));
|
76 |
+
}
|
77 |
+
|
78 |
+
protected function testManifestFile($fileName, $originalFile) {
|
79 |
+
$manifestKey = $this->getManifestKey($fileName);
|
80 |
+
if ($this->exists($manifestKey)) {
|
81 |
+
|
82 |
+
$manifestData = json_decode($this->get($manifestKey), true);
|
83 |
+
|
84 |
+
$newManifestData = $this->getManifestData($originalFile);
|
85 |
+
if ($manifestData['mtime'] == $newManifestData['mtime']) {
|
86 |
+
return true;
|
87 |
+
}
|
88 |
+
} else {
|
89 |
+
// Backward compatibility
|
90 |
+
$this->createManifestFile($fileName, $originalFile);
|
91 |
+
|
92 |
+
return true;
|
93 |
+
}
|
94 |
+
|
95 |
+
return false;
|
96 |
+
}
|
97 |
+
|
98 |
+
protected function createManifestFile($fileName, $originalFile) {
|
99 |
+
|
100 |
+
$this->set($this->getManifestKey($fileName), json_encode($this->getManifestData($originalFile)));
|
101 |
+
}
|
102 |
+
|
103 |
+
private function getManifestData($originalFile) {
|
104 |
+
$manifestData = array();
|
105 |
+
if (strpos($originalFile, '//') !== false) {
|
106 |
+
$manifestData['mtime'] = $this->getRemoteMTime($originalFile);
|
107 |
+
} else {
|
108 |
+
$manifestData['mtime'] = filemtime($originalFile);
|
109 |
+
}
|
110 |
+
|
111 |
+
return $manifestData;
|
112 |
+
}
|
113 |
+
|
114 |
+
private function getRemoteMTime($url) {
|
115 |
+
$h = get_headers($url, 1);
|
116 |
+
if (!$h || strpos($h[0], '200') !== false) {
|
117 |
+
foreach ($h as $k => $v) {
|
118 |
+
if (strtolower(trim($k)) == "last-modified") {
|
119 |
+
return (new DateTime($v))->getTimestamp();
|
120 |
+
}
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
return 0;
|
125 |
+
}
|
126 |
+
|
127 |
+
protected function getManifestKey($fileName) {
|
128 |
+
return $fileName . '.manifest';
|
129 |
+
}
|
130 |
+
}
|
Nextend/Framework/Cache/Combine.php
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Cache;
|
4 |
+
|
5 |
+
class Combine extends AbstractCache {
|
6 |
+
|
7 |
+
protected $files = array();
|
8 |
+
protected $inline = '';
|
9 |
+
protected $fileType = '';
|
10 |
+
protected $minify;
|
11 |
+
protected $options = array();
|
12 |
+
|
13 |
+
public function __construct($fileType, $minify = null, $options = array()) {
|
14 |
+
$this->fileType = $fileType;
|
15 |
+
$this->minify = $minify;
|
16 |
+
$this->options = $options;
|
17 |
+
$this->options['minify'] = $this->minify;
|
18 |
+
parent::__construct('combined', true);
|
19 |
+
}
|
20 |
+
|
21 |
+
public function add($file) {
|
22 |
+
if (!in_array($file, $this->files)) {
|
23 |
+
$this->files[] = $file;
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
public function addInline($text) {
|
28 |
+
$this->inline .= $text;
|
29 |
+
}
|
30 |
+
|
31 |
+
protected function getHash() {
|
32 |
+
$hash = '';
|
33 |
+
for ($i = 0; $i < count($this->files); $i++) {
|
34 |
+
$hash .= $this->files[$i] . filemtime($this->files[$i]);
|
35 |
+
}
|
36 |
+
if (!empty($this->inline)) {
|
37 |
+
$hash .= $this->inline;
|
38 |
+
}
|
39 |
+
|
40 |
+
return md5($hash . json_encode($this->options));
|
41 |
+
}
|
42 |
+
|
43 |
+
public function make() {
|
44 |
+
$hash = $this->getHash();
|
45 |
+
$fileName = $hash . '.' . $this->fileType;
|
46 |
+
if (!$this->exists($fileName)) {
|
47 |
+
$buffer = '';
|
48 |
+
for ($i = 0; $i < count($this->files); $i++) {
|
49 |
+
$buffer .= file_get_contents($this->files[$i]);
|
50 |
+
}
|
51 |
+
if (is_callable($this->minify)) {
|
52 |
+
$buffer = call_user_func($this->minify, $buffer);
|
53 |
+
}
|
54 |
+
$buffer .= $this->inline;
|
55 |
+
|
56 |
+
$this->set($fileName, $buffer);
|
57 |
+
}
|
58 |
+
|
59 |
+
return $this->getPath($fileName);
|
60 |
+
}
|
61 |
+
}
|
Nextend/Framework/Cache/Manifest.php
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Cache;
|
4 |
+
|
5 |
+
class Manifest extends AbstractCache {
|
6 |
+
|
7 |
+
private $isRaw = false;
|
8 |
+
|
9 |
+
private $manifestData;
|
10 |
+
|
11 |
+
public function __construct($group, $isAccessible = false, $isRaw = false) {
|
12 |
+
parent::__construct($group, $isAccessible);
|
13 |
+
$this->isRaw = $isRaw;
|
14 |
+
}
|
15 |
+
|
16 |
+
protected function decode($data) {
|
17 |
+
return $data;
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @param $fileName
|
22 |
+
* @param $hash
|
23 |
+
* @param callback $callable
|
24 |
+
*
|
25 |
+
* @return bool
|
26 |
+
*/
|
27 |
+
public function makeCache($fileName, $hash, $callable) {
|
28 |
+
if (!$this->isCached($fileName, $hash)) {
|
29 |
+
|
30 |
+
$return = call_user_func($callable, $this);
|
31 |
+
if ($return === false) {
|
32 |
+
return false;
|
33 |
+
}
|
34 |
+
|
35 |
+
return $this->createCacheFile($fileName, $hash, $return);
|
36 |
+
}
|
37 |
+
if ($this->isAccessible) {
|
38 |
+
return $this->getPath($fileName);
|
39 |
+
}
|
40 |
+
|
41 |
+
return $this->decode($this->get($fileName));
|
42 |
+
}
|
43 |
+
|
44 |
+
private function isCached($fileName, $hash) {
|
45 |
+
|
46 |
+
|
47 |
+
$manifestKey = $this->getManifestKey($fileName);
|
48 |
+
if ($this->exists($manifestKey)) {
|
49 |
+
|
50 |
+
$this->manifestData = json_decode($this->get($manifestKey), true);
|
51 |
+
|
52 |
+
if (!$this->isCacheValid($this->manifestData) || $this->manifestData['hash'] != $hash || !$this->exists($fileName)) {
|
53 |
+
$this->clean($fileName);
|
54 |
+
|
55 |
+
return false;
|
56 |
+
}
|
57 |
+
|
58 |
+
return true;
|
59 |
+
}
|
60 |
+
|
61 |
+
return false;
|
62 |
+
}
|
63 |
+
|
64 |
+
protected function createCacheFile($fileName, $hash, $content) {
|
65 |
+
|
66 |
+
$this->manifestData = array();
|
67 |
+
|
68 |
+
$this->manifestData['hash'] = $hash;
|
69 |
+
$this->addManifestData($this->manifestData);
|
70 |
+
|
71 |
+
$this->set($this->getManifestKey($fileName), json_encode($this->manifestData));
|
72 |
+
|
73 |
+
$this->set($fileName, $this->isRaw ? $content : json_encode($content));
|
74 |
+
|
75 |
+
if ($this->isAccessible) {
|
76 |
+
return $this->getPath($fileName);
|
77 |
+
}
|
78 |
+
|
79 |
+
return $content;
|
80 |
+
}
|
81 |
+
|
82 |
+
protected function isCacheValid(&$manifestData) {
|
83 |
+
return true;
|
84 |
+
}
|
85 |
+
|
86 |
+
protected function addManifestData(&$manifestData) {
|
87 |
+
|
88 |
+
}
|
89 |
+
|
90 |
+
public function clean($fileName) {
|
91 |
+
|
92 |
+
$this->remove($this->getManifestKey($fileName));
|
93 |
+
$this->remove($fileName);
|
94 |
+
}
|
95 |
+
|
96 |
+
protected function getManifestKey($fileName) {
|
97 |
+
return $fileName . '.manifest';
|
98 |
+
}
|
99 |
+
|
100 |
+
public function getData($key, $default = 0) {
|
101 |
+
return isset($this->manifestData[$key]) ? $this->manifestData[$key] : $default;
|
102 |
+
}
|
103 |
+
}
|
Nextend/Framework/Cache/Storage/AbstractStorage.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Cache\Storage;
|
5 |
+
|
6 |
+
|
7 |
+
abstract class AbstractStorage {
|
8 |
+
|
9 |
+
protected $paths = array();
|
10 |
+
|
11 |
+
public function isFilesystem() {
|
12 |
+
return false;
|
13 |
+
}
|
14 |
+
|
15 |
+
public abstract function clearAll($scope = 'notweb');
|
16 |
+
|
17 |
+
public abstract function clear($group, $scope = 'notweb');
|
18 |
+
|
19 |
+
public abstract function exists($group, $key, $scope = 'notweb');
|
20 |
+
|
21 |
+
public abstract function set($group, $key, $value, $scope = 'notweb');
|
22 |
+
|
23 |
+
public abstract function get($group, $key, $scope = 'notweb');
|
24 |
+
|
25 |
+
public abstract function remove($group, $key, $scope = 'notweb');
|
26 |
+
|
27 |
+
public abstract function getPath($group, $key, $scope = 'notweb');
|
28 |
+
}
|
Nextend/Framework/Cache/Storage/Database.php
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Cache\Storage;
|
4 |
+
|
5 |
+
use Nextend\Framework\Model\ApplicationSection;
|
6 |
+
use Nextend\Framework\Platform\Platform;
|
7 |
+
|
8 |
+
class Database extends AbstractStorage {
|
9 |
+
|
10 |
+
protected $db;
|
11 |
+
|
12 |
+
public function __construct() {
|
13 |
+
|
14 |
+
$this->paths['web'] = 'web';
|
15 |
+
$this->paths['notweb'] = 'notweb';
|
16 |
+
$this->paths['image'] = 'image';
|
17 |
+
|
18 |
+
$this->db = new ApplicationSection('cache');
|
19 |
+
}
|
20 |
+
|
21 |
+
public function clearAll($scope = 'notweb') {
|
22 |
+
|
23 |
+
}
|
24 |
+
|
25 |
+
public function clear($group, $scope = 'notweb') {
|
26 |
+
|
27 |
+
$this->db->delete($scope . '/' . $group);
|
28 |
+
}
|
29 |
+
|
30 |
+
public function exists($group, $key, $scope = 'notweb') {
|
31 |
+
|
32 |
+
if ($this->db->get($scope . '/' . $group, $key)) {
|
33 |
+
return true;
|
34 |
+
}
|
35 |
+
|
36 |
+
return false;
|
37 |
+
}
|
38 |
+
|
39 |
+
public function set($group, $key, $value, $scope = 'notweb') {
|
40 |
+
|
41 |
+
$this->db->set($scope . '/' . $group, $key, $value);
|
42 |
+
}
|
43 |
+
|
44 |
+
public function get($group, $key, $scope = 'notweb') {
|
45 |
+
return $this->db->get($scope . '/' . $group, $key);
|
46 |
+
}
|
47 |
+
|
48 |
+
public function remove($group, $key, $scope = 'notweb') {
|
49 |
+
$this->db->delete($scope . '/' . $group, $key);
|
50 |
+
}
|
51 |
+
|
52 |
+
public function getPath($group, $key, $scope = 'notweb') {
|
53 |
+
|
54 |
+
return Platform::getSiteUrl() . '?nextendcache=1&g=' . urlencode($group) . '&k=' . urlencode($key);
|
55 |
+
}
|
56 |
+
}
|
Nextend/Framework/Cache/Storage/Filesystem.php
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Cache\Storage;
|
5 |
+
|
6 |
+
|
7 |
+
class Filesystem extends AbstractStorage {
|
8 |
+
|
9 |
+
public function __construct() {
|
10 |
+
$this->paths['web'] = \Nextend\Framework\Filesystem\Filesystem::getWebCachePath();
|
11 |
+
$this->paths['notweb'] = \Nextend\Framework\Filesystem\Filesystem::getNotWebCachePath();
|
12 |
+
$this->paths['image'] = \Nextend\Framework\Filesystem\Filesystem::getImagesFolder();
|
13 |
+
}
|
14 |
+
|
15 |
+
public function isFilesystem() {
|
16 |
+
return true;
|
17 |
+
}
|
18 |
+
|
19 |
+
public function clearAll($scope = 'notweb') {
|
20 |
+
if (\Nextend\Framework\Filesystem\Filesystem::existsFolder($this->paths[$scope])) {
|
21 |
+
\Nextend\Framework\Filesystem\Filesystem::deleteFolder($this->paths[$scope]);
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
public function clear($group, $scope = 'notweb') {
|
26 |
+
|
27 |
+
if (\Nextend\Framework\Filesystem\Filesystem::existsFolder($this->paths[$scope] . '/' . $group)) {
|
28 |
+
\Nextend\Framework\Filesystem\Filesystem::deleteFolder($this->paths[$scope] . '/' . $group);
|
29 |
+
}
|
30 |
+
}
|
31 |
+
|
32 |
+
public function exists($group, $key, $scope = 'notweb') {
|
33 |
+
if (\Nextend\Framework\Filesystem\Filesystem::existsFile($this->paths[$scope] . '/' . $group . '/' . $key)) {
|
34 |
+
return true;
|
35 |
+
}
|
36 |
+
|
37 |
+
return false;
|
38 |
+
}
|
39 |
+
|
40 |
+
public function set($group, $key, $value, $scope = 'notweb') {
|
41 |
+
$path = $this->paths[$scope] . '/' . $group . '/' . $key;
|
42 |
+
$dir = dirname($path);
|
43 |
+
if (!\Nextend\Framework\Filesystem\Filesystem::existsFolder($dir)) {
|
44 |
+
\Nextend\Framework\Filesystem\Filesystem::createFolder($dir);
|
45 |
+
}
|
46 |
+
\Nextend\Framework\Filesystem\Filesystem::createFile($path, $value);
|
47 |
+
}
|
48 |
+
|
49 |
+
public function get($group, $key, $scope = 'notweb') {
|
50 |
+
return \Nextend\Framework\Filesystem\Filesystem::readFile($this->paths[$scope] . '/' . $group . '/' . $key);
|
51 |
+
}
|
52 |
+
|
53 |
+
public function remove($group, $key, $scope = 'notweb') {
|
54 |
+
if ($this->exists($group, $key, $scope)) {
|
55 |
+
@unlink($this->paths[$scope] . '/' . $group . '/' . $key);
|
56 |
+
}
|
57 |
+
}
|
58 |
+
|
59 |
+
public function getPath($group, $key, $scope = 'notweb') {
|
60 |
+
return $this->paths[$scope] . DIRECTORY_SEPARATOR . $group . DIRECTORY_SEPARATOR . $key;
|
61 |
+
}
|
62 |
+
}
|
Nextend/Framework/Cache/StoreImage.php
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Cache;
|
4 |
+
|
5 |
+
class StoreImage extends AbstractCache {
|
6 |
+
|
7 |
+
protected $_storageEngine = 'filesystem';
|
8 |
+
|
9 |
+
protected function getScope() {
|
10 |
+
return 'image';
|
11 |
+
}
|
12 |
+
|
13 |
+
public function makeCache($fileName, $content) {
|
14 |
+
if (!$this->isImage($fileName)) {
|
15 |
+
return false;
|
16 |
+
}
|
17 |
+
|
18 |
+
if (!$this->exists($fileName)) {
|
19 |
+
$this->set($fileName, $content);
|
20 |
+
}
|
21 |
+
|
22 |
+
return $this->getPath($fileName);
|
23 |
+
}
|
24 |
+
|
25 |
+
private function isImage($fileName) {
|
26 |
+
$supported_image = array(
|
27 |
+
'gif',
|
28 |
+
'jpg',
|
29 |
+
'jpeg',
|
30 |
+
'png',
|
31 |
+
'mp4',
|
32 |
+
'mp3',
|
33 |
+
'webp',
|
34 |
+
'svg'
|
35 |
+
);
|
36 |
+
|
37 |
+
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
38 |
+
if (in_array($ext, $supported_image)) {
|
39 |
+
return true;
|
40 |
+
}
|
41 |
+
|
42 |
+
return false;
|
43 |
+
}
|
44 |
+
}
|
Nextend/Framework/Cast.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework;
|
5 |
+
|
6 |
+
|
7 |
+
class Cast {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @param $number
|
11 |
+
*
|
12 |
+
* @return string the JavaScript float representation of the string
|
13 |
+
*/
|
14 |
+
public static function floatToString($number) {
|
15 |
+
|
16 |
+
return json_encode(floatval($number));
|
17 |
+
}
|
18 |
+
}
|
Nextend/Framework/Content/AbstractPlatformContent.php
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Content;
|
4 |
+
|
5 |
+
abstract class AbstractPlatformContent {
|
6 |
+
|
7 |
+
/**
|
8 |
+
* @param $keyword
|
9 |
+
*
|
10 |
+
* @return array links
|
11 |
+
* $links[] = array(
|
12 |
+
* 'title' => '',
|
13 |
+
* 'link' => '',
|
14 |
+
* 'info' => ''
|
15 |
+
* );
|
16 |
+
*/
|
17 |
+
abstract public function searchLink($keyword);
|
18 |
+
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @param $keyword
|
22 |
+
*
|
23 |
+
* @return array links
|
24 |
+
* $links[] = array(
|
25 |
+
* 'title' => '',
|
26 |
+
* 'description' => '',
|
27 |
+
* 'image' => '',
|
28 |
+
* 'link' => '',
|
29 |
+
* 'info' => ''
|
30 |
+
* );
|
31 |
+
*/
|
32 |
+
abstract public function searchContent($keyword);
|
33 |
+
}
|
Nextend/Framework/Content/Content.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Content;
|
4 |
+
|
5 |
+
use Nextend\Framework\Content\Joomla\JoomlaContent;
|
6 |
+
use Nextend\Framework\Content\WordPress\WordPressContent;
|
7 |
+
|
8 |
+
class Content {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var AbstractPlatformContent
|
12 |
+
*/
|
13 |
+
private static $platformContent;
|
14 |
+
|
15 |
+
public function __construct() {
|
16 |
+
self::$platformContent = new WordPressContent();
|
17 |
+
}
|
18 |
+
|
19 |
+
public static function searchLink($keyword) {
|
20 |
+
return self::$platformContent->searchLink($keyword);
|
21 |
+
}
|
22 |
+
|
23 |
+
public static function searchContent($keyword) {
|
24 |
+
return self::$platformContent->searchContent($keyword);
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
new Content();
|
Nextend/Framework/Content/ControllerAjaxContent.php
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Content;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Controller\Admin\AdminAjaxController;
|
8 |
+
use Nextend\Framework\Request\Request;
|
9 |
+
|
10 |
+
class ControllerAjaxContent extends AdminAjaxController {
|
11 |
+
|
12 |
+
public function actionSearchLink() {
|
13 |
+
$this->validateToken();
|
14 |
+
|
15 |
+
$keyword = Request::$REQUEST->getVar('keyword', '');
|
16 |
+
$this->response->respond(Content::searchLink($keyword));
|
17 |
+
}
|
18 |
+
|
19 |
+
public function actionSearchContent() {
|
20 |
+
$this->validateToken();
|
21 |
+
|
22 |
+
$keyword = Request::$REQUEST->getVar('keyword', '');
|
23 |
+
$this->response->respond(Content::searchContent($keyword));
|
24 |
+
}
|
25 |
+
}
|
Nextend/Framework/Content/WordPress/WordPressContent.php
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Content\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Content\AbstractPlatformContent;
|
6 |
+
use WP_Query;
|
7 |
+
use function get_post_thumbnail_id;
|
8 |
+
use function get_post_type;
|
9 |
+
use function get_post_type_object;
|
10 |
+
use function get_the_excerpt;
|
11 |
+
use function get_the_ID;
|
12 |
+
use function get_the_permalink;
|
13 |
+
use function get_the_title;
|
14 |
+
use function wp_get_attachment_url;
|
15 |
+
|
16 |
+
class WordPressContent extends AbstractPlatformContent {
|
17 |
+
|
18 |
+
public function searchLink($keyword) {
|
19 |
+
|
20 |
+
$the_query = new WP_Query('post_type=any&posts_per_page=20&post_status=publish&s=' . $keyword);
|
21 |
+
|
22 |
+
$links = array();
|
23 |
+
if ($the_query->have_posts()) {
|
24 |
+
while ($the_query->have_posts()) {
|
25 |
+
$the_query->the_post();
|
26 |
+
|
27 |
+
$link = array(
|
28 |
+
'title' => get_the_title(),
|
29 |
+
'link' => get_the_permalink(),
|
30 |
+
'info' => get_post_type_object(get_post_type())->labels->singular_name
|
31 |
+
);
|
32 |
+
|
33 |
+
$links[] = $link;
|
34 |
+
|
35 |
+
}
|
36 |
+
}
|
37 |
+
/* Restore original Post Data */
|
38 |
+
wp_reset_postdata();
|
39 |
+
|
40 |
+
return $links;
|
41 |
+
}
|
42 |
+
|
43 |
+
public function searchContent($keyword) {
|
44 |
+
|
45 |
+
$the_query = new WP_Query('post_type=any&posts_per_page=20&post_status=publish&s=' . $keyword);
|
46 |
+
|
47 |
+
$links = array();
|
48 |
+
if ($the_query->have_posts()) {
|
49 |
+
while ($the_query->have_posts()) {
|
50 |
+
$the_query->the_post();
|
51 |
+
|
52 |
+
$link = array(
|
53 |
+
'title' => get_the_title(),
|
54 |
+
'description' => get_the_excerpt(),
|
55 |
+
'image' => wp_get_attachment_url(get_post_thumbnail_id(get_the_ID())),
|
56 |
+
'link' => get_the_permalink(),
|
57 |
+
'info' => get_post_type_object(get_post_type())->labels->singular_name
|
58 |
+
);
|
59 |
+
|
60 |
+
$links[] = $link;
|
61 |
+
|
62 |
+
}
|
63 |
+
}
|
64 |
+
/* Restore original Post Data */
|
65 |
+
wp_reset_postdata();
|
66 |
+
|
67 |
+
return $links;
|
68 |
+
}
|
69 |
+
}
|
Nextend/Framework/Controller/AbstractController.php
ADDED
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Controller;
|
5 |
+
|
6 |
+
|
7 |
+
use Exception;
|
8 |
+
use Nextend\Framework\Acl\Acl;
|
9 |
+
use Nextend\Framework\Application\AbstractApplication;
|
10 |
+
use Nextend\Framework\Application\AbstractApplicationType;
|
11 |
+
use Nextend\Framework\Asset\AssetManager;
|
12 |
+
use Nextend\Framework\Asset\Predefined;
|
13 |
+
use Nextend\Framework\Form\Form;
|
14 |
+
use Nextend\Framework\Notification\Notification;
|
15 |
+
use Nextend\Framework\Pattern\GetPathTrait;
|
16 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
17 |
+
use Nextend\Framework\Plugin;
|
18 |
+
use Nextend\Framework\Request\Request;
|
19 |
+
use Nextend\SmartSlider3\Application\ApplicationSmartSlider3;
|
20 |
+
|
21 |
+
abstract class AbstractController {
|
22 |
+
|
23 |
+
use GetPathTrait;
|
24 |
+
use MVCHelperTrait;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @var AbstractApplicationType
|
28 |
+
*/
|
29 |
+
protected $applicationType;
|
30 |
+
|
31 |
+
/** @var callback[] */
|
32 |
+
protected $externalActions = array();
|
33 |
+
|
34 |
+
/**
|
35 |
+
* AbstractController constructor.
|
36 |
+
*
|
37 |
+
* @param AbstractApplicationType $applicationType
|
38 |
+
*/
|
39 |
+
public function __construct($applicationType) {
|
40 |
+
|
41 |
+
//PluggableController\Nextend\SmartSlider3\Application\Admin\Slider\ControllerSlider
|
42 |
+
Plugin::doAction('PluggableController\\' . get_class($this), array($this));
|
43 |
+
|
44 |
+
|
45 |
+
$this->applicationType = $applicationType;
|
46 |
+
$this->setMVCHelper($this->applicationType);
|
47 |
+
|
48 |
+
AssetManager::getInstance();
|
49 |
+
|
50 |
+
$this->initialize();
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @param $actionName
|
55 |
+
* @param callback $callable
|
56 |
+
*/
|
57 |
+
public function addExternalAction($actionName, $callable) {
|
58 |
+
|
59 |
+
$this->externalActions[$actionName] = $callable;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @return AbstractApplication
|
64 |
+
*/
|
65 |
+
public function getApplication() {
|
66 |
+
return $this->applicationType->getApplication();
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @return AbstractApplicationType
|
71 |
+
*/
|
72 |
+
public function getApplicationType() {
|
73 |
+
return $this->applicationType;
|
74 |
+
}
|
75 |
+
|
76 |
+
public function getRouter() {
|
77 |
+
return $this->applicationType->getRouter();
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @param $actionName
|
82 |
+
* @param array $args
|
83 |
+
*
|
84 |
+
* @throws Exception
|
85 |
+
*/
|
86 |
+
final public function doAction($actionName, $args = array()) {
|
87 |
+
|
88 |
+
$originalActionName = $actionName;
|
89 |
+
|
90 |
+
if (method_exists($this, 'action' . $actionName)) {
|
91 |
+
|
92 |
+
call_user_func_array(array(
|
93 |
+
$this,
|
94 |
+
'action' . $actionName
|
95 |
+
), $args);
|
96 |
+
|
97 |
+
} else if (isset($this->externalActions[$actionName]) && is_callable($this->externalActions[$actionName])) {
|
98 |
+
|
99 |
+
call_user_func_array($this->externalActions[$actionName], $args);
|
100 |
+
|
101 |
+
} else {
|
102 |
+
|
103 |
+
$actionName = $this->missingAction($this, $actionName);
|
104 |
+
|
105 |
+
if (method_exists($this, 'action' . $actionName)) {
|
106 |
+
|
107 |
+
call_user_func_array(array(
|
108 |
+
$this,
|
109 |
+
'action' . $actionName
|
110 |
+
), $args);
|
111 |
+
|
112 |
+
} else {
|
113 |
+
throw new Exception(sprintf('Missing action (%s) for controller (%s)', $originalActionName, static::class));
|
114 |
+
}
|
115 |
+
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
protected function missingAction($controllerName, $actionName) {
|
120 |
+
|
121 |
+
return 'index';
|
122 |
+
}
|
123 |
+
|
124 |
+
public function initialize() {
|
125 |
+
Predefined::frontend();
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Check ACL permissions
|
130 |
+
*
|
131 |
+
* @param $action
|
132 |
+
*
|
133 |
+
* @return bool
|
134 |
+
*/
|
135 |
+
public function canDo($action) {
|
136 |
+
return Acl::canDo($action, $this);
|
137 |
+
}
|
138 |
+
|
139 |
+
public function redirect($url, $statusCode = 302, $terminate = true) {
|
140 |
+
Request::redirect($url, $statusCode, $terminate);
|
141 |
+
}
|
142 |
+
|
143 |
+
public function validatePermission($permission) {
|
144 |
+
|
145 |
+
if (!$this->canDo($permission)) {
|
146 |
+
Notification::error(n2_('You are not authorised to view this resource.'));
|
147 |
+
|
148 |
+
ApplicationSmartSlider3::getInstance()
|
149 |
+
->getApplicationTypeAdmin()
|
150 |
+
->process('sliders', 'index');
|
151 |
+
|
152 |
+
return false;
|
153 |
+
}
|
154 |
+
|
155 |
+
return true;
|
156 |
+
}
|
157 |
+
|
158 |
+
public function validateVariable($condition, $property) {
|
159 |
+
|
160 |
+
if (!$condition) {
|
161 |
+
Notification::error(sprintf(n2_('Missing parameter: %s'), $property));
|
162 |
+
|
163 |
+
ApplicationSmartSlider3::getInstance()
|
164 |
+
->getApplicationTypeAdmin()
|
165 |
+
->process('sliders', 'index');
|
166 |
+
|
167 |
+
return false;
|
168 |
+
}
|
169 |
+
|
170 |
+
return true;
|
171 |
+
}
|
172 |
+
|
173 |
+
public function validateDatabase($condition, $showError = true) {
|
174 |
+
if (!$condition) {
|
175 |
+
if ($showError) {
|
176 |
+
Notification::error(n2_('Database error'));
|
177 |
+
|
178 |
+
ApplicationSmartSlider3::getInstance()
|
179 |
+
->getApplicationTypeAdmin()
|
180 |
+
->process('sliders', 'index');
|
181 |
+
}
|
182 |
+
|
183 |
+
return false;
|
184 |
+
}
|
185 |
+
|
186 |
+
return true;
|
187 |
+
}
|
188 |
+
|
189 |
+
public function validateToken() {
|
190 |
+
if (!Form::checkToken()) {
|
191 |
+
Notification::error(n2_('Security token mismatch'));
|
192 |
+
|
193 |
+
return false;
|
194 |
+
}
|
195 |
+
|
196 |
+
return true;
|
197 |
+
}
|
198 |
+
}
|
Nextend/Framework/Controller/Admin/AbstractAdminController.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Controller\Admin;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Css\Css;
|
8 |
+
use Nextend\Framework\Asset\Predefined;
|
9 |
+
use Nextend\Framework\Controller\AbstractController;
|
10 |
+
use Nextend\Framework\Settings;
|
11 |
+
|
12 |
+
abstract class AbstractAdminController extends AbstractController {
|
13 |
+
|
14 |
+
public function initialize() {
|
15 |
+
// Prevent browser from cache on backward button.
|
16 |
+
header("Cache-Control: no-store");
|
17 |
+
|
18 |
+
parent::initialize();
|
19 |
+
|
20 |
+
Predefined::frontend();
|
21 |
+
Predefined::backend();
|
22 |
+
}
|
23 |
+
}
|
Nextend/Framework/Controller/Admin/AdminAjaxController.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Controller\Admin;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Controller\AjaxController;
|
8 |
+
|
9 |
+
class AdminAjaxController extends AjaxController {
|
10 |
+
|
11 |
+
}
|
Nextend/Framework/Controller/Admin/AdminVisualManagerAjaxController.php
ADDED
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Controller\Admin;
|
5 |
+
|
6 |
+
use Nextend\Framework\Notification\Notification;
|
7 |
+
use Nextend\Framework\Request\Request;
|
8 |
+
use Nextend\Framework\Visual\ModelVisual;
|
9 |
+
|
10 |
+
abstract class AdminVisualManagerAjaxController extends AdminAjaxController {
|
11 |
+
|
12 |
+
protected $type = '';
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @return ModelVisual
|
16 |
+
*/
|
17 |
+
public abstract function getModel();
|
18 |
+
|
19 |
+
public function actionCreateSet() {
|
20 |
+
$this->validateToken();
|
21 |
+
|
22 |
+
$this->validatePermission('smartslider_edit');
|
23 |
+
|
24 |
+
$name = Request::$REQUEST->getVar('name');
|
25 |
+
$this->validateVariable(!empty($name), 'set name');
|
26 |
+
|
27 |
+
$model = $this->getModel();
|
28 |
+
if (($set = $model->createSet($name))) {
|
29 |
+
$this->response->respond(array(
|
30 |
+
'set' => $set
|
31 |
+
));
|
32 |
+
}
|
33 |
+
|
34 |
+
Notification::error(n2_('Unexpected error'));
|
35 |
+
$this->response->error();
|
36 |
+
}
|
37 |
+
|
38 |
+
public function actionRenameSet() {
|
39 |
+
$this->validateToken();
|
40 |
+
|
41 |
+
$this->validatePermission('smartslider_edit');
|
42 |
+
|
43 |
+
$setId = Request::$REQUEST->getInt('setId');
|
44 |
+
$this->validateVariable($setId > 0, 'set');
|
45 |
+
|
46 |
+
$name = Request::$REQUEST->getVar('name');
|
47 |
+
$this->validateVariable(!empty($name), 'set name');
|
48 |
+
|
49 |
+
$model = $this->getModel();
|
50 |
+
|
51 |
+
if (($set = $model->renameSet($setId, $name))) {
|
52 |
+
$this->response->respond(array(
|
53 |
+
'set' => $set
|
54 |
+
));
|
55 |
+
}
|
56 |
+
|
57 |
+
Notification::error(n2_('Set is not editable'));
|
58 |
+
$this->response->error();
|
59 |
+
}
|
60 |
+
|
61 |
+
public function actionDeleteSet() {
|
62 |
+
$this->validateToken();
|
63 |
+
|
64 |
+
$this->validatePermission('smartslider_delete');
|
65 |
+
|
66 |
+
$setId = Request::$REQUEST->getInt('setId');
|
67 |
+
$this->validateVariable($setId > 0, 'set');
|
68 |
+
|
69 |
+
$model = $this->getModel();
|
70 |
+
|
71 |
+
if (($set = $model->deleteSet($setId))) {
|
72 |
+
$this->response->respond(array(
|
73 |
+
'set' => $set
|
74 |
+
));
|
75 |
+
}
|
76 |
+
|
77 |
+
Notification::error(n2_('Set is not editable'));
|
78 |
+
$this->response->error();
|
79 |
+
}
|
80 |
+
|
81 |
+
public function actionLoadVisualsForSet() {
|
82 |
+
$this->validateToken();
|
83 |
+
|
84 |
+
|
85 |
+
$setId = Request::$REQUEST->getInt('setId');
|
86 |
+
$this->validateVariable($setId > 0, 'set');
|
87 |
+
|
88 |
+
$model = $this->getModel();
|
89 |
+
$visuals = $model->getVisuals($setId);
|
90 |
+
if (is_array($visuals)) {
|
91 |
+
$this->response->respond(array(
|
92 |
+
'visuals' => $visuals
|
93 |
+
));
|
94 |
+
}
|
95 |
+
|
96 |
+
Notification::error(n2_('Unexpected error'));
|
97 |
+
$this->response->error();
|
98 |
+
}
|
99 |
+
|
100 |
+
public function actionLoadSetByVisualId() {
|
101 |
+
$this->validateToken();
|
102 |
+
|
103 |
+
$visualId = Request::$REQUEST->getInt('visualId');
|
104 |
+
$this->validateVariable($visualId > 0, 'visual');
|
105 |
+
|
106 |
+
$model = $this->getModel();
|
107 |
+
|
108 |
+
$set = $model->getSetByVisualId($visualId);
|
109 |
+
|
110 |
+
if (is_array($set) && is_array($set['visuals'])) {
|
111 |
+
$this->response->respond(array(
|
112 |
+
'set' => $set
|
113 |
+
));
|
114 |
+
}
|
115 |
+
|
116 |
+
Notification::error(n2_('Visual do not exists'));
|
117 |
+
$this->response->error();
|
118 |
+
}
|
119 |
+
|
120 |
+
public function actionAddVisual() {
|
121 |
+
$this->validateToken();
|
122 |
+
|
123 |
+
$this->validatePermission('smartslider_edit');
|
124 |
+
|
125 |
+
$setId = Request::$REQUEST->getInt('setId');
|
126 |
+
$this->validateVariable($setId > 0, 'set');
|
127 |
+
|
128 |
+
$model = $this->getModel();
|
129 |
+
|
130 |
+
if (($visual = $model->addVisual($setId, Request::$REQUEST->getVar('value')))) {
|
131 |
+
$this->response->respond(array(
|
132 |
+
'visual' => $visual
|
133 |
+
));
|
134 |
+
}
|
135 |
+
|
136 |
+
Notification::error(n2_('Not editable'));
|
137 |
+
$this->response->error();
|
138 |
+
}
|
139 |
+
|
140 |
+
public function actionDeleteVisual() {
|
141 |
+
$this->validateToken();
|
142 |
+
|
143 |
+
$this->validatePermission('smartslider_delete');
|
144 |
+
|
145 |
+
$visualId = Request::$REQUEST->getInt('visualId');
|
146 |
+
$this->validateVariable($visualId > 0, 'visual');
|
147 |
+
|
148 |
+
$model = $this->getModel();
|
149 |
+
|
150 |
+
if (($visual = $model->deleteVisual($visualId))) {
|
151 |
+
$this->response->respond(array(
|
152 |
+
'visual' => $visual
|
153 |
+
));
|
154 |
+
}
|
155 |
+
|
156 |
+
Notification::error(n2_('Not editable'));
|
157 |
+
$this->response->error();
|
158 |
+
}
|
159 |
+
|
160 |
+
public function actionChangeVisual() {
|
161 |
+
$this->validateToken();
|
162 |
+
|
163 |
+
$this->validatePermission('smartslider_edit');
|
164 |
+
|
165 |
+
$visualId = Request::$REQUEST->getInt('visualId');
|
166 |
+
$this->validateVariable($visualId > 0, 'visual');
|
167 |
+
|
168 |
+
$model = $this->getModel();
|
169 |
+
|
170 |
+
if (($visual = $model->changeVisual($visualId, Request::$REQUEST->getVar('value')))) {
|
171 |
+
$this->response->respond(array(
|
172 |
+
'visual' => $visual
|
173 |
+
));
|
174 |
+
}
|
175 |
+
|
176 |
+
Notification::error(n2_('Unexpected error'));
|
177 |
+
$this->response->error();
|
178 |
+
}
|
179 |
+
|
180 |
+
}
|
Nextend/Framework/Controller/AjaxController.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Controller;
|
4 |
+
|
5 |
+
use Nextend\Framework\Form\Form;
|
6 |
+
use Nextend\Framework\Notification\Notification;
|
7 |
+
use Nextend\Framework\PageFlow;
|
8 |
+
use Nextend\Framework\Response\ResponseAjax;
|
9 |
+
|
10 |
+
class AjaxController extends AbstractController {
|
11 |
+
|
12 |
+
/** @var ResponseAjax */
|
13 |
+
protected $response;
|
14 |
+
|
15 |
+
public function __construct($applicationType) {
|
16 |
+
PageFlow::cleanOutputBuffers();
|
17 |
+
|
18 |
+
$this->response = new ResponseAjax($applicationType);
|
19 |
+
parent::__construct($applicationType);
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @return ResponseAjax
|
24 |
+
*/
|
25 |
+
public function getResponse() {
|
26 |
+
return $this->response;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function validateToken() {
|
30 |
+
|
31 |
+
if (!Form::checkToken()) {
|
32 |
+
Notification::error(n2_('Security token mismatch. Please refresh the page!'));
|
33 |
+
$this->response->error();
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
public function validatePermission($permission) {
|
38 |
+
|
39 |
+
if (!$this->canDo($permission)) {
|
40 |
+
|
41 |
+
Notification::error(n2_('You are not authorised to view this resource.'));
|
42 |
+
|
43 |
+
$this->response->error();
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
public function validateVariable($condition, $property) {
|
48 |
+
|
49 |
+
if (!$condition) {
|
50 |
+
Notification::error(sprintf(n2_('Missing parameter: %s'), $property));
|
51 |
+
$this->response->error();
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
public function validateDatabase($condition, $showError = true) {
|
56 |
+
if (!$condition) {
|
57 |
+
Notification::error(n2_('Database error'));
|
58 |
+
$this->response->error();
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
public function redirect($url, $statusCode = 302, $terminate = true) {
|
63 |
+
$this->response->redirect($url);
|
64 |
+
}
|
65 |
+
|
66 |
+
}
|
Nextend/Framework/Data/Data.php
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Data;
|
4 |
+
|
5 |
+
|
6 |
+
class Data {
|
7 |
+
|
8 |
+
/**
|
9 |
+
* @var array
|
10 |
+
*/
|
11 |
+
public $_data = array();
|
12 |
+
|
13 |
+
public function __construct($data = null, $json = false) {
|
14 |
+
|
15 |
+
if ($data) {
|
16 |
+
if (is_array($data)) {
|
17 |
+
$this->loadArray($data);
|
18 |
+
} else {
|
19 |
+
$this->loadJSON($data);
|
20 |
+
}
|
21 |
+
}
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @param $json
|
26 |
+
*/
|
27 |
+
public function loadJSON($json) {
|
28 |
+
$array = json_decode($json, true);
|
29 |
+
if (is_array($array)) $this->_data = array_merge($this->_data, $array);
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @param $array
|
34 |
+
*/
|
35 |
+
public function loadArray($array) {
|
36 |
+
if (!$this->_data) $this->_data = array();
|
37 |
+
if (is_array($array)) $this->_data = array_merge($this->_data, $array);
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* @return mixed|string
|
42 |
+
*/
|
43 |
+
public function toJSON() {
|
44 |
+
return json_encode($this->_data);
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* @return array
|
49 |
+
*/
|
50 |
+
public function toArray() {
|
51 |
+
return (array)$this->_data;
|
52 |
+
}
|
53 |
+
|
54 |
+
public function has($key) {
|
55 |
+
|
56 |
+
return isset($this->_data[$key]);
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @param string $key
|
61 |
+
* @param string $default
|
62 |
+
*
|
63 |
+
* @return mixed
|
64 |
+
*/
|
65 |
+
public function get($key, $default = '') {
|
66 |
+
if (isset($this->_data[$key])) return $this->_data[$key];
|
67 |
+
|
68 |
+
return $default;
|
69 |
+
}
|
70 |
+
|
71 |
+
public function getIfEmpty($key, $default = '') {
|
72 |
+
if (isset($this->_data[$key]) && !empty($this->_data[$key])) return $this->_data[$key];
|
73 |
+
|
74 |
+
return $default;
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* @param string $key
|
79 |
+
* @param mixed $value
|
80 |
+
*/
|
81 |
+
public function set($key, $value) {
|
82 |
+
$this->_data[$key] = $value;
|
83 |
+
}
|
84 |
+
|
85 |
+
public function un_set($key) {
|
86 |
+
if (isset($this->_data[$key])) {
|
87 |
+
unset($this->_data[$key]);
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
public function fillDefault($defaults) {
|
92 |
+
$this->_data = array_merge($defaults, $this->_data);
|
93 |
+
}
|
94 |
+
}
|
Nextend/Framework/Database/AbstractPlatformConnector.php
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Database;
|
4 |
+
|
5 |
+
abstract class AbstractPlatformConnector {
|
6 |
+
|
7 |
+
protected $_prefixJoker = '#__';
|
8 |
+
|
9 |
+
protected $_prefix = '';
|
10 |
+
|
11 |
+
public function getPrefix() {
|
12 |
+
return $this->_prefix;
|
13 |
+
}
|
14 |
+
|
15 |
+
public function parsePrefix($query) {
|
16 |
+
return str_replace($this->_prefixJoker, $this->_prefix, $query);
|
17 |
+
}
|
18 |
+
|
19 |
+
abstract public function insertId();
|
20 |
+
|
21 |
+
abstract public function query($query, $attributes = false);
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Return with one row by query string
|
25 |
+
*
|
26 |
+
* @param string $query
|
27 |
+
* @param array|bool $attributes for parameter binding
|
28 |
+
*
|
29 |
+
* @return mixed
|
30 |
+
*/
|
31 |
+
abstract public function queryRow($query, $attributes = false);
|
32 |
+
|
33 |
+
abstract public function queryAll($query, $attributes = false, $type = "assoc", $key = null);
|
34 |
+
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @param string $text
|
38 |
+
* @param bool $escape
|
39 |
+
*
|
40 |
+
* @return string
|
41 |
+
*/
|
42 |
+
abstract public function quote($text, $escape = true);
|
43 |
+
|
44 |
+
/**
|
45 |
+
* @param string $name
|
46 |
+
* @param null $as
|
47 |
+
*
|
48 |
+
* @return mixed
|
49 |
+
*/
|
50 |
+
abstract public function quoteName($name, $as = null);
|
51 |
+
|
52 |
+
public function checkError($result) {
|
53 |
+
return $result;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* @return string
|
58 |
+
*/
|
59 |
+
abstract public function getCharsetCollate();
|
60 |
+
}
|
Nextend/Framework/Database/AbstractPlatformConnectorTable.php
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Database;
|
5 |
+
|
6 |
+
|
7 |
+
abstract class AbstractPlatformConnectorTable {
|
8 |
+
|
9 |
+
protected $primaryKeyColumn = "id";
|
10 |
+
|
11 |
+
/** @var AbstractPlatformConnector */
|
12 |
+
protected static $connector;
|
13 |
+
|
14 |
+
protected $tableName;
|
15 |
+
|
16 |
+
public function __construct($tableName) {
|
17 |
+
|
18 |
+
$this->tableName = self::$connector->getPrefix() . $tableName;
|
19 |
+
}
|
20 |
+
|
21 |
+
public function getTableName() {
|
22 |
+
return $this->tableName;
|
23 |
+
}
|
24 |
+
|
25 |
+
abstract public function findByPk($primaryKey);
|
26 |
+
|
27 |
+
abstract public function findByAttributes(array $attributes, $fields = false, $order = false);
|
28 |
+
|
29 |
+
abstract public function findAll($order = false);
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Return with all row by attributes
|
33 |
+
*
|
34 |
+
* @param array $attributes
|
35 |
+
* @param bool|array $fields
|
36 |
+
* @param bool|string $order
|
37 |
+
*
|
38 |
+
* @return mixed
|
39 |
+
*/
|
40 |
+
abstract public function findAllByAttributes(array $attributes, $fields = false, $order = false);
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Insert new row
|
44 |
+
*
|
45 |
+
* @param array $attributes
|
46 |
+
*
|
47 |
+
* @return mixed|void
|
48 |
+
*/
|
49 |
+
abstract public function insert(array $attributes);
|
50 |
+
|
51 |
+
abstract public function insertId();
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Update row(s) by param(s)
|
55 |
+
*
|
56 |
+
* @param array $attributes
|
57 |
+
* @param array $conditions
|
58 |
+
*
|
59 |
+
* @return mixed
|
60 |
+
*/
|
61 |
+
abstract public function update(array $attributes, array $conditions);
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Update one row by primary key with $attributes
|
65 |
+
*
|
66 |
+
* @param mixed $primaryKey
|
67 |
+
* @param array $attributes
|
68 |
+
*
|
69 |
+
* @return mixed
|
70 |
+
*/
|
71 |
+
abstract public function updateByPk($primaryKey, array $attributes);
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Delete one with by primary key
|
75 |
+
*
|
76 |
+
* @param mixed $primaryKey
|
77 |
+
*
|
78 |
+
* @return mixed
|
79 |
+
*/
|
80 |
+
abstract public function deleteByPk($primaryKey);
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Delete all rows by attributes
|
84 |
+
*
|
85 |
+
* @param array $conditions
|
86 |
+
*
|
87 |
+
* @return mixed
|
88 |
+
*/
|
89 |
+
abstract public function deleteByAttributes(array $conditions);
|
90 |
+
}
|
Nextend/Framework/Database/Database.php
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Database;
|
4 |
+
|
5 |
+
use Nextend\Framework\Database\Joomla\JoomlaConnector;
|
6 |
+
use Nextend\Framework\Database\Joomla\JoomlaConnectorTable;
|
7 |
+
use Nextend\Framework\Database\WordPress\WordPressConnector;
|
8 |
+
use Nextend\Framework\Database\WordPress\WordPressConnectorTable;
|
9 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
10 |
+
|
11 |
+
class Database {
|
12 |
+
|
13 |
+
use SingletonTrait;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @var AbstractPlatformConnector
|
17 |
+
*/
|
18 |
+
private static $platformConnector;
|
19 |
+
|
20 |
+
protected function init() {
|
21 |
+
self::$platformConnector = new WordPressConnector();
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @param $tableName
|
26 |
+
*
|
27 |
+
* @return AbstractPlatformConnectorTable
|
28 |
+
*/
|
29 |
+
public static function getTable($tableName) {
|
30 |
+
return new WordPressConnectorTable($tableName);
|
31 |
+
}
|
32 |
+
|
33 |
+
public static function getPrefix() {
|
34 |
+
return self::$platformConnector->getPrefix();
|
35 |
+
}
|
36 |
+
|
37 |
+
public static function parsePrefix($query) {
|
38 |
+
return self::$platformConnector->parsePrefix($query);
|
39 |
+
}
|
40 |
+
|
41 |
+
public static function insertId() {
|
42 |
+
|
43 |
+
return self::$platformConnector->insertId();
|
44 |
+
}
|
45 |
+
|
46 |
+
public static function query($query, $attributes = false) {
|
47 |
+
|
48 |
+
return self::$platformConnector->query($query, $attributes);
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Return with one row by query string
|
53 |
+
*
|
54 |
+
* @param string $query
|
55 |
+
* @param array|bool $attributes for parameter binding
|
56 |
+
*
|
57 |
+
* @return mixed
|
58 |
+
*/
|
59 |
+
public static function queryRow($query, $attributes = false) {
|
60 |
+
|
61 |
+
return self::$platformConnector->queryRow($query, $attributes);
|
62 |
+
}
|
63 |
+
|
64 |
+
public static function queryAll($query, $attributes = false, $type = "assoc", $key = null) {
|
65 |
+
|
66 |
+
return self::$platformConnector->queryAll($query, $attributes, $type, $key);
|
67 |
+
}
|
68 |
+
|
69 |
+
|
70 |
+
/**
|
71 |
+
* @param string $text
|
72 |
+
* @param bool $escape
|
73 |
+
*
|
74 |
+
* @return string
|
75 |
+
*/
|
76 |
+
public static function quote($text, $escape = true) {
|
77 |
+
|
78 |
+
return self::$platformConnector->quote($text, $escape);
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* @param string $name
|
83 |
+
* @param null $as
|
84 |
+
*
|
85 |
+
* @return mixed
|
86 |
+
*/
|
87 |
+
public static function quoteName($name, $as = null) {
|
88 |
+
|
89 |
+
return self::$platformConnector->quoteName($name, $as);
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* @return string
|
94 |
+
*/
|
95 |
+
public static function getCharsetCollate() {
|
96 |
+
|
97 |
+
return self::$platformConnector->getCharsetCollate();
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
Database::getInstance();
|
Nextend/Framework/Database/WordPress/WordPressConnector.php
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Database\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Database\AbstractPlatformConnector;
|
6 |
+
use Nextend\Framework\Notification\Notification;
|
7 |
+
use Nextend\SmartSlider3\Platform\SmartSlider3Platform;
|
8 |
+
use wpdb;
|
9 |
+
|
10 |
+
class WordPressConnector extends AbstractPlatformConnector {
|
11 |
+
|
12 |
+
/** @var wpdb $wpdb */
|
13 |
+
private $db;
|
14 |
+
|
15 |
+
public function __construct() {
|
16 |
+
/** @var wpdb $wpdb */ global $wpdb;
|
17 |
+
$this->db = $wpdb;
|
18 |
+
$this->_prefix = $wpdb->prefix;
|
19 |
+
|
20 |
+
WordPressConnectorTable::init($this, $this->db);
|
21 |
+
}
|
22 |
+
|
23 |
+
public function query($query, $attributes = false) {
|
24 |
+
if ($attributes) {
|
25 |
+
foreach ($attributes as $key => $value) {
|
26 |
+
$replaceTo = is_numeric($value) ? $value : $this->db->prepare('%s', $value);
|
27 |
+
$query = str_replace($key, $replaceTo, $query);
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
return $this->checkError($this->db->query($query));
|
32 |
+
}
|
33 |
+
|
34 |
+
public function insertId() {
|
35 |
+
return $this->db->insert_id;
|
36 |
+
}
|
37 |
+
|
38 |
+
private function _querySQL($query, $attributes = false) {
|
39 |
+
|
40 |
+
$args = array('');
|
41 |
+
|
42 |
+
if ($attributes) {
|
43 |
+
foreach ($attributes as $key => $value) {
|
44 |
+
$replaceTo = is_numeric($value) ? '%d' : '%s';
|
45 |
+
$query = str_replace($key, $replaceTo, $query);
|
46 |
+
$args[] = $value;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
|
51 |
+
if (count($args) > 1) {
|
52 |
+
$args[0] = $query;
|
53 |
+
|
54 |
+
return call_user_func_array(array(
|
55 |
+
$this->db,
|
56 |
+
'prepare'
|
57 |
+
), $args);
|
58 |
+
} else {
|
59 |
+
return $query;
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
public function queryRow($query, $attributes = false) {
|
64 |
+
return $this->checkError($this->db->get_row($this->_querySQL($query, $attributes), ARRAY_A));
|
65 |
+
}
|
66 |
+
|
67 |
+
public function queryAll($query, $attributes = false, $type = "assoc", $key = null) {
|
68 |
+
$result = $this->checkError($this->db->get_results($this->_querySQL($query, $attributes), $type == 'assoc' ? ARRAY_A : OBJECT_K));
|
69 |
+
if (!$key) {
|
70 |
+
return $result;
|
71 |
+
}
|
72 |
+
$realResult = array();
|
73 |
+
|
74 |
+
for ($i = 0; $i < count($result); $i++) {
|
75 |
+
$key = $type == 'assoc' ? $result[i][$key] : $result[i]->{$key};
|
76 |
+
$realResult[$key] = $result[i];
|
77 |
+
}
|
78 |
+
|
79 |
+
return $realResult;
|
80 |
+
}
|
81 |
+
|
82 |
+
public function quote($text, $escape = true) {
|
83 |
+
return '\'' . (esc_sql($text)) . '\'';
|
84 |
+
}
|
85 |
+
|
86 |
+
public function quoteName($name, $as = null) {
|
87 |
+
if (strpos($name, '.') !== false) {
|
88 |
+
return $name;
|
89 |
+
} else {
|
90 |
+
$q = '`';
|
91 |
+
if (strlen($q) == 1) {
|
92 |
+
return $q . $name . $q;
|
93 |
+
} else {
|
94 |
+
return $q[0] . $name . $q[1];
|
95 |
+
}
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
public function checkError($result) {
|
100 |
+
if (!empty($this->db->last_error)) {
|
101 |
+
if (is_admin()) {
|
102 |
+
$lastError = $this->db->last_error;
|
103 |
+
$lastQuery = $this->db->last_query;
|
104 |
+
$message = array(
|
105 |
+
n2_('Unexpected database error.'),
|
106 |
+
'',
|
107 |
+
'<a href="' . wp_nonce_url(add_query_arg(array('repairss3' => '1'), SmartSlider3Platform::getAdminUrl()), 'repairss3') . '" class="n2_button n2_button--big n2_button--blue">' . n2_('Try to repair database') . '</a>',
|
108 |
+
'',
|
109 |
+
sprintf(n2_('If you see this message after the repair database process, please %1$scontact us%2$s with the log:'), '<a href="https://smartslider3.com/contact-us/support/" target="_blank">', '</a>'),
|
110 |
+
'<b>' . $lastError . '</b>',
|
111 |
+
$lastQuery
|
112 |
+
);
|
113 |
+
Notification::error(implode('<br>', $message), array(
|
114 |
+
'wide' => true
|
115 |
+
));
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
return $result;
|
120 |
+
}
|
121 |
+
|
122 |
+
public function getCharsetCollate() {
|
123 |
+
|
124 |
+
return $this->db->get_charset_collate();
|
125 |
+
}
|
126 |
+
}
|
Nextend/Framework/Database/WordPress/WordPressConnectorTable.php
ADDED
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Database\WordPress;
|
5 |
+
|
6 |
+
use Nextend\Framework\Database\AbstractPlatformConnector;
|
7 |
+
use Nextend\Framework\Database\AbstractPlatformConnectorTable;
|
8 |
+
use wpdb;
|
9 |
+
|
10 |
+
class WordPressConnectorTable extends AbstractPlatformConnectorTable {
|
11 |
+
|
12 |
+
/** @var wpdb */
|
13 |
+
protected static $db;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @param AbstractPlatformConnector $connector
|
17 |
+
* @param wpdb $db
|
18 |
+
*/
|
19 |
+
public static function init($connector, $db) {
|
20 |
+
self::$connector = $connector;
|
21 |
+
self::$db = $db;
|
22 |
+
}
|
23 |
+
|
24 |
+
public function findByPk($primaryKey) {
|
25 |
+
$query = self::$db->prepare("SELECT * FROM " . $this->tableName . " WHERE " . self::$connector->quoteName($this->primaryKeyColumn) . " = %s", $primaryKey);
|
26 |
+
|
27 |
+
return self::$connector->checkError(self::$db->get_row($query, ARRAY_A));
|
28 |
+
}
|
29 |
+
|
30 |
+
public function findByAttributes(array $attributes, $fields = false, $order = false) {
|
31 |
+
|
32 |
+
return self::$connector->checkError(self::$db->get_row($this->_findByAttributesSQL($attributes, $fields, $order), ARRAY_A));
|
33 |
+
}
|
34 |
+
|
35 |
+
|
36 |
+
public function findAll($order = false) {
|
37 |
+
|
38 |
+
return self::$connector->checkError(self::$db->get_results($this->_findByAttributesSQL(array(), false, $order), ARRAY_A));
|
39 |
+
}
|
40 |
+
|
41 |
+
public function findAllByAttributes(array $attributes, $fields = false, $order = false) {
|
42 |
+
|
43 |
+
return self::$connector->checkError(self::$db->get_results($this->_findByAttributesSQL($attributes, $fields, $order), ARRAY_A));
|
44 |
+
}
|
45 |
+
|
46 |
+
public function insert(array $attributes) {
|
47 |
+
return self::$connector->checkError(self::$db->insert($this->tableName, $attributes));
|
48 |
+
}
|
49 |
+
|
50 |
+
public function insertId() {
|
51 |
+
return self::$db->insert_id;
|
52 |
+
}
|
53 |
+
|
54 |
+
public function update(array $attributes, array $conditions) {
|
55 |
+
|
56 |
+
return self::$connector->checkError(self::$db->update($this->tableName, $attributes, $conditions));
|
57 |
+
}
|
58 |
+
|
59 |
+
public function updateByPk($primaryKey, array $attributes) {
|
60 |
+
|
61 |
+
$where = array();
|
62 |
+
$where[$this->primaryKeyColumn] = $primaryKey;
|
63 |
+
self::$connector->checkError(self::$db->update($this->tableName, $attributes, $where));
|
64 |
+
}
|
65 |
+
|
66 |
+
public function deleteByPk($primaryKey) {
|
67 |
+
$where = array();
|
68 |
+
$where[$this->primaryKeyColumn] = $primaryKey;
|
69 |
+
self::$connector->checkError(self::$db->delete($this->tableName, $where));
|
70 |
+
}
|
71 |
+
|
72 |
+
public function deleteByAttributes(array $conditions) {
|
73 |
+
self::$connector->checkError(self::$db->delete($this->tableName, $conditions));
|
74 |
+
}
|
75 |
+
|
76 |
+
private function _findByAttributesSQL(array $attributes, $fields = array(), $order = false) {
|
77 |
+
|
78 |
+
$args = array('');
|
79 |
+
|
80 |
+
$query = 'SELECT ';
|
81 |
+
if (!empty($fields)) {
|
82 |
+
|
83 |
+
$fields = array_map(array(
|
84 |
+
self::$connector,
|
85 |
+
'quoteName'
|
86 |
+
), $fields);
|
87 |
+
|
88 |
+
$query .= implode(', ', $fields);
|
89 |
+
} else {
|
90 |
+
$query .= '*';
|
91 |
+
}
|
92 |
+
$query .= ' FROM ' . $this->tableName;
|
93 |
+
|
94 |
+
$where = array();
|
95 |
+
foreach ($attributes as $key => $val) {
|
96 |
+
$where[] = self::$connector->quoteName($key) . ' = ' . (is_numeric($val) ? '%d' : '%s');
|
97 |
+
$args[] = $val;
|
98 |
+
}
|
99 |
+
if (count($where)) {
|
100 |
+
$query .= ' WHERE ' . implode(' AND ', $where);
|
101 |
+
}
|
102 |
+
|
103 |
+
if ($order) {
|
104 |
+
$query .= ' ORDER BY ' . $order;
|
105 |
+
}
|
106 |
+
|
107 |
+
if (count($args) > 1) {
|
108 |
+
$args[0] = $query;
|
109 |
+
|
110 |
+
return call_user_func_array(array(
|
111 |
+
self::$db,
|
112 |
+
'prepare'
|
113 |
+
), $args);
|
114 |
+
} else {
|
115 |
+
return $query;
|
116 |
+
}
|
117 |
+
}
|
118 |
+
}
|
Nextend/Framework/Filesystem/AbstractPlatformFilesystem.php
ADDED
@@ -0,0 +1,356 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Filesystem;
|
4 |
+
|
5 |
+
use Nextend\Framework\Url\Url;
|
6 |
+
|
7 |
+
if (!defined('NEXTEND_RELATIVE_CACHE_WEB')) {
|
8 |
+
define('NEXTEND_RELATIVE_CACHE_WEB', '/cache/nextend/web');
|
9 |
+
define('NEXTEND_CUSTOM_CACHE', 0);
|
10 |
+
} else {
|
11 |
+
define('NEXTEND_CUSTOM_CACHE', 1);
|
12 |
+
}
|
13 |
+
if (!defined('NEXTEND_RELATIVE_CACHE_NOTWEB')) {
|
14 |
+
define('NEXTEND_RELATIVE_CACHE_NOTWEB', '/cache/nextend/notweb');
|
15 |
+
}
|
16 |
+
|
17 |
+
abstract class AbstractPlatformFilesystem {
|
18 |
+
|
19 |
+
public $paths = array();
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @var string Absolute path which match to the baseuri. It must not end with /
|
23 |
+
* @example /asd/xyz/wordpress
|
24 |
+
*/
|
25 |
+
protected $_basepath;
|
26 |
+
|
27 |
+
protected $dirPermission = 0777;
|
28 |
+
|
29 |
+
protected $filePermission = 0666;
|
30 |
+
|
31 |
+
|
32 |
+
protected $translate = array();
|
33 |
+
|
34 |
+
public function init() {
|
35 |
+
|
36 |
+
}
|
37 |
+
|
38 |
+
public function getPaths() {
|
39 |
+
|
40 |
+
return $this->paths;
|
41 |
+
}
|
42 |
+
|
43 |
+
public function check($base, $folder) {
|
44 |
+
static $checked = array();
|
45 |
+
if (!isset($checked[$base . '/' . $folder])) {
|
46 |
+
$cacheFolder = $base . '/' . $folder;
|
47 |
+
if (!$this->existsFolder($cacheFolder)) {
|
48 |
+
if ($this->is_writable($base)) {
|
49 |
+
$this->createFolder($cacheFolder);
|
50 |
+
} else {
|
51 |
+
die('<div style="position:fixed;background:#fff;width:100%;height:100%;top:0;left:0;z-index:100000;">' . sprintf('<h2><b>%s</b> is not writable.</h2>', $base) . '</div>');
|
52 |
+
}
|
53 |
+
} else if (!$this->is_writable($cacheFolder)) {
|
54 |
+
die('<div style="position:fixed;background:#fff;width:100%;height:100%;top:0;left:0;z-index:100000;">' . sprintf('<h2><b>%s</b> is not writable.</h2>', $cacheFolder) . '</div>');
|
55 |
+
}
|
56 |
+
$checked[$base . '/' . $folder] = true;
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
public function measurePermission($testDir) {
|
61 |
+
while ('.' != $testDir && !is_dir($testDir)) {
|
62 |
+
$testDir = dirname($testDir);
|
63 |
+
}
|
64 |
+
|
65 |
+
if ($stat = @stat($testDir)) {
|
66 |
+
$this->dirPermission = $stat['mode'] & 0007777;
|
67 |
+
$this->filePermission = $this->dirPermission & 0000666;
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* @param $path
|
73 |
+
*
|
74 |
+
* @return mixed
|
75 |
+
*/
|
76 |
+
public function toLinux($path) {
|
77 |
+
return str_replace(DIRECTORY_SEPARATOR, '/', $path);
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @return string
|
82 |
+
*/
|
83 |
+
public function getBasePath() {
|
84 |
+
|
85 |
+
return $this->_basepath;
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* @param $path
|
90 |
+
*/
|
91 |
+
public function setBasePath($path) {
|
92 |
+
|
93 |
+
$this->_basepath = $path;
|
94 |
+
}
|
95 |
+
|
96 |
+
public function getWebCachePath() {
|
97 |
+
|
98 |
+
return $this->getBasePath() . NEXTEND_RELATIVE_CACHE_WEB;
|
99 |
+
}
|
100 |
+
|
101 |
+
public function getNotWebCachePath() {
|
102 |
+
return $this->getBasePath() . NEXTEND_RELATIVE_CACHE_NOTWEB;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* @param $path
|
107 |
+
*
|
108 |
+
* @return string
|
109 |
+
*/
|
110 |
+
public function pathToAbsoluteURL($path) {
|
111 |
+
return Url::pathToUri($path);
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* @param $path
|
116 |
+
*
|
117 |
+
* @return string
|
118 |
+
*/
|
119 |
+
public function pathToRelativePath($path) {
|
120 |
+
|
121 |
+
return preg_replace('/^' . preg_quote($this->_basepath, '/') . '/', '', str_replace('/', DIRECTORY_SEPARATOR, $path));
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* @param $path
|
126 |
+
*
|
127 |
+
* @return string
|
128 |
+
*/
|
129 |
+
public function pathToAbsolutePath($path) {
|
130 |
+
|
131 |
+
return $this->_basepath . str_replace('/', DIRECTORY_SEPARATOR, $path);
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* @param $url
|
136 |
+
*
|
137 |
+
* @return string
|
138 |
+
*/
|
139 |
+
public function absoluteURLToPath($url) {
|
140 |
+
|
141 |
+
$fullUri = Url::getFullUri();
|
142 |
+
if (substr($url, 0, strlen($fullUri)) == $fullUri) {
|
143 |
+
|
144 |
+
return str_replace($fullUri, $this->_basepath, $url);
|
145 |
+
}
|
146 |
+
|
147 |
+
return $url;
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* @param $file
|
152 |
+
*
|
153 |
+
* @return bool
|
154 |
+
*/
|
155 |
+
public function fileexists($file) {
|
156 |
+
return is_file($file);
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* @param $file
|
161 |
+
*
|
162 |
+
* @return bool
|
163 |
+
*/
|
164 |
+
public function safefileexists($file) {
|
165 |
+
return realpath($file) && is_file($file);
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
*
|
170 |
+
* @param $dir
|
171 |
+
*
|
172 |
+
* @return array Folder names without trailing slash
|
173 |
+
*/
|
174 |
+
public function folders($dir) {
|
175 |
+
if (!is_dir($dir)) {
|
176 |
+
return array();
|
177 |
+
}
|
178 |
+
$folders = array();
|
179 |
+
foreach (scandir($dir) as $file) {
|
180 |
+
if ($file == '.' || $file == '..') continue;
|
181 |
+
if (is_dir($dir . DIRECTORY_SEPARATOR . $file)) $folders[] = $file;
|
182 |
+
}
|
183 |
+
|
184 |
+
return $folders;
|
185 |
+
}
|
186 |
+
|
187 |
+
/**
|
188 |
+
* @param $path
|
189 |
+
*
|
190 |
+
* @return bool
|
191 |
+
*/
|
192 |
+
public function is_writable($path) {
|
193 |
+
return is_writable($path);
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* @param $path
|
198 |
+
*
|
199 |
+
* @return bool
|
200 |
+
*/
|
201 |
+
public function createFolder($path) {
|
202 |
+
|
203 |
+
return mkdir($path, $this->dirPermission, true);
|
204 |
+
}
|
205 |
+
|
206 |
+
public function deleteFolder($dir) {
|
207 |
+
if (!is_dir($dir) || is_link($dir)) return unlink($dir);
|
208 |
+
foreach (scandir($dir) as $file) {
|
209 |
+
if ($file == '.' || $file == '..') continue;
|
210 |
+
if (!$this->deleteFolder($dir . DIRECTORY_SEPARATOR . $file)) {
|
211 |
+
chmod($dir . DIRECTORY_SEPARATOR . $file, $this->dirPermission);
|
212 |
+
if (!$this->deleteFolder($dir . DIRECTORY_SEPARATOR . $file)) return false;
|
213 |
+
}
|
214 |
+
}
|
215 |
+
|
216 |
+
return rmdir($dir);
|
217 |
+
}
|
218 |
+
|
219 |
+
public function existsFolder($path) {
|
220 |
+
return is_dir($path);
|
221 |
+
}
|
222 |
+
|
223 |
+
public function files($path) {
|
224 |
+
$files = array();
|
225 |
+
if (is_dir($path)) {
|
226 |
+
if ($dh = opendir($path)) {
|
227 |
+
while (($file = readdir($dh)) !== false) {
|
228 |
+
if ($file[0] != ".") {
|
229 |
+
$files[] = $file;
|
230 |
+
}
|
231 |
+
}
|
232 |
+
closedir($dh);
|
233 |
+
}
|
234 |
+
}
|
235 |
+
|
236 |
+
return $files;
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* @param $path
|
241 |
+
*
|
242 |
+
* @return bool
|
243 |
+
*/
|
244 |
+
public function existsFile($path) {
|
245 |
+
|
246 |
+
return file_exists($path);
|
247 |
+
}
|
248 |
+
|
249 |
+
/**
|
250 |
+
* @param $path
|
251 |
+
* @param $buffer
|
252 |
+
*
|
253 |
+
* @return int
|
254 |
+
*/
|
255 |
+
public function createFile($path, $buffer) {
|
256 |
+
return file_put_contents($path, $buffer);
|
257 |
+
}
|
258 |
+
|
259 |
+
/**
|
260 |
+
* @param $path
|
261 |
+
*
|
262 |
+
* @return string
|
263 |
+
*/
|
264 |
+
public function readFile($path) {
|
265 |
+
return file_get_contents($path);
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* convert dir alias to normal format
|
270 |
+
*
|
271 |
+
* @param $pathName
|
272 |
+
*
|
273 |
+
* @return mixed
|
274 |
+
*/
|
275 |
+
public function dirFormat($pathName) {
|
276 |
+
return str_replace(".", DIRECTORY_SEPARATOR, $pathName);
|
277 |
+
}
|
278 |
+
|
279 |
+
public function getImagesFolder() {
|
280 |
+
return '';
|
281 |
+
}
|
282 |
+
|
283 |
+
public function realpath($path) {
|
284 |
+
return rtrim(realpath($path), '/\\');
|
285 |
+
}
|
286 |
+
|
287 |
+
public function registerTranslate($from, $to) {
|
288 |
+
$this->translate[$from] = $to;
|
289 |
+
}
|
290 |
+
|
291 |
+
protected function trailingslashit($string) {
|
292 |
+
return $this->untrailingslashit($string) . '/';
|
293 |
+
}
|
294 |
+
|
295 |
+
protected function untrailingslashit($string) {
|
296 |
+
return rtrim($string, '/\\');
|
297 |
+
}
|
298 |
+
|
299 |
+
public function convertToRealDirectorySeparator($path) {
|
300 |
+
return str_replace(DIRECTORY_SEPARATOR == '/' ? '\\' : '/', DIRECTORY_SEPARATOR, $path);
|
301 |
+
}
|
302 |
+
|
303 |
+
public function get_temp_dir() {
|
304 |
+
static $temp = '';
|
305 |
+
if (defined('SS_TEMP_DIR')) return $this->trailingslashit(SS_TEMP_DIR);
|
306 |
+
|
307 |
+
if ($temp) return $this->trailingslashit($temp);
|
308 |
+
|
309 |
+
if (function_exists('sys_get_temp_dir')) {
|
310 |
+
$temp = sys_get_temp_dir();
|
311 |
+
if (@is_dir($temp) && $this->is_writable($temp)) return $this->trailingslashit($temp);
|
312 |
+
}
|
313 |
+
|
314 |
+
$temp = ini_get('upload_tmp_dir');
|
315 |
+
if (@is_dir($temp) && $this->is_writable($temp)) return $this->trailingslashit($temp);
|
316 |
+
|
317 |
+
$temp = $this->getNotWebCachePath() . '/';
|
318 |
+
if (is_dir($temp) && $this->is_writable($temp)) return $temp;
|
319 |
+
|
320 |
+
return '/tmp/';
|
321 |
+
}
|
322 |
+
|
323 |
+
public function tempnam($filename = '', $dir = '') {
|
324 |
+
if (empty($dir)) {
|
325 |
+
$dir = $this->get_temp_dir();
|
326 |
+
}
|
327 |
+
|
328 |
+
if (empty($filename) || '.' == $filename || '/' == $filename || '\\' == $filename) {
|
329 |
+
$filename = time();
|
330 |
+
}
|
331 |
+
|
332 |
+
// Use the basename of the given file without the extension as the name for the temporary directory
|
333 |
+
$temp_filename = basename($filename);
|
334 |
+
$temp_filename = preg_replace('|\.[^.]*$|', '', $temp_filename);
|
335 |
+
|
336 |
+
// If the folder is falsey, use its parent directory name instead.
|
337 |
+
if (!$temp_filename) {
|
338 |
+
return $this->tempnam(dirname($filename), $dir);
|
339 |
+
}
|
340 |
+
|
341 |
+
// Suffix some random data to avoid filename conflicts
|
342 |
+
$temp_filename .= '-' . md5(uniqid(rand() . time()));
|
343 |
+
$temp_filename .= '.tmp';
|
344 |
+
$temp_filename = $dir . $temp_filename;
|
345 |
+
|
346 |
+
$fp = @fopen($temp_filename, 'x');
|
347 |
+
if (!$fp && is_writable($dir) && file_exists($temp_filename)) {
|
348 |
+
return $this->tempnam($filename, $dir);
|
349 |
+
}
|
350 |
+
if ($fp) {
|
351 |
+
fclose($fp);
|
352 |
+
}
|
353 |
+
|
354 |
+
return $temp_filename;
|
355 |
+
}
|
356 |
+
}
|
Nextend/Framework/Filesystem/Filesystem.php
ADDED
@@ -0,0 +1,275 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Filesystem;
|
4 |
+
|
5 |
+
use Nextend\Framework\Filesystem\Joomla\JoomlaFilesystem;
|
6 |
+
use Nextend\Framework\Filesystem\WordPress\WordPressFilesystem;
|
7 |
+
|
8 |
+
class Filesystem {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var AbstractPlatformFilesystem
|
12 |
+
*/
|
13 |
+
private static $platformFilesystem;
|
14 |
+
|
15 |
+
public function __construct() {
|
16 |
+
self::$platformFilesystem = new WordPressFilesystem();
|
17 |
+
|
18 |
+
self::$platformFilesystem->init();
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @return AbstractPlatformFilesystem
|
23 |
+
*/
|
24 |
+
public static function get() {
|
25 |
+
|
26 |
+
return self::$platformFilesystem;
|
27 |
+
}
|
28 |
+
|
29 |
+
public static function getPaths() {
|
30 |
+
|
31 |
+
return self::$platformFilesystem->getPaths();
|
32 |
+
}
|
33 |
+
|
34 |
+
public static function check($base, $folder) {
|
35 |
+
|
36 |
+
self::$platformFilesystem->check($base, $folder);
|
37 |
+
}
|
38 |
+
|
39 |
+
public static function measurePermission($testDir) {
|
40 |
+
|
41 |
+
self::$platformFilesystem->measurePermission($testDir);
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* @param $path
|
46 |
+
*
|
47 |
+
* @return string
|
48 |
+
*/
|
49 |
+
public static function toLinux($path) {
|
50 |
+
|
51 |
+
return self::$platformFilesystem->toLinux($path);
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* @return string
|
56 |
+
*/
|
57 |
+
public static function getBasePath() {
|
58 |
+
|
59 |
+
return self::$platformFilesystem->getBasePath();
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @param $path
|
64 |
+
*/
|
65 |
+
public static function setBasePath($path) {
|
66 |
+
|
67 |
+
self::$platformFilesystem->setBasePath($path);
|
68 |
+
}
|
69 |
+
|
70 |
+
public static function getWebCachePath() {
|
71 |
+
|
72 |
+
return self::$platformFilesystem->getWebCachePath();
|
73 |
+
}
|
74 |
+
|
75 |
+
public static function getNotWebCachePath() {
|
76 |
+
|
77 |
+
return self::$platformFilesystem->getNotWebCachePath();
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @param $path
|
82 |
+
*
|
83 |
+
* @return string
|
84 |
+
*/
|
85 |
+
public static function pathToAbsoluteURL($path) {
|
86 |
+
|
87 |
+
return self::$platformFilesystem->pathToAbsoluteURL($path);
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* @param $path
|
92 |
+
*
|
93 |
+
* @return string
|
94 |
+
*/
|
95 |
+
public static function pathToRelativePath($path) {
|
96 |
+
|
97 |
+
return self::$platformFilesystem->pathToRelativePath($path);
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* @param $path
|
102 |
+
*
|
103 |
+
* @return string
|
104 |
+
*/
|
105 |
+
public static function pathToAbsolutePath($path) {
|
106 |
+
|
107 |
+
return self::$platformFilesystem->pathToAbsolutePath($path);
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* @param $url
|
112 |
+
*
|
113 |
+
* @return string
|
114 |
+
*/
|
115 |
+
public static function absoluteURLToPath($url) {
|
116 |
+
|
117 |
+
return self::$platformFilesystem->absoluteURLToPath($url);
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* @param $file
|
122 |
+
*
|
123 |
+
* @return bool
|
124 |
+
*/
|
125 |
+
public static function fileexists($file) {
|
126 |
+
|
127 |
+
return self::$platformFilesystem->fileexists($file);
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* @param $file
|
132 |
+
*
|
133 |
+
* @return bool
|
134 |
+
*/
|
135 |
+
public static function safefileexists($file) {
|
136 |
+
|
137 |
+
return self::$platformFilesystem->safefileexists($file);
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
*
|
142 |
+
* @param $dir
|
143 |
+
*
|
144 |
+
* @return array Folder names without trailing slash
|
145 |
+
*/
|
146 |
+
public static function folders($dir) {
|
147 |
+
|
148 |
+
return self::$platformFilesystem->folders($dir);
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* @param $path
|
153 |
+
*
|
154 |
+
* @return bool
|
155 |
+
*/
|
156 |
+
public static function is_writable($path) {
|
157 |
+
|
158 |
+
return self::$platformFilesystem->is_writable($path);
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* @param $path
|
163 |
+
*
|
164 |
+
* @return bool
|
165 |
+
*/
|
166 |
+
public static function createFolder($path) {
|
167 |
+
|
168 |
+
return self::$platformFilesystem->createFolder($path);
|
169 |
+
}
|
170 |
+
|
171 |
+
/**
|
172 |
+
* @param $dir
|
173 |
+
*
|
174 |
+
* @return bool
|
175 |
+
*/
|
176 |
+
public static function deleteFolder($dir) {
|
177 |
+
|
178 |
+
return self::$platformFilesystem->deleteFolder($dir);
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* @param $path
|
183 |
+
*
|
184 |
+
* @return bool
|
185 |
+
*/
|
186 |
+
public static function existsFolder($path) {
|
187 |
+
|
188 |
+
return self::$platformFilesystem->existsFolder($path);
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* @param $path
|
193 |
+
*
|
194 |
+
* @return array
|
195 |
+
*/
|
196 |
+
public static function files($path) {
|
197 |
+
|
198 |
+
return self::$platformFilesystem->files($path);
|
199 |
+
}
|
200 |
+
|
201 |
+
/**
|
202 |
+
* @param $path
|
203 |
+
*
|
204 |
+
* @return bool
|
205 |
+
*/
|
206 |
+
public static function existsFile($path) {
|
207 |
+
|
208 |
+
return self::$platformFilesystem->existsFile($path);
|
209 |
+
}
|
210 |
+
|
211 |
+
/**
|
212 |
+
* @param $path
|
213 |
+
* @param $buffer
|
214 |
+
*
|
215 |
+
* @return int
|
216 |
+
*/
|
217 |
+
public static function createFile($path, $buffer) {
|
218 |
+
|
219 |
+
return self::$platformFilesystem->createFile($path, $buffer);
|
220 |
+
}
|
221 |
+
|
222 |
+
/**
|
223 |
+
* @param $path
|
224 |
+
*
|
225 |
+
* @return string
|
226 |
+
*/
|
227 |
+
public static function readFile($path) {
|
228 |
+
|
229 |
+
return self::$platformFilesystem->readFile($path);
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* convert dir alias to normal format
|
234 |
+
*
|
235 |
+
* @param $pathName
|
236 |
+
*
|
237 |
+
* @return mixed
|
238 |
+
*/
|
239 |
+
public static function dirFormat($pathName) {
|
240 |
+
|
241 |
+
return self::$platformFilesystem->dirFormat($pathName);
|
242 |
+
}
|
243 |
+
|
244 |
+
public static function getImagesFolder() {
|
245 |
+
|
246 |
+
return self::$platformFilesystem->getImagesFolder();
|
247 |
+
}
|
248 |
+
|
249 |
+
public static function realpath($path) {
|
250 |
+
|
251 |
+
return self::$platformFilesystem->realpath($path);
|
252 |
+
}
|
253 |
+
|
254 |
+
public static function registerTranslate($from, $to) {
|
255 |
+
|
256 |
+
self::$platformFilesystem->registerTranslate($from, $to);
|
257 |
+
}
|
258 |
+
|
259 |
+
public static function convertToRealDirectorySeparator($path) {
|
260 |
+
|
261 |
+
return self::$platformFilesystem->convertToRealDirectorySeparator($path);
|
262 |
+
}
|
263 |
+
|
264 |
+
public static function get_temp_dir() {
|
265 |
+
|
266 |
+
return self::$platformFilesystem->get_temp_dir();
|
267 |
+
}
|
268 |
+
|
269 |
+
public static function tempnam($filename = '', $dir = '') {
|
270 |
+
|
271 |
+
return self::$platformFilesystem->tempnam($filename = '', $dir = '');
|
272 |
+
}
|
273 |
+
}
|
274 |
+
|
275 |
+
new Filesystem();
|
Nextend/Framework/Filesystem/WordPress/WordPressFilesystem.php
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Filesystem\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Filesystem\AbstractPlatformFilesystem;
|
6 |
+
use Nextend\Framework\Platform\Platform;
|
7 |
+
use Nextend\Framework\Url\Url;
|
8 |
+
use function get_current_blog_id;
|
9 |
+
|
10 |
+
class WordPressFilesystem extends AbstractPlatformFilesystem {
|
11 |
+
|
12 |
+
public function init() {
|
13 |
+
|
14 |
+
$this->paths[] = realpath(ABSPATH);
|
15 |
+
|
16 |
+
$this->_basepath = realpath(WP_CONTENT_DIR);
|
17 |
+
|
18 |
+
$this->paths[] = $this->_basepath;
|
19 |
+
|
20 |
+
$this->paths[] = realpath(WP_PLUGIN_DIR);
|
21 |
+
|
22 |
+
$wp_upload_dir = wp_upload_dir();
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Amazon S3 storage has s3://my-bucket/uploads upload path. If we found a scheme in the path we will
|
26 |
+
* skip the realpath check so it won't fail in the future.
|
27 |
+
* @url https://github.com/humanmade/S3-Uploads
|
28 |
+
*/
|
29 |
+
if (!stream_is_local($wp_upload_dir['basedir'])) {
|
30 |
+
$uploadPath = $wp_upload_dir['basedir'];
|
31 |
+
} else {
|
32 |
+
$uploadPath = rtrim(realpath($wp_upload_dir['basedir']), "/\\");
|
33 |
+
if (empty($uploadPath)) {
|
34 |
+
echo 'Error: Your upload path is not valid or does not exist: ' . $wp_upload_dir['basedir'];
|
35 |
+
$uploadPath = rtrim($wp_upload_dir['basedir'], "/\\");
|
36 |
+
} else {
|
37 |
+
$this->measurePermission($uploadPath);
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
if (strpos($this->_basepath, $uploadPath) !== 0) {
|
42 |
+
$this->paths[] = $uploadPath;
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
public function getImagesFolder() {
|
47 |
+
return Platform::getPublicDirectory();
|
48 |
+
}
|
49 |
+
|
50 |
+
public function getWebCachePath() {
|
51 |
+
if (is_multisite()) {
|
52 |
+
return $this->getBasePath() . NEXTEND_RELATIVE_CACHE_WEB . get_current_blog_id();
|
53 |
+
}
|
54 |
+
|
55 |
+
return $this->getBasePath() . NEXTEND_RELATIVE_CACHE_WEB;
|
56 |
+
}
|
57 |
+
|
58 |
+
public function getNotWebCachePath() {
|
59 |
+
if (is_multisite()) {
|
60 |
+
return $this->getBasePath() . NEXTEND_RELATIVE_CACHE_NOTWEB . get_current_blog_id();
|
61 |
+
}
|
62 |
+
|
63 |
+
return $this->getBasePath() . NEXTEND_RELATIVE_CACHE_NOTWEB;
|
64 |
+
}
|
65 |
+
|
66 |
+
public function absoluteURLToPath($url) {
|
67 |
+
$uris = Url::getUris();
|
68 |
+
|
69 |
+
for ($i = count($uris) - 1; $i >= 0; $i--) {
|
70 |
+
$uri = $uris[$i];
|
71 |
+
if (substr($url, 0, strlen($uri)) == $uri) {
|
72 |
+
|
73 |
+
return str_replace($uri, $this->paths[$i], $url);
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
return $url;
|
78 |
+
}
|
79 |
+
|
80 |
+
public function tempnam($filename = '', $dir = '') {
|
81 |
+
return wp_tempnam($filename, $dir);
|
82 |
+
}
|
83 |
+
}
|
Nextend/Framework/Font/AbstractFontSource.php
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Font;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\ContainerInterface;
|
8 |
+
|
9 |
+
abstract class AbstractFontSource {
|
10 |
+
|
11 |
+
protected $name;
|
12 |
+
|
13 |
+
public abstract function getLabel();
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @return string
|
17 |
+
*/
|
18 |
+
public function getName() {
|
19 |
+
return $this->name;
|
20 |
+
}
|
21 |
+
|
22 |
+
public function onFontManagerLoad($force = false) {
|
23 |
+
|
24 |
+
}
|
25 |
+
|
26 |
+
public function onFontManagerLoadBackend() {
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @param ContainerInterface $container
|
31 |
+
*/
|
32 |
+
abstract public function renderFields($container);
|
33 |
+
}
|
Nextend/Framework/Font/Block/FontManager/BlockFontManager.php
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Font\Block\FontManager;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Font\FontRenderer;
|
9 |
+
use Nextend\Framework\Font\FontSettings;
|
10 |
+
use Nextend\Framework\Font\ModelFont;
|
11 |
+
use Nextend\Framework\Localization\Localization;
|
12 |
+
use Nextend\Framework\Visual\AbstractBlockVisual;
|
13 |
+
use Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonApply;
|
14 |
+
use Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonCancel;
|
15 |
+
|
16 |
+
class BlockFontManager extends AbstractBlockVisual {
|
17 |
+
|
18 |
+
/** @var ModelFont */
|
19 |
+
protected $model;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @return ModelFont
|
23 |
+
*/
|
24 |
+
public function getModel() {
|
25 |
+
return $this->model;
|
26 |
+
}
|
27 |
+
|
28 |
+
public function display() {
|
29 |
+
|
30 |
+
$this->model = new ModelFont($this);
|
31 |
+
|
32 |
+
$this->renderTemplatePart('Index');
|
33 |
+
}
|
34 |
+
|
35 |
+
public function displayTopBar() {
|
36 |
+
|
37 |
+
$buttonCancel = new BlockButtonCancel($this);
|
38 |
+
$buttonCancel->addClass('n2_fullscreen_editor__cancel');
|
39 |
+
$buttonCancel->display();
|
40 |
+
|
41 |
+
$buttonApply = new BlockButtonApply($this);
|
42 |
+
$buttonApply->addClass('n2_fullscreen_editor__save');
|
43 |
+
$buttonApply->display();
|
44 |
+
}
|
45 |
+
|
46 |
+
public function displayContent() {
|
47 |
+
$model = $this->getModel();
|
48 |
+
|
49 |
+
Js::addFirstCode("
|
50 |
+
N2Classes.CSSRendererFont.defaultFamily = " . json_encode(FontSettings::getDefaultFamily()) . ";
|
51 |
+
N2Classes.CSSRendererFont.rendererModes = " . json_encode(FontRenderer::$mode) . ";
|
52 |
+
N2Classes.CSSRendererFont.pre = " . json_encode(FontRenderer::$pre) . ";
|
53 |
+
new N2Classes.NextendFontManager();
|
54 |
+
");
|
55 |
+
|
56 |
+
$model->renderForm();
|
57 |
+
}
|
58 |
+
}
|
Nextend/Framework/Font/Block/FontManager/Index.phtml
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Font\Block\FontManager;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* @var BlockFontManager $this
|
7 |
+
*/
|
8 |
+
?>
|
9 |
+
<div id="n2-lightbox-font" class="n2_fullscreen_editor">
|
10 |
+
<div class="n2_fullscreen_editor__overlay"></div>
|
11 |
+
<div class="n2_fullscreen_editor__window">
|
12 |
+
<div class="n2_fullscreen_editor__nav_bar">
|
13 |
+
<div class="n2_fullscreen_editor__nav_bar_label">
|
14 |
+
<?php n2_e('Font manager'); ?>
|
15 |
+
</div>
|
16 |
+
<div class="n2_fullscreen_editor__nav_bar_actions">
|
17 |
+
<?php $this->displayTopBar(); ?>
|
18 |
+
</div>
|
19 |
+
</div>
|
20 |
+
<div class="n2_fullscreen_editor__content">
|
21 |
+
<div class="n2_fullscreen_editor__content_content n2_container_scrollable">
|
22 |
+
<?php $this->displayContent(); ?>
|
23 |
+
</div>
|
24 |
+
</div>
|
25 |
+
</div>
|
26 |
+
</div>
|
Nextend/Framework/Font/ControllerAjaxFont.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Font;
|
4 |
+
|
5 |
+
use Nextend\Framework\Controller\Admin\AdminVisualManagerAjaxController;
|
6 |
+
|
7 |
+
class ControllerAjaxFont extends AdminVisualManagerAjaxController {
|
8 |
+
|
9 |
+
protected $type = 'font';
|
10 |
+
|
11 |
+
public function getModel() {
|
12 |
+
|
13 |
+
return new ModelFont($this);
|
14 |
+
}
|
15 |
+
}
|
Nextend/Framework/Font/FontManager.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Font;
|
4 |
+
|
5 |
+
use Nextend\Framework\Font\Block\FontManager\BlockFontManager;
|
6 |
+
use Nextend\Framework\Pattern\VisualManagerTrait;
|
7 |
+
|
8 |
+
class FontManager {
|
9 |
+
|
10 |
+
use VisualManagerTrait;
|
11 |
+
|
12 |
+
public function display() {
|
13 |
+
|
14 |
+
$fontManagerBlock = new BlockFontManager($this->MVCHelper);
|
15 |
+
$fontManagerBlock->display();
|
16 |
+
}
|
17 |
+
}
|
Nextend/Framework/Font/FontParser.php
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Font;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Misc\Base64;
|
8 |
+
use Nextend\Framework\Model\Section;
|
9 |
+
|
10 |
+
class FontParser {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @param $data
|
14 |
+
*
|
15 |
+
* @return string
|
16 |
+
*/
|
17 |
+
public static function parse($data) {
|
18 |
+
if (empty($data)) {
|
19 |
+
return '';
|
20 |
+
} else if (is_numeric($data)) {
|
21 |
+
/**
|
22 |
+
* Linked font
|
23 |
+
*/
|
24 |
+
|
25 |
+
$font = Section::getById($data, 'font');
|
26 |
+
|
27 |
+
if (!$font) {
|
28 |
+
/**
|
29 |
+
* Linked font not exists anymore
|
30 |
+
*/
|
31 |
+
return '';
|
32 |
+
}
|
33 |
+
|
34 |
+
|
35 |
+
if (is_string($font['value'])) {
|
36 |
+
/**
|
37 |
+
* Old format when value stored as Base64
|
38 |
+
*/
|
39 |
+
$decoded = $font['value'];
|
40 |
+
if ($decoded[0] != '{') {
|
41 |
+
$decoded = Base64::decode($decoded);
|
42 |
+
}
|
43 |
+
|
44 |
+
return $decoded;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Value stored as array
|
49 |
+
*/
|
50 |
+
$value = json_encode($font['value']);
|
51 |
+
if ($value == false) {
|
52 |
+
return '';
|
53 |
+
}
|
54 |
+
|
55 |
+
return $value;
|
56 |
+
} else if ($data[0] != '{') {
|
57 |
+
return Base64::decode($data);
|
58 |
+
}
|
59 |
+
|
60 |
+
return $data;
|
61 |
+
}
|
62 |
+
}
|
Nextend/Framework/Font/FontRenderer.php
ADDED
@@ -0,0 +1,275 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Font;
|
4 |
+
|
5 |
+
use Nextend\Framework\Settings;
|
6 |
+
|
7 |
+
class FontRenderer {
|
8 |
+
|
9 |
+
public static $defaultFont = 'Montserrat';
|
10 |
+
|
11 |
+
public static $pre = '';
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var FontStyle
|
15 |
+
*/
|
16 |
+
public static $style;
|
17 |
+
|
18 |
+
public static $mode;
|
19 |
+
|
20 |
+
public static function setDefaultFont($fontFamily) {
|
21 |
+
self::$defaultFont = $fontFamily;
|
22 |
+
}
|
23 |
+
|
24 |
+
public static function render($font, $mode, $pre = '', $fontSize = false) {
|
25 |
+
self::$pre = $pre;
|
26 |
+
|
27 |
+
if (!empty($font)) {
|
28 |
+
$value = json_decode($font, true);
|
29 |
+
if ($value) {
|
30 |
+
$selector = 'n2-font-' . md5($font) . '-' . $mode;
|
31 |
+
|
32 |
+
return array(
|
33 |
+
$selector . ' ',
|
34 |
+
self::renderFont($mode, $pre, $selector, $value['data'], $fontSize)
|
35 |
+
);
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
return false;
|
40 |
+
}
|
41 |
+
|
42 |
+
private static function renderFont($mode, $pre, $selector, $tabs, $fontSize) {
|
43 |
+
$search = array(
|
44 |
+
'@pre',
|
45 |
+
'@selector'
|
46 |
+
);
|
47 |
+
$replace = array(
|
48 |
+
$pre,
|
49 |
+
'.' . $selector
|
50 |
+
);
|
51 |
+
$tabs[0] = array_merge(array(
|
52 |
+
'afont' => self::$defaultFont,
|
53 |
+
'color' => '000000ff',
|
54 |
+
'size' => '14||px',
|
55 |
+
'tshadow' => '0|*|0|*|0|*|000000ff',
|
56 |
+
'lineheight' => '1.5',
|
57 |
+
'bold' => 0,
|
58 |
+
'italic' => 0,
|
59 |
+
'underline' => 0,
|
60 |
+
'align' => 'left',
|
61 |
+
'letterspacing' => "normal",
|
62 |
+
'wordspacing' => "normal",
|
63 |
+
'texttransform' => "none",
|
64 |
+
'extra' => ''
|
65 |
+
), $tabs[0]);
|
66 |
+
|
67 |
+
if (self::$mode[$mode]['renderOptions']['combined']) {
|
68 |
+
for ($i = 1; $i < count($tabs); $i++) {
|
69 |
+
$tabs[$i] = array_merge($tabs[$i - 1], $tabs[$i]);
|
70 |
+
if ($tabs[$i]['size'] == $tabs[0]['size']) {
|
71 |
+
$tabs[$i]['size'] = '100||%';
|
72 |
+
} else {
|
73 |
+
$size1 = explode('||', $tabs[0]['size']);
|
74 |
+
$size2 = explode('||', $tabs[$i]['size']);
|
75 |
+
if (isset($size1[1]) && isset($size2[1]) && $size1[1] == 'px' && $size2[1] == 'px') {
|
76 |
+
$tabs[$i]['size'] = round($size2[0] / $size1[0] * 100) . '||%';
|
77 |
+
}
|
78 |
+
}
|
79 |
+
}
|
80 |
+
}
|
81 |
+
foreach ($tabs AS $k => $tab) {
|
82 |
+
$search[] = '@tab' . $k;
|
83 |
+
FontStyle::$fontSize = $fontSize;
|
84 |
+
$replace[] = self::$style->style($tab);
|
85 |
+
}
|
86 |
+
|
87 |
+
$template = '';
|
88 |
+
foreach (self::$mode[$mode]['selectors'] AS $s => $style) {
|
89 |
+
if (!in_array($style, $search) || !empty($replace[array_search($style, $search)])) {
|
90 |
+
$template .= $s . "{" . $style . "}";
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
return str_replace($search, $replace, $template);
|
95 |
+
}
|
96 |
+
}
|
97 |
+
|
98 |
+
$frontendAccessibility = intval(Settings::get('frontend-accessibility', 1));
|
99 |
+
|
100 |
+
FontRenderer::$mode = array(
|
101 |
+
'0' => array(
|
102 |
+
'id' => '0',
|
103 |
+
'label' => n2_('Text'),
|
104 |
+
'tabs' => array(
|
105 |
+
n2_('Text')
|
106 |
+
),
|
107 |
+
'renderOptions' => array(
|
108 |
+
'combined' => false
|
109 |
+
),
|
110 |
+
'preview' => '<div class="{fontClassName}">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>',
|
111 |
+
'selectors' => array(
|
112 |
+
'@pre@selector' => '@tab0'
|
113 |
+
)
|
114 |
+
),
|
115 |
+
'simple' => array(
|
116 |
+
'id' => 'simple',
|
117 |
+
'label' => n2_('Text'),
|
118 |
+
'tabs' => array(
|
119 |
+
n2_('Text')
|
120 |
+
),
|
121 |
+
'renderOptions' => array(
|
122 |
+
'combined' => false
|
123 |
+
),
|
124 |
+
'preview' => '<div class="{fontClassName}">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>',
|
125 |
+
'selectors' => array(
|
126 |
+
'@pre@selector' => '@tab0'
|
127 |
+
)
|
128 |
+
),
|
129 |
+
'hover' => array(
|
130 |
+
'id' => 'hover',
|
131 |
+
'label' => n2_('Hover'),
|
132 |
+
'tabs' => array(
|
133 |
+
n2_('Text'),
|
134 |
+
n2_('Hover')
|
135 |
+
),
|
136 |
+
'renderOptions' => array(
|
137 |
+
'combined' => false
|
138 |
+
),
|
139 |
+
'preview' => '<div class="{fontClassName}">' . n2_('Heading') . '</div>',
|
140 |
+
'selectors' => $frontendAccessibility ? array(
|
141 |
+
'@pre@selector' => '@tab0',
|
142 |
+
'@pre@selector:HOVER, @pre@selector:ACTIVE, @pre@selector:FOCUS' => '@tab1'
|
143 |
+
) : array(
|
144 |
+
'@pre@selector, @pre@selector:FOCUS' => '@tab0',
|
145 |
+
'@pre@selector:HOVER, @pre@selector:ACTIVE' => '@tab1'
|
146 |
+
)
|
147 |
+
),
|
148 |
+
'link' => array(
|
149 |
+
'id' => 'link',
|
150 |
+
'label' => n2_('Link'),
|
151 |
+
'tabs' => array(
|
152 |
+
n2_('Text'),
|
153 |
+
n2_('Hover')
|
154 |
+
),
|
155 |
+
'renderOptions' => array(
|
156 |
+
'combined' => false
|
157 |
+
),
|
158 |
+
'preview' => '<div class="{fontClassName}"><a href="#" onclick="return false;">' . n2_('Button') . '</a></div>',
|
159 |
+
'selectors' => $frontendAccessibility ? array(
|
160 |
+
'@pre@selector a' => '@tab0',
|
161 |
+
'@pre@selector a:HOVER, @pre@selector a:ACTIVE, @pre@selector a:FOCUS' => '@tab1'
|
162 |
+
) : array(
|
163 |
+
'@pre@selector a, @pre@selector a:FOCUS' => '@tab0',
|
164 |
+
'@pre@selector a:HOVER, @pre@selector a:ACTIVE' => '@tab1'
|
165 |
+
)
|
166 |
+
),
|
167 |
+
'accordionslidetitle' => array(
|
168 |
+
'id' => 'accordionslidetitle',
|
169 |
+
'label' => n2_('Accordion slide title'),
|
170 |
+
'tabs' => array(
|
171 |
+
n2_('Normal'),
|
172 |
+
n2_('Active')
|
173 |
+
),
|
174 |
+
'renderOptions' => array(
|
175 |
+
'combined' => false
|
176 |
+
),
|
177 |
+
'preview' => '<div class="{fontClassName}">' . n2_('Slide title') . '</div>',
|
178 |
+
'selectors' => array(
|
179 |
+
'@pre@selector' => '@tab0',
|
180 |
+
'@pre.n2-ss-slide-active @selector, @pre@selector:HOVER' => '@tab1'
|
181 |
+
)
|
182 |
+
),
|
183 |
+
'paragraph' => array(
|
184 |
+
'id' => 'paragraph',
|
185 |
+
'label' => n2_('Paragraph'),
|
186 |
+
'tabs' => array(
|
187 |
+
n2_('Text'),
|
188 |
+
n2_('Link'),
|
189 |
+
n2_('Hover')
|
190 |
+
),
|
191 |
+
'renderOptions' => array(
|
192 |
+
'combined' => true
|
193 |
+
),
|
194 |
+
'preview' => '<div class="{fontClassName}">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do <a href="#">test link</a> incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in <a href="#">test link</a> velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat <a href="#">test link</a>, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>',
|
195 |
+
'selectors' => array(
|
196 |
+
'@pre@selector' => '@tab0',
|
197 |
+
'@pre@selector a, @pre@selector a:FOCUS' => '@tab1',
|
198 |
+
'@pre@selector a:HOVER, @pre@selector a:ACTIVE' => '@tab2'
|
199 |
+
)
|
200 |
+
),
|
201 |
+
'input' => array(
|
202 |
+
'id' => 'input',
|
203 |
+
'label' => 'Input',
|
204 |
+
'tabs' => array(
|
205 |
+
n2_('Text'),
|
206 |
+
n2_('Hover')
|
207 |
+
),
|
208 |
+
'renderOptions' => array(
|
209 |
+
'combined' => false
|
210 |
+
),
|
211 |
+
'preview' => '<div class="{fontClassName}">Excepteur sint occaecat</div>',
|
212 |
+
'selectors' => array(
|
213 |
+
'@pre@selector' => '@tab0',
|
214 |
+
'@pre@selector:HOVER, @pre@selector:FOCUS' => '@tab2'
|
215 |
+
)
|
216 |
+
),
|
217 |
+
'dot' => array(
|
218 |
+
'id' => 'dot',
|
219 |
+
'label' => n2_('Dot'),
|
220 |
+
'tabs' => array(
|
221 |
+
n2_('Text'),
|
222 |
+
n2_('Active')
|
223 |
+
),
|
224 |
+
'renderOptions' => array(
|
225 |
+
'combined' => false
|
226 |
+
),
|
227 |
+
'preview' => '',
|
228 |
+
'selectors' => array(
|
229 |
+
'@pre@selector, @pre@selector:FOCUS' => '@tab0',
|
230 |
+
'@pre@selector.n2-active, @pre@selector:HOVER, @pre@selector:ACTIVE' => '@tab1'
|
231 |
+
)
|
232 |
+
),
|
233 |
+
'list' => array(
|
234 |
+
'id' => 'list',
|
235 |
+
'label' => n2_('List'),
|
236 |
+
'tabs' => array(
|
237 |
+
n2_('Text'),
|
238 |
+
n2_('Link'),
|
239 |
+
n2_('Hover')
|
240 |
+
),
|
241 |
+
'renderOptions' => array(
|
242 |
+
'combined' => false
|
243 |
+
),
|
244 |
+
'preview' => '',
|
245 |
+
'selectors' => array(
|
246 |
+
'@pre@selector li' => '@tab0',
|
247 |
+
'@pre@selector li a, @pre@selector li a:FOCUS' => '@tab1',
|
248 |
+
'@pre@selector li a:HOVER, @pre@selector li a:ACTIVE' => '@tab2'
|
249 |
+
)
|
250 |
+
),
|
251 |
+
'highlight' => array(
|
252 |
+
'id' => 'highlight',
|
253 |
+
'label' => n2_('Highlight'),
|
254 |
+
'tabs' => array(
|
255 |
+
n2_('Text'),
|
256 |
+
n2_('Highlight'),
|
257 |
+
n2_('Hover')
|
258 |
+
),
|
259 |
+
'renderOptions' => array(
|
260 |
+
'combined' => true
|
261 |
+
),
|
262 |
+
'preview' => '<div class="{fontClassName}">' . n2_('Button') . '</div>',
|
263 |
+
'selectors' => $frontendAccessibility ? array(
|
264 |
+
'@pre@selector' => '@tab0',
|
265 |
+
'@pre@selector .n2-highlighted' => '@tab1',
|
266 |
+
'@pre@selector .n2-highlighted:HOVER, @pre@selector .n2-highlighted:ACTIVE, @pre@selector .n2-highlighted:FOCUS' => '@tab2'
|
267 |
+
) : array(
|
268 |
+
'@pre@selector' => '@tab0',
|
269 |
+
'@pre@selector .n2-highlighted, @pre@selector .n2-highlighted:FOCUS' => '@tab1',
|
270 |
+
'@pre@selector .n2-highlighted:HOVER, @pre@selector .n2-highlighted:ACTIVE' => '@tab2'
|
271 |
+
)
|
272 |
+
),
|
273 |
+
);
|
274 |
+
|
275 |
+
FontRenderer::$style = new FontStyle();
|
Nextend/Framework/Font/FontSettings.php
ADDED
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Font;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Data\Data;
|
8 |
+
use Nextend\Framework\Model\Section;
|
9 |
+
|
10 |
+
class FontSettings {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var Data
|
14 |
+
*/
|
15 |
+
private static $data;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @var Data
|
19 |
+
*/
|
20 |
+
private static $pluginsData;
|
21 |
+
|
22 |
+
public function __construct() {
|
23 |
+
self::load();
|
24 |
+
FontRenderer::setDefaultFont(self::$data->get('default-family'));
|
25 |
+
}
|
26 |
+
|
27 |
+
public static function load() {
|
28 |
+
|
29 |
+
self::$data = new Data(array(
|
30 |
+
'default-family' => n2_x('Roboto,Arial', 'Default font'),
|
31 |
+
'preset-families' => n2_x(implode("\n", array(
|
32 |
+
"Abel",
|
33 |
+
"Arial",
|
34 |
+
"Arimo",
|
35 |
+
"Average",
|
36 |
+
"Bevan",
|
37 |
+
"Bitter",
|
38 |
+
"'Bree Serif'",
|
39 |
+
"Cabin",
|
40 |
+
"Calligraffitti",
|
41 |
+
"Chewy",
|
42 |
+
"Comfortaa",
|
43 |
+
"'Covered By Your Grace'",
|
44 |
+
"'Crafty Girls'",
|
45 |
+
"'Dancing Script'",
|
46 |
+
"'Noto Sans'",
|
47 |
+
"'Noto Serif'",
|
48 |
+
"'Francois One'",
|
49 |
+
"'Fredoka One'",
|
50 |
+
"'Gloria Hallelujah'",
|
51 |
+
"'Happy Monkey'",
|
52 |
+
"'Josefin Slab'",
|
53 |
+
"Lato",
|
54 |
+
"Lobster",
|
55 |
+
"'Luckiest Guy'",
|
56 |
+
"Montserrat",
|
57 |
+
"'Nova Square'",
|
58 |
+
"Nunito",
|
59 |
+
"'Open Sans'",
|
60 |
+
"Oswald",
|
61 |
+
"Oxygen",
|
62 |
+
"Pacifico",
|
63 |
+
"'Permanent Marker'",
|
64 |
+
"'Playfair Display'",
|
65 |
+
"'PT Sans'",
|
66 |
+
"'Poiret One'",
|
67 |
+
"Raleway",
|
68 |
+
"Roboto",
|
69 |
+
"'Rock Salt'",
|
70 |
+
"Quicksand",
|
71 |
+
"Satisfy",
|
72 |
+
"'Squada One'",
|
73 |
+
"'The Girl Next Door'",
|
74 |
+
"'Titillium Web'",
|
75 |
+
"'Varela Round'",
|
76 |
+
"Vollkorn",
|
77 |
+
"'Walter Turncoat'"
|
78 |
+
)), 'Default font family list'),
|
79 |
+
'plugins' => array()
|
80 |
+
));
|
81 |
+
|
82 |
+
foreach (Section::getAll('system', 'fonts') AS $data) {
|
83 |
+
self::$data->set($data['referencekey'], $data['value']);
|
84 |
+
}
|
85 |
+
|
86 |
+
self::$pluginsData = new Data(self::$data->get('plugins'), true);
|
87 |
+
}
|
88 |
+
|
89 |
+
public static function store($data) {
|
90 |
+
if (is_array($data)) {
|
91 |
+
foreach ($data as $key => $value) {
|
92 |
+
if (self::$data->has($key)) {
|
93 |
+
self::$data->set($key, $value);
|
94 |
+
Section::set('system', 'fonts', $key, $value, 1, 1);
|
95 |
+
unset($data[$key]);
|
96 |
+
}
|
97 |
+
}
|
98 |
+
if (count($data)) {
|
99 |
+
self::$pluginsData = new Data($data);
|
100 |
+
Section::set('system', 'fonts', 'plugins', self::$pluginsData->toJSON(), 1, 1);
|
101 |
+
|
102 |
+
}
|
103 |
+
|
104 |
+
return true;
|
105 |
+
}
|
106 |
+
|
107 |
+
return false;
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* @return Data
|
112 |
+
*/
|
113 |
+
public static function getData() {
|
114 |
+
|
115 |
+
return self::$data;
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* @return Data
|
120 |
+
*/
|
121 |
+
public static function getPluginsData() {
|
122 |
+
|
123 |
+
return self::$pluginsData;
|
124 |
+
}
|
125 |
+
|
126 |
+
public static function getDefaultFamily() {
|
127 |
+
return self::$data->get('default-family');
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* @return array
|
132 |
+
*/
|
133 |
+
public static function getPresetFamilies() {
|
134 |
+
return array_filter(explode("\n", self::$data->get('preset-families')));
|
135 |
+
}
|
136 |
+
}
|
137 |
+
|
138 |
+
new FontSettings();
|
Nextend/Framework/Font/FontSources.php
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Font;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
8 |
+
|
9 |
+
class FontSources {
|
10 |
+
|
11 |
+
/** @var AbstractFontSource[] */
|
12 |
+
private static $fontSources = array();
|
13 |
+
|
14 |
+
public function __construct() {
|
15 |
+
$dir = dirname(__FILE__) . '/Sources/';
|
16 |
+
foreach (Filesystem::folders($dir) AS $folder) {
|
17 |
+
$file = $dir . $folder . '/' . $folder . '.php';
|
18 |
+
if (Filesystem::fileexists($file)) {
|
19 |
+
require_once($file);
|
20 |
+
}
|
21 |
+
}
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @param string $class
|
26 |
+
*/
|
27 |
+
public static function registerSource($class) {
|
28 |
+
|
29 |
+
/** @var AbstractFontSource $source */
|
30 |
+
$source = new $class();
|
31 |
+
|
32 |
+
self::$fontSources[$source->getName()] = $source;
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @return AbstractFontSource[]
|
37 |
+
*/
|
38 |
+
public static function getFontSources() {
|
39 |
+
return self::$fontSources;
|
40 |
+
}
|
41 |
+
|
42 |
+
public static function onFontManagerLoad($force = false) {
|
43 |
+
foreach (self::$fontSources AS $source) {
|
44 |
+
$source->onFontManagerLoad($force);
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
public static function onFontManagerLoadBackend() {
|
49 |
+
foreach (self::$fontSources AS $source) {
|
50 |
+
$source->onFontManagerLoadBackend();
|
51 |
+
}
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
new FontSources();
|
Nextend/Framework/Font/FontStorage.php
ADDED
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Font;
|
5 |
+
|
6 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
7 |
+
use Nextend\Framework\Plugin;
|
8 |
+
|
9 |
+
class FontStorage {
|
10 |
+
|
11 |
+
use SingletonTrait;
|
12 |
+
|
13 |
+
private $sets = array();
|
14 |
+
|
15 |
+
private $fonts = array();
|
16 |
+
|
17 |
+
private $fontsBySet = array();
|
18 |
+
|
19 |
+
private $fontsById = array();
|
20 |
+
|
21 |
+
protected function init() {
|
22 |
+
|
23 |
+
Plugin::addAction('systemfontset', array(
|
24 |
+
$this,
|
25 |
+
'fontSet'
|
26 |
+
));
|
27 |
+
Plugin::addAction('systemfont', array(
|
28 |
+
$this,
|
29 |
+
'fonts'
|
30 |
+
));
|
31 |
+
Plugin::addAction('font', array(
|
32 |
+
$this,
|
33 |
+
'font'
|
34 |
+
));
|
35 |
+
}
|
36 |
+
|
37 |
+
private function load() {
|
38 |
+
static $loaded;
|
39 |
+
if (!$loaded) {
|
40 |
+
Plugin::doAction('fontStorage', array(
|
41 |
+
&$this->sets,
|
42 |
+
&$this->fonts
|
43 |
+
));
|
44 |
+
|
45 |
+
for ($i = 0; $i < count($this->fonts); $i++) {
|
46 |
+
if (!isset($this->fontsBySet[$this->fonts[$i]['referencekey']])) {
|
47 |
+
$this->fontsBySet[$this->fonts[$i]['referencekey']] = array();
|
48 |
+
}
|
49 |
+
$this->fontsBySet[$this->fonts[$i]['referencekey']][] = &$this->fonts[$i];
|
50 |
+
$this->fontsById[$this->fonts[$i]['id']] = &$this->fonts[$i];
|
51 |
+
}
|
52 |
+
$loaded = true;
|
53 |
+
}
|
54 |
+
}
|
55 |
+
|
56 |
+
public function fontSet($referenceKey, &$sets) {
|
57 |
+
|
58 |
+
$this->load();
|
59 |
+
|
60 |
+
for ($i = count($this->sets) - 1; $i >= 0; $i--) {
|
61 |
+
$this->sets[$i]['system'] = 1;
|
62 |
+
$this->sets[$i]['editable'] = 0;
|
63 |
+
array_unshift($sets, $this->sets[$i]);
|
64 |
+
}
|
65 |
+
|
66 |
+
}
|
67 |
+
|
68 |
+
public function fonts($referenceKey, &$fonts) {
|
69 |
+
|
70 |
+
$this->load();
|
71 |
+
|
72 |
+
if (isset($this->fontsBySet[$referenceKey])) {
|
73 |
+
$_fonts = &$this->fontsBySet[$referenceKey];
|
74 |
+
for ($i = count($_fonts) - 1; $i >= 0; $i--) {
|
75 |
+
$_fonts[$i]['system'] = 1;
|
76 |
+
$_fonts[$i]['editable'] = 0;
|
77 |
+
array_unshift($fonts, $_fonts[$i]);
|
78 |
+
}
|
79 |
+
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
public function font($id, &$font) {
|
84 |
+
|
85 |
+
$this->load();
|
86 |
+
|
87 |
+
if (isset($this->fontsById[$id])) {
|
88 |
+
$this->fontsById[$id]['system'] = 1;
|
89 |
+
$this->fontsById[$id]['editable'] = 0;
|
90 |
+
$font = $this->fontsById[$id];
|
91 |
+
}
|
92 |
+
}
|
93 |
+
}
|
Nextend/Framework/Font/FontStyle.php
ADDED
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Font;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Parser\Color;
|
8 |
+
use Nextend\Framework\Parser\Common;
|
9 |
+
use Nextend\Framework\Plugin;
|
10 |
+
use Nextend\Framework\Sanitize;
|
11 |
+
|
12 |
+
class FontStyle {
|
13 |
+
|
14 |
+
public static $fontSize = false;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @param string $tab
|
18 |
+
*
|
19 |
+
* @return string
|
20 |
+
*/
|
21 |
+
public function style($tab) {
|
22 |
+
$style = '';
|
23 |
+
$extra = '';
|
24 |
+
if (isset($tab['extra'])) {
|
25 |
+
$extra = $tab['extra'];
|
26 |
+
unset($tab['extra']);
|
27 |
+
}
|
28 |
+
foreach ($tab AS $k => $v) {
|
29 |
+
$style .= $this->parse($k, $v);
|
30 |
+
}
|
31 |
+
$style .= $this->parse('extra', $extra);
|
32 |
+
|
33 |
+
return $style;
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @param $property
|
38 |
+
* @param $value
|
39 |
+
*
|
40 |
+
* @return mixed
|
41 |
+
*/
|
42 |
+
public function parse($property, $value) {
|
43 |
+
$fn = 'parse' . $property;
|
44 |
+
|
45 |
+
return $this->$fn($value);
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @param $v
|
50 |
+
*
|
51 |
+
* @return string
|
52 |
+
*/
|
53 |
+
public function parseColor($v) {
|
54 |
+
$hex = Color::hex82hex($v);
|
55 |
+
if ($hex[1] == 'ff') {
|
56 |
+
return 'color: #' . $hex[0] . ';';
|
57 |
+
}
|
58 |
+
|
59 |
+
$rgba = Color::hex2rgba($v);
|
60 |
+
|
61 |
+
return 'color: RGBA(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ');';
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @param $v
|
66 |
+
*
|
67 |
+
* @return string
|
68 |
+
*/
|
69 |
+
public function parseSize($v) {
|
70 |
+
if (self::$fontSize) {
|
71 |
+
$fontSize = Common::parse($v);
|
72 |
+
if ($fontSize[1] == 'px') {
|
73 |
+
return 'font-size:' . ($fontSize[0] / self::$fontSize * 100) . '%;';
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
return 'font-size:' . Common::parse($v, '') . ';';
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @param $v
|
82 |
+
*
|
83 |
+
* @return string
|
84 |
+
*/
|
85 |
+
public function parseTshadow($v) {
|
86 |
+
$v = Common::parse($v);
|
87 |
+
$rgba = Color::hex2rgba($v[3]);
|
88 |
+
if ($v[0] == 0 && $v[1] == 0 && $v[2] == 0) return 'text-shadow: none;';
|
89 |
+
|
90 |
+
return 'text-shadow: ' . $v[0] . 'px ' . $v[1] . 'px ' . $v[2] . 'px RGBA(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ');';
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* @param $v
|
95 |
+
*
|
96 |
+
* @return string
|
97 |
+
*/
|
98 |
+
public function parseAfont($v) {
|
99 |
+
return 'font-family: ' . Sanitize::esc_css_value($this->loadFont($v)) . ';';
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* @param $v
|
104 |
+
*
|
105 |
+
* @return string
|
106 |
+
*/
|
107 |
+
public function parseLineheight($v) {
|
108 |
+
if ($v == '') return '';
|
109 |
+
|
110 |
+
return 'line-height: ' . $v . ';';
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* @param $v
|
115 |
+
*
|
116 |
+
* @return string
|
117 |
+
*/
|
118 |
+
public function parseBold($v) {
|
119 |
+
return $this->parseWeight($v);
|
120 |
+
}
|
121 |
+
|
122 |
+
public function parseWeight($v) {
|
123 |
+
if ($v == '1') return 'font-weight: bold;';
|
124 |
+
if ($v > 1) return 'font-weight: ' . intval($v) . ';';
|
125 |
+
|
126 |
+
return 'font-weight: normal;';
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* @param $v
|
131 |
+
*
|
132 |
+
* @return string
|
133 |
+
*/
|
134 |
+
public function parseItalic($v) {
|
135 |
+
if ($v == '1') return 'font-style: italic;';
|
136 |
+
|
137 |
+
return 'font-style: normal;';
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* @param $v
|
142 |
+
*
|
143 |
+
* @return string
|
144 |
+
*/
|
145 |
+
public function parseUnderline($v) {
|
146 |
+
if ($v == '1') return 'text-decoration: underline;';
|
147 |
+
|
148 |
+
return 'text-decoration: none;';
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* @param $v
|
153 |
+
*
|
154 |
+
* @return string
|
155 |
+
*/
|
156 |
+
public function parseAlign($v) {
|
157 |
+
return 'text-align: ' . $v . ';';
|
158 |
+
}
|
159 |
+
|
160 |
+
public function parseLetterSpacing($v) {
|
161 |
+
return 'letter-spacing: ' . $v . ';';
|
162 |
+
}
|
163 |
+
|
164 |
+
public function parseWordSpacing($v) {
|
165 |
+
return 'word-spacing: ' . $v . ';';
|
166 |
+
}
|
167 |
+
|
168 |
+
public function parseTextTransform($v) {
|
169 |
+
return 'text-transform: ' . $v . ';';
|
170 |
+
}
|
171 |
+
|
172 |
+
public function parseExtra($v) {
|
173 |
+
return $v;
|
174 |
+
}
|
175 |
+
|
176 |
+
/**
|
177 |
+
* @param $families
|
178 |
+
*
|
179 |
+
* @return mixed
|
180 |
+
*/
|
181 |
+
public function loadFont($families) {
|
182 |
+
$families = explode(',', $families);
|
183 |
+
for ($i = 0; $i < count($families); $i++) {
|
184 |
+
if ($families[$i] != "inherit") {
|
185 |
+
$families[$i] = $this->getFamily(trim(trim($families[$i]), '\'"'));
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
+
return implode(',', $families);
|
190 |
+
}
|
191 |
+
|
192 |
+
private function getFamily($family) {
|
193 |
+
return "'" . Plugin::applyFilters('fontFamily', $family) . "'";
|
194 |
+
}
|
195 |
+
}
|
Nextend/Framework/Font/ModelFont.php
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Font;
|
4 |
+
|
5 |
+
use Nextend\Framework\Form\Container\ContainerTable;
|
6 |
+
use Nextend\Framework\Form\Element\Button;
|
7 |
+
use Nextend\Framework\Form\Element\Decoration;
|
8 |
+
use Nextend\Framework\Form\Element\Mixed;
|
9 |
+
use Nextend\Framework\Form\Element\Radio\TextAlign;
|
10 |
+
use Nextend\Framework\Form\Element\Select;
|
11 |
+
use Nextend\Framework\Form\Element\Select\FontWeight;
|
12 |
+
use Nextend\Framework\Form\Element\Tab;
|
13 |
+
use Nextend\Framework\Form\Element\Text\Color;
|
14 |
+
use Nextend\Framework\Form\Element\Text\Family;
|
15 |
+
use Nextend\Framework\Form\Element\Text\TextAutoComplete;
|
16 |
+
use Nextend\Framework\Form\Element\Textarea;
|
17 |
+
use Nextend\Framework\Form\Form;
|
18 |
+
use Nextend\Framework\Visual\ModelVisual;
|
19 |
+
|
20 |
+
class ModelFont extends ModelVisual {
|
21 |
+
|
22 |
+
protected $type = 'font';
|
23 |
+
|
24 |
+
public function renderForm() {
|
25 |
+
|
26 |
+
$form = new Form($this, 'n2-font-editor');
|
27 |
+
|
28 |
+
$table = new ContainerTable($form->getContainer(), 'font', n2_('Font settings'));
|
29 |
+
|
30 |
+
$table->setFieldsetPositionEnd();
|
31 |
+
|
32 |
+
new Button($table->getFieldsetLabel(), 'font-clear-tab', false, n2_('Clear tab'));
|
33 |
+
|
34 |
+
new Tab($table->getFieldsetLabel(), 'font-state');
|
35 |
+
|
36 |
+
$row1 = $table->createRow('font-row-1');
|
37 |
+
new Family($row1, 'family', n2_('Family'), 'Arial, Helvetica', array(
|
38 |
+
'style' => 'width:150px;'
|
39 |
+
));
|
40 |
+
new Color($row1, 'color', n2_('Color'), '000000FF', array(
|
41 |
+
'alpha' => true
|
42 |
+
));
|
43 |
+
|
44 |
+
new Mixed\FontSize($row1, 'size', n2_('Size'), '14|*|px');
|
45 |
+
|
46 |
+
new FontWeight($row1, 'weight', n2_('Font weight'), '');
|
47 |
+
new Decoration($row1, 'decoration', n2_('Decoration'));
|
48 |
+
new TextAutoComplete($row1, 'lineheight', n2_('Line height'), '18px', array(
|
49 |
+
'values' => array(
|
50 |
+
'normal',
|
51 |
+
'1',
|
52 |
+
'1.2',
|
53 |
+
'1.5',
|
54 |
+
'1.8',
|
55 |
+
'2'
|
56 |
+
),
|
57 |
+
'style' => 'width:70px;'
|
58 |
+
));
|
59 |
+
new TextAlign($row1, 'textalign', n2_('Text align'), 'inherit');
|
60 |
+
|
61 |
+
$row2 = $table->createRow('font-row-2');
|
62 |
+
|
63 |
+
new TextAutoComplete($row2, 'letterspacing', n2_('Letter spacing'), 'normal', array(
|
64 |
+
'values' => array(
|
65 |
+
'normal',
|
66 |
+
'1px',
|
67 |
+
'2px',
|
68 |
+
'5px',
|
69 |
+
'10px',
|
70 |
+
'15px'
|
71 |
+
),
|
72 |
+
'style' => 'width:50px;'
|
73 |
+
));
|
74 |
+
new TextAutoComplete($row2, 'wordspacing', n2_('Word spacing'), 'normal', array(
|
75 |
+
'values' => array(
|
76 |
+
'normal',
|
77 |
+
'2px',
|
78 |
+
'5px',
|
79 |
+
'10px',
|
80 |
+
'15px'
|
81 |
+
),
|
82 |
+
'style' => 'width:50px;'
|
83 |
+
));
|
84 |
+
new Select($row2, 'texttransform', n2_('Transform'), 'none', array(
|
85 |
+
'options' => array(
|
86 |
+
'none' => n2_('None'),
|
87 |
+
'capitalize' => n2_('Capitalize'),
|
88 |
+
'uppercase' => n2_('Uppercase'),
|
89 |
+
'lowercase' => n2_('Lowercase')
|
90 |
+
)
|
91 |
+
));
|
92 |
+
|
93 |
+
new Mixed\TextShadow($row2, 'tshadow', n2_('Text shadow'), '0|*|0|*|1|*|000000FF');
|
94 |
+
|
95 |
+
new Textarea($row2, 'extracss', 'CSS', '', array(
|
96 |
+
'width' => 200,
|
97 |
+
'height' => 26
|
98 |
+
));
|
99 |
+
|
100 |
+
$previewTable = new ContainerTable($form->getContainer(), 'font-preview', n2_('Preview'));
|
101 |
+
|
102 |
+
$previewTable->setFieldsetPositionEnd();
|
103 |
+
|
104 |
+
new Color($previewTable->getFieldsetLabel(), 'preview-background', false, 'ced3d5');
|
105 |
+
|
106 |
+
$form->render();
|
107 |
+
}
|
108 |
+
}
|
Nextend/Framework/Font/Sources/GoogleFonts/GoogleFonts.php
ADDED
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Font\Sources\GoogleFonts;
|
5 |
+
|
6 |
+
use Nextend\Framework\Asset\AssetManager;
|
7 |
+
use Nextend\Framework\Asset\Fonts\Google\Google;
|
8 |
+
use Nextend\Framework\Asset\Js\Js;
|
9 |
+
use Nextend\Framework\Font\AbstractFontSource;
|
10 |
+
use Nextend\Framework\Font\FontSettings;
|
11 |
+
use Nextend\Framework\Font\FontSources;
|
12 |
+
use Nextend\Framework\Form\Container\ContainerRowGroup;
|
13 |
+
use Nextend\Framework\Form\Element\OnOff;
|
14 |
+
use Nextend\Framework\Form\Fieldset\FieldsetRow;
|
15 |
+
use Nextend\Framework\Platform\Platform;
|
16 |
+
use Nextend\Framework\Plugin;
|
17 |
+
|
18 |
+
|
19 |
+
/*
|
20 |
+
jQuery.getJSON('https://www.googleapis.com/webfonts/v1/webfonts?sort=alpha&key=AIzaSyBIzBtder0-ef5a6kX-Ri9IfzVwFu21PGw').done(function(data){
|
21 |
+
var f = [];
|
22 |
+
for(var i = 0; i < data.items.length; i++){
|
23 |
+
f.push(data.items[i].family);
|
24 |
+
}
|
25 |
+
console.log(JSON.stringify(f));
|
26 |
+
});
|
27 |
+
*/
|
28 |
+
|
29 |
+
class GoogleFonts extends AbstractFontSource {
|
30 |
+
|
31 |
+
protected $name = 'google';
|
32 |
+
|
33 |
+
private static $fonts = array();
|
34 |
+
|
35 |
+
private static $styles = array();
|
36 |
+
private static $subsets = array();
|
37 |
+
|
38 |
+
public function __construct() {
|
39 |
+
$lines = file(dirname(__FILE__) . '/families.csv', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
40 |
+
for ($i = 0; $i < count($lines); $i++) {
|
41 |
+
self::$fonts[strtolower($lines[$i])] = $lines[$i];
|
42 |
+
}
|
43 |
+
self::$fonts['droid sans'] = 'Noto Sans';
|
44 |
+
self::$fonts['droid sans mono'] = 'Roboto Mono';
|
45 |
+
self::$fonts['droid serif'] = 'Noto Serif';
|
46 |
+
}
|
47 |
+
|
48 |
+
public function getLabel() {
|
49 |
+
return 'Google';
|
50 |
+
}
|
51 |
+
|
52 |
+
public function renderFields($container) {
|
53 |
+
|
54 |
+
$row1 = new FieldsetRow($container, 'fonts-google-1');
|
55 |
+
new OnOff($row1, 'google-enabled', n2_('Frontend'), 1, array(
|
56 |
+
'tipLabel' => n2_('Frontend'),
|
57 |
+
'tipDescription' => n2_('You can load Google Fonts on the frontend.')
|
58 |
+
));
|
59 |
+
new OnOff($row1, 'google-enabled-backend', n2_('Backend'), 1, array(
|
60 |
+
'tipLabel' => n2_('Backend'),
|
61 |
+
'tipDescription' => n2_('You can load Google Fonts in the backend.')
|
62 |
+
));
|
63 |
+
|
64 |
+
$rowGroupStyle = new ContainerRowGroup($container, 'fonts-google-style', n2_('Style'));
|
65 |
+
$rowStyle = $rowGroupStyle->createRow('fonts-google-style');
|
66 |
+
new OnOff($rowStyle, 'google-style-100', '100', 0);
|
67 |
+
new OnOff($rowStyle, 'google-style-100italic', '100 ' . n2_x('Italic', "Font style"), 0);
|
68 |
+
new OnOff($rowStyle, 'google-style-200', '200', 0);
|
69 |
+
new OnOff($rowStyle, 'google-style-200italic', '200 ' . n2_x('Italic', "Font style"), 0);
|
70 |
+
new OnOff($rowStyle, 'google-style-300', '300', 1);
|
71 |
+
new OnOff($rowStyle, 'google-style-300italic', '300 ' . n2_x('Italic', "Font style"), 0);
|
72 |
+
new OnOff($rowStyle, 'google-style-400', n2_('Normal'), 1);
|
73 |
+
new OnOff($rowStyle, 'google-style-400italic', n2_('Normal') . ' ' . n2_x('Italic', "Font style"), 0);
|
74 |
+
new OnOff($rowStyle, 'google-style-500', '500', 0);
|
75 |
+
new OnOff($rowStyle, 'google-style-500italic', '500 ' . n2_x('Italic', "Font style"), 0);
|
76 |
+
new OnOff($rowStyle, 'google-style-600', '600', 0);
|
77 |
+
new OnOff($rowStyle, 'google-style-600italic', '600 ' . n2_x('Italic', "Font style"), 0);
|
78 |
+
new OnOff($rowStyle, 'google-style-700', '700', 0);
|
79 |
+
new OnOff($rowStyle, 'google-style-700italic', '700 ' . n2_x('Italic', "Font style"), 0);
|
80 |
+
new OnOff($rowStyle, 'google-style-800', '800', 0);
|
81 |
+
new OnOff($rowStyle, 'google-style-800italic', '800 ' . n2_x('Italic', "Font style"), 0);
|
82 |
+
new OnOff($rowStyle, 'google-style-900', '900', 0);
|
83 |
+
new OnOff($rowStyle, 'google-style-900italic', '900 ' . n2_x('Italic', "Font style"), 0);
|
84 |
+
|
85 |
+
|
86 |
+
$rowGroupCharacterSet = new ContainerRowGroup($container, 'fonts-google-character-set', n2_('Character set'));
|
87 |
+
$rowCharacterSet = $rowGroupCharacterSet->createRow('fonts-google-character-set');
|
88 |
+
new OnOff($rowCharacterSet, 'google-set-latin', n2_x('Latin', "Character set"), 1);
|
89 |
+
new OnOff($rowCharacterSet, 'google-set-latin-ext', n2_x('Latin Extended', "Character set"), 0);
|
90 |
+
new OnOff($rowCharacterSet, 'google-set-greek', n2_x('Greek', "Character set"), 0);
|
91 |
+
new OnOff($rowCharacterSet, 'google-set-greek-ext', n2_x('Greek Extended', "Character set"), 0);
|
92 |
+
new OnOff($rowCharacterSet, 'google-set-cyrillic', n2_x('Cyrillic', "Character set"), 0);
|
93 |
+
new OnOff($rowCharacterSet, 'google-set-devanagari', n2_x('Devanagari', "Character set"), 0);
|
94 |
+
new OnOff($rowCharacterSet, 'google-set-arabic', n2_x('Arabic', "Character set"), 0);
|
95 |
+
new OnOff($rowCharacterSet, 'google-set-khmer', n2_x('Khmer', "Character set"), 0);
|
96 |
+
new OnOff($rowCharacterSet, 'google-set-telugu', n2_x('Telugu', "Character set"), 0);
|
97 |
+
new OnOff($rowCharacterSet, 'google-set-vietnamese', n2_x('Vietnamese', "Character set"), 0);
|
98 |
+
}
|
99 |
+
|
100 |
+
public static function getDefaults() {
|
101 |
+
$defaults = array();
|
102 |
+
$fontsSets = explode(',', n2_x('latin', 'Default font sets'));
|
103 |
+
for ($i = 0; $i < count($fontsSets); $i++) {
|
104 |
+
$fontsSets[$i] = 'google-set-' . $fontsSets[$i];
|
105 |
+
}
|
106 |
+
$defaults += array_fill_keys($fontsSets, 1);
|
107 |
+
|
108 |
+
return $defaults;
|
109 |
+
}
|
110 |
+
|
111 |
+
public function getPath() {
|
112 |
+
return dirname(__FILE__) . DIRECTORY_SEPARATOR . 'google' . DIRECTORY_SEPARATOR;
|
113 |
+
}
|
114 |
+
|
115 |
+
public function onFontManagerLoad($force = false) {
|
116 |
+
static $loaded;
|
117 |
+
if (!$loaded || $force) {
|
118 |
+
$loaded = true;
|
119 |
+
$parameters = FontSettings::getPluginsData();
|
120 |
+
|
121 |
+
$parameters->fillDefault(self::getDefaults());
|
122 |
+
|
123 |
+
if ((!Platform::isAdmin() && $parameters->get('google-enabled', 1)) || (Platform::isAdmin() && $parameters->get('google-enabled-backend', 1))) {
|
124 |
+
Google::$enabled = 1;
|
125 |
+
|
126 |
+
for ($i = 100; $i < 1000; $i += 100) {
|
127 |
+
$this->addStyle($parameters, $i);
|
128 |
+
$this->addStyle($parameters, $i . 'italic');
|
129 |
+
}
|
130 |
+
if (empty(self::$styles)) {
|
131 |
+
self::$styles[] = '300';
|
132 |
+
self::$styles[] = '400';
|
133 |
+
}
|
134 |
+
|
135 |
+
$this->addSubset($parameters, 'latin');
|
136 |
+
$this->addSubset($parameters, 'latin-ext');
|
137 |
+
$this->addSubset($parameters, 'greek');
|
138 |
+
$this->addSubset($parameters, 'greek-ext');
|
139 |
+
$this->addSubset($parameters, 'cyrillic');
|
140 |
+
$this->addSubset($parameters, 'devanagari');
|
141 |
+
$this->addSubset($parameters, 'arabic');
|
142 |
+
$this->addSubset($parameters, 'khmer');
|
143 |
+
$this->addSubset($parameters, 'telugu');
|
144 |
+
$this->addSubset($parameters, 'vietnamese');
|
145 |
+
if (empty(self::$subsets)) {
|
146 |
+
self::$subsets[] = 'latin';
|
147 |
+
}
|
148 |
+
foreach (self::$subsets as $subset) {
|
149 |
+
Google::addSubset($subset);
|
150 |
+
}
|
151 |
+
Plugin::addAction('fontFamily', array(
|
152 |
+
$this,
|
153 |
+
'onFontFamily'
|
154 |
+
));
|
155 |
+
}
|
156 |
+
}
|
157 |
+
}
|
158 |
+
|
159 |
+
public function onFontManagerLoadBackend() {
|
160 |
+
$parameters = FontSettings::getPluginsData();
|
161 |
+
|
162 |
+
$parameters->fillDefault(self::getDefaults());
|
163 |
+
|
164 |
+
if ($parameters->get('google-enabled-backend', 1)) {
|
165 |
+
Js::addInline('new N2Classes.NextendFontServiceGoogle("' . implode(',', self::$styles) . '","' . implode(',', self::$subsets) . '", ' . json_encode(self::$fonts) . ', ' . json_encode(AssetManager::$googleFonts->getLoadedFamilies()) . ');');
|
166 |
+
}
|
167 |
+
}
|
168 |
+
|
169 |
+
function addStyle($parameters, $weight) {
|
170 |
+
if ($parameters->get('google-style-' . $weight, 0)) {
|
171 |
+
self::$styles[] = $weight;
|
172 |
+
}
|
173 |
+
}
|
174 |
+
|
175 |
+
function addSubset($parameters, $subset) {
|
176 |
+
if ($parameters->get('google-set-' . $subset, 0)) {
|
177 |
+
self::$subsets[] = $subset;
|
178 |
+
}
|
179 |
+
}
|
180 |
+
|
181 |
+
function onFontFamily($family) {
|
182 |
+
$familyLower = strtolower($family);
|
183 |
+
if (isset(self::$fonts[$familyLower])) {
|
184 |
+
foreach (self::$styles as $style) {
|
185 |
+
Google::addFont(self::$fonts[$familyLower], $style);
|
186 |
+
}
|
187 |
+
|
188 |
+
return self::$fonts[$familyLower];
|
189 |
+
}
|
190 |
+
|
191 |
+
return $family;
|
192 |
+
}
|
193 |
+
}
|
194 |
+
|
195 |
+
FontSources::registerSource(GoogleFonts::class);
|
{nextend/library/applications/system/plugins/nextendfontservices/google → Nextend/Framework/Font/Sources/GoogleFonts}/families.csv
RENAMED
File without changes
|
Nextend/Framework/Form/AbstractContainer.php
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
|
7 |
+
abstract class AbstractContainer implements ContainerContainedInterface {
|
8 |
+
|
9 |
+
use TraitContainer;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var ContainerContainedInterface
|
13 |
+
*/
|
14 |
+
protected $first, $last;
|
15 |
+
|
16 |
+
protected $controlName = '';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var ContainerInterface;
|
20 |
+
*/
|
21 |
+
private $previous, $next;
|
22 |
+
|
23 |
+
public function getPrevious() {
|
24 |
+
return $this->previous;
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @param ContainedInterface|null $element
|
29 |
+
*/
|
30 |
+
public function setPrevious($element = null) {
|
31 |
+
$this->previous = $element;
|
32 |
+
}
|
33 |
+
|
34 |
+
public function getNext() {
|
35 |
+
return $this->next;
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @param ContainedInterface|null $element
|
40 |
+
*/
|
41 |
+
public function setNext($element = null) {
|
42 |
+
$this->next = $element;
|
43 |
+
if ($element) {
|
44 |
+
$element->setPrevious($this);
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
public function remove() {
|
49 |
+
$this->getParent()
|
50 |
+
->removeElement($this);
|
51 |
+
}
|
52 |
+
|
53 |
+
public function render() {
|
54 |
+
$this->renderContainer();
|
55 |
+
}
|
56 |
+
|
57 |
+
public function renderContainer() {
|
58 |
+
$element = $this->first;
|
59 |
+
while ($element) {
|
60 |
+
$element->renderContainer();
|
61 |
+
$element = $element->getNext();
|
62 |
+
}
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* @return string
|
67 |
+
*/
|
68 |
+
public function getControlName() {
|
69 |
+
return $this->controlName;
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* @param string $controlName
|
74 |
+
*/
|
75 |
+
public function setControlName($controlName) {
|
76 |
+
$this->controlName = $controlName;
|
77 |
+
}
|
78 |
+
}
|
Nextend/Framework/Form/AbstractField.php
ADDED
@@ -0,0 +1,377 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Insert\AbstractInsert;
|
9 |
+
use Nextend\Framework\View\Html;
|
10 |
+
|
11 |
+
abstract class AbstractField implements ContainedInterface {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var AbstractField;
|
15 |
+
*/
|
16 |
+
private $previous, $next;
|
17 |
+
|
18 |
+
public function getPrevious() {
|
19 |
+
return $this->previous;
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @param AbstractField|null $element
|
24 |
+
*/
|
25 |
+
public function setPrevious($element = null) {
|
26 |
+
$this->previous = $element;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function getNext() {
|
30 |
+
return $this->next;
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* @param AbstractField|null $element
|
35 |
+
*/
|
36 |
+
public function setNext($element = null) {
|
37 |
+
$this->next = $element;
|
38 |
+
if ($element) {
|
39 |
+
$element->setPrevious($this);
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
public function remove() {
|
44 |
+
$this->getParent()
|
45 |
+
->removeElement($this);
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @var TraitFieldset
|
50 |
+
*/
|
51 |
+
protected $parent;
|
52 |
+
|
53 |
+
protected $name = '';
|
54 |
+
|
55 |
+
protected $label = '';
|
56 |
+
|
57 |
+
protected $controlName = '';
|
58 |
+
|
59 |
+
protected $defaultValue;
|
60 |
+
|
61 |
+
protected $fieldID;
|
62 |
+
|
63 |
+
private $exposeName = true;
|
64 |
+
|
65 |
+
protected $tip = '';
|
66 |
+
|
67 |
+
protected $tipLabel = '';
|
68 |
+
|
69 |
+
protected $tipDescription = '';
|
70 |
+
|
71 |
+
protected $tipLink = '';
|
72 |
+
|
73 |
+
protected $rowClass = '';
|
74 |
+
|
75 |
+
protected $rowAttributes = array();
|
76 |
+
|
77 |
+
protected $class = '';
|
78 |
+
|
79 |
+
protected $style = '';
|
80 |
+
|
81 |
+
protected $post = '';
|
82 |
+
|
83 |
+
protected $relatedFields = array();
|
84 |
+
|
85 |
+
protected $relatedFieldsOff = array();
|
86 |
+
|
87 |
+
/**
|
88 |
+
* AbstractField constructor.
|
89 |
+
*
|
90 |
+
* @param TraitFieldset|AbstractInsert $insertAt
|
91 |
+
* @param string $name
|
92 |
+
* @param string $label
|
93 |
+
* @param string $default
|
94 |
+
* @param array $parameters
|
95 |
+
*/
|
96 |
+
public function __construct($insertAt, $name = '', $label = '', $default = '', $parameters = array()) {
|
97 |
+
|
98 |
+
$this->name = $name;
|
99 |
+
$this->label = $label;
|
100 |
+
|
101 |
+
if ($insertAt instanceof ContainerInterface) {
|
102 |
+
$this->parent = $insertAt;
|
103 |
+
$this->parent->addElement($this);
|
104 |
+
} else if ($insertAt instanceof AbstractInsert) {
|
105 |
+
$this->parent = $insertAt->insert($this);
|
106 |
+
}
|
107 |
+
|
108 |
+
$this->controlName = $this->parent->getControlName();
|
109 |
+
|
110 |
+
$this->fieldID = $this->generateId($this->controlName . $this->name);
|
111 |
+
|
112 |
+
$this->defaultValue = $default;
|
113 |
+
|
114 |
+
foreach ($parameters AS $option => $value) {
|
115 |
+
$option = 'set' . $option;
|
116 |
+
$this->{$option}($value);
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* @return string
|
122 |
+
*/
|
123 |
+
public function getID() {
|
124 |
+
return $this->fieldID;
|
125 |
+
}
|
126 |
+
|
127 |
+
public function setDefaultValue($defaultValue) {
|
128 |
+
$this->defaultValue = $defaultValue;
|
129 |
+
}
|
130 |
+
|
131 |
+
public function setExposeName($exposeName) {
|
132 |
+
$this->exposeName = $exposeName;
|
133 |
+
}
|
134 |
+
|
135 |
+
public function getPost() {
|
136 |
+
return $this->post;
|
137 |
+
}
|
138 |
+
|
139 |
+
public function setPost($post) {
|
140 |
+
$this->post = $post;
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* @param string $tip
|
145 |
+
*/
|
146 |
+
public function setTip($tip) {
|
147 |
+
$this->tip = $tip;
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* @param string $tipLabel
|
152 |
+
*/
|
153 |
+
public function setTipLabel($tipLabel) {
|
154 |
+
$this->tipLabel = $tipLabel;
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* @param string $tipDescription
|
159 |
+
*/
|
160 |
+
public function setTipDescription($tipDescription) {
|
161 |
+
$this->tipDescription = $tipDescription;
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* @param string $tipLink
|
166 |
+
*/
|
167 |
+
public function setTipLink($tipLink) {
|
168 |
+
$this->tipLink = $tipLink;
|
169 |
+
}
|
170 |
+
|
171 |
+
public function setRowClass($rowClass) {
|
172 |
+
$this->rowClass .= $rowClass;
|
173 |
+
}
|
174 |
+
|
175 |
+
public function getRowClass() {
|
176 |
+
return $this->rowClass;
|
177 |
+
}
|
178 |
+
|
179 |
+
public function getClass() {
|
180 |
+
return $this->class;
|
181 |
+
}
|
182 |
+
|
183 |
+
public function setClass($class) {
|
184 |
+
$this->class = $class;
|
185 |
+
}
|
186 |
+
|
187 |
+
protected function getFieldName() {
|
188 |
+
if ($this->exposeName) {
|
189 |
+
return $this->controlName . '[' . $this->name . ']';
|
190 |
+
}
|
191 |
+
|
192 |
+
return '';
|
193 |
+
}
|
194 |
+
|
195 |
+
public function render() {
|
196 |
+
|
197 |
+
return array(
|
198 |
+
$this->fetchTooltip(),
|
199 |
+
$this->fetchElement()
|
200 |
+
);
|
201 |
+
}
|
202 |
+
|
203 |
+
public function displayLabel() {
|
204 |
+
|
205 |
+
echo $this->fetchTooltip();
|
206 |
+
}
|
207 |
+
|
208 |
+
public function displayElement() {
|
209 |
+
|
210 |
+
echo $this->fetchElement();
|
211 |
+
}
|
212 |
+
|
213 |
+
protected function fetchTooltip() {
|
214 |
+
|
215 |
+
if ($this->label === false || $this->label === '') {
|
216 |
+
return '';
|
217 |
+
}
|
218 |
+
|
219 |
+
$attributes = array(
|
220 |
+
'for' => $this->fieldID
|
221 |
+
);
|
222 |
+
|
223 |
+
|
224 |
+
$post = '';
|
225 |
+
if (!empty($this->tipDescription)) {
|
226 |
+
$tipAttributes = array(
|
227 |
+
'class' => 'ssi_16 ssi_16--info',
|
228 |
+
'data-tip-description' => $this->tipDescription
|
229 |
+
);
|
230 |
+
if (!empty($this->tipLabel)) {
|
231 |
+
$tipAttributes['data-tip-label'] = $this->tipLabel;
|
232 |
+
}
|
233 |
+
if (!empty($this->tipLink)) {
|
234 |
+
$tipAttributes['data-tip-link'] = $this->tipLink;
|
235 |
+
}
|
236 |
+
$post .= Html::tag('i', $tipAttributes);
|
237 |
+
}
|
238 |
+
|
239 |
+
return Html::tag('label', $attributes, $this->label) . $post;
|
240 |
+
}
|
241 |
+
|
242 |
+
protected function fetchNoTooltip() {
|
243 |
+
return "";
|
244 |
+
}
|
245 |
+
|
246 |
+
/**
|
247 |
+
* @return string
|
248 |
+
*/
|
249 |
+
abstract protected function fetchElement();
|
250 |
+
|
251 |
+
public function getValue() {
|
252 |
+
return $this->getForm()
|
253 |
+
->get($this->name, $this->defaultValue);
|
254 |
+
}
|
255 |
+
|
256 |
+
public function setValue($value) {
|
257 |
+
$this->parent->getForm()
|
258 |
+
->set($this->name, $value);
|
259 |
+
}
|
260 |
+
|
261 |
+
/**
|
262 |
+
* @param array $rowAttributes
|
263 |
+
*/
|
264 |
+
public function setRowAttributes($rowAttributes) {
|
265 |
+
$this->rowAttributes = $rowAttributes;
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* @return array
|
270 |
+
*/
|
271 |
+
public function getRowAttributes() {
|
272 |
+
return $this->rowAttributes;
|
273 |
+
}
|
274 |
+
|
275 |
+
public function setStyle($style) {
|
276 |
+
$this->style = $style;
|
277 |
+
}
|
278 |
+
|
279 |
+
protected function getStyle() {
|
280 |
+
return $this->style;
|
281 |
+
}
|
282 |
+
|
283 |
+
/**
|
284 |
+
* @param string $relatedFields
|
285 |
+
*/
|
286 |
+
public function setRelatedFields($relatedFields) {
|
287 |
+
$this->relatedFields = $relatedFields;
|
288 |
+
}
|
289 |
+
|
290 |
+
public function setRelatedFieldsOff($relatedFieldsOff) {
|
291 |
+
$this->relatedFieldsOff = $relatedFieldsOff;
|
292 |
+
}
|
293 |
+
|
294 |
+
protected function renderRelatedFields() {
|
295 |
+
if (!empty($this->relatedFields) || !empty($this->relatedFieldsOff)) {
|
296 |
+
$options = array(
|
297 |
+
'relatedFieldsOn' => $this->relatedFields,
|
298 |
+
'relatedFieldsOff' => $this->relatedFieldsOff
|
299 |
+
);
|
300 |
+
Js::addInline('new N2Classes.FormRelatedFields("' . $this->fieldID . '", ' . json_encode($options) . ');');
|
301 |
+
}
|
302 |
+
}
|
303 |
+
|
304 |
+
/**
|
305 |
+
* @param $name
|
306 |
+
*
|
307 |
+
* @return string
|
308 |
+
*/
|
309 |
+
protected function generateId($name) {
|
310 |
+
|
311 |
+
return str_replace(array(
|
312 |
+
'[',
|
313 |
+
']',
|
314 |
+
' '
|
315 |
+
), array(
|
316 |
+
'',
|
317 |
+
'',
|
318 |
+
''
|
319 |
+
), $name);
|
320 |
+
}
|
321 |
+
|
322 |
+
public function getLabelClass() {
|
323 |
+
if ($this->label === false) {
|
324 |
+
return 'n2_field--label-none';
|
325 |
+
} else if ($this->label === '') {
|
326 |
+
return 'n2_field--label-placeholder';
|
327 |
+
}
|
328 |
+
|
329 |
+
return '';
|
330 |
+
}
|
331 |
+
|
332 |
+
/**
|
333 |
+
* @return bool
|
334 |
+
*/
|
335 |
+
public function hasLabel() {
|
336 |
+
return !empty($this->label);
|
337 |
+
}
|
338 |
+
|
339 |
+
/**
|
340 |
+
* @return string
|
341 |
+
*/
|
342 |
+
public function getName() {
|
343 |
+
return $this->name;
|
344 |
+
}
|
345 |
+
|
346 |
+
/**
|
347 |
+
* @return Form
|
348 |
+
*/
|
349 |
+
public function getForm() {
|
350 |
+
return $this->parent->getForm();
|
351 |
+
}
|
352 |
+
|
353 |
+
/**
|
354 |
+
* @return string
|
355 |
+
*/
|
356 |
+
public function getControlName() {
|
357 |
+
return $this->controlName;
|
358 |
+
}
|
359 |
+
|
360 |
+
/**
|
361 |
+
* @param string $controlName
|
362 |
+
*/
|
363 |
+
public function setControlName($controlName) {
|
364 |
+
$this->controlName = $controlName;
|
365 |
+
}
|
366 |
+
|
367 |
+
/**
|
368 |
+
* @return TraitFieldset
|
369 |
+
*/
|
370 |
+
public function getParent() {
|
371 |
+
return $this->parent;
|
372 |
+
}
|
373 |
+
|
374 |
+
public function getPath() {
|
375 |
+
return $this->parent->getPath() . '/' . $this->name;
|
376 |
+
}
|
377 |
+
}
|
Nextend/Framework/Form/AbstractFieldset.php
ADDED
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
use Nextend\Framework\Form\Insert\AbstractInsert;
|
7 |
+
|
8 |
+
abstract class AbstractFieldset implements ContainerContainedInterface {
|
9 |
+
|
10 |
+
use TraitFieldset;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var ContainedInterface;
|
14 |
+
*/
|
15 |
+
private $previous, $next;
|
16 |
+
|
17 |
+
public function getPrevious() {
|
18 |
+
return $this->previous;
|
19 |
+
}
|
20 |
+
|
21 |
+
public function setPrevious($element = null) {
|
22 |
+
$this->previous = $element;
|
23 |
+
}
|
24 |
+
|
25 |
+
public function getNext() {
|
26 |
+
return $this->next;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function setNext($element = null) {
|
30 |
+
$this->next = $element;
|
31 |
+
if ($element) {
|
32 |
+
$element->setPrevious($this);
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
public function remove() {
|
37 |
+
$this->getParent()
|
38 |
+
->removeElement($this);
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @var ContainerInterface
|
43 |
+
*/
|
44 |
+
protected $parent;
|
45 |
+
|
46 |
+
protected $name = '';
|
47 |
+
|
48 |
+
protected $label = '';
|
49 |
+
|
50 |
+
protected $controlName = '';
|
51 |
+
|
52 |
+
protected $class = '';
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Container constructor.
|
56 |
+
*
|
57 |
+
* @param ContainerInterface|AbstractInsert $insertAt
|
58 |
+
* @param $name
|
59 |
+
* @param boolean|string $label
|
60 |
+
* @param array $parameters
|
61 |
+
*/
|
62 |
+
public function __construct($insertAt, $name, $label = false, $parameters = array()) {
|
63 |
+
|
64 |
+
$this->name = $name;
|
65 |
+
$this->label = $label;
|
66 |
+
|
67 |
+
if ($insertAt instanceof ContainerInterface) {
|
68 |
+
$this->parent = $insertAt;
|
69 |
+
$this->parent->addElement($this);
|
70 |
+
} else if ($insertAt instanceof AbstractInsert) {
|
71 |
+
$this->parent = $insertAt->insert($this);
|
72 |
+
}
|
73 |
+
|
74 |
+
$this->controlName = $this->parent->getControlName();
|
75 |
+
|
76 |
+
foreach ($parameters AS $option => $value) {
|
77 |
+
$option = 'set' . $option;
|
78 |
+
$this->{$option}($value);
|
79 |
+
}
|
80 |
+
|
81 |
+
}
|
82 |
+
|
83 |
+
public function render() {
|
84 |
+
$this->renderContainer();
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* @param AbstractField $element
|
89 |
+
*
|
90 |
+
* @return string
|
91 |
+
*/
|
92 |
+
public function decorateElement($element) {
|
93 |
+
|
94 |
+
ob_start();
|
95 |
+
|
96 |
+
$element->displayElement();
|
97 |
+
|
98 |
+
return ob_get_clean();
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* @return bool
|
103 |
+
*/
|
104 |
+
public function hasLabel() {
|
105 |
+
return !empty($this->label);
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* @return string
|
110 |
+
*/
|
111 |
+
public function getName() {
|
112 |
+
return $this->name;
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* @return Form
|
117 |
+
*/
|
118 |
+
public function getForm() {
|
119 |
+
return $this->parent->getForm();
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* @return string
|
124 |
+
*/
|
125 |
+
public function getControlName() {
|
126 |
+
return $this->controlName;
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* @param string $controlName
|
131 |
+
*/
|
132 |
+
public function setControlName($controlName) {
|
133 |
+
$this->controlName = $controlName;
|
134 |
+
}
|
135 |
+
|
136 |
+
public function hasFields() {
|
137 |
+
|
138 |
+
return !empty($this->flattenElements);
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* @param string $class
|
143 |
+
*/
|
144 |
+
public function setClass($class) {
|
145 |
+
$this->class = $class;
|
146 |
+
}
|
147 |
+
}
|
Nextend/Framework/Form/AbstractFormManager.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
8 |
+
|
9 |
+
abstract class AbstractFormManager {
|
10 |
+
|
11 |
+
use MVCHelperTrait;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* AbstractFormManager constructor.
|
15 |
+
*
|
16 |
+
* @param MVCHelperTrait $MVCHelper
|
17 |
+
*/
|
18 |
+
public function __construct($MVCHelper) {
|
19 |
+
|
20 |
+
$this->setMVCHelper($MVCHelper);
|
21 |
+
}
|
22 |
+
}
|
Nextend/Framework/Form/Base/PlatformFormBase.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Base;
|
5 |
+
|
6 |
+
class PlatformFormBase {
|
7 |
+
|
8 |
+
public function tokenize() {
|
9 |
+
return '';
|
10 |
+
}
|
11 |
+
|
12 |
+
public function tokenizeUrl() {
|
13 |
+
return '';
|
14 |
+
}
|
15 |
+
|
16 |
+
public function checkToken() {
|
17 |
+
return true;
|
18 |
+
}
|
19 |
+
}
|
Nextend/Framework/Form/ContainedInterface.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
|
7 |
+
interface ContainedInterface {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @return ContainedInterface|null
|
11 |
+
*/
|
12 |
+
public function getPrevious();
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @param ContainedInterface|null $element
|
16 |
+
*/
|
17 |
+
public function setPrevious($element = null);
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @return ContainedInterface|null
|
21 |
+
*/
|
22 |
+
public function getNext();
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @param ContainedInterface|null $element
|
26 |
+
*/
|
27 |
+
public function setNext($element = null);
|
28 |
+
|
29 |
+
public function remove();
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @return ContainerInterface
|
33 |
+
*/
|
34 |
+
public function getParent();
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @return string
|
38 |
+
*/
|
39 |
+
public function getPath();
|
40 |
+
|
41 |
+
public function render();
|
42 |
+
}
|
Nextend/Framework/Form/Container/ContainerAlternative.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Container;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\ContainerGeneral;
|
8 |
+
|
9 |
+
class ContainerAlternative extends ContainerGeneral {
|
10 |
+
|
11 |
+
public function renderContainer() {
|
12 |
+
|
13 |
+
}
|
14 |
+
}
|
Nextend/Framework/Form/Container/ContainerRowGroup.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Container;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\ContainerGeneral;
|
8 |
+
use Nextend\Framework\Form\Fieldset\FieldsetRow;
|
9 |
+
|
10 |
+
class ContainerRowGroup extends ContainerGeneral {
|
11 |
+
|
12 |
+
public function renderContainer() {
|
13 |
+
echo '<div class="n2_form__table_row_group" data-field="table-row-group-' . $this->name . '">';
|
14 |
+
if ($this->label !== false) {
|
15 |
+
echo '<div class="n2_form__table_row_group_label">';
|
16 |
+
echo $this->label;
|
17 |
+
echo '</div>';
|
18 |
+
}
|
19 |
+
|
20 |
+
echo '<div class="n2_form__table_row_group_rows" data-field="table-row-group-rows-' . $this->name . '">';
|
21 |
+
parent::renderContainer();
|
22 |
+
echo '</div>';
|
23 |
+
echo '</div>';
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @param $name
|
28 |
+
*
|
29 |
+
* @return FieldsetRow
|
30 |
+
*/
|
31 |
+
public function createRow($name) {
|
32 |
+
|
33 |
+
return new FieldsetRow($this, $name);
|
34 |
+
}
|
35 |
+
}
|
Nextend/Framework/Form/Container/ContainerSubform.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Container;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\ContainerGeneral;
|
8 |
+
|
9 |
+
class ContainerSubform extends ContainerGeneral {
|
10 |
+
|
11 |
+
public function renderContainer() {
|
12 |
+
echo '<div id="' . $this->getId() . '" class="n2_form__subform">';
|
13 |
+
parent::renderContainer();
|
14 |
+
echo '</div>';
|
15 |
+
}
|
16 |
+
|
17 |
+
public function getId() {
|
18 |
+
return 'n2_form__subform_' . $this->controlName . '_' . $this->name;
|
19 |
+
}
|
20 |
+
}
|
Nextend/Framework/Form/Container/ContainerTab.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Container;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\ContainerGeneral;
|
8 |
+
|
9 |
+
class ContainerTab extends ContainerGeneral {
|
10 |
+
|
11 |
+
public function renderContainer() {
|
12 |
+
echo '<div class="n2_form__tab" data-related-form="' . $this->getForm()
|
13 |
+
->getId() . '" data-tab="' . $this->getId() . '">';
|
14 |
+
parent::renderContainer();
|
15 |
+
echo '</div>';
|
16 |
+
}
|
17 |
+
|
18 |
+
public function getId() {
|
19 |
+
return 'n2_form__tab_' . $this->controlName . '_' . $this->name;
|
20 |
+
}
|
21 |
+
}
|
Nextend/Framework/Form/Container/ContainerTable.php
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Container;
|
5 |
+
|
6 |
+
use Nextend\Framework\Form\ContainerGeneral;
|
7 |
+
use Nextend\Framework\Form\Fieldset\FieldsetRow;
|
8 |
+
use Nextend\Framework\Form\Fieldset\FieldsetTableLabel;
|
9 |
+
|
10 |
+
class ContainerTable extends ContainerGeneral {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var FieldsetTableLabel
|
14 |
+
*/
|
15 |
+
protected $fieldsetLabel;
|
16 |
+
|
17 |
+
protected $fieldsetLabelPosition = 'start';
|
18 |
+
|
19 |
+
public function __construct($insertAt, $name, $label = false, $parameters = array()) {
|
20 |
+
parent::__construct($insertAt, $name, $label, $parameters);
|
21 |
+
|
22 |
+
$labelContainer = new ContainerAlternative($this, $name . '-container-label');
|
23 |
+
$this->fieldsetLabel = new FieldsetTableLabel($labelContainer, $name . '-label', false);
|
24 |
+
}
|
25 |
+
|
26 |
+
public function renderContainer() {
|
27 |
+
echo '<div class="n2_form__table" data-field="table-' . $this->name . '">';
|
28 |
+
echo '<div class="n2_form__table_label">';
|
29 |
+
echo '<div class="n2_form__table_label_title">';
|
30 |
+
echo $this->label;
|
31 |
+
echo '</div>';
|
32 |
+
if ($this->fieldsetLabel->hasFields()) {
|
33 |
+
echo '<div class="n2_form__table_label_fields n2_form__table_label_fields--' . $this->fieldsetLabelPosition . '">';
|
34 |
+
$this->fieldsetLabel->renderContainer();
|
35 |
+
echo '</div>';
|
36 |
+
}
|
37 |
+
echo '</div>';
|
38 |
+
|
39 |
+
if ($this->first) {
|
40 |
+
echo '<div class="n2_form__table_rows" data-field="table-rows-' . $this->name . '">';
|
41 |
+
parent::renderContainer();
|
42 |
+
echo '</div>';
|
43 |
+
}
|
44 |
+
echo '</div>';
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* @param $name
|
49 |
+
*
|
50 |
+
* @return FieldsetRow
|
51 |
+
*/
|
52 |
+
public function createRow($name) {
|
53 |
+
|
54 |
+
return new FieldsetRow($this, $name);
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* @param $name
|
59 |
+
* @param string $label
|
60 |
+
*
|
61 |
+
* @return ContainerRowGroup
|
62 |
+
*/
|
63 |
+
public function createRowGroup($name, $label) {
|
64 |
+
|
65 |
+
return new ContainerRowGroup($this, $name, $label);
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @return FieldsetTableLabel
|
70 |
+
*/
|
71 |
+
public function getFieldsetLabel() {
|
72 |
+
return $this->fieldsetLabel;
|
73 |
+
}
|
74 |
+
|
75 |
+
public function setFieldsetPositionEnd() {
|
76 |
+
$this->fieldsetLabelPosition = 'end';
|
77 |
+
}
|
78 |
+
|
79 |
+
}
|
Nextend/Framework/Form/Container/LayerWindow/ContainerAnimation.php
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Container\LayerWindow;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\ContainerGeneral;
|
8 |
+
|
9 |
+
class ContainerAnimation extends ContainerGeneral {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @param $name
|
13 |
+
* @param $label
|
14 |
+
*
|
15 |
+
* @return ContainerAnimationTab
|
16 |
+
*/
|
17 |
+
public function createTab($name, $label) {
|
18 |
+
return new ContainerAnimationTab($this, $name, $label);
|
19 |
+
}
|
20 |
+
|
21 |
+
public function renderContainer() {
|
22 |
+
echo '<div class="n2_container_animation" data-field="animation-' . $this->name . '">';
|
23 |
+
echo '<div class="n2_container_animation__buttons">';
|
24 |
+
|
25 |
+
$element = $this->first;
|
26 |
+
while ($element) {
|
27 |
+
|
28 |
+
if ($element instanceof ContainerAnimationTab) {
|
29 |
+
echo '<div class="n2_container_animation__button" data-related-tab="' . $element->getName() . '">' . $element->getLabel() . '</div>';
|
30 |
+
}
|
31 |
+
|
32 |
+
$element = $element->getNext();
|
33 |
+
}
|
34 |
+
|
35 |
+
echo '</div>';
|
36 |
+
echo '<div class="n2_container_animation__tabs">';
|
37 |
+
parent::renderContainer();
|
38 |
+
echo '</div>';
|
39 |
+
echo '</div>';
|
40 |
+
}
|
41 |
+
}
|
Nextend/Framework/Form/Container/LayerWindow/ContainerAnimationTab.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Container\LayerWindow;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\ContainerGeneral;
|
8 |
+
|
9 |
+
class ContainerAnimationTab extends ContainerGeneral {
|
10 |
+
|
11 |
+
public function renderContainer() {
|
12 |
+
echo '<div class="n2_container_animation__tab" data-tab="' . $this->name . '">';
|
13 |
+
parent::renderContainer();
|
14 |
+
echo '</div>';
|
15 |
+
}
|
16 |
+
}
|
Nextend/Framework/Form/Container/LayerWindow/ContainerDesign.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Container\LayerWindow;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\ContainerGeneral;
|
9 |
+
use Nextend\Framework\Form\ContainerInterface;
|
10 |
+
use Nextend\Framework\View\Html;
|
11 |
+
|
12 |
+
class ContainerDesign extends ContainerGeneral {
|
13 |
+
|
14 |
+
public function __construct(ContainerInterface $insertAt, $name) {
|
15 |
+
parent::__construct($insertAt, $name);
|
16 |
+
}
|
17 |
+
|
18 |
+
public function renderContainer() {
|
19 |
+
|
20 |
+
$id = 'n2_css_' . $this->name;
|
21 |
+
|
22 |
+
echo Html::openTag('div', array(
|
23 |
+
'id' => $id,
|
24 |
+
'class' => 'n2_ss_design_' . $this->name
|
25 |
+
));
|
26 |
+
|
27 |
+
$element = $this->first;
|
28 |
+
while ($element) {
|
29 |
+
$element->renderContainer();
|
30 |
+
$element = $element->getNext();
|
31 |
+
}
|
32 |
+
|
33 |
+
echo Html::closeTag('div');
|
34 |
+
|
35 |
+
$options = array(
|
36 |
+
'ajaxUrl' => $this->getForm()
|
37 |
+
->createAjaxUrl('css/index')
|
38 |
+
);
|
39 |
+
|
40 |
+
Js::addInline('new N2Classes.BasicCSS(' . json_encode($id) . ', ' . json_encode($options) . ');');
|
41 |
+
}
|
42 |
+
}
|
Nextend/Framework/Form/Container/LayerWindow/ContainerSettings.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Container\LayerWindow;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\ContainerGeneral;
|
8 |
+
use Nextend\Framework\Form\ContainerInterface;
|
9 |
+
|
10 |
+
class ContainerSettings extends ContainerGeneral {
|
11 |
+
|
12 |
+
public function __construct(ContainerInterface $insertAt, $name, $parameters = array()) {
|
13 |
+
parent::__construct($insertAt, $name, false, $parameters);
|
14 |
+
}
|
15 |
+
|
16 |
+
public function renderContainer() {
|
17 |
+
echo '<div class="n2_ss_layer_window__tab_panel" data-panel="' . $this->name . '">';
|
18 |
+
parent::renderContainer();
|
19 |
+
echo '</div>';
|
20 |
+
}
|
21 |
+
}
|
Nextend/Framework/Form/ContainerContainedInterface.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
|
7 |
+
interface ContainerContainedInterface extends ContainerInterface, ContainedInterface {
|
8 |
+
|
9 |
+
}
|
Nextend/Framework/Form/ContainerGeneral.php
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form;
|
4 |
+
|
5 |
+
use Nextend\Framework\Form\Insert\AbstractInsert;
|
6 |
+
|
7 |
+
class ContainerGeneral extends AbstractContainer {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @var ContainerInterface
|
11 |
+
*/
|
12 |
+
protected $parent;
|
13 |
+
|
14 |
+
protected $name = '';
|
15 |
+
|
16 |
+
protected $label = '';
|
17 |
+
|
18 |
+
protected $class = '';
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Container constructor.
|
22 |
+
*
|
23 |
+
* @param ContainerInterface|AbstractInsert $insertAt
|
24 |
+
* @param string $name
|
25 |
+
* @param boolean|string $label
|
26 |
+
* @param array $parameters
|
27 |
+
*/
|
28 |
+
public function __construct($insertAt, $name, $label = false, $parameters = array()) {
|
29 |
+
|
30 |
+
$this->name = $name;
|
31 |
+
$this->label = $label;
|
32 |
+
|
33 |
+
if ($insertAt instanceof ContainerInterface) {
|
34 |
+
$this->parent = $insertAt;
|
35 |
+
$this->parent->addElement($this);
|
36 |
+
} else if ($insertAt instanceof AbstractInsert) {
|
37 |
+
$this->parent = $insertAt->insert($this);
|
38 |
+
}
|
39 |
+
|
40 |
+
$this->controlName = $this->parent->getControlName();
|
41 |
+
|
42 |
+
foreach ($parameters AS $option => $value) {
|
43 |
+
$option = 'set' . $option;
|
44 |
+
$this->{$option}($value);
|
45 |
+
}
|
46 |
+
|
47 |
+
}
|
48 |
+
|
49 |
+
public function removeElement($element) {
|
50 |
+
$previous = $element->getPrevious();
|
51 |
+
$next = $element->getNext();
|
52 |
+
|
53 |
+
if ($this->first === $element) {
|
54 |
+
$this->first = $next;
|
55 |
+
}
|
56 |
+
|
57 |
+
if ($this->last === $element) {
|
58 |
+
$this->last = $previous;
|
59 |
+
}
|
60 |
+
|
61 |
+
if ($previous) {
|
62 |
+
$previous->setNext($next);
|
63 |
+
} else {
|
64 |
+
$next->setPrevious();
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @return ContainerInterface
|
70 |
+
*/
|
71 |
+
public function getParent() {
|
72 |
+
return $this->parent;
|
73 |
+
}
|
74 |
+
|
75 |
+
public function getPath() {
|
76 |
+
return $this->parent->getPath() . '/' . $this->name;
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* @param string $class
|
81 |
+
*/
|
82 |
+
public function setClass($class) {
|
83 |
+
$this->class = $class;
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* @return bool
|
88 |
+
*/
|
89 |
+
public function hasLabel() {
|
90 |
+
return !empty($this->label);
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* @return string
|
95 |
+
*/
|
96 |
+
public function getLabel() {
|
97 |
+
return $this->label;
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* @return string
|
102 |
+
*/
|
103 |
+
public function getName() {
|
104 |
+
return $this->name;
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* @return Form
|
109 |
+
*/
|
110 |
+
public function getForm() {
|
111 |
+
return $this->parent->getForm();
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* @return string
|
116 |
+
*/
|
117 |
+
public function getControlName() {
|
118 |
+
return $this->controlName;
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* @param string $controlName
|
123 |
+
*/
|
124 |
+
public function setControlName($controlName) {
|
125 |
+
$this->controlName = $controlName;
|
126 |
+
}
|
127 |
+
}
|
Nextend/Framework/Form/ContainerInterface.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
|
7 |
+
interface ContainerInterface {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @param ContainedInterface $element
|
11 |
+
*/
|
12 |
+
public function addElement($element);
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @param ContainedInterface $element
|
16 |
+
* @param ContainedInterface $target
|
17 |
+
*/
|
18 |
+
public function insertElementBefore($element, $target);
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @param ContainedInterface $element
|
22 |
+
* @param ContainedInterface $target
|
23 |
+
*/
|
24 |
+
public function insertElementAfter($element, $target);
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @param ContainedInterface $element
|
28 |
+
*/
|
29 |
+
public function removeElement($element);
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @param $path
|
33 |
+
*
|
34 |
+
* @return ContainedInterface
|
35 |
+
*/
|
36 |
+
public function getElement($path);
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @return string
|
40 |
+
*/
|
41 |
+
public function getPath();
|
42 |
+
|
43 |
+
/**
|
44 |
+
* @return Form
|
45 |
+
*/
|
46 |
+
public function getForm();
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @return string
|
50 |
+
*/
|
51 |
+
public function getName();
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @return string
|
55 |
+
*/
|
56 |
+
public function getControlName();
|
57 |
+
|
58 |
+
public function renderContainer();
|
59 |
+
}
|
Nextend/Framework/Form/ContainerMain.php
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Fieldset\FieldsetHidden;
|
8 |
+
|
9 |
+
class ContainerMain extends AbstractContainer {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var Form
|
13 |
+
*/
|
14 |
+
protected $form;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @var FieldsetHidden
|
18 |
+
*/
|
19 |
+
protected $fieldsetHidden;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* ContainerMain constructor.
|
23 |
+
*
|
24 |
+
* @param Form $form
|
25 |
+
*/
|
26 |
+
public function __construct($form) {
|
27 |
+
$this->form = $form;
|
28 |
+
$this->controlName = $form->getControlName();
|
29 |
+
|
30 |
+
$this->fieldsetHidden = new FieldsetHidden($this);
|
31 |
+
}
|
32 |
+
|
33 |
+
public function removeElement($element) {
|
34 |
+
$previous = $element->getPrevious();
|
35 |
+
$next = $element->getNext();
|
36 |
+
|
37 |
+
if ($this->first === $element) {
|
38 |
+
$this->first = $next;
|
39 |
+
}
|
40 |
+
|
41 |
+
if ($this->last === $element) {
|
42 |
+
$this->last = $previous;
|
43 |
+
}
|
44 |
+
|
45 |
+
if ($previous) {
|
46 |
+
$previous->setNext($next);
|
47 |
+
} else {
|
48 |
+
$next->setPrevious();
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
public function getParent() {
|
53 |
+
return false;
|
54 |
+
}
|
55 |
+
|
56 |
+
public function getPath() {
|
57 |
+
return '';
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @return Form
|
62 |
+
*/
|
63 |
+
public function getForm() {
|
64 |
+
return $this->form;
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* @return string
|
69 |
+
*/
|
70 |
+
public function getName() {
|
71 |
+
return 'ContainerMain';
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* @return FieldsetHidden
|
76 |
+
*/
|
77 |
+
public function getFieldsetHidden() {
|
78 |
+
return $this->fieldsetHidden;
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
*
|
83 |
+
* @return ContainerContainedInterface
|
84 |
+
*/
|
85 |
+
public function getFirst() {
|
86 |
+
return $this->first;
|
87 |
+
}
|
88 |
+
}
|
Nextend/Framework/Form/Element/AbstractChooser.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Localization\Localization;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
abstract class AbstractChooser extends AbstractFieldHidden {
|
11 |
+
|
12 |
+
protected $hasClear = true;
|
13 |
+
|
14 |
+
protected $class = '';
|
15 |
+
|
16 |
+
protected $width;
|
17 |
+
|
18 |
+
abstract protected function addScript();
|
19 |
+
|
20 |
+
protected function fetchElement() {
|
21 |
+
|
22 |
+
$this->addScript();
|
23 |
+
|
24 |
+
$this->renderRelatedFields();
|
25 |
+
|
26 |
+
return Html::tag('div', array(
|
27 |
+
'class' => 'n2_field_chooser ' . $this->class
|
28 |
+
), $this->pre() . parent::fetchElement() . $this->field() . $this->post());
|
29 |
+
}
|
30 |
+
|
31 |
+
protected function pre() {
|
32 |
+
|
33 |
+
}
|
34 |
+
|
35 |
+
protected function field() {
|
36 |
+
$style = '';
|
37 |
+
if ($this->width) {
|
38 |
+
$style = 'width: ' . $this->width . 'px;';
|
39 |
+
}
|
40 |
+
|
41 |
+
return '<div class="n2_field_chooser__label" style="' . $style . '"></div>';
|
42 |
+
}
|
43 |
+
|
44 |
+
protected function post() {
|
45 |
+
|
46 |
+
$html = '';
|
47 |
+
if ($this->hasClear) {
|
48 |
+
$html .= Html::tag('a', array(
|
49 |
+
'href' => '#',
|
50 |
+
'class' => 'n2_field_chooser__clear'
|
51 |
+
), Html::tag('i', array('class' => 'ssi_16 ssi_16--circularremove'), ''));
|
52 |
+
}
|
53 |
+
|
54 |
+
$html .= Html::tag('a', array(
|
55 |
+
'href' => '#',
|
56 |
+
'class' => 'n2_field_chooser__choose'
|
57 |
+
), '<i class="ssi_16 ssi_16--plus"></i>');
|
58 |
+
|
59 |
+
return $html;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @param bool $hasClear
|
64 |
+
*/
|
65 |
+
public function setHasClear($hasClear) {
|
66 |
+
$this->hasClear = $hasClear;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @param int $width
|
71 |
+
*/
|
72 |
+
public function setWidth($width) {
|
73 |
+
$this->width = $width;
|
74 |
+
}
|
75 |
+
}
|
Nextend/Framework/Form/Element/AbstractChooserText.php
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\View\Html;
|
8 |
+
|
9 |
+
abstract class AbstractChooserText extends AbstractFieldHidden {
|
10 |
+
|
11 |
+
protected $hasClear = true;
|
12 |
+
|
13 |
+
protected $width = 130;
|
14 |
+
|
15 |
+
protected $class = '';
|
16 |
+
|
17 |
+
protected $type = 'text';
|
18 |
+
|
19 |
+
abstract protected function addScript();
|
20 |
+
|
21 |
+
protected function fetchElement() {
|
22 |
+
|
23 |
+
$this->addScript();
|
24 |
+
|
25 |
+
$this->renderRelatedFields();
|
26 |
+
|
27 |
+
return Html::tag('div', array(
|
28 |
+
'class' => 'n2_field_text' . $this->class
|
29 |
+
), $this->pre() . $this->field() . $this->post());
|
30 |
+
}
|
31 |
+
|
32 |
+
protected function pre() {
|
33 |
+
|
34 |
+
}
|
35 |
+
|
36 |
+
protected function field() {
|
37 |
+
|
38 |
+
if ($this->type === 'hidden') {
|
39 |
+
return Html::tag('input', array(
|
40 |
+
'type' => 'text',
|
41 |
+
'style' => 'width: ' . $this->width . 'px;',
|
42 |
+
'disabled' => 'disabled'
|
43 |
+
), false);
|
44 |
+
}
|
45 |
+
|
46 |
+
return Html::tag('input', array(
|
47 |
+
'id' => $this->fieldID,
|
48 |
+
'name' => $this->getFieldName(),
|
49 |
+
'value' => $this->getValue(),
|
50 |
+
'type' => $this->type,
|
51 |
+
'style' => 'width: ' . $this->width . 'px;',
|
52 |
+
'autocomplete' => 'off'
|
53 |
+
), false);
|
54 |
+
|
55 |
+
}
|
56 |
+
|
57 |
+
protected function post() {
|
58 |
+
|
59 |
+
$html = '';
|
60 |
+
if ($this->hasClear) {
|
61 |
+
$html .= Html::tag('a', array(
|
62 |
+
'href' => '#',
|
63 |
+
'class' => 'n2_field_text__clear'
|
64 |
+
), Html::tag('i', array('class' => 'ssi_16 ssi_16--circularremove'), ''));
|
65 |
+
}
|
66 |
+
|
67 |
+
$html .= Html::tag('a', array(
|
68 |
+
'href' => '#',
|
69 |
+
'class' => 'n2_field_text__choose'
|
70 |
+
), '<i class="ssi_16 ssi_16--plus"></i>');
|
71 |
+
|
72 |
+
return $html;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* @param bool $hasClear
|
77 |
+
*/
|
78 |
+
public function setHasClear($hasClear) {
|
79 |
+
$this->hasClear = $hasClear;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* @param int $width
|
84 |
+
*/
|
85 |
+
public function setWidth($width) {
|
86 |
+
$this->width = $width;
|
87 |
+
}
|
88 |
+
}
|
Nextend/Framework/Form/Element/AbstractFieldHidden.php
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class AbstractFieldHidden extends AbstractField {
|
11 |
+
|
12 |
+
protected $hasTooltip = true;
|
13 |
+
|
14 |
+
protected $type = 'hidden';
|
15 |
+
|
16 |
+
public function __construct($insertAt, $name = '', $label = false, $default = '', $parameters = array()) {
|
17 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
18 |
+
}
|
19 |
+
|
20 |
+
protected function fetchTooltip() {
|
21 |
+
if ($this->hasTooltip) {
|
22 |
+
return parent::fetchTooltip();
|
23 |
+
} else {
|
24 |
+
return $this->fetchNoTooltip();
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
protected function fetchElement() {
|
29 |
+
|
30 |
+
return Html::tag('input', array(
|
31 |
+
'id' => $this->fieldID,
|
32 |
+
'name' => $this->getFieldName(),
|
33 |
+
'value' => $this->getValue(),
|
34 |
+
'type' => $this->type,
|
35 |
+
'autocomplete' => 'off'
|
36 |
+
), false);
|
37 |
+
}
|
38 |
+
}
|
Nextend/Framework/Form/Element/Breakpoint.php
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\AbstractField;
|
9 |
+
use Nextend\Framework\Form\ContainerInterface;
|
10 |
+
use Nextend\Framework\Form\TraitFieldset;
|
11 |
+
use Nextend\Framework\View\Html;
|
12 |
+
|
13 |
+
class Breakpoint extends AbstractField implements ContainerInterface {
|
14 |
+
|
15 |
+
use TraitFieldset;
|
16 |
+
|
17 |
+
protected $fields = array();
|
18 |
+
|
19 |
+
protected $enables = false;
|
20 |
+
|
21 |
+
protected $global = false;
|
22 |
+
|
23 |
+
public function __construct($insertAt, $name = '', $fields = array(), $enables = false, $global = false) {
|
24 |
+
|
25 |
+
$this->fields = $fields;
|
26 |
+
$this->enables = $enables;
|
27 |
+
$this->global = $global;
|
28 |
+
|
29 |
+
parent::__construct($insertAt, $name, false, '');
|
30 |
+
}
|
31 |
+
|
32 |
+
public function getLabelClass() {
|
33 |
+
|
34 |
+
return parent::getLabelClass() . ' n2_field--raw';
|
35 |
+
}
|
36 |
+
|
37 |
+
protected function fetchElement() {
|
38 |
+
|
39 |
+
$orientation = new Tab($this, $this->name . '-orientation', n2_('Orientation'), 'portrait', array(
|
40 |
+
'options' => array(
|
41 |
+
'portrait' => n2_('Portrait'),
|
42 |
+
'landscape' => n2_('Landscape')
|
43 |
+
)
|
44 |
+
));
|
45 |
+
$devices = array(
|
46 |
+
array(
|
47 |
+
'id' => 'mobileportrait',
|
48 |
+
'icon' => 'ssi_16 ssi_16--mobileportrait',
|
49 |
+
'label' => n2_('Mobile')
|
50 |
+
),
|
51 |
+
array(
|
52 |
+
'id' => 'tabletportrait',
|
53 |
+
'icon' => 'ssi_16 ssi_16--tabletportrait',
|
54 |
+
'label' => n2_('Tablet')
|
55 |
+
),
|
56 |
+
array(
|
57 |
+
'id' => 'desktopportrait',
|
58 |
+
'icon' => 'ssi_16 ssi_16--desktopportrait',
|
59 |
+
'label' => n2_('Desktop')
|
60 |
+
)
|
61 |
+
);
|
62 |
+
|
63 |
+
|
64 |
+
$preHtml = '';
|
65 |
+
$element = $this->first;
|
66 |
+
while ($element) {
|
67 |
+
$preHtml .= $this->decorateElement($element);
|
68 |
+
|
69 |
+
$element = $element->getNext();
|
70 |
+
}
|
71 |
+
|
72 |
+
$html = '';
|
73 |
+
|
74 |
+
for ($i = 0; $i < count($devices); $i++) {
|
75 |
+
$html .= Html::tag('div', array(
|
76 |
+
'data-id' => $devices[$i]['id'],
|
77 |
+
'class' => 'n2_field_breakpoint__device'
|
78 |
+
), '<div class="n2_field_breakpoint__device_enable" data-n2tip="' . $devices[$i]['label'] . '"><i class="' . $devices[$i]['icon'] . '"></i></div>');
|
79 |
+
}
|
80 |
+
|
81 |
+
$options = array(
|
82 |
+
'orientation' => $orientation->getID(),
|
83 |
+
'fields' => $this->fields,
|
84 |
+
'enables' => $this->enables,
|
85 |
+
'global' => $this->global
|
86 |
+
);
|
87 |
+
|
88 |
+
Js::addInline('new N2Classes.FormElementBreakpoint("' . $this->fieldID . '", ' . json_encode($options) . ');');
|
89 |
+
|
90 |
+
|
91 |
+
return '<div id="' . $this->getID() . '" class="n2_field_breakpoint"><div class="n2_field_breakpoint__pre_fields">' . $preHtml . '</div><div class="n2_field_breakpoint__breakpoint_container" data-orientation="portrait">' . $html . '</div></div>';
|
92 |
+
}
|
93 |
+
|
94 |
+
public function decorateElement($element) {
|
95 |
+
return $this->parent->decorateElement($element);
|
96 |
+
}
|
97 |
+
|
98 |
+
}
|
Nextend/Framework/Form/Element/Button.php
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class Button extends AbstractField {
|
11 |
+
|
12 |
+
protected $url = '';
|
13 |
+
|
14 |
+
protected $target = '';
|
15 |
+
|
16 |
+
protected $buttonLabel = '';
|
17 |
+
|
18 |
+
protected $classes = array('n2_field_button');
|
19 |
+
|
20 |
+
public function __construct($insertAt, $name = '', $label = '', $buttonLabel = '', $parameters = array()) {
|
21 |
+
$this->buttonLabel = $buttonLabel;
|
22 |
+
parent::__construct($insertAt, $name, $label, '', $parameters);
|
23 |
+
}
|
24 |
+
|
25 |
+
protected function fetchElement() {
|
26 |
+
|
27 |
+
return Html::tag('a', $this->getAttributes(), $this->buttonLabel);
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @param $className
|
32 |
+
*/
|
33 |
+
public function addClass($className) {
|
34 |
+
$this->classes[] = $className;
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @return array
|
39 |
+
*/
|
40 |
+
protected function getAttributes() {
|
41 |
+
$attributes = array(
|
42 |
+
'id' => $this->fieldID,
|
43 |
+
'class' => implode(' ', $this->classes)
|
44 |
+
);
|
45 |
+
|
46 |
+
if (!empty($this->url)) {
|
47 |
+
$attributes['href'] = $this->url;
|
48 |
+
if (!empty($this->target)) {
|
49 |
+
$attributes['target'] = $this->target;
|
50 |
+
}
|
51 |
+
} else {
|
52 |
+
$attributes['href'] = '#';
|
53 |
+
}
|
54 |
+
|
55 |
+
return $attributes;
|
56 |
+
}
|
57 |
+
|
58 |
+
public function setUrl($url) {
|
59 |
+
$this->url = $url;
|
60 |
+
}
|
61 |
+
|
62 |
+
public function setTarget($target) {
|
63 |
+
$this->target = $target;
|
64 |
+
}
|
65 |
+
}
|
Nextend/Framework/Form/Element/Button/ButtonIcon.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Button;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Button;
|
8 |
+
|
9 |
+
class ButtonIcon extends Button {
|
10 |
+
|
11 |
+
protected $hoverTip = '';
|
12 |
+
|
13 |
+
public function __construct($insertAt, $name = '', $label = '', $icon = '', $parameters = array()) {
|
14 |
+
|
15 |
+
$this->classes[] = 'n2_field_button--icon';
|
16 |
+
parent::__construct($insertAt, $name, $label, '<i class="' . $icon . '"></i>', $parameters);
|
17 |
+
}
|
18 |
+
|
19 |
+
protected function getAttributes() {
|
20 |
+
$attributes = parent::getAttributes();
|
21 |
+
|
22 |
+
if (!empty($this->hoverTip)) {
|
23 |
+
$attributes['data-n2tip'] = $this->hoverTip;
|
24 |
+
}
|
25 |
+
|
26 |
+
return $attributes;
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @param string $hoverTip
|
31 |
+
*/
|
32 |
+
public function setHoverTip($hoverTip) {
|
33 |
+
$this->hoverTip = $hoverTip;
|
34 |
+
}
|
35 |
+
}
|
Nextend/Framework/Form/Element/Button/ButtonMoreLess.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Button;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Element\Button;
|
9 |
+
|
10 |
+
class ButtonMoreLess extends Button {
|
11 |
+
|
12 |
+
public function __construct($insertAt, $name, $label = '', $parameters = array()) {
|
13 |
+
parent::__construct($insertAt, $name, $label, n2_('More'), $parameters);
|
14 |
+
}
|
15 |
+
|
16 |
+
protected function fetchElement() {
|
17 |
+
|
18 |
+
$options = array(
|
19 |
+
'labelMore' => n2_('More'),
|
20 |
+
'labelLess' => n2_('Less')
|
21 |
+
);
|
22 |
+
|
23 |
+
if (!empty($this->relatedFields)) {
|
24 |
+
$options['relatedFields'] = $this->relatedFields;
|
25 |
+
}
|
26 |
+
|
27 |
+
Js::addInline('new N2Classes.FormElementButtonMoreLess("' . $this->fieldID . '", ' . json_encode($options) . ');');
|
28 |
+
|
29 |
+
return parent::fetchElement();
|
30 |
+
}
|
31 |
+
}
|
Nextend/Framework/Form/Element/Button/ButtonRecordViewer.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Button;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Element\Button;
|
9 |
+
|
10 |
+
class ButtonRecordViewer extends Button {
|
11 |
+
|
12 |
+
public function __construct($insertAt, $name = '', $parameters = array()) {
|
13 |
+
parent::__construct($insertAt, $name, '', n2_('View records'), $parameters);
|
14 |
+
|
15 |
+
|
16 |
+
$this->addClass('n2_field_button--blue');
|
17 |
+
}
|
18 |
+
|
19 |
+
protected function fetchElement() {
|
20 |
+
|
21 |
+
$ajaxRecordUrl = $this->getForm()
|
22 |
+
->createAjaxUrl(array(
|
23 |
+
'generator/recordstable'
|
24 |
+
));
|
25 |
+
Js::addInline('new N2Classes.FieldRecordViewer(' . json_encode($this->fieldID) . ',' . json_encode($ajaxRecordUrl) . ');');
|
26 |
+
|
27 |
+
|
28 |
+
return parent::fetchElement();
|
29 |
+
}
|
30 |
+
}
|
Nextend/Framework/Form/Element/CheckboxOnOff.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class CheckboxOnOff extends AbstractFieldHidden {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var string
|
14 |
+
*/
|
15 |
+
protected $icon;
|
16 |
+
|
17 |
+
protected $invert = false;
|
18 |
+
|
19 |
+
protected $checkboxTip;
|
20 |
+
|
21 |
+
public function __construct($insertAt, $name, $label, $icon, $default = 0, $parameters = array()) {
|
22 |
+
|
23 |
+
$this->icon = $icon;
|
24 |
+
|
25 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
26 |
+
}
|
27 |
+
|
28 |
+
protected function fetchElement() {
|
29 |
+
|
30 |
+
$options = array(
|
31 |
+
'invert' => $this->invert,
|
32 |
+
'relatedFields' => $this->relatedFields
|
33 |
+
);
|
34 |
+
|
35 |
+
Js::addInline('new N2Classes.FormElementCheckboxOnOff("' . $this->fieldID . '", ' . json_encode($options) . ');');
|
36 |
+
|
37 |
+
$attr = array(
|
38 |
+
'class' => 'n2_field_checkbox_onoff' . ($this->isActive() ? ' n2_field_checkbox_onoff--active' : '')
|
39 |
+
);
|
40 |
+
|
41 |
+
if (!empty($this->checkboxTip)) {
|
42 |
+
$attr['data-n2tip'] = $this->checkboxTip;
|
43 |
+
}
|
44 |
+
|
45 |
+
return Html::tag('div', $attr, '<i class="' . $this->icon . '"></i>' . parent::fetchElement());
|
46 |
+
}
|
47 |
+
|
48 |
+
protected function isActive() {
|
49 |
+
|
50 |
+
$value = $this->getValue();
|
51 |
+
|
52 |
+
if (!$this->invert && $value) {
|
53 |
+
return true;
|
54 |
+
} else if ($this->invert && !$value) {
|
55 |
+
return true;
|
56 |
+
}
|
57 |
+
|
58 |
+
return false;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* @param bool $invert
|
63 |
+
*/
|
64 |
+
public function setInvert($invert) {
|
65 |
+
$this->invert = $invert;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @param string $tip
|
70 |
+
*/
|
71 |
+
public function setCheckboxTip($tip) {
|
72 |
+
$this->checkboxTip = $tip;
|
73 |
+
}
|
74 |
+
|
75 |
+
}
|
Nextend/Framework/Form/Element/Connected.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element;
|
4 |
+
|
5 |
+
use Nextend\Framework\Form\AbstractField;
|
6 |
+
|
7 |
+
class Connected extends Mixed {
|
8 |
+
|
9 |
+
protected $rowClass = 'n2_field_connected ';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @param AbstractField $element
|
13 |
+
*
|
14 |
+
* @return string
|
15 |
+
*/
|
16 |
+
public function decorateElement($element) {
|
17 |
+
|
18 |
+
$elementHtml = $element->render();
|
19 |
+
|
20 |
+
return $elementHtml[1];
|
21 |
+
}
|
22 |
+
|
23 |
+
protected function decorate($html) {
|
24 |
+
|
25 |
+
return '<div class="n2_field_connected__container" style="' . $this->style . '">' . $html . '</div>';
|
26 |
+
}
|
27 |
+
}
|
Nextend/Framework/Form/Element/Decoration.php
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
use Nextend\Framework\Asset\Js\Js;
|
7 |
+
use Nextend\Framework\View\Html;
|
8 |
+
|
9 |
+
class Decoration extends AbstractFieldHidden {
|
10 |
+
|
11 |
+
protected $value = null;
|
12 |
+
|
13 |
+
protected $options = array(
|
14 |
+
'italic' => 'ssi_16 ssi_16--italic',
|
15 |
+
'underline' => 'ssi_16 ssi_16--underline'
|
16 |
+
);
|
17 |
+
|
18 |
+
protected $style = '';
|
19 |
+
|
20 |
+
protected function fetchElement() {
|
21 |
+
|
22 |
+
$this->value = explode('||', $this->getValue());
|
23 |
+
|
24 |
+
$html = Html::tag('div', array(
|
25 |
+
'class' => 'n2_field_decoration',
|
26 |
+
'style' => $this->style
|
27 |
+
), $this->renderOptions() . parent::fetchElement());
|
28 |
+
|
29 |
+
Js::addInline('new N2Classes.FormElementDecoration("' . $this->fieldID . '", ' . json_encode(array_keys($this->options)) . ');');
|
30 |
+
|
31 |
+
return $html;
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
*
|
36 |
+
* @return string
|
37 |
+
*/
|
38 |
+
protected function renderOptions() {
|
39 |
+
|
40 |
+
$length = count($this->options) - 1;
|
41 |
+
|
42 |
+
$html = '';
|
43 |
+
$i = 0;
|
44 |
+
foreach ($this->options AS $value => $class) {
|
45 |
+
|
46 |
+
$html .= Html::tag('div', array(
|
47 |
+
'class' => 'n2_field_decoration__option ' . ($this->isSelected($value) ? ' n2_field_decoration__option--selected' : ''),
|
48 |
+
'data-value' => $value
|
49 |
+
), Html::tag('i', array('class' => $class)));
|
50 |
+
$i++;
|
51 |
+
}
|
52 |
+
|
53 |
+
return $html;
|
54 |
+
}
|
55 |
+
|
56 |
+
function isSelected($value) {
|
57 |
+
if (in_array($value, $this->value)) {
|
58 |
+
return true;
|
59 |
+
}
|
60 |
+
|
61 |
+
return false;
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @param array $options
|
66 |
+
*/
|
67 |
+
public function setOptions($options) {
|
68 |
+
$this->options = $options;
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* @param string $style
|
73 |
+
*/
|
74 |
+
public function setStyle($style) {
|
75 |
+
$this->style = $style;
|
76 |
+
}
|
77 |
+
}
|
Nextend/Framework/Form/Element/Devices.php
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class Devices extends AbstractFieldHidden {
|
11 |
+
|
12 |
+
private $values = array();
|
13 |
+
|
14 |
+
protected function fetchElement() {
|
15 |
+
|
16 |
+
$html = Html::tag('div', array(
|
17 |
+
'id' => $this->fieldID,
|
18 |
+
'class' => 'n2_field_radio_icon'
|
19 |
+
), $this->generateOptions());
|
20 |
+
|
21 |
+
Js::addInline('new N2Classes.FormElementDevices("' . $this->fieldID . '", ' . json_encode($this->values) . ');');
|
22 |
+
|
23 |
+
return $html;
|
24 |
+
}
|
25 |
+
|
26 |
+
function generateOptions() {
|
27 |
+
$options = array(
|
28 |
+
'desktop-portrait' => 'ssi_16 ssi_16--desktopportrait',
|
29 |
+
'tablet-portrait' => 'ssi_16 ssi_16--tabletportrait',
|
30 |
+
'mobile-portrait' => 'ssi_16 ssi_16--mobileportrait'
|
31 |
+
);
|
32 |
+
|
33 |
+
|
34 |
+
$html = '';
|
35 |
+
$i = 0;
|
36 |
+
foreach ($options AS $value => $class) {
|
37 |
+
$this->values[] = $value;
|
38 |
+
|
39 |
+
$html .= Html::tag('div', array(
|
40 |
+
'class' => 'n2_field_radio__option'
|
41 |
+
), Html::tag('i', array(
|
42 |
+
'class' => $class
|
43 |
+
)) . Html::tag('input', array(
|
44 |
+
'type' => 'hidden',
|
45 |
+
'id' => $this->fieldID . '-' . $value
|
46 |
+
)));
|
47 |
+
$i++;
|
48 |
+
}
|
49 |
+
|
50 |
+
return $html;
|
51 |
+
}
|
52 |
+
}
|
Nextend/Framework/Form/Element/EmptyArea.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class EmptyArea extends AbstractField {
|
11 |
+
|
12 |
+
protected function fetchElement() {
|
13 |
+
|
14 |
+
return Html::tag('div', array(
|
15 |
+
'id' => $this->fieldID
|
16 |
+
));
|
17 |
+
}
|
18 |
+
}
|
Nextend/Framework/Form/Element/FloatToPercent.php
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
use Nextend\Framework\View\Html;
|
7 |
+
|
8 |
+
class FloatToPercent extends AbstractFieldHidden {
|
9 |
+
|
10 |
+
protected $class = 'n2_field_number ';
|
11 |
+
|
12 |
+
protected $min = '';
|
13 |
+
|
14 |
+
protected $max = '';
|
15 |
+
|
16 |
+
protected $sublabel = '';
|
17 |
+
|
18 |
+
protected $fieldType = 'text';
|
19 |
+
|
20 |
+
protected $unit = '%';
|
21 |
+
|
22 |
+
protected $style = 'width:32px;';
|
23 |
+
|
24 |
+
protected function fetchElement() {
|
25 |
+
|
26 |
+
if ($this->min == '') {
|
27 |
+
$this->min = '-Number.MAX_VALUE';
|
28 |
+
}
|
29 |
+
|
30 |
+
if ($this->max == '') {
|
31 |
+
$this->max = 'Number.MAX_VALUE';
|
32 |
+
}
|
33 |
+
|
34 |
+
Js::addInline('new N2Classes.FormElementFloatToPercent("' . $this->fieldID . '", ' . $this->min . ', ' . $this->max . ');');
|
35 |
+
|
36 |
+
$html = Html::openTag('div', array(
|
37 |
+
'class' => 'n2_field_text ' . $this->getClass()
|
38 |
+
));
|
39 |
+
|
40 |
+
$html .= Html::tag('input', array(
|
41 |
+
'type' => $this->fieldType,
|
42 |
+
'id' => $this->fieldID . '-input',
|
43 |
+
'value' => $this->getValue() * 100,
|
44 |
+
'style' => $this->getStyle(),
|
45 |
+
'autocomplete' => 'off'
|
46 |
+
), false);
|
47 |
+
|
48 |
+
if ($this->unit) {
|
49 |
+
$html .= Html::tag('div', array(
|
50 |
+
'class' => 'n2_field_number__unit'
|
51 |
+
), $this->unit);
|
52 |
+
}
|
53 |
+
$html .= parent::fetchElement();
|
54 |
+
$html .= "</div>";
|
55 |
+
|
56 |
+
return $html;
|
57 |
+
}
|
58 |
+
|
59 |
+
public function setMin($min) {
|
60 |
+
$this->min = $min;
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* @param int $max
|
65 |
+
*/
|
66 |
+
public function setMax($max) {
|
67 |
+
$this->max = $max;
|
68 |
+
}
|
69 |
+
}
|
Nextend/Framework/Form/Element/Font.php
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
use Nextend\Framework\Font\FontManager;
|
7 |
+
use Nextend\Framework\Font\FontParser;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class Font extends AbstractFieldHidden {
|
11 |
+
|
12 |
+
protected $mode = '';
|
13 |
+
|
14 |
+
protected $css = '';
|
15 |
+
|
16 |
+
protected $style2 = '';
|
17 |
+
|
18 |
+
protected $preview = '';
|
19 |
+
|
20 |
+
|
21 |
+
protected function addScript() {
|
22 |
+
|
23 |
+
FontManager::enqueue($this->getForm());
|
24 |
+
|
25 |
+
Js::addInline('new N2Classes.FormElementFont("' . $this->fieldID . '", {
|
26 |
+
mode: "' . $this->mode . '",
|
27 |
+
label: "' . $this->label . '",
|
28 |
+
style: "' . $this->style . '",
|
29 |
+
style2: "' . $this->style2 . '",
|
30 |
+
preview: ' . json_encode($this->preview) . '
|
31 |
+
});');
|
32 |
+
}
|
33 |
+
|
34 |
+
protected function fetchElement() {
|
35 |
+
|
36 |
+
$this->addScript();
|
37 |
+
|
38 |
+
return Html::tag('div', array(
|
39 |
+
'class' => 'n2_field_font'
|
40 |
+
), n2_('Font') . parent::fetchElement());
|
41 |
+
}
|
42 |
+
|
43 |
+
public function getValue() {
|
44 |
+
|
45 |
+
return FontParser::parse(parent::getValue());
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @param string $mode
|
50 |
+
*/
|
51 |
+
public function setMode($mode) {
|
52 |
+
$this->mode = $mode;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* @param string $css
|
57 |
+
*/
|
58 |
+
public function setCss($css) {
|
59 |
+
$this->css = $css;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @param string $style2
|
64 |
+
*/
|
65 |
+
public function setStyle2($style2) {
|
66 |
+
$this->style2 = $style2;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @param string $preview
|
71 |
+
*/
|
72 |
+
public function setPreview($preview) {
|
73 |
+
$this->preview = $preview;
|
74 |
+
}
|
75 |
+
|
76 |
+
}
|
Nextend/Framework/Form/Element/Group/GroupCheckboxOnOff.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Group;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Grouping;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class GroupCheckboxOnOff extends Grouping {
|
11 |
+
|
12 |
+
protected function fetchElement() {
|
13 |
+
return Html::tag('div', array(
|
14 |
+
'class' => 'n2_field_group_checkbox_onoff'
|
15 |
+
), parent::fetchElement());
|
16 |
+
}
|
17 |
+
|
18 |
+
}
|
Nextend/Framework/Form/Element/Grouping.php
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\Form\ContainerInterface;
|
9 |
+
use Nextend\Framework\Form\TraitFieldset;
|
10 |
+
|
11 |
+
class Grouping extends AbstractField implements ContainerInterface {
|
12 |
+
|
13 |
+
use TraitFieldset;
|
14 |
+
|
15 |
+
protected $rowClass = 'n2_field__grouping';
|
16 |
+
|
17 |
+
public function __construct($insertAt, $name = '', $label = false, $parameters = array()) {
|
18 |
+
parent::__construct($insertAt, $name, $label, '', $parameters);
|
19 |
+
}
|
20 |
+
|
21 |
+
protected function fetchElement() {
|
22 |
+
|
23 |
+
$html = '';
|
24 |
+
|
25 |
+
$element = $this->first;
|
26 |
+
while ($element) {
|
27 |
+
$html .= $this->decorateElement($element);
|
28 |
+
|
29 |
+
$element = $element->getNext();
|
30 |
+
}
|
31 |
+
|
32 |
+
return $html;
|
33 |
+
}
|
34 |
+
|
35 |
+
public function decorateElement($element) {
|
36 |
+
|
37 |
+
return $this->parent->decorateElement($element);
|
38 |
+
}
|
39 |
+
}
|
Nextend/Framework/Form/Element/Hidden.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
class Hidden extends AbstractFieldHidden {
|
8 |
+
|
9 |
+
protected $hasTooltip = false;
|
10 |
+
|
11 |
+
public function __construct($insertAt, $name = '', $default = '', $parameters = array()) {
|
12 |
+
parent::__construct($insertAt, $name, false, $default, $parameters);
|
13 |
+
}
|
14 |
+
|
15 |
+
public function getRowClass() {
|
16 |
+
return 'n2_form_element--hidden';
|
17 |
+
}
|
18 |
+
}
|
Nextend/Framework/Form/Element/Hidden/HiddenFont.php
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element\Hidden;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
use Nextend\Framework\Font\FontManager;
|
7 |
+
use Nextend\Framework\Form\Element\AbstractFieldHidden;
|
8 |
+
|
9 |
+
class HiddenFont extends AbstractFieldHidden {
|
10 |
+
|
11 |
+
protected $rowClass = 'n2_form_element--hidden';
|
12 |
+
|
13 |
+
protected $mode = '';
|
14 |
+
|
15 |
+
protected function fetchElement() {
|
16 |
+
|
17 |
+
FontManager::enqueue($this->getForm());
|
18 |
+
|
19 |
+
Js::addInline('new N2Classes.FormElementFontHidden("' . $this->fieldID . '", {
|
20 |
+
mode: "' . $this->mode . '",
|
21 |
+
label: "' . $this->label . '"
|
22 |
+
});');
|
23 |
+
|
24 |
+
return parent::fetchElement();
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @param string $mode
|
29 |
+
*/
|
30 |
+
public function setMode($mode) {
|
31 |
+
$this->mode = $mode;
|
32 |
+
}
|
33 |
+
}
|
Nextend/Framework/Form/Element/Hidden/HiddenOnOff.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Hidden;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\OnOff;
|
8 |
+
|
9 |
+
class HiddenOnOff extends OnOff {
|
10 |
+
|
11 |
+
protected $rowClass = 'n2_form_element--hidden';
|
12 |
+
|
13 |
+
}
|
Nextend/Framework/Form/Element/Hidden/HiddenStyle.php
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element\Hidden;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
use Nextend\Framework\Form\Element\AbstractFieldHidden;
|
7 |
+
use Nextend\Framework\Style\StyleManager;
|
8 |
+
|
9 |
+
class HiddenStyle extends AbstractFieldHidden {
|
10 |
+
|
11 |
+
protected $rowClass = 'n2_form_element--hidden';
|
12 |
+
|
13 |
+
protected $mode = '';
|
14 |
+
|
15 |
+
protected function fetchElement() {
|
16 |
+
|
17 |
+
StyleManager::enqueue($this->getForm());
|
18 |
+
|
19 |
+
Js::addInline('new N2Classes.FormElementStyleHidden("' . $this->fieldID . '", {
|
20 |
+
mode: "' . $this->mode . '",
|
21 |
+
label: "' . $this->label . '"
|
22 |
+
});');
|
23 |
+
|
24 |
+
return parent::fetchElement();
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @param string $mode
|
29 |
+
*/
|
30 |
+
public function setMode($mode) {
|
31 |
+
$this->mode = $mode;
|
32 |
+
}
|
33 |
+
}
|
Nextend/Framework/Form/Element/IconTab.php
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class IconTab extends AbstractFieldHidden {
|
11 |
+
|
12 |
+
protected $options = array();
|
13 |
+
protected $relatedValueFields = array();
|
14 |
+
protected $relatedAttribute = '';
|
15 |
+
protected $tooltips = array();
|
16 |
+
|
17 |
+
protected function fetchElement() {
|
18 |
+
|
19 |
+
$value = $this->getValue();
|
20 |
+
if (!empty($value)) {
|
21 |
+
$this->defaultValue = $value;
|
22 |
+
} else if (empty($this->defaultValue)) {
|
23 |
+
$this->defaultValue = array_keys($this->options)[0];
|
24 |
+
}
|
25 |
+
|
26 |
+
$html = Html::openTag("div", array(
|
27 |
+
"id" => $this->fieldID . "_icon_tab",
|
28 |
+
"class" => "n2_field_icon_tab",
|
29 |
+
"style" => $this->style
|
30 |
+
));
|
31 |
+
|
32 |
+
$html .= $this->renderOptions();
|
33 |
+
|
34 |
+
$html .= Html::closeTag("div");
|
35 |
+
|
36 |
+
$html .= parent::fetchElement();
|
37 |
+
|
38 |
+
if (!empty($this->relatedAttribute)) {
|
39 |
+
$options['relatedAttribute'] = $this->relatedAttribute;
|
40 |
+
}
|
41 |
+
|
42 |
+
$options = array();
|
43 |
+
|
44 |
+
if (!empty($this->relatedValueFields)) {
|
45 |
+
$options['relatedValueFields'] = $this->relatedValueFields;
|
46 |
+
}
|
47 |
+
|
48 |
+
Js::addInline('new N2Classes.FormElementIconTab("' . $this->fieldID . '", ' . json_encode($options) . ');');
|
49 |
+
|
50 |
+
return $html;
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @param array $options
|
55 |
+
*/
|
56 |
+
public function setOptions($options) {
|
57 |
+
|
58 |
+
$this->options = $options;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* @param array $tooltips
|
63 |
+
*/
|
64 |
+
public function setTooltips($tooltips) {
|
65 |
+
|
66 |
+
$this->tooltips = $tooltips;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @param $relatedValueFields
|
71 |
+
*/
|
72 |
+
public function setRelatedValueFields($relatedValueFields) {
|
73 |
+
$this->relatedValueFields = $relatedValueFields;
|
74 |
+
}
|
75 |
+
|
76 |
+
public function renderOptions() {
|
77 |
+
$html = '';
|
78 |
+
foreach ($this->options AS $option => $icon) {
|
79 |
+
$class = 'n2_field_icon_tab__option';
|
80 |
+
if ($option == $this->defaultValue) {
|
81 |
+
$class .= ' n2_field_icon_tab__option--selected';
|
82 |
+
}
|
83 |
+
|
84 |
+
$element = array(
|
85 |
+
"class" => $class,
|
86 |
+
"data-ssoption" => $option
|
87 |
+
);
|
88 |
+
|
89 |
+
if (isset($this->tooltips[$option])) {
|
90 |
+
$element += array(
|
91 |
+
"data-n2tip" => $this->tooltips[$option]
|
92 |
+
);
|
93 |
+
|
94 |
+
}
|
95 |
+
$html .= Html::openTag("div", $element);
|
96 |
+
$html .= Html::openTag("i", array(
|
97 |
+
"class" => $icon
|
98 |
+
));
|
99 |
+
$html .= Html::closeTag("i");
|
100 |
+
$html .= Html::closeTag("div");
|
101 |
+
}
|
102 |
+
|
103 |
+
return $html;
|
104 |
+
}
|
105 |
+
}
|
Nextend/Framework/Form/Element/LayerWindowFocus.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\AbstractField;
|
9 |
+
|
10 |
+
class LayerWindowFocus extends AbstractField {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var AbstractField
|
14 |
+
*/
|
15 |
+
protected $fieldImage;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @var AbstractField
|
19 |
+
*/
|
20 |
+
protected $fieldFocusX;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var AbstractField
|
24 |
+
*/
|
25 |
+
protected $fieldFocusY;
|
26 |
+
|
27 |
+
|
28 |
+
/**
|
29 |
+
* LayerWindowFocus constructor.
|
30 |
+
*
|
31 |
+
* @param $insertAt
|
32 |
+
* @param $name
|
33 |
+
* @param $label
|
34 |
+
* @param array $parameters
|
35 |
+
*/
|
36 |
+
public function __construct($insertAt, $name, $label, $parameters = array()) {
|
37 |
+
|
38 |
+
parent::__construct($insertAt, $name, $label, '', $parameters);
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @param AbstractField $fieldImage
|
43 |
+
* @param AbstractField $fieldFocusX
|
44 |
+
* @param AbstractField $fieldFocusY
|
45 |
+
*/
|
46 |
+
public function setFields($fieldImage, $fieldFocusX, $fieldFocusY) {
|
47 |
+
|
48 |
+
$this->fieldImage = $fieldImage;
|
49 |
+
$this->fieldFocusX = $fieldFocusX;
|
50 |
+
$this->fieldFocusY = $fieldFocusY;
|
51 |
+
}
|
52 |
+
|
53 |
+
protected function fetchElement() {
|
54 |
+
|
55 |
+
Js::addInline('new N2Classes.FormElementLayerWindowFocus("' . $this->fieldID . '", ' . json_encode(array(
|
56 |
+
'image' => $this->fieldImage->getID(),
|
57 |
+
'focusX' => $this->fieldFocusX->getID(),
|
58 |
+
'focusY' => $this->fieldFocusY->getID(),
|
59 |
+
)) . ');');
|
60 |
+
|
61 |
+
return '<div id="' . $this->fieldID . '" class="n2_field_layer_window_focus" style="width:314px;"><img class="n2_field_layer_window_focus__image" alt="Error" /></div>';
|
62 |
+
}
|
63 |
+
|
64 |
+
}
|
Nextend/Framework/Form/Element/MarginPadding.php
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\AbstractField;
|
9 |
+
use Nextend\Framework\Form\ContainerInterface;
|
10 |
+
use Nextend\Framework\Form\TraitFieldset;
|
11 |
+
|
12 |
+
class MarginPadding extends AbstractFieldHidden implements ContainerInterface {
|
13 |
+
|
14 |
+
use TraitFieldset;
|
15 |
+
|
16 |
+
private static $separator = '|*|';
|
17 |
+
|
18 |
+
protected $unit = false;
|
19 |
+
|
20 |
+
protected function fetchElement() {
|
21 |
+
$default = explode(self::$separator, $this->defaultValue);
|
22 |
+
$value = explode(self::$separator, $this->getValue());
|
23 |
+
$value = $value + $default;
|
24 |
+
|
25 |
+
$html = "<div class='n2_field_margin_padding' style='" . $this->style . "'>";
|
26 |
+
|
27 |
+
$html .= '<div class="n2_field_margin_padding__pre_label"><i class="ssi_16 ssi_16--unlink"></i></div>';
|
28 |
+
$subElements = array();
|
29 |
+
$i = 0;
|
30 |
+
|
31 |
+
$element = $this->first;
|
32 |
+
while ($element) {
|
33 |
+
$element->setExposeName(false);
|
34 |
+
if (isset($value[$i])) {
|
35 |
+
$element->setDefaultValue($value[$i]);
|
36 |
+
}
|
37 |
+
|
38 |
+
$html .= $this->decorateElement($element);
|
39 |
+
$subElements[$i] = $element->getID();
|
40 |
+
$i++;
|
41 |
+
|
42 |
+
$element = $element->getNext();
|
43 |
+
}
|
44 |
+
|
45 |
+
if ($this->unit) {
|
46 |
+
$html .= '<div class="n2_field_unit"><div class="n2_field_unit__current_unit">' . $this->unit . '</div></div>';
|
47 |
+
}
|
48 |
+
|
49 |
+
$html .= parent::fetchElement();
|
50 |
+
$html .= "</div>";
|
51 |
+
|
52 |
+
Js::addInline('new N2Classes.FormElementMarginPadding("' . $this->fieldID . '", ' . json_encode($subElements) . ', "' . self::$separator . '");');
|
53 |
+
|
54 |
+
$this->renderRelatedFields();
|
55 |
+
|
56 |
+
return $html;
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @param string $unit
|
61 |
+
*/
|
62 |
+
public function setUnit($unit) {
|
63 |
+
$this->unit = $unit;
|
64 |
+
}
|
65 |
+
|
66 |
+
public function getControlName() {
|
67 |
+
return $this->name . $this->controlName;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* @param AbstractField $element
|
72 |
+
*
|
73 |
+
* @return string
|
74 |
+
*/
|
75 |
+
public function decorateElement($element) {
|
76 |
+
|
77 |
+
$elementHtml = $element->render();
|
78 |
+
|
79 |
+
return $elementHtml[1];
|
80 |
+
}
|
81 |
+
}
|
Nextend/Framework/Form/Element/Message.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
|
9 |
+
abstract class Message extends AbstractField {
|
10 |
+
|
11 |
+
protected $description = '';
|
12 |
+
|
13 |
+
protected $classes = array('n2_field_message');
|
14 |
+
|
15 |
+
public function __construct($insertAt, $name, $label, $description) {
|
16 |
+
$this->description = $description;
|
17 |
+
parent::__construct($insertAt, $name, $label);
|
18 |
+
}
|
19 |
+
|
20 |
+
protected function fetchElement() {
|
21 |
+
echo '<div class="' . implode(' ', $this->classes) . '">' . $this->description . '</div>';
|
22 |
+
}
|
23 |
+
}
|
Nextend/Framework/Form/Element/Message/Notice.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Message;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Message;
|
8 |
+
|
9 |
+
class Notice extends Message {
|
10 |
+
|
11 |
+
public function __construct($insertAt, $name, $label, $description) {
|
12 |
+
$this->classes[] = 'n2_field_message--notice';
|
13 |
+
parent::__construct($insertAt, $name, $label, $description);
|
14 |
+
}
|
15 |
+
}
|
Nextend/Framework/Form/Element/Message/Warning.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Message;
|
5 |
+
|
6 |
+
use Nextend\Framework\Form\Element\Message;
|
7 |
+
|
8 |
+
class Warning extends Message {
|
9 |
+
|
10 |
+
protected $description = '';
|
11 |
+
|
12 |
+
public function __construct($insertAt, $name, $description) {
|
13 |
+
$this->classes[] = 'n2_field_message--warning';
|
14 |
+
parent::__construct($insertAt, $name, n2_('Warning'), $description);
|
15 |
+
}
|
16 |
+
|
17 |
+
protected function fetchElement() {
|
18 |
+
echo '<div class="' . implode(' ', $this->classes) . '">' . $this->description . '</div>';
|
19 |
+
}
|
20 |
+
}
|
Nextend/Framework/Form/Element/Mixed.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\AbstractField;
|
9 |
+
use Nextend\Framework\Form\ContainerInterface;
|
10 |
+
use Nextend\Framework\Form\TraitFieldset;
|
11 |
+
|
12 |
+
class Mixed extends AbstractFieldHidden implements ContainerInterface {
|
13 |
+
|
14 |
+
use TraitFieldset;
|
15 |
+
|
16 |
+
private $separator = '|*|';
|
17 |
+
|
18 |
+
protected $style = '';
|
19 |
+
|
20 |
+
protected $rowClass = 'n2_field_mixed ';
|
21 |
+
|
22 |
+
protected function fetchElement() {
|
23 |
+
|
24 |
+
$default = explode($this->separator, $this->defaultValue);
|
25 |
+
$value = explode($this->separator, $this->getValue());
|
26 |
+
$value = $value + $default;
|
27 |
+
|
28 |
+
$html = '';
|
29 |
+
$subElements = array();
|
30 |
+
$i = 0;
|
31 |
+
|
32 |
+
|
33 |
+
$element = $this->first;
|
34 |
+
while ($element) {
|
35 |
+
$element->setExposeName(false);
|
36 |
+
if (isset($value[$i])) {
|
37 |
+
$element->setDefaultValue($value[$i]);
|
38 |
+
}
|
39 |
+
|
40 |
+
$html .= $this->decorateElement($element);
|
41 |
+
|
42 |
+
$subElements[$i] = $element->getID();
|
43 |
+
$i++;
|
44 |
+
|
45 |
+
$element = $element->getNext();
|
46 |
+
}
|
47 |
+
|
48 |
+
$html .= parent::fetchElement();
|
49 |
+
|
50 |
+
Js::addInline('new N2Classes.FormElementMixed("' . $this->fieldID . '", ' . json_encode($subElements) . ', "' . $this->separator . '");');
|
51 |
+
|
52 |
+
return $this->decorate($html);
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* @param string $style
|
57 |
+
*/
|
58 |
+
public function setStyle($style) {
|
59 |
+
$this->style = $style;
|
60 |
+
}
|
61 |
+
|
62 |
+
public function getControlName() {
|
63 |
+
return $this->name . $this->controlName;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* @param AbstractField $element
|
68 |
+
*
|
69 |
+
* @return string
|
70 |
+
*/
|
71 |
+
public function decorateElement($element) {
|
72 |
+
|
73 |
+
return $this->parent->decorateElement($element);
|
74 |
+
}
|
75 |
+
|
76 |
+
protected function decorate($html) {
|
77 |
+
|
78 |
+
return '<div class="n2_field_mixed__container" style="' . $this->style . '">' . $html . '</div>';
|
79 |
+
}
|
80 |
+
}
|
Nextend/Framework/Form/Element/Mixed/Border.php
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Mixed;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\Form\Element\Mixed;
|
9 |
+
use Nextend\Framework\Form\Element\Select;
|
10 |
+
use Nextend\Framework\Form\Element\Text\Color;
|
11 |
+
use Nextend\Framework\Form\Element\Text\NumberAutoComplete;
|
12 |
+
use Nextend\Framework\View\Html;
|
13 |
+
|
14 |
+
class Border extends Mixed {
|
15 |
+
|
16 |
+
protected $rowClass = 'n2_field_mixed_border ';
|
17 |
+
|
18 |
+
public function __construct($insertAt, $name = '', $label = '', $default = '', $parameters = array()) {
|
19 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
20 |
+
|
21 |
+
new NumberAutoComplete($this, $this->name . '-1', false, '', array(
|
22 |
+
'values' => array(
|
23 |
+
0,
|
24 |
+
1,
|
25 |
+
3,
|
26 |
+
5
|
27 |
+
),
|
28 |
+
'min' => 0,
|
29 |
+
'wide' => 3,
|
30 |
+
'unit' => 'px',
|
31 |
+
'relatedFields' => array(
|
32 |
+
$this->generateId($this->getControlName() . $this->name . '-2'),
|
33 |
+
$this->generateId($this->getControlName() . $this->name . '-3')
|
34 |
+
)
|
35 |
+
));
|
36 |
+
|
37 |
+
new Select($this, $this->name . '-2', false, '', array(
|
38 |
+
'options' => array(
|
39 |
+
'none' => n2_('None'),
|
40 |
+
'dotted' => n2_('Dotted'),
|
41 |
+
'dashed' => n2_('Dashed'),
|
42 |
+
'solid' => n2_('Solid'),
|
43 |
+
'double' => n2_('Double'),
|
44 |
+
'groove' => n2_('Groove'),
|
45 |
+
'ridge' => n2_('Ridge'),
|
46 |
+
'inset' => n2_('Inset'),
|
47 |
+
'outset' => n2_('Outset')
|
48 |
+
)
|
49 |
+
));
|
50 |
+
|
51 |
+
new Color($this, $this->name . '-3', false, '', array(
|
52 |
+
'alpha' => true
|
53 |
+
));
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* @param AbstractField $element
|
58 |
+
*
|
59 |
+
* @return string
|
60 |
+
*/
|
61 |
+
public function decorateElement($element) {
|
62 |
+
|
63 |
+
$elementHtml = $element->render();
|
64 |
+
|
65 |
+
return Html::tag('div', array(
|
66 |
+
'data-field' => $element->getID()
|
67 |
+
), $elementHtml[1]);
|
68 |
+
}
|
69 |
+
|
70 |
+
protected function decorate($html) {
|
71 |
+
|
72 |
+
return '<div class="n2_field_mixed_border__container" style="' . $this->style . '">' . $html . '</div>';
|
73 |
+
}
|
74 |
+
}
|
Nextend/Framework/Form/Element/Mixed/BoxShadow.php
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Mixed;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\Form\Element\Mixed;
|
9 |
+
use Nextend\Framework\Form\Element\Text\Color;
|
10 |
+
use Nextend\Framework\Form\Element\Text\NumberAutoComplete;
|
11 |
+
|
12 |
+
class BoxShadow extends Mixed {
|
13 |
+
|
14 |
+
protected $rowClass = 'n2_field_mixed_box_shadow ';
|
15 |
+
|
16 |
+
public function __construct($insertAt, $name = '', $label = '', $default = '', $parameters = array()) {
|
17 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
18 |
+
|
19 |
+
for ($i = 1; $i < 5; $i++) {
|
20 |
+
new NumberAutoComplete($this, $this->name . '-' . $i, false, 0, array(
|
21 |
+
'wide' => 3
|
22 |
+
));
|
23 |
+
}
|
24 |
+
new Color($this, $this->name . '-5', false, '', array(
|
25 |
+
'alpha' => true
|
26 |
+
));
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @param AbstractField $element
|
31 |
+
*
|
32 |
+
* @return string
|
33 |
+
*/
|
34 |
+
public function decorateElement($element) {
|
35 |
+
|
36 |
+
$elementHtml = $element->render();
|
37 |
+
|
38 |
+
return $elementHtml[1];
|
39 |
+
}
|
40 |
+
|
41 |
+
protected function decorate($html) {
|
42 |
+
|
43 |
+
return '<div class="n2_field_mixed_box_shadow__container" style="' . $this->style . '">' . $html . '</div>';
|
44 |
+
}
|
45 |
+
}
|
Nextend/Framework/Form/Element/Mixed/FontSize.php
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Mixed;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\Form\Element\Mixed;
|
9 |
+
use Nextend\Framework\Form\Element\Text\NumberSlider;
|
10 |
+
use Nextend\Framework\Form\Element\Unit;
|
11 |
+
|
12 |
+
class FontSize extends Mixed {
|
13 |
+
|
14 |
+
protected $rowClass = 'n2_field_mixed_font_size ';
|
15 |
+
|
16 |
+
public function __construct($insertAt, $name = '', $label = '', $default = '', $parameters = array()) {
|
17 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
18 |
+
|
19 |
+
new NumberSlider($this, $this->name . '-1', false, '', array(
|
20 |
+
'min' => 1,
|
21 |
+
'max' => 10000,
|
22 |
+
'sliderMax' => 100,
|
23 |
+
'units' => array(
|
24 |
+
'pxMin' => 1,
|
25 |
+
'pxMax' => 10000,
|
26 |
+
'pxSliderMax' => 100,
|
27 |
+
'%Min' => 1,
|
28 |
+
'%Max' => 10000,
|
29 |
+
'%SliderMax' => 600
|
30 |
+
),
|
31 |
+
'style' => 'width: 22px;'
|
32 |
+
));
|
33 |
+
new Unit($this, $this->name . '-2', false, '', array(
|
34 |
+
'units' => array(
|
35 |
+
'px' => 'px',
|
36 |
+
'%' => '%'
|
37 |
+
)
|
38 |
+
));
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @param AbstractField $element
|
43 |
+
*
|
44 |
+
* @return string
|
45 |
+
*/
|
46 |
+
public function decorateElement($element) {
|
47 |
+
|
48 |
+
$elementHtml = $element->render();
|
49 |
+
|
50 |
+
return $elementHtml[1];
|
51 |
+
}
|
52 |
+
|
53 |
+
protected function decorate($html) {
|
54 |
+
|
55 |
+
return '<div class="n2_field_mixed_font_size__container" style="' . $this->style . '">' . $html . '</div>';
|
56 |
+
}
|
57 |
+
}
|
Nextend/Framework/Form/Element/Mixed/GeneratorOrder.php
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Mixed;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Mixed;
|
8 |
+
use Nextend\Framework\Form\Element\Radio;
|
9 |
+
use Nextend\Framework\Form\Element\Select;
|
10 |
+
|
11 |
+
class GeneratorOrder extends Mixed {
|
12 |
+
|
13 |
+
protected $rowClass = 'n2_field_mixed_generator_order ';
|
14 |
+
|
15 |
+
protected $options = array();
|
16 |
+
|
17 |
+
public function __construct($insertAt, $name = '', $default = '', $parameters = array()) {
|
18 |
+
parent::__construct($insertAt, $name, false, $default, $parameters);
|
19 |
+
|
20 |
+
new Select($this, $name . '-1', n2_('Field'), '', $this->options);
|
21 |
+
|
22 |
+
new Radio($this, $name . '-2', n2_('Order'), '', array(
|
23 |
+
'options' => array(
|
24 |
+
'asc' => n2_('Ascending'),
|
25 |
+
'desc' => n2_('Descending')
|
26 |
+
)
|
27 |
+
));
|
28 |
+
}
|
29 |
+
|
30 |
+
protected function decorate($html) {
|
31 |
+
|
32 |
+
return '<div class="n2_field_mixed_generator_order__container" style="' . $this->style . '">' . $html . '</div>';
|
33 |
+
}
|
34 |
+
|
35 |
+
protected function setOptions($options) {
|
36 |
+
$this->options = array(
|
37 |
+
'options' => $options
|
38 |
+
);
|
39 |
+
}
|
40 |
+
}
|
Nextend/Framework/Form/Element/Mixed/TextShadow.php
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Mixed;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\Form\Element\Mixed;
|
9 |
+
use Nextend\Framework\Form\Element\Text\Color;
|
10 |
+
use Nextend\Framework\Form\Element\Text\NumberAutoComplete;
|
11 |
+
|
12 |
+
class TextShadow extends Mixed {
|
13 |
+
|
14 |
+
protected $rowClass = 'n2_field_mixed_text_shadow ';
|
15 |
+
|
16 |
+
public function __construct($insertAt, $name = '', $label = '', $default = '', $parameters = array()) {
|
17 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
18 |
+
|
19 |
+
for ($i = 1; $i < 4; $i++) {
|
20 |
+
new NumberAutoComplete($this, $this->name . '-' . $i, false, 0, array(
|
21 |
+
'wide' => 3
|
22 |
+
));
|
23 |
+
}
|
24 |
+
new Color($this, $this->name . '-4', false, '', array(
|
25 |
+
'alpha' => true
|
26 |
+
));
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @param AbstractField $element
|
31 |
+
*
|
32 |
+
* @return string
|
33 |
+
*/
|
34 |
+
public function decorateElement($element) {
|
35 |
+
|
36 |
+
$elementHtml = $element->render();
|
37 |
+
|
38 |
+
return $elementHtml[1];
|
39 |
+
}
|
40 |
+
|
41 |
+
protected function decorate($html) {
|
42 |
+
|
43 |
+
return '<div class="n2_field_mixed_text_shadow__container" style="' . $this->style . '">' . $html . '</div>';
|
44 |
+
}
|
45 |
+
}
|
Nextend/Framework/Form/Element/OnOff.php
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
|
7 |
+
class OnOff extends AbstractFieldHidden {
|
8 |
+
|
9 |
+
protected $relatedFieldsOn = array();
|
10 |
+
|
11 |
+
protected $relatedAttribute = '';
|
12 |
+
|
13 |
+
protected $values = array(
|
14 |
+
0 => 0,
|
15 |
+
1 => 1
|
16 |
+
);
|
17 |
+
|
18 |
+
protected $customValues = false;
|
19 |
+
|
20 |
+
protected function fetchElement() {
|
21 |
+
|
22 |
+
$html = '<div class="n2_field_onoff' . $this->isOn() . '">' . parent::fetchElement() . '<div class="n2_field_onoff__slider"><div class="n2_field_onoff__slider_bullet"></div></div><div class="n2_field_onoff__labels"><div class="n2_field_onoff__label n2_field_onoff__label_off">' . n2_('Off') . '</div><div class="n2_field_onoff__label n2_field_onoff__label_on">' . n2_('On') . '</div></div></div>';
|
23 |
+
|
24 |
+
$options = array();
|
25 |
+
|
26 |
+
if ($this->customValues) {
|
27 |
+
$options['values'] = $this->customValues;
|
28 |
+
}
|
29 |
+
if (!empty($this->relatedFieldsOff)) {
|
30 |
+
$options['relatedFieldsOff'] = $this->relatedFieldsOff;
|
31 |
+
}
|
32 |
+
if (!empty($this->relatedFieldsOn)) {
|
33 |
+
$options['relatedFieldsOn'] = $this->relatedFieldsOn;
|
34 |
+
}
|
35 |
+
if (!empty($this->relatedAttribute)) {
|
36 |
+
$options['relatedAttribute'] = $this->relatedAttribute;
|
37 |
+
}
|
38 |
+
|
39 |
+
Js::addInline('new N2Classes.FormElementOnoff("' . $this->fieldID . '", ' . json_encode($options) . ');');
|
40 |
+
|
41 |
+
return $html;
|
42 |
+
}
|
43 |
+
|
44 |
+
private function isOn() {
|
45 |
+
$value = $this->getValue();
|
46 |
+
if (($this->customValues && $this->customValues[$value]) || (!$this->customValues && $value)) {
|
47 |
+
return ' n2_field_onoff--on';
|
48 |
+
}
|
49 |
+
|
50 |
+
return '';
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @param array $relatedFields
|
55 |
+
*/
|
56 |
+
public function setRelatedFieldsOn($relatedFields) {
|
57 |
+
$this->relatedFieldsOn = $relatedFields;
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @param array $relatedFields
|
62 |
+
*/
|
63 |
+
public function setRelatedFieldsOff($relatedFields) {
|
64 |
+
$this->relatedFieldsOff = $relatedFields;
|
65 |
+
}
|
66 |
+
|
67 |
+
public function setRelatedAttribute($relatedAttribute) {
|
68 |
+
$this->relatedAttribute = $relatedAttribute;
|
69 |
+
}
|
70 |
+
|
71 |
+
public function setCustomValues($offValue = 0, $onValue = 1) {
|
72 |
+
|
73 |
+
if ($offValue === 0 && $onValue === 1) {
|
74 |
+
$this->customValues = false;
|
75 |
+
} else {
|
76 |
+
$this->customValues = array();
|
77 |
+
$this->customValues[$offValue] = 0;
|
78 |
+
$this->customValues[$onValue] = 1;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
public function setInvert($isInvert) {
|
83 |
+
if ($isInvert) {
|
84 |
+
$this->setCustomValues(1, 0);
|
85 |
+
} else {
|
86 |
+
$this->setCustomValues(0, 1);
|
87 |
+
}
|
88 |
+
}
|
89 |
+
}
|
Nextend/Framework/Form/Element/Radio.php
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
use Nextend\Framework\Asset\Js\Js;
|
7 |
+
use Nextend\Framework\View\Html;
|
8 |
+
|
9 |
+
class Radio extends AbstractFieldHidden {
|
10 |
+
|
11 |
+
protected $options = array();
|
12 |
+
|
13 |
+
protected $class = 'n2_field_radio';
|
14 |
+
|
15 |
+
protected $style = '';
|
16 |
+
|
17 |
+
protected $value;
|
18 |
+
|
19 |
+
protected function addScript() {
|
20 |
+
Js::addInline('new N2Classes.FormElementRadio("' . $this->fieldID . '", ' . json_encode(array_keys($this->options)) . ', ' . json_encode($this->relatedFields) . ');');
|
21 |
+
}
|
22 |
+
|
23 |
+
protected function fetchElement() {
|
24 |
+
|
25 |
+
$this->value = $this->getValue();
|
26 |
+
|
27 |
+
$html = Html::tag('div', array(
|
28 |
+
'class' => $this->class,
|
29 |
+
'style' => $this->style
|
30 |
+
), $this->renderOptions() . parent::fetchElement());
|
31 |
+
|
32 |
+
$this->addScript();
|
33 |
+
|
34 |
+
return $html;
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @return string
|
39 |
+
*/
|
40 |
+
protected function renderOptions() {
|
41 |
+
|
42 |
+
$html = '';
|
43 |
+
$i = 0;
|
44 |
+
foreach ($this->options AS $value => $label) {
|
45 |
+
$html .= Html::tag('div', array(
|
46 |
+
'class' => 'n2_field_radio__option' . ($this->isSelected($value) ? ' n2_field_radio__option--selected' : '')
|
47 |
+
), Html::tag('div', array(
|
48 |
+
'class' => 'n2_field_radio__option_marker'
|
49 |
+
), '<i class="ssi_16 ssi_16--check"></i>') . '<div class="n2_field_radio__option_label">' . $label . '</div>');
|
50 |
+
$i++;
|
51 |
+
}
|
52 |
+
|
53 |
+
return $html;
|
54 |
+
}
|
55 |
+
|
56 |
+
function isSelected($value) {
|
57 |
+
if ((string)$value == $this->value) {
|
58 |
+
return true;
|
59 |
+
}
|
60 |
+
|
61 |
+
return false;
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @param array $options
|
66 |
+
*/
|
67 |
+
public function setOptions($options) {
|
68 |
+
$this->options = $options;
|
69 |
+
}
|
70 |
+
|
71 |
+
public function setStyle($style) {
|
72 |
+
$this->style = $style;
|
73 |
+
}
|
74 |
+
}
|
Nextend/Framework/Form/Element/Radio/AbstractRadioIcon.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Radio;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Radio;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
abstract class AbstractRadioIcon extends Radio {
|
11 |
+
|
12 |
+
protected $class = 'n2_field_radio_icon';
|
13 |
+
|
14 |
+
protected function renderOptions() {
|
15 |
+
|
16 |
+
$html = '';
|
17 |
+
$i = 0;
|
18 |
+
foreach ($this->options AS $value => $class) {
|
19 |
+
|
20 |
+
$html .= Html::tag('div', array(
|
21 |
+
'class' => 'n2_field_radio__option' . ($this->isSelected($value) ? ' n2_field_radio__option--selected' : '')
|
22 |
+
), Html::tag('i', array('class' => $class)));
|
23 |
+
$i++;
|
24 |
+
}
|
25 |
+
|
26 |
+
return $html;
|
27 |
+
}
|
28 |
+
}
|
Nextend/Framework/Form/Element/Radio/ImageList.php
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Radio;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Element\AbstractFieldHidden;
|
9 |
+
use Nextend\Framework\Localization\Localization;
|
10 |
+
use Nextend\Framework\Url\Url;
|
11 |
+
use Nextend\Framework\View\Html;
|
12 |
+
|
13 |
+
abstract class ImageList extends AbstractFieldHidden {
|
14 |
+
|
15 |
+
protected $hasDisabled = true;
|
16 |
+
|
17 |
+
protected $width = 44;
|
18 |
+
|
19 |
+
protected $column = 5;
|
20 |
+
|
21 |
+
protected $options = array();
|
22 |
+
|
23 |
+
protected function fetchElement() {
|
24 |
+
|
25 |
+
$jsParameters = array(
|
26 |
+
'width' => $this->width
|
27 |
+
);
|
28 |
+
|
29 |
+
if ($this->hasDisabled) {
|
30 |
+
$jsParameters['hasDisabled'] = true;
|
31 |
+
}
|
32 |
+
|
33 |
+
$html = Html::openTag("div", array(
|
34 |
+
'class' => 'n2_field_image_list',
|
35 |
+
'style' => $this->style
|
36 |
+
));
|
37 |
+
|
38 |
+
$html .= parent::fetchElement();
|
39 |
+
$html .= '<div class="n2_field_image_list__preview">';
|
40 |
+
|
41 |
+
$html .= '</div>';
|
42 |
+
$html .= '<i class="n2_field_image_list__arrow ssi_16 ssi_16--selectarrow"></i>';
|
43 |
+
|
44 |
+
$html .= $this->postHTML();
|
45 |
+
|
46 |
+
$html .= Html::closeTag('div');
|
47 |
+
|
48 |
+
$frontendOptions = array();
|
49 |
+
foreach ($this->options as $key => $option) {
|
50 |
+
$frontendOptions[$key] = array(
|
51 |
+
'url' => Url::pathToUri($option['path'])
|
52 |
+
);
|
53 |
+
|
54 |
+
if (!empty($option['label'])) {
|
55 |
+
$frontendOptions[$key]['label'] = $option['label'];
|
56 |
+
}
|
57 |
+
}
|
58 |
+
|
59 |
+
$jsParameters['column'] = min($this->column, count($this->options) + ($this->hasDisabled ? 1 : 0));
|
60 |
+
$jsParameters['options'] = $frontendOptions;
|
61 |
+
|
62 |
+
Js::addInline('new N2Classes.FormElementImageList("' . $this->fieldID . '", ' . json_encode($jsParameters) . ', ' . json_encode($this->relatedFields) . ');');
|
63 |
+
|
64 |
+
return $html;
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* @param bool $hasDisabled
|
69 |
+
*/
|
70 |
+
public function setHasDisabled($hasDisabled) {
|
71 |
+
$this->hasDisabled = $hasDisabled;
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* @param int $width
|
76 |
+
*/
|
77 |
+
public function setWidth($width) {
|
78 |
+
$this->width = $width;
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* @param int $column
|
83 |
+
*/
|
84 |
+
public function setColumn($column) {
|
85 |
+
$this->column = $column;
|
86 |
+
}
|
87 |
+
|
88 |
+
protected function postHTML() {
|
89 |
+
return '';
|
90 |
+
}
|
91 |
+
}
|
Nextend/Framework/Form/Element/Radio/ImageListFromFolder.php
ADDED
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element\Radio;
|
4 |
+
|
5 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
6 |
+
use Nextend\Framework\Form\AbstractField;
|
7 |
+
use Nextend\Framework\Form\ContainerInterface;
|
8 |
+
use Nextend\Framework\Form\TraitFieldset;
|
9 |
+
|
10 |
+
class ImageListFromFolder extends ImageList implements ContainerInterface {
|
11 |
+
|
12 |
+
use TraitFieldset;
|
13 |
+
|
14 |
+
protected $folder = '';
|
15 |
+
|
16 |
+
protected $filenameOnly = false;
|
17 |
+
|
18 |
+
protected function fetchElement() {
|
19 |
+
|
20 |
+
$this->initOptions();
|
21 |
+
|
22 |
+
return parent::fetchElement();
|
23 |
+
}
|
24 |
+
|
25 |
+
private function initOptions() {
|
26 |
+
|
27 |
+
$value = $this->getValue();
|
28 |
+
$currentValue = basename($value);
|
29 |
+
if ($value !== $currentValue) {
|
30 |
+
$this->setValue($currentValue);
|
31 |
+
}
|
32 |
+
|
33 |
+
|
34 |
+
$files = Filesystem::files($this->folder);
|
35 |
+
for ($i = 0; $i < count($files); $i++) {
|
36 |
+
$ext = pathinfo($files[$i], PATHINFO_EXTENSION);
|
37 |
+
$extensions = array(
|
38 |
+
'jpg',
|
39 |
+
'jpeg',
|
40 |
+
'png',
|
41 |
+
'svg',
|
42 |
+
'gif',
|
43 |
+
'webp'
|
44 |
+
);
|
45 |
+
if (in_array($ext, $extensions)) {
|
46 |
+
|
47 |
+
$path = $this->folder . $files[$i];
|
48 |
+
|
49 |
+
if ($this->filenameOnly) {
|
50 |
+
$value = pathinfo($files[$i], PATHINFO_FILENAME);
|
51 |
+
} else {
|
52 |
+
$value = basename($files[$i]);
|
53 |
+
}
|
54 |
+
|
55 |
+
$this->options[$value] = array(
|
56 |
+
'path' => $path
|
57 |
+
);
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
if (!isset($this->options[$currentValue])) {
|
62 |
+
foreach ($this->options AS $value => $option) {
|
63 |
+
if (pathinfo($value, PATHINFO_FILENAME) == $currentValue) {
|
64 |
+
$currentValue = $value;
|
65 |
+
$this->setValue($currentValue);
|
66 |
+
}
|
67 |
+
}
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
protected function postHTML() {
|
72 |
+
if ($this->first) {
|
73 |
+
$html = '<div class="n2_field_image_list__fields">';
|
74 |
+
|
75 |
+
$element = $this->first;
|
76 |
+
while ($element) {
|
77 |
+
$html .= $this->decorateElement($element);
|
78 |
+
|
79 |
+
$element = $element->getNext();
|
80 |
+
}
|
81 |
+
|
82 |
+
$html .= '</div>';
|
83 |
+
|
84 |
+
return $html;
|
85 |
+
}
|
86 |
+
|
87 |
+
return '';
|
88 |
+
}
|
89 |
+
|
90 |
+
public function setFolder($folder) {
|
91 |
+
$this->folder = $folder;
|
92 |
+
}
|
93 |
+
|
94 |
+
public function setFilenameOnly($value) {
|
95 |
+
$this->filenameOnly = $value;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* @param AbstractField $element
|
100 |
+
*
|
101 |
+
* @return string
|
102 |
+
*/
|
103 |
+
public function decorateElement($element) {
|
104 |
+
$html = '<div class="n2_field">';
|
105 |
+
$html .= '<div class="n2_field__label">';
|
106 |
+
$html .= $element->fetchTooltip();
|
107 |
+
$html .= '</div>';
|
108 |
+
$html .= '<div class="n2_field__element">';
|
109 |
+
$html .= $element->fetchElement();
|
110 |
+
$html .= '</div>';
|
111 |
+
$html .= '</div>';
|
112 |
+
|
113 |
+
return $html;
|
114 |
+
}
|
115 |
+
}
|
Nextend/Framework/Form/Element/Radio/TextAlign.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element\Radio;
|
4 |
+
|
5 |
+
class TextAlign extends AbstractRadioIcon {
|
6 |
+
|
7 |
+
protected $options = array(
|
8 |
+
'inherit' => 'ssi_16 ssi_16--none',
|
9 |
+
'left' => 'ssi_16 ssi_16--textleft',
|
10 |
+
'center' => 'ssi_16 ssi_16--textcenter',
|
11 |
+
'right' => 'ssi_16 ssi_16--textright',
|
12 |
+
'justify' => 'ssi_16 ssi_16--textjustify'
|
13 |
+
);
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @param $excluded array
|
17 |
+
*/
|
18 |
+
public function setExcludeOptions($excluded) {
|
19 |
+
foreach ($excluded AS $exclude) {
|
20 |
+
if (isset($this->options[$exclude])) {
|
21 |
+
unset($this->options[$exclude]);
|
22 |
+
}
|
23 |
+
|
24 |
+
}
|
25 |
+
}
|
26 |
+
}
|
Nextend/Framework/Form/Element/RichTextarea.php
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\AbstractField;
|
9 |
+
use Nextend\Framework\View\Html;
|
10 |
+
|
11 |
+
class RichTextarea extends AbstractField {
|
12 |
+
|
13 |
+
protected $fieldStyle = '';
|
14 |
+
|
15 |
+
protected function fetchElement() {
|
16 |
+
|
17 |
+
Js::addInline('new N2Classes.FormElementRichText("' . $this->fieldID . '");');
|
18 |
+
|
19 |
+
$tools = array(
|
20 |
+
Html::tag('div', array(
|
21 |
+
'class' => 'n2_field_textarea_rich__button',
|
22 |
+
'data-action' => 'bold'
|
23 |
+
), Html::tag('I', array('class' => 'ssi_16 ssi_16--bold'))),
|
24 |
+
Html::tag('div', array(
|
25 |
+
'class' => 'n2_field_textarea_rich__button',
|
26 |
+
'data-action' => 'italic'
|
27 |
+
), Html::tag('I', array('class' => 'ssi_16 ssi_16--italic'))),
|
28 |
+
Html::tag('div', array(
|
29 |
+
'class' => 'n2_field_textarea_rich__button',
|
30 |
+
'data-action' => 'link'
|
31 |
+
), Html::tag('I', array('class' => 'ssi_16 ssi_16--link')))
|
32 |
+
);
|
33 |
+
|
34 |
+
$buttons = Html::tag('div', array(
|
35 |
+
'class' => 'n2_field_textarea_rich__buttons'
|
36 |
+
), implode('', $tools));
|
37 |
+
|
38 |
+
return Html::tag('div', array(
|
39 |
+
'class' => 'n2_field_textarea_rich',
|
40 |
+
'style' => $this->style
|
41 |
+
), $buttons . Html::tag('textarea', array(
|
42 |
+
'id' => $this->fieldID,
|
43 |
+
'name' => $this->getFieldName(),
|
44 |
+
'autocomplete' => 'off',
|
45 |
+
'style' => $this->fieldStyle
|
46 |
+
), $this->getValue()));
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* @param string $fieldStyle
|
51 |
+
*/
|
52 |
+
public function setFieldStyle($fieldStyle) {
|
53 |
+
$this->fieldStyle = $fieldStyle;
|
54 |
+
}
|
55 |
+
}
|
Nextend/Framework/Form/Element/Select.php
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class Select extends AbstractFieldHidden {
|
11 |
+
|
12 |
+
public $value;
|
13 |
+
|
14 |
+
protected $values = array();
|
15 |
+
protected $options = array();
|
16 |
+
protected $optgroup = array();
|
17 |
+
protected $isMultiple = false;
|
18 |
+
protected $size = '';
|
19 |
+
|
20 |
+
protected $relatedValueFields = array();
|
21 |
+
protected $relatedAttribute = '';
|
22 |
+
|
23 |
+
protected function fetchElement() {
|
24 |
+
|
25 |
+
$this->values = explode('||', $this->getValue());
|
26 |
+
if (!is_array($this->values)) {
|
27 |
+
$this->values = array();
|
28 |
+
}
|
29 |
+
|
30 |
+
$html = Html::openTag("div", array(
|
31 |
+
"class" => "n2_field_select",
|
32 |
+
"style" => $this->style
|
33 |
+
));
|
34 |
+
|
35 |
+
$selectAttributes = array(
|
36 |
+
'id' => $this->fieldID . '_select',
|
37 |
+
'name' => 'select' . $this->getFieldName(),
|
38 |
+
'autocomplete' => 'off'
|
39 |
+
);
|
40 |
+
|
41 |
+
if (!empty($this->size)) {
|
42 |
+
$selectAttributes['size'] = $this->size;
|
43 |
+
}
|
44 |
+
|
45 |
+
if ($this->isMultiple) {
|
46 |
+
$selectAttributes['multiple'] = 'multiple';
|
47 |
+
$selectAttributes['class'] = 'nextend-element-hastip';
|
48 |
+
$selectAttributes['title'] = n2_('Hold down the ctrl (Windows) or command (MAC) button to select multiple options.');
|
49 |
+
}
|
50 |
+
|
51 |
+
$html .= Html::tag('select', $selectAttributes, $this->renderOptions($this->options) . (!empty($this->optgroup) ? $this->renderOptgroup() : ''));
|
52 |
+
|
53 |
+
$html .= Html::closeTag("div");
|
54 |
+
|
55 |
+
$html .= parent::fetchElement();
|
56 |
+
|
57 |
+
$options = array();
|
58 |
+
|
59 |
+
if (!empty($this->relatedFields)) {
|
60 |
+
$options['relatedFields'] = $this->relatedFields;
|
61 |
+
}
|
62 |
+
|
63 |
+
if (!empty($this->relatedValueFields)) {
|
64 |
+
$options['relatedValueFields'] = $this->relatedValueFields;
|
65 |
+
}
|
66 |
+
|
67 |
+
if (!empty($this->relatedAttribute)) {
|
68 |
+
$options['relatedAttribute'] = $this->relatedAttribute;
|
69 |
+
}
|
70 |
+
|
71 |
+
Js::addInline('new N2Classes.FormElementList("' . $this->fieldID . '", ' . json_encode($options) . ');');
|
72 |
+
|
73 |
+
return $html;
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
*
|
78 |
+
* @return string
|
79 |
+
*/
|
80 |
+
protected function renderOptgroup() {
|
81 |
+
$html = '';
|
82 |
+
foreach ($this->optgroup AS $label => $options) {
|
83 |
+
if (is_array($options)) {
|
84 |
+
$html .= "<optgroup label='" . $label . "'>";
|
85 |
+
$html .= $this->renderOptions($options);
|
86 |
+
$html .= "</optgroup>";
|
87 |
+
} else {
|
88 |
+
$html .= $this->renderOption($label, $options);
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
return $html;
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* @param array $options
|
97 |
+
*
|
98 |
+
* @return string
|
99 |
+
*/
|
100 |
+
protected function renderOptions($options) {
|
101 |
+
$html = '';
|
102 |
+
foreach ($options AS $value => $label) {
|
103 |
+
$html .= $this->renderOption($value, $label);
|
104 |
+
}
|
105 |
+
|
106 |
+
return $html;
|
107 |
+
}
|
108 |
+
|
109 |
+
protected function renderOption($value, $label) {
|
110 |
+
|
111 |
+
return '<option value="' . $value . '" ' . $this->isSelected($value) . '>' . $label . '</option>';
|
112 |
+
}
|
113 |
+
|
114 |
+
protected function isSelected($value) {
|
115 |
+
if (in_array($value, $this->values)) {
|
116 |
+
return ' selected="selected"';
|
117 |
+
}
|
118 |
+
|
119 |
+
return '';
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* @param array $options
|
124 |
+
*/
|
125 |
+
public function setOptions($options) {
|
126 |
+
|
127 |
+
$this->options = $options;
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* @param array $optgroup
|
132 |
+
*/
|
133 |
+
public function setOptgroup($optgroup) {
|
134 |
+
$this->optgroup = $optgroup;
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* @param bool $isMultiple
|
139 |
+
*/
|
140 |
+
public function setIsMultiple($isMultiple) {
|
141 |
+
$this->isMultiple = $isMultiple;
|
142 |
+
$this->size = 10;
|
143 |
+
}
|
144 |
+
|
145 |
+
/**
|
146 |
+
* @param string $size
|
147 |
+
*/
|
148 |
+
public function setSize($size) {
|
149 |
+
$this->size = $size;
|
150 |
+
}
|
151 |
+
|
152 |
+
protected function createTree(&$list, &$new, $parent, $cindent = '', $indent = '- ') {
|
153 |
+
|
154 |
+
if (isset($new[$parent])) {
|
155 |
+
for ($i = 0; $i < count($new[$parent]); $i++) {
|
156 |
+
$new[$parent][$i]->treename = $cindent . $new[$parent][$i]->name;
|
157 |
+
$list[] = $new[$parent][$i];
|
158 |
+
$this->createTree($list, $new, $new[$parent][$i]->cat_ID, $cindent . $indent, $indent);
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
return $list;
|
163 |
+
}
|
164 |
+
|
165 |
+
public function setRelatedValueFields($relatedValueFields) {
|
166 |
+
$this->relatedValueFields = $relatedValueFields;
|
167 |
+
}
|
168 |
+
|
169 |
+
public function setRelatedAttribute($relatedAttribute) {
|
170 |
+
$this->relatedAttribute = $relatedAttribute;
|
171 |
+
}
|
172 |
+
}
|
Nextend/Framework/Form/Element/Select/Easing.php
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Select;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Select;
|
8 |
+
|
9 |
+
class Easing extends Select {
|
10 |
+
|
11 |
+
protected $options = array(
|
12 |
+
"linear" => "Linear",
|
13 |
+
"easeInQuad" => "Quad In",
|
14 |
+
"easeOutQuad" => "Quad Out",
|
15 |
+
"easeInOutQuad" => "Quad In Out",
|
16 |
+
"easeInCubic" => "Cubic In",
|
17 |
+
"easeOutCubic" => "Cubic Out",
|
18 |
+
"easeInOutCubic" => "Cubic In Out",
|
19 |
+
"easeInQuart" => "Quart In",
|
20 |
+
"easeOutQuart" => "Quart Out",
|
21 |
+
"easeInOutQuart" => "Quart In Out",
|
22 |
+
"easeInQuint" => "Quint In",
|
23 |
+
"easeOutQuint" => "Quint Out",
|
24 |
+
"easeInOutQuint" => "Quint In Out",
|
25 |
+
"easeInSine" => "Sine In",
|
26 |
+
"easeOutSine" => "Sine Out",
|
27 |
+
"easeInOutSine" => "Sine In Out",
|
28 |
+
"easeInExpo" => "Expo In",
|
29 |
+
"easeOutExpo" => "Expo Out",
|
30 |
+
"easeInOutExpo" => "Expo In Out",
|
31 |
+
"easeInCirc" => "Circ In",
|
32 |
+
"easeOutCirc" => "Circ Out",
|
33 |
+
"easeInOutCirc" => "Circ In Out",
|
34 |
+
"easeInElastic" => "Elastic In",
|
35 |
+
"easeOutElastic" => "Elastic Out",
|
36 |
+
"easeInOutElastic" => "Elastic In Out",
|
37 |
+
"easeInBack" => "Back In",
|
38 |
+
"easeOutBack" => "Back Out",
|
39 |
+
"easeInOutBack" => "Back In Out",
|
40 |
+
"easeInBounce" => "Bounce In",
|
41 |
+
"easeOutBounce" => "Bounce Out",
|
42 |
+
"easeInOutBounce" => "Bounce In Out"
|
43 |
+
);
|
44 |
+
}
|
Nextend/Framework/Form/Element/Select/FillMode.php
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Select;
|
5 |
+
|
6 |
+
use Nextend\Framework\Form\Element\Select;
|
7 |
+
|
8 |
+
class FillMode extends Select {
|
9 |
+
|
10 |
+
protected $useGlobal = false;
|
11 |
+
|
12 |
+
protected function fetchElement() {
|
13 |
+
|
14 |
+
$this->options = array(
|
15 |
+
'fill' => n2_('Fill'),
|
16 |
+
'blurfit' => n2_('Blur fit'),
|
17 |
+
'fit' => n2_('Fit'),
|
18 |
+
'stretch' => n2_('Stretch'),
|
19 |
+
'center' => n2_('Center'),
|
20 |
+
'tile' => n2_('Tile')
|
21 |
+
|
22 |
+
);
|
23 |
+
|
24 |
+
if ($this->useGlobal) {
|
25 |
+
$this->options = array_merge(array(
|
26 |
+
'default' => n2_('Slider\'s default')
|
27 |
+
), $this->options);
|
28 |
+
}
|
29 |
+
|
30 |
+
return parent::fetchElement();
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* @param bool $useGlobal
|
35 |
+
*/
|
36 |
+
public function setUseGlobal($useGlobal) {
|
37 |
+
$this->useGlobal = $useGlobal;
|
38 |
+
}
|
39 |
+
}
|
Nextend/Framework/Form/Element/Select/Filter.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Select;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Select;
|
8 |
+
|
9 |
+
class Filter extends Select {
|
10 |
+
|
11 |
+
public function __construct($insertAt, $name = '', $label = '', $default = '', $parameters = array()) {
|
12 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
13 |
+
|
14 |
+
$no_label = strtolower($this->label);
|
15 |
+
|
16 |
+
$this->options = array(
|
17 |
+
'0' => n2_('All'),
|
18 |
+
'1' => $this->label,
|
19 |
+
'-1' => sprintf(n2_('Not %s'), $no_label)
|
20 |
+
);
|
21 |
+
}
|
22 |
+
}
|
Nextend/Framework/Form/Element/Select/FontWeight.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Select;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Select;
|
8 |
+
|
9 |
+
class FontWeight extends Select {
|
10 |
+
|
11 |
+
public function __construct($insertAt, $name = '', $label = false, $default = '', $parameters = array()) {
|
12 |
+
$this->options = array(
|
13 |
+
'0' => n2_('Normal'),
|
14 |
+
'1' => n2_('Bold'),
|
15 |
+
'100' => '100',
|
16 |
+
'200' => '200 - ' . n2_('Extra light'),
|
17 |
+
'300' => '300 - ' . n2_('Light'),
|
18 |
+
'400' => '400 - ' . n2_('Normal'),
|
19 |
+
'500' => '500',
|
20 |
+
'600' => '600 - ' . n2_('Semi bold'),
|
21 |
+
'700' => '700 - ' . n2_('Bold'),
|
22 |
+
'800' => '800 - ' . n2_('Extra bold'),
|
23 |
+
'900' => '900'
|
24 |
+
);
|
25 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
26 |
+
}
|
27 |
+
}
|
Nextend/Framework/Form/Element/Select/Gradient.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Select;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Select;
|
8 |
+
|
9 |
+
class Gradient extends Select {
|
10 |
+
|
11 |
+
public function __construct($insertAt, $name = '', $label = '', $default = '', $parameters = array()) {
|
12 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
13 |
+
|
14 |
+
$this->options = array(
|
15 |
+
'off' => n2_('Off'),
|
16 |
+
'vertical' => '↓',
|
17 |
+
'horizontal' => '→',
|
18 |
+
'diagonal1' => '↗',
|
19 |
+
'diagonal2' => '↘'
|
20 |
+
);
|
21 |
+
}
|
22 |
+
}
|
Nextend/Framework/Form/Element/Select/LinkTarget.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Select;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Select;
|
8 |
+
|
9 |
+
class LinkTarget extends Select {
|
10 |
+
|
11 |
+
public function __construct($insertAt, $name = '', $label = '', $default = '_self', array $parameters = array()) {
|
12 |
+
$this->options = array(
|
13 |
+
'_self' => n2_('Self'),
|
14 |
+
'_blank' => n2_('New'),
|
15 |
+
'_parent' => n2_('Parent'),
|
16 |
+
'_top' => n2_('Top')
|
17 |
+
);
|
18 |
+
|
19 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
20 |
+
}
|
21 |
+
}
|
Nextend/Framework/Form/Element/Select/SelectFile.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Select;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Select;
|
8 |
+
use Nextend\Framework\Platform\Platform;
|
9 |
+
|
10 |
+
class SelectFile extends Select {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* File constructor.
|
14 |
+
*
|
15 |
+
* @param $insertAt
|
16 |
+
* @param string $name
|
17 |
+
* @param string $label
|
18 |
+
* @param string $default
|
19 |
+
* @param string $extension
|
20 |
+
* @param array $parameters
|
21 |
+
*
|
22 |
+
*/
|
23 |
+
public function __construct($insertAt, $name = '', $label = '', $default = '', $extension = '', $parameters = array()) {
|
24 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
25 |
+
|
26 |
+
$dir = Platform::getPublicDirectory();
|
27 |
+
$files = scandir($dir);
|
28 |
+
$validated_files = array();
|
29 |
+
|
30 |
+
foreach ($files as $file) {
|
31 |
+
if (strtolower(pathinfo($file, PATHINFO_EXTENSION)) == $extension) {
|
32 |
+
$validated_files[] = $file;
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
$this->options[''] = n2_('Choose');
|
37 |
+
|
38 |
+
foreach ($validated_files AS $f) {
|
39 |
+
$this->options[$f] = $f;
|
40 |
+
}
|
41 |
+
}
|
42 |
+
}
|
Nextend/Framework/Form/Element/Select/Skin.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Select;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Element\Select;
|
9 |
+
use Nextend\Framework\Localization\Localization;
|
10 |
+
|
11 |
+
class Skin extends Select {
|
12 |
+
|
13 |
+
protected $fixed = false;
|
14 |
+
|
15 |
+
protected function fetchElement() {
|
16 |
+
|
17 |
+
$html = parent::fetchElement();
|
18 |
+
|
19 |
+
Js::addInline('new N2Classes.FormElementSkin("' . $this->fieldID . '", "' . str_replace($this->name, '', $this->fieldID) . '", ' . json_encode($this->options) . ', ' . json_encode($this->fixed) . ');');
|
20 |
+
|
21 |
+
return $html;
|
22 |
+
}
|
23 |
+
|
24 |
+
protected function renderOptions($options) {
|
25 |
+
$html = '';
|
26 |
+
if (!$this->fixed) {
|
27 |
+
$html .= '<option value="0" selected="selected">' . n2_('Choose') . '</option>';
|
28 |
+
}
|
29 |
+
foreach ($options as $value => $option) {
|
30 |
+
$html .= '<option ' . $this->isSelected($value) . ' value="' . $value . '">' . $option['label'] . '</option>';
|
31 |
+
}
|
32 |
+
|
33 |
+
return $html;
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @param bool $fixed
|
38 |
+
*/
|
39 |
+
public function setFixed($fixed) {
|
40 |
+
$this->fixed = $fixed;
|
41 |
+
}
|
42 |
+
}
|
Nextend/Framework/Form/Element/Select/SubFormIcon.php
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Select;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Container\ContainerSubform;
|
9 |
+
use Nextend\Framework\Form\ContainerInterface;
|
10 |
+
use Nextend\Framework\Form\Element\AbstractFieldHidden;
|
11 |
+
use Nextend\Framework\Form\TraitFieldset;
|
12 |
+
use Nextend\Framework\View\Html;
|
13 |
+
|
14 |
+
abstract class SubFormIcon extends AbstractFieldHidden {
|
15 |
+
|
16 |
+
protected $ajaxUrl = '';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var ContainerSubform
|
20 |
+
*/
|
21 |
+
protected $containerSubform;
|
22 |
+
|
23 |
+
protected $plugins = array();
|
24 |
+
|
25 |
+
protected $options = array();
|
26 |
+
|
27 |
+
/**
|
28 |
+
* SubFormIcon constructor.
|
29 |
+
*
|
30 |
+
* @param TraitFieldset $insertAt
|
31 |
+
* @param string $name
|
32 |
+
* @param ContainerInterface $container
|
33 |
+
* @param string $ajaxUrl
|
34 |
+
* @param string $default
|
35 |
+
* @param array $parameters
|
36 |
+
*/
|
37 |
+
public function __construct($insertAt, $name, $container, $ajaxUrl, $default = '', $parameters = array()) {
|
38 |
+
|
39 |
+
$this->ajaxUrl = $ajaxUrl;
|
40 |
+
|
41 |
+
parent::__construct($insertAt, $name, '', $default, $parameters);
|
42 |
+
|
43 |
+
$this->loadOptions();
|
44 |
+
|
45 |
+
$this->containerSubform = new ContainerSubform($container, $name . '-subform');
|
46 |
+
|
47 |
+
$this->getCurrentPlugin($this->getValue())
|
48 |
+
->renderFields($this->containerSubform);
|
49 |
+
}
|
50 |
+
|
51 |
+
protected function fetchElement() {
|
52 |
+
|
53 |
+
$currentValue = $this->getValue();
|
54 |
+
|
55 |
+
Js::addInline('
|
56 |
+
new N2Classes.FormElementSubformIcon(
|
57 |
+
"' . $this->fieldID . '",
|
58 |
+
"' . $this->ajaxUrl . '",
|
59 |
+
"' . $this->containerSubform->getId() . '",
|
60 |
+
"' . $currentValue . '"
|
61 |
+
);
|
62 |
+
');
|
63 |
+
$html = Html::openTag('div', array(
|
64 |
+
'class' => 'n2_field_subform_icon'
|
65 |
+
));
|
66 |
+
foreach ($this->options AS $value => $option) {
|
67 |
+
$html .= Html::tag('div', array(
|
68 |
+
'class' => 'n2_field_subform_icon__option' . ($value == $currentValue ? ' n2_field_subform_icon__option--selected' : ''),
|
69 |
+
'data-value' => $value
|
70 |
+
), Html::tag('div', array(
|
71 |
+
'class' => 'n2_field_subform_icon__option_icon'
|
72 |
+
), '<i class="' . $option['icon'] . '"></i>') . Html::tag('div', array(
|
73 |
+
'class' => 'n2_field_subform_icon__option_label'
|
74 |
+
), $option['label']));
|
75 |
+
}
|
76 |
+
|
77 |
+
$html .= parent::fetchElement() . '</div>';
|
78 |
+
|
79 |
+
return $html;
|
80 |
+
}
|
81 |
+
|
82 |
+
protected abstract function loadOptions();
|
83 |
+
|
84 |
+
|
85 |
+
protected function getCurrentPlugin($value) {
|
86 |
+
|
87 |
+
if (!isset($this->plugins[$value])) {
|
88 |
+
list($value) = array_keys($this->plugins);
|
89 |
+
$this->setValue($value);
|
90 |
+
}
|
91 |
+
|
92 |
+
return $this->plugins[$value];
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* @param string $option
|
97 |
+
*/
|
98 |
+
public function removeOption($option) {
|
99 |
+
if (isset($this->options[$option])) {
|
100 |
+
unset($this->options[$option]);
|
101 |
+
|
102 |
+
if ($this->getValue() === $option) {
|
103 |
+
$this->setValue($this->defaultValue);
|
104 |
+
}
|
105 |
+
}
|
106 |
+
}
|
107 |
+
}
|
Nextend/Framework/Form/Element/SelectIcon.php
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class SelectIcon extends AbstractFieldHidden {
|
11 |
+
|
12 |
+
protected $options;
|
13 |
+
|
14 |
+
public function __construct($insertAt, $name = '', $label = false, $options = array(), $default = '', $parameters = array()) {
|
15 |
+
|
16 |
+
$this->options = $options;
|
17 |
+
|
18 |
+
parent::__construct($insertAt, $name, $label, $default, $parameters);
|
19 |
+
}
|
20 |
+
|
21 |
+
|
22 |
+
protected function fetchElement() {
|
23 |
+
|
24 |
+
$currentValue = $this->getValue();
|
25 |
+
|
26 |
+
$html = Html::openTag('div', array(
|
27 |
+
'class' => 'n2_field_select_icon'
|
28 |
+
));
|
29 |
+
|
30 |
+
foreach ($this->options AS $value => $option) {
|
31 |
+
|
32 |
+
$classes = array('n2_field_select_icon__option');
|
33 |
+
if ($currentValue == $value) {
|
34 |
+
$classes[] = 'n2_field_select_icon__option--selected';
|
35 |
+
}
|
36 |
+
|
37 |
+
$html .= Html::tag('div', array(
|
38 |
+
'class' => implode(' ', $classes),
|
39 |
+
'data-value' => $value
|
40 |
+
), Html::tag('div', array(
|
41 |
+
'class' => 'n2_field_select_icon__option_icon'
|
42 |
+
), '<i class="' . $option['icon'] . '"></i>') . Html::tag('div', array(
|
43 |
+
'class' => 'n2_field_select_icon__option_label'
|
44 |
+
), $option['label']) . Html::tag('div', array(
|
45 |
+
'class' => 'n2_field_select_icon__selected_marker'
|
46 |
+
), '<i class="ssi_16 ssi_16--check"></i>'));
|
47 |
+
}
|
48 |
+
|
49 |
+
$html .= Html::closeTag('div');
|
50 |
+
|
51 |
+
$html .= parent::fetchElement();
|
52 |
+
|
53 |
+
Js::addInline('new N2Classes.FormElementSelectIcon("' . $this->fieldID . '", ' . json_encode(array()) . ');');
|
54 |
+
|
55 |
+
return $html;
|
56 |
+
}
|
57 |
+
}
|
Nextend/Framework/Form/Element/Style.php
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
|
7 |
+
use Nextend\Framework\Style\StyleManager;
|
8 |
+
use Nextend\Framework\Style\StyleParser;
|
9 |
+
use Nextend\Framework\View\Html;
|
10 |
+
|
11 |
+
class Style extends AbstractFieldHidden {
|
12 |
+
|
13 |
+
protected $mode = '';
|
14 |
+
|
15 |
+
protected $font = '';
|
16 |
+
|
17 |
+
protected $font2 = '';
|
18 |
+
|
19 |
+
protected $style2 = '';
|
20 |
+
|
21 |
+
protected $preview = '';
|
22 |
+
|
23 |
+
protected $css = '';
|
24 |
+
|
25 |
+
protected function addScript() {
|
26 |
+
|
27 |
+
StyleManager::enqueue($this->getForm());
|
28 |
+
|
29 |
+
$preview = preg_replace_callback('/url\(\'(.*?)\'\)/', array(
|
30 |
+
$this,
|
31 |
+
'fixPreviewImages'
|
32 |
+
), $this->preview);
|
33 |
+
|
34 |
+
Js::addInline('new N2Classes.FormElementStyle("' . $this->fieldID . '", {
|
35 |
+
mode: "' . $this->mode . '",
|
36 |
+
label: "' . $this->label . '",
|
37 |
+
font: "' . $this->font . '",
|
38 |
+
font2: "' . $this->font2 . '",
|
39 |
+
style2: "' . $this->style2 . '",
|
40 |
+
preview: ' . json_encode($preview) . '
|
41 |
+
});');
|
42 |
+
}
|
43 |
+
|
44 |
+
protected function fetchElement() {
|
45 |
+
|
46 |
+
$this->addScript();
|
47 |
+
|
48 |
+
return Html::tag('div', array(
|
49 |
+
'class' => 'n2_field_style'
|
50 |
+
), n2_('Style') . parent::fetchElement());
|
51 |
+
}
|
52 |
+
|
53 |
+
public function fixPreviewImages($matches) {
|
54 |
+
return "url(" . ResourceTranslator::toUrl($matches[1]) . ")";
|
55 |
+
}
|
56 |
+
|
57 |
+
public function getValue() {
|
58 |
+
|
59 |
+
return StyleParser::parse(parent::getValue());
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @param string $mode
|
64 |
+
*/
|
65 |
+
public function setMode($mode) {
|
66 |
+
$this->mode = $mode;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @param string $font
|
71 |
+
*/
|
72 |
+
public function setFont($font) {
|
73 |
+
$this->font = $font;
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* @param string $font2
|
78 |
+
*/
|
79 |
+
public function setFont2($font2) {
|
80 |
+
$this->font2 = $font2;
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* @param string $style2
|
85 |
+
*/
|
86 |
+
public function setStyle2($style2) {
|
87 |
+
$this->style2 = $style2;
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* @param string $preview
|
92 |
+
*/
|
93 |
+
public function setPreview($preview) {
|
94 |
+
$this->preview = $preview;
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* @param string $css
|
99 |
+
*/
|
100 |
+
public function setCss($css) {
|
101 |
+
$this->css = $css;
|
102 |
+
}
|
103 |
+
}
|
Nextend/Framework/Form/Element/Tab.php
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class Tab extends AbstractFieldHidden {
|
11 |
+
|
12 |
+
protected $options = array();
|
13 |
+
protected $relatedValueFields = array();
|
14 |
+
|
15 |
+
protected function fetchElement() {
|
16 |
+
|
17 |
+
if (empty($this->defaultValue) && !empty($this->options)) {
|
18 |
+
$this->defaultValue = array_keys($this->options)[0];
|
19 |
+
}
|
20 |
+
|
21 |
+
$html = Html::openTag("div", array(
|
22 |
+
"id" => $this->fieldID . "_tab",
|
23 |
+
"class" => "n2_field_tab",
|
24 |
+
"style" => $this->style
|
25 |
+
));
|
26 |
+
|
27 |
+
$html .= $this->renderOptions();
|
28 |
+
|
29 |
+
$html .= Html::closeTag("div");
|
30 |
+
|
31 |
+
$html .= parent::fetchElement();
|
32 |
+
|
33 |
+
Js::addInline('new N2Classes.FormElementTab("' . $this->fieldID . '", ' . json_encode($this->relatedValueFields) . ');');
|
34 |
+
|
35 |
+
return $html;
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @param array $options
|
40 |
+
*/
|
41 |
+
public function setOptions($options) {
|
42 |
+
|
43 |
+
$this->options = $options;
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* @param $relatedValueFields
|
48 |
+
*/
|
49 |
+
public function setRelatedValueFields($relatedValueFields) {
|
50 |
+
$this->relatedValueFields = $relatedValueFields;
|
51 |
+
}
|
52 |
+
|
53 |
+
public function renderOptions() {
|
54 |
+
$html = '';
|
55 |
+
foreach ($this->options AS $option => $label) {
|
56 |
+
$class = 'n2_field_tab__option';
|
57 |
+
if ($option == $this->defaultValue) {
|
58 |
+
$class .= ' n2_field_tab__option--selected';
|
59 |
+
}
|
60 |
+
$html .= Html::openTag("div", array(
|
61 |
+
"class" => $class,
|
62 |
+
"data-ssoption" => $option
|
63 |
+
));
|
64 |
+
$html .= $label;
|
65 |
+
$html .= Html::closeTag("div");
|
66 |
+
}
|
67 |
+
|
68 |
+
return $html;
|
69 |
+
}
|
70 |
+
}
|
Nextend/Framework/Form/Element/Text.php
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\AbstractField;
|
9 |
+
use Nextend\Framework\Form\ContainerInterface;
|
10 |
+
use Nextend\Framework\Form\TraitFieldset;
|
11 |
+
use Nextend\Framework\View\Html;
|
12 |
+
|
13 |
+
class Text extends AbstractField implements ContainerInterface {
|
14 |
+
|
15 |
+
use TraitFieldset;
|
16 |
+
|
17 |
+
protected $attributes = array();
|
18 |
+
|
19 |
+
public $fieldType = 'text';
|
20 |
+
|
21 |
+
protected $unit = false;
|
22 |
+
|
23 |
+
protected function addScript() {
|
24 |
+
Js::addInline('new N2Classes.FormElementText("' . $this->fieldID . '");');
|
25 |
+
}
|
26 |
+
|
27 |
+
protected function fetchElement() {
|
28 |
+
|
29 |
+
$this->addScript();
|
30 |
+
|
31 |
+
if ($this->getValue() === '') {
|
32 |
+
$this->class .= 'n2_field_text--empty ';
|
33 |
+
}
|
34 |
+
|
35 |
+
$html = Html::openTag('div', array(
|
36 |
+
'class' => 'n2_field_text ' . $this->getClass(),
|
37 |
+
'style' => ($this->fieldType == 'hidden' ? 'display: none;' : '')
|
38 |
+
));
|
39 |
+
|
40 |
+
$html .= $this->pre();
|
41 |
+
$html .= Html::tag('input', $this->attributes + array(
|
42 |
+
'type' => $this->fieldType,
|
43 |
+
'id' => $this->fieldID,
|
44 |
+
'name' => $this->getFieldName(),
|
45 |
+
'value' => $this->getValue(),
|
46 |
+
'style' => $this->getStyle(),
|
47 |
+
'autocomplete' => 'off'
|
48 |
+
), false);
|
49 |
+
|
50 |
+
$html .= $this->post();
|
51 |
+
|
52 |
+
if (!empty($this->unit)) {
|
53 |
+
$html .= Html::tag('div', array(
|
54 |
+
'class' => 'n2_field_text__unit'
|
55 |
+
), $this->unit);
|
56 |
+
}
|
57 |
+
$html .= "</div>";
|
58 |
+
|
59 |
+
return $html;
|
60 |
+
}
|
61 |
+
|
62 |
+
public function setUnit($unit) {
|
63 |
+
$this->unit = $unit;
|
64 |
+
}
|
65 |
+
|
66 |
+
protected function pre() {
|
67 |
+
return '';
|
68 |
+
}
|
69 |
+
|
70 |
+
protected function post() {
|
71 |
+
|
72 |
+
if ($this->first) {
|
73 |
+
$html = '';
|
74 |
+
|
75 |
+
$element = $this->first;
|
76 |
+
while ($element) {
|
77 |
+
|
78 |
+
$html .= $this->decorateElement($element);
|
79 |
+
|
80 |
+
$element = $element->getNext();
|
81 |
+
}
|
82 |
+
|
83 |
+
return '<div class="n2_field_text__post">' . $html . '</div>';
|
84 |
+
}
|
85 |
+
|
86 |
+
return '';
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* @param AbstractField $element
|
91 |
+
*
|
92 |
+
* @return string
|
93 |
+
*/
|
94 |
+
public function decorateElement($element) {
|
95 |
+
|
96 |
+
list($label, $fieldHTML) = $element->render();
|
97 |
+
|
98 |
+
return $fieldHTML;
|
99 |
+
}
|
100 |
+
}
|
Nextend/Framework/Form/Element/Text/Color.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Element\Text;
|
9 |
+
|
10 |
+
class Color extends Text {
|
11 |
+
|
12 |
+
protected $alpha = false;
|
13 |
+
|
14 |
+
protected $class = 'n2_field_color ';
|
15 |
+
|
16 |
+
protected function fetchElement() {
|
17 |
+
|
18 |
+
if ($this->alpha) {
|
19 |
+
$this->class .= 'n2_field_color--alpha ';
|
20 |
+
}
|
21 |
+
|
22 |
+
$html = parent::fetchElement();
|
23 |
+
Js::addInline('new N2Classes.FormElementColor("' . $this->fieldID . '", ' . intval($this->alpha) . ');');
|
24 |
+
|
25 |
+
return $html;
|
26 |
+
}
|
27 |
+
|
28 |
+
protected function pre() {
|
29 |
+
return '<div class="n2-sp-replacer"><div class="n2-sp-preview" style="background-color: rgb(62, 62, 62);"></div></div>';
|
30 |
+
}
|
31 |
+
|
32 |
+
protected function post() {
|
33 |
+
return '';
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @param boolean $alpha
|
38 |
+
*/
|
39 |
+
public function setAlpha($alpha) {
|
40 |
+
$this->alpha = $alpha;
|
41 |
+
}
|
42 |
+
}
|
Nextend/Framework/Form/Element/Text/Disabled.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element\Text;
|
4 |
+
|
5 |
+
use Nextend\Framework\Form\Element\Text;
|
6 |
+
|
7 |
+
class Disabled extends Text {
|
8 |
+
|
9 |
+
protected $attributes = array('disabled' => 'disabled');
|
10 |
+
}
|
Nextend/Framework/Form/Element/Text/Family.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Font\FontSettings;
|
9 |
+
use Nextend\Framework\Form\Element\Text;
|
10 |
+
|
11 |
+
class Family extends Text {
|
12 |
+
|
13 |
+
protected $class = 'n2_field_autocomplete n2_autocomplete_position_to';
|
14 |
+
|
15 |
+
protected function addScript() {
|
16 |
+
parent::addScript();
|
17 |
+
|
18 |
+
$families = FontSettings::getPresetFamilies();
|
19 |
+
Js::addInline('N2Classes.AutocompleteSimple("' . $this->fieldID . '", ' . json_encode($families) . ');');
|
20 |
+
}
|
21 |
+
}
|
Nextend/Framework/Form/Element/Text/FieldImage.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Browse\BrowseManager;
|
9 |
+
use Nextend\Framework\Form\Element\AbstractChooserText;
|
10 |
+
use Nextend\Framework\Image\Image;
|
11 |
+
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
|
12 |
+
use Nextend\Framework\Sanitize;
|
13 |
+
|
14 |
+
class FieldImage extends AbstractChooserText {
|
15 |
+
|
16 |
+
protected $attributes = array();
|
17 |
+
|
18 |
+
protected $relatedAlt = '';
|
19 |
+
|
20 |
+
protected $class = ' n2_field_text_image';
|
21 |
+
|
22 |
+
protected function addScript() {
|
23 |
+
|
24 |
+
$options = array();
|
25 |
+
if (!empty($this->relatedAlt)) {
|
26 |
+
$options['alt'] = $this->relatedAlt;
|
27 |
+
}
|
28 |
+
|
29 |
+
Js::addInline("new N2Classes.FormElementImage('" . $this->fieldID . "', " . json_encode($options) . " );");
|
30 |
+
}
|
31 |
+
|
32 |
+
protected function fetchElement() {
|
33 |
+
|
34 |
+
BrowseManager::enqueue($this->getForm());
|
35 |
+
|
36 |
+
$html = parent::fetchElement();
|
37 |
+
|
38 |
+
Image::initLightbox();
|
39 |
+
|
40 |
+
return $html;
|
41 |
+
}
|
42 |
+
|
43 |
+
protected function pre() {
|
44 |
+
|
45 |
+
return '<div class="n2_field_text_image__preview" style="' . $this->getImageStyle() . '"></div>';
|
46 |
+
}
|
47 |
+
|
48 |
+
protected function getImageStyle() {
|
49 |
+
$image = $this->getValue();
|
50 |
+
if (empty($image) || $image[0] == '{') {
|
51 |
+
return '';
|
52 |
+
}
|
53 |
+
|
54 |
+
return 'background-image:URL(' . Sanitize::esc_attr(ResourceTranslator::toUrl($image)) . ');';
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* @param string $relatedAlt
|
59 |
+
*/
|
60 |
+
public function setRelatedAlt($relatedAlt) {
|
61 |
+
$this->relatedAlt = $relatedAlt;
|
62 |
+
}
|
63 |
+
}
|
Nextend/Framework/Form/Element/Text/FieldImageResponsive.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Image\ImageManager;
|
9 |
+
use Nextend\Framework\View\Html;
|
10 |
+
|
11 |
+
class FieldImageResponsive extends FieldImage {
|
12 |
+
|
13 |
+
protected function fetchElement() {
|
14 |
+
|
15 |
+
$html = parent::fetchElement();
|
16 |
+
|
17 |
+
return $html;
|
18 |
+
}
|
19 |
+
}
|
Nextend/Framework/Form/Element/Text/Folder.php
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Browse\BrowseManager;
|
9 |
+
use Nextend\Framework\Form\Element\Text;
|
10 |
+
use Nextend\Framework\Image\Image;
|
11 |
+
use Nextend\Framework\View\Html;
|
12 |
+
|
13 |
+
class Folder extends Text {
|
14 |
+
|
15 |
+
protected $width = 300;
|
16 |
+
|
17 |
+
protected function addScript() {
|
18 |
+
|
19 |
+
BrowseManager::enqueue($this->getForm());
|
20 |
+
|
21 |
+
Image::initLightbox();
|
22 |
+
|
23 |
+
Js::addInline("new N2Classes.FormElementFolders('" . $this->fieldID . "' );");
|
24 |
+
}
|
25 |
+
|
26 |
+
protected function post() {
|
27 |
+
|
28 |
+
$html = Html::tag('a', array(
|
29 |
+
'href' => '#',
|
30 |
+
'class' => 'n2_field_text__clear'
|
31 |
+
), Html::tag('i', array('class' => 'ssi_16 ssi_16--circularremove'), ''));
|
32 |
+
|
33 |
+
$html .= Html::tag('a', array(
|
34 |
+
'href' => '#',
|
35 |
+
'class' => 'n2_field_text__choose'
|
36 |
+
), '<i class="ssi_16 ssi_16--plus"></i>');
|
37 |
+
|
38 |
+
return $html;
|
39 |
+
}
|
40 |
+
|
41 |
+
public function setWidth($width) {
|
42 |
+
$this->width = $width;
|
43 |
+
}
|
44 |
+
}
|
Nextend/Framework/Form/Element/Text/HiddenText.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Text;
|
8 |
+
|
9 |
+
class HiddenText extends Text {
|
10 |
+
|
11 |
+
public $fieldType = 'hidden';
|
12 |
+
|
13 |
+
public function getRowClass() {
|
14 |
+
return 'n2_form_element--hidden';
|
15 |
+
}
|
16 |
+
}
|
Nextend/Framework/Form/Element/Text/Number.php
ADDED
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element\Text;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
use Nextend\Framework\Form\Element\Text;
|
7 |
+
use Nextend\Framework\View\Html;
|
8 |
+
|
9 |
+
class Number extends Text {
|
10 |
+
|
11 |
+
protected $class = 'n2_field_number ';
|
12 |
+
|
13 |
+
protected $min = false;
|
14 |
+
protected $max = false;
|
15 |
+
protected $sublabel = '';
|
16 |
+
|
17 |
+
protected $units = false;
|
18 |
+
|
19 |
+
protected function fetchElement() {
|
20 |
+
|
21 |
+
if ($this->min === false) {
|
22 |
+
$this->min = '-Number.MAX_VALUE';
|
23 |
+
}
|
24 |
+
|
25 |
+
if ($this->max === false) {
|
26 |
+
$this->max = 'Number.MAX_VALUE';
|
27 |
+
}
|
28 |
+
|
29 |
+
$this->addScript();
|
30 |
+
|
31 |
+
$this->renderRelatedFields();
|
32 |
+
|
33 |
+
$html = Html::openTag('div', array(
|
34 |
+
'class' => 'n2_field_text ' . $this->getClass(),
|
35 |
+
'style' => ($this->fieldType == 'hidden' ? 'display: none;' : '')
|
36 |
+
));
|
37 |
+
|
38 |
+
if (!empty($this->sublabel)) {
|
39 |
+
$html .= Html::tag('div', array(
|
40 |
+
'class' => 'n2_field_text__pre_label'
|
41 |
+
), $this->sublabel);
|
42 |
+
}
|
43 |
+
|
44 |
+
$html .= $this->pre();
|
45 |
+
|
46 |
+
$html .= Html::tag('input', array(
|
47 |
+
'type' => $this->fieldType,
|
48 |
+
'id' => $this->fieldID,
|
49 |
+
'name' => $this->getFieldName(),
|
50 |
+
'value' => $this->getValue(),
|
51 |
+
'style' => $this->getStyle(),
|
52 |
+
'autocomplete' => 'off'
|
53 |
+
), false);
|
54 |
+
|
55 |
+
$html .= $this->post();
|
56 |
+
|
57 |
+
if ($this->unit) {
|
58 |
+
$html .= Html::tag('div', array(
|
59 |
+
'class' => 'n2_field_number__unit'
|
60 |
+
), $this->unit);
|
61 |
+
}
|
62 |
+
$html .= "</div>";
|
63 |
+
|
64 |
+
return $html;
|
65 |
+
}
|
66 |
+
|
67 |
+
protected function addScript() {
|
68 |
+
Js::addInline('new N2Classes.FormElementNumber("' . $this->fieldID . '", ' . $this->min . ', ' . $this->max . ', ' . json_encode($this->units) . ');');
|
69 |
+
}
|
70 |
+
|
71 |
+
public function setMin($min) {
|
72 |
+
$this->min = $min;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* @param int $max
|
77 |
+
*/
|
78 |
+
public function setMax($max) {
|
79 |
+
$this->max = $max;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* @param string $sublabel
|
84 |
+
*/
|
85 |
+
public function setSublabel($sublabel) {
|
86 |
+
$this->sublabel = $sublabel;
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* @param bool|array $units
|
91 |
+
*/
|
92 |
+
public function setUnits($units) {
|
93 |
+
$this->units = $units;
|
94 |
+
}
|
95 |
+
|
96 |
+
public function setWide($wide) {
|
97 |
+
switch ($wide) {
|
98 |
+
case 2:
|
99 |
+
$this->style .= 'width:20px;';
|
100 |
+
break;
|
101 |
+
case 3:
|
102 |
+
$this->style .= 'width:26px;';
|
103 |
+
break;
|
104 |
+
case 4:
|
105 |
+
$this->style .= 'width:32px;';
|
106 |
+
break;
|
107 |
+
case 5:
|
108 |
+
$this->style .= 'width:44px;';
|
109 |
+
break;
|
110 |
+
case 6:
|
111 |
+
$this->style .= 'width:60px;';
|
112 |
+
break;
|
113 |
+
}
|
114 |
+
}
|
115 |
+
}
|
Nextend/Framework/Form/Element/Text/NumberAutoComplete.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
|
9 |
+
class NumberAutoComplete extends Number {
|
10 |
+
|
11 |
+
protected $values = array();
|
12 |
+
|
13 |
+
protected $class = 'n2_field_number n2_autocomplete_position_to ';
|
14 |
+
|
15 |
+
protected function addScript() {
|
16 |
+
parent::addScript();
|
17 |
+
|
18 |
+
Js::addInline('N2Classes.AutocompleteSimple("' . $this->fieldID . '", ' . json_encode($this->values) . ');');
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @param array $values
|
23 |
+
*/
|
24 |
+
public function setValues($values) {
|
25 |
+
$this->values = $values;
|
26 |
+
}
|
27 |
+
}
|
Nextend/Framework/Form/Element/Text/NumberSlider.php
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
|
9 |
+
class NumberSlider extends Number {
|
10 |
+
|
11 |
+
protected $step = 1;
|
12 |
+
|
13 |
+
protected $sliderMax;
|
14 |
+
|
15 |
+
protected function fetchElement() {
|
16 |
+
$html = parent::fetchElement();
|
17 |
+
|
18 |
+
Js::addInline('new N2Classes.FormElementNumberSlider("' . $this->fieldID . '", ' . json_encode(array(
|
19 |
+
'min' => floatval($this->min),
|
20 |
+
'max' => floatval($this->sliderMax),
|
21 |
+
'step' => floatval($this->step),
|
22 |
+
'units' => $this->units
|
23 |
+
)) . ');');
|
24 |
+
|
25 |
+
return $html;
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @param int $step
|
30 |
+
*/
|
31 |
+
public function setStep($step) {
|
32 |
+
$this->step = $step;
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @param int $sliderMax
|
37 |
+
*/
|
38 |
+
public function setSliderMax($sliderMax) {
|
39 |
+
$this->sliderMax = $sliderMax;
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* @param int $max
|
44 |
+
*/
|
45 |
+
public function setMax($max) {
|
46 |
+
parent::setMax($max);
|
47 |
+
|
48 |
+
if ($this->sliderMax === null) {
|
49 |
+
$this->sliderMax = $max;
|
50 |
+
}
|
51 |
+
}
|
52 |
+
}
|
Nextend/Framework/Form/Element/Text/TextAutoComplete.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Element\Text;
|
9 |
+
|
10 |
+
class TextAutoComplete extends Text {
|
11 |
+
|
12 |
+
protected $class = 'n2_field_autocomplete n2_autocomplete_position_to';
|
13 |
+
|
14 |
+
protected $values = array();
|
15 |
+
|
16 |
+
protected function addScript() {
|
17 |
+
parent::addScript();
|
18 |
+
|
19 |
+
Js::addInline('N2Classes.AutocompleteSimple("' . $this->fieldID . '", ' . json_encode($this->values) . ');');
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @param array $values
|
24 |
+
*/
|
25 |
+
public function setValues($values) {
|
26 |
+
$this->values = $values;
|
27 |
+
}
|
28 |
+
}
|
Nextend/Framework/Form/Element/Text/TextMultiAutoComplete.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Element\Text;
|
9 |
+
use Nextend\Framework\View\Html;
|
10 |
+
|
11 |
+
class TextMultiAutoComplete extends Text {
|
12 |
+
|
13 |
+
protected $options = array();
|
14 |
+
|
15 |
+
protected $class = 'n2_field_autocomplete ';
|
16 |
+
|
17 |
+
protected function addScript() {
|
18 |
+
Js::addInline('new N2Classes.FormElementAutocomplete("' . $this->fieldID . '", ' . json_encode($this->options) . ');');
|
19 |
+
}
|
20 |
+
|
21 |
+
protected function post() {
|
22 |
+
return Html::tag('a', array(
|
23 |
+
'href' => '#',
|
24 |
+
'class' => 'n2_field_text__clear'
|
25 |
+
), Html::tag('i', array('class' => 'ssi_16 ssi_16--circularremove'), ''));
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @param array $options
|
30 |
+
*/
|
31 |
+
public function setOptions($options) {
|
32 |
+
$this->options = $options;
|
33 |
+
}
|
34 |
+
}
|
Nextend/Framework/Form/Element/Text/Url.php
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Element\AbstractChooserText;
|
9 |
+
use Nextend\Framework\Localization\Localization;
|
10 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
11 |
+
use Nextend\Framework\Platform\Platform;
|
12 |
+
|
13 |
+
class Url extends AbstractChooserText {
|
14 |
+
|
15 |
+
protected function addScript() {
|
16 |
+
Js::addInline("new N2Classes.FormElementUrl('" . $this->fieldID . "', " . $this->getElementUrlParameters($this->getForm()) . " );");
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @param MVCHelperTrait $MVCHelper
|
21 |
+
*
|
22 |
+
* @return string
|
23 |
+
*/
|
24 |
+
private function getElementUrlParameters($MVCHelper) {
|
25 |
+
$params = array(
|
26 |
+
'hasPosts' => Platform::hasPosts()
|
27 |
+
);
|
28 |
+
|
29 |
+
$params['url'] = $MVCHelper->createAjaxUrl("content/searchlink");
|
30 |
+
$params['labelButton'] = 'WordPress';
|
31 |
+
$params['labelDescription'] = n2_(/** @lang text */ 'Select a page or a blog post from your WordPress site.');
|
32 |
+
|
33 |
+
return json_encode($params);
|
34 |
+
}
|
35 |
+
|
36 |
+
protected function post() {
|
37 |
+
if (!Platform::hasPosts()) {
|
38 |
+
return '';
|
39 |
+
}
|
40 |
+
|
41 |
+
|
42 |
+
return parent::post();
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @param int $width
|
47 |
+
*/
|
48 |
+
public function setWidth($width) {
|
49 |
+
$this->width = $width;
|
50 |
+
}
|
51 |
+
|
52 |
+
}
|
Nextend/Framework/Form/Element/Text/Video.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Text;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Browse\BrowseManager;
|
8 |
+
|
9 |
+
class Video extends FieldImage {
|
10 |
+
|
11 |
+
protected function fetchElement() {
|
12 |
+
|
13 |
+
BrowseManager::enqueue($this->getForm());
|
14 |
+
|
15 |
+
$html = parent::fetchElement();
|
16 |
+
|
17 |
+
return $html;
|
18 |
+
}
|
19 |
+
}
|
Nextend/Framework/Form/Element/Textarea.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\AbstractField;
|
9 |
+
use Nextend\Framework\Sanitize;
|
10 |
+
use Nextend\Framework\View\Html;
|
11 |
+
|
12 |
+
class Textarea extends AbstractField {
|
13 |
+
|
14 |
+
protected $width = 200;
|
15 |
+
|
16 |
+
protected $height = 44;
|
17 |
+
|
18 |
+
protected $minHeight = 44;
|
19 |
+
|
20 |
+
protected $resize = 'vertical';
|
21 |
+
|
22 |
+
protected $classes = array(
|
23 |
+
'n2_field_textarea'
|
24 |
+
);
|
25 |
+
|
26 |
+
protected function fetchElement() {
|
27 |
+
|
28 |
+
Js::addInline('new N2Classes.FormElementText("' . $this->fieldID . '");');
|
29 |
+
|
30 |
+
return Html::tag('div', array(
|
31 |
+
'class' => implode(' ', $this->classes),
|
32 |
+
'style' => $this->style
|
33 |
+
), Html::tag('textarea', array(
|
34 |
+
'id' => $this->fieldID,
|
35 |
+
'name' => $this->getFieldName(),
|
36 |
+
'autocomplete' => 'off',
|
37 |
+
'style' => 'width:' . $this->width . 'px;height:' . $this->height . 'px;min-height:' . $this->minHeight . 'px;resize:' . $this->resize . ';'
|
38 |
+
), Sanitize::esc_textarea($this->getValue())));
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @param int $width
|
43 |
+
*/
|
44 |
+
public function setWidth($width) {
|
45 |
+
$this->width = $width;
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @param int $height
|
50 |
+
*/
|
51 |
+
public function setHeight($height) {
|
52 |
+
$this->height = $height;
|
53 |
+
if ($this->minHeight > $height) {
|
54 |
+
$this->minHeight = $height;
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* @param int $minHeight
|
60 |
+
*/
|
61 |
+
public function setMinHeight($minHeight) {
|
62 |
+
$this->minHeight = $minHeight;
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* @param string $resize
|
67 |
+
*/
|
68 |
+
public function setResize($resize) {
|
69 |
+
$this->resize = $resize;
|
70 |
+
}
|
71 |
+
|
72 |
+
public function setFieldStyle($style) {
|
73 |
+
|
74 |
+
}
|
75 |
+
}
|
Nextend/Framework/Form/Element/Textarea/TextareaInline.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element\Textarea;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Textarea;
|
8 |
+
|
9 |
+
class TextareaInline extends Textarea {
|
10 |
+
|
11 |
+
protected $width = 200;
|
12 |
+
|
13 |
+
protected $height = 26;
|
14 |
+
|
15 |
+
protected $classes = array(
|
16 |
+
'n2_field_textarea',
|
17 |
+
'n2_field_textarea--inline'
|
18 |
+
);
|
19 |
+
}
|
Nextend/Framework/Form/Element/Token.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
use Nextend\Framework\Form\Form;
|
7 |
+
|
8 |
+
class Token extends Hidden {
|
9 |
+
|
10 |
+
protected function fetchElement() {
|
11 |
+
|
12 |
+
return Form::tokenize();
|
13 |
+
}
|
14 |
+
}
|
Nextend/Framework/Form/Element/Unit.php
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Element;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class Unit extends AbstractFieldHidden {
|
11 |
+
|
12 |
+
protected $style = '';
|
13 |
+
|
14 |
+
protected $units = array();
|
15 |
+
|
16 |
+
protected function fetchElement() {
|
17 |
+
|
18 |
+
$values = array();
|
19 |
+
|
20 |
+
$html = "<div class='n2_field_unit' style='" . $this->style . "'>";
|
21 |
+
|
22 |
+
$currentValue = $this->getValue();
|
23 |
+
$currentLabel = '';
|
24 |
+
|
25 |
+
$html .= Html::openTag('div', array(
|
26 |
+
'class' => 'n2_field_unit__units'
|
27 |
+
));
|
28 |
+
foreach ($this->units AS $unit) {
|
29 |
+
$values[] = $unit;
|
30 |
+
|
31 |
+
$html .= Html::tag('div', array(
|
32 |
+
'class' => 'n2_field_unit__unit'
|
33 |
+
), $unit);
|
34 |
+
|
35 |
+
if ($currentValue == $unit) {
|
36 |
+
$currentLabel = $unit;
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
$html .= "</div>";
|
41 |
+
|
42 |
+
$html .= Html::tag('div', array(
|
43 |
+
'class' => 'n2_field_unit__current_unit'
|
44 |
+
), $currentLabel);
|
45 |
+
|
46 |
+
$html .= parent::fetchElement();
|
47 |
+
|
48 |
+
$html .= "</div>";
|
49 |
+
|
50 |
+
Js::addInline('new N2Classes.FormElementUnits("' . $this->fieldID . '", ' . json_encode($values) . ');');
|
51 |
+
|
52 |
+
return $html;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* @param string $style
|
57 |
+
*/
|
58 |
+
public function setStyle($style) {
|
59 |
+
$this->style = $style;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @param array $units
|
64 |
+
*/
|
65 |
+
public function setUnits($units) {
|
66 |
+
$this->units = $units;
|
67 |
+
}
|
68 |
+
}
|
Nextend/Framework/Form/Element/Upload.php
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Element;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
use Nextend\Framework\Form\AbstractField;
|
7 |
+
use Nextend\Framework\View\Html;
|
8 |
+
|
9 |
+
class Upload extends AbstractField {
|
10 |
+
|
11 |
+
protected $class = 'n2-form-element-file ';
|
12 |
+
|
13 |
+
protected function fetchElement() {
|
14 |
+
|
15 |
+
$html = '';
|
16 |
+
$html .= '<div class="n2_field_chooser__label"></div>';
|
17 |
+
$html .= Html::tag('a', array(
|
18 |
+
'href' => '#',
|
19 |
+
'class' => 'n2_field_chooser__choose'
|
20 |
+
), '<i class="ssi_16 ssi_16--plus"></i>');
|
21 |
+
|
22 |
+
$html .= Html::tag('input', array(
|
23 |
+
'type' => 'file',
|
24 |
+
'id' => $this->fieldID,
|
25 |
+
'name' => $this->getFieldName(),
|
26 |
+
'value' => $this->getValue(),
|
27 |
+
'autocomplete' => 'off'
|
28 |
+
), false);
|
29 |
+
|
30 |
+
Js::addInline('new N2Classes.FormElementUpload("' . $this->fieldID . '");');
|
31 |
+
|
32 |
+
return Html::tag('div', array(
|
33 |
+
'class' => 'n2_field_chooser n2_field_upload '
|
34 |
+
), $html);
|
35 |
+
}
|
36 |
+
}
|
Nextend/Framework/Form/Fieldset/FieldsetHidden.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Fieldset;
|
5 |
+
|
6 |
+
use Nextend\Framework\Form\AbstractFieldset;
|
7 |
+
|
8 |
+
class FieldsetHidden extends AbstractFieldset {
|
9 |
+
|
10 |
+
public function __construct($insertAt) {
|
11 |
+
|
12 |
+
parent::__construct($insertAt, '');
|
13 |
+
}
|
14 |
+
|
15 |
+
public function renderContainer() {
|
16 |
+
|
17 |
+
if ($this->first) {
|
18 |
+
echo '<div class="n2_form_element--hidden">';
|
19 |
+
|
20 |
+
$element = $this->first;
|
21 |
+
while ($element) {
|
22 |
+
echo $this->decorateElement($element);
|
23 |
+
|
24 |
+
$element = $element->getNext();
|
25 |
+
}
|
26 |
+
|
27 |
+
echo '</div>';
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
}
|
Nextend/Framework/Form/Fieldset/FieldsetRow.php
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Fieldset;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\Form\AbstractFieldset;
|
9 |
+
use Nextend\Framework\View\Html;
|
10 |
+
|
11 |
+
class FieldsetRow extends AbstractFieldset {
|
12 |
+
|
13 |
+
public function __construct($insertAt, $name, $parameters = array()) {
|
14 |
+
parent::__construct($insertAt, $name, false, $parameters);
|
15 |
+
}
|
16 |
+
|
17 |
+
public function renderContainer() {
|
18 |
+
|
19 |
+
$classes = array('n2_form__table_row');
|
20 |
+
if (!$this->isVisible) {
|
21 |
+
$classes[] = 'n2_form__table_row--hidden';
|
22 |
+
}
|
23 |
+
|
24 |
+
echo Html::openTag('div', array(
|
25 |
+
'class' => implode(' ', $classes),
|
26 |
+
'data-field' => 'table-row-' . $this->name
|
27 |
+
));
|
28 |
+
|
29 |
+
$element = $this->first;
|
30 |
+
while ($element) {
|
31 |
+
echo $this->decorateElement($element);
|
32 |
+
|
33 |
+
$element = $element->getNext();
|
34 |
+
}
|
35 |
+
echo '</div>';
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @param AbstractField $element
|
40 |
+
*
|
41 |
+
* @return string
|
42 |
+
*/
|
43 |
+
public function decorateElement($element) {
|
44 |
+
|
45 |
+
ob_start();
|
46 |
+
|
47 |
+
$hasLabel = $element->hasLabel();
|
48 |
+
|
49 |
+
$classes = array(
|
50 |
+
'n2_field',
|
51 |
+
$element->getLabelClass(),
|
52 |
+
$element->getRowClass()
|
53 |
+
);
|
54 |
+
|
55 |
+
echo Html::openTag('div', array(
|
56 |
+
'class' => implode(' ', array_filter($classes)),
|
57 |
+
'data-field' => $element->getID()
|
58 |
+
) + $element->getRowAttributes());
|
59 |
+
|
60 |
+
if ($hasLabel) {
|
61 |
+
echo "<div class='n2_field__label'>";
|
62 |
+
$element->displayLabel();
|
63 |
+
echo "</div>";
|
64 |
+
}
|
65 |
+
|
66 |
+
echo "<div class='n2_field__element'>";
|
67 |
+
$element->displayElement();
|
68 |
+
echo "</div>";
|
69 |
+
|
70 |
+
echo "</div>";
|
71 |
+
|
72 |
+
return ob_get_clean();
|
73 |
+
}
|
74 |
+
}
|
Nextend/Framework/Form/Fieldset/FieldsetRowPlain.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Fieldset;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
|
9 |
+
class FieldsetRowPlain extends FieldsetRow {
|
10 |
+
|
11 |
+
public function renderContainer() {
|
12 |
+
echo '<div class="n2_form__table_row_plain" data-field="table-row-plain-' . $this->name . '">';
|
13 |
+
|
14 |
+
$element = $this->first;
|
15 |
+
while ($element) {
|
16 |
+
echo $this->decorateElement($element);
|
17 |
+
|
18 |
+
$element = $element->getNext();
|
19 |
+
}
|
20 |
+
|
21 |
+
echo '</div>';
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @param AbstractField $element
|
26 |
+
*
|
27 |
+
* @return string
|
28 |
+
*/
|
29 |
+
public function decorateElement($element) {
|
30 |
+
|
31 |
+
ob_start();
|
32 |
+
|
33 |
+
$element->displayElement();
|
34 |
+
|
35 |
+
return ob_get_clean();
|
36 |
+
}
|
37 |
+
}
|
Nextend/Framework/Form/Fieldset/FieldsetTableLabel.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Fieldset;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractFieldset;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class FieldsetTableLabel extends AbstractFieldset {
|
11 |
+
|
12 |
+
public function renderContainer() {
|
13 |
+
|
14 |
+
$element = $this->first;
|
15 |
+
while ($element) {
|
16 |
+
|
17 |
+
echo Html::openTag('div', array(
|
18 |
+
'class' => 'n2_form__table_label_field ' . $element->getRowClass(),
|
19 |
+
'data-field' => $element->getID()
|
20 |
+
) + $element->getRowAttributes());
|
21 |
+
echo $this->decorateElement($element);
|
22 |
+
echo "</div>";
|
23 |
+
|
24 |
+
$element = $element->getNext();
|
25 |
+
}
|
26 |
+
}
|
27 |
+
}
|
Nextend/Framework/Form/Fieldset/FieldsetVisualSet.php
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Fieldset;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\Form\AbstractFieldset;
|
9 |
+
use Nextend\Framework\View\Html;
|
10 |
+
|
11 |
+
class FieldsetVisualSet extends AbstractFieldset {
|
12 |
+
|
13 |
+
public function renderContainer() {
|
14 |
+
echo '<div class="n2_form__visual_set" data-field="visual-set-' . $this->name . '">';
|
15 |
+
|
16 |
+
echo "<div class='n2_form__visual_set_label'>" . $this->label . '</div>';
|
17 |
+
|
18 |
+
$element = $this->first;
|
19 |
+
while ($element) {
|
20 |
+
echo $this->decorateElement($element);
|
21 |
+
|
22 |
+
$element = $element->getNext();
|
23 |
+
}
|
24 |
+
echo '</div>';
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @param AbstractField $element
|
29 |
+
*
|
30 |
+
* @return string
|
31 |
+
*/
|
32 |
+
public function decorateElement($element) {
|
33 |
+
|
34 |
+
ob_start();
|
35 |
+
|
36 |
+
$classes = array(
|
37 |
+
'n2_field',
|
38 |
+
$element->getRowClass()
|
39 |
+
);
|
40 |
+
|
41 |
+
echo Html::openTag('div', array(
|
42 |
+
'class' => implode(' ', array_filter($classes)),
|
43 |
+
'data-field' => $element->getID()
|
44 |
+
) + $element->getRowAttributes());
|
45 |
+
|
46 |
+
$element->displayElement();
|
47 |
+
|
48 |
+
echo "</div>";
|
49 |
+
|
50 |
+
return ob_get_clean();
|
51 |
+
}
|
52 |
+
}
|
Nextend/Framework/Form/Fieldset/LayerWindow/FieldsetDesign.php
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\Fieldset\LayerWindow;
|
4 |
+
|
5 |
+
use Nextend\Framework\Form\Element\Button\ButtonIcon;
|
6 |
+
use Nextend\Framework\Form\Element\Select;
|
7 |
+
|
8 |
+
class FieldsetDesign extends FieldsetLayerWindowLabelFields {
|
9 |
+
|
10 |
+
public function __construct($insertAt, $name, $label) {
|
11 |
+
parent::__construct($insertAt, $name, $label);
|
12 |
+
|
13 |
+
$this->addAttribute('data-fieldset-type', 'design');
|
14 |
+
|
15 |
+
new ButtonIcon($this->fieldsetLabel, $name . '-reset-to-normal', false, 'ssi_16 ssi_16--reset', array(
|
16 |
+
'hoverTip' => n2_('Reset to normal state'),
|
17 |
+
'rowAttributes' => array(
|
18 |
+
'data-design-feature' => 'reset-to-normal'
|
19 |
+
)
|
20 |
+
));
|
21 |
+
new Select($this->fieldsetLabel, $name . '-element', false, '', array(
|
22 |
+
'rowAttributes' => array(
|
23 |
+
'data-design-feature' => 'element'
|
24 |
+
)
|
25 |
+
));
|
26 |
+
new Select($this->fieldsetLabel, $name . '-state', false, '', array(
|
27 |
+
'rowAttributes' => array(
|
28 |
+
'data-design-feature' => 'state'
|
29 |
+
)
|
30 |
+
));
|
31 |
+
}
|
32 |
+
|
33 |
+
protected function renderTitle() {
|
34 |
+
|
35 |
+
echo '<div class="n2_fields_layer_window__label">' . $this->label . '</div>';
|
36 |
+
|
37 |
+
if ($this->fieldsetLabel->hasFields()) {
|
38 |
+
echo '<div class="n2_fields_layer_window__title_fields">';
|
39 |
+
$this->fieldsetLabel->renderContainer();
|
40 |
+
echo '</div>';
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* @param mixed $parentDesign
|
46 |
+
*/
|
47 |
+
public function setParentDesign($parentDesign) {
|
48 |
+
$this->addAttribute('data-parent-design', $parentDesign);
|
49 |
+
}
|
50 |
+
}
|
Nextend/Framework/Form/Fieldset/LayerWindow/FieldsetInsideLabel.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Fieldset\LayerWindow;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractFieldset;
|
8 |
+
use Nextend\Framework\View\Html;
|
9 |
+
|
10 |
+
class FieldsetInsideLabel extends AbstractFieldset {
|
11 |
+
|
12 |
+
public function renderContainer() {
|
13 |
+
|
14 |
+
$element = $this->first;
|
15 |
+
while ($element) {
|
16 |
+
|
17 |
+
echo Html::openTag('div', array(
|
18 |
+
'class' => 'n2_form__table_label_field ' . $element->getRowClass(),
|
19 |
+
'data-field' => $element->getID()
|
20 |
+
) + $element->getRowAttributes());
|
21 |
+
$element->displayElement();
|
22 |
+
echo "</div>";
|
23 |
+
|
24 |
+
$element = $element->getNext();
|
25 |
+
}
|
26 |
+
}
|
27 |
+
}
|
Nextend/Framework/Form/Fieldset/LayerWindow/FieldsetLayerWindow.php
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Fieldset\LayerWindow;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\AbstractField;
|
8 |
+
use Nextend\Framework\Form\AbstractFieldset;
|
9 |
+
use Nextend\Framework\View\Html;
|
10 |
+
|
11 |
+
class FieldsetLayerWindow extends AbstractFieldset {
|
12 |
+
|
13 |
+
protected $attributes = array();
|
14 |
+
|
15 |
+
public function renderContainer() {
|
16 |
+
|
17 |
+
echo Html::openTag('div', array(
|
18 |
+
'class' => 'n2_fields_layer_window',
|
19 |
+
'data-field' => 'fieldset-layer-window-' . $this->name
|
20 |
+
) + $this->attributes);
|
21 |
+
|
22 |
+
if (!empty($this->label)) {
|
23 |
+
echo '<div class="n2_fields_layer_window__title">';
|
24 |
+
$this->renderTitle();
|
25 |
+
echo '</div>';
|
26 |
+
}
|
27 |
+
|
28 |
+
echo '<div class="n2_fields_layer_window__fields">';
|
29 |
+
|
30 |
+
$element = $this->first;
|
31 |
+
while ($element) {
|
32 |
+
echo $this->decorateElement($element);
|
33 |
+
|
34 |
+
$element = $element->getNext();
|
35 |
+
}
|
36 |
+
|
37 |
+
echo '</div>';
|
38 |
+
echo '</div>';
|
39 |
+
}
|
40 |
+
|
41 |
+
protected function renderTitle() {
|
42 |
+
|
43 |
+
echo '<div class="n2_fields_layer_window__label">' . $this->label . '</div>';
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* @param AbstractField $element
|
48 |
+
*
|
49 |
+
* @return string
|
50 |
+
*/
|
51 |
+
public function decorateElement($element) {
|
52 |
+
|
53 |
+
ob_start();
|
54 |
+
|
55 |
+
$hasLabel = $element->hasLabel();
|
56 |
+
|
57 |
+
$classes = array(
|
58 |
+
'n2_field',
|
59 |
+
$element->getLabelClass(),
|
60 |
+
$element->getRowClass()
|
61 |
+
);
|
62 |
+
|
63 |
+
echo Html::openTag('div', array(
|
64 |
+
'class' => implode(' ', array_filter($classes)),
|
65 |
+
'data-field' => $element->getID()
|
66 |
+
) + $element->getRowAttributes());
|
67 |
+
|
68 |
+
if ($hasLabel) {
|
69 |
+
echo "<div class='n2_field__label'>";
|
70 |
+
$element->displayLabel();
|
71 |
+
echo "</div>";
|
72 |
+
}
|
73 |
+
|
74 |
+
echo "<div class='n2_field__element'>";
|
75 |
+
$element->displayElement();
|
76 |
+
echo "</div>";
|
77 |
+
|
78 |
+
echo "</div>";
|
79 |
+
|
80 |
+
return ob_get_clean();
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* @param array $attributes
|
85 |
+
*/
|
86 |
+
public function setAttributes($attributes) {
|
87 |
+
$this->attributes = $attributes;
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* @param string $name
|
92 |
+
* @param string $value
|
93 |
+
*/
|
94 |
+
public function addAttribute($name, $value) {
|
95 |
+
$this->attributes[$name] = $value;
|
96 |
+
}
|
97 |
+
}
|
Nextend/Framework/Form/Fieldset/LayerWindow/FieldsetLayerWindowLabelFields.php
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Fieldset\LayerWindow;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Container\ContainerAlternative;
|
8 |
+
|
9 |
+
class FieldsetLayerWindowLabelFields extends FieldsetLayerWindow {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var FieldsetInsideLabel
|
13 |
+
*/
|
14 |
+
protected $fieldsetLabel;
|
15 |
+
|
16 |
+
public function __construct($insertAt, $name, $label, $parameters = array()) {
|
17 |
+
parent::__construct($insertAt, $name, $label, $parameters);
|
18 |
+
|
19 |
+
$labelContainer = new ContainerAlternative($this->parent, $name . '-container-label');
|
20 |
+
$this->fieldsetLabel = new FieldsetInsideLabel($labelContainer, $name . '-label', false);
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @return FieldsetInsideLabel
|
25 |
+
*/
|
26 |
+
public function getFieldsetLabel() {
|
27 |
+
return $this->fieldsetLabel;
|
28 |
+
}
|
29 |
+
|
30 |
+
protected function renderTitle() {
|
31 |
+
echo '<div class="n2_fields_layer_window__label">' . $this->label . '</div>';
|
32 |
+
|
33 |
+
echo '<div class="n2_fields_layer_window__title_fields">';
|
34 |
+
if ($this->fieldsetLabel->hasFields()) {
|
35 |
+
$this->fieldsetLabel->renderContainer();
|
36 |
+
}
|
37 |
+
echo '</div>';
|
38 |
+
}
|
39 |
+
}
|
Nextend/Framework/Form/Fieldset/LayerWindow/FieldsetLayerWindowStyleMode.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Fieldset\LayerWindow;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Element\Button\ButtonIcon;
|
8 |
+
use Nextend\Framework\Form\Element\Select;
|
9 |
+
|
10 |
+
class FieldsetLayerWindowStyleMode extends FieldsetLayerWindowLabelFields {
|
11 |
+
|
12 |
+
public function __construct($insertAt, $name, $label, $modes, $parameters = array()) {
|
13 |
+
parent::__construct($insertAt, $name, $label, $parameters);
|
14 |
+
|
15 |
+
$this->addAttribute('data-fieldset-type', 'style-mode');
|
16 |
+
|
17 |
+
new ButtonIcon($this->fieldsetLabel, $name . '-mode-reset-to-normal', false, 'ssi_16 ssi_16--reset', array(
|
18 |
+
'hoverTip' => n2_('Reset to normal state'),
|
19 |
+
'rowAttributes' => array(
|
20 |
+
'data-style-mode-feature' => 'reset-to-normal'
|
21 |
+
)
|
22 |
+
));
|
23 |
+
|
24 |
+
new Select($this->fieldsetLabel, $name . '-mode', false, '', array(
|
25 |
+
'options' => $modes
|
26 |
+
));
|
27 |
+
}
|
28 |
+
}
|
Nextend/Framework/Form/Form.php
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Data\Data;
|
8 |
+
use Nextend\Framework\Form\Fieldset\FieldsetHidden;
|
9 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
10 |
+
|
11 |
+
class Form extends Data {
|
12 |
+
|
13 |
+
use MVCHelperTrait;
|
14 |
+
|
15 |
+
protected static $counter = 1;
|
16 |
+
|
17 |
+
/** @var Base\PlatformFormBase */
|
18 |
+
private static $platformForm;
|
19 |
+
|
20 |
+
protected $id;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var Data
|
24 |
+
*/
|
25 |
+
protected $context;
|
26 |
+
|
27 |
+
protected $controlName = '';
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @var ContainerMain
|
31 |
+
*/
|
32 |
+
protected $container;
|
33 |
+
|
34 |
+
protected $classes = array(
|
35 |
+
'n2_form'
|
36 |
+
);
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Form constructor.
|
40 |
+
*
|
41 |
+
* @param MVCHelperTrait $MVCHelper
|
42 |
+
* @param string $controlName
|
43 |
+
*/
|
44 |
+
public function __construct($MVCHelper, $controlName) {
|
45 |
+
|
46 |
+
$this->id = 'n2_form_' . self::$counter++;
|
47 |
+
|
48 |
+
$this->controlName = $controlName;
|
49 |
+
|
50 |
+
$this->setMVCHelper($MVCHelper);
|
51 |
+
|
52 |
+
$this->context = new Data();
|
53 |
+
parent::__construct();
|
54 |
+
|
55 |
+
$this->container = new ContainerMain($this);
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* @return ContainerMain
|
60 |
+
*/
|
61 |
+
public function getContainer() {
|
62 |
+
return $this->container;
|
63 |
+
}
|
64 |
+
|
65 |
+
public function getId() {
|
66 |
+
return $this->id;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @return Data
|
71 |
+
*/
|
72 |
+
public function getContext() {
|
73 |
+
return $this->context;
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* @param $path
|
78 |
+
*
|
79 |
+
* @return ContainerInterface|AbstractField
|
80 |
+
*/
|
81 |
+
public function getElement($path) {
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Remove starting / path separator
|
85 |
+
*/
|
86 |
+
return $this->container->getElement(substr($path, 1));
|
87 |
+
}
|
88 |
+
|
89 |
+
public function render() {
|
90 |
+
echo '<div class="' . implode(' ', $this->classes) . '">';
|
91 |
+
|
92 |
+
$this->container->renderContainer();
|
93 |
+
|
94 |
+
echo '</div>';
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* @return string
|
99 |
+
*/
|
100 |
+
public function getControlName() {
|
101 |
+
return $this->controlName;
|
102 |
+
}
|
103 |
+
|
104 |
+
public static function init() {
|
105 |
+
self::$platformForm = new WordPress\PlatformForm();
|
106 |
+
}
|
107 |
+
|
108 |
+
public static function tokenize() {
|
109 |
+
return self::$platformForm->tokenize();
|
110 |
+
}
|
111 |
+
|
112 |
+
public static function tokenizeUrl() {
|
113 |
+
return self::$platformForm->tokenizeUrl();
|
114 |
+
}
|
115 |
+
|
116 |
+
public static function checkToken() {
|
117 |
+
return self::$platformForm->checkToken();
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* @return FieldsetHidden
|
122 |
+
*/
|
123 |
+
public function getFieldsetHidden() {
|
124 |
+
return $this->container->getFieldsetHidden();
|
125 |
+
}
|
126 |
+
|
127 |
+
public function setDark() {
|
128 |
+
$this->classes[] = 'n2_form--dark';
|
129 |
+
}
|
130 |
+
|
131 |
+
public function addClass($className) {
|
132 |
+
$this->classes[] = $className;
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
Form::init();
|
Nextend/Framework/Form/FormTabbed.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Form\Container\ContainerTab;
|
9 |
+
use Nextend\SmartSlider3\Application\Admin\Layout\Block\Core\Header\BlockHeader;
|
10 |
+
use Nextend\SmartSlider3\Application\Admin\Layout\Block\Core\Header\MenuItem;
|
11 |
+
|
12 |
+
class FormTabbed extends Form {
|
13 |
+
|
14 |
+
protected $classes = array(
|
15 |
+
'n2_form',
|
16 |
+
'n2_form_tabbed'
|
17 |
+
);
|
18 |
+
|
19 |
+
protected $toggleMode = false;
|
20 |
+
|
21 |
+
protected $sessionID = '';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @param $name
|
25 |
+
* @param $label
|
26 |
+
*
|
27 |
+
* @return ContainerTab
|
28 |
+
*/
|
29 |
+
public function createTab($name, $label) {
|
30 |
+
|
31 |
+
return new ContainerTab($this->container, $name, $label);
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* @param BlockHeader $blockHeader
|
36 |
+
*/
|
37 |
+
public function addTabsToHeader($blockHeader) {
|
38 |
+
$element = $this->container->getFirst();
|
39 |
+
while ($element) {
|
40 |
+
if ($element instanceof ContainerTab) {
|
41 |
+
|
42 |
+
$tab = new MenuItem($element->getLabel());
|
43 |
+
$tab->addClass('n2_form__tab_button');
|
44 |
+
$tab->setAttribute('data-related-form', $this->id);
|
45 |
+
$tab->setAttribute('data-related-tab', $element->getId());
|
46 |
+
$blockHeader->addMenuItem($tab);
|
47 |
+
}
|
48 |
+
|
49 |
+
$element = $element->getNext();
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
public function render() {
|
54 |
+
parent::render();
|
55 |
+
|
56 |
+
Js::addInline('new N2Classes.FormTabbed("' . $this->id . '", ' . json_encode(array(
|
57 |
+
'toggleMode' => $this->toggleMode,
|
58 |
+
'sessionID' => $this->sessionID
|
59 |
+
)) . ');');
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @param bool $toggleMode
|
64 |
+
*/
|
65 |
+
public function setToggleMode($toggleMode) {
|
66 |
+
$this->toggleMode = $toggleMode;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @param string $sessionID
|
71 |
+
*/
|
72 |
+
public function setSessionID($sessionID) {
|
73 |
+
$this->sessionID = $sessionID;
|
74 |
+
}
|
75 |
+
}
|
Nextend/Framework/Form/Insert/AbstractInsert.php
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Insert;
|
5 |
+
|
6 |
+
use Nextend\Framework\Form\ContainedInterface;
|
7 |
+
use Nextend\Framework\Form\ContainerInterface;
|
8 |
+
|
9 |
+
abstract class AbstractInsert {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var ContainedInterface
|
13 |
+
*/
|
14 |
+
protected $at;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* AbstractInsert constructor.
|
18 |
+
*
|
19 |
+
* @param ContainedInterface $at
|
20 |
+
*/
|
21 |
+
public function __construct($at) {
|
22 |
+
$this->at = $at;
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @param ContainedInterface $element
|
27 |
+
*
|
28 |
+
* @return ContainerInterface Returns the parent
|
29 |
+
*/
|
30 |
+
public abstract function insert($element);
|
31 |
+
}
|
Nextend/Framework/Form/Insert/InsertAfter.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Insert;
|
5 |
+
|
6 |
+
|
7 |
+
class InsertAfter extends AbstractInsert {
|
8 |
+
|
9 |
+
public function insert($element) {
|
10 |
+
$parent = $this->at->getParent();
|
11 |
+
$parent->insertElementAfter($element, $this->at);
|
12 |
+
|
13 |
+
return $parent;
|
14 |
+
}
|
15 |
+
}
|
Nextend/Framework/Form/Insert/InsertBefore.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form\Insert;
|
5 |
+
|
6 |
+
|
7 |
+
class InsertBefore extends AbstractInsert {
|
8 |
+
|
9 |
+
public function insert($element) {
|
10 |
+
$parent = $this->at->getParent();
|
11 |
+
$parent->insertElementBefore($element, $this->at);
|
12 |
+
|
13 |
+
return $parent;
|
14 |
+
}
|
15 |
+
}
|
Nextend/Framework/Form/TraitContainer.php
ADDED
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Form;
|
5 |
+
|
6 |
+
|
7 |
+
trait TraitContainer {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @var ContainedInterface
|
11 |
+
*/
|
12 |
+
protected $first, $last;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @var ContainedInterface[]
|
16 |
+
*/
|
17 |
+
protected $flattenElements = array();
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @param ContainedInterface $element
|
21 |
+
*/
|
22 |
+
public function addElement($element) {
|
23 |
+
|
24 |
+
if (!$this->first) {
|
25 |
+
$this->first = $element;
|
26 |
+
}
|
27 |
+
|
28 |
+
if ($this->last) {
|
29 |
+
$this->last->setNext($element);
|
30 |
+
}
|
31 |
+
|
32 |
+
$this->last = $element;
|
33 |
+
|
34 |
+
$name = $element->getName();
|
35 |
+
if ($name) {
|
36 |
+
$this->flattenElements[$name] = $element;
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* @param ContainedInterface $element
|
42 |
+
* @param ContainedInterface $target
|
43 |
+
*/
|
44 |
+
public function insertElementBefore($element, $target) {
|
45 |
+
$previous = $target->getPrevious();
|
46 |
+
if ($previous) {
|
47 |
+
$previous->setNext($element);
|
48 |
+
} else {
|
49 |
+
$this->first = $element;
|
50 |
+
}
|
51 |
+
|
52 |
+
$element->setNext($target);
|
53 |
+
|
54 |
+
$name = $element->getName();
|
55 |
+
if ($name) {
|
56 |
+
$this->flattenElements[$name] = $element;
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @param AbstractField $element
|
62 |
+
* @param AbstractField $target
|
63 |
+
*/
|
64 |
+
public function insertElementAfter($element, $target) {
|
65 |
+
|
66 |
+
$next = $target->getNext();
|
67 |
+
$target->setNext($element);
|
68 |
+
|
69 |
+
if ($next) {
|
70 |
+
$element->setNext($next);
|
71 |
+
} else {
|
72 |
+
$this->last = $element;
|
73 |
+
}
|
74 |
+
|
75 |
+
$name = $element->getName();
|
76 |
+
if ($name) {
|
77 |
+
$this->flattenElements[$name] = $element;
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* @param AbstractField $element
|
83 |
+
*/
|
84 |
+
public function removeElement($element) {
|
85 |
+
$previous = $element->getPrevious();
|
86 |
+
$next = $element->getNext();
|
87 |
+
|
88 |
+
if ($this->first === $element) {
|
89 |
+
$this->first = $next;
|
90 |
+
}
|
91 |
+
|
92 |
+
if ($this->last === $element) {
|
93 |
+
$this->last = $previous;
|
94 |
+
}
|
95 |
+
|
96 |
+
if ($previous) {
|
97 |
+
$previous->setNext($next);
|
98 |
+
} else {
|
99 |
+
$next->setPrevious();
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* @param $path
|
105 |
+
*
|
106 |
+
* @return AbstractField
|
107 |
+
*/
|
108 |
+
public function getElement($path) {
|
109 |
+
$parts = explode('/', $path, 2);
|
110 |
+
$element = $this->flattenElements[$parts[0]];
|
111 |
+
if (!empty($parts[1]) && $element instanceof ContainerInterface) {
|
112 |
+
$element = $element->getElement($parts[1]);
|
113 |
+
}
|
114 |
+
|
115 |
+
return $element;
|
116 |
+
}
|
117 |
+
|
118 |
+
public function getElementIdentifiers() {
|
119 |
+
return array_keys($this->flattenElements);
|
120 |
+
}
|
121 |
+
}
|
Nextend/Framework/Form/TraitFieldset.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form;
|
4 |
+
|
5 |
+
trait TraitFieldset {
|
6 |
+
|
7 |
+
use TraitContainer;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @var AbstractField
|
11 |
+
*/
|
12 |
+
protected $first, $last;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @var bool
|
16 |
+
*/
|
17 |
+
protected $isVisible = true;
|
18 |
+
|
19 |
+
public function hide() {
|
20 |
+
$this->isVisible = false;
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @return ContainerInterface
|
25 |
+
*/
|
26 |
+
public function getParent() {
|
27 |
+
return $this->parent;
|
28 |
+
}
|
29 |
+
|
30 |
+
public function getPath() {
|
31 |
+
return $this->getParent()
|
32 |
+
->getPath() . '/' . $this->name;
|
33 |
+
}
|
34 |
+
|
35 |
+
public function renderContainer() {
|
36 |
+
|
37 |
+
}
|
38 |
+
|
39 |
+
abstract public function getControlName();
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @return Form
|
43 |
+
*/
|
44 |
+
abstract public function getForm();
|
45 |
+
|
46 |
+
/**
|
47 |
+
* @param AbstractField $element
|
48 |
+
*
|
49 |
+
* @return string
|
50 |
+
*/
|
51 |
+
abstract public function decorateElement($element);
|
52 |
+
|
53 |
+
abstract public function getName();
|
54 |
+
}
|
Nextend/Framework/Form/WordPress/PlatformForm.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Form\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Form\Base\PlatformFormBase;
|
6 |
+
use Nextend\Framework\Request\Request;
|
7 |
+
|
8 |
+
class PlatformForm extends PlatformFormBase {
|
9 |
+
|
10 |
+
public function tokenize() {
|
11 |
+
return '<input type="hidden" name="nextend_nonce" value="' . wp_create_nonce('nextend_security') . '" />';
|
12 |
+
}
|
13 |
+
|
14 |
+
public function tokenizeUrl() {
|
15 |
+
$a = array();
|
16 |
+
$a['nextend_nonce'] = wp_create_nonce('nextend_security');
|
17 |
+
|
18 |
+
return $a;
|
19 |
+
}
|
20 |
+
|
21 |
+
public function checkToken() {
|
22 |
+
return wp_verify_nonce(Request::$REQUEST->getVar('nextend_nonce'), 'nextend_security');
|
23 |
+
}
|
24 |
+
}
|
Nextend/Framework/Framework.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Font\FontStorage;
|
8 |
+
use Nextend\Framework\Localization\Localization;
|
9 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
10 |
+
use Nextend\Framework\Style\StyleStorage;
|
11 |
+
|
12 |
+
class Framework {
|
13 |
+
|
14 |
+
use SingletonTrait;
|
15 |
+
|
16 |
+
protected function init() {
|
17 |
+
|
18 |
+
Localization::getInstance();
|
19 |
+
|
20 |
+
FontStorage::getInstance();
|
21 |
+
StyleStorage::getInstance();
|
22 |
+
}
|
23 |
+
}
|
Nextend/Framework/Image/AbstractPlatformImage.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Image;
|
4 |
+
|
5 |
+
abstract class AbstractPlatformImage {
|
6 |
+
|
7 |
+
public function initLightbox() {
|
8 |
+
|
9 |
+
}
|
10 |
+
|
11 |
+
public function onImageUploaded($filename) {
|
12 |
+
}
|
13 |
+
}
|
Nextend/Framework/Image/Block/ImageManager/BlockImageManager.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Image\Block\ImageManager;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Image\ImageManager;
|
9 |
+
use Nextend\Framework\Image\ModelImage;
|
10 |
+
use Nextend\Framework\Localization\Localization;
|
11 |
+
use Nextend\Framework\Visual\AbstractBlockVisual;
|
12 |
+
use Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonApply;
|
13 |
+
use Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonCancel;
|
14 |
+
use Nextend\SmartSlider3\Application\Admin\TraitAdminUrl;
|
15 |
+
|
16 |
+
class BlockImageManager extends AbstractBlockVisual {
|
17 |
+
|
18 |
+
use TraitAdminUrl;
|
19 |
+
|
20 |
+
/** @var ModelImage */
|
21 |
+
protected $model;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @return ModelImage
|
25 |
+
*/
|
26 |
+
public function getModel() {
|
27 |
+
return $this->model;
|
28 |
+
}
|
29 |
+
|
30 |
+
public function display() {
|
31 |
+
|
32 |
+
$this->model = new ModelImage($this);
|
33 |
+
|
34 |
+
$this->renderTemplatePart('Index');
|
35 |
+
}
|
36 |
+
|
37 |
+
public function displayTopBar() {
|
38 |
+
|
39 |
+
$buttonCancel = new BlockButtonCancel($this);
|
40 |
+
$buttonCancel->addClass('n2_fullscreen_editor__cancel');
|
41 |
+
$buttonCancel->display();
|
42 |
+
|
43 |
+
$buttonApply = new BlockButtonApply($this);
|
44 |
+
$buttonApply->addClass('n2_fullscreen_editor__save');
|
45 |
+
$buttonApply->display();
|
46 |
+
}
|
47 |
+
|
48 |
+
public function displayContent() {
|
49 |
+
Js::addFirstCode("
|
50 |
+
new N2Classes.NextendImageManager({
|
51 |
+
visuals: " . json_encode(ImageManager::$loaded) . ",
|
52 |
+
ajaxUrl: '" . $this->getAjaxUrlImage() . "'
|
53 |
+
});
|
54 |
+
");
|
55 |
+
|
56 |
+
$this->getModel()
|
57 |
+
->renderForm();
|
58 |
+
}
|
59 |
+
}
|
Nextend/Framework/Image/Block/ImageManager/Index.phtml
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Image\Block\ImageManager;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* @var BlockImageManager $this
|
7 |
+
*/
|
8 |
+
?>
|
9 |
+
<div id="n2-lightbox-image" class="n2_fullscreen_editor">
|
10 |
+
<div class="n2_fullscreen_editor__overlay"></div>
|
11 |
+
<div class="n2_fullscreen_editor__window">
|
12 |
+
<div class="n2_fullscreen_editor__nav_bar">
|
13 |
+
<div class="n2_fullscreen_editor__nav_bar_label">
|
14 |
+
<?php n2_e('Image manager'); ?>
|
15 |
+
</div>
|
16 |
+
<div class="n2_fullscreen_editor__nav_bar_actions">
|
17 |
+
<?php $this->displayTopBar(); ?>
|
18 |
+
</div>
|
19 |
+
</div>
|
20 |
+
<div class="n2_fullscreen_editor__content">
|
21 |
+
<div class="n2_fullscreen_editor__content_content n2_container_scrollable">
|
22 |
+
<?php $this->displayContent(); ?>
|
23 |
+
</div>
|
24 |
+
</div>
|
25 |
+
</div>
|
26 |
+
</div>
|
Nextend/Framework/Image/ControllerAjaxImage.php
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Image;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Controller\Admin\AdminVisualManagerAjaxController;
|
8 |
+
use Nextend\Framework\Notification\Notification;
|
9 |
+
use Nextend\Framework\Request\Request;
|
10 |
+
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
|
11 |
+
|
12 |
+
class ControllerAjaxImage extends AdminVisualManagerAjaxController {
|
13 |
+
|
14 |
+
protected $type = 'image';
|
15 |
+
|
16 |
+
public function actionLoadVisualForImage() {
|
17 |
+
$this->validateToken();
|
18 |
+
$model = $this->getModel();
|
19 |
+
$image = Request::$REQUEST->getVar('image');
|
20 |
+
$visual = $model->getVisual($image);
|
21 |
+
if (!empty($visual)) {
|
22 |
+
$this->response->respond(array(
|
23 |
+
'visual' => $visual
|
24 |
+
));
|
25 |
+
} else {
|
26 |
+
|
27 |
+
if (($visual = $model->addVisual($image, ImageStorage::$emptyImage))) {
|
28 |
+
$this->response->respond(array(
|
29 |
+
'visual' => $visual
|
30 |
+
));
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
Notification::error(n2_('Unexpected error'));
|
35 |
+
$this->response->error();
|
36 |
+
}
|
37 |
+
|
38 |
+
public function actionGenerateImage() {
|
39 |
+
$this->validateToken();
|
40 |
+
|
41 |
+
$device = Request::$REQUEST->getVar('device');
|
42 |
+
$this->validateVariable($device == 'tablet' || $device == 'mobile', 'device');
|
43 |
+
|
44 |
+
$image = Request::$REQUEST->getVar('image');
|
45 |
+
$this->validateVariable(!empty($image), 'image');
|
46 |
+
|
47 |
+
$scale = array(
|
48 |
+
'tablet' => 0.5,
|
49 |
+
'mobile' => 0.3
|
50 |
+
);
|
51 |
+
|
52 |
+
$newImage = ImageEdit::scaleImage('image', $image, $scale[$device], true);
|
53 |
+
|
54 |
+
$this->response->respond(array(
|
55 |
+
'image' => ResourceTranslator::toUrl($newImage)
|
56 |
+
));
|
57 |
+
}
|
58 |
+
|
59 |
+
public function actionAddVisual() {
|
60 |
+
$this->validateToken();
|
61 |
+
|
62 |
+
$image = Request::$REQUEST->getVar('image');
|
63 |
+
$this->validateVariable(!empty($image), 'image');
|
64 |
+
|
65 |
+
$model = $this->getModel();
|
66 |
+
|
67 |
+
if (($visual = $model->addVisual($image, Request::$REQUEST->getVar('value')))) {
|
68 |
+
$this->response->respond(array(
|
69 |
+
'visual' => $visual
|
70 |
+
));
|
71 |
+
}
|
72 |
+
|
73 |
+
Notification::error(n2_('Unexpected error'));
|
74 |
+
$this->response->error();
|
75 |
+
}
|
76 |
+
|
77 |
+
public function actionDeleteVisual() {
|
78 |
+
$this->validateToken();
|
79 |
+
|
80 |
+
$visualId = Request::$REQUEST->getInt('visualId');
|
81 |
+
$this->validateVariable($visualId > 0, 'image');
|
82 |
+
|
83 |
+
$model = $this->getModel();
|
84 |
+
|
85 |
+
if (($visual = $model->deleteVisual($visualId))) {
|
86 |
+
$this->response->respond(array(
|
87 |
+
'visual' => $visual
|
88 |
+
));
|
89 |
+
}
|
90 |
+
|
91 |
+
Notification::error(n2_('Not editable'));
|
92 |
+
$this->response->error();
|
93 |
+
}
|
94 |
+
|
95 |
+
public function actionChangeVisual() {
|
96 |
+
$this->validateToken();
|
97 |
+
|
98 |
+
$visualId = Request::$REQUEST->getInt('visualId');
|
99 |
+
$this->validateVariable($visualId > 0, 'image');
|
100 |
+
|
101 |
+
$model = $this->getModel();
|
102 |
+
|
103 |
+
if (($visual = $model->changeVisual($visualId, Request::$REQUEST->getVar('value')))) {
|
104 |
+
$this->response->respond(array(
|
105 |
+
'visual' => $visual
|
106 |
+
));
|
107 |
+
}
|
108 |
+
|
109 |
+
Notification::error(n2_('Unexpected error'));
|
110 |
+
$this->response->error();
|
111 |
+
}
|
112 |
+
|
113 |
+
public function getModel() {
|
114 |
+
return new ModelImage($this);
|
115 |
+
}
|
116 |
+
}
|
Nextend/Framework/Image/Image.php
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Image;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
7 |
+
use Nextend\Framework\Image\Joomla\JoomlaImage;
|
8 |
+
use Nextend\Framework\Image\WordPress\WordPressImage;
|
9 |
+
use Nextend\Framework\Misc\Base64;
|
10 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
11 |
+
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
|
12 |
+
|
13 |
+
class Image {
|
14 |
+
|
15 |
+
use SingletonTrait;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @var AbstractPlatformImage
|
19 |
+
*/
|
20 |
+
private static $platformImage;
|
21 |
+
|
22 |
+
public function __construct() {
|
23 |
+
self::$platformImage = new WordPressImage();
|
24 |
+
}
|
25 |
+
|
26 |
+
public static function init() {
|
27 |
+
|
28 |
+
if (!self::$platformImage) {
|
29 |
+
new Image();
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
public static function enqueueHelper() {
|
34 |
+
$parameters = array(
|
35 |
+
'siteKeywords' => ResourceTranslator::getResourceIdentifierKeywords(),
|
36 |
+
'imageUrls' => ResourceTranslator::getResourceIdentifierUrls(),
|
37 |
+
'protocolRelative' => ResourceTranslator::isProtocolRelative()
|
38 |
+
);
|
39 |
+
|
40 |
+
$parameters['placeholderImage'] = '$ss3-frontend$/images/placeholder/image.png';
|
41 |
+
$parameters['placeholderRepeatedImage'] = '$ss3-frontend$/images/placeholder/image.png';
|
42 |
+
|
43 |
+
Js::addFirstCode('new N2Classes.ImageHelper(' . json_encode($parameters) . ');');
|
44 |
+
}
|
45 |
+
|
46 |
+
public static function initLightbox() {
|
47 |
+
|
48 |
+
self::$platformImage->initLightbox();
|
49 |
+
}
|
50 |
+
|
51 |
+
public static function onImageUploaded($filename) {
|
52 |
+
|
53 |
+
self::$platformImage->onImageUploaded($filename);
|
54 |
+
}
|
55 |
+
|
56 |
+
public static function SVGToBase64($image) {
|
57 |
+
|
58 |
+
$ext = pathinfo($image, PATHINFO_EXTENSION);
|
59 |
+
if ($ext == 'svg' && ResourceTranslator::isResource($image)) {
|
60 |
+
return 'data:image/svg+xml;base64,' . Base64::encode(Filesystem::readFile(ResourceTranslator::toPath($image)));
|
61 |
+
}
|
62 |
+
|
63 |
+
return ResourceTranslator::toUrl($image);
|
64 |
+
}
|
65 |
+
}
|
Nextend/Framework/Image/ImageEdit.php
ADDED
@@ -0,0 +1,457 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Image;
|
5 |
+
|
6 |
+
|
7 |
+
use Exception;
|
8 |
+
use Nextend\Framework\Cache\CacheImage;
|
9 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
10 |
+
use Nextend\Framework\Misc\Base64;
|
11 |
+
use Nextend\Framework\Parser\Color;
|
12 |
+
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
|
13 |
+
use Nextend\Framework\Url\Url;
|
14 |
+
|
15 |
+
class ImageEdit {
|
16 |
+
|
17 |
+
public static function resizeImage($group, $imageUrl, $targetWidth, $targetHeight, $lazy = false, $mode = 'cover', $backgroundColor = false, $resizeRemote = false, $quality = 100, $optimize = false, $x = 50, $y = 50) {
|
18 |
+
|
19 |
+
if (strpos($imageUrl, Filesystem::getBasePath()) === 0) {
|
20 |
+
$imageUrl = Url::pathToUri($imageUrl);
|
21 |
+
}
|
22 |
+
|
23 |
+
if ($targetWidth <= 0 || $targetHeight <= 0 || !function_exists('imagecreatefrompng')) {
|
24 |
+
return Filesystem::pathToAbsoluteURL($$imageUrl);
|
25 |
+
}
|
26 |
+
|
27 |
+
|
28 |
+
$quality = max(0, min(100, $quality));
|
29 |
+
$originalImageUrl = $imageUrl;
|
30 |
+
|
31 |
+
if (substr($imageUrl, 0, 2) == '//') {
|
32 |
+
$imageUrl = parse_url(Url::getFullUri(), PHP_URL_SCHEME) . ':' . $imageUrl;
|
33 |
+
}
|
34 |
+
|
35 |
+
if (strpos($imageUrl, Filesystem::getBasePath()) !== 0) {
|
36 |
+
$imageUrl = Url::relativetoabsolute($imageUrl);
|
37 |
+
$imagePath = Filesystem::absoluteURLToPath($imageUrl);
|
38 |
+
} else {
|
39 |
+
$imagePath = $imageUrl;
|
40 |
+
}
|
41 |
+
|
42 |
+
$cache = new CacheImage($group);
|
43 |
+
if ($lazy) {
|
44 |
+
$cache->setLazy(true);
|
45 |
+
}
|
46 |
+
|
47 |
+
if ($imagePath == $imageUrl) {
|
48 |
+
// The image is not local
|
49 |
+
if (!$resizeRemote) {
|
50 |
+
return Filesystem::pathToAbsoluteURL($originalImageUrl);
|
51 |
+
}
|
52 |
+
|
53 |
+
$pathInfo = pathinfo(parse_url($imageUrl, PHP_URL_PATH));
|
54 |
+
$extension = self::validateExtension($pathInfo['extension']);
|
55 |
+
if (!$extension) {
|
56 |
+
return Filesystem::pathToAbsoluteURL($originalImageUrl);
|
57 |
+
}
|
58 |
+
|
59 |
+
$resizedPath = $cache->makeCache($extension, array(
|
60 |
+
self::class,
|
61 |
+
'_resizeRemoteImage'
|
62 |
+
), array(
|
63 |
+
$extension,
|
64 |
+
$imageUrl,
|
65 |
+
$targetWidth,
|
66 |
+
$targetHeight,
|
67 |
+
$mode,
|
68 |
+
$backgroundColor,
|
69 |
+
$quality,
|
70 |
+
$optimize,
|
71 |
+
$x,
|
72 |
+
$y
|
73 |
+
));
|
74 |
+
|
75 |
+
if (substr($resizedPath, 0, 5) == 'http:' || substr($resizedPath, 0, 6) == 'https:') {
|
76 |
+
return $resizedPath;
|
77 |
+
}
|
78 |
+
|
79 |
+
if ($resizedPath === $originalImageUrl) {
|
80 |
+
return Filesystem::pathToAbsoluteURL($originalImageUrl);
|
81 |
+
}
|
82 |
+
|
83 |
+
return Filesystem::pathToAbsoluteURL($resizedPath);
|
84 |
+
|
85 |
+
} else {
|
86 |
+
$extension = false;
|
87 |
+
$imageType = @self::exif_imagetype($imagePath);
|
88 |
+
switch ($imageType) {
|
89 |
+
case IMAGETYPE_JPEG:
|
90 |
+
$extension = 'jpg';
|
91 |
+
break;
|
92 |
+
case IMAGETYPE_PNG:
|
93 |
+
$extension = 'png';
|
94 |
+
break;
|
95 |
+
}
|
96 |
+
if (!$extension) {
|
97 |
+
return Filesystem::pathToAbsoluteURL($originalImageUrl);
|
98 |
+
}
|
99 |
+
|
100 |
+
return Filesystem::pathToAbsoluteURL($cache->makeCache($extension, array(
|
101 |
+
self::class,
|
102 |
+
'_resizeImage'
|
103 |
+
), array(
|
104 |
+
$extension,
|
105 |
+
$imagePath,
|
106 |
+
$targetWidth,
|
107 |
+
$targetHeight,
|
108 |
+
$mode,
|
109 |
+
$backgroundColor,
|
110 |
+
$quality,
|
111 |
+
$optimize,
|
112 |
+
$x,
|
113 |
+
$y
|
114 |
+
)));
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
public static function _resizeRemoteImage($targetFile, $extension, $imageUrl, $targetWidth, $targetHeight, $mode, $backgroundColor, $quality, $optimize, $x, $y) {
|
119 |
+
return self::_resizeImage($targetFile, $extension, $imageUrl, $targetWidth, $targetHeight, $mode, $backgroundColor, $quality, $optimize, $x, $y);
|
120 |
+
}
|
121 |
+
|
122 |
+
public static function _resizeImage($targetFile, $extension, $imagePath, $targetWidth, $targetHeight, $mode, $backgroundColor, $quality = 100, $optimize = false, $x = 50, $y = 50) {
|
123 |
+
$targetDir = dirname($targetFile);
|
124 |
+
|
125 |
+
$rotated = false;
|
126 |
+
|
127 |
+
if ($extension == 'png') {
|
128 |
+
$image = @imagecreatefrompng($imagePath);
|
129 |
+
} else if ($extension == 'jpg') {
|
130 |
+
$image = @imagecreatefromjpeg($imagePath);
|
131 |
+
if (function_exists("exif_read_data")) {
|
132 |
+
$exif = @exif_read_data($imagePath);
|
133 |
+
|
134 |
+
$rotated = self::getOrientation($exif, $image);
|
135 |
+
if ($rotated) {
|
136 |
+
imagedestroy($image);
|
137 |
+
$image = $rotated;
|
138 |
+
}
|
139 |
+
}
|
140 |
+
}
|
141 |
+
|
142 |
+
if (isset($image) && $image) {
|
143 |
+
$originalWidth = imagesx($image);
|
144 |
+
$originalHeight = imagesy($image);
|
145 |
+
|
146 |
+
if ($optimize) {
|
147 |
+
|
148 |
+
if ($originalWidth <= $targetWidth || $originalHeight <= $targetHeight) {
|
149 |
+
if (!Filesystem::existsFolder($targetDir)) {
|
150 |
+
Filesystem::createFolder($targetDir);
|
151 |
+
}
|
152 |
+
if ($extension == 'png') {
|
153 |
+
imagepng($image, $targetFile);
|
154 |
+
} else if ($extension == 'jpg') {
|
155 |
+
imagejpeg($image, $targetFile, $quality);
|
156 |
+
}
|
157 |
+
imagedestroy($image);
|
158 |
+
|
159 |
+
return true;
|
160 |
+
}
|
161 |
+
|
162 |
+
if ($originalWidth / $targetWidth > $originalHeight / $targetHeight) {
|
163 |
+
$targetWidth = $originalWidth / ($originalHeight / $targetHeight);
|
164 |
+
} else {
|
165 |
+
$targetHeight = $originalHeight / ($originalWidth / $targetWidth);
|
166 |
+
}
|
167 |
+
}
|
168 |
+
if ($rotated || $originalWidth != $targetWidth || $originalHeight != $targetHeight) {
|
169 |
+
$newImage = imagecreatetruecolor($targetWidth, $targetHeight);
|
170 |
+
if ($extension == 'png') {
|
171 |
+
imagesavealpha($newImage, true);
|
172 |
+
imagealphablending($newImage, false);
|
173 |
+
$transparent = imagecolorallocatealpha($newImage, 255, 255, 255, 127);
|
174 |
+
imagefilledrectangle($image, 0, 0, $targetWidth, $targetHeight, $transparent);
|
175 |
+
} else if ($extension == 'jpg' && $backgroundColor) {
|
176 |
+
$rgb = Color::hex2rgb($backgroundColor);
|
177 |
+
$background = imagecolorallocate($newImage, $rgb[0], $rgb[1], $rgb[2]);
|
178 |
+
imagefilledrectangle($newImage, 0, 0, $targetWidth, $targetHeight, $background);
|
179 |
+
}
|
180 |
+
|
181 |
+
list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = self::imageMode($targetWidth, $targetHeight, $originalWidth, $originalHeight, $mode, $x, $y);
|
182 |
+
imagecopyresampled($newImage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
|
183 |
+
imagedestroy($image);
|
184 |
+
|
185 |
+
} else {
|
186 |
+
$newImage = $image;
|
187 |
+
}
|
188 |
+
|
189 |
+
if (!Filesystem::existsFolder($targetDir)) {
|
190 |
+
Filesystem::createFolder($targetDir);
|
191 |
+
}
|
192 |
+
if ($extension == 'png') {
|
193 |
+
imagepng($newImage, $targetFile);
|
194 |
+
} else if ($extension == 'jpg') {
|
195 |
+
imagejpeg($newImage, $targetFile, $quality);
|
196 |
+
}
|
197 |
+
imagedestroy($newImage);
|
198 |
+
|
199 |
+
return true;
|
200 |
+
}
|
201 |
+
|
202 |
+
throw new Exception('Unable to resize image: ' . $imagePath);
|
203 |
+
}
|
204 |
+
|
205 |
+
public static function scaleImage($group, $imageUrl, $scale = 1, $resizeRemote = false, $quality = 100) {
|
206 |
+
|
207 |
+
if ($scale <= 0 || !function_exists('imagecreatefrompng')) {
|
208 |
+
return Filesystem::pathToAbsoluteURL($imageUrl);
|
209 |
+
}
|
210 |
+
|
211 |
+
$quality = max(0, min(100, $quality));
|
212 |
+
$originalImageUrl = $imageUrl;
|
213 |
+
$imageUrl = ResourceTranslator::toUrl($imageUrl);
|
214 |
+
|
215 |
+
|
216 |
+
if (substr($imageUrl, 0, 2) == '//') {
|
217 |
+
$imageUrl = parse_url(Url::getFullUri(), PHP_URL_SCHEME) . ':' . $imageUrl;
|
218 |
+
}
|
219 |
+
|
220 |
+
if (strpos($imageUrl, Filesystem::getBasePath()) !== 0) {
|
221 |
+
$imageUrl = Url::relativetoabsolute($imageUrl);
|
222 |
+
$imagePath = Filesystem::absoluteURLToPath($imageUrl);
|
223 |
+
} else {
|
224 |
+
$imagePath = $imageUrl;
|
225 |
+
}
|
226 |
+
|
227 |
+
$cache = new CacheImage($group);
|
228 |
+
if ($imagePath == $imageUrl) {
|
229 |
+
// The image is not local
|
230 |
+
if (!$resizeRemote) {
|
231 |
+
return Filesystem::pathToAbsoluteURL($originalImageUrl);
|
232 |
+
}
|
233 |
+
|
234 |
+
$pathInfo = pathinfo(parse_url($imageUrl, PHP_URL_PATH));
|
235 |
+
$extension = self::validateExtension($pathInfo['extension']);
|
236 |
+
if (!$extension) {
|
237 |
+
return Filesystem::pathToAbsoluteURL($originalImageUrl);
|
238 |
+
}
|
239 |
+
|
240 |
+
return ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($cache->makeCache($extension, array(
|
241 |
+
self::class,
|
242 |
+
'_scaleRemoteImage'
|
243 |
+
), array(
|
244 |
+
$extension,
|
245 |
+
$imageUrl,
|
246 |
+
$scale,
|
247 |
+
$quality
|
248 |
+
))));
|
249 |
+
|
250 |
+
} else {
|
251 |
+
$extension = false;
|
252 |
+
$imageType = @self::exif_imagetype($imagePath);
|
253 |
+
switch ($imageType) {
|
254 |
+
case IMAGETYPE_JPEG:
|
255 |
+
$extension = 'jpg';
|
256 |
+
break;
|
257 |
+
case IMAGETYPE_PNG:
|
258 |
+
$extension = 'png';
|
259 |
+
$fp = fopen($imagePath, 'r');
|
260 |
+
fseek($fp, 25);
|
261 |
+
$data = fgets($fp, 2);
|
262 |
+
fclose($fp);
|
263 |
+
if (ord($data) == 3) {
|
264 |
+
// GD cannot resize palette PNG so we return the original image
|
265 |
+
return Filesystem::pathToAbsoluteURL($originalImageUrl);
|
266 |
+
}
|
267 |
+
break;
|
268 |
+
}
|
269 |
+
if (!$extension) {
|
270 |
+
return Filesystem::pathToAbsoluteURL($originalImageUrl);
|
271 |
+
}
|
272 |
+
|
273 |
+
return ResourceTranslator::urlToResource(Filesystem::pathToAbsoluteURL($cache->makeCache($extension, array(
|
274 |
+
self::class,
|
275 |
+
'_scaleImage'
|
276 |
+
), array(
|
277 |
+
$extension,
|
278 |
+
$imagePath,
|
279 |
+
$scale,
|
280 |
+
$quality
|
281 |
+
))));
|
282 |
+
}
|
283 |
+
}
|
284 |
+
|
285 |
+
public static function _scaleRemoteImage($targetFile, $extension, $imageUrl, $scale, $quality) {
|
286 |
+
return self::_scaleImage($targetFile, $extension, $imageUrl, $scale, $quality);
|
287 |
+
}
|
288 |
+
|
289 |
+
public static function _scaleImage($targetFile, $extension, $imagePath, $scale, $quality = 100) {
|
290 |
+
$targetDir = dirname($targetFile);
|
291 |
+
|
292 |
+
$image = false;
|
293 |
+
|
294 |
+
if ($extension == 'png') {
|
295 |
+
$image = @imagecreatefrompng($imagePath);
|
296 |
+
} else if ($extension == 'jpg') {
|
297 |
+
$image = @imagecreatefromjpeg($imagePath);
|
298 |
+
if (function_exists("exif_read_data")) {
|
299 |
+
$exif = @exif_read_data($imagePath);
|
300 |
+
|
301 |
+
$rotated = self::getOrientation($exif, $image);
|
302 |
+
if ($rotated) {
|
303 |
+
imagedestroy($image);
|
304 |
+
$image = $rotated;
|
305 |
+
}
|
306 |
+
}
|
307 |
+
}
|
308 |
+
|
309 |
+
if ($image) {
|
310 |
+
$originalWidth = imagesx($image);
|
311 |
+
$originalHeight = imagesy($image);
|
312 |
+
$targetWidth = $originalWidth * $scale;
|
313 |
+
$targetHeight = $originalHeight * $scale;
|
314 |
+
if ((isset($rotated) && $rotated) || $originalWidth != $targetWidth || $originalHeight != $targetHeight) {
|
315 |
+
$newImage = imagecreatetruecolor($targetWidth, $targetHeight);
|
316 |
+
if ($extension == 'png') {
|
317 |
+
imagesavealpha($newImage, true);
|
318 |
+
imagealphablending($newImage, false);
|
319 |
+
$transparent = imagecolorallocatealpha($newImage, 255, 255, 255, 127);
|
320 |
+
imagefilledrectangle($image, 0, 0, $targetWidth, $targetHeight, $transparent);
|
321 |
+
}
|
322 |
+
|
323 |
+
list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = self::imageMode($targetWidth, $targetHeight, $originalWidth, $originalHeight);
|
324 |
+
imagecopyresampled($newImage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
|
325 |
+
imagedestroy($image);
|
326 |
+
|
327 |
+
} else {
|
328 |
+
$newImage = $image;
|
329 |
+
}
|
330 |
+
|
331 |
+
if (!Filesystem::existsFolder($targetDir)) {
|
332 |
+
Filesystem::createFolder($targetDir);
|
333 |
+
}
|
334 |
+
if ($extension == 'png') {
|
335 |
+
imagepng($newImage, $targetFile);
|
336 |
+
} else if ($extension == 'jpg') {
|
337 |
+
imagejpeg($newImage, $targetFile, $quality);
|
338 |
+
}
|
339 |
+
imagedestroy($newImage);
|
340 |
+
|
341 |
+
return true;
|
342 |
+
}
|
343 |
+
|
344 |
+
throw new Exception('Unable to scale image: ' . $imagePath);
|
345 |
+
}
|
346 |
+
|
347 |
+
private static function getOrientation($exif, $image) {
|
348 |
+
if ($exif && !empty($exif['Orientation'])) {
|
349 |
+
$rotated = false;
|
350 |
+
switch ($exif['Orientation']) {
|
351 |
+
case 3:
|
352 |
+
$rotated = imagerotate($image, 180, 0);
|
353 |
+
break;
|
354 |
+
|
355 |
+
case 6:
|
356 |
+
$rotated = imagerotate($image, -90, 0);
|
357 |
+
break;
|
358 |
+
|
359 |
+
case 8:
|
360 |
+
$rotated = imagerotate($image, 90, 0);
|
361 |
+
break;
|
362 |
+
}
|
363 |
+
|
364 |
+
return $rotated;
|
365 |
+
}
|
366 |
+
|
367 |
+
return false;
|
368 |
+
}
|
369 |
+
|
370 |
+
private static function imageMode($width, $height, $originalWidth, $OriginalHeight, $mode = 'cover', $x = 50, $y = 50) {
|
371 |
+
$dst_x = 0;
|
372 |
+
$dst_y = 0;
|
373 |
+
$src_x = 0;
|
374 |
+
$src_y = 0;
|
375 |
+
$dst_w = $width;
|
376 |
+
$dst_h = $height;
|
377 |
+
$src_w = $originalWidth;
|
378 |
+
$src_h = $OriginalHeight;
|
379 |
+
$horizontalRatio = $width / $originalWidth;
|
380 |
+
$verticalRatio = $height / $OriginalHeight;
|
381 |
+
if ($mode == 'cover') {
|
382 |
+
if ($horizontalRatio > $verticalRatio) {
|
383 |
+
$new_h = $horizontalRatio * $OriginalHeight;
|
384 |
+
$dst_y = ($height - $new_h) / 2 * $y / 50;
|
385 |
+
$dst_h = $new_h;
|
386 |
+
} else {
|
387 |
+
$new_w = $verticalRatio * $originalWidth;
|
388 |
+
$dst_x = ($width - $new_w) / 2 * $x / 50;
|
389 |
+
$dst_w = $new_w;
|
390 |
+
}
|
391 |
+
} else if ($mode == 'contain') {
|
392 |
+
if ($horizontalRatio < $verticalRatio) {
|
393 |
+
$new_h = $horizontalRatio * $OriginalHeight;
|
394 |
+
$dst_y = ($height - $new_h) / 2 * $y / 50;
|
395 |
+
$dst_h = $new_h;
|
396 |
+
} else {
|
397 |
+
$new_w = $verticalRatio * $originalWidth;
|
398 |
+
$dst_x = ($width - $new_w) / 2 * $x / 50;
|
399 |
+
$dst_w = $new_w;
|
400 |
+
}
|
401 |
+
}
|
402 |
+
|
403 |
+
return array(
|
404 |
+
$dst_x,
|
405 |
+
$dst_y,
|
406 |
+
$src_x,
|
407 |
+
$src_y,
|
408 |
+
$dst_w,
|
409 |
+
$dst_h,
|
410 |
+
$src_w,
|
411 |
+
$src_h
|
412 |
+
);
|
413 |
+
}
|
414 |
+
|
415 |
+
private static function validateExtension($extension) {
|
416 |
+
static $validExtensions = array(
|
417 |
+
'png' => 'png',
|
418 |
+
'jpg' => 'jpg',
|
419 |
+
'jpeg' => 'jpg',
|
420 |
+
'gif' => 'gif',
|
421 |
+
'webp' => 'webp',
|
422 |
+
'svg' => 'svg'
|
423 |
+
);
|
424 |
+
$extension = strtolower($extension);
|
425 |
+
if (isset($validExtensions[$extension])) {
|
426 |
+
return $validExtensions[$extension];
|
427 |
+
}
|
428 |
+
|
429 |
+
return false;
|
430 |
+
}
|
431 |
+
|
432 |
+
public static function base64Transparent() {
|
433 |
+
return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
434 |
+
}
|
435 |
+
|
436 |
+
public static function base64($imagePath, $image) {
|
437 |
+
$pathInfo = pathinfo(parse_url($imagePath, PHP_URL_PATH));
|
438 |
+
$extension = self::validateExtension($pathInfo['extension']);
|
439 |
+
if ($extension) {
|
440 |
+
return 'data:image/' . $extension . ';base64,' . Base64::encode(Filesystem::readFile($imagePath));
|
441 |
+
}
|
442 |
+
|
443 |
+
return ResourceTranslator::toUrl($image);
|
444 |
+
}
|
445 |
+
|
446 |
+
public static function exif_imagetype($filename) {
|
447 |
+
if (!function_exists('exif_imagetype')) {
|
448 |
+
if ((list($width, $height, $type, $attr) = getimagesize($filename)) !== false) {
|
449 |
+
return $type;
|
450 |
+
}
|
451 |
+
|
452 |
+
return false;
|
453 |
+
}
|
454 |
+
|
455 |
+
return exif_imagetype($filename);
|
456 |
+
}
|
457 |
+
}
|
Nextend/Framework/Image/ImageManager.php
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Image;
|
4 |
+
|
5 |
+
use Nextend\Framework\Image\Block\ImageManager\BlockImageManager;
|
6 |
+
use Nextend\Framework\Misc\Base64;
|
7 |
+
use Nextend\Framework\Pattern\VisualManagerTrait;
|
8 |
+
|
9 |
+
class ImageManager {
|
10 |
+
|
11 |
+
use VisualManagerTrait;
|
12 |
+
/**
|
13 |
+
* @var ImageStorage
|
14 |
+
*/
|
15 |
+
private static $model;
|
16 |
+
|
17 |
+
public static $loaded = array();
|
18 |
+
|
19 |
+
public function display() {
|
20 |
+
|
21 |
+
$imageManagerBlock = new BlockImageManager($this->MVCHelper);
|
22 |
+
$imageManagerBlock->display();
|
23 |
+
}
|
24 |
+
|
25 |
+
public static function init() {
|
26 |
+
self::$model = new ImageStorage();
|
27 |
+
}
|
28 |
+
|
29 |
+
public static function hasImageData($image) {
|
30 |
+
$image = self::$model->getByImage($image);
|
31 |
+
if (!empty($image)) {
|
32 |
+
return true;
|
33 |
+
}
|
34 |
+
|
35 |
+
return false;
|
36 |
+
}
|
37 |
+
|
38 |
+
public static function getImageData($image, $read = false) {
|
39 |
+
$visual = self::$model->getByImage($image);
|
40 |
+
if (empty($visual)) {
|
41 |
+
if ($read) {
|
42 |
+
return false;
|
43 |
+
} else {
|
44 |
+
$id = self::addImageData($image, ImageStorage::$emptyImage);
|
45 |
+
$visual = self::$model->getById($id);
|
46 |
+
}
|
47 |
+
}
|
48 |
+
self::$loaded[] = $visual;
|
49 |
+
|
50 |
+
return array_merge(ImageStorage::$emptyImage, json_decode(Base64::decode($visual['value']), true));
|
51 |
+
}
|
52 |
+
|
53 |
+
public static function addImageData($image, $value) {
|
54 |
+
return self::$model->add($image, $value);
|
55 |
+
}
|
56 |
+
|
57 |
+
public static function setImageData($image, $value) {
|
58 |
+
self::$model->setByImage($image, $value);
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
ImageManager::init();
|
Nextend/Framework/Image/ImageStorage.php
ADDED
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Image;
|
4 |
+
|
5 |
+
use Nextend\Framework\Database\Base\AbstractConnectorTable;
|
6 |
+
use Nextend\Framework\Database\Database;
|
7 |
+
use Nextend\Framework\Misc\Base64;
|
8 |
+
|
9 |
+
class ImageStorage {
|
10 |
+
|
11 |
+
/** @var AbstractConnectorTable */
|
12 |
+
private $tableImageStorage;
|
13 |
+
|
14 |
+
public static $emptyImage = array(
|
15 |
+
'desktop' => array(
|
16 |
+
'size' => '0|*|0'
|
17 |
+
),
|
18 |
+
'desktop-retina' => array(
|
19 |
+
'image' => '',
|
20 |
+
'size' => '0|*|0'
|
21 |
+
),
|
22 |
+
'tablet' => array(
|
23 |
+
'image' => '',
|
24 |
+
'size' => '0|*|0'
|
25 |
+
),
|
26 |
+
'tablet-retina' => array(
|
27 |
+
'image' => '',
|
28 |
+
'size' => '0|*|0'
|
29 |
+
),
|
30 |
+
'mobile' => array(
|
31 |
+
'image' => '',
|
32 |
+
'size' => '0|*|0'
|
33 |
+
),
|
34 |
+
'mobile-retina' => array(
|
35 |
+
'image' => '',
|
36 |
+
'size' => '0|*|0'
|
37 |
+
)
|
38 |
+
);
|
39 |
+
|
40 |
+
public function __construct() {
|
41 |
+
$this->tableImageStorage = Database::getTable("nextend2_image_storage");
|
42 |
+
}
|
43 |
+
|
44 |
+
public function getById($id) {
|
45 |
+
return $this->tableImageStorage->findByAttributes(array(
|
46 |
+
"id" => $id
|
47 |
+
));
|
48 |
+
}
|
49 |
+
|
50 |
+
public function getByImage($image) {
|
51 |
+
static $cache = array();
|
52 |
+
|
53 |
+
if (!isset($cache[$image])) {
|
54 |
+
$cache[$image] = $this->tableImageStorage->findByAttributes(array(
|
55 |
+
"hash" => md5($image)
|
56 |
+
));
|
57 |
+
}
|
58 |
+
|
59 |
+
return $cache[$image];
|
60 |
+
}
|
61 |
+
|
62 |
+
public function setById($id, $value) {
|
63 |
+
|
64 |
+
if (is_array($value)) {
|
65 |
+
$value = Base64::encode(json_encode($value));
|
66 |
+
}
|
67 |
+
|
68 |
+
$result = $this->getById($id);
|
69 |
+
|
70 |
+
if ($result !== null) {
|
71 |
+
$this->tableImageStorage->update(array('value' => $value), array(
|
72 |
+
"id" => $id
|
73 |
+
));
|
74 |
+
|
75 |
+
return true;
|
76 |
+
}
|
77 |
+
|
78 |
+
return false;
|
79 |
+
}
|
80 |
+
|
81 |
+
public function setByImage($image, $value) {
|
82 |
+
|
83 |
+
if (is_array($value)) {
|
84 |
+
$value = Base64::encode(json_encode($value));
|
85 |
+
}
|
86 |
+
|
87 |
+
$result = $this->getByImage($image);
|
88 |
+
|
89 |
+
if ($result !== null) {
|
90 |
+
$this->tableImageStorage->update(array('value' => $value), array(
|
91 |
+
"id" => $result['id']
|
92 |
+
));
|
93 |
+
|
94 |
+
return true;
|
95 |
+
}
|
96 |
+
|
97 |
+
return false;
|
98 |
+
}
|
99 |
+
|
100 |
+
public function getAll() {
|
101 |
+
return $this->tableImageStorage->findAllByAttributes(array(), array(
|
102 |
+
"id",
|
103 |
+
"hash",
|
104 |
+
"image",
|
105 |
+
"value"
|
106 |
+
));
|
107 |
+
}
|
108 |
+
|
109 |
+
public function set($image, $value) {
|
110 |
+
|
111 |
+
if (is_array($value)) {
|
112 |
+
$value = Base64::encode(json_encode($value));
|
113 |
+
}
|
114 |
+
|
115 |
+
$result = $this->getByImage($image);
|
116 |
+
|
117 |
+
if (empty($result)) {
|
118 |
+
return $this->add($image, $value);
|
119 |
+
} else {
|
120 |
+
$attributes = array(
|
121 |
+
"id" => $result['id']
|
122 |
+
);
|
123 |
+
$this->tableImageStorage->update(array('value' => $value), $attributes);
|
124 |
+
|
125 |
+
return true;
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
public function add($image, $value) {
|
130 |
+
|
131 |
+
if (is_array($value)) {
|
132 |
+
$value = Base64::encode(json_encode($value));
|
133 |
+
}
|
134 |
+
|
135 |
+
$this->tableImageStorage->insert(array(
|
136 |
+
"hash" => md5($image),
|
137 |
+
"image" => $image,
|
138 |
+
"value" => $value
|
139 |
+
));
|
140 |
+
|
141 |
+
return $this->tableImageStorage->insertId();
|
142 |
+
}
|
143 |
+
|
144 |
+
public function deleteById($id) {
|
145 |
+
|
146 |
+
$this->tableImageStorage->deleteByAttributes(array(
|
147 |
+
"id" => $id
|
148 |
+
));
|
149 |
+
|
150 |
+
return true;
|
151 |
+
}
|
152 |
+
|
153 |
+
public function deleteByImage($image) {
|
154 |
+
|
155 |
+
$this->tableImageStorage->deleteByAttributes(array(
|
156 |
+
"hash" => md5($image)
|
157 |
+
));
|
158 |
+
|
159 |
+
return true;
|
160 |
+
}
|
161 |
+
}
|
Nextend/Framework/Image/ModelImage.php
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Image;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Form\Container\ContainerTable;
|
8 |
+
use Nextend\Framework\Form\ContainerInterface;
|
9 |
+
use Nextend\Framework\Form\Element\EmptyArea;
|
10 |
+
use Nextend\Framework\Form\Element\Text\FieldImage;
|
11 |
+
use Nextend\Framework\Form\Form;
|
12 |
+
use Nextend\Framework\Visual\ModelVisual;
|
13 |
+
|
14 |
+
class ModelImage extends ModelVisual {
|
15 |
+
|
16 |
+
protected $type = 'image';
|
17 |
+
|
18 |
+
/** @var ImageStorage */
|
19 |
+
protected $storage;
|
20 |
+
|
21 |
+
protected function init() {
|
22 |
+
|
23 |
+
$this->storage = new ImageStorage();
|
24 |
+
}
|
25 |
+
|
26 |
+
|
27 |
+
public function renderForm() {
|
28 |
+
$form = new Form($this, 'n2-image-editor');
|
29 |
+
$container = $form->getContainer();
|
30 |
+
|
31 |
+
$desktopTable = new ContainerTable($container, 'desktop', n2_('Desktop'));
|
32 |
+
|
33 |
+
$previewRow = $desktopTable->createRow('desktop-preview');
|
34 |
+
|
35 |
+
new EmptyArea($previewRow, 'desktop-preview', n2_('Preview'));
|
36 |
+
|
37 |
+
$this->renderDeviceTab($container, 'desktop-retina', n2_('Desktop retina'));
|
38 |
+
$this->renderDeviceTab($container, 'tablet', n2_('Tablet'));
|
39 |
+
$this->renderDeviceTab($container, 'tablet-retina', n2_('Tablet retina'));
|
40 |
+
$this->renderDeviceTab($container, 'mobile', n2_('Mobile'));
|
41 |
+
$this->renderDeviceTab($container, 'mobile-retina', n2_('Mobile retina'));
|
42 |
+
|
43 |
+
$form->render();
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* @param ContainerInterface $container
|
48 |
+
*/
|
49 |
+
private function renderDeviceTab($container, $name, $label) {
|
50 |
+
|
51 |
+
$table = new ContainerTable($container, $name, $label);
|
52 |
+
|
53 |
+
$row1 = $table->createRow('desktop-row-1');
|
54 |
+
|
55 |
+
new FieldImage($row1, $name . '-image', n2_('Image'));
|
56 |
+
|
57 |
+
$previewRow = $table->createRow($name . '-preview');
|
58 |
+
new EmptyArea($previewRow, $name . '-preview', n2_('Preview'));
|
59 |
+
|
60 |
+
}
|
61 |
+
|
62 |
+
public function addVisual($image, $visual) {
|
63 |
+
|
64 |
+
$visualId = $this->storage->add($image, $visual);
|
65 |
+
|
66 |
+
$visual = $this->storage->getById($visualId);
|
67 |
+
if (!empty($visual)) {
|
68 |
+
return $visual;
|
69 |
+
}
|
70 |
+
|
71 |
+
return false;
|
72 |
+
}
|
73 |
+
|
74 |
+
public function getVisual($image) {
|
75 |
+
return $this->storage->getByImage($image);
|
76 |
+
}
|
77 |
+
|
78 |
+
public function deleteVisual($id) {
|
79 |
+
$visual = $this->storage->getById($id);
|
80 |
+
$this->storage->deleteById($id);
|
81 |
+
|
82 |
+
return $visual;
|
83 |
+
}
|
84 |
+
|
85 |
+
public function changeVisual($id, $value) {
|
86 |
+
if ($this->storage->setById($id, $value)) {
|
87 |
+
return $this->storage->getById($id);
|
88 |
+
}
|
89 |
+
|
90 |
+
return false;
|
91 |
+
}
|
92 |
+
|
93 |
+
public function getVisuals($setId) {
|
94 |
+
return $this->storage->getAll();
|
95 |
+
}
|
96 |
+
}
|
Nextend/Framework/Image/WordPress/WordPressImage.php
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Image\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Image\AbstractPlatformImage;
|
6 |
+
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
|
7 |
+
use function wp_check_filetype;
|
8 |
+
use function wp_upload_dir;
|
9 |
+
|
10 |
+
class WordPressImage extends AbstractPlatformImage {
|
11 |
+
|
12 |
+
public function __construct() {
|
13 |
+
$wp_upload_dir = wp_upload_dir();
|
14 |
+
ResourceTranslator::createResource('$upload$', rtrim($wp_upload_dir['basedir'], "/\\"), rtrim($wp_upload_dir['baseurl'], "/\\"));
|
15 |
+
}
|
16 |
+
|
17 |
+
public function initLightbox() {
|
18 |
+
|
19 |
+
wp_enqueue_media();
|
20 |
+
}
|
21 |
+
|
22 |
+
public function onImageUploaded($filename) {
|
23 |
+
$filename = str_replace(DIRECTORY_SEPARATOR, '/', $filename); // fix for Windows servers
|
24 |
+
|
25 |
+
// Check the type of file. We'll use this as the 'post_mime_type'.
|
26 |
+
$filetype = wp_check_filetype(basename($filename), null);
|
27 |
+
|
28 |
+
// Get the path to the upload directory.
|
29 |
+
$wp_upload_dir = wp_upload_dir();
|
30 |
+
|
31 |
+
// Prepare an array of post data for the attachment.
|
32 |
+
$attachment = array(
|
33 |
+
'guid' => $wp_upload_dir['url'] . '/' . basename($filename),
|
34 |
+
'post_mime_type' => $filetype['type'],
|
35 |
+
'post_title' => preg_replace('/\.[^.]+$/', '', basename($filename)),
|
36 |
+
'post_content' => '',
|
37 |
+
'post_status' => 'inherit'
|
38 |
+
);
|
39 |
+
|
40 |
+
// Insert the attachment.
|
41 |
+
$attach_id = wp_insert_attachment($attachment, $filename);
|
42 |
+
|
43 |
+
// Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
|
44 |
+
require_once(ABSPATH . 'wp-admin/includes/image.php');
|
45 |
+
|
46 |
+
// Generate the metadata for the attachment, and update the database record.
|
47 |
+
$attach_data = wp_generate_attachment_metadata($attach_id, $filename);
|
48 |
+
wp_update_attachment_metadata($attach_id, $attach_data);
|
49 |
+
}
|
50 |
+
}
|
Nextend/Framework/Localization/AbstractLocalization.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Localization;
|
4 |
+
|
5 |
+
abstract class AbstractLocalization {
|
6 |
+
|
7 |
+
public function getLocale() {
|
8 |
+
return 'en_US';
|
9 |
+
}
|
10 |
+
}
|
Nextend/Framework/Localization/Functions.php
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
use Nextend\Framework\Localization\Localization;
|
4 |
+
|
5 |
+
function n2_($text, $domain = 'nextend') {
|
6 |
+
$translations = Localization::getTranslationsForDomain($domain);
|
7 |
+
|
8 |
+
return $translations->translate($text);
|
9 |
+
}
|
10 |
+
|
11 |
+
function n2_e($text, $domain = 'nextend') {
|
12 |
+
echo n2_($text, $domain);
|
13 |
+
}
|
14 |
+
|
15 |
+
function n2_n($single, $plural, $number, $domain = 'nextend') {
|
16 |
+
$translations = Localization::getTranslationsForDomain($domain);
|
17 |
+
|
18 |
+
return $translations->translate_plural($single, $plural, $number);
|
19 |
+
}
|
20 |
+
|
21 |
+
function n2_en($single, $plural, $number, $domain = 'nextend') {
|
22 |
+
echo n2_n($single, $plural, $number, $domain);
|
23 |
+
}
|
24 |
+
|
25 |
+
function n2_x($text, $context, $domain = 'nextend') {
|
26 |
+
$translations = Localization::getTranslationsForDomain($domain);
|
27 |
+
|
28 |
+
return $translations->translate($text, $context);
|
29 |
+
}
|
30 |
+
|
31 |
+
function n2_ex($text, $context, $domain = 'nextend') {
|
32 |
+
echo n2_x($text, $context, $domain);
|
33 |
+
}
|
Nextend/Framework/Localization/Localization.php
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Localization;
|
4 |
+
|
5 |
+
use MO;
|
6 |
+
use Nextend\Framework\Localization\Joomla\JoomlaLocalization;
|
7 |
+
use Nextend\Framework\Localization\WordPress\WordPressLocalization;
|
8 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
9 |
+
use Nextend\Framework\Settings;
|
10 |
+
use NOOP_Translations;
|
11 |
+
|
12 |
+
class Localization {
|
13 |
+
|
14 |
+
use SingletonTrait;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @var AbstractLocalization
|
18 |
+
*/
|
19 |
+
private static $platformLocalization;
|
20 |
+
|
21 |
+
private static $l10n = array();
|
22 |
+
|
23 |
+
private static $js = array();
|
24 |
+
|
25 |
+
protected function init() {
|
26 |
+
|
27 |
+
require_once 'Pomo/translations.php';
|
28 |
+
require_once 'Pomo/mo.php';
|
29 |
+
require_once 'Functions.php';
|
30 |
+
self::$platformLocalization = new WordPressLocalization();
|
31 |
+
}
|
32 |
+
|
33 |
+
public static function getLocale() {
|
34 |
+
return self::$platformLocalization->getLocale();
|
35 |
+
}
|
36 |
+
|
37 |
+
private static function loadTextDomain($domain, $mofile) {
|
38 |
+
if (!is_readable($mofile)) return false;
|
39 |
+
|
40 |
+
$mo = new MO();
|
41 |
+
if (!$mo->import_from_file($mofile)) return false;
|
42 |
+
|
43 |
+
if (isset(self::$l10n[$domain])) $mo->merge_with(self::$l10n[$domain]);
|
44 |
+
self::$l10n[$domain] = &$mo;
|
45 |
+
|
46 |
+
return true;
|
47 |
+
}
|
48 |
+
|
49 |
+
public static function loadPluginTextDomain($path, $domain = 'nextend') {
|
50 |
+
if (Settings::get('force-english-backend')) {
|
51 |
+
$locale = 'en_EN';
|
52 |
+
} else {
|
53 |
+
$locale = self::getLocale();
|
54 |
+
}
|
55 |
+
$mofile = $locale . '.mo';
|
56 |
+
if ($loaded = self::loadTextDomain($domain, $path . '/' . $mofile)) {
|
57 |
+
return $loaded;
|
58 |
+
}
|
59 |
+
|
60 |
+
return false;
|
61 |
+
}
|
62 |
+
|
63 |
+
public static function getTranslationsForDomain($domain) {
|
64 |
+
if (!isset(self::$l10n[$domain])) {
|
65 |
+
self::$l10n[$domain] = new NOOP_Translations;
|
66 |
+
}
|
67 |
+
|
68 |
+
return self::$l10n[$domain];
|
69 |
+
}
|
70 |
+
|
71 |
+
public static function addJS($texts) {
|
72 |
+
foreach ((array)$texts as $text) {
|
73 |
+
self::$js[$text] = n2_($text);
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
public static function toJS() {
|
78 |
+
if (count(self::$js)) {
|
79 |
+
return 'window.nextend.localization = ' . json_encode(self::$js) . ';';
|
80 |
+
}
|
81 |
+
|
82 |
+
return '';
|
83 |
+
}
|
84 |
+
}
|
Nextend/Framework/Localization/Pomo/entry.php
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Contains Translation_Entry class
|
4 |
+
*
|
5 |
+
* @version $Id: entry.php 1157 2015-11-20 04:30:11Z dd32 $
|
6 |
+
* @package pomo
|
7 |
+
* @subpackage entry
|
8 |
+
*/
|
9 |
+
|
10 |
+
if (!class_exists('Translation_Entry', false)):
|
11 |
+
/**
|
12 |
+
* Translation_Entry class encapsulates a translatable string
|
13 |
+
*/
|
14 |
+
class Translation_Entry {
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Whether the entry contains a string and its plural form, default is false
|
18 |
+
*
|
19 |
+
* @var boolean
|
20 |
+
*/
|
21 |
+
var $is_plural = false;
|
22 |
+
|
23 |
+
var $context = null;
|
24 |
+
var $singular = null;
|
25 |
+
var $plural = null;
|
26 |
+
var $translations = array();
|
27 |
+
var $translator_comments = '';
|
28 |
+
var $extracted_comments = '';
|
29 |
+
var $references = array();
|
30 |
+
var $flags = array();
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @param array $args associative array, support following keys:
|
34 |
+
* - singular (string) -- the string to translate, if omitted and empty entry will be created
|
35 |
+
* - plural (string) -- the plural form of the string, setting this will set {@link $is_plural} to true
|
36 |
+
* - translations (array) -- translations of the string and possibly -- its plural forms
|
37 |
+
* - context (string) -- a string differentiating two equal strings used in different contexts
|
38 |
+
* - translator_comments (string) -- comments left by translators
|
39 |
+
* - extracted_comments (string) -- comments left by developers
|
40 |
+
* - references (array) -- places in the code this strings is used, in relative_to_root_path/file.php:linenum form
|
41 |
+
* - flags (array) -- flags like php-format
|
42 |
+
*/
|
43 |
+
function __construct($args = array()) {
|
44 |
+
// if no singular -- empty object
|
45 |
+
if (!isset($args['singular'])) {
|
46 |
+
return;
|
47 |
+
}
|
48 |
+
// get member variable values from args hash
|
49 |
+
foreach ($args as $varname => $value) {
|
50 |
+
$this->$varname = $value;
|
51 |
+
}
|
52 |
+
if (isset($args['plural']) && $args['plural']) $this->is_plural = true;
|
53 |
+
if (!is_array($this->translations)) $this->translations = array();
|
54 |
+
if (!is_array($this->references)) $this->references = array();
|
55 |
+
if (!is_array($this->flags)) $this->flags = array();
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* PHP4 constructor.
|
60 |
+
*/
|
61 |
+
public function Translation_Entry($args = array()) {
|
62 |
+
self::__construct($args);
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Generates a unique key for this entry
|
67 |
+
*
|
68 |
+
* @return string|bool the key or false if the entry is empty
|
69 |
+
*/
|
70 |
+
function key() {
|
71 |
+
if (null === $this->singular || '' === $this->singular) return false;
|
72 |
+
|
73 |
+
// Prepend context and EOT, like in MO files
|
74 |
+
$key = !$this->context ? $this->singular : $this->context . chr(4) . $this->singular;
|
75 |
+
// Standardize on \n line endings
|
76 |
+
$key = str_replace(array(
|
77 |
+
"\r\n",
|
78 |
+
"\r"
|
79 |
+
), "\n", $key);
|
80 |
+
|
81 |
+
return $key;
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* @param object $other
|
86 |
+
*/
|
87 |
+
function merge_with(&$other) {
|
88 |
+
$this->flags = array_unique(array_merge($this->flags, $other->flags));
|
89 |
+
$this->references = array_unique(array_merge($this->references, $other->references));
|
90 |
+
if ($this->extracted_comments != $other->extracted_comments) {
|
91 |
+
$this->extracted_comments .= $other->extracted_comments;
|
92 |
+
}
|
93 |
+
|
94 |
+
}
|
95 |
+
}
|
96 |
+
endif;
|
Nextend/Framework/Localization/Pomo/mo.php
ADDED
@@ -0,0 +1,338 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class for working with MO files
|
4 |
+
*
|
5 |
+
* @version $Id: mo.php 1157 2015-11-20 04:30:11Z dd32 $
|
6 |
+
* @package pomo
|
7 |
+
* @subpackage mo
|
8 |
+
*/
|
9 |
+
|
10 |
+
require_once dirname(__FILE__) . '/translations.php';
|
11 |
+
require_once dirname(__FILE__) . '/streams.php';
|
12 |
+
|
13 |
+
if (!class_exists('MO', false)):
|
14 |
+
class MO extends Gettext_Translations {
|
15 |
+
|
16 |
+
var $_nplurals = 2;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Loaded MO file.
|
20 |
+
*
|
21 |
+
* @var string
|
22 |
+
*/
|
23 |
+
private $filename = '';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Returns the loaded MO file.
|
27 |
+
*
|
28 |
+
* @return string The loaded MO file.
|
29 |
+
*/
|
30 |
+
public function get_filename() {
|
31 |
+
return $this->filename;
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Fills up with the entries from MO file $filename
|
36 |
+
*
|
37 |
+
* @param string $filename MO file to load
|
38 |
+
*/
|
39 |
+
function import_from_file($filename) {
|
40 |
+
$reader = new POMO_FileReader($filename);
|
41 |
+
|
42 |
+
if (!$reader->is_resource()) {
|
43 |
+
return false;
|
44 |
+
}
|
45 |
+
|
46 |
+
$this->filename = (string)$filename;
|
47 |
+
|
48 |
+
return $this->import_from_reader($reader);
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* @param string $filename
|
53 |
+
*
|
54 |
+
* @return bool
|
55 |
+
*/
|
56 |
+
function export_to_file($filename) {
|
57 |
+
$fh = fopen($filename, 'wb');
|
58 |
+
if (!$fh) return false;
|
59 |
+
$res = $this->export_to_file_handle($fh);
|
60 |
+
fclose($fh);
|
61 |
+
|
62 |
+
return $res;
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* @return string|false
|
67 |
+
*/
|
68 |
+
function export() {
|
69 |
+
$tmp_fh = fopen("php://temp", 'r+');
|
70 |
+
if (!$tmp_fh) return false;
|
71 |
+
$this->export_to_file_handle($tmp_fh);
|
72 |
+
rewind($tmp_fh);
|
73 |
+
|
74 |
+
return stream_get_contents($tmp_fh);
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* @param Translation_Entry $entry
|
79 |
+
*
|
80 |
+
* @return bool
|
81 |
+
*/
|
82 |
+
function is_entry_good_for_export($entry) {
|
83 |
+
if (empty($entry->translations)) {
|
84 |
+
return false;
|
85 |
+
}
|
86 |
+
|
87 |
+
if (!array_filter($entry->translations)) {
|
88 |
+
return false;
|
89 |
+
}
|
90 |
+
|
91 |
+
return true;
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* @param resource $fh
|
96 |
+
*
|
97 |
+
* @return true
|
98 |
+
*/
|
99 |
+
function export_to_file_handle($fh) {
|
100 |
+
$entries = array_filter($this->entries, array(
|
101 |
+
$this,
|
102 |
+
'is_entry_good_for_export'
|
103 |
+
));
|
104 |
+
ksort($entries);
|
105 |
+
$magic = 0x950412de;
|
106 |
+
$revision = 0;
|
107 |
+
$total = count($entries) + 1; // all the headers are one entry
|
108 |
+
$originals_lenghts_addr = 28;
|
109 |
+
$translations_lenghts_addr = $originals_lenghts_addr + 8 * $total;
|
110 |
+
$size_of_hash = 0;
|
111 |
+
$hash_addr = $translations_lenghts_addr + 8 * $total;
|
112 |
+
$current_addr = $hash_addr;
|
113 |
+
fwrite($fh, pack('V*', $magic, $revision, $total, $originals_lenghts_addr, $translations_lenghts_addr, $size_of_hash, $hash_addr));
|
114 |
+
fseek($fh, $originals_lenghts_addr);
|
115 |
+
|
116 |
+
// headers' msgid is an empty string
|
117 |
+
fwrite($fh, pack('VV', 0, $current_addr));
|
118 |
+
$current_addr++;
|
119 |
+
$originals_table = chr(0);
|
120 |
+
|
121 |
+
$reader = new POMO_Reader();
|
122 |
+
|
123 |
+
foreach ($entries as $entry) {
|
124 |
+
$originals_table .= $this->export_original($entry) . chr(0);
|
125 |
+
$length = $reader->strlen($this->export_original($entry));
|
126 |
+
fwrite($fh, pack('VV', $length, $current_addr));
|
127 |
+
$current_addr += $length + 1; // account for the NULL byte after
|
128 |
+
}
|
129 |
+
|
130 |
+
$exported_headers = $this->export_headers();
|
131 |
+
fwrite($fh, pack('VV', $reader->strlen($exported_headers), $current_addr));
|
132 |
+
$current_addr += strlen($exported_headers) + 1;
|
133 |
+
$translations_table = $exported_headers . chr(0);
|
134 |
+
|
135 |
+
foreach ($entries as $entry) {
|
136 |
+
$translations_table .= $this->export_translations($entry) . chr(0);
|
137 |
+
$length = $reader->strlen($this->export_translations($entry));
|
138 |
+
fwrite($fh, pack('VV', $length, $current_addr));
|
139 |
+
$current_addr += $length + 1;
|
140 |
+
}
|
141 |
+
|
142 |
+
fwrite($fh, $originals_table);
|
143 |
+
fwrite($fh, $translations_table);
|
144 |
+
|
145 |
+
return true;
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* @param Translation_Entry $entry
|
150 |
+
*
|
151 |
+
* @return string
|
152 |
+
*/
|
153 |
+
function export_original($entry) {
|
154 |
+
//TODO: warnings for control characters
|
155 |
+
$exported = $entry->singular;
|
156 |
+
if ($entry->is_plural) $exported .= chr(0) . $entry->plural;
|
157 |
+
if ($entry->context) $exported = $entry->context . chr(4) . $exported;
|
158 |
+
|
159 |
+
return $exported;
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* @param Translation_Entry $entry
|
164 |
+
*
|
165 |
+
* @return string
|
166 |
+
*/
|
167 |
+
function export_translations($entry) {
|
168 |
+
//TODO: warnings for control characters
|
169 |
+
return $entry->is_plural ? implode(chr(0), $entry->translations) : $entry->translations[0];
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
* @return string
|
174 |
+
*/
|
175 |
+
function export_headers() {
|
176 |
+
$exported = '';
|
177 |
+
foreach ($this->headers as $header => $value) {
|
178 |
+
$exported .= "$header: $value\n";
|
179 |
+
}
|
180 |
+
|
181 |
+
return $exported;
|
182 |
+
}
|
183 |
+
|
184 |
+
/**
|
185 |
+
* @param int $magic
|
186 |
+
*
|
187 |
+
* @return string|false
|
188 |
+
*/
|
189 |
+
function get_byteorder($magic) {
|
190 |
+
// The magic is 0x950412de
|
191 |
+
|
192 |
+
// bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
|
193 |
+
$magic_little = (int)-1794895138;
|
194 |
+
$magic_little_64 = (int)2500072158;
|
195 |
+
// 0xde120495
|
196 |
+
$magic_big = ((int)-569244523) & 0xFFFFFFFF;
|
197 |
+
if ($magic_little == $magic || $magic_little_64 == $magic) {
|
198 |
+
return 'little';
|
199 |
+
} else if ($magic_big == $magic) {
|
200 |
+
return 'big';
|
201 |
+
} else {
|
202 |
+
return false;
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* @param POMO_FileReader $reader
|
208 |
+
*/
|
209 |
+
function import_from_reader($reader) {
|
210 |
+
$endian_string = MO::get_byteorder($reader->readint32());
|
211 |
+
if (false === $endian_string) {
|
212 |
+
return false;
|
213 |
+
}
|
214 |
+
$reader->setEndian($endian_string);
|
215 |
+
|
216 |
+
$endian = ('big' == $endian_string) ? 'N' : 'V';
|
217 |
+
|
218 |
+
$header = $reader->read(24);
|
219 |
+
if ($reader->strlen($header) != 24) return false;
|
220 |
+
|
221 |
+
// parse header
|
222 |
+
$header = unpack("{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header);
|
223 |
+
if (!is_array($header)) return false;
|
224 |
+
|
225 |
+
// support revision 0 of MO format specs, only
|
226 |
+
if ($header['revision'] != 0) {
|
227 |
+
return false;
|
228 |
+
}
|
229 |
+
|
230 |
+
// seek to data blocks
|
231 |
+
$reader->seekto($header['originals_lenghts_addr']);
|
232 |
+
|
233 |
+
// read originals' indices
|
234 |
+
$originals_lengths_length = $header['translations_lenghts_addr'] - $header['originals_lenghts_addr'];
|
235 |
+
if ($originals_lengths_length != $header['total'] * 8) {
|
236 |
+
return false;
|
237 |
+
}
|
238 |
+
|
239 |
+
$originals = $reader->read($originals_lengths_length);
|
240 |
+
if ($reader->strlen($originals) != $originals_lengths_length) {
|
241 |
+
return false;
|
242 |
+
}
|
243 |
+
|
244 |
+
// read translations' indices
|
245 |
+
$translations_lenghts_length = $header['hash_addr'] - $header['translations_lenghts_addr'];
|
246 |
+
if ($translations_lenghts_length != $header['total'] * 8) {
|
247 |
+
return false;
|
248 |
+
}
|
249 |
+
|
250 |
+
$translations = $reader->read($translations_lenghts_length);
|
251 |
+
if ($reader->strlen($translations) != $translations_lenghts_length) {
|
252 |
+
return false;
|
253 |
+
}
|
254 |
+
|
255 |
+
// transform raw data into set of indices
|
256 |
+
$originals = $reader->str_split($originals, 8);
|
257 |
+
$translations = $reader->str_split($translations, 8);
|
258 |
+
|
259 |
+
// skip hash table
|
260 |
+
$strings_addr = $header['hash_addr'] + $header['hash_length'] * 4;
|
261 |
+
|
262 |
+
$reader->seekto($strings_addr);
|
263 |
+
|
264 |
+
$strings = $reader->read_all();
|
265 |
+
$reader->close();
|
266 |
+
|
267 |
+
for ($i = 0; $i < $header['total']; $i++) {
|
268 |
+
$o = unpack("{$endian}length/{$endian}pos", $originals[$i]);
|
269 |
+
$t = unpack("{$endian}length/{$endian}pos", $translations[$i]);
|
270 |
+
if (!$o || !$t) return false;
|
271 |
+
|
272 |
+
// adjust offset due to reading strings to separate space before
|
273 |
+
$o['pos'] -= $strings_addr;
|
274 |
+
$t['pos'] -= $strings_addr;
|
275 |
+
|
276 |
+
$original = $reader->substr($strings, $o['pos'], $o['length']);
|
277 |
+
$translation = $reader->substr($strings, $t['pos'], $t['length']);
|
278 |
+
|
279 |
+
if ('' === $original) {
|
280 |
+
$this->set_headers($this->make_headers($translation));
|
281 |
+
} else {
|
282 |
+
$entry = &$this->make_entry($original, $translation);
|
283 |
+
$this->entries[$entry->key()] = &$entry;
|
284 |
+
}
|
285 |
+
}
|
286 |
+
|
287 |
+
return true;
|
288 |
+
}
|
289 |
+
|
290 |
+
/**
|
291 |
+
* Build a Translation_Entry from original string and translation strings,
|
292 |
+
* found in a MO file
|
293 |
+
*
|
294 |
+
* @static
|
295 |
+
*
|
296 |
+
* @param string $original original string to translate from MO file. Might contain
|
297 |
+
* 0x04 as context separator or 0x00 as singular/plural separator
|
298 |
+
* @param string $translation translation string from MO file. Might contain
|
299 |
+
* 0x00 as a plural translations separator
|
300 |
+
*/
|
301 |
+
function &make_entry($original, $translation) {
|
302 |
+
$entry = new Translation_Entry();
|
303 |
+
// look for context
|
304 |
+
$parts = explode(chr(4), $original);
|
305 |
+
if (isset($parts[1])) {
|
306 |
+
$original = $parts[1];
|
307 |
+
$entry->context = $parts[0];
|
308 |
+
}
|
309 |
+
// look for plural original
|
310 |
+
$parts = explode(chr(0), $original);
|
311 |
+
$entry->singular = $parts[0];
|
312 |
+
if (isset($parts[1])) {
|
313 |
+
$entry->is_plural = true;
|
314 |
+
$entry->plural = $parts[1];
|
315 |
+
}
|
316 |
+
// plural translations are also separated by \0
|
317 |
+
$entry->translations = explode(chr(0), $translation);
|
318 |
+
|
319 |
+
return $entry;
|
320 |
+
}
|
321 |
+
|
322 |
+
/**
|
323 |
+
* @param int $count
|
324 |
+
*
|
325 |
+
* @return string
|
326 |
+
*/
|
327 |
+
function select_plural_form($count) {
|
328 |
+
return $this->gettext_select_plural_form($count);
|
329 |
+
}
|
330 |
+
|
331 |
+
/**
|
332 |
+
* @return int
|
333 |
+
*/
|
334 |
+
function get_plural_forms_count() {
|
335 |
+
return $this->_nplurals;
|
336 |
+
}
|
337 |
+
}
|
338 |
+
endif;
|
Nextend/Framework/Localization/Pomo/plural-forms.php
ADDED
@@ -0,0 +1,366 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A gettext Plural-Forms parser.
|
5 |
+
*
|
6 |
+
* @since 4.9.0
|
7 |
+
*/
|
8 |
+
if (!class_exists('Plural_Forms', false)):
|
9 |
+
class Plural_Forms {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Operator characters.
|
13 |
+
*
|
14 |
+
* @since 4.9.0
|
15 |
+
* @var string OP_CHARS Operator characters.
|
16 |
+
*/
|
17 |
+
const OP_CHARS = '|&><!=%?:';
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Valid number characters.
|
21 |
+
*
|
22 |
+
* @since 4.9.0
|
23 |
+
* @var string NUM_CHARS Valid number characters.
|
24 |
+
*/
|
25 |
+
const NUM_CHARS = '0123456789';
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Operator precedence.
|
29 |
+
*
|
30 |
+
* Operator precedence from highest to lowest. Higher numbers indicate
|
31 |
+
* higher precedence, and are executed first.
|
32 |
+
*
|
33 |
+
* @see https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
|
34 |
+
*
|
35 |
+
* @since 4.9.0
|
36 |
+
* @var array $op_precedence Operator precedence from highest to lowest.
|
37 |
+
*/
|
38 |
+
protected static $op_precedence = array(
|
39 |
+
'%' => 6,
|
40 |
+
|
41 |
+
'<' => 5,
|
42 |
+
'<=' => 5,
|
43 |
+
'>' => 5,
|
44 |
+
'>=' => 5,
|
45 |
+
|
46 |
+
'==' => 4,
|
47 |
+
'!=' => 4,
|
48 |
+
|
49 |
+
'&&' => 3,
|
50 |
+
|
51 |
+
'||' => 2,
|
52 |
+
|
53 |
+
'?:' => 1,
|
54 |
+
'?' => 1,
|
55 |
+
|
56 |
+
'(' => 0,
|
57 |
+
')' => 0,
|
58 |
+
);
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Tokens generated from the string.
|
62 |
+
*
|
63 |
+
* @since 4.9.0
|
64 |
+
* @var array $tokens List of tokens.
|
65 |
+
*/
|
66 |
+
protected $tokens = array();
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Cache for repeated calls to the function.
|
70 |
+
*
|
71 |
+
* @since 4.9.0
|
72 |
+
* @var array $cache Map of $n => $result
|
73 |
+
*/
|
74 |
+
protected $cache = array();
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Constructor.
|
78 |
+
*
|
79 |
+
* @param string $str Plural function (just the bit after `plural=` from Plural-Forms)
|
80 |
+
*
|
81 |
+
* @since 4.9.0
|
82 |
+
*
|
83 |
+
*/
|
84 |
+
public function __construct($str) {
|
85 |
+
$this->parse($str);
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Parse a Plural-Forms string into tokens.
|
90 |
+
*
|
91 |
+
* Uses the shunting-yard algorithm to convert the string to Reverse Polish
|
92 |
+
* Notation tokens.
|
93 |
+
*
|
94 |
+
* @param string $str String to parse.
|
95 |
+
*
|
96 |
+
* @since 4.9.0
|
97 |
+
*
|
98 |
+
*/
|
99 |
+
protected function parse($str) {
|
100 |
+
$pos = 0;
|
101 |
+
$len = strlen($str);
|
102 |
+
|
103 |
+
// Convert infix operators to postfix using the shunting-yard algorithm.
|
104 |
+
$output = array();
|
105 |
+
$stack = array();
|
106 |
+
while ($pos < $len) {
|
107 |
+
$next = substr($str, $pos, 1);
|
108 |
+
|
109 |
+
switch ($next) {
|
110 |
+
// Ignore whitespace
|
111 |
+
case ' ':
|
112 |
+
case "\t":
|
113 |
+
$pos++;
|
114 |
+
break;
|
115 |
+
|
116 |
+
// Variable (n)
|
117 |
+
case 'n':
|
118 |
+
$output[] = array('var');
|
119 |
+
$pos++;
|
120 |
+
break;
|
121 |
+
|
122 |
+
// Parentheses
|
123 |
+
case '(':
|
124 |
+
$stack[] = $next;
|
125 |
+
$pos++;
|
126 |
+
break;
|
127 |
+
|
128 |
+
case ')':
|
129 |
+
$found = false;
|
130 |
+
while (!empty($stack)) {
|
131 |
+
$o2 = $stack[count($stack) - 1];
|
132 |
+
if ($o2 !== '(') {
|
133 |
+
$output[] = array(
|
134 |
+
'op',
|
135 |
+
array_pop($stack)
|
136 |
+
);
|
137 |
+
continue;
|
138 |
+
}
|
139 |
+
|
140 |
+
// Discard open paren.
|
141 |
+
array_pop($stack);
|
142 |
+
$found = true;
|
143 |
+
break;
|
144 |
+
}
|
145 |
+
|
146 |
+
if (!$found) {
|
147 |
+
throw new Exception('Mismatched parentheses');
|
148 |
+
}
|
149 |
+
|
150 |
+
$pos++;
|
151 |
+
break;
|
152 |
+
|
153 |
+
// Operators
|
154 |
+
case '|':
|
155 |
+
case '&':
|
156 |
+
case '>':
|
157 |
+
case '<':
|
158 |
+
case '!':
|
159 |
+
case '=':
|
160 |
+
case '%':
|
161 |
+
case '?':
|
162 |
+
$end_operator = strspn($str, self::OP_CHARS, $pos);
|
163 |
+
$operator = substr($str, $pos, $end_operator);
|
164 |
+
if (!array_key_exists($operator, self::$op_precedence)) {
|
165 |
+
throw new Exception(sprintf('Unknown operator "%s"', $operator));
|
166 |
+
}
|
167 |
+
|
168 |
+
while (!empty($stack)) {
|
169 |
+
$o2 = $stack[count($stack) - 1];
|
170 |
+
|
171 |
+
// Ternary is right-associative in C
|
172 |
+
if ($operator === '?:' || $operator === '?') {
|
173 |
+
if (self::$op_precedence[$operator] >= self::$op_precedence[$o2]) {
|
174 |
+
break;
|
175 |
+
}
|
176 |
+
} elseif (self::$op_precedence[$operator] > self::$op_precedence[$o2]) {
|
177 |
+
break;
|
178 |
+
}
|
179 |
+
|
180 |
+
$output[] = array(
|
181 |
+
'op',
|
182 |
+
array_pop($stack)
|
183 |
+
);
|
184 |
+
}
|
185 |
+
$stack[] = $operator;
|
186 |
+
|
187 |
+
$pos += $end_operator;
|
188 |
+
break;
|
189 |
+
|
190 |
+
// Ternary "else"
|
191 |
+
case ':':
|
192 |
+
$found = false;
|
193 |
+
$s_pos = count($stack) - 1;
|
194 |
+
while ($s_pos >= 0) {
|
195 |
+
$o2 = $stack[$s_pos];
|
196 |
+
if ($o2 !== '?') {
|
197 |
+
$output[] = array(
|
198 |
+
'op',
|
199 |
+
array_pop($stack)
|
200 |
+
);
|
201 |
+
$s_pos--;
|
202 |
+
continue;
|
203 |
+
}
|
204 |
+
|
205 |
+
// Replace.
|
206 |
+
$stack[$s_pos] = '?:';
|
207 |
+
$found = true;
|
208 |
+
break;
|
209 |
+
}
|
210 |
+
|
211 |
+
if (!$found) {
|
212 |
+
throw new Exception('Missing starting "?" ternary operator');
|
213 |
+
}
|
214 |
+
$pos++;
|
215 |
+
break;
|
216 |
+
|
217 |
+
// Default - number or invalid
|
218 |
+
default:
|
219 |
+
if ($next >= '0' && $next <= '9') {
|
220 |
+
$span = strspn($str, self::NUM_CHARS, $pos);
|
221 |
+
$output[] = array(
|
222 |
+
'value',
|
223 |
+
intval(substr($str, $pos, $span))
|
224 |
+
);
|
225 |
+
$pos += $span;
|
226 |
+
break;
|
227 |
+
}
|
228 |
+
|
229 |
+
throw new Exception(sprintf('Unknown symbol "%s"', $next));
|
230 |
+
}
|
231 |
+
}
|
232 |
+
|
233 |
+
while (!empty($stack)) {
|
234 |
+
$o2 = array_pop($stack);
|
235 |
+
if ($o2 === '(' || $o2 === ')') {
|
236 |
+
throw new Exception('Mismatched parentheses');
|
237 |
+
}
|
238 |
+
|
239 |
+
$output[] = array(
|
240 |
+
'op',
|
241 |
+
$o2
|
242 |
+
);
|
243 |
+
}
|
244 |
+
|
245 |
+
$this->tokens = $output;
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* Get the plural form for a number.
|
250 |
+
*
|
251 |
+
* Caches the value for repeated calls.
|
252 |
+
*
|
253 |
+
* @param int $num Number to get plural form for.
|
254 |
+
*
|
255 |
+
* @return int Plural form value.
|
256 |
+
* @since 4.9.0
|
257 |
+
*
|
258 |
+
*/
|
259 |
+
public function get($num) {
|
260 |
+
if (isset($this->cache[$num])) {
|
261 |
+
return $this->cache[$num];
|
262 |
+
}
|
263 |
+
|
264 |
+
return $this->cache[$num] = $this->execute($num);
|
265 |
+
}
|
266 |
+
|
267 |
+
/**
|
268 |
+
* Execute the plural form function.
|
269 |
+
*
|
270 |
+
* @param int $n Variable "n" to substitute.
|
271 |
+
*
|
272 |
+
* @return int Plural form value.
|
273 |
+
* @since 4.9.0
|
274 |
+
*
|
275 |
+
*/
|
276 |
+
public function execute($n) {
|
277 |
+
$stack = array();
|
278 |
+
$i = 0;
|
279 |
+
$total = count($this->tokens);
|
280 |
+
while ($i < $total) {
|
281 |
+
$next = $this->tokens[$i];
|
282 |
+
$i++;
|
283 |
+
if ($next[0] === 'var') {
|
284 |
+
$stack[] = $n;
|
285 |
+
continue;
|
286 |
+
} elseif ($next[0] === 'value') {
|
287 |
+
$stack[] = $next[1];
|
288 |
+
continue;
|
289 |
+
}
|
290 |
+
|
291 |
+
// Only operators left.
|
292 |
+
switch ($next[1]) {
|
293 |
+
case '%':
|
294 |
+
$v2 = array_pop($stack);
|
295 |
+
$v1 = array_pop($stack);
|
296 |
+
$stack[] = $v1 % $v2;
|
297 |
+
break;
|
298 |
+
|
299 |
+
case '||':
|
300 |
+
$v2 = array_pop($stack);
|
301 |
+
$v1 = array_pop($stack);
|
302 |
+
$stack[] = $v1 || $v2;
|
303 |
+
break;
|
304 |
+
|
305 |
+
case '&&':
|
306 |
+
$v2 = array_pop($stack);
|
307 |
+
$v1 = array_pop($stack);
|
308 |
+
$stack[] = $v1 && $v2;
|
309 |
+
break;
|
310 |
+
|
311 |
+
case '<':
|
312 |
+
$v2 = array_pop($stack);
|
313 |
+
$v1 = array_pop($stack);
|
314 |
+
$stack[] = $v1 < $v2;
|
315 |
+
break;
|
316 |
+
|
317 |
+
case '<=':
|
318 |
+
$v2 = array_pop($stack);
|
319 |
+
$v1 = array_pop($stack);
|
320 |
+
$stack[] = $v1 <= $v2;
|
321 |
+
break;
|
322 |
+
|
323 |
+
case '>':
|
324 |
+
$v2 = array_pop($stack);
|
325 |
+
$v1 = array_pop($stack);
|
326 |
+
$stack[] = $v1 > $v2;
|
327 |
+
break;
|
328 |
+
|
329 |
+
case '>=':
|
330 |
+
$v2 = array_pop($stack);
|
331 |
+
$v1 = array_pop($stack);
|
332 |
+
$stack[] = $v1 >= $v2;
|
333 |
+
break;
|
334 |
+
|
335 |
+
case '!=':
|
336 |
+
$v2 = array_pop($stack);
|
337 |
+
$v1 = array_pop($stack);
|
338 |
+
$stack[] = $v1 != $v2;
|
339 |
+
break;
|
340 |
+
|
341 |
+
case '==':
|
342 |
+
$v2 = array_pop($stack);
|
343 |
+
$v1 = array_pop($stack);
|
344 |
+
$stack[] = $v1 == $v2;
|
345 |
+
break;
|
346 |
+
|
347 |
+
case '?:':
|
348 |
+
$v3 = array_pop($stack);
|
349 |
+
$v2 = array_pop($stack);
|
350 |
+
$v1 = array_pop($stack);
|
351 |
+
$stack[] = $v1 ? $v2 : $v3;
|
352 |
+
break;
|
353 |
+
|
354 |
+
default:
|
355 |
+
throw new Exception(sprintf('Unknown operator "%s"', $next[1]));
|
356 |
+
}
|
357 |
+
}
|
358 |
+
|
359 |
+
if (count($stack) !== 1) {
|
360 |
+
throw new Exception('Too many values remaining on the stack');
|
361 |
+
}
|
362 |
+
|
363 |
+
return (int)$stack[0];
|
364 |
+
}
|
365 |
+
}
|
366 |
+
endif;
|
Nextend/Framework/Localization/Pomo/streams.php
ADDED
@@ -0,0 +1,325 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Classes, which help reading streams of data from files.
|
4 |
+
* Based on the classes from Danilo Segan <danilo@kvota.net>
|
5 |
+
*
|
6 |
+
* @version $Id: streams.php 1157 2015-11-20 04:30:11Z dd32 $
|
7 |
+
* @package pomo
|
8 |
+
* @subpackage streams
|
9 |
+
*/
|
10 |
+
|
11 |
+
if (!class_exists('POMO_Reader', false)):
|
12 |
+
class POMO_Reader {
|
13 |
+
|
14 |
+
var $endian = 'little';
|
15 |
+
var $_post = '';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* PHP5 constructor.
|
19 |
+
*/
|
20 |
+
function __construct() {
|
21 |
+
$this->is_overloaded = ((ini_get("mbstring.func_overload") & 2) != 0) && function_exists('mb_substr');
|
22 |
+
$this->_pos = 0;
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* PHP4 constructor.
|
27 |
+
*/
|
28 |
+
public function POMO_Reader() {
|
29 |
+
self::__construct();
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Sets the endianness of the file.
|
34 |
+
*
|
35 |
+
* @param $endian string 'big' or 'little'
|
36 |
+
*/
|
37 |
+
function setEndian($endian) {
|
38 |
+
$this->endian = $endian;
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Reads a 32bit Integer from the Stream
|
43 |
+
*
|
44 |
+
* @return mixed The integer, corresponding to the next 32 bits from
|
45 |
+
* the stream of false if there are not enough bytes or on error
|
46 |
+
*/
|
47 |
+
function readint32() {
|
48 |
+
$bytes = $this->read(4);
|
49 |
+
if (4 != $this->strlen($bytes)) return false;
|
50 |
+
$endian_letter = ('big' == $this->endian) ? 'N' : 'V';
|
51 |
+
$int = unpack($endian_letter, $bytes);
|
52 |
+
|
53 |
+
return reset($int);
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Reads an array of 32-bit Integers from the Stream
|
58 |
+
*
|
59 |
+
* @param integer count How many elements should be read
|
60 |
+
*
|
61 |
+
* @return mixed Array of integers or false if there isn't
|
62 |
+
* enough data or on error
|
63 |
+
*/
|
64 |
+
function readint32array($count) {
|
65 |
+
$bytes = $this->read(4 * $count);
|
66 |
+
if (4 * $count != $this->strlen($bytes)) return false;
|
67 |
+
$endian_letter = ('big' == $this->endian) ? 'N' : 'V';
|
68 |
+
|
69 |
+
return unpack($endian_letter . $count, $bytes);
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* @param string $string
|
74 |
+
* @param int $start
|
75 |
+
* @param int $length
|
76 |
+
*
|
77 |
+
* @return string
|
78 |
+
*/
|
79 |
+
function substr($string, $start, $length) {
|
80 |
+
if ($this->is_overloaded) {
|
81 |
+
return mb_substr($string, $start, $length, 'ascii');
|
82 |
+
} else {
|
83 |
+
return substr($string, $start, $length);
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* @param string $string
|
89 |
+
*
|
90 |
+
* @return int
|
91 |
+
*/
|
92 |
+
function strlen($string) {
|
93 |
+
if ($this->is_overloaded) {
|
94 |
+
return mb_strlen($string, 'ascii');
|
95 |
+
} else {
|
96 |
+
return strlen($string);
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* @param string $string
|
102 |
+
* @param int $chunk_size
|
103 |
+
*
|
104 |
+
* @return array
|
105 |
+
*/
|
106 |
+
function str_split($string, $chunk_size) {
|
107 |
+
if (!function_exists('str_split')) {
|
108 |
+
$length = $this->strlen($string);
|
109 |
+
$out = array();
|
110 |
+
for ($i = 0; $i < $length; $i += $chunk_size) $out[] = $this->substr($string, $i, $chunk_size);
|
111 |
+
|
112 |
+
return $out;
|
113 |
+
} else {
|
114 |
+
return str_split($string, $chunk_size);
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* @return int
|
120 |
+
*/
|
121 |
+
function pos() {
|
122 |
+
return $this->_pos;
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* @return true
|
127 |
+
*/
|
128 |
+
function is_resource() {
|
129 |
+
return true;
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* @return true
|
134 |
+
*/
|
135 |
+
function close() {
|
136 |
+
return true;
|
137 |
+
}
|
138 |
+
}
|
139 |
+
endif;
|
140 |
+
|
141 |
+
if (!class_exists('POMO_FileReader', false)):
|
142 |
+
class POMO_FileReader extends POMO_Reader {
|
143 |
+
|
144 |
+
/**
|
145 |
+
* @param string $filename
|
146 |
+
*/
|
147 |
+
function __construct($filename) {
|
148 |
+
parent::POMO_Reader();
|
149 |
+
$this->_f = fopen($filename, 'rb');
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* PHP4 constructor.
|
154 |
+
*/
|
155 |
+
public function POMO_FileReader($filename) {
|
156 |
+
self::__construct($filename);
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* @param int $bytes
|
161 |
+
*/
|
162 |
+
function read($bytes) {
|
163 |
+
return fread($this->_f, $bytes);
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* @param int $pos
|
168 |
+
*
|
169 |
+
* @return boolean
|
170 |
+
*/
|
171 |
+
function seekto($pos) {
|
172 |
+
if (-1 == fseek($this->_f, $pos, SEEK_SET)) {
|
173 |
+
return false;
|
174 |
+
}
|
175 |
+
$this->_pos = $pos;
|
176 |
+
|
177 |
+
return true;
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* @return bool
|
182 |
+
*/
|
183 |
+
function is_resource() {
|
184 |
+
return is_resource($this->_f);
|
185 |
+
}
|
186 |
+
|
187 |
+
/**
|
188 |
+
* @return bool
|
189 |
+
*/
|
190 |
+
function feof() {
|
191 |
+
return feof($this->_f);
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* @return bool
|
196 |
+
*/
|
197 |
+
function close() {
|
198 |
+
return fclose($this->_f);
|
199 |
+
}
|
200 |
+
|
201 |
+
/**
|
202 |
+
* @return string
|
203 |
+
*/
|
204 |
+
function read_all() {
|
205 |
+
$all = '';
|
206 |
+
while (!$this->feof()) $all .= $this->read(4096);
|
207 |
+
|
208 |
+
return $all;
|
209 |
+
}
|
210 |
+
}
|
211 |
+
endif;
|
212 |
+
|
213 |
+
if (!class_exists('POMO_StringReader', false)):
|
214 |
+
/**
|
215 |
+
* Provides file-like methods for manipulating a string instead
|
216 |
+
* of a physical file.
|
217 |
+
*/
|
218 |
+
class POMO_StringReader extends POMO_Reader {
|
219 |
+
|
220 |
+
var $_str = '';
|
221 |
+
|
222 |
+
/**
|
223 |
+
* PHP5 constructor.
|
224 |
+
*/
|
225 |
+
function __construct($str = '') {
|
226 |
+
parent::POMO_Reader();
|
227 |
+
$this->_str = $str;
|
228 |
+
$this->_pos = 0;
|
229 |
+
}
|
230 |
+
|
231 |
+
/**
|
232 |
+
* PHP4 constructor.
|
233 |
+
*/
|
234 |
+
public function POMO_StringReader($str = '') {
|
235 |
+
self::__construct($str);
|
236 |
+
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* @param string $bytes
|
240 |
+
*
|
241 |
+
* @return string
|
242 |
+
*/
|
243 |
+
function read($bytes) {
|
244 |
+
$data = $this->substr($this->_str, $this->_pos, $bytes);
|
245 |
+
$this->_pos += $bytes;
|
246 |
+
if ($this->strlen($this->_str) < $this->_pos) $this->_pos = $this->strlen($this->_str);
|
247 |
+
|
248 |
+
return $data;
|
249 |
+
}
|
250 |
+
|
251 |
+
/**
|
252 |
+
* @param int $pos
|
253 |
+
*
|
254 |
+
* @return int
|
255 |
+
*/
|
256 |
+
function seekto($pos) {
|
257 |
+
$this->_pos = $pos;
|
258 |
+
if ($this->strlen($this->_str) < $this->_pos) $this->_pos = $this->strlen($this->_str);
|
259 |
+
|
260 |
+
return $this->_pos;
|
261 |
+
}
|
262 |
+
|
263 |
+
/**
|
264 |
+
* @return int
|
265 |
+
*/
|
266 |
+
function length() {
|
267 |
+
return $this->strlen($this->_str);
|
268 |
+
}
|
269 |
+
|
270 |
+
/**
|
271 |
+
* @return string
|
272 |
+
*/
|
273 |
+
function read_all() {
|
274 |
+
return $this->substr($this->_str, $this->_pos, $this->strlen($this->_str));
|
275 |
+
}
|
276 |
+
|
277 |
+
}
|
278 |
+
endif;
|
279 |
+
|
280 |
+
if (!class_exists('POMO_CachedFileReader', false)):
|
281 |
+
/**
|
282 |
+
* Reads the contents of the file in the beginning.
|
283 |
+
*/
|
284 |
+
class POMO_CachedFileReader extends POMO_StringReader {
|
285 |
+
|
286 |
+
/**
|
287 |
+
* PHP5 constructor.
|
288 |
+
*/
|
289 |
+
function __construct($filename) {
|
290 |
+
parent::POMO_StringReader();
|
291 |
+
$this->_str = file_get_contents($filename);
|
292 |
+
if (false === $this->_str) return false;
|
293 |
+
$this->_pos = 0;
|
294 |
+
}
|
295 |
+
|
296 |
+
/**
|
297 |
+
* PHP4 constructor.
|
298 |
+
*/
|
299 |
+
public function POMO_CachedFileReader($filename) {
|
300 |
+
self::__construct($filename);
|
301 |
+
}
|
302 |
+
}
|
303 |
+
endif;
|
304 |
+
|
305 |
+
if (!class_exists('POMO_CachedIntFileReader', false)):
|
306 |
+
/**
|
307 |
+
* Reads the contents of the file in the beginning.
|
308 |
+
*/
|
309 |
+
class POMO_CachedIntFileReader extends POMO_CachedFileReader {
|
310 |
+
|
311 |
+
/**
|
312 |
+
* PHP5 constructor.
|
313 |
+
*/
|
314 |
+
public function __construct($filename) {
|
315 |
+
parent::POMO_CachedFileReader($filename);
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
* PHP4 constructor.
|
320 |
+
*/
|
321 |
+
function POMO_CachedIntFileReader($filename) {
|
322 |
+
self::__construct($filename);
|
323 |
+
}
|
324 |
+
}
|
325 |
+
endif;
|
Nextend/Framework/Localization/Pomo/translations.php
ADDED
@@ -0,0 +1,392 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class for a set of entries for translation and their associated headers
|
4 |
+
*
|
5 |
+
* @version $Id: translations.php 1157 2015-11-20 04:30:11Z dd32 $
|
6 |
+
* @package pomo
|
7 |
+
* @subpackage translations
|
8 |
+
*/
|
9 |
+
|
10 |
+
require_once dirname(__FILE__) . '/plural-forms.php';
|
11 |
+
require_once dirname(__FILE__) . '/entry.php';
|
12 |
+
|
13 |
+
if (!class_exists('Translations', false)):
|
14 |
+
class Translations {
|
15 |
+
|
16 |
+
var $entries = array();
|
17 |
+
var $headers = array();
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Add entry to the PO structure
|
21 |
+
*
|
22 |
+
* @param array|Translation_Entry $entry
|
23 |
+
*
|
24 |
+
* @return bool true on success, false if the entry doesn't have a key
|
25 |
+
*/
|
26 |
+
function add_entry($entry) {
|
27 |
+
if (is_array($entry)) {
|
28 |
+
$entry = new Translation_Entry($entry);
|
29 |
+
}
|
30 |
+
$key = $entry->key();
|
31 |
+
if (false === $key) return false;
|
32 |
+
$this->entries[$key] = &$entry;
|
33 |
+
|
34 |
+
return true;
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @param array|Translation_Entry $entry
|
39 |
+
*
|
40 |
+
* @return bool
|
41 |
+
*/
|
42 |
+
function add_entry_or_merge($entry) {
|
43 |
+
if (is_array($entry)) {
|
44 |
+
$entry = new Translation_Entry($entry);
|
45 |
+
}
|
46 |
+
$key = $entry->key();
|
47 |
+
if (false === $key) return false;
|
48 |
+
if (isset($this->entries[$key])) $this->entries[$key]->merge_with($entry); else
|
49 |
+
$this->entries[$key] = &$entry;
|
50 |
+
|
51 |
+
return true;
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Sets $header PO header to $value
|
56 |
+
*
|
57 |
+
* If the header already exists, it will be overwritten
|
58 |
+
*
|
59 |
+
* TODO: this should be out of this class, it is gettext specific
|
60 |
+
*
|
61 |
+
* @param string $header header name, without trailing :
|
62 |
+
* @param string $value header value, without trailing \n
|
63 |
+
*/
|
64 |
+
function set_header($header, $value) {
|
65 |
+
$this->headers[$header] = $value;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @param array $headers
|
70 |
+
*/
|
71 |
+
function set_headers($headers) {
|
72 |
+
foreach ($headers as $header => $value) {
|
73 |
+
$this->set_header($header, $value);
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* @param string $header
|
79 |
+
*/
|
80 |
+
function get_header($header) {
|
81 |
+
return isset($this->headers[$header]) ? $this->headers[$header] : false;
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* @param Translation_Entry $entry
|
86 |
+
*/
|
87 |
+
function translate_entry(&$entry) {
|
88 |
+
$key = $entry->key();
|
89 |
+
|
90 |
+
return isset($this->entries[$key]) ? $this->entries[$key] : false;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* @param string $singular
|
95 |
+
* @param string $context
|
96 |
+
*
|
97 |
+
* @return string
|
98 |
+
*/
|
99 |
+
function translate($singular, $context = null) {
|
100 |
+
$entry = new Translation_Entry(array(
|
101 |
+
'singular' => $singular,
|
102 |
+
'context' => $context
|
103 |
+
));
|
104 |
+
$translated = $this->translate_entry($entry);
|
105 |
+
|
106 |
+
return ($translated && !empty($translated->translations)) ? $translated->translations[0] : $singular;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Given the number of items, returns the 0-based index of the plural form to use
|
111 |
+
*
|
112 |
+
* Here, in the base Translations class, the common logic for English is implemented:
|
113 |
+
* 0 if there is one element, 1 otherwise
|
114 |
+
*
|
115 |
+
* This function should be overridden by the sub-classes. For example MO/PO can derive the logic
|
116 |
+
* from their headers.
|
117 |
+
*
|
118 |
+
* @param integer $count number of items
|
119 |
+
*/
|
120 |
+
function select_plural_form($count) {
|
121 |
+
return 1 == $count ? 0 : 1;
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* @return int
|
126 |
+
*/
|
127 |
+
function get_plural_forms_count() {
|
128 |
+
return 2;
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* @param string $singular
|
133 |
+
* @param string $plural
|
134 |
+
* @param int $count
|
135 |
+
* @param string $context
|
136 |
+
*/
|
137 |
+
function translate_plural($singular, $plural, $count, $context = null) {
|
138 |
+
$entry = new Translation_Entry(array(
|
139 |
+
'singular' => $singular,
|
140 |
+
'plural' => $plural,
|
141 |
+
'context' => $context
|
142 |
+
));
|
143 |
+
$translated = $this->translate_entry($entry);
|
144 |
+
$index = $this->select_plural_form($count);
|
145 |
+
$total_plural_forms = $this->get_plural_forms_count();
|
146 |
+
if ($translated && 0 <= $index && $index < $total_plural_forms && is_array($translated->translations) && isset($translated->translations[$index])) return $translated->translations[$index]; else
|
147 |
+
return 1 == $count ? $singular : $plural;
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Merge $other in the current object.
|
152 |
+
*
|
153 |
+
* @param Object $other Another Translation object, whose translations will be merged in this one (passed by reference).
|
154 |
+
*
|
155 |
+
* @return void
|
156 |
+
**/
|
157 |
+
function merge_with(&$other) {
|
158 |
+
foreach ($other->entries as $entry) {
|
159 |
+
$this->entries[$entry->key()] = $entry;
|
160 |
+
}
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* @param object $other
|
165 |
+
*/
|
166 |
+
function merge_originals_with(&$other) {
|
167 |
+
foreach ($other->entries as $entry) {
|
168 |
+
if (!isset($this->entries[$entry->key()])) $this->entries[$entry->key()] = $entry; else
|
169 |
+
$this->entries[$entry->key()]->merge_with($entry);
|
170 |
+
}
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
class Gettext_Translations extends Translations {
|
175 |
+
|
176 |
+
/**
|
177 |
+
* The gettext implementation of select_plural_form.
|
178 |
+
*
|
179 |
+
* It lives in this class, because there are more than one descendand, which will use it and
|
180 |
+
* they can't share it effectively.
|
181 |
+
*
|
182 |
+
* @param int $count
|
183 |
+
*/
|
184 |
+
function gettext_select_plural_form($count) {
|
185 |
+
if (!isset($this->_gettext_select_plural_form) || is_null($this->_gettext_select_plural_form)) {
|
186 |
+
list($nplurals, $expression) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
|
187 |
+
$this->_nplurals = $nplurals;
|
188 |
+
$this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);
|
189 |
+
}
|
190 |
+
|
191 |
+
return call_user_func($this->_gettext_select_plural_form, $count);
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* @param string $header
|
196 |
+
*
|
197 |
+
* @return array
|
198 |
+
*/
|
199 |
+
function nplurals_and_expression_from_header($header) {
|
200 |
+
if (preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches)) {
|
201 |
+
$nplurals = (int)$matches[1];
|
202 |
+
$expression = trim($matches[2]);
|
203 |
+
|
204 |
+
return array(
|
205 |
+
$nplurals,
|
206 |
+
$expression
|
207 |
+
);
|
208 |
+
} else {
|
209 |
+
return array(
|
210 |
+
2,
|
211 |
+
'n != 1'
|
212 |
+
);
|
213 |
+
}
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Makes a function, which will return the right translation index, according to the
|
218 |
+
* plural forms header
|
219 |
+
*
|
220 |
+
* @param int $nplurals
|
221 |
+
* @param string $expression
|
222 |
+
*/
|
223 |
+
function make_plural_form_function($nplurals, $expression) {
|
224 |
+
try {
|
225 |
+
$handler = new Plural_Forms(rtrim($expression, ';'));
|
226 |
+
|
227 |
+
return array(
|
228 |
+
$handler,
|
229 |
+
'get'
|
230 |
+
);
|
231 |
+
} catch (Exception $e) {
|
232 |
+
// Fall back to default plural-form function.
|
233 |
+
return $this->make_plural_form_function(2, 'n != 1');
|
234 |
+
}
|
235 |
+
}
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Adds parentheses to the inner parts of ternary operators in
|
239 |
+
* plural expressions, because PHP evaluates ternary oerators from left to right
|
240 |
+
*
|
241 |
+
* @param string $expression the expression without parentheses
|
242 |
+
*
|
243 |
+
* @return string the expression with parentheses added
|
244 |
+
*/
|
245 |
+
function parenthesize_plural_exression($expression) {
|
246 |
+
$expression .= ';';
|
247 |
+
$res = '';
|
248 |
+
$depth = 0;
|
249 |
+
for ($i = 0; $i < strlen($expression); ++$i) {
|
250 |
+
$char = $expression[$i];
|
251 |
+
switch ($char) {
|
252 |
+
case '?':
|
253 |
+
$res .= ' ? (';
|
254 |
+
$depth++;
|
255 |
+
break;
|
256 |
+
case ':':
|
257 |
+
$res .= ') : (';
|
258 |
+
break;
|
259 |
+
case ';':
|
260 |
+
$res .= str_repeat(')', $depth) . ';';
|
261 |
+
$depth = 0;
|
262 |
+
break;
|
263 |
+
default:
|
264 |
+
$res .= $char;
|
265 |
+
}
|
266 |
+
}
|
267 |
+
|
268 |
+
return rtrim($res, ';');
|
269 |
+
}
|
270 |
+
|
271 |
+
/**
|
272 |
+
* @param string $translation
|
273 |
+
*
|
274 |
+
* @return array
|
275 |
+
*/
|
276 |
+
function make_headers($translation) {
|
277 |
+
$headers = array();
|
278 |
+
// sometimes \ns are used instead of real new lines
|
279 |
+
$translation = str_replace('\n', "\n", $translation);
|
280 |
+
$lines = explode("\n", $translation);
|
281 |
+
foreach ($lines as $line) {
|
282 |
+
$parts = explode(':', $line, 2);
|
283 |
+
if (!isset($parts[1])) continue;
|
284 |
+
$headers[trim($parts[0])] = trim($parts[1]);
|
285 |
+
}
|
286 |
+
|
287 |
+
return $headers;
|
288 |
+
}
|
289 |
+
|
290 |
+
/**
|
291 |
+
* @param string $header
|
292 |
+
* @param string $value
|
293 |
+
*/
|
294 |
+
function set_header($header, $value) {
|
295 |
+
parent::set_header($header, $value);
|
296 |
+
if ('Plural-Forms' == $header) {
|
297 |
+
list($nplurals, $expression) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
|
298 |
+
$this->_nplurals = $nplurals;
|
299 |
+
$this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);
|
300 |
+
}
|
301 |
+
}
|
302 |
+
}
|
303 |
+
endif;
|
304 |
+
|
305 |
+
if (!class_exists('NOOP_Translations', false)):
|
306 |
+
/**
|
307 |
+
* Provides the same interface as Translations, but doesn't do anything
|
308 |
+
*/
|
309 |
+
class NOOP_Translations {
|
310 |
+
|
311 |
+
var $entries = array();
|
312 |
+
var $headers = array();
|
313 |
+
|
314 |
+
function add_entry($entry) {
|
315 |
+
return true;
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
*
|
320 |
+
* @param string $header
|
321 |
+
* @param string $value
|
322 |
+
*/
|
323 |
+
function set_header($header, $value) {
|
324 |
+
}
|
325 |
+
|
326 |
+
/**
|
327 |
+
*
|
328 |
+
* @param array $headers
|
329 |
+
*/
|
330 |
+
function set_headers($headers) {
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
* @param string $header
|
335 |
+
*
|
336 |
+
* @return false
|
337 |
+
*/
|
338 |
+
function get_header($header) {
|
339 |
+
return false;
|
340 |
+
}
|
341 |
+
|
342 |
+
/**
|
343 |
+
* @param Translation_Entry $entry
|
344 |
+
*
|
345 |
+
* @return false
|
346 |
+
*/
|
347 |
+
function translate_entry(&$entry) {
|
348 |
+
return false;
|
349 |
+
}
|
350 |
+
|
351 |
+
/**
|
352 |
+
* @param string $singular
|
353 |
+
* @param string $context
|
354 |
+
*/
|
355 |
+
function translate($singular, $context = null) {
|
356 |
+
return $singular;
|
357 |
+
}
|
358 |
+
|
359 |
+
/**
|
360 |
+
*
|
361 |
+
* @param int $count
|
362 |
+
*
|
363 |
+
* @return bool
|
364 |
+
*/
|
365 |
+
function select_plural_form($count) {
|
366 |
+
return 1 == $count ? 0 : 1;
|
367 |
+
}
|
368 |
+
|
369 |
+
/**
|
370 |
+
* @return int
|
371 |
+
*/
|
372 |
+
function get_plural_forms_count() {
|
373 |
+
return 2;
|
374 |
+
}
|
375 |
+
|
376 |
+
/**
|
377 |
+
* @param string $singular
|
378 |
+
* @param string $plural
|
379 |
+
* @param int $count
|
380 |
+
* @param string $context
|
381 |
+
*/
|
382 |
+
function translate_plural($singular, $plural, $count, $context = null) {
|
383 |
+
return 1 == $count ? $singular : $plural;
|
384 |
+
}
|
385 |
+
|
386 |
+
/**
|
387 |
+
* @param object $other
|
388 |
+
*/
|
389 |
+
function merge_with(&$other) {
|
390 |
+
}
|
391 |
+
}
|
392 |
+
endif;
|
Nextend/Framework/Localization/WordPress/WordPressLocalization.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Localization\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Localization\AbstractLocalization;
|
6 |
+
use function get_locale;
|
7 |
+
use function get_user_locale;
|
8 |
+
use function is_admin;
|
9 |
+
|
10 |
+
class WordPressLocalization extends AbstractLocalization {
|
11 |
+
|
12 |
+
|
13 |
+
public function getLocale() {
|
14 |
+
|
15 |
+
return is_admin() && function_exists('\\get_user_locale') ? get_user_locale() : get_locale();
|
16 |
+
}
|
17 |
+
}
|
Nextend/Framework/Misc/Base64.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc;
|
4 |
+
|
5 |
+
use Nextend\Framework\Misc\Base64\Decoder;
|
6 |
+
use Nextend\Framework\Misc\Base64\Encoder;
|
7 |
+
|
8 |
+
class Base64 {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @param $data
|
12 |
+
*
|
13 |
+
* @return string
|
14 |
+
*/
|
15 |
+
public static function decode($data) {
|
16 |
+
return Decoder::decode($data);
|
17 |
+
}
|
18 |
+
|
19 |
+
public static function encode($data) {
|
20 |
+
return Encoder::encode($data);
|
21 |
+
}
|
22 |
+
}
|
Nextend/Framework/Misc/Base64/Decoder.php
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc\Base64;
|
4 |
+
|
5 |
+
class Decoder {
|
6 |
+
|
7 |
+
public static function decode($data) {
|
8 |
+
|
9 |
+
if (function_exists('base64_decode')) {
|
10 |
+
return base64_decode($data);
|
11 |
+
}
|
12 |
+
|
13 |
+
return self::decodeShim($data);
|
14 |
+
}
|
15 |
+
|
16 |
+
private static function decodeShim($input) {
|
17 |
+
$keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
18 |
+
$i = 0;
|
19 |
+
$output = "";
|
20 |
+
|
21 |
+
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
|
22 |
+
$filter = $input;
|
23 |
+
$input = preg_replace("[^A-Za-z0-9\+\/\=]", "", $input);
|
24 |
+
if ($filter != $input) {
|
25 |
+
return false;
|
26 |
+
}
|
27 |
+
|
28 |
+
do {
|
29 |
+
$enc1 = strpos($keyStr, substr($input, $i++, 1));
|
30 |
+
$enc2 = strpos($keyStr, substr($input, $i++, 1));
|
31 |
+
$enc3 = strpos($keyStr, substr($input, $i++, 1));
|
32 |
+
$enc4 = strpos($keyStr, substr($input, $i++, 1));
|
33 |
+
$chr1 = ($enc1 << 2) | ($enc2 >> 4);
|
34 |
+
$chr2 = (($enc2 & 15) << 4) | ($enc3 >> 2);
|
35 |
+
$chr3 = (($enc3 & 3) << 6) | $enc4;
|
36 |
+
$output = $output . chr((int)$chr1);
|
37 |
+
if ($enc3 != 64) {
|
38 |
+
$output = $output . chr((int)$chr2);
|
39 |
+
}
|
40 |
+
if ($enc4 != 64) {
|
41 |
+
$output = $output . chr((int)$chr3);
|
42 |
+
}
|
43 |
+
} while ($i < strlen($input));
|
44 |
+
|
45 |
+
return urldecode($output);
|
46 |
+
}
|
47 |
+
}
|
Nextend/Framework/Misc/Base64/Encoder.php
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Misc\Base64;
|
5 |
+
|
6 |
+
class Encoder {
|
7 |
+
|
8 |
+
public static function encode($data) {
|
9 |
+
|
10 |
+
if (function_exists('base64_encode')) {
|
11 |
+
return base64_encode($data);
|
12 |
+
}
|
13 |
+
|
14 |
+
return self::encodeShim($data);
|
15 |
+
}
|
16 |
+
|
17 |
+
private static function encodeShim($data) {
|
18 |
+
$b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
19 |
+
$o1 = $o2 = $o3 = $h1 = $h2 = $h3 = $h4 = $bits = $i = 0;
|
20 |
+
$ac = 0;
|
21 |
+
$enc = '';
|
22 |
+
$tmp_arr = array();
|
23 |
+
if (!$data) {
|
24 |
+
return $data;
|
25 |
+
}
|
26 |
+
do {
|
27 |
+
// pack three octets into four hexets
|
28 |
+
$o1 = self::charCodeAt($data, $i++);
|
29 |
+
$o2 = self::charCodeAt($data, $i++);
|
30 |
+
$o3 = self::charCodeAt($data, $i++);
|
31 |
+
$bits = $o1 << 16 | $o2 << 8 | $o3;
|
32 |
+
$h1 = $bits >> 18 & 0x3f;
|
33 |
+
$h2 = $bits >> 12 & 0x3f;
|
34 |
+
$h3 = $bits >> 6 & 0x3f;
|
35 |
+
$h4 = $bits & 0x3f;
|
36 |
+
// use hexets to index into b64, and append result to encoded string
|
37 |
+
$tmp_arr[$ac++] = self::charAt($b64, $h1) . self::charAt($b64, $h2) . self::charAt($b64, $h3) . self::charAt($b64, $h4);
|
38 |
+
} while ($i < strlen($data));
|
39 |
+
$enc = implode('', $tmp_arr);
|
40 |
+
$r = (strlen($data) % 3);
|
41 |
+
|
42 |
+
return ($r ? substr($enc, 0, ($r - 3)) . substr('===', $r) : $enc);
|
43 |
+
}
|
44 |
+
|
45 |
+
private static function charCodeAt($data, $char) {
|
46 |
+
return ord(substr($data, $char, 1));
|
47 |
+
}
|
48 |
+
|
49 |
+
private static function charAt($data, $char) {
|
50 |
+
return substr($data, $char, 1);
|
51 |
+
}
|
52 |
+
}
|
Nextend/Framework/Misc/HttpClient.php
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc;
|
4 |
+
|
5 |
+
use Nextend\Framework\Notification\Notification;
|
6 |
+
use Nextend\Framework\Settings;
|
7 |
+
use Nextend\Framework\View\Html;
|
8 |
+
use Nextend\SmartSlider3\Application\ApplicationSmartSlider3;
|
9 |
+
|
10 |
+
class HttpClient {
|
11 |
+
|
12 |
+
public static function getCacertPath() {
|
13 |
+
return dirname(__FILE__) . '/cacert.pem';
|
14 |
+
}
|
15 |
+
|
16 |
+
public static function get($url, $options = array()) {
|
17 |
+
|
18 |
+
$options = array_merge(array(
|
19 |
+
'referer' => $_SERVER['REQUEST_URI']
|
20 |
+
), $options);
|
21 |
+
|
22 |
+
if (function_exists('curl_init') && function_exists('curl_exec') && Settings::get('curl', 1)) {
|
23 |
+
|
24 |
+
$ch = curl_init();
|
25 |
+
curl_setopt($ch, CURLOPT_URL, $url);
|
26 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
27 |
+
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
|
28 |
+
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
29 |
+
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36');
|
30 |
+
$proxy = new \WP_HTTP_Proxy();
|
31 |
+
|
32 |
+
if ($proxy->is_enabled() && $proxy->send_through_proxy($url)) {
|
33 |
+
|
34 |
+
|
35 |
+
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
36 |
+
|
37 |
+
curl_setopt($ch, CURLOPT_PROXY, $proxy->host());
|
38 |
+
|
39 |
+
curl_setopt($ch, CURLOPT_PROXYPORT, $proxy->port());
|
40 |
+
|
41 |
+
|
42 |
+
if ($proxy->use_authentication()) {
|
43 |
+
|
44 |
+
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
45 |
+
|
46 |
+
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxy->authentication());
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
|
51 |
+
if (!empty($options['referer'])) {
|
52 |
+
curl_setopt($ch, CURLOPT_REFERER, $options['referer']);
|
53 |
+
}
|
54 |
+
|
55 |
+
|
56 |
+
if (Settings::get('curl-clean-proxy', 0)) {
|
57 |
+
curl_setopt($ch, CURLOPT_PROXY, '');
|
58 |
+
}
|
59 |
+
|
60 |
+
$data = curl_exec($ch);
|
61 |
+
if (curl_errno($ch) == 60) {
|
62 |
+
curl_setopt($ch, CURLOPT_CAINFO, self::getCacertPath());
|
63 |
+
$data = curl_exec($ch);
|
64 |
+
}
|
65 |
+
$error = curl_error($ch);
|
66 |
+
$curlErrorNumber = curl_errno($ch);
|
67 |
+
curl_close($ch);
|
68 |
+
|
69 |
+
if ($curlErrorNumber) {
|
70 |
+
|
71 |
+
|
72 |
+
$href = ApplicationSmartSlider3::getInstance()
|
73 |
+
->getApplicationTypeAdmin()
|
74 |
+
->getUrlHelpCurl();
|
75 |
+
|
76 |
+
if (!isset($options['error']) || $options['error'] !== false) {
|
77 |
+
Notification::error(Html::tag('a', array(
|
78 |
+
'href' => $href . '#support-form'
|
79 |
+
), n2_('Debug error')));
|
80 |
+
|
81 |
+
Notification::error($curlErrorNumber . $error);
|
82 |
+
}
|
83 |
+
|
84 |
+
return false;
|
85 |
+
}
|
86 |
+
|
87 |
+
return $data;
|
88 |
+
} else {
|
89 |
+
|
90 |
+
if (!ini_get('allow_url_fopen')) {
|
91 |
+
Notification::error(sprintf(n2_('The %1$s is not turned on in your server, which is necessary to read rss feeds. You should contact your server host, and ask them to enable it!'), '<a href="http://php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen" target="_blank">allow_url_fopen</a>'));
|
92 |
+
|
93 |
+
return false;
|
94 |
+
}
|
95 |
+
|
96 |
+
$opts = array(
|
97 |
+
'http' => array(
|
98 |
+
'method' => 'GET'
|
99 |
+
)
|
100 |
+
);
|
101 |
+
$context = stream_context_create($opts);
|
102 |
+
$data = file_get_contents($url, false, $context);
|
103 |
+
if ($data === false) {
|
104 |
+
Notification::error(n2_('CURL disabled in your php.ini configuration. Please enable it!'));
|
105 |
+
|
106 |
+
return false;
|
107 |
+
}
|
108 |
+
$headers = self::parseHeaders($http_response_header);
|
109 |
+
if ($headers['status'] != '200') {
|
110 |
+
Notification::error(n2_('Unable to contact with the licensing server, please try again later!'));
|
111 |
+
|
112 |
+
return false;
|
113 |
+
}
|
114 |
+
|
115 |
+
return $data;
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
private static function parseHeaders(array $headers, $header = null) {
|
120 |
+
$output = array();
|
121 |
+
if ('HTTP' === substr($headers[0], 0, 4)) {
|
122 |
+
list(, $output['status'], $output['status_text']) = explode(' ', $headers[0]);
|
123 |
+
unset($headers[0]);
|
124 |
+
}
|
125 |
+
foreach ($headers as $v) {
|
126 |
+
$h = preg_split('/:\s*/', $v);
|
127 |
+
if (count($h) >= 2) {
|
128 |
+
$output[strtolower($h[0])] = $h[1];
|
129 |
+
}
|
130 |
+
}
|
131 |
+
if (null !== $header) {
|
132 |
+
if (isset($output[strtolower($header)])) {
|
133 |
+
return $output[strtolower($header)];
|
134 |
+
}
|
135 |
+
|
136 |
+
return null;
|
137 |
+
}
|
138 |
+
|
139 |
+
return $output;
|
140 |
+
}
|
141 |
+
}
|
Nextend/Framework/Misc/OAuth/HTTP.php
ADDED
@@ -0,0 +1,1603 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc\OAuth;
|
4 |
+
|
5 |
+
|
6 |
+
use Nextend\Framework\Misc\Base64;
|
7 |
+
use Nextend\Framework\Misc\HttpClient;
|
8 |
+
|
9 |
+
defined('HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR') || define('HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR', -1);
|
10 |
+
defined('HTTP_CLIENT_ERROR_NO_ERROR') || define('HTTP_CLIENT_ERROR_NO_ERROR', 0);
|
11 |
+
defined('HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS') || define('HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS', 1);
|
12 |
+
defined('HTTP_CLIENT_ERROR_CANNOT_CONNECT') || define('HTTP_CLIENT_ERROR_CANNOT_CONNECT', 2);
|
13 |
+
defined('HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE') || define('HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE', 3);
|
14 |
+
defined('HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE') || define('HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE', 4);
|
15 |
+
defined('HTTP_CLIENT_ERROR_PROTOCOL_FAILURE') || define('HTTP_CLIENT_ERROR_PROTOCOL_FAILURE', 5);
|
16 |
+
defined('HTTP_CLIENT_ERROR_INVALID_PARAMETERS') || define('HTTP_CLIENT_ERROR_INVALID_PARAMETERS', 6);
|
17 |
+
|
18 |
+
class HTTP {
|
19 |
+
|
20 |
+
var $host_name = "";
|
21 |
+
var $host_port = 0;
|
22 |
+
var $proxy_host_name = "";
|
23 |
+
var $proxy_host_port = 80;
|
24 |
+
var $socks_host_name = '';
|
25 |
+
var $socks_host_port = 1080;
|
26 |
+
var $socks_version = '5';
|
27 |
+
|
28 |
+
var $protocol = "http";
|
29 |
+
var $request_method = "GET";
|
30 |
+
var $user_agent = 'httpclient (http://www.phpclasses.org/httpclient $Revision: 1.92 $)';
|
31 |
+
var $accept = '';
|
32 |
+
var $authentication_mechanism = "";
|
33 |
+
var $user;
|
34 |
+
var $password;
|
35 |
+
var $realm;
|
36 |
+
var $workstation;
|
37 |
+
var $proxy_authentication_mechanism = "";
|
38 |
+
var $proxy_user;
|
39 |
+
var $proxy_password;
|
40 |
+
var $proxy_realm;
|
41 |
+
var $proxy_workstation;
|
42 |
+
var $request_uri = "";
|
43 |
+
var $request = "";
|
44 |
+
var $request_headers = array();
|
45 |
+
var $request_user;
|
46 |
+
var $request_password;
|
47 |
+
var $request_realm;
|
48 |
+
var $request_workstation;
|
49 |
+
var $proxy_request_user;
|
50 |
+
var $proxy_request_password;
|
51 |
+
var $proxy_request_realm;
|
52 |
+
var $proxy_request_workstation;
|
53 |
+
var $request_body = "";
|
54 |
+
var $request_arguments = array();
|
55 |
+
var $protocol_version = "1.1";
|
56 |
+
var $timeout = 0;
|
57 |
+
var $data_timeout = 0;
|
58 |
+
var $debug = 0;
|
59 |
+
var $log_debug = 0;
|
60 |
+
var $debug_response_body = 1;
|
61 |
+
var $html_debug = 0;
|
62 |
+
var $support_cookies = 1;
|
63 |
+
var $cookies = array();
|
64 |
+
var $error = "";
|
65 |
+
var $error_code = HTTP_CLIENT_ERROR_NO_ERROR;
|
66 |
+
var $exclude_address = "";
|
67 |
+
var $follow_redirect = 0;
|
68 |
+
var $redirection_limit = 5;
|
69 |
+
var $response_status = "";
|
70 |
+
var $response_message = "";
|
71 |
+
var $file_buffer_length = 8000;
|
72 |
+
var $force_multipart_form_post = 0;
|
73 |
+
var $prefer_curl = 1;
|
74 |
+
var $keep_alive = 1;
|
75 |
+
var $sasl_authenticate = 1;
|
76 |
+
|
77 |
+
/* private variables - DO NOT ACCESS */
|
78 |
+
|
79 |
+
var $state = "Disconnected";
|
80 |
+
var $use_curl = 0;
|
81 |
+
var $connection = 0;
|
82 |
+
var $content_length = 0;
|
83 |
+
var $response = "";
|
84 |
+
var $read_response = 0;
|
85 |
+
var $read_length = 0;
|
86 |
+
var $request_host = "";
|
87 |
+
var $next_token = "";
|
88 |
+
var $redirection_level = 0;
|
89 |
+
var $chunked = 0;
|
90 |
+
var $remaining_chunk = 0;
|
91 |
+
var $last_chunk_read = 0;
|
92 |
+
var $months = array(
|
93 |
+
"Jan" => "01",
|
94 |
+
"Feb" => "02",
|
95 |
+
"Mar" => "03",
|
96 |
+
"Apr" => "04",
|
97 |
+
"May" => "05",
|
98 |
+
"Jun" => "06",
|
99 |
+
"Jul" => "07",
|
100 |
+
"Aug" => "08",
|
101 |
+
"Sep" => "09",
|
102 |
+
"Oct" => "10",
|
103 |
+
"Nov" => "11",
|
104 |
+
"Dec" => "12"
|
105 |
+
);
|
106 |
+
var $session = '';
|
107 |
+
var $connection_close = 0;
|
108 |
+
var $force_close = 0;
|
109 |
+
var $connected_host = '';
|
110 |
+
var $connected_port = -1;
|
111 |
+
var $connected_ssl = 0;
|
112 |
+
|
113 |
+
public static function PHPErrorMessage() {
|
114 |
+
$lastError = error_get_last();
|
115 |
+
if ($lastError === null) {
|
116 |
+
return '';
|
117 |
+
}
|
118 |
+
|
119 |
+
return $lastError['message'];
|
120 |
+
}
|
121 |
+
|
122 |
+
/* Private methods - DO NOT CALL */
|
123 |
+
|
124 |
+
Function Tokenize($string, $separator = "") {
|
125 |
+
if (!strcmp($separator, "")) {
|
126 |
+
$separator = $string;
|
127 |
+
$string = $this->next_token;
|
128 |
+
}
|
129 |
+
for ($character = 0; $character < strlen($separator); $character++) {
|
130 |
+
$position = strpos($string, $separator[$character]);
|
131 |
+
if (GetType($position) == "integer") $found = (IsSet($found) ? min($found, $position) : $position);
|
132 |
+
}
|
133 |
+
if (IsSet($found)) {
|
134 |
+
$this->next_token = substr($string, $found + 1);
|
135 |
+
|
136 |
+
return (substr($string, 0, $found));
|
137 |
+
} else {
|
138 |
+
$this->next_token = "";
|
139 |
+
|
140 |
+
return ($string);
|
141 |
+
}
|
142 |
+
}
|
143 |
+
|
144 |
+
Function CookieEncode($value, $name) {
|
145 |
+
return ($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
|
146 |
+
}
|
147 |
+
|
148 |
+
Function SetError($error, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR) {
|
149 |
+
$this->error_code = $error_code;
|
150 |
+
|
151 |
+
return ($this->error = $error);
|
152 |
+
}
|
153 |
+
|
154 |
+
Function SetPHPError($error, $php_error_message, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR) {
|
155 |
+
if (IsSet($php_error_message) && strlen($php_error_message)) $error .= ": " . $php_error_message;
|
156 |
+
|
157 |
+
return ($this->SetError($error, $error_code));
|
158 |
+
}
|
159 |
+
|
160 |
+
Function SetDataAccessError($error, $check_connection = 0) {
|
161 |
+
$this->error = $error;
|
162 |
+
$this->error_code = HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE;
|
163 |
+
if (!$this->use_curl && function_exists("socket_get_status")) {
|
164 |
+
$status = socket_get_status($this->connection);
|
165 |
+
if ($status["timed_out"]) $this->error .= ": data access time out"; elseif ($status["eof"]) {
|
166 |
+
if ($check_connection) $this->error = ""; else
|
167 |
+
$this->error .= ": the server disconnected";
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
Function OutputDebug($message) {
|
173 |
+
if ($this->log_debug) error_log($message); else {
|
174 |
+
$message .= "\n";
|
175 |
+
if ($this->html_debug) $message = str_replace("\n", "<br />\n", HtmlEntities($message));
|
176 |
+
echo $message;
|
177 |
+
flush();
|
178 |
+
}
|
179 |
+
}
|
180 |
+
|
181 |
+
Function GetLine() {
|
182 |
+
for ($line = ""; ;) {
|
183 |
+
if ($this->use_curl) {
|
184 |
+
$eol = strpos($this->response, "\n", $this->read_response);
|
185 |
+
$data = ($eol ? substr($this->response, $this->read_response, $eol + 1 - $this->read_response) : "");
|
186 |
+
$this->read_response += strlen($data);
|
187 |
+
} else {
|
188 |
+
if (feof($this->connection)) {
|
189 |
+
$this->SetDataAccessError("reached the end of data while reading from the HTTP server connection");
|
190 |
+
|
191 |
+
return (0);
|
192 |
+
}
|
193 |
+
$data = fgets($this->connection, 100);
|
194 |
+
}
|
195 |
+
if (GetType($data) != "string" || strlen($data) == 0) {
|
196 |
+
$this->SetDataAccessError("it was not possible to read line from the HTTP server");
|
197 |
+
|
198 |
+
return (0);
|
199 |
+
}
|
200 |
+
$line .= $data;
|
201 |
+
$length = strlen($line);
|
202 |
+
if ($length && !strcmp(substr($line, $length - 1, 1), "\n")) {
|
203 |
+
$length -= (($length >= 2 && !strcmp(substr($line, $length - 2, 1), "\r")) ? 2 : 1);
|
204 |
+
$line = substr($line, 0, $length);
|
205 |
+
if ($this->debug) $this->OutputDebug("S $line");
|
206 |
+
|
207 |
+
return ($line);
|
208 |
+
}
|
209 |
+
}
|
210 |
+
}
|
211 |
+
|
212 |
+
Function PutLine($line) {
|
213 |
+
if ($this->debug) $this->OutputDebug("C $line");
|
214 |
+
if (!fputs($this->connection, $line . "\r\n")) {
|
215 |
+
$this->SetDataAccessError("it was not possible to send a line to the HTTP server");
|
216 |
+
|
217 |
+
return (0);
|
218 |
+
}
|
219 |
+
|
220 |
+
return (1);
|
221 |
+
}
|
222 |
+
|
223 |
+
Function PutData($data) {
|
224 |
+
if (strlen($data)) {
|
225 |
+
if ($this->debug) $this->OutputDebug('C ' . $data);
|
226 |
+
if (!fputs($this->connection, $data)) {
|
227 |
+
$this->SetDataAccessError("it was not possible to send data to the HTTP server");
|
228 |
+
|
229 |
+
return (0);
|
230 |
+
}
|
231 |
+
}
|
232 |
+
|
233 |
+
return (1);
|
234 |
+
}
|
235 |
+
|
236 |
+
Function FlushData() {
|
237 |
+
if (!fflush($this->connection)) {
|
238 |
+
$this->SetDataAccessError("it was not possible to send data to the HTTP server");
|
239 |
+
|
240 |
+
return (0);
|
241 |
+
}
|
242 |
+
|
243 |
+
return (1);
|
244 |
+
}
|
245 |
+
|
246 |
+
Function ReadChunkSize() {
|
247 |
+
if ($this->remaining_chunk == 0) {
|
248 |
+
$debug = $this->debug;
|
249 |
+
if (!$this->debug_response_body) $this->debug = 0;
|
250 |
+
$line = $this->GetLine();
|
251 |
+
$this->debug = $debug;
|
252 |
+
if (GetType($line) != "string") return ($this->SetError("could not read chunk start: " . $this->error, $this->error_code));
|
253 |
+
$this->remaining_chunk = hexdec($line);
|
254 |
+
if ($this->remaining_chunk == 0) {
|
255 |
+
if (!$this->debug_response_body) $this->debug = 0;
|
256 |
+
$line = $this->GetLine();
|
257 |
+
$this->debug = $debug;
|
258 |
+
if (GetType($line) != "string") return ($this->SetError("could not read chunk end: " . $this->error, $this->error_code));
|
259 |
+
}
|
260 |
+
}
|
261 |
+
|
262 |
+
return ("");
|
263 |
+
}
|
264 |
+
|
265 |
+
Function ReadBytes($length) {
|
266 |
+
if ($this->use_curl) {
|
267 |
+
$bytes = substr($this->response, $this->read_response, min($length, strlen($this->response) - $this->read_response));
|
268 |
+
$this->read_response += strlen($bytes);
|
269 |
+
if ($this->debug && $this->debug_response_body && strlen($bytes)) $this->OutputDebug("S " . $bytes);
|
270 |
+
} else {
|
271 |
+
if ($this->chunked) {
|
272 |
+
for ($bytes = "", $remaining = $length; $remaining;) {
|
273 |
+
if (strlen($this->ReadChunkSize())) return ("");
|
274 |
+
if ($this->remaining_chunk == 0) {
|
275 |
+
$this->last_chunk_read = 1;
|
276 |
+
break;
|
277 |
+
}
|
278 |
+
$ask = min($this->remaining_chunk, $remaining);
|
279 |
+
$chunk = @fread($this->connection, $ask);
|
280 |
+
$read = strlen($chunk);
|
281 |
+
if ($read == 0) {
|
282 |
+
$this->SetDataAccessError("it was not possible to read data chunk from the HTTP server");
|
283 |
+
|
284 |
+
return ("");
|
285 |
+
}
|
286 |
+
if ($this->debug && $this->debug_response_body) $this->OutputDebug("S " . $chunk);
|
287 |
+
$bytes .= $chunk;
|
288 |
+
$this->remaining_chunk -= $read;
|
289 |
+
$remaining -= $read;
|
290 |
+
if ($this->remaining_chunk == 0) {
|
291 |
+
if (feof($this->connection)) return ($this->SetError("reached the end of data while reading the end of data chunk mark from the HTTP server", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
|
292 |
+
$data = @fread($this->connection, 2);
|
293 |
+
if (strcmp($data, "\r\n")) {
|
294 |
+
$this->SetDataAccessError("it was not possible to read end of data chunk from the HTTP server");
|
295 |
+
|
296 |
+
return ("");
|
297 |
+
}
|
298 |
+
}
|
299 |
+
}
|
300 |
+
} else {
|
301 |
+
$bytes = @fread($this->connection, $length);
|
302 |
+
if (strlen($bytes)) {
|
303 |
+
if ($this->debug && $this->debug_response_body) $this->OutputDebug("S " . $bytes);
|
304 |
+
} else
|
305 |
+
$this->SetDataAccessError("it was not possible to read data from the HTTP server", $this->connection_close);
|
306 |
+
}
|
307 |
+
}
|
308 |
+
|
309 |
+
return ($bytes);
|
310 |
+
}
|
311 |
+
|
312 |
+
Function EndOfInput() {
|
313 |
+
if ($this->use_curl) return ($this->read_response >= strlen($this->response));
|
314 |
+
if ($this->chunked) return ($this->last_chunk_read);
|
315 |
+
if ($this->content_length_set) return ($this->content_length <= $this->read_length);
|
316 |
+
|
317 |
+
return (feof($this->connection));
|
318 |
+
}
|
319 |
+
|
320 |
+
Function Resolve($domain, &$ip, $server_type) {
|
321 |
+
if (preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $domain)) $ip = $domain; else {
|
322 |
+
if ($this->debug) $this->OutputDebug('Resolving ' . $server_type . ' server domain "' . $domain . '"...');
|
323 |
+
if (!strcmp($ip = @gethostbyname($domain), $domain)) $ip = "";
|
324 |
+
}
|
325 |
+
if (strlen($ip) == 0 || (strlen($this->exclude_address) && !strcmp(@gethostbyname($this->exclude_address), $ip))) return ($this->SetError("could not resolve the host domain \"" . $domain . "\"", HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS));
|
326 |
+
|
327 |
+
return ('');
|
328 |
+
}
|
329 |
+
|
330 |
+
Function Connect($host_name, $host_port, $ssl, $server_type = 'HTTP') {
|
331 |
+
$domain = $host_name;
|
332 |
+
$port = $host_port;
|
333 |
+
if (strlen($error = $this->Resolve($domain, $ip, $server_type))) return ($error);
|
334 |
+
if (strlen($this->socks_host_name)) {
|
335 |
+
switch ($this->socks_version) {
|
336 |
+
case '4':
|
337 |
+
$version = 4;
|
338 |
+
break;
|
339 |
+
case '5':
|
340 |
+
$version = 5;
|
341 |
+
break;
|
342 |
+
default:
|
343 |
+
return ('it was not specified a supported SOCKS protocol version');
|
344 |
+
break;
|
345 |
+
}
|
346 |
+
$host_ip = $ip;
|
347 |
+
$port = $this->socks_host_port;
|
348 |
+
$host_server_type = $server_type;
|
349 |
+
$server_type = 'SOCKS';
|
350 |
+
if (strlen($error = $this->Resolve($this->socks_host_name, $ip, $server_type))) return ($error);
|
351 |
+
}
|
352 |
+
if ($this->debug) $this->OutputDebug('Connecting to ' . $server_type . ' server IP ' . $ip . ' port ' . $port . '...');
|
353 |
+
if ($ssl) $ip = "ssl://" . $host_name;
|
354 |
+
if (($this->connection = ($this->timeout ? @fsockopen($ip, $port, $errno, $error, $this->timeout) : @fsockopen($ip, $port, $errno))) == 0) {
|
355 |
+
$error_code = HTTP_CLIENT_ERROR_CANNOT_CONNECT;
|
356 |
+
switch ($errno) {
|
357 |
+
case -3:
|
358 |
+
return ($this->SetError("socket could not be created", $error_code));
|
359 |
+
case -4:
|
360 |
+
return ($this->SetError("dns lookup on hostname \"" . $host_name . "\" failed", $error_code));
|
361 |
+
case -5:
|
362 |
+
return ($this->SetError("connection refused or timed out", $error_code));
|
363 |
+
case -6:
|
364 |
+
return ($this->SetError("fdopen() call failed", $error_code));
|
365 |
+
case -7:
|
366 |
+
return ($this->SetError("setvbuf() call failed", $error_code));
|
367 |
+
default:
|
368 |
+
return ($this->SetPHPError($errno . " could not connect to the host \"" . $host_name . "\"", self::PHPErrorMessage(), $error_code));
|
369 |
+
}
|
370 |
+
} else {
|
371 |
+
if ($this->data_timeout && function_exists("socket_set_timeout")) socket_set_timeout($this->connection, $this->data_timeout, 0);
|
372 |
+
if (strlen($this->socks_host_name)) {
|
373 |
+
if ($this->debug) $this->OutputDebug('Connected to the SOCKS server ' . $this->socks_host_name);
|
374 |
+
$send_error = 'it was not possible to send data to the SOCKS server';
|
375 |
+
$receive_error = 'it was not possible to receive data from the SOCKS server';
|
376 |
+
switch ($version) {
|
377 |
+
case 4:
|
378 |
+
$command = 1;
|
379 |
+
$user = '';
|
380 |
+
if (!fputs($this->connection, chr($version) . chr($command) . pack('nN', $host_port, ip2long($host_ip)) . $user . Chr(0))) $error = $this->SetDataAccessError($send_error); else {
|
381 |
+
$response = fgets($this->connection, 9);
|
382 |
+
if (strlen($response) != 8) $error = $this->SetDataAccessError($receive_error); else {
|
383 |
+
$socks_errors = array(
|
384 |
+
"\x5a" => '',
|
385 |
+
"\x5b" => 'request rejected',
|
386 |
+
"\x5c" => 'request failed because client is not running identd (or not reachable from the server)',
|
387 |
+
"\x5d" => 'request failed because client\'s identd could not confirm the user ID string in the request',
|
388 |
+
);
|
389 |
+
$error_code = $response[1];
|
390 |
+
$error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
|
391 |
+
if (strlen($error)) $error = 'SOCKS error: ' . $error;
|
392 |
+
}
|
393 |
+
}
|
394 |
+
break;
|
395 |
+
case 5:
|
396 |
+
if ($this->debug) $this->OutputDebug('Negotiating the authentication method ...');
|
397 |
+
$methods = 1;
|
398 |
+
$method = 0;
|
399 |
+
if (!fputs($this->connection, chr($version) . chr($methods) . chr($method))) $error = $this->SetDataAccessError($send_error); else {
|
400 |
+
$response = fgets($this->connection, 3);
|
401 |
+
if (strlen($response) != 2) $error = $this->SetDataAccessError($receive_error); elseif (Ord($response[1]) != $method) $error = 'the SOCKS server requires an authentication method that is not yet supported';
|
402 |
+
else {
|
403 |
+
if ($this->debug) $this->OutputDebug('Connecting to ' . $host_server_type . ' server IP ' . $host_ip . ' port ' . $host_port . '...');
|
404 |
+
$command = 1;
|
405 |
+
$address_type = 1;
|
406 |
+
if (!fputs($this->connection, chr($version) . chr($command) . "\x00" . chr($address_type) . pack('Nn', ip2long($host_ip), $host_port))) $error = $this->SetDataAccessError($send_error); else {
|
407 |
+
$response = fgets($this->connection, 11);
|
408 |
+
if (strlen($response) != 10) $error = $this->SetDataAccessError($receive_error); else {
|
409 |
+
$socks_errors = array(
|
410 |
+
"\x00" => '',
|
411 |
+
"\x01" => 'general SOCKS server failure',
|
412 |
+
"\x02" => 'connection not allowed by ruleset',
|
413 |
+
"\x03" => 'Network unreachable',
|
414 |
+
"\x04" => 'Host unreachable',
|
415 |
+
"\x05" => 'Connection refused',
|
416 |
+
"\x06" => 'TTL expired',
|
417 |
+
"\x07" => 'Command not supported',
|
418 |
+
"\x08" => 'Address type not supported'
|
419 |
+
);
|
420 |
+
$error_code = $response[1];
|
421 |
+
$error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
|
422 |
+
if (strlen($error)) $error = 'SOCKS error: ' . $error;
|
423 |
+
}
|
424 |
+
}
|
425 |
+
}
|
426 |
+
}
|
427 |
+
break;
|
428 |
+
default:
|
429 |
+
$error = 'support for SOCKS protocol version ' . $this->socks_version . ' is not yet implemented';
|
430 |
+
break;
|
431 |
+
}
|
432 |
+
if (strlen($error)) {
|
433 |
+
fclose($this->connection);
|
434 |
+
|
435 |
+
return ($error);
|
436 |
+
}
|
437 |
+
}
|
438 |
+
if ($this->debug) $this->OutputDebug("Connected to $host_name");
|
439 |
+
if (strlen($this->proxy_host_name) && !strcmp(strtolower($this->protocol), 'https')) {
|
440 |
+
if (function_exists('stream_socket_enable_crypto') && in_array('ssl', stream_get_transports())) $this->state = "ConnectedToProxy"; else {
|
441 |
+
$this->OutputDebug("It is not possible to start SSL after connecting to the proxy server. If the proxy refuses to forward the SSL request, you may need to upgrade to PHP 5.1 or later with OpenSSL support enabled.");
|
442 |
+
$this->state = "Connected";
|
443 |
+
}
|
444 |
+
} else
|
445 |
+
$this->state = "Connected";
|
446 |
+
|
447 |
+
return ("");
|
448 |
+
}
|
449 |
+
}
|
450 |
+
|
451 |
+
Function Disconnect() {
|
452 |
+
if ($this->debug) $this->OutputDebug("Disconnected from " . $this->connected_host);
|
453 |
+
if ($this->use_curl) {
|
454 |
+
curl_close($this->connection);
|
455 |
+
$this->response = "";
|
456 |
+
} else
|
457 |
+
fclose($this->connection);
|
458 |
+
$this->state = "Disconnected";
|
459 |
+
|
460 |
+
return ("");
|
461 |
+
}
|
462 |
+
|
463 |
+
/* Public methods */
|
464 |
+
|
465 |
+
Function GetRequestArguments($url, &$arguments) {
|
466 |
+
$this->error = '';
|
467 |
+
$this->error_code = HTTP_CLIENT_ERROR_NO_ERROR;
|
468 |
+
$arguments = array();
|
469 |
+
$url = str_replace(' ', '%20', $url);
|
470 |
+
$parameters = @parse_url($url);
|
471 |
+
if (!$parameters) return ($this->SetError("it was not specified a valid URL", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
472 |
+
if (!IsSet($parameters["scheme"])) return ($this->SetError("it was not specified the protocol type argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
473 |
+
switch (strtolower($parameters["scheme"])) {
|
474 |
+
case "http":
|
475 |
+
case "https":
|
476 |
+
$arguments["Protocol"] = $parameters["scheme"];
|
477 |
+
break;
|
478 |
+
default:
|
479 |
+
return ($parameters["scheme"] . " connection scheme is not yet supported");
|
480 |
+
}
|
481 |
+
if (!IsSet($parameters["host"])) return ($this->SetError("it was not specified the connection host argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
482 |
+
$arguments["HostName"] = $parameters["host"];
|
483 |
+
$arguments["Headers"] = array("Host" => $parameters["host"] . (IsSet($parameters["port"]) ? ":" . $parameters["port"] : ""));
|
484 |
+
if (IsSet($parameters["user"])) {
|
485 |
+
$arguments["AuthUser"] = UrlDecode($parameters["user"]);
|
486 |
+
if (!IsSet($parameters["pass"])) $arguments["AuthPassword"] = "";
|
487 |
+
}
|
488 |
+
if (IsSet($parameters["pass"])) {
|
489 |
+
if (!IsSet($parameters["user"])) $arguments["AuthUser"] = "";
|
490 |
+
$arguments["AuthPassword"] = UrlDecode($parameters["pass"]);
|
491 |
+
}
|
492 |
+
if (IsSet($parameters["port"])) {
|
493 |
+
if (strcmp($parameters["port"], strval(intval($parameters["port"])))) return ($this->SetError("it was not specified a valid connection host argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
494 |
+
$arguments["HostPort"] = intval($parameters["port"]);
|
495 |
+
} else
|
496 |
+
$arguments["HostPort"] = 0;
|
497 |
+
$arguments["RequestURI"] = (IsSet($parameters["path"]) ? $parameters["path"] : "/") . (IsSet($parameters["query"]) ? "?" . $parameters["query"] : "");
|
498 |
+
if (strlen($this->user_agent)) $arguments["Headers"]["User-Agent"] = $this->user_agent;
|
499 |
+
if (strlen($this->accept)) $arguments["Headers"]["Accept"] = $this->accept;
|
500 |
+
|
501 |
+
return ("");
|
502 |
+
}
|
503 |
+
|
504 |
+
Function Open($arguments) {
|
505 |
+
if (strlen($this->error)) return ($this->error);
|
506 |
+
$error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR;
|
507 |
+
if (IsSet($arguments["HostName"])) $this->host_name = $arguments["HostName"];
|
508 |
+
if (IsSet($arguments["HostPort"])) $this->host_port = $arguments["HostPort"];
|
509 |
+
if (IsSet($arguments["ProxyHostName"])) $this->proxy_host_name = $arguments["ProxyHostName"];
|
510 |
+
if (IsSet($arguments["ProxyHostPort"])) $this->proxy_host_port = $arguments["ProxyHostPort"];
|
511 |
+
if (IsSet($arguments["SOCKSHostName"])) $this->socks_host_name = $arguments["SOCKSHostName"];
|
512 |
+
if (IsSet($arguments["SOCKSHostPort"])) $this->socks_host_port = $arguments["SOCKSHostPort"];
|
513 |
+
if (IsSet($arguments["SOCKSVersion"])) $this->socks_version = $arguments["SOCKSVersion"];
|
514 |
+
if (IsSet($arguments["Protocol"])) $this->protocol = $arguments["Protocol"];
|
515 |
+
switch (strtolower($this->protocol)) {
|
516 |
+
case "http":
|
517 |
+
$default_port = 80;
|
518 |
+
break;
|
519 |
+
case "https":
|
520 |
+
$default_port = 443;
|
521 |
+
break;
|
522 |
+
default:
|
523 |
+
return ($this->SetError("it was not specified a valid connection protocol", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
524 |
+
}
|
525 |
+
if (strlen($this->proxy_host_name) == 0) {
|
526 |
+
if (strlen($this->host_name) == 0) return ($this->SetError("it was not specified a valid hostname", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
527 |
+
$host_name = $this->host_name;
|
528 |
+
$host_port = ($this->host_port ? $this->host_port : $default_port);
|
529 |
+
$server_type = 'HTTP';
|
530 |
+
} else {
|
531 |
+
$host_name = $this->proxy_host_name;
|
532 |
+
$host_port = $this->proxy_host_port;
|
533 |
+
$server_type = 'HTTP proxy';
|
534 |
+
}
|
535 |
+
$ssl = (strtolower($this->protocol) == "https" && strlen($this->proxy_host_name) == 0);
|
536 |
+
if ($ssl && strlen($this->socks_host_name)) return ($this->SetError('establishing SSL connections via a SOCKS server is not yet supported', HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
537 |
+
$this->use_curl = ($ssl && $this->prefer_curl && function_exists("curl_init"));
|
538 |
+
switch ($this->state) {
|
539 |
+
case 'Connected':
|
540 |
+
if (!strcmp($host_name, $this->connected_host) && intval($host_port) == $this->connected_port && intval($ssl) == $this->connected_ssl) {
|
541 |
+
if ($this->debug) $this->OutputDebug("Reusing connection to " . $this->connected_host);
|
542 |
+
|
543 |
+
return ('');
|
544 |
+
}
|
545 |
+
if (strlen($error = $this->Disconnect())) return ($error);
|
546 |
+
break;
|
547 |
+
case "Disconnected":
|
548 |
+
break;
|
549 |
+
default:
|
550 |
+
return ("1 already connected");
|
551 |
+
}
|
552 |
+
if ($this->debug) $this->OutputDebug("Connecting to " . $this->host_name);
|
553 |
+
if ($this->use_curl) {
|
554 |
+
$error = (($this->connection = curl_init($this->protocol . "://" . $this->host_name . ($host_port == $default_port ? "" : ":" . strval($host_port)) . "/")) ? "" : "Could not initialize a CURL session");
|
555 |
+
if (strlen($error) == 0) {
|
556 |
+
curl_setopt($this->connection, CURLOPT_CAINFO, HttpClient::getCacertPath());
|
557 |
+
if (IsSet($arguments["SSLCertificateFile"])) curl_setopt($this->connection, CURLOPT_SSLCERT, $arguments["SSLCertificateFile"]);
|
558 |
+
if (IsSet($arguments["SSLCertificatePassword"])) curl_setopt($this->connection, CURLOPT_SSLCERTPASSWD, $arguments["SSLCertificatePassword"]);
|
559 |
+
if (IsSet($arguments["SSLKeyFile"])) curl_setopt($this->connection, CURLOPT_SSLKEY, $arguments["SSLKeyFile"]);
|
560 |
+
if (IsSet($arguments["SSLKeyPassword"])) curl_setopt($this->connection, CURLOPT_SSLKEYPASSWD, $arguments["SSLKeyPassword"]);
|
561 |
+
}
|
562 |
+
$this->state = "Connected";
|
563 |
+
} else {
|
564 |
+
$error = "";
|
565 |
+
if (strlen($this->proxy_host_name) && (IsSet($arguments["SSLCertificateFile"]) || IsSet($arguments["SSLCertificateFile"]))) $error = "establishing SSL connections using certificates or private keys via non-SSL proxies is not supported"; else {
|
566 |
+
if ($ssl) {
|
567 |
+
if (IsSet($arguments["SSLCertificateFile"])) $error = "establishing SSL connections using certificates is only supported when the cURL extension is enabled"; elseif (IsSet($arguments["SSLKeyFile"])) $error = "establishing SSL connections using a private key is only supported when the cURL extension is enabled";
|
568 |
+
}
|
569 |
+
if (strlen($error) == 0) {
|
570 |
+
$error = $this->Connect($host_name, $host_port, $ssl, $server_type);
|
571 |
+
$error_code = $this->error_code;
|
572 |
+
}
|
573 |
+
}
|
574 |
+
}
|
575 |
+
if (strlen($error)) return ($this->SetError($error, $error_code));
|
576 |
+
$this->session = md5(uniqid(""));
|
577 |
+
$this->connected_host = $host_name;
|
578 |
+
$this->connected_port = intval($host_port);
|
579 |
+
$this->connected_ssl = intval($ssl);
|
580 |
+
|
581 |
+
return ("");
|
582 |
+
}
|
583 |
+
|
584 |
+
Function Close($force = 0) {
|
585 |
+
if ($this->state == "Disconnected") return ("1 already disconnected");
|
586 |
+
if (!$this->force_close && $this->keep_alive && !$force && $this->state == 'ResponseReceived') {
|
587 |
+
if ($this->debug) $this->OutputDebug('Keeping the connection alive to ' . $this->connected_host);
|
588 |
+
$this->state = 'Connected';
|
589 |
+
|
590 |
+
return ('');
|
591 |
+
}
|
592 |
+
|
593 |
+
return ($this->Disconnect());
|
594 |
+
}
|
595 |
+
|
596 |
+
Function PickCookies(&$cookies, $secure) {
|
597 |
+
if (IsSet($this->cookies[$secure])) {
|
598 |
+
$now = gmdate("Y-m-d H-i-s");
|
599 |
+
for ($domain = 0, Reset($this->cookies[$secure]); $domain < count($this->cookies[$secure]); Next($this->cookies[$secure]), $domain++) {
|
600 |
+
$domain_pattern = Key($this->cookies[$secure]);
|
601 |
+
$match = strlen($this->request_host) - strlen($domain_pattern);
|
602 |
+
if ($match >= 0 && !strcmp($domain_pattern, substr($this->request_host, $match)) && ($match == 0 || $domain_pattern[0] == "." || $this->request_host[$match - 1] == ".")) {
|
603 |
+
for (Reset($this->cookies[$secure][$domain_pattern]), $path_part = 0; $path_part < count($this->cookies[$secure][$domain_pattern]); Next($this->cookies[$secure][$domain_pattern]), $path_part++) {
|
604 |
+
$path = Key($this->cookies[$secure][$domain_pattern]);
|
605 |
+
if (strlen($this->request_uri) >= strlen($path) && substr($this->request_uri, 0, strlen($path)) == $path) {
|
606 |
+
for (Reset($this->cookies[$secure][$domain_pattern][$path]), $cookie = 0; $cookie < count($this->cookies[$secure][$domain_pattern][$path]); Next($this->cookies[$secure][$domain_pattern][$path]), $cookie++) {
|
607 |
+
$cookie_name = Key($this->cookies[$secure][$domain_pattern][$path]);
|
608 |
+
$expires = $this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
|
609 |
+
if ($expires == "" || strcmp($now, $expires) < 0) $cookies[$cookie_name] = $this->cookies[$secure][$domain_pattern][$path][$cookie_name];
|
610 |
+
}
|
611 |
+
}
|
612 |
+
}
|
613 |
+
}
|
614 |
+
}
|
615 |
+
}
|
616 |
+
}
|
617 |
+
|
618 |
+
Function GetFileDefinition($file, &$definition) {
|
619 |
+
$name = "";
|
620 |
+
if (IsSet($file["FileName"])) $name = basename($file["FileName"]);
|
621 |
+
if (IsSet($file["Name"])) $name = $file["Name"];
|
622 |
+
if (strlen($name) == 0) return ("it was not specified the file part name");
|
623 |
+
if (IsSet($file["Content-Type"])) {
|
624 |
+
$content_type = $file["Content-Type"];
|
625 |
+
$type = $this->Tokenize(strtolower($content_type), "/");
|
626 |
+
$sub_type = $this->Tokenize("");
|
627 |
+
switch ($type) {
|
628 |
+
case "text":
|
629 |
+
case "image":
|
630 |
+
case "audio":
|
631 |
+
case "video":
|
632 |
+
case "application":
|
633 |
+
case "message":
|
634 |
+
break;
|
635 |
+
case "automatic":
|
636 |
+
switch ($sub_type) {
|
637 |
+
case "name":
|
638 |
+
switch (GetType($dot = strrpos($name, ".")) == "integer" ? strtolower(substr($name, $dot)) : "") {
|
639 |
+
case ".xls":
|
640 |
+
$content_type = "application/excel";
|
641 |
+
break;
|
642 |
+
case ".hqx":
|
643 |
+
$content_type = "application/macbinhex40";
|
644 |
+
break;
|
645 |
+
case ".doc":
|
646 |
+
case ".dot":
|
647 |
+
case ".wrd":
|
648 |
+
$content_type = "application/msword";
|
649 |
+
break;
|
650 |
+
case ".pdf":
|
651 |
+
$content_type = "application/pdf";
|
652 |
+
break;
|
653 |
+
case ".pgp":
|
654 |
+
$content_type = "application/pgp";
|
655 |
+
break;
|
656 |
+
case ".ps":
|
657 |
+
case ".eps":
|
658 |
+
case ".ai":
|
659 |
+
$content_type = "application/postscript";
|
660 |
+
break;
|
661 |
+
case ".ppt":
|
662 |
+
$content_type = "application/powerpoint";
|
663 |
+
break;
|
664 |
+
case ".rtf":
|
665 |
+
$content_type = "application/rtf";
|
666 |
+
break;
|
667 |
+
case ".tgz":
|
668 |
+
case ".gtar":
|
669 |
+
$content_type = "application/x-gtar";
|
670 |
+
break;
|
671 |
+
case ".gz":
|
672 |
+
$content_type = "application/x-gzip";
|
673 |
+
break;
|
674 |
+
case ".php":
|
675 |
+
case ".php3":
|
676 |
+
$content_type = "application/x-httpd-php";
|
677 |
+
break;
|
678 |
+
case ".js":
|
679 |
+
$content_type = "application/x-javascript";
|
680 |
+
break;
|
681 |
+
case ".ppd":
|
682 |
+
case ".psd":
|
683 |
+
$content_type = "application/x-photoshop";
|
684 |
+
break;
|
685 |
+
case ".svg":
|
686 |
+
$content_type = "image/svg+xml";
|
687 |
+
break;
|
688 |
+
case ".swf":
|
689 |
+
case ".swc":
|
690 |
+
case ".rf":
|
691 |
+
$content_type = "application/x-shockwave-flash";
|
692 |
+
break;
|
693 |
+
case ".tar":
|
694 |
+
$content_type = "application/x-tar";
|
695 |
+
break;
|
696 |
+
case ".zip":
|
697 |
+
$content_type = "application/zip";
|
698 |
+
break;
|
699 |
+
case ".mid":
|
700 |
+
case ".midi":
|
701 |
+
case ".kar":
|
702 |
+
$content_type = "audio/midi";
|
703 |
+
break;
|
704 |
+
case ".mp2":
|
705 |
+
case ".mp3":
|
706 |
+
case ".mpga":
|
707 |
+
$content_type = "audio/mpeg";
|
708 |
+
break;
|
709 |
+
case ".ra":
|
710 |
+
$content_type = "audio/x-realaudio";
|
711 |
+
break;
|
712 |
+
case ".wav":
|
713 |
+
$content_type = "audio/wav";
|
714 |
+
break;
|
715 |
+
case ".bmp":
|
716 |
+
$content_type = "image/bitmap";
|
717 |
+
break;
|
718 |
+
case ".gif":
|
719 |
+
$content_type = "image/gif";
|
720 |
+
break;
|
721 |
+
case ".iff":
|
722 |
+
$content_type = "image/iff";
|
723 |
+
break;
|
724 |
+
case ".jb2":
|
725 |
+
$content_type = "image/jb2";
|
726 |
+
break;
|
727 |
+
case ".jpg":
|
728 |
+
case ".jpe":
|
729 |
+
case ".jpeg":
|
730 |
+
$content_type = "image/jpeg";
|
731 |
+
break;
|
732 |
+
case ".jpx":
|
733 |
+
$content_type = "image/jpx";
|
734 |
+
break;
|
735 |
+
case ".png":
|
736 |
+
$content_type = "image/png";
|
737 |
+
break;
|
738 |
+
case ".tif":
|
739 |
+
case ".tiff":
|
740 |
+
$content_type = "image/tiff";
|
741 |
+
break;
|
742 |
+
case ".wbmp":
|
743 |
+
$content_type = "image/vnd.wap.wbmp";
|
744 |
+
break;
|
745 |
+
case ".webp":
|
746 |
+
$content_type = "image/webp";
|
747 |
+
break;
|
748 |
+
case ".xbm":
|
749 |
+
$content_type = "image/xbm";
|
750 |
+
break;
|
751 |
+
case ".css":
|
752 |
+
$content_type = "text/css";
|
753 |
+
break;
|
754 |
+
case ".txt":
|
755 |
+
$content_type = "text/plain";
|
756 |
+
break;
|
757 |
+
case ".htm":
|
758 |
+
case ".html":
|
759 |
+
$content_type = "text/html";
|
760 |
+
break;
|
761 |
+
case ".xml":
|
762 |
+
$content_type = "text/xml";
|
763 |
+
break;
|
764 |
+
case ".mpg":
|
765 |
+
case ".mpe":
|
766 |
+
case ".mpeg":
|
767 |
+
$content_type = "video/mpeg";
|
768 |
+
break;
|
769 |
+
case ".qt":
|
770 |
+
case ".mov":
|
771 |
+
$content_type = "video/quicktime";
|
772 |
+
break;
|
773 |
+
case ".avi":
|
774 |
+
$content_type = "video/x-ms-video";
|
775 |
+
break;
|
776 |
+
case ".eml":
|
777 |
+
$content_type = "message/rfc822";
|
778 |
+
break;
|
779 |
+
default:
|
780 |
+
$content_type = "application/octet-stream";
|
781 |
+
break;
|
782 |
+
}
|
783 |
+
break;
|
784 |
+
default:
|
785 |
+
return ($content_type . " is not a supported automatic content type detection method");
|
786 |
+
}
|
787 |
+
break;
|
788 |
+
default:
|
789 |
+
return ($content_type . " is not a supported file content type");
|
790 |
+
}
|
791 |
+
} else
|
792 |
+
$content_type = "application/octet-stream";
|
793 |
+
$definition = array(
|
794 |
+
"Content-Type" => $content_type,
|
795 |
+
"NAME" => $name
|
796 |
+
);
|
797 |
+
if (IsSet($file["FileName"])) {
|
798 |
+
if (GetType($length = @filesize($file["FileName"])) != "integer") {
|
799 |
+
$error = "it was not possible to determine the length of the file " . $file["FileName"];
|
800 |
+
$errorMessage = self::PHPErrorMessage();
|
801 |
+
if (strlen($errorMessage)) $error .= ": " . $errorMessage;
|
802 |
+
if (!file_exists($file["FileName"])) $error = "it was not possible to access the file " . $file["FileName"];
|
803 |
+
|
804 |
+
return ($error);
|
805 |
+
}
|
806 |
+
$definition["FILENAME"] = $file["FileName"];
|
807 |
+
$definition["Content-Length"] = $length;
|
808 |
+
} elseif (IsSet($file["Data"])) $definition["Content-Length"] = strlen($definition["DATA"] = $file["Data"]);
|
809 |
+
else
|
810 |
+
return ("it was not specified a valid file name");
|
811 |
+
|
812 |
+
return ("");
|
813 |
+
}
|
814 |
+
|
815 |
+
Function ConnectFromProxy($arguments, &$headers) {
|
816 |
+
if (!$this->PutLine('CONNECT ' . $this->host_name . ':' . ($this->host_port ? $this->host_port : 443) . ' HTTP/1.0') || (strlen($this->user_agent) && !$this->PutLine('User-Agent: ' . $this->user_agent)) || (strlen($this->accept) && !$this->PutLine('Accept: ' . $this->accept)) || (IsSet($arguments['Headers']['Proxy-Authorization']) && !$this->PutLine('Proxy-Authorization: ' . $arguments['Headers']['Proxy-Authorization'])) || !$this->PutLine('')) {
|
817 |
+
$this->Disconnect();
|
818 |
+
|
819 |
+
return ($this->error);
|
820 |
+
}
|
821 |
+
$this->state = "ConnectSent";
|
822 |
+
if (strlen($error = $this->ReadReplyHeadersResponse($headers))) return ($error);
|
823 |
+
$proxy_authorization = "";
|
824 |
+
while (!strcmp($this->response_status, "100")) {
|
825 |
+
$this->state = "ConnectSent";
|
826 |
+
if (strlen($error = $this->ReadReplyHeadersResponse($headers))) return ($error);
|
827 |
+
}
|
828 |
+
switch ($this->response_status) {
|
829 |
+
case "200":
|
830 |
+
if (!@stream_socket_enable_crypto($this->connection, 1, STREAM_CRYPTO_METHOD_SSLv23_CLIENT)) {
|
831 |
+
$this->SetPHPError('it was not possible to start a SSL encrypted connection via this proxy', self::PHPErrorMessage(), HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE);
|
832 |
+
$this->Disconnect();
|
833 |
+
|
834 |
+
return ($this->error);
|
835 |
+
}
|
836 |
+
$this->state = "Connected";
|
837 |
+
break;
|
838 |
+
case "407":
|
839 |
+
if (strlen($error = $this->Authenticate($headers, -1, $proxy_authorization, $this->proxy_request_user, $this->proxy_request_password, $this->proxy_request_realm, $this->proxy_request_workstation))) return ($error);
|
840 |
+
break;
|
841 |
+
default:
|
842 |
+
return ($this->SetError("unable to send request via proxy", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
|
843 |
+
}
|
844 |
+
|
845 |
+
return ("");
|
846 |
+
}
|
847 |
+
|
848 |
+
Function SendRequest($arguments) {
|
849 |
+
if (strlen($this->error)) return ($this->error);
|
850 |
+
if (IsSet($arguments["ProxyUser"])) $this->proxy_request_user = $arguments["ProxyUser"]; elseif (IsSet($this->proxy_user)) $this->proxy_request_user = $this->proxy_user;
|
851 |
+
if (IsSet($arguments["ProxyPassword"])) $this->proxy_request_password = $arguments["ProxyPassword"]; elseif (IsSet($this->proxy_password)) $this->proxy_request_password = $this->proxy_password;
|
852 |
+
if (IsSet($arguments["ProxyRealm"])) $this->proxy_request_realm = $arguments["ProxyRealm"]; elseif (IsSet($this->proxy_realm)) $this->proxy_request_realm = $this->proxy_realm;
|
853 |
+
if (IsSet($arguments["ProxyWorkstation"])) $this->proxy_request_workstation = $arguments["ProxyWorkstation"]; elseif (IsSet($this->proxy_workstation)) $this->proxy_request_workstation = $this->proxy_workstation;
|
854 |
+
switch ($this->state) {
|
855 |
+
case "Disconnected":
|
856 |
+
return ($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
857 |
+
case "Connected":
|
858 |
+
$connect = 0;
|
859 |
+
break;
|
860 |
+
case "ConnectedToProxy":
|
861 |
+
if (strlen($error = $this->ConnectFromProxy($arguments, $headers))) return ($error);
|
862 |
+
$connect = 1;
|
863 |
+
break;
|
864 |
+
default:
|
865 |
+
return ($this->SetError("can not send request in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
866 |
+
}
|
867 |
+
if (IsSet($arguments["RequestMethod"])) $this->request_method = $arguments["RequestMethod"];
|
868 |
+
if (IsSet($arguments["User-Agent"])) $this->user_agent = $arguments["User-Agent"];
|
869 |
+
if (!IsSet($arguments["Headers"]["User-Agent"]) && strlen($this->user_agent)) $arguments["Headers"]["User-Agent"] = $this->user_agent;
|
870 |
+
if (IsSet($arguments["KeepAlive"])) $this->keep_alive = intval($arguments["KeepAlive"]);
|
871 |
+
if (!IsSet($arguments["Headers"]["Connection"]) && $this->keep_alive) $arguments["Headers"]["Connection"] = 'Keep-Alive';
|
872 |
+
if (IsSet($arguments["Accept"])) $this->user_agent = $arguments["Accept"];
|
873 |
+
if (!IsSet($arguments["Headers"]["Accept"]) && strlen($this->accept)) $arguments["Headers"]["Accept"] = $this->accept;
|
874 |
+
if (strlen($this->request_method) == 0) return ($this->SetError("it was not specified a valid request method", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
875 |
+
if (IsSet($arguments["RequestURI"])) $this->request_uri = $arguments["RequestURI"];
|
876 |
+
if (strlen($this->request_uri) == 0 || substr($this->request_uri, 0, 1) != "/") return ($this->SetError("it was not specified a valid request URI", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
877 |
+
$this->request_arguments = $arguments;
|
878 |
+
$this->request_headers = (IsSet($arguments["Headers"]) ? $arguments["Headers"] : array());
|
879 |
+
$body_length = 0;
|
880 |
+
$this->request_body = "";
|
881 |
+
$get_body = 1;
|
882 |
+
if ($this->request_method == "POST" || $this->request_method == "PUT") {
|
883 |
+
if (IsSet($arguments['StreamRequest'])) {
|
884 |
+
$get_body = 0;
|
885 |
+
$this->request_headers["Transfer-Encoding"] = "chunked";
|
886 |
+
} elseif (IsSet($arguments["PostFiles"]) || ($this->force_multipart_form_post && IsSet($arguments["PostValues"]))) {
|
887 |
+
$boundary = "--" . md5(uniqid(time()));
|
888 |
+
$this->request_headers["Content-Type"] = "multipart/form-data; boundary=" . $boundary . (IsSet($arguments["CharSet"]) ? "; charset=" . $arguments["CharSet"] : "");
|
889 |
+
$post_parts = array();
|
890 |
+
if (IsSet($arguments["PostValues"])) {
|
891 |
+
$values = $arguments["PostValues"];
|
892 |
+
if (GetType($values) != "array") return ($this->SetError("it was not specified a valid POST method values array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
893 |
+
for (Reset($values), $value = 0; $value < count($values); Next($values), $value++) {
|
894 |
+
$input = Key($values);
|
895 |
+
$headers = "--" . $boundary . "\r\nContent-Disposition: form-data; name=\"" . $input . "\"\r\n\r\n";
|
896 |
+
$data = $values[$input];
|
897 |
+
$post_parts[] = array(
|
898 |
+
"HEADERS" => $headers,
|
899 |
+
"DATA" => $data
|
900 |
+
);
|
901 |
+
$body_length += strlen($headers) + strlen($data) + strlen("\r\n");
|
902 |
+
}
|
903 |
+
}
|
904 |
+
$body_length += strlen("--" . $boundary . "--\r\n");
|
905 |
+
$files = (IsSet($arguments["PostFiles"]) ? $arguments["PostFiles"] : array());
|
906 |
+
Reset($files);
|
907 |
+
$end = (GetType($input = Key($files)) != "string");
|
908 |
+
for (; !$end;) {
|
909 |
+
if (strlen($error = $this->GetFileDefinition($files[$input], $definition))) return ("3 " . $error);
|
910 |
+
$headers = "--" . $boundary . "\r\nContent-Disposition: form-data; name=\"" . $input . "\"; filename=\"" . $definition["NAME"] . "\"\r\nContent-Type: " . $definition["Content-Type"] . "\r\n\r\n";
|
911 |
+
$part = count($post_parts);
|
912 |
+
$post_parts[$part] = array("HEADERS" => $headers);
|
913 |
+
if (IsSet($definition["FILENAME"])) {
|
914 |
+
$post_parts[$part]["FILENAME"] = $definition["FILENAME"];
|
915 |
+
$data = "";
|
916 |
+
} else
|
917 |
+
$data = $definition["DATA"];
|
918 |
+
$post_parts[$part]["DATA"] = $data;
|
919 |
+
$body_length += strlen($headers) + $definition["Content-Length"] + strlen("\r\n");
|
920 |
+
Next($files);
|
921 |
+
$end = (GetType($input = Key($files)) != "string");
|
922 |
+
}
|
923 |
+
$get_body = 0;
|
924 |
+
} elseif (IsSet($arguments["PostValues"])) {
|
925 |
+
$values = $arguments["PostValues"];
|
926 |
+
if (GetType($values) != "array") return ($this->SetError("it was not specified a valid POST method values array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
927 |
+
for (Reset($values), $value = 0; $value < count($values); Next($values), $value++) {
|
928 |
+
$k = Key($values);
|
929 |
+
if (GetType($values[$k]) == "array") {
|
930 |
+
for ($v = 0; $v < count($values[$k]); $v++) {
|
931 |
+
if ($value + $v > 0) $this->request_body .= "&";
|
932 |
+
$this->request_body .= UrlEncode($k) . "=" . UrlEncode($values[$k][$v]);
|
933 |
+
}
|
934 |
+
} else {
|
935 |
+
if ($value > 0) $this->request_body .= "&";
|
936 |
+
$this->request_body .= UrlEncode($k) . "=" . UrlEncode($values[$k]);
|
937 |
+
}
|
938 |
+
}
|
939 |
+
$this->request_headers["Content-Type"] = "application/x-www-form-urlencoded" . (IsSet($arguments["CharSet"]) ? "; charset=" . $arguments["CharSet"] : "");
|
940 |
+
$get_body = 0;
|
941 |
+
}
|
942 |
+
}
|
943 |
+
if ($get_body && (IsSet($arguments["Body"]) || IsSet($arguments["BodyStream"]))) {
|
944 |
+
if (IsSet($arguments["Body"])) $this->request_body = $arguments["Body"]; else {
|
945 |
+
$stream = $arguments["BodyStream"];
|
946 |
+
$this->request_body = "";
|
947 |
+
for ($part = 0; $part < count($stream); $part++) {
|
948 |
+
if (IsSet($stream[$part]["Data"])) $this->request_body .= $stream[$part]["Data"]; elseif (IsSet($stream[$part]["File"])) {
|
949 |
+
if (!($file = @fopen($stream[$part]["File"], "rb"))) return ($this->SetPHPError("could not open upload file " . $stream[$part]["File"], self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE));
|
950 |
+
while (!feof($file)) {
|
951 |
+
if (GetType($block = @fread($file, $this->file_buffer_length)) != "string") {
|
952 |
+
$error = $this->SetPHPError("could not read body stream file " . $stream[$part]["File"], self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
|
953 |
+
fclose($file);
|
954 |
+
|
955 |
+
return ($error);
|
956 |
+
}
|
957 |
+
$this->request_body .= $block;
|
958 |
+
}
|
959 |
+
fclose($file);
|
960 |
+
} else
|
961 |
+
return ("5 it was not specified a valid file or data body stream element at position " . $part);
|
962 |
+
}
|
963 |
+
}
|
964 |
+
if (!IsSet($this->request_headers["Content-Type"])) $this->request_headers["Content-Type"] = "application/octet-stream" . (IsSet($arguments["CharSet"]) ? "; charset=" . $arguments["CharSet"] : "");
|
965 |
+
}
|
966 |
+
if (IsSet($arguments["AuthUser"])) $this->request_user = $arguments["AuthUser"]; elseif (IsSet($this->user)) $this->request_user = $this->user;
|
967 |
+
if (IsSet($arguments["AuthPassword"])) $this->request_password = $arguments["AuthPassword"]; elseif (IsSet($this->password)) $this->request_password = $this->password;
|
968 |
+
if (IsSet($arguments["AuthRealm"])) $this->request_realm = $arguments["AuthRealm"]; elseif (IsSet($this->realm)) $this->request_realm = $this->realm;
|
969 |
+
if (IsSet($arguments["AuthWorkstation"])) $this->request_workstation = $arguments["AuthWorkstation"]; elseif (IsSet($this->workstation)) $this->request_workstation = $this->workstation;
|
970 |
+
if (strlen($this->proxy_host_name) == 0 || $connect) $request_uri = $this->request_uri; else {
|
971 |
+
switch (strtolower($this->protocol)) {
|
972 |
+
case "http":
|
973 |
+
$default_port = 80;
|
974 |
+
break;
|
975 |
+
case "https":
|
976 |
+
$default_port = 443;
|
977 |
+
break;
|
978 |
+
}
|
979 |
+
$request_uri = strtolower($this->protocol) . "://" . $this->host_name . (($this->host_port == 0 || $this->host_port == $default_port) ? "" : ":" . $this->host_port) . $this->request_uri;
|
980 |
+
}
|
981 |
+
if ($this->use_curl) {
|
982 |
+
$version = (GetType($v = curl_version()) == "array" ? (IsSet($v["version"]) ? $v["version"] : "0.0.0") : (preg_match("/^libcurl\\/([0-9]+\\.[0-9]+\\.[0-9]+)/", $v, $m) ? $m[1] : "0.0.0"));
|
983 |
+
$curl_version = 100000 * intval($this->Tokenize($version, ".")) + 1000 * intval($this->Tokenize(".")) + intval($this->Tokenize(""));
|
984 |
+
$protocol_version = ($curl_version < 713002 ? "1.0" : $this->protocol_version);
|
985 |
+
} else
|
986 |
+
$protocol_version = $this->protocol_version;
|
987 |
+
$this->request = $this->request_method . " " . $request_uri . " HTTP/" . $protocol_version;
|
988 |
+
if ($body_length || ($body_length = strlen($this->request_body)) || !strcmp($this->request_method, 'POST')) $this->request_headers["Content-Length"] = $body_length;
|
989 |
+
for ($headers = array(), $host_set = 0, Reset($this->request_headers), $header = 0; $header < count($this->request_headers); Next($this->request_headers), $header++) {
|
990 |
+
$header_name = Key($this->request_headers);
|
991 |
+
$header_value = $this->request_headers[$header_name];
|
992 |
+
if (GetType($header_value) == "array") {
|
993 |
+
for (Reset($header_value), $value = 0; $value < count($header_value); Next($header_value), $value++) $headers[] = $header_name . ": " . $header_value[Key($header_value)];
|
994 |
+
} else
|
995 |
+
$headers[] = $header_name . ": " . $header_value;
|
996 |
+
if (strtolower(Key($this->request_headers)) == "host") {
|
997 |
+
$this->request_host = strtolower($header_value);
|
998 |
+
$host_set = 1;
|
999 |
+
}
|
1000 |
+
}
|
1001 |
+
if (!$host_set) {
|
1002 |
+
$headers[] = "Host: " . $this->host_name;
|
1003 |
+
$this->request_host = strtolower($this->host_name);
|
1004 |
+
}
|
1005 |
+
if (count($this->cookies)) {
|
1006 |
+
$cookies = array();
|
1007 |
+
$this->PickCookies($cookies, 0);
|
1008 |
+
if (strtolower($this->protocol) == "https") $this->PickCookies($cookies, 1);
|
1009 |
+
if (count($cookies)) {
|
1010 |
+
$h = count($headers);
|
1011 |
+
$headers[$h] = "Cookie:";
|
1012 |
+
for (Reset($cookies), $cookie = 0; $cookie < count($cookies); Next($cookies), $cookie++) {
|
1013 |
+
$cookie_name = Key($cookies);
|
1014 |
+
$headers[$h] .= " " . $cookie_name . "=" . $cookies[$cookie_name]["value"] . ";";
|
1015 |
+
}
|
1016 |
+
}
|
1017 |
+
}
|
1018 |
+
$next_state = "RequestSent";
|
1019 |
+
if ($this->use_curl) {
|
1020 |
+
if (IsSet($arguments['StreamRequest'])) return ($this->SetError("Streaming request data is not supported when using Curl", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1021 |
+
if ($body_length && strlen($this->request_body) == 0) {
|
1022 |
+
for ($request_body = "", $success = 1, $part = 0; $part < count($post_parts); $part++) {
|
1023 |
+
$request_body .= $post_parts[$part]["HEADERS"] . $post_parts[$part]["DATA"];
|
1024 |
+
if (IsSet($post_parts[$part]["FILENAME"])) {
|
1025 |
+
if (!($file = @fopen($post_parts[$part]["FILENAME"], "rb"))) {
|
1026 |
+
$this->SetPHPError("could not open upload file " . $post_parts[$part]["FILENAME"], self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
|
1027 |
+
$success = 0;
|
1028 |
+
break;
|
1029 |
+
}
|
1030 |
+
while (!feof($file)) {
|
1031 |
+
if (GetType($block = @fread($file, $this->file_buffer_length)) != "string") {
|
1032 |
+
$this->SetPHPError("could not read upload file", self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
|
1033 |
+
$success = 0;
|
1034 |
+
break;
|
1035 |
+
}
|
1036 |
+
$request_body .= $block;
|
1037 |
+
}
|
1038 |
+
fclose($file);
|
1039 |
+
if (!$success) break;
|
1040 |
+
}
|
1041 |
+
$request_body .= "\r\n";
|
1042 |
+
}
|
1043 |
+
$request_body .= "--" . $boundary . "--\r\n";
|
1044 |
+
} else
|
1045 |
+
$request_body = $this->request_body;
|
1046 |
+
curl_setopt($this->connection, CURLOPT_HEADER, 1);
|
1047 |
+
curl_setopt($this->connection, CURLOPT_RETURNTRANSFER, 1);
|
1048 |
+
if ($this->timeout) curl_setopt($this->connection, CURLOPT_TIMEOUT, $this->timeout);
|
1049 |
+
curl_setopt($this->connection, CURLOPT_SSL_VERIFYPEER, 0);
|
1050 |
+
curl_setopt($this->connection, CURLOPT_SSL_VERIFYHOST, 0);
|
1051 |
+
$request = $this->request . "\r\n" . implode("\r\n", $headers) . "\r\n\r\n" . $request_body;
|
1052 |
+
curl_setopt($this->connection, CURLOPT_CUSTOMREQUEST, $request);
|
1053 |
+
if ($this->debug) $this->OutputDebug("C " . $request);
|
1054 |
+
if (!($success = (strlen($this->response = curl_exec($this->connection)) != 0))) {
|
1055 |
+
$error = curl_error($this->connection);
|
1056 |
+
$this->SetError("Could not execute the request" . (strlen($error) ? ": " . $error : ""), HTTP_CLIENT_ERROR_PROTOCOL_FAILURE);
|
1057 |
+
}
|
1058 |
+
} else {
|
1059 |
+
if (($success = $this->PutLine($this->request))) {
|
1060 |
+
for ($header = 0; $header < count($headers); $header++) {
|
1061 |
+
if (!$success = $this->PutLine($headers[$header])) break;
|
1062 |
+
}
|
1063 |
+
if ($success && ($success = $this->PutLine(""))) {
|
1064 |
+
if (IsSet($arguments['StreamRequest'])) $next_state = "SendingRequestBody"; elseif ($body_length) {
|
1065 |
+
if (strlen($this->request_body)) $success = $this->PutData($this->request_body); else {
|
1066 |
+
for ($part = 0; $part < count($post_parts); $part++) {
|
1067 |
+
if (!($success = $this->PutData($post_parts[$part]["HEADERS"])) || !($success = $this->PutData($post_parts[$part]["DATA"]))) break;
|
1068 |
+
if (IsSet($post_parts[$part]["FILENAME"])) {
|
1069 |
+
if (!($file = @fopen($post_parts[$part]["FILENAME"], "rb"))) {
|
1070 |
+
$this->SetPHPError("could not open upload file " . $post_parts[$part]["FILENAME"], self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
|
1071 |
+
$success = 0;
|
1072 |
+
break;
|
1073 |
+
}
|
1074 |
+
while (!feof($file)) {
|
1075 |
+
if (GetType($block = @fread($file, $this->file_buffer_length)) != "string") {
|
1076 |
+
$this->SetPHPError("could not read upload file", self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
|
1077 |
+
$success = 0;
|
1078 |
+
break;
|
1079 |
+
}
|
1080 |
+
if (!($success = $this->PutData($block))) break;
|
1081 |
+
}
|
1082 |
+
fclose($file);
|
1083 |
+
if (!$success) break;
|
1084 |
+
}
|
1085 |
+
if (!($success = $this->PutLine(""))) break;
|
1086 |
+
}
|
1087 |
+
if ($success) $success = $this->PutLine("--" . $boundary . "--");
|
1088 |
+
}
|
1089 |
+
if ($success) $sucess = $this->FlushData();
|
1090 |
+
}
|
1091 |
+
}
|
1092 |
+
}
|
1093 |
+
}
|
1094 |
+
if (!$success) return ($this->SetError("could not send the HTTP request: " . $this->error, $this->error_code));
|
1095 |
+
$this->state = $next_state;
|
1096 |
+
|
1097 |
+
return ("");
|
1098 |
+
}
|
1099 |
+
|
1100 |
+
Function SetCookie($name, $value, $expires = "", $path = "/", $domain = "", $secure = 0, $verbatim = 0) {
|
1101 |
+
if (strlen($this->error)) return ($this->error);
|
1102 |
+
if (strlen($name) == 0) return ($this->SetError("it was not specified a valid cookie name", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1103 |
+
if (strlen($path) == 0 || strcmp($path[0], "/")) return ($this->SetError($path . " is not a valid path for setting cookie " . $name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1104 |
+
if ($domain == "" || strpos($domain, ".", $domain[0] == "." ? 1 : 0) === false) return ($this->SetError($domain . " is not a valid domain for setting cookie " . $name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1105 |
+
$domain = strtolower($domain);
|
1106 |
+
if (!strcmp($domain[0], ".")) $domain = substr($domain, 1);
|
1107 |
+
if (!$verbatim) {
|
1108 |
+
$name = $this->CookieEncode($name, 1);
|
1109 |
+
$value = $this->CookieEncode($value, 0);
|
1110 |
+
}
|
1111 |
+
$secure = intval($secure);
|
1112 |
+
$this->cookies[$secure][$domain][$path][$name] = array(
|
1113 |
+
"name" => $name,
|
1114 |
+
"value" => $value,
|
1115 |
+
"domain" => $domain,
|
1116 |
+
"path" => $path,
|
1117 |
+
"expires" => $expires,
|
1118 |
+
"secure" => $secure
|
1119 |
+
);
|
1120 |
+
|
1121 |
+
return ("");
|
1122 |
+
}
|
1123 |
+
|
1124 |
+
Function SendRequestBody($data, $end_of_data) {
|
1125 |
+
if (strlen($this->error)) return ($this->error);
|
1126 |
+
switch ($this->state) {
|
1127 |
+
case "Disconnected":
|
1128 |
+
return ($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1129 |
+
case "Connected":
|
1130 |
+
case "ConnectedToProxy":
|
1131 |
+
return ($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1132 |
+
case "SendingRequestBody":
|
1133 |
+
break;
|
1134 |
+
case "RequestSent":
|
1135 |
+
return ($this->SetError("request body was already sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1136 |
+
default:
|
1137 |
+
return ($this->SetError("can not send the request body in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1138 |
+
}
|
1139 |
+
$length = strlen($data);
|
1140 |
+
if ($length) {
|
1141 |
+
$size = dechex($length) . "\r\n";
|
1142 |
+
if (!$this->PutData($size) || !$this->PutData($data)) return ($this->error);
|
1143 |
+
}
|
1144 |
+
if ($end_of_data) {
|
1145 |
+
$size = "0\r\n";
|
1146 |
+
if (!$this->PutData($size)) return ($this->error);
|
1147 |
+
$this->state = "RequestSent";
|
1148 |
+
}
|
1149 |
+
|
1150 |
+
return ("");
|
1151 |
+
}
|
1152 |
+
|
1153 |
+
Function ReadReplyHeadersResponse(&$headers) {
|
1154 |
+
$headers = array();
|
1155 |
+
if (strlen($this->error)) return ($this->error);
|
1156 |
+
switch ($this->state) {
|
1157 |
+
case "Disconnected":
|
1158 |
+
return ($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1159 |
+
case "Connected":
|
1160 |
+
return ($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1161 |
+
case "ConnectedToProxy":
|
1162 |
+
return ($this->SetError("connection from the remote server from the proxy was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1163 |
+
case "SendingRequestBody":
|
1164 |
+
return ($this->SetError("request body data was not completely sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1165 |
+
case "ConnectSent":
|
1166 |
+
$connect = 1;
|
1167 |
+
break;
|
1168 |
+
case "RequestSent":
|
1169 |
+
$connect = 0;
|
1170 |
+
break;
|
1171 |
+
default:
|
1172 |
+
return ($this->SetError("can not get request headers in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1173 |
+
}
|
1174 |
+
$this->content_length = $this->read_length = $this->read_response = $this->remaining_chunk = 0;
|
1175 |
+
$this->content_length_set = $this->chunked = $this->last_chunk_read = $chunked = 0;
|
1176 |
+
$this->force_close = $this->connection_close = 0;
|
1177 |
+
for ($this->response_status = ""; ;) {
|
1178 |
+
$line = $this->GetLine();
|
1179 |
+
if (GetType($line) != "string") return ($this->SetError("could not read request reply: " . $this->error, $this->error_code));
|
1180 |
+
if (strlen($this->response_status) == 0) {
|
1181 |
+
if (!preg_match($match = "/^http\\/[0-9]+\\.[0-9]+[ \t]+([0-9]+)[ \t]*(.*)\$/i", $line, $matches)) return ($this->SetError("it was received an unexpected HTTP response status", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
|
1182 |
+
$this->response_status = $matches[1];
|
1183 |
+
$this->response_message = $matches[2];
|
1184 |
+
if ($this->response_status == 204) {
|
1185 |
+
$this->content_length = 0;
|
1186 |
+
$this->content_length_set = 1;
|
1187 |
+
}
|
1188 |
+
}
|
1189 |
+
if ($line == "") {
|
1190 |
+
if (strlen($this->response_status) == 0) return ($this->SetError("it was not received HTTP response status", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
|
1191 |
+
$this->state = ($connect ? "GotConnectHeaders" : "GotReplyHeaders");
|
1192 |
+
break;
|
1193 |
+
}
|
1194 |
+
$header_name = strtolower($this->Tokenize($line, ":"));
|
1195 |
+
$header_value = Trim(Chop($this->Tokenize("\r\n")));
|
1196 |
+
if (IsSet($headers[$header_name])) {
|
1197 |
+
if (GetType($headers[$header_name]) == "string") $headers[$header_name] = array($headers[$header_name]);
|
1198 |
+
$headers[$header_name][] = $header_value;
|
1199 |
+
} else
|
1200 |
+
$headers[$header_name] = $header_value;
|
1201 |
+
if (!$connect) {
|
1202 |
+
switch ($header_name) {
|
1203 |
+
case "content-length":
|
1204 |
+
$this->content_length = intval($headers[$header_name]);
|
1205 |
+
$this->content_length_set = 1;
|
1206 |
+
break;
|
1207 |
+
case "transfer-encoding":
|
1208 |
+
$encoding = $this->Tokenize($header_value, "; \t");
|
1209 |
+
if (!$this->use_curl && !strcmp($encoding, "chunked")) $chunked = 1;
|
1210 |
+
break;
|
1211 |
+
case "set-cookie":
|
1212 |
+
if ($this->support_cookies) {
|
1213 |
+
if (GetType($headers[$header_name]) == "array") $cookie_headers = $headers[$header_name]; else
|
1214 |
+
$cookie_headers = array($headers[$header_name]);
|
1215 |
+
for ($cookie = 0; $cookie < count($cookie_headers); $cookie++) {
|
1216 |
+
$cookie_name = trim($this->Tokenize($cookie_headers[$cookie], "="));
|
1217 |
+
$cookie_value = $this->Tokenize(";");
|
1218 |
+
$domain = $this->request_host;
|
1219 |
+
$path = "/";
|
1220 |
+
$expires = "";
|
1221 |
+
$secure = 0;
|
1222 |
+
while (($name = strtolower(trim(UrlDecode($this->Tokenize("="))))) != "") {
|
1223 |
+
$value = UrlDecode($this->Tokenize(";"));
|
1224 |
+
switch ($name) {
|
1225 |
+
case "domain":
|
1226 |
+
$domain = $value;
|
1227 |
+
break;
|
1228 |
+
case "path":
|
1229 |
+
$path = $value;
|
1230 |
+
break;
|
1231 |
+
case "expires":
|
1232 |
+
if (preg_match("/^((Mon|Monday|Tue|Tuesday|Wed|Wednesday|Thu|Thursday|Fri|Friday|Sat|Saturday|Sun|Sunday), )?([0-9]{2})\\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\-([0-9]{2,4}) ([0-9]{2})\\:([0-9]{2})\\:([0-9]{2}) GMT\$/", $value, $matches)) {
|
1233 |
+
$year = intval($matches[5]);
|
1234 |
+
if ($year < 1900) $year += ($year < 70 ? 2000 : 1900);
|
1235 |
+
$expires = "$year-" . $this->months[$matches[4]] . "-" . $matches[3] . " " . $matches[6] . ":" . $matches[7] . ":" . $matches[8];
|
1236 |
+
}
|
1237 |
+
break;
|
1238 |
+
case "secure":
|
1239 |
+
$secure = 1;
|
1240 |
+
break;
|
1241 |
+
}
|
1242 |
+
}
|
1243 |
+
if (strlen($this->SetCookie($cookie_name, $cookie_value, $expires, $path, $domain, $secure, 1))) $this->error = "";
|
1244 |
+
}
|
1245 |
+
}
|
1246 |
+
break;
|
1247 |
+
case "connection":
|
1248 |
+
$this->force_close = $this->connection_close = !strcmp(strtolower($header_value), "close");
|
1249 |
+
break;
|
1250 |
+
}
|
1251 |
+
}
|
1252 |
+
}
|
1253 |
+
$this->chunked = $chunked;
|
1254 |
+
if ($this->content_length_set) $this->connection_close = 0;
|
1255 |
+
|
1256 |
+
return ("");
|
1257 |
+
}
|
1258 |
+
|
1259 |
+
Function Redirect(&$headers) {
|
1260 |
+
if ($this->follow_redirect) {
|
1261 |
+
if (!IsSet($headers["location"]) || (GetType($headers["location"]) != "array" && strlen($location = $headers["location"]) == 0) || (GetType($headers["location"]) == "array" && strlen($location = $headers["location"][0]) == 0)) return ($this->SetError("it was received a redirect without location URL", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
|
1262 |
+
if (strcmp($location[0], "/")) {
|
1263 |
+
if (!($location_arguments = @parse_url($location))) return ($this->SetError("the server did not return a valid redirection location URL", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
|
1264 |
+
if (!IsSet($location_arguments["scheme"])) $location = ((GetType($end = strrpos($this->request_uri, "/")) == "integer" && $end > 1) ? substr($this->request_uri, 0, $end) : "") . "/" . $location;
|
1265 |
+
}
|
1266 |
+
if (!strcmp($location[0], "/")) $location = $this->protocol . "://" . $this->host_name . ($this->host_port ? ":" . $this->host_port : "") . $location;
|
1267 |
+
$error = $this->GetRequestArguments($location, $arguments);
|
1268 |
+
if (strlen($error)) return ($this->SetError("could not process redirect url: " . $error, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
|
1269 |
+
$arguments["RequestMethod"] = "GET";
|
1270 |
+
if (strlen($error = $this->Close()) == 0 && strlen($error = $this->Open($arguments)) == 0 && strlen($error = $this->SendRequest($arguments)) == 0) {
|
1271 |
+
$this->redirection_level++;
|
1272 |
+
if ($this->redirection_level > $this->redirection_limit) {
|
1273 |
+
$error = "it was exceeded the limit of request redirections";
|
1274 |
+
$this->error_code = HTTP_CLIENT_ERROR_PROTOCOL_FAILURE;
|
1275 |
+
} else
|
1276 |
+
$error = $this->ReadReplyHeaders($headers);
|
1277 |
+
$this->redirection_level--;
|
1278 |
+
}
|
1279 |
+
if (strlen($error)) return ($this->SetError($error, $this->error_code));
|
1280 |
+
}
|
1281 |
+
|
1282 |
+
return ("");
|
1283 |
+
}
|
1284 |
+
|
1285 |
+
Function Authenticate(&$headers, $proxy, &$proxy_authorization, &$user, &$password, &$realm, &$workstation) {
|
1286 |
+
if ($proxy) {
|
1287 |
+
$authenticate_header = "proxy-authenticate";
|
1288 |
+
$authorization_header = "Proxy-Authorization";
|
1289 |
+
$authenticate_status = "407";
|
1290 |
+
$authentication_mechanism = $this->proxy_authentication_mechanism;
|
1291 |
+
} else {
|
1292 |
+
$authenticate_header = "www-authenticate";
|
1293 |
+
$authorization_header = "Authorization";
|
1294 |
+
$authenticate_status = "401";
|
1295 |
+
$authentication_mechanism = $this->authentication_mechanism;
|
1296 |
+
}
|
1297 |
+
if (IsSet($headers[$authenticate_header]) && $this->sasl_authenticate) {
|
1298 |
+
if (function_exists("class_exists") && !class_exists("sasl_client_class")) return ($this->SetError("the SASL client class needs to be loaded to be able to authenticate" . ($proxy ? " with the proxy server" : "") . " and access this site", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1299 |
+
if (GetType($headers[$authenticate_header]) == "array") $authenticate = $headers[$authenticate_header]; else
|
1300 |
+
$authenticate = array($headers[$authenticate_header]);
|
1301 |
+
for ($response = "", $mechanisms = array(), $m = 0; $m < count($authenticate); $m++) {
|
1302 |
+
$mechanism = $this->Tokenize($authenticate[$m], " ");
|
1303 |
+
$response = $this->Tokenize("");
|
1304 |
+
if (strlen($authentication_mechanism)) {
|
1305 |
+
if (!strcmp($authentication_mechanism, $mechanism)) {
|
1306 |
+
$mechanisms[] = $mechanism;
|
1307 |
+
break;
|
1308 |
+
}
|
1309 |
+
} else
|
1310 |
+
$mechanisms[] = $mechanism;
|
1311 |
+
}
|
1312 |
+
$sasl = new sasl_client_class;
|
1313 |
+
if (IsSet($user)) $sasl->SetCredential("user", $user);
|
1314 |
+
if (IsSet($password)) $sasl->SetCredential("password", $password);
|
1315 |
+
if (IsSet($realm)) $sasl->SetCredential("realm", $realm);
|
1316 |
+
if (IsSet($workstation)) $sasl->SetCredential("workstation", $workstation);
|
1317 |
+
$sasl->SetCredential("uri", $this->request_uri);
|
1318 |
+
$sasl->SetCredential("method", $this->request_method);
|
1319 |
+
$sasl->SetCredential("session", $this->session);
|
1320 |
+
do {
|
1321 |
+
$status = $sasl->Start($mechanisms, $message, $interactions);
|
1322 |
+
} while ($status == SASL_INTERACT);
|
1323 |
+
switch ($status) {
|
1324 |
+
case SASL_CONTINUE:
|
1325 |
+
break;
|
1326 |
+
case SASL_NOMECH:
|
1327 |
+
return ($this->SetError(($proxy ? "proxy " : "") . "authentication error: " . (strlen($authentication_mechanism) ? "authentication mechanism " . $authentication_mechanism . " may not be used: " : "") . $sasl->error, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1328 |
+
default:
|
1329 |
+
return ($this->SetError("Could not start the SASL " . ($proxy ? "proxy " : "") . "authentication client: " . $sasl->error, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1330 |
+
}
|
1331 |
+
if ($proxy >= 0) {
|
1332 |
+
for (; ;) {
|
1333 |
+
if (strlen($error = $this->ReadReplyBody($body, $this->file_buffer_length))) return ($error);
|
1334 |
+
if (strlen($body) == 0) break;
|
1335 |
+
}
|
1336 |
+
}
|
1337 |
+
$authorization_value = $sasl->mechanism . (IsSet($message) ? " " . ($sasl->encode_response ? Base64::encode($message) : $message) : "");
|
1338 |
+
$request_arguments = $this->request_arguments;
|
1339 |
+
$arguments = $request_arguments;
|
1340 |
+
$arguments["Headers"][$authorization_header] = $authorization_value;
|
1341 |
+
if (!$proxy && strlen($proxy_authorization)) $arguments["Headers"]["Proxy-Authorization"] = $proxy_authorization;
|
1342 |
+
if (strlen($error = $this->Close()) || strlen($error = $this->Open($arguments))) return ($this->SetError($error, $this->error_code));
|
1343 |
+
$authenticated = 0;
|
1344 |
+
if (IsSet($message)) {
|
1345 |
+
if ($proxy < 0) {
|
1346 |
+
if (strlen($error = $this->ConnectFromProxy($arguments, $headers))) return ($this->SetError($error, $this->error_code));
|
1347 |
+
} else {
|
1348 |
+
if (strlen($error = $this->SendRequest($arguments)) || strlen($error = $this->ReadReplyHeadersResponse($headers))) return ($this->SetError($error, $this->error_code));
|
1349 |
+
}
|
1350 |
+
if (!IsSet($headers[$authenticate_header])) $authenticate = array(); elseif (GetType($headers[$authenticate_header]) == "array") $authenticate = $headers[$authenticate_header];
|
1351 |
+
else
|
1352 |
+
$authenticate = array($headers[$authenticate_header]);
|
1353 |
+
for ($mechanism = 0; $mechanism < count($authenticate); $mechanism++) {
|
1354 |
+
if (!strcmp($this->Tokenize($authenticate[$mechanism], " "), $sasl->mechanism)) {
|
1355 |
+
$response = $this->Tokenize("");
|
1356 |
+
break;
|
1357 |
+
}
|
1358 |
+
}
|
1359 |
+
switch ($this->response_status) {
|
1360 |
+
case $authenticate_status:
|
1361 |
+
break;
|
1362 |
+
case "301":
|
1363 |
+
case "302":
|
1364 |
+
case "303":
|
1365 |
+
case "307":
|
1366 |
+
if ($proxy >= 0) return ($this->Redirect($headers));
|
1367 |
+
default:
|
1368 |
+
if (intval($this->response_status / 100) == 2) {
|
1369 |
+
if ($proxy) $proxy_authorization = $authorization_value;
|
1370 |
+
$authenticated = 1;
|
1371 |
+
break;
|
1372 |
+
}
|
1373 |
+
if ($proxy && !strcmp($this->response_status, "401")) {
|
1374 |
+
$proxy_authorization = $authorization_value;
|
1375 |
+
$authenticated = 1;
|
1376 |
+
break;
|
1377 |
+
}
|
1378 |
+
|
1379 |
+
return ($this->SetError(($proxy ? "proxy " : "") . "authentication error: " . $this->response_status . " " . $this->response_message, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
|
1380 |
+
}
|
1381 |
+
}
|
1382 |
+
for (; !$authenticated;) {
|
1383 |
+
do {
|
1384 |
+
$status = $sasl->Step($response, $message, $interactions);
|
1385 |
+
} while ($status == SASL_INTERACT);
|
1386 |
+
switch ($status) {
|
1387 |
+
case SASL_CONTINUE:
|
1388 |
+
$authorization_value = $sasl->mechanism . (IsSet($message) ? " " . ($sasl->encode_response ? Base64::encode($message) : $message) : "");
|
1389 |
+
$arguments = $request_arguments;
|
1390 |
+
$arguments["Headers"][$authorization_header] = $authorization_value;
|
1391 |
+
if (!$proxy && strlen($proxy_authorization)) $arguments["Headers"]["Proxy-Authorization"] = $proxy_authorization;
|
1392 |
+
if ($proxy < 0) {
|
1393 |
+
if (strlen($error = $this->ConnectFromProxy($arguments, $headers))) return ($this->SetError($error, $this->error_code));
|
1394 |
+
} else {
|
1395 |
+
if (strlen($error = $this->SendRequest($arguments)) || strlen($error = $this->ReadReplyHeadersResponse($headers))) return ($this->SetError($error, $this->error_code));
|
1396 |
+
}
|
1397 |
+
switch ($this->response_status) {
|
1398 |
+
case $authenticate_status:
|
1399 |
+
if (GetType($headers[$authenticate_header]) == "array") $authenticate = $headers[$authenticate_header]; else
|
1400 |
+
$authenticate = array($headers[$authenticate_header]);
|
1401 |
+
for ($response = "", $mechanism = 0; $mechanism < count($authenticate); $mechanism++) {
|
1402 |
+
if (!strcmp($this->Tokenize($authenticate[$mechanism], " "), $sasl->mechanism)) {
|
1403 |
+
$response = $this->Tokenize("");
|
1404 |
+
break;
|
1405 |
+
}
|
1406 |
+
}
|
1407 |
+
if ($proxy >= 0) {
|
1408 |
+
for (; ;) {
|
1409 |
+
if (strlen($error = $this->ReadReplyBody($body, $this->file_buffer_length))) return ($error);
|
1410 |
+
if (strlen($body) == 0) break;
|
1411 |
+
}
|
1412 |
+
}
|
1413 |
+
$this->state = "Connected";
|
1414 |
+
break;
|
1415 |
+
case "301":
|
1416 |
+
case "302":
|
1417 |
+
case "303":
|
1418 |
+
case "307":
|
1419 |
+
if ($proxy >= 0) return ($this->Redirect($headers));
|
1420 |
+
default:
|
1421 |
+
if (intval($this->response_status / 100) == 2) {
|
1422 |
+
if ($proxy) $proxy_authorization = $authorization_value;
|
1423 |
+
$authenticated = 1;
|
1424 |
+
break;
|
1425 |
+
}
|
1426 |
+
if ($proxy && !strcmp($this->response_status, "401")) {
|
1427 |
+
$proxy_authorization = $authorization_value;
|
1428 |
+
$authenticated = 1;
|
1429 |
+
break;
|
1430 |
+
}
|
1431 |
+
|
1432 |
+
return ($this->SetError(($proxy ? "proxy " : "") . "authentication error: " . $this->response_status . " " . $this->response_message));
|
1433 |
+
}
|
1434 |
+
break;
|
1435 |
+
default:
|
1436 |
+
return ($this->SetError("Could not process the SASL " . ($proxy ? "proxy " : "") . "authentication step: " . $sasl->error, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
|
1437 |
+
}
|
1438 |
+
}
|
1439 |
+
}
|
1440 |
+
|
1441 |
+
return ("");
|
1442 |
+
}
|
1443 |
+
|
1444 |
+
Function ReadReplyHeaders(&$headers) {
|
1445 |
+
if (strlen($error = $this->ReadReplyHeadersResponse($headers))) return ($error);
|
1446 |
+
$proxy_authorization = "";
|
1447 |
+
while (!strcmp($this->response_status, "100")) {
|
1448 |
+
$this->state = "RequestSent";
|
1449 |
+
if (strlen($error = $this->ReadReplyHeadersResponse($headers))) return ($error);
|
1450 |
+
}
|
1451 |
+
switch ($this->response_status) {
|
1452 |
+
case "301":
|
1453 |
+
case "302":
|
1454 |
+
case "303":
|
1455 |
+
case "307":
|
1456 |
+
if (strlen($error = $this->Redirect($headers))) return ($error);
|
1457 |
+
break;
|
1458 |
+
case "407":
|
1459 |
+
if (strlen($error = $this->Authenticate($headers, 1, $proxy_authorization, $this->proxy_request_user, $this->proxy_request_password, $this->proxy_request_realm, $this->proxy_request_workstation))) return ($error);
|
1460 |
+
if (strcmp($this->response_status, "401")) return ("");
|
1461 |
+
case "401":
|
1462 |
+
return ($this->Authenticate($headers, 0, $proxy_authorization, $this->request_user, $this->request_password, $this->request_realm, $this->request_workstation));
|
1463 |
+
}
|
1464 |
+
|
1465 |
+
return ("");
|
1466 |
+
}
|
1467 |
+
|
1468 |
+
Function ReadReplyBody(&$body, $length) {
|
1469 |
+
$body = "";
|
1470 |
+
if (strlen($this->error)) return ($this->error);
|
1471 |
+
switch ($this->state) {
|
1472 |
+
case "Disconnected":
|
1473 |
+
return ($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1474 |
+
case "Connected":
|
1475 |
+
case "ConnectedToProxy":
|
1476 |
+
return ($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1477 |
+
case "RequestSent":
|
1478 |
+
if (($error = $this->ReadReplyHeaders($headers)) != "") return ($error);
|
1479 |
+
break;
|
1480 |
+
case "GotReplyHeaders":
|
1481 |
+
break;
|
1482 |
+
case 'ResponseReceived':
|
1483 |
+
$body = '';
|
1484 |
+
|
1485 |
+
return ('');
|
1486 |
+
default:
|
1487 |
+
return ($this->SetError("can not get request headers in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1488 |
+
}
|
1489 |
+
if ($this->content_length_set) $length = min($this->content_length - $this->read_length, $length);
|
1490 |
+
$body = '';
|
1491 |
+
if ($length > 0) {
|
1492 |
+
if (!$this->EndOfInput() && ($body = $this->ReadBytes($length)) == "") {
|
1493 |
+
if (strlen($this->error)) return ($this->SetError("could not get the request reply body: " . $this->error, $this->error_code));
|
1494 |
+
}
|
1495 |
+
$this->read_length += strlen($body);
|
1496 |
+
if ($this->EndOfInput()) $this->state = 'ResponseReceived';
|
1497 |
+
}
|
1498 |
+
|
1499 |
+
return ("");
|
1500 |
+
}
|
1501 |
+
|
1502 |
+
Function ReadWholeReplyBody(&$body) {
|
1503 |
+
$body = '';
|
1504 |
+
for (; ;) {
|
1505 |
+
if (strlen($error = $this->ReadReplyBody($block, $this->file_buffer_length))) return ($error);
|
1506 |
+
if (strlen($block) == 0) return ('');
|
1507 |
+
$body .= $block;
|
1508 |
+
}
|
1509 |
+
}
|
1510 |
+
|
1511 |
+
Function ReadWholeReplyIntoTemporaryFile(&$file) {
|
1512 |
+
if (!($file = tmpfile())) return $this->SetPHPError('could not create the temporary file to save the response', self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
|
1513 |
+
for (; ;) {
|
1514 |
+
if (strlen($error = $this->ReadReplyBody($block, $this->file_buffer_length))) {
|
1515 |
+
fclose($file);
|
1516 |
+
|
1517 |
+
return ($error);
|
1518 |
+
}
|
1519 |
+
if (strlen($block) == 0) {
|
1520 |
+
if (@fseek($file, 0) != 0) {
|
1521 |
+
$error = $this->SetPHPError('could not seek to the beginning of temporary file with the response', self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
|
1522 |
+
fclose($file);
|
1523 |
+
|
1524 |
+
return $error;
|
1525 |
+
}
|
1526 |
+
|
1527 |
+
return ('');
|
1528 |
+
}
|
1529 |
+
if (!@fwrite($file, $block)) {
|
1530 |
+
$error = $this->SetPHPError('could not write to the temporary file to save the response', self::PHPErrorMessage(), HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
|
1531 |
+
fclose($file);
|
1532 |
+
|
1533 |
+
return $error;
|
1534 |
+
}
|
1535 |
+
}
|
1536 |
+
}
|
1537 |
+
|
1538 |
+
Function SaveCookies(&$cookies, $domain = '', $secure_only = 0, $persistent_only = 0) {
|
1539 |
+
$now = gmdate("Y-m-d H-i-s");
|
1540 |
+
$cookies = array();
|
1541 |
+
for ($secure_cookies = 0, Reset($this->cookies); $secure_cookies < count($this->cookies); Next($this->cookies), $secure_cookies++) {
|
1542 |
+
$secure = Key($this->cookies);
|
1543 |
+
if (!$secure_only || $secure) {
|
1544 |
+
for ($cookie_domain = 0, Reset($this->cookies[$secure]); $cookie_domain < count($this->cookies[$secure]); Next($this->cookies[$secure]), $cookie_domain++) {
|
1545 |
+
$domain_pattern = Key($this->cookies[$secure]);
|
1546 |
+
$match = strlen($domain) - strlen($domain_pattern);
|
1547 |
+
if (strlen($domain) == 0 || ($match >= 0 && !strcmp($domain_pattern, substr($domain, $match)) && ($match == 0 || $domain_pattern[0] == "." || $domain[$match - 1] == "."))) {
|
1548 |
+
for (Reset($this->cookies[$secure][$domain_pattern]), $path_part = 0; $path_part < count($this->cookies[$secure][$domain_pattern]); Next($this->cookies[$secure][$domain_pattern]), $path_part++) {
|
1549 |
+
$path = Key($this->cookies[$secure][$domain_pattern]);
|
1550 |
+
for (Reset($this->cookies[$secure][$domain_pattern][$path]), $cookie = 0; $cookie < count($this->cookies[$secure][$domain_pattern][$path]); Next($this->cookies[$secure][$domain_pattern][$path]), $cookie++) {
|
1551 |
+
$cookie_name = Key($this->cookies[$secure][$domain_pattern][$path]);
|
1552 |
+
$expires = $this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
|
1553 |
+
if ((!$persistent_only && strlen($expires) == 0) || (strlen($expires) && strcmp($now, $expires) < 0)) $cookies[$secure][$domain_pattern][$path][$cookie_name] = $this->cookies[$secure][$domain_pattern][$path][$cookie_name];
|
1554 |
+
}
|
1555 |
+
}
|
1556 |
+
}
|
1557 |
+
}
|
1558 |
+
}
|
1559 |
+
}
|
1560 |
+
}
|
1561 |
+
|
1562 |
+
Function SavePersistentCookies(&$cookies, $domain = '', $secure_only = 0) {
|
1563 |
+
$this->SaveCookies($cookies, $domain, $secure_only, 1);
|
1564 |
+
}
|
1565 |
+
|
1566 |
+
Function GetPersistentCookies(&$cookies, $domain = '', $secure_only = 0) {
|
1567 |
+
$this->SavePersistentCookies($cookies, $domain, $secure_only);
|
1568 |
+
}
|
1569 |
+
|
1570 |
+
Function RestoreCookies($cookies, $clear = 1) {
|
1571 |
+
$new_cookies = ($clear ? array() : $this->cookies);
|
1572 |
+
for ($secure_cookies = 0, Reset($cookies); $secure_cookies < count($cookies); Next($cookies), $secure_cookies++) {
|
1573 |
+
$secure = Key($cookies);
|
1574 |
+
if (GetType($secure) != "integer") return ($this->SetError("invalid cookie secure value type (" . serialize($secure) . ")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1575 |
+
for ($cookie_domain = 0, Reset($cookies[$secure]); $cookie_domain < count($cookies[$secure]); Next($cookies[$secure]), $cookie_domain++) {
|
1576 |
+
$domain_pattern = Key($cookies[$secure]);
|
1577 |
+
if (GetType($domain_pattern) != "string") return ($this->SetError("invalid cookie domain value type (" . serialize($domain_pattern) . ")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1578 |
+
for (Reset($cookies[$secure][$domain_pattern]), $path_part = 0; $path_part < count($cookies[$secure][$domain_pattern]); Next($cookies[$secure][$domain_pattern]), $path_part++) {
|
1579 |
+
$path = Key($cookies[$secure][$domain_pattern]);
|
1580 |
+
if (GetType($path) != "string" || strcmp(substr($path, 0, 1), "/")) return ($this->SetError("invalid cookie path value type (" . serialize($path) . ")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1581 |
+
for (Reset($cookies[$secure][$domain_pattern][$path]), $cookie = 0; $cookie < count($cookies[$secure][$domain_pattern][$path]); Next($cookies[$secure][$domain_pattern][$path]), $cookie++) {
|
1582 |
+
$cookie_name = Key($cookies[$secure][$domain_pattern][$path]);
|
1583 |
+
$expires = $cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
|
1584 |
+
$value = $cookies[$secure][$domain_pattern][$path][$cookie_name]["value"];
|
1585 |
+
if (GetType($expires) != "string" || (strlen($expires) && !preg_match("/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\$/", $expires))) return ($this->SetError("invalid cookie expiry value type (" . serialize($expires) . ")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
|
1586 |
+
$new_cookies[$secure][$domain_pattern][$path][$cookie_name] = array(
|
1587 |
+
"name" => $cookie_name,
|
1588 |
+
"value" => $value,
|
1589 |
+
"domain" => $domain_pattern,
|
1590 |
+
"path" => $path,
|
1591 |
+
"expires" => $expires,
|
1592 |
+
"secure" => $secure
|
1593 |
+
);
|
1594 |
+
}
|
1595 |
+
}
|
1596 |
+
}
|
1597 |
+
}
|
1598 |
+
$this->cookies = $new_cookies;
|
1599 |
+
|
1600 |
+
return ("");
|
1601 |
+
}
|
1602 |
+
}
|
1603 |
+
|
Nextend/Framework/Misc/OAuth/OAuth.php
ADDED
@@ -0,0 +1,2536 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc\OAuth;
|
4 |
+
|
5 |
+
/*
|
6 |
+
{metadocument}<?xml version="1.0" encoding="ISO-8859-1" ?>
|
7 |
+
<class>
|
8 |
+
|
9 |
+
<package>net.manuellemos.oauth</package>
|
10 |
+
|
11 |
+
<version>@(#) $Id: oauth_client.php,v 1.139 2015/07/23 20:41:37 mlemos Exp $</version>
|
12 |
+
<copyright>Copyright � (C) Manuel Lemos 2012</copyright>
|
13 |
+
<title>OAuth client</title>
|
14 |
+
<author>Manuel Lemos</author>
|
15 |
+
<authoraddress>mlemos-at-acm.org</authoraddress>
|
16 |
+
|
17 |
+
<documentation>
|
18 |
+
<idiom>en</idiom>
|
19 |
+
<purpose>This class serves two main purposes:<paragraphbreak />
|
20 |
+
1) Implement the OAuth protocol to retrieve a token from a server to
|
21 |
+
authorize the access to an API on behalf of the current
|
22 |
+
user.<paragraphbreak />
|
23 |
+
2) Perform calls to a Web services API using a token previously
|
24 |
+
obtained using this class or a token provided some other way by the
|
25 |
+
Web services provider.</purpose>
|
26 |
+
<usage>Regardless of your purposes, you always need to start calling
|
27 |
+
the class <functionlink>Initialize</functionlink> function after
|
28 |
+
initializing setup variables. After you are done with the class,
|
29 |
+
always call the <functionlink>Finalize</functionlink> function at
|
30 |
+
the end.<paragraphbreak />
|
31 |
+
This class supports either OAuth protocol versions 1.0, 1.0a and
|
32 |
+
2.0. It abstracts the differences between these protocol versions,
|
33 |
+
so the class usage is the same independently of the OAuth
|
34 |
+
version of the server.<paragraphbreak />
|
35 |
+
The class also provides built-in support to several popular OAuth
|
36 |
+
servers, so you do not have to manually configure all the details to
|
37 |
+
access those servers. Just set the
|
38 |
+
<variablelink>server</variablelink> variable to configure the class
|
39 |
+
to access one of the built-in supported servers.<paragraphbreak />
|
40 |
+
If you need to access one type of server that is not yet directly
|
41 |
+
supported by the class, you need to configure it explicitly setting
|
42 |
+
the variables: <variablelink>oauth_version</variablelink>,
|
43 |
+
<variablelink>url_parameters</variablelink>,
|
44 |
+
<variablelink>authorization_header</variablelink>,
|
45 |
+
<variablelink>request_token_url</variablelink>,
|
46 |
+
<variablelink>dialog_url</variablelink>,
|
47 |
+
<variablelink>pin_dialog_url</variablelink>,
|
48 |
+
<variablelink>offline_dialog_url</variablelink>,
|
49 |
+
<variablelink>append_state_to_redirect_uri</variablelink> and
|
50 |
+
<variablelink>access_token_url</variablelink>.<paragraphbreak />
|
51 |
+
Before proceeding to the actual OAuth authorization process, you
|
52 |
+
need to have registered your application with the OAuth server. The
|
53 |
+
registration provides you values to set the variables
|
54 |
+
<variablelink>client_id</variablelink> and
|
55 |
+
<variablelink>client_secret</variablelink>. Some servers also
|
56 |
+
provide an additional value to set the
|
57 |
+
<variablelink>api_key</variablelink> variable.<paragraphbreak />
|
58 |
+
You also need to set the variables
|
59 |
+
<variablelink>redirect_uri</variablelink> and
|
60 |
+
<variablelink>scope</variablelink> before calling the
|
61 |
+
<functionlink>Process</functionlink> function to make the class
|
62 |
+
perform the necessary interactions with the OAuth
|
63 |
+
server.<paragraphbreak />
|
64 |
+
The OAuth protocol involves multiple steps that include redirection
|
65 |
+
to the OAuth server. There it asks permission to the current user to
|
66 |
+
grant your application access to APIs on his/her behalf. When there
|
67 |
+
is a redirection, the class will set the
|
68 |
+
<variablelink>exit</variablelink> variable to
|
69 |
+
<booleanvalue>1</booleanvalue>. Then your script should exit
|
70 |
+
immediately without outputting anything.<paragraphbreak />
|
71 |
+
When the OAuth access token is successfully obtained, the following
|
72 |
+
variables are set by the class with the obtained values:
|
73 |
+
<variablelink>access_token</variablelink>,
|
74 |
+
<variablelink>access_token_secret</variablelink>,
|
75 |
+
<variablelink>access_token_expiry</variablelink>,
|
76 |
+
<variablelink>access_token_type</variablelink>. You may want to
|
77 |
+
store these values to use them later when calling the server
|
78 |
+
APIs.<paragraphbreak />
|
79 |
+
If there was a problem during OAuth authorization process, check the
|
80 |
+
variable <variablelink>authorization_error</variablelink> to
|
81 |
+
determine the reason.<paragraphbreak />
|
82 |
+
Once you get the access token, you can call the server APIs using
|
83 |
+
the <functionlink>CallAPI</functionlink> function. Check the
|
84 |
+
<variablelink>access_token_error</variablelink> variable to
|
85 |
+
determine if there was an error when trying to to call the
|
86 |
+
API.<paragraphbreak />
|
87 |
+
If for some reason the user has revoked the access to your
|
88 |
+
application, you need to ask the user to authorize your application
|
89 |
+
again. First you may need to call the function
|
90 |
+
<functionlink>ResetAccessToken</functionlink> to reset the value of
|
91 |
+
the access token that may be cached in session variables.</usage>
|
92 |
+
</documentation>
|
93 |
+
|
94 |
+
{/metadocument}
|
95 |
+
*/
|
96 |
+
|
97 |
+
use Nextend\Framework\Misc\Base64;
|
98 |
+
|
99 |
+
class OAuth {
|
100 |
+
|
101 |
+
/*
|
102 |
+
{metadocument}
|
103 |
+
<variable>
|
104 |
+
<name>error</name>
|
105 |
+
<type>STRING</type>
|
106 |
+
<value></value>
|
107 |
+
<documentation>
|
108 |
+
<purpose>Store the message that is returned when an error
|
109 |
+
occurs.</purpose>
|
110 |
+
<usage>Check this variable to understand what happened when a call to
|
111 |
+
any of the class functions has failed.<paragraphbreak />
|
112 |
+
This class uses cumulative error handling. This means that if one
|
113 |
+
class functions that may fail is called and this variable was
|
114 |
+
already set to an error message due to a failure in a previous call
|
115 |
+
to the same or other function, the function will also fail and does
|
116 |
+
not do anything.<paragraphbreak />
|
117 |
+
This allows programs using this class to safely call several
|
118 |
+
functions that may fail and only check the failure condition after
|
119 |
+
the last function call.<paragraphbreak />
|
120 |
+
Just set this variable to an empty string to clear the error
|
121 |
+
condition.</usage>
|
122 |
+
</documentation>
|
123 |
+
</variable>
|
124 |
+
{/metadocument}
|
125 |
+
*/
|
126 |
+
var $error = '';
|
127 |
+
|
128 |
+
/*
|
129 |
+
{metadocument}
|
130 |
+
<variable>
|
131 |
+
<name>debug</name>
|
132 |
+
<type>BOOLEAN</type>
|
133 |
+
<value>0</value>
|
134 |
+
<documentation>
|
135 |
+
<purpose>Control whether debug output is enabled</purpose>
|
136 |
+
<usage>Set this variable to <booleanvalue>1</booleanvalue> if you
|
137 |
+
need to check what is going on during calls to the class. When
|
138 |
+
enabled, the debug output goes either to the variable
|
139 |
+
<variablelink>debug_output</variablelink> and the PHP error log.</usage>
|
140 |
+
</documentation>
|
141 |
+
</variable>
|
142 |
+
{/metadocument}
|
143 |
+
*/
|
144 |
+
var $debug = false;
|
145 |
+
|
146 |
+
/*
|
147 |
+
{metadocument}
|
148 |
+
<variable>
|
149 |
+
<name>debug_http</name>
|
150 |
+
<type>BOOLEAN</type>
|
151 |
+
<value>0</value>
|
152 |
+
<documentation>
|
153 |
+
<purpose>Control whether the dialog with the remote Web server
|
154 |
+
should also be logged.</purpose>
|
155 |
+
<usage>Set this variable to <booleanvalue>1</booleanvalue> if you
|
156 |
+
want to inspect the data exchange with the OAuth server.</usage>
|
157 |
+
</documentation>
|
158 |
+
</variable>
|
159 |
+
{/metadocument}
|
160 |
+
*/
|
161 |
+
var $debug_http = false;
|
162 |
+
|
163 |
+
/*
|
164 |
+
{metadocument}
|
165 |
+
<variable>
|
166 |
+
<name>exit</name>
|
167 |
+
<type>BOOLEAN</type>
|
168 |
+
<value>0</value>
|
169 |
+
<documentation>
|
170 |
+
<purpose>Determine if the current script should be exited.</purpose>
|
171 |
+
<usage>Check this variable after calling the
|
172 |
+
<functionlink>Process</functionlink> function and exit your script
|
173 |
+
immediately if the variable is set to
|
174 |
+
<booleanvalue>1</booleanvalue>.</usage>
|
175 |
+
</documentation>
|
176 |
+
</variable>
|
177 |
+
{/metadocument}
|
178 |
+
*/
|
179 |
+
var $exit = false;
|
180 |
+
|
181 |
+
/*
|
182 |
+
{metadocument}
|
183 |
+
<variable>
|
184 |
+
<name>debug_output</name>
|
185 |
+
<type>STRING</type>
|
186 |
+
<value></value>
|
187 |
+
<documentation>
|
188 |
+
<purpose>Capture the debug output generated by the class</purpose>
|
189 |
+
<usage>Inspect this variable if you need to see what happened during
|
190 |
+
the class function calls.</usage>
|
191 |
+
</documentation>
|
192 |
+
</variable>
|
193 |
+
{/metadocument}
|
194 |
+
*/
|
195 |
+
var $debug_output = '';
|
196 |
+
|
197 |
+
/*
|
198 |
+
{metadocument}
|
199 |
+
<variable>
|
200 |
+
<name>debug_prefix</name>
|
201 |
+
<type>STRING</type>
|
202 |
+
<value>OAuth client: </value>
|
203 |
+
<documentation>
|
204 |
+
<purpose>Mark the lines of the debug output to identify actions
|
205 |
+
performed by this class.</purpose>
|
206 |
+
<usage>Change this variable if you prefer the debug output lines to
|
207 |
+
be prefixed with a different text.</usage>
|
208 |
+
</documentation>
|
209 |
+
</variable>
|
210 |
+
{/metadocument}
|
211 |
+
*/
|
212 |
+
var $debug_prefix = 'OAuth client: ';
|
213 |
+
|
214 |
+
/*
|
215 |
+
{metadocument}
|
216 |
+
<variable>
|
217 |
+
<name>server</name>
|
218 |
+
<type>STRING</type>
|
219 |
+
<value></value>
|
220 |
+
<documentation>
|
221 |
+
<purpose>Identify the type of OAuth server to access.</purpose>
|
222 |
+
<usage>The class provides built-in support to several types of OAuth
|
223 |
+
servers. This means that the class can automatically initialize
|
224 |
+
several configuration variables just by setting this server
|
225 |
+
variable.<paragraphbreak />
|
226 |
+
Currently it supports the following servers:
|
227 |
+
<stringvalue>37Signals</stringvalue>,
|
228 |
+
<stringvalue>Amazon</stringvalue>,
|
229 |
+
<stringvalue>AOL</stringvalue>,
|
230 |
+
<stringvalue>Bitbucket</stringvalue>,
|
231 |
+
<stringvalue>Bitly</stringvalue>,
|
232 |
+
<stringvalue>Box</stringvalue>,
|
233 |
+
<stringvalue>Buffer</stringvalue>,
|
234 |
+
<stringvalue>Copy</stringvalue>,
|
235 |
+
<stringvalue>Dailymotion</stringvalue>,
|
236 |
+
<stringvalue>Discogs</stringvalue>,
|
237 |
+
<stringvalue>Disqus</stringvalue>,
|
238 |
+
<stringvalue>Dropbox</stringvalue> (Dropbox with OAuth 1.0),
|
239 |
+
<stringvalue>Dropbox2</stringvalue> (Dropbox with OAuth 2.0),
|
240 |
+
<stringvalue>Etsy</stringvalue>,
|
241 |
+
<stringvalue>Eventful</stringvalue>,
|
242 |
+
<stringvalue>Facebook</stringvalue>,
|
243 |
+
<stringvalue>Fitbit</stringvalue>,
|
244 |
+
<stringvalue>Flickr</stringvalue>,
|
245 |
+
<stringvalue>Foursquare</stringvalue>,
|
246 |
+
<stringvalue>github</stringvalue>,
|
247 |
+
<stringvalue>Google</stringvalue>,
|
248 |
+
<stringvalue>Google1</stringvalue> (Google with OAuth 1.0),
|
249 |
+
<stringvalue>imgur</stringvalue>,
|
250 |
+
<stringvalue>Intuit</stringvalue>,
|
251 |
+
<stringvalue>Instagram</stringvalue>,
|
252 |
+
<stringvalue>Jawbone</stringvalue>,
|
253 |
+
<stringvalue>LinkedIn</stringvalue>,
|
254 |
+
<stringvalue>LinkedIn2</stringvalue> (LinkedIn with OAuth 2.0),
|
255 |
+
<stringvalue>mail.ru</stringvalue>,
|
256 |
+
<stringvalue>MailChimp</stringvalue>,
|
257 |
+
<stringvalue>Mavenlink</stringvalue>,
|
258 |
+
<stringvalue>Meetup</stringvalue>,
|
259 |
+
<stringvalue>Microsoft</stringvalue>,
|
260 |
+
<stringvalue>Misfit</stringvalue>,
|
261 |
+
<stringvalue>oDesk</stringvalue>,
|
262 |
+
<stringvalue>Paypal</stringvalue>,
|
263 |
+
<stringvalue>PaypalApplication</stringvalue>,
|
264 |
+
<stringvalue>Rdio</stringvalue>,
|
265 |
+
<stringvalue>Reddit</stringvalue>,
|
266 |
+
<stringvalue>RunKeeper</stringvalue>,
|
267 |
+
<stringvalue>Salesforce</stringvalue>,
|
268 |
+
<stringvalue>Scoop.it</stringvalue>,
|
269 |
+
<stringvalue>StockTwits</stringvalue>,
|
270 |
+
<stringvalue>SurveyMonkey</stringvalue>,
|
271 |
+
<stringvalue>TeamViewer</stringvalue>,
|
272 |
+
<stringvalue>Tumblr</stringvalue>,
|
273 |
+
<stringvalue>Twitter</stringvalue>,
|
274 |
+
<stringvalue>Vimeo</stringvalue>,
|
275 |
+
<stringvalue>VK</stringvalue>,
|
276 |
+
<stringvalue>Withings</stringvalue>,
|
277 |
+
<stringvalue>Wordpress</stringvalue>,
|
278 |
+
<stringvalue>Xero</stringvalue>,
|
279 |
+
<stringvalue>XING</stringvalue>,
|
280 |
+
<stringvalue>Yahoo</stringvalue> and
|
281 |
+
<stringvalue>Yandex</stringvalue>. Please contact the author if you
|
282 |
+
would like to ask to add built-in support for other types of OAuth
|
283 |
+
servers.<paragraphbreak />
|
284 |
+
If you want to access other types of OAuth servers that are not
|
285 |
+
yet supported, set this variable to an empty string and configure
|
286 |
+
other variables with values specific to those servers.</usage>
|
287 |
+
</documentation>
|
288 |
+
</variable>
|
289 |
+
{/metadocument}
|
290 |
+
*/
|
291 |
+
var $server = '';
|
292 |
+
|
293 |
+
/*
|
294 |
+
{metadocument}
|
295 |
+
<variable>
|
296 |
+
<name>configuration_file</name>
|
297 |
+
<type>STRING</type>
|
298 |
+
<value>oauth_configuration.json</value>
|
299 |
+
<documentation>
|
300 |
+
<purpose>Specify the path of the configuration file that defines the
|
301 |
+
properties of additional OAuth server types.</purpose>
|
302 |
+
<usage>Change the path in this variable if you are accessing a type
|
303 |
+
of server without support built-in the class and you need to put
|
304 |
+
the configuration file path in a different directory.</usage>
|
305 |
+
</documentation>
|
306 |
+
</variable>
|
307 |
+
{/metadocument}
|
308 |
+
*/
|
309 |
+
var $configuration_file = 'oauth_configuration.json';
|
310 |
+
|
311 |
+
/*
|
312 |
+
{metadocument}
|
313 |
+
<variable>
|
314 |
+
<name>request_token_url</name>
|
315 |
+
<type>STRING</type>
|
316 |
+
<value></value>
|
317 |
+
<documentation>
|
318 |
+
<purpose>URL of the OAuth server to request the initial token for
|
319 |
+
OAuth 1.0 and 1.0a servers.</purpose>
|
320 |
+
<usage>Set this variable to the OAuth request token URL when you are
|
321 |
+
not accessing one of the built-in supported OAuth
|
322 |
+
servers.<paragraphbreak />
|
323 |
+
For OAuth 1.0 and 1.0a servers, the request token URL can have
|
324 |
+
certain marks that will act as template placeholders which will be
|
325 |
+
replaced with given values before requesting the authorization
|
326 |
+
token. Currently it supports the following placeholder
|
327 |
+
marks:<paragraphbreak />
|
328 |
+
{SCOPE} - scope of the requested permissions to the granted by the
|
329 |
+
OAuth server with the user permissions</usage>
|
330 |
+
</documentation>
|
331 |
+
</variable>
|
332 |
+
{/metadocument}
|
333 |
+
*/
|
334 |
+
var $request_token_url = '';
|
335 |
+
|
336 |
+
/*
|
337 |
+
{metadocument}
|
338 |
+
<variable>
|
339 |
+
<name>dialog_url</name>
|
340 |
+
<type>STRING</type>
|
341 |
+
<value></value>
|
342 |
+
<documentation>
|
343 |
+
<purpose>URL of the OAuth server to redirect the browser so the user
|
344 |
+
can grant access to your application.</purpose>
|
345 |
+
<usage>Set this variable to the OAuth request token URL when you are
|
346 |
+
not accessing one of the built-in supported OAuth servers.<paragraphbreak />
|
347 |
+
For OAuth 1.0a servers that return the login dialog URL
|
348 |
+
automatically, set this variable to
|
349 |
+
<stringvalue>automatic</stringvalue><paragraphbreak />
|
350 |
+
For certain servers, the dialog URL can have certain marks that
|
351 |
+
will act as template placeholders which will be replaced with
|
352 |
+
values defined before redirecting the users browser. Currently it
|
353 |
+
supports the following placeholder marks:<paragraphbreak />
|
354 |
+
{REDIRECT_URI} - URL to redirect when returning from the OAuth
|
355 |
+
server authorization page<paragraphbreak />
|
356 |
+
{CLIENT_ID} - client application identifier registered at the
|
357 |
+
server<paragraphbreak />
|
358 |
+
{SCOPE} - scope of the requested permissions to the granted by the
|
359 |
+
OAuth server with the user permissions<paragraphbreak />
|
360 |
+
{STATE} - identifier of the OAuth session state<paragraphbreak />
|
361 |
+
{API_KEY} - API key to access the server<paragraphbreak />
|
362 |
+
{REALM} - realm name for OpenID Connect</usage>
|
363 |
+
</documentation>
|
364 |
+
</variable>
|
365 |
+
{/metadocument}
|
366 |
+
*/
|
367 |
+
var $dialog_url = '';
|
368 |
+
|
369 |
+
/*
|
370 |
+
{metadocument}
|
371 |
+
<variable>
|
372 |
+
<name>pin_dialog_url</name>
|
373 |
+
<type>STRING</type>
|
374 |
+
<value></value>
|
375 |
+
<documentation>
|
376 |
+
<purpose>URL of the OAuth server to redirect the browser so the user
|
377 |
+
can grant access to your application.</purpose>
|
378 |
+
<usage>Set this variable when using the pin based authorization and
|
379 |
+
the format of the of the authorization dialog page URL is
|
380 |
+
different than the one set to the
|
381 |
+
<variablelink>dialog_url</variablelink> variable.</usage>
|
382 |
+
</documentation>
|
383 |
+
</variable>
|
384 |
+
{/metadocument}
|
385 |
+
*/
|
386 |
+
var $pin_dialog_url = '';
|
387 |
+
|
388 |
+
/*
|
389 |
+
{metadocument}
|
390 |
+
<variable>
|
391 |
+
<name>offline_dialog_url</name>
|
392 |
+
<type>STRING</type>
|
393 |
+
<value></value>
|
394 |
+
<documentation>
|
395 |
+
<purpose>URL of the OAuth server to redirect the browser so the user
|
396 |
+
can grant access to your application when offline access is
|
397 |
+
requested.</purpose>
|
398 |
+
<usage>Set this variable to the OAuth request token URL when you are
|
399 |
+
not accessing one of the built-in supported OAuth servers and the
|
400 |
+
OAuth server supports offline access.<paragraphbreak />
|
401 |
+
It should have the same format as the
|
402 |
+
<variablelink>dialog_url</variablelink> variable.</usage>
|
403 |
+
</documentation>
|
404 |
+
</variable>
|
405 |
+
{/metadocument}
|
406 |
+
*/
|
407 |
+
var $offline_dialog_url = '';
|
408 |
+
|
409 |
+
/*
|
410 |
+
{metadocument}
|
411 |
+
<variable>
|
412 |
+
<name>pin</name>
|
413 |
+
<type>STRING</type>
|
414 |
+
<value></value>
|
415 |
+
<documentation>
|
416 |
+
<purpose>Value of the pin code for pin based authorization.</purpose>
|
417 |
+
<usage>Set this value to the pin informed by the user when
|
418 |
+
implementing the pin based authorization.<paragraphbreak />
|
419 |
+
Make sure the <variablelink>redirect_uri</variablelink> variable
|
420 |
+
is set to <stringvalue>oob</stringvalue>.</usage>
|
421 |
+
</documentation>
|
422 |
+
</variable>
|
423 |
+
{/metadocument}
|
424 |
+
*/
|
425 |
+
var $pin = '';
|
426 |
+
|
427 |
+
/*
|
428 |
+
{metadocument}
|
429 |
+
<variable>
|
430 |
+
<name>append_state_to_redirect_uri</name>
|
431 |
+
<type>STRING</type>
|
432 |
+
<value></value>
|
433 |
+
<documentation>
|
434 |
+
<purpose>Pass the OAuth session state in a variable with a different
|
435 |
+
name to work around implementation bugs of certain OAuth
|
436 |
+
servers</purpose>
|
437 |
+
<usage>Set this variable when you are not accessing one of the
|
438 |
+
built-in supported OAuth servers if the OAuth server has a bug
|
439 |
+
that makes it not pass back the OAuth state identifier in a
|
440 |
+
request variable named state.</usage>
|
441 |
+
</documentation>
|
442 |
+
</variable>
|
443 |
+
{/metadocument}
|
444 |
+
*/
|
445 |
+
var $append_state_to_redirect_uri = '';
|
446 |
+
|
447 |
+
/*
|
448 |
+
{metadocument}
|
449 |
+
<variable>
|
450 |
+
<name>access_token_url</name>
|
451 |
+
<type>STRING</type>
|
452 |
+
<value></value>
|
453 |
+
<documentation>
|
454 |
+
<purpose>OAuth server URL that will return the access token
|
455 |
+
URL.</purpose>
|
456 |
+
<usage>Set this variable to the OAuth access token URL when you are
|
457 |
+
not accessing one of the built-in supported OAuth servers.</usage>
|
458 |
+
</documentation>
|
459 |
+
</variable>
|
460 |
+
{/metadocument}
|
461 |
+
*/
|
462 |
+
var $access_token_url = '';
|
463 |
+
|
464 |
+
|
465 |
+
/*
|
466 |
+
{metadocument}
|
467 |
+
<variable>
|
468 |
+
<name>oauth_version</name>
|
469 |
+
<type>STRING</type>
|
470 |
+
<value>2.0</value>
|
471 |
+
<documentation>
|
472 |
+
<purpose>Version of the protocol version supported by the OAuth
|
473 |
+
server.</purpose>
|
474 |
+
<usage>Set this variable to the OAuth server protocol version when
|
475 |
+
you are not accessing one of the built-in supported OAuth
|
476 |
+
servers.</usage>
|
477 |
+
</documentation>
|
478 |
+
</variable>
|
479 |
+
{/metadocument}
|
480 |
+
*/
|
481 |
+
var $oauth_version = '2.0';
|
482 |
+
|
483 |
+
/*
|
484 |
+
{metadocument}
|
485 |
+
<variable>
|
486 |
+
<name>url_parameters</name>
|
487 |
+
<type>BOOLEAN</type>
|
488 |
+
<value>0</value>
|
489 |
+
<documentation>
|
490 |
+
<purpose>Determine if the API call parameters should be moved to the
|
491 |
+
call URL.</purpose>
|
492 |
+
<usage>Set this variable to <booleanvalue>1</booleanvalue> if the
|
493 |
+
API you need to call requires that the call parameters always be
|
494 |
+
passed via the API URL.</usage>
|
495 |
+
</documentation>
|
496 |
+
</variable>
|
497 |
+
{/metadocument}
|
498 |
+
*/
|
499 |
+
var $url_parameters = false;
|
500 |
+
|
501 |
+
/*
|
502 |
+
{metadocument}
|
503 |
+
<variable>
|
504 |
+
<name>authorization_header</name>
|
505 |
+
<type>BOOLEAN</type>
|
506 |
+
<value>1</value>
|
507 |
+
<documentation>
|
508 |
+
<purpose>Determine if the OAuth parameters should be passed via HTTP
|
509 |
+
Authorization request header.</purpose>
|
510 |
+
<usage>Set this variable to <booleanvalue>1</booleanvalue> if the
|
511 |
+
OAuth server requires that the OAuth parameters be passed using
|
512 |
+
the HTTP Authorization instead of the request URI parameters.</usage>
|
513 |
+
</documentation>
|
514 |
+
</variable>
|
515 |
+
{/metadocument}
|
516 |
+
*/
|
517 |
+
var $authorization_header = true;
|
518 |
+
|
519 |
+
/*
|
520 |
+
{metadocument}
|
521 |
+
<variable>
|
522 |
+
<name>token_request_method</name>
|
523 |
+
<type>STRING</type>
|
524 |
+
<value>GET</value>
|
525 |
+
<documentation>
|
526 |
+
<purpose>Define the HTTP method that should be used to request
|
527 |
+
tokens from the server.</purpose>
|
528 |
+
<usage>Set this variable to <stringvalue>POST</stringvalue> if the
|
529 |
+
OAuth server does not support requesting tokens using the HTTP GET
|
530 |
+
method.</usage>
|
531 |
+
</documentation>
|
532 |
+
</variable>
|
533 |
+
{/metadocument}
|
534 |
+
*/
|
535 |
+
var $token_request_method = 'GET';
|
536 |
+
|
537 |
+
/*
|
538 |
+
{metadocument}
|
539 |
+
<variable>
|
540 |
+
<name>signature_method</name>
|
541 |
+
<type>STRING</type>
|
542 |
+
<value>HMAC-SHA1</value>
|
543 |
+
<documentation>
|
544 |
+
<purpose>Define the method to generate the signature for API request
|
545 |
+
parameters values.</purpose>
|
546 |
+
<usage>Currently it supports <stringvalue>PLAINTEXT</stringvalue>
|
547 |
+
and <stringvalue>HMAC-SHA1</stringvalue>.</usage>
|
548 |
+
</documentation>
|
549 |
+
</variable>
|
550 |
+
{/metadocument}
|
551 |
+
*/
|
552 |
+
var $signature_method = 'HMAC-SHA1';
|
553 |
+
|
554 |
+
/*
|
555 |
+
{metadocument}
|
556 |
+
<variable>
|
557 |
+
<name>redirect_uri</name>
|
558 |
+
<type>STRING</type>
|
559 |
+
<value></value>
|
560 |
+
<documentation>
|
561 |
+
<purpose>URL of the current script page that is calling this
|
562 |
+
class</purpose>
|
563 |
+
<usage>Set this variable to the current script page URL before
|
564 |
+
proceeding the the OAuth authorization process.<paragraphbreak />
|
565 |
+
For pin based authorization, set this variable to
|
566 |
+
<stringvalue>oob</stringvalue>.</usage>
|
567 |
+
</documentation>
|
568 |
+
</variable>
|
569 |
+
{/metadocument}
|
570 |
+
*/
|
571 |
+
var $redirect_uri = '';
|
572 |
+
|
573 |
+
/*
|
574 |
+
{metadocument}
|
575 |
+
<variable>
|
576 |
+
<name>client_id</name>
|
577 |
+
<type>STRING</type>
|
578 |
+
<value></value>
|
579 |
+
<documentation>
|
580 |
+
<purpose>Identifier of your application registered with the OAuth
|
581 |
+
server</purpose>
|
582 |
+
<usage>Set this variable to the application identifier that is
|
583 |
+
provided by the OAuth server when you register the
|
584 |
+
application.</usage>
|
585 |
+
</documentation>
|
586 |
+
</variable>
|
587 |
+
{/metadocument}
|
588 |
+
*/
|
589 |
+
var $client_id = '';
|
590 |
+
|
591 |
+
/*
|
592 |
+
{metadocument}
|
593 |
+
<variable>
|
594 |
+
<name>client_secret</name>
|
595 |
+
<type>STRING</type>
|
596 |
+
<value></value>
|
597 |
+
<documentation>
|
598 |
+
<purpose>Secret value assigned to your application when it is
|
599 |
+
registered with the OAuth server.</purpose>
|
600 |
+
<usage>Set this variable to the application secret that is provided
|
601 |
+
by the OAuth server when you register the application.</usage>
|
602 |
+
</documentation>
|
603 |
+
</variable>
|
604 |
+
{/metadocument}
|
605 |
+
*/
|
606 |
+
var $client_secret = '';
|
607 |
+
|
608 |
+
/*
|
609 |
+
{metadocument}
|
610 |
+
<variable>
|
611 |
+
<name>api_key</name>
|
612 |
+
<type>STRING</type>
|
613 |
+
<value></value>
|
614 |
+
<documentation>
|
615 |
+
<purpose>Identifier of your API key provided by the OAuth
|
616 |
+
server</purpose>
|
617 |
+
<usage>Set this variable to the API key if the OAuth server requires
|
618 |
+
one.</usage>
|
619 |
+
</documentation>
|
620 |
+
</variable>
|
621 |
+
{/metadocument}
|
622 |
+
*/
|
623 |
+
var $api_key = '';
|
624 |
+
|
625 |
+
/*
|
626 |
+
{metadocument}
|
627 |
+
<variable>
|
628 |
+
<name>get_token_with_api_key</name>
|
629 |
+
<type>BOOLEAN</type>
|
630 |
+
<value>0</value>
|
631 |
+
<documentation>
|
632 |
+
<purpose>Option to determine if the access token should be retrieved
|
633 |
+
using the API key value instead of the client secret.</purpose>
|
634 |
+
<usage>Set this variable to <booleanvalue>1</booleanvalue> if the
|
635 |
+
OAuth server requires that the client secret be set to the API key
|
636 |
+
when retrieving the OAuth token.</usage>
|
637 |
+
</documentation>
|
638 |
+
</variable>
|
639 |
+
{/metadocument}
|
640 |
+
*/
|
641 |
+
var $get_token_with_api_key = false;
|
642 |
+
|
643 |
+
/*
|
644 |
+
{metadocument}
|
645 |
+
<variable>
|
646 |
+
<name>scope</name>
|
647 |
+
<type>STRING</type>
|
648 |
+
<value></value>
|
649 |
+
<documentation>
|
650 |
+
<purpose>Permissions that your application needs to call the OAuth
|
651 |
+
server APIs</purpose>
|
652 |
+
<usage>Check the documentation of the APIs that your application
|
653 |
+
needs to call to set this variable with the identifiers of the
|
654 |
+
permissions that the user needs to grant to your application.</usage>
|
655 |
+
</documentation>
|
656 |
+
</variable>
|
657 |
+
{/metadocument}
|
658 |
+
*/
|
659 |
+
var $scope = '';
|
660 |
+
|
661 |
+
/*
|
662 |
+
{metadocument}
|
663 |
+
<variable>
|
664 |
+
<name>realm</name>
|
665 |
+
<type>STRING</type>
|
666 |
+
<value></value>
|
667 |
+
<documentation>
|
668 |
+
<purpose>Realm of authorization for OpenID Connect</purpose>
|
669 |
+
<usage>Set this variable to the realm value when using OpenID
|
670 |
+
Connect.</usage>
|
671 |
+
</documentation>
|
672 |
+
</variable>
|
673 |
+
{/metadocument}
|
674 |
+
*/
|
675 |
+
var $realm = '';
|
676 |
+
|
677 |
+
/*
|
678 |
+
{metadocument}
|
679 |
+
<variable>
|
680 |
+
<name>offline</name>
|
681 |
+
<type>BOOLEAN</type>
|
682 |
+
<value>0</value>
|
683 |
+
<documentation>
|
684 |
+
<purpose>Specify whether it will be necessary to call the API when
|
685 |
+
the user is not present and the server supports renewing expired
|
686 |
+
access tokens using refresh tokens.</purpose>
|
687 |
+
<usage>Set this variable to <booleanvalue>1</booleanvalue> if the
|
688 |
+
server supports renewing expired tokens automatically when the
|
689 |
+
user is not present.</usage>
|
690 |
+
</documentation>
|
691 |
+
</variable>
|
692 |
+
{/metadocument}
|
693 |
+
*/
|
694 |
+
var $offline = false;
|
695 |
+
|
696 |
+
/*
|
697 |
+
{metadocument}
|
698 |
+
<variable>
|
699 |
+
<name>access_token</name>
|
700 |
+
<type>STRING</type>
|
701 |
+
<value></value>
|
702 |
+
<documentation>
|
703 |
+
<purpose>Access token obtained from the OAuth server</purpose>
|
704 |
+
<usage>Check this variable to get the obtained access token upon
|
705 |
+
successful OAuth authorization.</usage>
|
706 |
+
</documentation>
|
707 |
+
</variable>
|
708 |
+
{/metadocument}
|
709 |
+
*/
|
710 |
+
var $access_token = '';
|
711 |
+
|
712 |
+
/*
|
713 |
+
{metadocument}
|
714 |
+
<variable>
|
715 |
+
<name>access_token_secret</name>
|
716 |
+
<type>STRING</type>
|
717 |
+
<value></value>
|
718 |
+
<documentation>
|
719 |
+
<purpose>Access token secret obtained from the OAuth server</purpose>
|
720 |
+
<usage>If the OAuth protocol version is 1.0 or 1.0a, check this
|
721 |
+
variable to get the obtained access token secret upon successful
|
722 |
+
OAuth authorization.</usage>
|
723 |
+
</documentation>
|
724 |
+
</variable>
|
725 |
+
{/metadocument}
|
726 |
+
*/
|
727 |
+
var $access_token_secret = '';
|
728 |
+
|
729 |
+
/*
|
730 |
+
{metadocument}
|
731 |
+
<variable>
|
732 |
+
<name>access_token_expiry</name>
|
733 |
+
<type>STRING</type>
|
734 |
+
<value></value>
|
735 |
+
<documentation>
|
736 |
+
<purpose>Timestamp of the expiry of the access token obtained from
|
737 |
+
the OAuth server.</purpose>
|
738 |
+
<usage>Check this variable to get the obtained access token expiry
|
739 |
+
time upon successful OAuth authorization. If this variable is
|
740 |
+
empty, that means no expiry time was set.</usage>
|
741 |
+
</documentation>
|
742 |
+
</variable>
|
743 |
+
{/metadocument}
|
744 |
+
*/
|
745 |
+
var $access_token_expiry = '';
|
746 |
+
|
747 |
+
/*
|
748 |
+
{metadocument}
|
749 |
+
<variable>
|
750 |
+
<name>access_token_type</name>
|
751 |
+
<type>STRING</type>
|
752 |
+
<value></value>
|
753 |
+
<documentation>
|
754 |
+
<purpose>Type of access token obtained from the OAuth server.</purpose>
|
755 |
+
<usage>Check this variable to get the obtained access token type
|
756 |
+
upon successful OAuth authorization.</usage>
|
757 |
+
</documentation>
|
758 |
+
</variable>
|
759 |
+
{/metadocument}
|
760 |
+
*/
|
761 |
+
var $access_token_type = '';
|
762 |
+
|
763 |
+
/*
|
764 |
+
{metadocument}
|
765 |
+
<variable>
|
766 |
+
<name>default_access_token_type</name>
|
767 |
+
<type>STRING</type>
|
768 |
+
<value></value>
|
769 |
+
<documentation>
|
770 |
+
<purpose>Type of access token to be assumed when the OAuth server
|
771 |
+
does not specify an access token type.</purpose>
|
772 |
+
<usage>Set this variable if the server requires a certain type of
|
773 |
+
access token to be used but it does not specify a token type
|
774 |
+
when the access token is returned.</usage>
|
775 |
+
</documentation>
|
776 |
+
</variable>
|
777 |
+
{/metadocument}
|
778 |
+
*/
|
779 |
+
var $default_access_token_type = '';
|
780 |
+
|
781 |
+
|
782 |
+
/*
|
783 |
+
{metadocument}
|
784 |
+
<variable>
|
785 |
+
<name>access_token_parameter</name>
|
786 |
+
<type>STRING</type>
|
787 |
+
<value></value>
|
788 |
+
<documentation>
|
789 |
+
<purpose>Name of the access token parameter to be passed in API call
|
790 |
+
requests.</purpose>
|
791 |
+
<usage>Set this variable to a non-empty string to override the
|
792 |
+
default name for the access token parameter which is
|
793 |
+
<stringvalue>oauth_token</stringvalue> of OAuth 1 and
|
794 |
+
<stringvalue>access_token</stringvalue> for OAuth 2.</usage>
|
795 |
+
</documentation>
|
796 |
+
</variable>
|
797 |
+
{/metadocument}
|
798 |
+
*/
|
799 |
+
var $access_token_parameter = '';
|
800 |
+
|
801 |
+
|
802 |
+
/*
|
803 |
+
{metadocument}
|
804 |
+
<variable>
|
805 |
+
<name>access_token_response</name>
|
806 |
+
<type>ARRAY</type>
|
807 |
+
<documentation>
|
808 |
+
<purpose>The original response for the access token request</purpose>
|
809 |
+
<usage>Check this variable if the OAuth server returns custom
|
810 |
+
parameters in the request to obtain the access token.</usage>
|
811 |
+
</documentation>
|
812 |
+
</variable>
|
813 |
+
{/metadocument}
|
814 |
+
*/
|
815 |
+
var $access_token_response;
|
816 |
+
|
817 |
+
/*
|
818 |
+
{metadocument}
|
819 |
+
<variable>
|
820 |
+
<name>store_access_token_response</name>
|
821 |
+
<type>BOOLEAN</type>
|
822 |
+
<value>0</value>
|
823 |
+
<documentation>
|
824 |
+
<purpose>Option to determine if the original response for the access
|
825 |
+
token request should be stored in the
|
826 |
+
<variablelink>access_token_response</variablelink>
|
827 |
+
variable.</purpose>
|
828 |
+
<usage>Set this variable to <booleanvalue>1</booleanvalue> if the
|
829 |
+
OAuth server returns custom parameters in the request to obtain
|
830 |
+
the access token that may be needed in subsequent API calls.</usage>
|
831 |
+
</documentation>
|
832 |
+
</variable>
|
833 |
+
{/metadocument}
|
834 |
+
*/
|
835 |
+
var $store_access_token_response = false;
|
836 |
+
|
837 |
+
/*
|
838 |
+
{metadocument}
|
839 |
+
<variable>
|
840 |
+
<name>access_token_authentication</name>
|
841 |
+
<type>STRING</type>
|
842 |
+
<value></value>
|
843 |
+
<documentation>
|
844 |
+
<purpose>Option to determine if the requests to obtain a new access
|
845 |
+
token should use authentication to pass the application client ID
|
846 |
+
and secret.</purpose>
|
847 |
+
<usage>Set this variable to <stringvalue>basic</stringvalue> if the
|
848 |
+
OAuth server requires that the the client ID and secret be passed
|
849 |
+
using HTTP basic authentication headers when retrieving a new
|
850 |
+
token.</usage>
|
851 |
+
</documentation>
|
852 |
+
</variable>
|
853 |
+
{/metadocument}
|
854 |
+
*/
|
855 |
+
var $access_token_authentication = '';
|
856 |
+
|
857 |
+
/*
|
858 |
+
{metadocument}
|
859 |
+
<variable>
|
860 |
+
<name>refresh_token</name>
|
861 |
+
<type>STRING</type>
|
862 |
+
<value></value>
|
863 |
+
<documentation>
|
864 |
+
<purpose>Refresh token obtained from the OAuth server</purpose>
|
865 |
+
<usage>Check this variable to get the obtained refresh token upon
|
866 |
+
successful OAuth authorization.</usage>
|
867 |
+
</documentation>
|
868 |
+
</variable>
|
869 |
+
{/metadocument}
|
870 |
+
*/
|
871 |
+
var $refresh_token = '';
|
872 |
+
|
873 |
+
/*
|
874 |
+
{metadocument}
|
875 |
+
<variable>
|
876 |
+
<name>access_token_error</name>
|
877 |
+
<type>STRING</type>
|
878 |
+
<value></value>
|
879 |
+
<documentation>
|
880 |
+
<purpose>Error message returned when a call to the API fails.</purpose>
|
881 |
+
<usage>Check this variable to determine if there was an error while
|
882 |
+
calling the Web services API when using the
|
883 |
+
<functionlink>CallAPI</functionlink> function.</usage>
|
884 |
+
</documentation>
|
885 |
+
</variable>
|
886 |
+
{/metadocument}
|
887 |
+
*/
|
888 |
+
var $access_token_error = '';
|
889 |
+
|
890 |
+
/*
|
891 |
+
{metadocument}
|
892 |
+
<variable>
|
893 |
+
<name>authorization_error</name>
|
894 |
+
<type>STRING</type>
|
895 |
+
<value></value>
|
896 |
+
<documentation>
|
897 |
+
<purpose>Error message returned when it was not possible to obtain
|
898 |
+
an OAuth access token</purpose>
|
899 |
+
<usage>Check this variable to determine if there was an error while
|
900 |
+
trying to obtain the OAuth access token.</usage>
|
901 |
+
</documentation>
|
902 |
+
</variable>
|
903 |
+
{/metadocument}
|
904 |
+
*/
|
905 |
+
var $authorization_error = '';
|
906 |
+
|
907 |
+
/*
|
908 |
+
{metadocument}
|
909 |
+
<variable>
|
910 |
+
<name>response_status</name>
|
911 |
+
<type>INTEGER</type>
|
912 |
+
<value>0</value>
|
913 |
+
<documentation>
|
914 |
+
<purpose>HTTP response status returned by the server when calling an
|
915 |
+
API</purpose>
|
916 |
+
<usage>Check this variable after calling the
|
917 |
+
<functionlink>CallAPI</functionlink> function if the API calls and you
|
918 |
+
need to process the error depending the response status.
|
919 |
+
<integervalue>200</integervalue> means no error.
|
920 |
+
<integervalue>0</integervalue> means the server response was not
|
921 |
+
retrieved.</usage>
|
922 |
+
</documentation>
|
923 |
+
</variable>
|
924 |
+
{/metadocument}
|
925 |
+
*/
|
926 |
+
var $response_status = 0;
|
927 |
+
|
928 |
+
/*
|
929 |
+
{metadocument}
|
930 |
+
<variable>
|
931 |
+
<name>oauth_username</name>
|
932 |
+
<type>STRING</type>
|
933 |
+
<value></value>
|
934 |
+
<documentation>
|
935 |
+
<purpose>Define the user name to obtain authorization using a password.</purpose>
|
936 |
+
<usage>Set this variable to the user name of the account to
|
937 |
+
authorize instead of going through the interactive user
|
938 |
+
authorization process.</usage>
|
939 |
+
</documentation>
|
940 |
+
</variable>
|
941 |
+
{/metadocument}
|
942 |
+
*/
|
943 |
+
var $oauth_username = '';
|
944 |
+
|
945 |
+
/*
|
946 |
+
{metadocument}
|
947 |
+
<variable>
|
948 |
+
<name>oauth_password</name>
|
949 |
+
<type>STRING</type>
|
950 |
+
<value></value>
|
951 |
+
<documentation>
|
952 |
+
<purpose>Define the user name to obtain authorization using a password.</purpose>
|
953 |
+
<usage>Set this variable to the user password of the account to
|
954 |
+
authorize instead of going through the interactive user
|
955 |
+
authorization process.</usage>
|
956 |
+
</documentation>
|
957 |
+
</variable>
|
958 |
+
{/metadocument}
|
959 |
+
*/
|
960 |
+
var $oauth_password = '';
|
961 |
+
|
962 |
+
/*
|
963 |
+
{metadocument}
|
964 |
+
<variable>
|
965 |
+
<name>grant_type</name>
|
966 |
+
<type>STRING</type>
|
967 |
+
<value>authorization_code</value>
|
968 |
+
<documentation>
|
969 |
+
<purpose>Define the type of grant to obtain the OAuth 2 access
|
970 |
+
token.</purpose>
|
971 |
+
<usage>Change this variable to
|
972 |
+
<stringvalue>client_credentials</stringvalue> to obtain
|
973 |
+
application only access token.<paragraphbreak />
|
974 |
+
Change this variable to <stringvalue>password</stringvalue> to
|
975 |
+
obtain an access token on behalf of an user with a given username
|
976 |
+
and password specified by the
|
977 |
+
<variablelink>oauth_username</variablelink> and
|
978 |
+
<variablelink>oauth_password</variablelink> variables
|
979 |
+
respectively.<paragraphbreak />In this case the user does not need
|
980 |
+
to be present, so the class will not redirect the user to the
|
981 |
+
authorization dialog page.<paragraphbreak />
|
982 |
+
</usage>
|
983 |
+
</documentation>
|
984 |
+
</variable>
|
985 |
+
{/metadocument}
|
986 |
+
*/
|
987 |
+
var $grant_type = "authorization_code";
|
988 |
+
|
989 |
+
/*
|
990 |
+
{metadocument}
|
991 |
+
<variable>
|
992 |
+
<name>http_arguments</name>
|
993 |
+
<type>HASH</type>
|
994 |
+
<value></value>
|
995 |
+
<documentation>
|
996 |
+
<purpose>Define additional arguments to configure the HTTP
|
997 |
+
requests.</purpose>
|
998 |
+
<usage>Set this associative array with argument values that you need
|
999 |
+
to set options of the HTTP requests sent to the OAuth server and
|
1000 |
+
API URLs.<paragraphbreak />
|
1001 |
+
Check the documentation of the <link>
|
1002 |
+
<data>HTTP client class</data>
|
1003 |
+
<url>http://www.phpclasses.org/httpclient</url>
|
1004 |
+
</link> for more
|
1005 |
+
information on the available arguments that can be configured
|
1006 |
+
using this option.</usage>
|
1007 |
+
</documentation>
|
1008 |
+
</variable>
|
1009 |
+
{/metadocument}
|
1010 |
+
*/
|
1011 |
+
var $http_arguments = array();
|
1012 |
+
var $oauth_user_agent = 'PHP-OAuth-API (http://www.phpclasses.org/oauth-api $Revision: 1.139 $)';
|
1013 |
+
|
1014 |
+
var $response_time = 0;
|
1015 |
+
|
1016 |
+
function __construct() {
|
1017 |
+
$this->configuration_file = dirname(__FILE__) . '/oauth_configuration.json';
|
1018 |
+
}
|
1019 |
+
|
1020 |
+
public static function PHPErrorMessage() {
|
1021 |
+
$lastError = error_get_last();
|
1022 |
+
if ($lastError === null) {
|
1023 |
+
return '';
|
1024 |
+
}
|
1025 |
+
|
1026 |
+
return $lastError['message'];
|
1027 |
+
}
|
1028 |
+
|
1029 |
+
Function SetError($error) {
|
1030 |
+
$this->error = $error;
|
1031 |
+
if ($this->debug) $this->OutputDebug('Error: ' . $error);
|
1032 |
+
|
1033 |
+
return (false);
|
1034 |
+
}
|
1035 |
+
|
1036 |
+
Function SetPHPError($error, $php_error_message) {
|
1037 |
+
if (IsSet($php_error_message) && strlen($php_error_message)) $error .= ": " . $php_error_message;
|
1038 |
+
|
1039 |
+
return ($this->SetError($error));
|
1040 |
+
}
|
1041 |
+
|
1042 |
+
Function OutputDebug($message) {
|
1043 |
+
if ($this->debug) {
|
1044 |
+
$message = $this->debug_prefix . $message;
|
1045 |
+
$this->debug_output .= $message . "\n";
|
1046 |
+
error_log($message);
|
1047 |
+
}
|
1048 |
+
|
1049 |
+
return (true);
|
1050 |
+
}
|
1051 |
+
|
1052 |
+
Function GetRequestTokenURL(&$request_token_url) {
|
1053 |
+
$request_token_url = $this->request_token_url;
|
1054 |
+
|
1055 |
+
return (true);
|
1056 |
+
}
|
1057 |
+
|
1058 |
+
Function GetDialogURL(&$url, $redirect_uri = '', $state = '') {
|
1059 |
+
$url = (($this->offline && strlen($this->offline_dialog_url)) ? $this->offline_dialog_url : (($redirect_uri === 'oob' && strlen($this->pin_dialog_url)) ? $this->pin_dialog_url : $this->dialog_url));
|
1060 |
+
if (strlen($url) === 0) return $this->SetError('the dialog URL ' . ($this->offline ? 'for offline access ' : '') . 'is not defined for this server');
|
1061 |
+
$url = str_replace('{REDIRECT_URI}', UrlEncode($redirect_uri), str_replace('{STATE}', UrlEncode($state), str_replace('{CLIENT_ID}', UrlEncode($this->client_id), str_replace('{API_KEY}', UrlEncode($this->api_key), str_replace('{SCOPE}', UrlEncode($this->scope), str_replace('{REALM}', UrlEncode($this->realm), $url))))));
|
1062 |
+
|
1063 |
+
return (true);
|
1064 |
+
}
|
1065 |
+
|
1066 |
+
Function GetAccessTokenURL(&$access_token_url) {
|
1067 |
+
$access_token_url = str_replace('{API_KEY}', $this->api_key, $this->access_token_url);
|
1068 |
+
|
1069 |
+
return (true);
|
1070 |
+
}
|
1071 |
+
|
1072 |
+
Function GetStoredState(&$state) {
|
1073 |
+
if (!function_exists('session_start')) return $this->SetError('Session variables are not accessible in this PHP environment');
|
1074 |
+
if (session_id() === '' && !session_start()) return ($this->SetPHPError('it was not possible to start the PHP session', self::PHPErrorMessage()));
|
1075 |
+
if (IsSet($_SESSION['OAUTH_STATE'])) $state = $_SESSION['OAUTH_STATE']; else
|
1076 |
+
$state = $_SESSION['OAUTH_STATE'] = time() . '-' . substr(md5(rand() . time()), 0, 6);
|
1077 |
+
|
1078 |
+
return (true);
|
1079 |
+
}
|
1080 |
+
|
1081 |
+
Function GetRequestState(&$state) {
|
1082 |
+
$check = (strlen($this->append_state_to_redirect_uri) ? $this->append_state_to_redirect_uri : 'state');
|
1083 |
+
$state = (IsSet($_GET[$check]) ? $_GET[$check] : null);
|
1084 |
+
|
1085 |
+
return (true);
|
1086 |
+
}
|
1087 |
+
|
1088 |
+
Function GetRequestCode(&$code) {
|
1089 |
+
$code = (IsSet($_GET['code']) ? $_GET['code'] : null);
|
1090 |
+
|
1091 |
+
return (true);
|
1092 |
+
}
|
1093 |
+
|
1094 |
+
Function GetRequestError(&$error) {
|
1095 |
+
$error = (IsSet($_GET['error']) ? $_GET['error'] : null);
|
1096 |
+
|
1097 |
+
return (true);
|
1098 |
+
}
|
1099 |
+
|
1100 |
+
Function GetRequestDenied(&$denied) {
|
1101 |
+
$denied = (IsSet($_GET['denied']) ? $_GET['denied'] : null);
|
1102 |
+
|
1103 |
+
return (true);
|
1104 |
+
}
|
1105 |
+
|
1106 |
+
Function GetRequestToken(&$token, &$verifier) {
|
1107 |
+
$token = (IsSet($_GET['oauth_token']) ? $_GET['oauth_token'] : null);
|
1108 |
+
$verifier = (IsSet($_GET['oauth_verifier']) ? $_GET['oauth_verifier'] : null);
|
1109 |
+
|
1110 |
+
return (true);
|
1111 |
+
}
|
1112 |
+
|
1113 |
+
Function GetRedirectURI(&$redirect_uri) {
|
1114 |
+
if (strlen($this->redirect_uri)) $redirect_uri = $this->redirect_uri; else
|
1115 |
+
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
1116 |
+
|
1117 |
+
return true;
|
1118 |
+
}
|
1119 |
+
|
1120 |
+
/*
|
1121 |
+
{metadocument}
|
1122 |
+
<function>
|
1123 |
+
<name>Redirect</name>
|
1124 |
+
<type>VOID</type>
|
1125 |
+
<documentation>
|
1126 |
+
<purpose>Redirect the user browser to a given page.</purpose>
|
1127 |
+
<usage>This function is meant to be only be called from inside the
|
1128 |
+
class. By default it issues HTTP 302 response status and sets the
|
1129 |
+
redirection location to a given URL. Sub-classes may override this
|
1130 |
+
function to implement a different way to redirect the user
|
1131 |
+
browser.</usage>
|
1132 |
+
</documentation>
|
1133 |
+
<argument>
|
1134 |
+
<name>url</name>
|
1135 |
+
<type>STRING</type>
|
1136 |
+
<documentation>
|
1137 |
+
<purpose>String with the full URL of the page to redirect.</purpose>
|
1138 |
+
</documentation>
|
1139 |
+
</argument>
|
1140 |
+
<do>
|
1141 |
+
{/metadocument}
|
1142 |
+
*/
|
1143 |
+
Function Redirect($url) {
|
1144 |
+
Header('HTTP/1.0 302 OAuth Redirection');
|
1145 |
+
Header('Location: ' . $url);
|
1146 |
+
}
|
1147 |
+
/*
|
1148 |
+
{metadocument}
|
1149 |
+
</do>
|
1150 |
+
</function>
|
1151 |
+
{/metadocument}
|
1152 |
+
*/
|
1153 |
+
|
1154 |
+
/*
|
1155 |
+
{metadocument}
|
1156 |
+
<function>
|
1157 |
+
<name>StoreAccessToken</name>
|
1158 |
+
<type>BOOLEAN</type>
|
1159 |
+
<documentation>
|
1160 |
+
<purpose>Store the values of the access token when it is succefully
|
1161 |
+
retrieved from the OAuth server.</purpose>
|
1162 |
+
<usage>This function is meant to be only be called from inside the
|
1163 |
+
class. By default it stores access tokens in a session variable
|
1164 |
+
named <stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak />
|
1165 |
+
Actual implementations should create a sub-class and override this
|
1166 |
+
function to make the access token values be stored in other types
|
1167 |
+
of containers, like for instance databases.</usage>
|
1168 |
+
<returnvalue>This function should return
|
1169 |
+
<booleanvalue>1</booleanvalue> if the access token was stored
|
1170 |
+
successfully.</returnvalue>
|
1171 |
+
</documentation>
|
1172 |
+
<argument>
|
1173 |
+
<name>access_token</name>
|
1174 |
+
<type>HASH</type>
|
1175 |
+
<documentation>
|
1176 |
+
<purpose>Associative array with properties of the access token.
|
1177 |
+
The array may have set the following
|
1178 |
+
properties:<paragraphbreak />
|
1179 |
+
<stringvalue>value</stringvalue>: string value of the access
|
1180 |
+
token<paragraphbreak />
|
1181 |
+
<stringvalue>authorized</stringvalue>: boolean value that
|
1182 |
+
determines if the access token was obtained
|
1183 |
+
successfully<paragraphbreak />
|
1184 |
+
<stringvalue>expiry</stringvalue>: (optional) timestamp in ISO
|
1185 |
+
format relative to UTC time zone of the access token expiry
|
1186 |
+
time<paragraphbreak />
|
1187 |
+
<stringvalue>type</stringvalue>: (optional) type of OAuth token
|
1188 |
+
that may determine how it should be used when sending API call
|
1189 |
+
requests.<paragraphbreak />
|
1190 |
+
<stringvalue>refresh</stringvalue>: (optional) token that some
|
1191 |
+
servers may set to allowing refreshing access tokens when they
|
1192 |
+
expire.</purpose>
|
1193 |
+
</documentation>
|
1194 |
+
</argument>
|
1195 |
+
<do>
|
1196 |
+
{/metadocument}
|
1197 |
+
*/
|
1198 |
+
Function StoreAccessToken($access_token) {
|
1199 |
+
if (!function_exists('session_start')) return $this->SetError('Session variables are not accessible in this PHP environment');
|
1200 |
+
if (session_id() === '' && !session_start()) return ($this->SetPHPError('it was not possible to start the PHP session', self::PHPErrorMessage()));
|
1201 |
+
if (!$this->GetAccessTokenURL($access_token_url)) return false;
|
1202 |
+
$_SESSION['OAUTH_ACCESS_TOKEN'][$access_token_url] = $access_token;
|
1203 |
+
|
1204 |
+
return true;
|
1205 |
+
}
|
1206 |
+
/*
|
1207 |
+
{metadocument}
|
1208 |
+
</do>
|
1209 |
+
</function>
|
1210 |
+
{/metadocument}
|
1211 |
+
*/
|
1212 |
+
|
1213 |
+
/*
|
1214 |
+
{metadocument}
|
1215 |
+
<function>
|
1216 |
+
<name>GetAccessToken</name>
|
1217 |
+
<type>BOOLEAN</type>
|
1218 |
+
<documentation>
|
1219 |
+
<purpose>Retrieve the OAuth access token if it was already
|
1220 |
+
previously stored by the
|
1221 |
+
<functionlink>StoreAccessToken</functionlink> function.</purpose>
|
1222 |
+
<usage>This function is meant to be only be called from inside the
|
1223 |
+
class. By default it retrieves access tokens stored in a session
|
1224 |
+
variable named
|
1225 |
+
<stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak />
|
1226 |
+
Actual implementations should create a sub-class and override this
|
1227 |
+
function to retrieve the access token values from other types of
|
1228 |
+
containers, like for instance databases.</usage>
|
1229 |
+
<returnvalue>This function should return
|
1230 |
+
<booleanvalue>1</booleanvalue> if the access token was retrieved
|
1231 |
+
successfully.</returnvalue>
|
1232 |
+
</documentation>
|
1233 |
+
<argument>
|
1234 |
+
<name>access_token</name>
|
1235 |
+
<type>STRING</type>
|
1236 |
+
<out />
|
1237 |
+
<documentation>
|
1238 |
+
<purpose>Return the properties of the access token in an
|
1239 |
+
associative array. If the access token was not yet stored, it
|
1240 |
+
returns an empty array. Otherwise, the properties it may return
|
1241 |
+
are the same that may be passed to the
|
1242 |
+
<functionlink>StoreAccessToken</functionlink>.</purpose>
|
1243 |
+
</documentation>
|
1244 |
+
</argument>
|
1245 |
+
<do>
|
1246 |
+
{/metadocument}
|
1247 |
+
*/
|
1248 |
+
Function GetAccessToken(&$access_token) {
|
1249 |
+
if (!function_exists('session_start')) return $this->SetError('Session variables are not accessible in this PHP environment');
|
1250 |
+
if (session_id() === '' && !session_start()) return ($this->SetPHPError('it was not possible to start the PHP session', self::PHPErrorMessage()));
|
1251 |
+
if (!$this->GetAccessTokenURL($access_token_url)) return false;
|
1252 |
+
if (IsSet($_SESSION['OAUTH_ACCESS_TOKEN'][$access_token_url])) $access_token = $_SESSION['OAUTH_ACCESS_TOKEN'][$access_token_url]; else
|
1253 |
+
$access_token = array();
|
1254 |
+
|
1255 |
+
return true;
|
1256 |
+
}
|
1257 |
+
/*
|
1258 |
+
{metadocument}
|
1259 |
+
</do>
|
1260 |
+
</function>
|
1261 |
+
{/metadocument}
|
1262 |
+
*/
|
1263 |
+
|
1264 |
+
/*
|
1265 |
+
{metadocument}
|
1266 |
+
<function>
|
1267 |
+
<name>ResetAccessToken</name>
|
1268 |
+
<type>BOOLEAN</type>
|
1269 |
+
<documentation>
|
1270 |
+
<purpose>Reset the access token to a state back when the user has
|
1271 |
+
not yet authorized the access to the OAuth server API.</purpose>
|
1272 |
+
<usage>Call this function if for some reason the token to access
|
1273 |
+
the API was revoked and you need to ask the user to authorize
|
1274 |
+
the access again.<paragraphbreak />
|
1275 |
+
By default the class stores and retrieves access tokens in a
|
1276 |
+
session variable named
|
1277 |
+
<stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak />
|
1278 |
+
This function must be called when the user is accessing your site
|
1279 |
+
pages, so it can reset the information stored in session variables
|
1280 |
+
that cache the state of a previously retrieved access
|
1281 |
+
token.<paragraphbreak />
|
1282 |
+
Actual implementations should create a sub-class and override this
|
1283 |
+
function to reset the access token state when it is stored in
|
1284 |
+
other types of containers, like for instance databases.</usage>
|
1285 |
+
<returnvalue>This function should return
|
1286 |
+
<booleanvalue>1</booleanvalue> if the access token was resetted
|
1287 |
+
successfully.</returnvalue>
|
1288 |
+
</documentation>
|
1289 |
+
<do>
|
1290 |
+
{/metadocument}
|
1291 |
+
*/
|
1292 |
+
Function ResetAccessToken() {
|
1293 |
+
if (!$this->GetAccessTokenURL($access_token_url)) return false;
|
1294 |
+
if ($this->debug) $this->OutputDebug('Resetting the access token status for OAuth server located at ' . $access_token_url);
|
1295 |
+
if (!function_exists('session_start')) return $this->SetError('Session variables are not accessible in this PHP environment');
|
1296 |
+
if (session_id() === '' && !session_start()) return ($this->SetPHPError('it was not possible to start the PHP session', self::PHPErrorMessage()));
|
1297 |
+
Unset($_SESSION['OAUTH_ACCESS_TOKEN'][$access_token_url]);
|
1298 |
+
UnSet($_SESSION['OAUTH_STATE']);
|
1299 |
+
|
1300 |
+
return true;
|
1301 |
+
}
|
1302 |
+
|
1303 |
+
/*
|
1304 |
+
{metadocument}
|
1305 |
+
</do>
|
1306 |
+
</function>
|
1307 |
+
{/metadocument}
|
1308 |
+
*/
|
1309 |
+
|
1310 |
+
Function Encode($value) {
|
1311 |
+
return (is_array($value) ? $this->EncodeArray($value) : str_replace('%7E', '~', str_replace('+', ' ', RawURLEncode($value))));
|
1312 |
+
}
|
1313 |
+
|
1314 |
+
Function EncodeArray($array) {
|
1315 |
+
foreach ($array as $key => $value) $array[$key] = $this->Encode($value);
|
1316 |
+
|
1317 |
+
return $array;
|
1318 |
+
}
|
1319 |
+
|
1320 |
+
Function HMAC($function, $data, $key) {
|
1321 |
+
switch ($function) {
|
1322 |
+
case 'sha1':
|
1323 |
+
$pack = 'H40';
|
1324 |
+
break;
|
1325 |
+
default:
|
1326 |
+
if ($this->debug) $this->OutputDebug($function . ' is not a supported an HMAC hash type');
|
1327 |
+
|
1328 |
+
return ('');
|
1329 |
+
}
|
1330 |
+
if (strlen($key) > 64) $key = pack($pack, $function($key));
|
1331 |
+
if (strlen($key) < 64) $key = str_pad($key, 64, "\0");
|
1332 |
+
|
1333 |
+
return (pack($pack, $function((str_repeat("\x5c", 64) ^ $key) . pack($pack, $function((str_repeat("\x36", 64) ^ $key) . $data)))));
|
1334 |
+
}
|
1335 |
+
|
1336 |
+
Function Sign(&$url, $method, $parameters, $oauth, $request_content_type, $has_files, $post_values_in_uri, &$authorization, &$post_values) {
|
1337 |
+
$values = array(
|
1338 |
+
'oauth_consumer_key' => $this->client_id,
|
1339 |
+
'oauth_nonce' => md5(uniqid(rand(), true)),
|
1340 |
+
'oauth_signature_method' => $this->signature_method,
|
1341 |
+
'oauth_timestamp' => time(),
|
1342 |
+
'oauth_version' => '1.0',
|
1343 |
+
);
|
1344 |
+
if ($has_files) $value_parameters = array(); else {
|
1345 |
+
if (($this->url_parameters || $method !== 'POST') && $request_content_type === 'application/x-www-form-urlencoded' && count($parameters)) {
|
1346 |
+
$first = (strpos($url, '?') === false);
|
1347 |
+
foreach ($parameters as $parameter => $value) {
|
1348 |
+
$url .= ($first ? '?' : '&') . UrlEncode($parameter) . '=' . UrlEncode($value);
|
1349 |
+
$first = false;
|
1350 |
+
}
|
1351 |
+
$parameters = array();
|
1352 |
+
}
|
1353 |
+
$value_parameters = (($request_content_type !== 'application/x-www-form-urlencoded') ? array() : $parameters);
|
1354 |
+
}
|
1355 |
+
$header_values = ($method === 'GET' ? array_merge($values, $oauth, $value_parameters) : array_merge($values, $oauth));
|
1356 |
+
$values = array_merge($values, $oauth, $value_parameters);
|
1357 |
+
$key = $this->Encode($this->client_secret) . '&' . $this->Encode($this->access_token_secret);
|
1358 |
+
switch ($this->signature_method) {
|
1359 |
+
case 'PLAINTEXT':
|
1360 |
+
$values['oauth_signature'] = $key;
|
1361 |
+
break;
|
1362 |
+
case 'HMAC-SHA1':
|
1363 |
+
$uri = strtok($url, '?');
|
1364 |
+
$sign = $method . '&' . $this->Encode($uri) . '&';
|
1365 |
+
$first = true;
|
1366 |
+
$sign_values = $values;
|
1367 |
+
$u = parse_url($url);
|
1368 |
+
if (IsSet($u['query'])) {
|
1369 |
+
parse_str($u['query'], $q);
|
1370 |
+
foreach ($q as $parameter => $value) $sign_values[$parameter] = $value;
|
1371 |
+
}
|
1372 |
+
KSort($sign_values);
|
1373 |
+
foreach ($sign_values as $parameter => $value) {
|
1374 |
+
$sign .= $this->Encode(($first ? '' : '&') . $parameter . '=' . $this->Encode($value));
|
1375 |
+
$first = false;
|
1376 |
+
}
|
1377 |
+
$header_values['oauth_signature'] = $values['oauth_signature'] = Base64::encode($this->HMAC('sha1', $sign, $key));
|
1378 |
+
break;
|
1379 |
+
default:
|
1380 |
+
return $this->SetError($this->signature_method . ' signature method is not yet supported');
|
1381 |
+
}
|
1382 |
+
if ($this->authorization_header) {
|
1383 |
+
$authorization = 'OAuth';
|
1384 |
+
$first = true;
|
1385 |
+
foreach ($header_values as $parameter => $value) {
|
1386 |
+
$authorization .= ($first ? ' ' : ',') . $parameter . '="' . $this->Encode($value) . '"';
|
1387 |
+
$first = false;
|
1388 |
+
}
|
1389 |
+
$post_values = $parameters;
|
1390 |
+
} else {
|
1391 |
+
if ($method !== 'POST' || $post_values_in_uri) {
|
1392 |
+
$first = (strcspn($url, '?') == strlen($url));
|
1393 |
+
foreach ($values as $parameter => $value) {
|
1394 |
+
$url .= ($first ? '?' : '&') . $parameter . '=' . $this->Encode($value);
|
1395 |
+
$first = false;
|
1396 |
+
}
|
1397 |
+
$post_values = array();
|
1398 |
+
} else
|
1399 |
+
$post_values = $values;
|
1400 |
+
}
|
1401 |
+
|
1402 |
+
return true;
|
1403 |
+
}
|
1404 |
+
|
1405 |
+
Function SendAPIRequest($url, $method, $parameters, $oauth, $options, &$response) {
|
1406 |
+
$this->response_status = 0;
|
1407 |
+
$http = new HTTP();
|
1408 |
+
$http->debug = ($this->debug && $this->debug_http);
|
1409 |
+
$http->log_debug = true;
|
1410 |
+
$http->sasl_authenticate = 0;
|
1411 |
+
$http->user_agent = $this->oauth_user_agent;
|
1412 |
+
$http->redirection_limit = (IsSet($options['FollowRedirection']) ? intval($options['FollowRedirection']) : 0);
|
1413 |
+
$http->follow_redirect = ($http->redirection_limit != 0);
|
1414 |
+
if ($this->debug) $this->OutputDebug('Accessing the ' . $options['Resource'] . ' at ' . $url);
|
1415 |
+
$post_files = array();
|
1416 |
+
$method = strtoupper($method);
|
1417 |
+
$authorization = '';
|
1418 |
+
$request_content_type = (IsSet($options['RequestContentType']) ? strtolower(trim(strtok($options['RequestContentType'], ';'))) : (($method === 'POST' || IsSet($oauth)) ? 'application/x-www-form-urlencoded' : ''));
|
1419 |
+
$files = (IsSet($options['Files']) ? $options['Files'] : array());
|
1420 |
+
if (count($files)) {
|
1421 |
+
foreach ($files as $name => $value) {
|
1422 |
+
if (!IsSet($parameters[$name])) return ($this->SetError('it was not specified a file parameter named ' . $name));
|
1423 |
+
$file = array();
|
1424 |
+
$value_type = IsSet($value['Type']) ? $value['Type'] : 'FileName';
|
1425 |
+
switch ($value_type) {
|
1426 |
+
case 'FileName':
|
1427 |
+
$file['FileName'] = $parameters[$name];
|
1428 |
+
if (IsSet($value['FileName'])) $file['Name'] = $value['FileName'];
|
1429 |
+
break;
|
1430 |
+
case 'Data':
|
1431 |
+
$file['Data'] = $parameters[$name];
|
1432 |
+
if (!IsSet($value['FileName'])) return ($this->SetError('it was not specified the file name for data file parameter ' . $name));
|
1433 |
+
$file['Name'] = $value['FileName'];
|
1434 |
+
break;
|
1435 |
+
default:
|
1436 |
+
return ($this->SetError($value_type . ' is not a valid type for file ' . $name));
|
1437 |
+
}
|
1438 |
+
$file['Content-Type'] = (IsSet($value['ContentType']) ? $value['ContentType'] : 'automatic/name');
|
1439 |
+
$post_files[$name] = $file;
|
1440 |
+
}
|
1441 |
+
UnSet($parameters[$name]);
|
1442 |
+
if ($method !== 'POST') {
|
1443 |
+
$this->OutputDebug('For uploading files the method should be POST not ' . $method);
|
1444 |
+
$method = 'POST';
|
1445 |
+
}
|
1446 |
+
if ($request_content_type !== 'multipart/form-data') {
|
1447 |
+
if (IsSet($options['RequestContentType'])) return ($this->SetError('the request content type for uploading files should be multipart/form-data'));
|
1448 |
+
$request_content_type = 'multipart/form-data';
|
1449 |
+
}
|
1450 |
+
}
|
1451 |
+
if (IsSet($oauth)) {
|
1452 |
+
if (!$this->Sign($url, $method, $parameters, $oauth, $request_content_type, count($files) !== 0, IsSet($options['PostValuesInURI']) && $options['PostValuesInURI'], $authorization, $post_values)) return false;
|
1453 |
+
} else {
|
1454 |
+
$post_values = $parameters;
|
1455 |
+
if (count($parameters)) {
|
1456 |
+
switch ($request_content_type) {
|
1457 |
+
case 'application/x-www-form-urlencoded':
|
1458 |
+
case 'multipart/form-data':
|
1459 |
+
case 'application/json':
|
1460 |
+
case 'application/javascript':
|
1461 |
+
break;
|
1462 |
+
default:
|
1463 |
+
$first = (strpos($url, '?') === false);
|
1464 |
+
foreach ($parameters as $name => $value) {
|
1465 |
+
if (GetType($value) === 'array') {
|
1466 |
+
foreach ($value as $index => $data) {
|
1467 |
+
$url .= ($first ? '?' : '&') . $name . '=' . UrlEncode($data);
|
1468 |
+
$first = false;
|
1469 |
+
}
|
1470 |
+
} else {
|
1471 |
+
$url .= ($first ? '?' : '&') . $name . '=' . UrlEncode($value);
|
1472 |
+
$first = false;
|
1473 |
+
}
|
1474 |
+
}
|
1475 |
+
}
|
1476 |
+
}
|
1477 |
+
}
|
1478 |
+
if (strlen($authorization) === 0 && !strcasecmp($this->access_token_type, 'Bearer')) $authorization = 'Bearer ' . $this->access_token;
|
1479 |
+
if (strlen($error = $http->GetRequestArguments($url, $arguments))) return ($this->SetError('it was not possible to open the ' . $options['Resource'] . ' URL: ' . $error));
|
1480 |
+
$arguments = array_merge($this->http_arguments, $arguments);
|
1481 |
+
if (strlen($error = $http->Open($arguments))) return ($this->SetError('it was not possible to open the ' . $options['Resource'] . ' URL: ' . $error));
|
1482 |
+
if (count($post_files)) $arguments['PostFiles'] = $post_files;
|
1483 |
+
$arguments['RequestMethod'] = $method;
|
1484 |
+
switch ($request_content_type) {
|
1485 |
+
case 'application/x-www-form-urlencoded':
|
1486 |
+
case 'multipart/form-data':
|
1487 |
+
if (IsSet($options['RequestBody'])) return ($this->SetError('the request body is defined automatically from the parameters'));
|
1488 |
+
$arguments['PostValues'] = $post_values;
|
1489 |
+
break;
|
1490 |
+
case 'application/json':
|
1491 |
+
case 'application/javascript':
|
1492 |
+
$arguments['Headers']['Content-Type'] = $options['RequestContentType'];
|
1493 |
+
$arguments['Body'] = (IsSet($options['RequestBody']) ? $options['RequestBody'] : json_encode($parameters));
|
1494 |
+
break;
|
1495 |
+
default:
|
1496 |
+
if (!IsSet($options['RequestBody'])) {
|
1497 |
+
if (IsSet($options['RequestContentType'])) return ($this->SetError('it was not specified the body value of the of the API call request'));
|
1498 |
+
break;
|
1499 |
+
}
|
1500 |
+
$arguments['Headers']['Content-Type'] = $options['RequestContentType'];
|
1501 |
+
$arguments['Body'] = $options['RequestBody'];
|
1502 |
+
break;
|
1503 |
+
}
|
1504 |
+
$arguments['Headers']['Accept'] = (IsSet($options['Accept']) ? $options['Accept'] : '*/*');
|
1505 |
+
switch ($authentication = (IsSet($options['AccessTokenAuthentication']) ? strtolower($options['AccessTokenAuthentication']) : '')) {
|
1506 |
+
case 'basic':
|
1507 |
+
$arguments['Headers']['Authorization'] = 'Basic ' . Base64::encode($this->client_id . ':' . ($this->get_token_with_api_key ? $this->api_key : $this->client_secret));
|
1508 |
+
break;
|
1509 |
+
case '':
|
1510 |
+
if (strlen($authorization)) $arguments['Headers']['Authorization'] = $authorization;
|
1511 |
+
break;
|
1512 |
+
default:
|
1513 |
+
return ($this->SetError($authentication . ' is not a supported authentication mechanism to retrieve an access token'));
|
1514 |
+
}
|
1515 |
+
if (IsSet($options['RequestHeaders'])) $arguments['Headers'] = array_merge($arguments['Headers'], $options['RequestHeaders']);
|
1516 |
+
if (strlen($error = $http->SendRequest($arguments)) || strlen($error = $http->ReadReplyHeaders($headers))) {
|
1517 |
+
$http->Close();
|
1518 |
+
|
1519 |
+
return ($this->SetError('it was not possible to retrieve the ' . $options['Resource'] . ': ' . $error));
|
1520 |
+
}
|
1521 |
+
$error = $http->ReadWholeReplyBody($data);
|
1522 |
+
$http->Close();
|
1523 |
+
if (strlen($error)) {
|
1524 |
+
return ($this->SetError('it was not possible to access the ' . $options['Resource'] . ': ' . $error));
|
1525 |
+
}
|
1526 |
+
$this->response_status = intval($http->response_status);
|
1527 |
+
$content_type = (IsSet($options['ResponseContentType']) ? $options['ResponseContentType'] : (IsSet($headers['content-type']) ? strtolower(trim(strtok($headers['content-type'], ';'))) : 'unspecified'));
|
1528 |
+
$content_type = preg_replace('/^(.+\\/).+\\+(.+)$/', '\\1\\2', $content_type);
|
1529 |
+
$this->response_time = (IsSet($headers['date']) ? strtotime(GetType($headers['date']) === 'array' ? $headers['date'][0] : $headers['date']) : time());
|
1530 |
+
switch ($content_type) {
|
1531 |
+
case 'text/javascript':
|
1532 |
+
case 'application/json':
|
1533 |
+
case 'application/javascript':
|
1534 |
+
if (!function_exists('json_decode')) return ($this->SetError('the JSON extension is not available in this PHP setup'));
|
1535 |
+
$object = json_decode($data);
|
1536 |
+
switch (GetType($object)) {
|
1537 |
+
case 'object':
|
1538 |
+
if (!IsSet($options['ConvertObjects']) || !$options['ConvertObjects']) $response = $object; else {
|
1539 |
+
$response = array();
|
1540 |
+
foreach ($object as $property => $value) $response[$property] = $value;
|
1541 |
+
}
|
1542 |
+
break;
|
1543 |
+
case 'array':
|
1544 |
+
$response = $object;
|
1545 |
+
break;
|
1546 |
+
default:
|
1547 |
+
if (!IsSet($object)) return ($this->SetError('it was not returned a valid JSON definition of the ' . $options['Resource'] . ' values'));
|
1548 |
+
$response = $object;
|
1549 |
+
break;
|
1550 |
+
}
|
1551 |
+
break;
|
1552 |
+
case 'application/x-www-form-urlencoded':
|
1553 |
+
case 'text/plain':
|
1554 |
+
case 'text/html':
|
1555 |
+
parse_str($data, $response);
|
1556 |
+
break;
|
1557 |
+
case 'text/xml':
|
1558 |
+
if (IsSet($options['DecodeXMLResponse'])) {
|
1559 |
+
switch (strtolower($options['DecodeXMLResponse'])) {
|
1560 |
+
case 'simplexml':
|
1561 |
+
if ($this->debug) $this->OutputDebug('Decoding XML response with simplexml');
|
1562 |
+
try {
|
1563 |
+
$response = @new \SimpleXMLElement($data);
|
1564 |
+
} catch (\Exception $exception) {
|
1565 |
+
return $this->SetError('Could not parse XML response: ' . $exception->getMessage());
|
1566 |
+
}
|
1567 |
+
break 2;
|
1568 |
+
default:
|
1569 |
+
return $this->SetError($options['DecodeXML'] . ' is not a supported method to decode XML responses');
|
1570 |
+
}
|
1571 |
+
}
|
1572 |
+
default:
|
1573 |
+
$response = $data;
|
1574 |
+
break;
|
1575 |
+
}
|
1576 |
+
if ($this->response_status >= 200 && $this->response_status < 300) $this->access_token_error = ''; else {
|
1577 |
+
$this->access_token_error = 'it was not possible to access the ' . $options['Resource'] . ': it was returned an unexpected response status ' . $http->response_status . ' Response: ' . $data;
|
1578 |
+
if ($this->debug) $this->OutputDebug('Could not retrieve the OAuth access token. Error: ' . $this->access_token_error);
|
1579 |
+
if (IsSet($options['FailOnAccessError']) && $options['FailOnAccessError']) {
|
1580 |
+
$this->error = $this->access_token_error;
|
1581 |
+
|
1582 |
+
return false;
|
1583 |
+
}
|
1584 |
+
}
|
1585 |
+
|
1586 |
+
return true;
|
1587 |
+
}
|
1588 |
+
|
1589 |
+
Function ProcessToken1($oauth, &$access_token) {
|
1590 |
+
if (!$this->GetAccessTokenURL($url)) return false;
|
1591 |
+
$options = array('Resource' => 'OAuth access token');
|
1592 |
+
$method = strtoupper($this->token_request_method);
|
1593 |
+
switch ($method) {
|
1594 |
+
case 'GET':
|
1595 |
+
break;
|
1596 |
+
case 'POST':
|
1597 |
+
$options['PostValuesInURI'] = true;
|
1598 |
+
break;
|
1599 |
+
default:
|
1600 |
+
$this->error = $method . ' is not a supported method to request tokens';
|
1601 |
+
|
1602 |
+
return false;
|
1603 |
+
}
|
1604 |
+
if (!$this->SendAPIRequest($url, $method, array(), $oauth, $options, $response)) return false;
|
1605 |
+
if (strlen($this->access_token_error)) {
|
1606 |
+
$this->authorization_error = $this->access_token_error;
|
1607 |
+
|
1608 |
+
return true;
|
1609 |
+
}
|
1610 |
+
if (!IsSet($response['oauth_token']) || !IsSet($response['oauth_token_secret'])) {
|
1611 |
+
$this->authorization_error = 'it was not returned the access token and secret';
|
1612 |
+
|
1613 |
+
return true;
|
1614 |
+
}
|
1615 |
+
$access_token = array(
|
1616 |
+
'value' => $response['oauth_token'],
|
1617 |
+
'secret' => $response['oauth_token_secret'],
|
1618 |
+
'authorized' => true
|
1619 |
+
);
|
1620 |
+
if (IsSet($response['oauth_expires_in']) && $response['oauth_expires_in'] == 0) {
|
1621 |
+
if ($this->debug) $this->OutputDebug('Ignoring access token expiry set to 0');
|
1622 |
+
$this->access_token_expiry = '';
|
1623 |
+
} elseif (IsSet($response['oauth_expires_in'])) {
|
1624 |
+
$expires = $response['oauth_expires_in'];
|
1625 |
+
if (strval($expires) !== strval(intval($expires)) || $expires <= 0) return ($this->SetError('OAuth server did not return a supported type of access token expiry time'));
|
1626 |
+
$this->access_token_expiry = gmstrftime('%Y-%m-%d %H:%M:%S', $this->response_time + $expires);
|
1627 |
+
if ($this->debug) $this->OutputDebug('Access token expiry: ' . $this->access_token_expiry . ' UTC');
|
1628 |
+
$access_token['expiry'] = $this->access_token_expiry;
|
1629 |
+
} else
|
1630 |
+
$this->access_token_expiry = '';
|
1631 |
+
if (IsSet($response['oauth_session_handle'])) {
|
1632 |
+
$access_token['refresh'] = $response['oauth_session_handle'];
|
1633 |
+
if ($this->debug) $this->OutputDebug('Refresh token: ' . $access_token['refresh']);
|
1634 |
+
}
|
1635 |
+
|
1636 |
+
return $this->StoreAccessToken($access_token);
|
1637 |
+
}
|
1638 |
+
|
1639 |
+
Function ProcessToken2($code, $refresh) {
|
1640 |
+
if (!$this->GetRedirectURI($redirect_uri)) return false;
|
1641 |
+
$authentication = $this->access_token_authentication;
|
1642 |
+
if (strlen($this->oauth_username)) {
|
1643 |
+
$values = array(
|
1644 |
+
'grant_type' => 'password',
|
1645 |
+
'username' => $this->oauth_username,
|
1646 |
+
'password' => $this->oauth_password,
|
1647 |
+
'redirect_uri' => $redirect_uri
|
1648 |
+
);
|
1649 |
+
$authentication = 'Basic';
|
1650 |
+
} elseif ($this->redirect_uri === 'oob' && strlen($this->pin)) {
|
1651 |
+
$values = array(
|
1652 |
+
'grant_type' => 'pin',
|
1653 |
+
'pin' => $this->pin,
|
1654 |
+
'scope' => $this->scope,
|
1655 |
+
);
|
1656 |
+
} elseif ($refresh) {
|
1657 |
+
$values = array(
|
1658 |
+
'refresh_token' => $this->refresh_token,
|
1659 |
+
'grant_type' => 'refresh_token',
|
1660 |
+
'scope' => $this->scope,
|
1661 |
+
);
|
1662 |
+
} else {
|
1663 |
+
switch ($this->grant_type) {
|
1664 |
+
case 'password':
|
1665 |
+
return $this->SetError('it was not specified the username for obtaining a password based OAuth 2 authorization');
|
1666 |
+
case 'authorization_code':
|
1667 |
+
$values = array(
|
1668 |
+
'code' => $code,
|
1669 |
+
'redirect_uri' => $redirect_uri,
|
1670 |
+
'grant_type' => 'authorization_code'
|
1671 |
+
);
|
1672 |
+
$authentication = $this->access_token_authentication;
|
1673 |
+
break;
|
1674 |
+
case 'client_credentials':
|
1675 |
+
$values = array(
|
1676 |
+
'grant_type' => 'client_credentials'
|
1677 |
+
);
|
1678 |
+
$authentication = 'Basic';
|
1679 |
+
break;
|
1680 |
+
default:
|
1681 |
+
return $this->SetError($this->grant_type . ' is not yet a supported OAuth 2 grant type');
|
1682 |
+
}
|
1683 |
+
}
|
1684 |
+
$options = array(
|
1685 |
+
'Resource' => 'OAuth ' . ($refresh ? 'refresh' : 'access') . ' token',
|
1686 |
+
'ConvertObjects' => true
|
1687 |
+
);
|
1688 |
+
switch (strtolower($authentication)) {
|
1689 |
+
case 'basic':
|
1690 |
+
$options['AccessTokenAuthentication'] = $authentication;
|
1691 |
+
break;
|
1692 |
+
case '':
|
1693 |
+
$values['client_id'] = $this->client_id;
|
1694 |
+
$values['client_secret'] = ($this->get_token_with_api_key ? $this->api_key : $this->client_secret);
|
1695 |
+
break;
|
1696 |
+
default:
|
1697 |
+
return ($this->SetError($authentication . ' is not a supported authentication mechanism to retrieve an access token'));
|
1698 |
+
}
|
1699 |
+
if (!$this->GetAccessTokenURL($access_token_url)) return false;
|
1700 |
+
if (!$this->SendAPIRequest($access_token_url, 'POST', $values, null, $options, $response)) return false;
|
1701 |
+
if (strlen($this->access_token_error)) {
|
1702 |
+
$this->authorization_error = $this->access_token_error;
|
1703 |
+
|
1704 |
+
return true;
|
1705 |
+
}
|
1706 |
+
if (!IsSet($response['access_token'])) {
|
1707 |
+
if (IsSet($response['error'])) {
|
1708 |
+
$this->authorization_error = 'it was not possible to retrieve the access token: it was returned the error: ' . $response['error'];
|
1709 |
+
|
1710 |
+
return true;
|
1711 |
+
}
|
1712 |
+
|
1713 |
+
return ($this->SetError('OAuth server did not return the access token'));
|
1714 |
+
}
|
1715 |
+
$access_token = array(
|
1716 |
+
'value' => ($this->access_token = $response['access_token']),
|
1717 |
+
'authorized' => true,
|
1718 |
+
);
|
1719 |
+
if ($this->store_access_token_response) $access_token['response'] = $this->access_token_response = $response;
|
1720 |
+
if ($this->debug) $this->OutputDebug('Access token: ' . $this->access_token);
|
1721 |
+
if (IsSet($response['expires_in']) && $response['expires_in'] == 0) {
|
1722 |
+
if ($this->debug) $this->OutputDebug('Ignoring access token expiry set to 0');
|
1723 |
+
$this->access_token_expiry = '';
|
1724 |
+
} elseif (IsSet($response['expires']) || IsSet($response['expires_in'])) {
|
1725 |
+
$expires = (IsSet($response['expires_in']) ? $response['expires_in'] : $response['expires'] - ($response['expires'] > $this->response_time ? $this->response_time : 0));
|
1726 |
+
if (strval($expires) !== strval(intval($expires)) || $expires <= 0) return ($this->SetError('OAuth server did not return a supported type of access token expiry time'));
|
1727 |
+
$this->access_token_expiry = gmstrftime('%Y-%m-%d %H:%M:%S', $this->response_time + $expires);
|
1728 |
+
if ($this->debug) $this->OutputDebug('Access token expiry: ' . $this->access_token_expiry . ' UTC');
|
1729 |
+
$access_token['expiry'] = $this->access_token_expiry;
|
1730 |
+
} else
|
1731 |
+
$this->access_token_expiry = '';
|
1732 |
+
if (IsSet($response['token_type'])) {
|
1733 |
+
$this->access_token_type = $response['token_type'];
|
1734 |
+
if (strlen($this->access_token_type) && $this->debug) $this->OutputDebug('Access token type: ' . $this->access_token_type);
|
1735 |
+
$access_token['type'] = $this->access_token_type;
|
1736 |
+
} else {
|
1737 |
+
$this->access_token_type = $this->default_access_token_type;
|
1738 |
+
if (strlen($this->access_token_type) && $this->debug) $this->OutputDebug('Assumed the default for OAuth access token type which is ' . $this->access_token_type);
|
1739 |
+
}
|
1740 |
+
if (IsSet($response['refresh_token'])) {
|
1741 |
+
$this->refresh_token = $response['refresh_token'];
|
1742 |
+
if ($this->debug) $this->OutputDebug('Refresh token: ' . $this->refresh_token);
|
1743 |
+
$access_token['refresh'] = $this->refresh_token;
|
1744 |
+
} elseif (strlen($this->refresh_token)) {
|
1745 |
+
if ($this->debug) $this->OutputDebug('Reusing previous refresh token: ' . $this->refresh_token);
|
1746 |
+
$access_token['refresh'] = $this->refresh_token;
|
1747 |
+
}
|
1748 |
+
|
1749 |
+
return $this->StoreAccessToken($access_token);
|
1750 |
+
}
|
1751 |
+
|
1752 |
+
Function RetrieveToken(&$valid) {
|
1753 |
+
$valid = false;
|
1754 |
+
if (!$this->GetAccessToken($access_token)) return false;
|
1755 |
+
if (IsSet($access_token['value'])) {
|
1756 |
+
$this->access_token_expiry = '';
|
1757 |
+
$expired = (IsSet($access_token['expiry']) && strcmp($this->access_token_expiry = $access_token['expiry'], gmstrftime('%Y-%m-%d %H:%M:%S')) < 0);
|
1758 |
+
if ($expired) {
|
1759 |
+
if ($this->debug) $this->OutputDebug('The OAuth access token expired on ' . $this->access_token_expiry . ' UTC');
|
1760 |
+
}
|
1761 |
+
$this->access_token = $access_token['value'];
|
1762 |
+
if (!$expired && $this->debug) $this->OutputDebug('The OAuth access token ' . $this->access_token . ' is valid');
|
1763 |
+
if (IsSet($access_token['type'])) {
|
1764 |
+
$this->access_token_type = $access_token['type'];
|
1765 |
+
if (strlen($this->access_token_type) && !$expired && $this->debug) $this->OutputDebug('The OAuth access token is of type ' . $this->access_token_type);
|
1766 |
+
} else {
|
1767 |
+
$this->access_token_type = $this->default_access_token_type;
|
1768 |
+
if (strlen($this->access_token_type) && !$expired && $this->debug) $this->OutputDebug('Assumed the default for OAuth access token type which is ' . $this->access_token_type);
|
1769 |
+
}
|
1770 |
+
if (IsSet($access_token['secret'])) {
|
1771 |
+
$this->access_token_secret = $access_token['secret'];
|
1772 |
+
if ($this->debug && !$expired && strlen($this->access_token_secret)) $this->OutputDebug('The OAuth access token secret is ' . $this->access_token_secret);
|
1773 |
+
}
|
1774 |
+
if (IsSet($access_token['refresh'])) $this->refresh_token = $access_token['refresh']; else
|
1775 |
+
$this->refresh_token = '';
|
1776 |
+
$this->access_token_response = (($this->store_access_token_response && IsSet($access_token['response'])) ? $access_token['response'] : null);
|
1777 |
+
$valid = true;
|
1778 |
+
}
|
1779 |
+
|
1780 |
+
return true;
|
1781 |
+
}
|
1782 |
+
|
1783 |
+
/*
|
1784 |
+
{metadocument}
|
1785 |
+
<function>
|
1786 |
+
<name>CallAPI</name>
|
1787 |
+
<type>BOOLEAN</type>
|
1788 |
+
<documentation>
|
1789 |
+
<purpose>Send a HTTP request to the Web services API using a
|
1790 |
+
previously obtained authorization token via OAuth.</purpose>
|
1791 |
+
<usage>This function can be used to call an API after having
|
1792 |
+
previously obtained an access token through the OAuth protocol
|
1793 |
+
using the <functionlink>Process</functionlink> function, or by
|
1794 |
+
directly setting the variables
|
1795 |
+
<variablelink>access_token</variablelink>, as well as
|
1796 |
+
<variablelink>access_token_secret</variablelink> in case of using
|
1797 |
+
OAuth 1.0 or 1.0a services.</usage>
|
1798 |
+
<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
|
1799 |
+
the call was done successfully.</returnvalue>
|
1800 |
+
</documentation>
|
1801 |
+
<argument>
|
1802 |
+
<name>url</name>
|
1803 |
+
<type>STRING</type>
|
1804 |
+
<documentation>
|
1805 |
+
<purpose>URL of the API where the HTTP request will be sent.</purpose>
|
1806 |
+
</documentation>
|
1807 |
+
</argument>
|
1808 |
+
<argument>
|
1809 |
+
<name>method</name>
|
1810 |
+
<type>STRING</type>
|
1811 |
+
<documentation>
|
1812 |
+
<purpose>HTTP method that will be used to send the request. It can
|
1813 |
+
be <stringvalue>GET</stringvalue>,
|
1814 |
+
<stringvalue>POST</stringvalue>,
|
1815 |
+
<stringvalue>DELETE</stringvalue>, <stringvalue>PUT</stringvalue>,
|
1816 |
+
etc..</purpose>
|
1817 |
+
</documentation>
|
1818 |
+
</argument>
|
1819 |
+
<argument>
|
1820 |
+
<name>parameters</name>
|
1821 |
+
<type>HASH</type>
|
1822 |
+
<documentation>
|
1823 |
+
<purpose>Associative array with the names and values of the API
|
1824 |
+
call request parameters.</purpose>
|
1825 |
+
</documentation>
|
1826 |
+
</argument>
|
1827 |
+
<argument>
|
1828 |
+
<name>options</name>
|
1829 |
+
<type>HASH</type>
|
1830 |
+
<documentation>
|
1831 |
+
<purpose>Associative array with additional options to configure
|
1832 |
+
the request. Currently it supports the following
|
1833 |
+
options:<paragraphbreak />
|
1834 |
+
<stringvalue>2Legged</stringvalue>: boolean option that
|
1835 |
+
determines if the API request should be 2 legged. The default
|
1836 |
+
value is <tt><booleanvalue>0</booleanvalue></tt>.<paragraphbreak />
|
1837 |
+
<stringvalue>Accept</stringvalue>: content type value of the
|
1838 |
+
Accept HTTP header to be sent in the API call HTTP request.
|
1839 |
+
Some APIs require that a certain value be sent to specify
|
1840 |
+
which version of the API is being called. The default value is
|
1841 |
+
<stringvalue>*/*</stringvalue>.<paragraphbreak />
|
1842 |
+
<stringvalue>ConvertObjects</stringvalue>: boolean option that
|
1843 |
+
determines if objects should be converted into arrays when the
|
1844 |
+
response is returned in JSON format. The default value is
|
1845 |
+
<booleanvalue>0</booleanvalue>.<paragraphbreak />
|
1846 |
+
<stringvalue>DecodeXMLResponse</stringvalue>: name of the method
|
1847 |
+
to decode XML responses. Currently only
|
1848 |
+
<stringvalue>simplexml</stringvalue> is supported. It makes a
|
1849 |
+
XML response be parsed and returned as a SimpleXMLElement
|
1850 |
+
object.<paragraphbreak />
|
1851 |
+
<stringvalue>FailOnAccessError</stringvalue>: boolean option
|
1852 |
+
that determines if this functions should fail when the server
|
1853 |
+
response status is not between 200 and 299. The default value
|
1854 |
+
is <booleanvalue>0</booleanvalue>.<paragraphbreak />
|
1855 |
+
<stringvalue>Files</stringvalue>: associative array with
|
1856 |
+
details of the parameters that must be passed as file uploads.
|
1857 |
+
The array indexes must have the same name of the parameters
|
1858 |
+
to be sent as files. The respective array entry values must
|
1859 |
+
also be associative arrays with the parameters for each file.
|
1860 |
+
Currently it supports the following parameters:<paragraphbreak />
|
1861 |
+
- <tt>Type</tt> - defines how the parameter value should be
|
1862 |
+
treated. It can be <tt>'FileName'</tt> if the parameter value is
|
1863 |
+
is the name of a local file to be uploaded. It may also be
|
1864 |
+
<tt>'Data'</tt> if the parameter value is the actual data of
|
1865 |
+
the file to be uploaded.<paragraphbreak />
|
1866 |
+
Default: <tt>'FileName'</tt><paragraphbreak />
|
1867 |
+
- <tt>FileName</tt> - defines a custom file name for the file
|
1868 |
+
to be uploaded.<paragraphbreak />
|
1869 |
+
Default: none<paragraphbreak />
|
1870 |
+
- <tt>ContentType</tt> - MIME value of the content type of the
|
1871 |
+
file. It can be <tt>'automatic/name'</tt> if the content type
|
1872 |
+
should be determine from the file name extension.<paragraphbreak />
|
1873 |
+
Default: <tt>'automatic/name'</tt><paragraphbreak />
|
1874 |
+
<stringvalue>PostValuesInURI</stringvalue>: boolean option to
|
1875 |
+
determine that a POST request should pass the request values
|
1876 |
+
in the URI. The default value is
|
1877 |
+
<booleanvalue>0</booleanvalue>.<paragraphbreak />
|
1878 |
+
<stringvalue>FollowRedirection</stringvalue>: limit number of
|
1879 |
+
times that HTTP response redirects will be followed. If it is
|
1880 |
+
set to <integervalue>0</integervalue>, redirection responses
|
1881 |
+
fail in error. The default value is
|
1882 |
+
<integervalue>0</integervalue>.<paragraphbreak />
|
1883 |
+
<stringvalue>RequestBody</stringvalue>: request body data of a
|
1884 |
+
custom type. The <stringvalue>RequestContentType</stringvalue>
|
1885 |
+
option must be specified, so the
|
1886 |
+
<stringvalue>RequestBody</stringvalue> option is considered.<paragraphbreak />
|
1887 |
+
<stringvalue>RequestContentType</stringvalue>: content type that
|
1888 |
+
should be used to send the request values. It can be either
|
1889 |
+
<stringvalue>application/x-www-form-urlencoded</stringvalue>
|
1890 |
+
for sending values like from Web forms, or
|
1891 |
+
<stringvalue>application/json</stringvalue> for sending the
|
1892 |
+
values encoded in JSON format. Other types are accepted if the
|
1893 |
+
<stringvalue>RequestBody</stringvalue> option is specified.
|
1894 |
+
The default value is
|
1895 |
+
<stringvalue>application/x-www-form-urlencoded</stringvalue>.<paragraphbreak />
|
1896 |
+
<stringvalue>RequestHeaders</stringvalue>: associative array of
|
1897 |
+
custom headers to be sent with the API call. These headers
|
1898 |
+
override any values set by the class when sending the API
|
1899 |
+
call HTTP request.<paragraphbreak />
|
1900 |
+
<stringvalue>Resource</stringvalue>: string with a label that
|
1901 |
+
will be used in the error messages and debug log entries to
|
1902 |
+
identify what operation the request is performing. The default
|
1903 |
+
value is <stringvalue>API call</stringvalue>.<paragraphbreak />
|
1904 |
+
<stringvalue>ResponseContentType</stringvalue>: content type
|
1905 |
+
that should be considered when decoding the API request
|
1906 |
+
response. This overrides the <tt>Content-Type</tt> header
|
1907 |
+
returned by the server. If the content type is
|
1908 |
+
<stringvalue>application/x-www-form-urlencoded</stringvalue>
|
1909 |
+
the function will parse the data returning an array of
|
1910 |
+
key-value pairs. If the content type is
|
1911 |
+
<stringvalue>application/json</stringvalue> the response will
|
1912 |
+
be decode as a JSON-encoded data type. Other content type
|
1913 |
+
values will make the function return the original response
|
1914 |
+
value as it was returned from the server. The default value
|
1915 |
+
for this option is to use what the server returned in the
|
1916 |
+
<tt>Content-Type</tt> header.</purpose>
|
1917 |
+
</documentation>
|
1918 |
+
</argument>
|
1919 |
+
<argument>
|
1920 |
+
<name>response</name>
|
1921 |
+
<type>STRING</type>
|
1922 |
+
<out />
|
1923 |
+
<documentation>
|
1924 |
+
<purpose>Return the value of the API response. If the value is
|
1925 |
+
JSON encoded, this function will decode it and return the value
|
1926 |
+
converted to respective types. If the value is form encoded,
|
1927 |
+
this function will decode the response and return it as an
|
1928 |
+
array. Otherwise, the class will return the value as a
|
1929 |
+
string.</purpose>
|
1930 |
+
</documentation>
|
1931 |
+
</argument>
|
1932 |
+
<do>
|
1933 |
+
{/metadocument}
|
1934 |
+
*/
|
1935 |
+
Function CallAPI($url, $method, $parameters, $options, &$response) {
|
1936 |
+
if (!IsSet($options['Resource'])) $options['Resource'] = 'API call';
|
1937 |
+
if (!IsSet($options['ConvertObjects'])) $options['ConvertObjects'] = false;
|
1938 |
+
$version = intval($this->oauth_version);
|
1939 |
+
$two_legged = ($version === 1 && IsSet($options['2Legged']) && $options['2Legged']);
|
1940 |
+
if (strlen($this->access_token) === 0 && !$two_legged) {
|
1941 |
+
if (!$this->RetrieveToken($valid)) return false;
|
1942 |
+
if (!$valid) return $this->SetError('the access token is not set to a valid value');
|
1943 |
+
}
|
1944 |
+
switch ($version) {
|
1945 |
+
case 1:
|
1946 |
+
if (!$two_legged && strlen($this->access_token_expiry) && strcmp($this->access_token_expiry, gmstrftime('%Y-%m-%d %H:%M:%S')) <= 0) {
|
1947 |
+
if (strlen($this->refresh_token) === 0) return ($this->SetError('the access token expired and no refresh token is available'));
|
1948 |
+
if ($this->debug) $this->OutputDebug('Refreshing the OAuth access token expired on ' . $this->access_token_expiry);
|
1949 |
+
$oauth = array(
|
1950 |
+
'oauth_token' => $this->access_token,
|
1951 |
+
'oauth_session_handle' => $this->refresh_token
|
1952 |
+
);
|
1953 |
+
if (!$this->ProcessToken1($oauth, $access_token)) return false;
|
1954 |
+
if (IsSet($options['FailOnAccessError']) && $options['FailOnAccessError'] && strlen($this->authorization_error)) {
|
1955 |
+
$this->error = $this->authorization_error;
|
1956 |
+
|
1957 |
+
return false;
|
1958 |
+
}
|
1959 |
+
if (!IsSet($access_token['authorized']) || !$access_token['authorized']) return ($this->SetError('failed to obtain a renewed the expired access token'));
|
1960 |
+
$this->access_token = $access_token['value'];
|
1961 |
+
$this->access_token_secret = $access_token['secret'];
|
1962 |
+
if (IsSet($access_token['refresh'])) $this->refresh_token = $access_token['refresh'];
|
1963 |
+
}
|
1964 |
+
$oauth = array();
|
1965 |
+
if (!$two_legged) $oauth[strlen($this->access_token_parameter) ? $this->access_token_parameter : 'oauth_token'] = $this->access_token;
|
1966 |
+
break;
|
1967 |
+
|
1968 |
+
case 2:
|
1969 |
+
if (strlen($this->access_token_expiry) && strcmp($this->access_token_expiry, gmstrftime('%Y-%m-%d %H:%M:%S')) <= 0) {
|
1970 |
+
if (strlen($this->refresh_token) === 0) return ($this->SetError('the access token expired and no refresh token is available'));
|
1971 |
+
if ($this->debug) $this->OutputDebug('Refreshing the OAuth access token expired on ' . $this->access_token_expiry);
|
1972 |
+
if (!$this->ProcessToken2(null, true)) return false;
|
1973 |
+
if (IsSet($options['FailOnAccessError']) && $options['FailOnAccessError'] && strlen($this->authorization_error)) {
|
1974 |
+
$this->error = $this->authorization_error;
|
1975 |
+
|
1976 |
+
return false;
|
1977 |
+
}
|
1978 |
+
}
|
1979 |
+
$oauth = null;
|
1980 |
+
if (strcasecmp($this->access_token_type, 'Bearer')) $url .= (strcspn($url, '?') < strlen($url) ? '&' : '?') . (strlen($this->access_token_parameter) ? $this->access_token_parameter : 'access_token') . '=' . UrlEncode($this->access_token);
|
1981 |
+
break;
|
1982 |
+
|
1983 |
+
default:
|
1984 |
+
return ($this->SetError($this->oauth_version . ' is not a supported version of the OAuth protocol'));
|
1985 |
+
}
|
1986 |
+
|
1987 |
+
return ($this->SendAPIRequest($url, $method, $parameters, $oauth, $options, $response));
|
1988 |
+
}
|
1989 |
+
/*
|
1990 |
+
{metadocument}
|
1991 |
+
</do>
|
1992 |
+
</function>
|
1993 |
+
{/metadocument}
|
1994 |
+
*/
|
1995 |
+
|
1996 |
+
/*
|
1997 |
+
{metadocument}
|
1998 |
+
<function>
|
1999 |
+
<name>Initialize</name>
|
2000 |
+
<type>BOOLEAN</type>
|
2001 |
+
<documentation>
|
2002 |
+
<purpose>Initialize the class variables and internal state. It must
|
2003 |
+
be called before calling other class functions.</purpose>
|
2004 |
+
<usage>Set the <variablelink>server</variablelink> variable before
|
2005 |
+
calling this function to let it initialize the class variables to
|
2006 |
+
work with the specified server type. Alternatively, you can set
|
2007 |
+
other class variables manually to make it work with servers that
|
2008 |
+
are not yet built-in supported.</usage>
|
2009 |
+
<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
|
2010 |
+
it was able to successfully initialize the class for the specified
|
2011 |
+
server type.</returnvalue>
|
2012 |
+
</documentation>
|
2013 |
+
<do>
|
2014 |
+
{/metadocument}
|
2015 |
+
*/
|
2016 |
+
Function Initialize() {
|
2017 |
+
if (strlen($this->server) === 0) return true;
|
2018 |
+
$this->oauth_version = $this->dialog_url = $this->pin_dialog_url = $this->access_token_url = $this->request_token_url = $this->append_state_to_redirect_uri = '';
|
2019 |
+
$this->authorization_header = true;
|
2020 |
+
$this->url_parameters = false;
|
2021 |
+
$this->token_request_method = 'GET';
|
2022 |
+
$this->signature_method = 'HMAC-SHA1';
|
2023 |
+
$this->access_token_authentication = '';
|
2024 |
+
$this->access_token_parameter = '';
|
2025 |
+
$this->default_access_token_type = '';
|
2026 |
+
$this->store_access_token_response = false;
|
2027 |
+
switch ($this->server) {
|
2028 |
+
case 'Facebook':
|
2029 |
+
$this->oauth_version = '2.0';
|
2030 |
+
$this->dialog_url = 'https://www.facebook.com/v2.3/dialog/oauth?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
|
2031 |
+
$this->access_token_url = 'https://graph.facebook.com/oauth/access_token';
|
2032 |
+
break;
|
2033 |
+
|
2034 |
+
case 'github':
|
2035 |
+
$this->oauth_version = '2.0';
|
2036 |
+
$this->dialog_url = 'https://github.com/login/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
|
2037 |
+
$this->access_token_url = 'https://github.com/login/oauth/access_token';
|
2038 |
+
break;
|
2039 |
+
|
2040 |
+
case 'Google':
|
2041 |
+
$this->oauth_version = '2.0';
|
2042 |
+
$this->dialog_url = 'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
|
2043 |
+
$this->offline_dialog_url = 'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}&access_type=offline&approval_prompt=force';
|
2044 |
+
$this->access_token_url = 'https://accounts.google.com/o/oauth2/token';
|
2045 |
+
break;
|
2046 |
+
|
2047 |
+
case 'LinkedIn':
|
2048 |
+
$this->oauth_version = '1.0a';
|
2049 |
+
$this->request_token_url = 'https://api.linkedin.com/uas/oauth/requestToken?scope={SCOPE}';
|
2050 |
+
$this->dialog_url = 'https://api.linkedin.com/uas/oauth/authenticate';
|
2051 |
+
$this->access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken';
|
2052 |
+
$this->url_parameters = true;
|
2053 |
+
break;
|
2054 |
+
|
2055 |
+
case 'Microsoft':
|
2056 |
+
$this->oauth_version = '2.0';
|
2057 |
+
$this->dialog_url = 'https://login.live.com/oauth20_authorize.srf?client_id={CLIENT_ID}&scope={SCOPE}&response_type=code&redirect_uri={REDIRECT_URI}&state={STATE}';
|
2058 |
+
$this->access_token_url = 'https://login.live.com/oauth20_token.srf';
|
2059 |
+
break;
|
2060 |
+
|
2061 |
+
case 'Twitter':
|
2062 |
+
$this->oauth_version = '1.0a';
|
2063 |
+
$this->request_token_url = 'https://api.twitter.com/oauth/request_token';
|
2064 |
+
$this->dialog_url = 'https://api.twitter.com/oauth/authenticate';
|
2065 |
+
$this->access_token_url = 'https://api.twitter.com/oauth/access_token';
|
2066 |
+
$this->url_parameters = false;
|
2067 |
+
break;
|
2068 |
+
|
2069 |
+
case 'Yahoo':
|
2070 |
+
$this->oauth_version = '1.0a';
|
2071 |
+
$this->request_token_url = 'https://api.login.yahoo.com/oauth/v2/get_request_token';
|
2072 |
+
$this->dialog_url = 'https://api.login.yahoo.com/oauth/v2/request_auth';
|
2073 |
+
$this->access_token_url = 'https://api.login.yahoo.com/oauth/v2/get_token';
|
2074 |
+
$this->authorization_header = false;
|
2075 |
+
break;
|
2076 |
+
|
2077 |
+
default:
|
2078 |
+
if (!($json = @file_get_contents($this->configuration_file))) {
|
2079 |
+
if (!file_exists($this->configuration_file)) return $this->SetError('the OAuth server configuration file ' . $this->configuration_file . ' does not exist');
|
2080 |
+
|
2081 |
+
return $this->SetPHPError('could not read the OAuth server configuration file ' . $this->configuration_file, self::PHPErrorMessage());
|
2082 |
+
}
|
2083 |
+
$oauth_server = json_decode($json);
|
2084 |
+
if (!IsSet($oauth_server)) return $this->SetPHPError('It was not possible to decode the OAuth server configuration file ' . $this->configuration_file . ' eventually due to incorrect format', self::PHPErrorMessage());
|
2085 |
+
if (GetType($oauth_server) !== 'object') return $this->SetError('It was not possible to decode the OAuth server configuration file ' . $this->configuration_file . ' because it does not correctly define a JSON object');
|
2086 |
+
if (!IsSet($oauth_server->servers) || GetType($oauth_server->servers) !== 'object') return $this->SetError('It was not possible to decode the OAuth server configuration file ' . $this->configuration_file . ' because it does not correctly define a JSON object for servers');
|
2087 |
+
if (!IsSet($oauth_server->servers->{$this->server})) return ($this->SetError($this->server . ' is not yet a supported type of OAuth server. Please send a request in this class support forum (preferred) http://www.phpclasses.org/oauth-api , or if it is a security or private matter, contact the author Manuel Lemos mlemos@acm.org to request adding built-in support to this type of OAuth server.'));
|
2088 |
+
$properties = $oauth_server->servers->{$this->server};
|
2089 |
+
if (GetType($properties) !== 'object') return $this->SetError('The OAuth server configuration file ' . $this->configuration_file . ' for the "' . $this->server . '" server does not correctly define a JSON object');
|
2090 |
+
$types = array(
|
2091 |
+
'oauth_version' => 'string',
|
2092 |
+
'request_token_url' => 'string',
|
2093 |
+
'dialog_url' => 'string',
|
2094 |
+
'pin_dialog_url' => 'string',
|
2095 |
+
'offline_dialog_url' => 'string',
|
2096 |
+
'access_token_url' => 'string',
|
2097 |
+
'append_state_to_redirect_uri' => 'string',
|
2098 |
+
'authorization_header' => 'boolean',
|
2099 |
+
'url_parameters' => 'boolean',
|
2100 |
+
'token_request_method' => 'string',
|
2101 |
+
'signature_method' => 'string',
|
2102 |
+
'access_token_authentication' => 'string',
|
2103 |
+
'access_token_parameter' => 'string',
|
2104 |
+
'default_access_token_type' => 'string',
|
2105 |
+
'store_access_token_response' => 'boolean'
|
2106 |
+
);
|
2107 |
+
$required = array(
|
2108 |
+
'oauth_version' => array(),
|
2109 |
+
'request_token_url' => array(
|
2110 |
+
'1.0',
|
2111 |
+
'1.0a'
|
2112 |
+
),
|
2113 |
+
'dialog_url' => array(),
|
2114 |
+
'access_token_url' => array(),
|
2115 |
+
);
|
2116 |
+
foreach ($properties as $property => $value) {
|
2117 |
+
if (!IsSet($types[$property])) return $this->SetError($property . ' is not a supported property for the "' . $this->server . '" server in the OAuth server configuration file ' . $this->configuration_file);
|
2118 |
+
$type = GetType($value);
|
2119 |
+
$expected = $types[$property];
|
2120 |
+
if ($type !== $expected) return $this->SetError(' the property "' . $property . '" for the "' . $this->server . '" server is not of type "' . $expected . '", it is of type "' . $type . '", in the OAuth server configuration file ' . $this->configuration_file);
|
2121 |
+
$this->{$property} = $value;
|
2122 |
+
UnSet($required[$property]);
|
2123 |
+
}
|
2124 |
+
foreach ($required as $property => $value) {
|
2125 |
+
if (count($value) && in_array($this->oauth_version, $value)) return $this->SetError('the property "' . $property . '" is not defined for the "' . $this->server . '" server in the OAuth server configuration file ' . $this->configuration_file);
|
2126 |
+
}
|
2127 |
+
break;
|
2128 |
+
}
|
2129 |
+
|
2130 |
+
return (true);
|
2131 |
+
}
|
2132 |
+
/*
|
2133 |
+
{metadocument}
|
2134 |
+
</do>
|
2135 |
+
</function>
|
2136 |
+
{/metadocument}
|
2137 |
+
*/
|
2138 |
+
|
2139 |
+
/*
|
2140 |
+
{metadocument}
|
2141 |
+
<function>
|
2142 |
+
<name>CheckAccessToken</name>
|
2143 |
+
<type>BOOLEAN</type>
|
2144 |
+
<documentation>
|
2145 |
+
<purpose>Check if the access token was retrieved and if it is
|
2146 |
+
valid.</purpose>
|
2147 |
+
<usage>Call this function when you need to check of an access token
|
2148 |
+
is valid without forcing to redirect the user to the OAuth server
|
2149 |
+
authorization page.<paragraphbreak />
|
2150 |
+
If a previously retrieved access token has expired, this function
|
2151 |
+
may renew it automatically.</usage>
|
2152 |
+
<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
|
2153 |
+
the OAuth protocol was checked without errors.</returnvalue>
|
2154 |
+
</documentation>
|
2155 |
+
<argument>
|
2156 |
+
<name>redirect_url</name>
|
2157 |
+
<type>STRING</type>
|
2158 |
+
<out />
|
2159 |
+
<documentation>
|
2160 |
+
<purpose>Return the URL of the OAuth server authorization to
|
2161 |
+
redirect the user if the access token was not yet retrieved or
|
2162 |
+
is not valid.</purpose>
|
2163 |
+
</documentation>
|
2164 |
+
</argument>
|
2165 |
+
<do>
|
2166 |
+
{/metadocument}
|
2167 |
+
*/
|
2168 |
+
Function CheckAccessToken(&$redirect_url) {
|
2169 |
+
$redirect_url = null;
|
2170 |
+
if (strlen($this->access_token) || strlen($this->access_token_secret)) {
|
2171 |
+
if ($this->debug) $this->OutputDebug('The Process function should not be called again if the OAuth token was already set manually');
|
2172 |
+
|
2173 |
+
return $this->SetError('the OAuth token was already set');
|
2174 |
+
}
|
2175 |
+
switch (intval($this->oauth_version)) {
|
2176 |
+
case 1:
|
2177 |
+
$one_a = ($this->oauth_version === '1.0a');
|
2178 |
+
if ($this->debug) $this->OutputDebug('Checking the OAuth token authorization state');
|
2179 |
+
if (!$this->GetAccessToken($access_token)) return false;
|
2180 |
+
if (IsSet($access_token['expiry'])) $this->access_token_expiry = $access_token['expiry'];
|
2181 |
+
if (IsSet($access_token['authorized']) && IsSet($access_token['value'])) {
|
2182 |
+
$expired = (IsSet($access_token['expiry']) && strcmp($access_token['expiry'], gmstrftime('%Y-%m-%d %H:%M:%S')) <= 0);
|
2183 |
+
if (!$access_token['authorized'] || $expired) {
|
2184 |
+
if ($this->debug) {
|
2185 |
+
if ($expired) $this->OutputDebug('The OAuth token expired on ' . $access_token['expiry'] . 'UTC'); else
|
2186 |
+
$this->OutputDebug('The OAuth token is not yet authorized');
|
2187 |
+
}
|
2188 |
+
if ($one_a && $this->redirect_uri === 'oob' && strlen($this->pin)) {
|
2189 |
+
if ($this->debug) $this->OutputDebug('Checking the pin');
|
2190 |
+
$this->access_token_secret = $access_token['secret'];
|
2191 |
+
$oauth = array(
|
2192 |
+
'oauth_token' => $access_token['value'],
|
2193 |
+
'oauth_verifier' => $this->pin
|
2194 |
+
);
|
2195 |
+
if (!$this->ProcessToken1($oauth, $access_token)) return false;
|
2196 |
+
if ($this->debug) $this->OutputDebug('The OAuth token was authorized');
|
2197 |
+
} else {
|
2198 |
+
if ($this->debug) $this->OutputDebug('Checking the OAuth token and verifier');
|
2199 |
+
if (!$this->GetRequestToken($token, $verifier)) return false;
|
2200 |
+
if (!IsSet($token) || ($one_a && !IsSet($verifier))) {
|
2201 |
+
if (!$this->GetRequestDenied($denied)) return false;
|
2202 |
+
if (IsSet($denied) && $denied === $access_token['value']) {
|
2203 |
+
if ($this->debug) $this->OutputDebug('The authorization request was denied');
|
2204 |
+
$this->authorization_error = 'the request was denied';
|
2205 |
+
|
2206 |
+
return true;
|
2207 |
+
} else {
|
2208 |
+
if ($this->debug) $this->OutputDebug('Reset the OAuth token state because token and verifier are not both set');
|
2209 |
+
$access_token = array();
|
2210 |
+
}
|
2211 |
+
} elseif ($token !== $access_token['value']) {
|
2212 |
+
if ($this->debug) $this->OutputDebug('Reset the OAuth token state because token does not match what as previously retrieved');
|
2213 |
+
$access_token = array();
|
2214 |
+
} else {
|
2215 |
+
$this->access_token_secret = $access_token['secret'];
|
2216 |
+
$oauth = array(
|
2217 |
+
'oauth_token' => $token,
|
2218 |
+
);
|
2219 |
+
if ($one_a) $oauth['oauth_verifier'] = $verifier;
|
2220 |
+
if (!$this->ProcessToken1($oauth, $access_token)) return false;
|
2221 |
+
if ($this->debug) $this->OutputDebug('The OAuth token was authorized');
|
2222 |
+
}
|
2223 |
+
}
|
2224 |
+
} elseif ($this->debug) $this->OutputDebug('The OAuth token was already authorized');
|
2225 |
+
if (IsSet($access_token['authorized']) && $access_token['authorized']) {
|
2226 |
+
$this->access_token = $access_token['value'];
|
2227 |
+
$this->access_token_secret = $access_token['secret'];
|
2228 |
+
if (IsSet($access_token['refresh'])) $this->refresh_token = $access_token['refresh'];
|
2229 |
+
|
2230 |
+
return true;
|
2231 |
+
}
|
2232 |
+
} else {
|
2233 |
+
if ($this->debug) $this->OutputDebug('The OAuth access token is not set');
|
2234 |
+
$access_token = array();
|
2235 |
+
}
|
2236 |
+
if (!IsSet($access_token['authorized'])) {
|
2237 |
+
if ($this->debug) $this->OutputDebug('Requesting the unauthorized OAuth token');
|
2238 |
+
if (!$this->GetRequestTokenURL($url)) return false;
|
2239 |
+
$url = str_replace('{SCOPE}', UrlEncode($this->scope), $url);
|
2240 |
+
if (!$this->GetRedirectURI($redirect_uri)) return false;
|
2241 |
+
$oauth = array(
|
2242 |
+
'oauth_callback' => $redirect_uri,
|
2243 |
+
);
|
2244 |
+
$options = array(
|
2245 |
+
'Resource' => 'OAuth request token',
|
2246 |
+
'FailOnAccessError' => true
|
2247 |
+
);
|
2248 |
+
$method = strtoupper($this->token_request_method);
|
2249 |
+
switch ($method) {
|
2250 |
+
case 'GET':
|
2251 |
+
break;
|
2252 |
+
case 'POST':
|
2253 |
+
$options['PostValuesInURI'] = true;
|
2254 |
+
break;
|
2255 |
+
default:
|
2256 |
+
$this->error = $method . ' is not a supported method to request tokens';
|
2257 |
+
break;
|
2258 |
+
}
|
2259 |
+
if (!$this->SendAPIRequest($url, $method, array(), $oauth, $options, $response)) return false;
|
2260 |
+
if (strlen($this->access_token_error)) {
|
2261 |
+
$this->authorization_error = $this->access_token_error;
|
2262 |
+
|
2263 |
+
return true;
|
2264 |
+
}
|
2265 |
+
if (!IsSet($response['oauth_token']) || !IsSet($response['oauth_token_secret'])) {
|
2266 |
+
$this->authorization_error = 'it was not returned the requested token';
|
2267 |
+
|
2268 |
+
return true;
|
2269 |
+
}
|
2270 |
+
$access_token = array(
|
2271 |
+
'value' => $response['oauth_token'],
|
2272 |
+
'secret' => $response['oauth_token_secret'],
|
2273 |
+
'authorized' => false
|
2274 |
+
);
|
2275 |
+
if (IsSet($response['login_url'])) $access_token['login_url'] = $response['login_url'];
|
2276 |
+
if (!$this->StoreAccessToken($access_token)) return false;
|
2277 |
+
}
|
2278 |
+
if (!$this->GetDialogURL($url)) return false;
|
2279 |
+
if ($url === 'automatic') {
|
2280 |
+
if (!IsSet($access_token['login_url'])) return ($this->SetError('The request token response did not automatically the login dialog URL as expected'));
|
2281 |
+
if ($this->debug) $this->OutputDebug('Dialog URL obtained automatically from the request token response: ' . $url);
|
2282 |
+
$url = $access_token['login_url'];
|
2283 |
+
} else
|
2284 |
+
$url .= (strpos($url, '?') === false ? '?' : '&') . 'oauth_token=' . $access_token['value'];
|
2285 |
+
if (!$one_a) {
|
2286 |
+
if (!$this->GetRedirectURI($redirect_uri)) return false;
|
2287 |
+
$url .= '&oauth_callback=' . UrlEncode($redirect_uri);
|
2288 |
+
}
|
2289 |
+
if ($this->debug) $this->OutputDebug('Redirecting to OAuth authorize page ' . $url);
|
2290 |
+
$redirect_url = $url;
|
2291 |
+
|
2292 |
+
return true;
|
2293 |
+
|
2294 |
+
case 2:
|
2295 |
+
if ($this->debug) {
|
2296 |
+
if (!$this->GetAccessTokenURL($access_token_url)) return false;
|
2297 |
+
$this->OutputDebug('Checking if OAuth access token was already retrieved from ' . $access_token_url);
|
2298 |
+
}
|
2299 |
+
if (!$this->RetrieveToken($valid)) return false;
|
2300 |
+
$expired = (strlen($this->access_token_expiry) && strcmp($this->access_token_expiry, gmstrftime('%Y-%m-%d %H:%M:%S')) <= 0 && strlen($this->refresh_token) === 0);
|
2301 |
+
if ($valid && !$expired) return true;
|
2302 |
+
if ($this->debug) {
|
2303 |
+
if (!$valid) $this->OutputDebug('A valid access token is not available'); elseif ($expired) $this->OutputDebug('The access token expired');
|
2304 |
+
}
|
2305 |
+
switch ($this->grant_type) {
|
2306 |
+
case 'authorization_code':
|
2307 |
+
if ($this->redirect_uri === 'oob' && strlen($this->pin)) {
|
2308 |
+
if ($this->debug) $this->OutputDebug('Getting the access token using the pin');
|
2309 |
+
if (!$this->ProcessToken2(null, false)) return false;
|
2310 |
+
if (strlen($this->authorization_error)) return $this->SetError($this->authorization_error);
|
2311 |
+
|
2312 |
+
return true;
|
2313 |
+
} elseif (strlen($this->oauth_username) === 0) break;
|
2314 |
+
case 'password':
|
2315 |
+
if ($this->debug) $this->OutputDebug('Getting the access token using the username and password');
|
2316 |
+
if (!$this->ProcessToken2(null, false)) return false;
|
2317 |
+
if (strlen($this->authorization_error)) return $this->SetError($this->authorization_error);
|
2318 |
+
|
2319 |
+
return true;
|
2320 |
+
case 'client_credentials':
|
2321 |
+
if ($this->debug) $this->OutputDebug('Getting the access token using the client credentials');
|
2322 |
+
if (!$this->ProcessToken2(null, false)) return false;
|
2323 |
+
if (strlen($this->authorization_error)) return $this->SetError($this->authorization_error);
|
2324 |
+
|
2325 |
+
return true;
|
2326 |
+
default:
|
2327 |
+
return $this->SetError($this->grant_type . ' is not yet a supported OAuth 2 grant type');
|
2328 |
+
}
|
2329 |
+
if ($this->debug) $this->OutputDebug('Checking the authentication state in URI ' . $_SERVER['REQUEST_URI']);
|
2330 |
+
if (!$this->GetStoredState($stored_state)) return false;
|
2331 |
+
if (strlen($stored_state) == 0) return ($this->SetError('it was not set the OAuth state'));
|
2332 |
+
if (!$this->GetRequestState($state)) return false;
|
2333 |
+
if ($state === $stored_state) {
|
2334 |
+
if ($this->debug) $this->OutputDebug('Checking the authentication code');
|
2335 |
+
if (!$this->GetRequestCode($code)) return false;
|
2336 |
+
if (strlen($code) == 0) {
|
2337 |
+
if (!$this->GetRequestError($this->authorization_error)) return false;
|
2338 |
+
if (IsSet($this->authorization_error)) {
|
2339 |
+
if ($this->debug) $this->OutputDebug('Authorization failed with error code ' . $this->authorization_error);
|
2340 |
+
switch ($this->authorization_error) {
|
2341 |
+
case 'invalid_request':
|
2342 |
+
case 'unauthorized_client':
|
2343 |
+
case 'access_denied':
|
2344 |
+
case 'unsupported_response_type':
|
2345 |
+
case 'invalid_scope':
|
2346 |
+
case 'server_error':
|
2347 |
+
case 'temporarily_unavailable':
|
2348 |
+
case 'user_denied':
|
2349 |
+
return true;
|
2350 |
+
default:
|
2351 |
+
return ($this->SetError('it was returned an unknown OAuth error code'));
|
2352 |
+
}
|
2353 |
+
}
|
2354 |
+
|
2355 |
+
return ($this->SetError('it was not returned the OAuth dialog code'));
|
2356 |
+
}
|
2357 |
+
if (!$this->ProcessToken2($code, false)) return false;
|
2358 |
+
if (strlen($this->authorization_error)) return $this->SetError($this->authorization_error);
|
2359 |
+
} else {
|
2360 |
+
if (!$this->GetRedirectURI($redirect_uri)) return false;
|
2361 |
+
if (strlen($this->append_state_to_redirect_uri)) $redirect_uri .= (strpos($redirect_uri, '?') === false ? '?' : '&') . $this->append_state_to_redirect_uri . '=' . $stored_state;
|
2362 |
+
if (!$this->GetDialogURL($url, $redirect_uri, $stored_state)) return false;
|
2363 |
+
if (strlen($url) == 0) return ($this->SetError('it was not set the OAuth dialog URL'));
|
2364 |
+
if ($this->debug) $this->OutputDebug('Redirecting to OAuth Dialog ' . $url);
|
2365 |
+
$redirect_url = $url;
|
2366 |
+
}
|
2367 |
+
break;
|
2368 |
+
|
2369 |
+
default:
|
2370 |
+
return ($this->SetError($this->oauth_version . ' is not a supported version of the OAuth protocol'));
|
2371 |
+
}
|
2372 |
+
|
2373 |
+
return (true);
|
2374 |
+
}
|
2375 |
+
/*
|
2376 |
+
{metadocument}
|
2377 |
+
</do>
|
2378 |
+
</function>
|
2379 |
+
{/metadocument}
|
2380 |
+
*/
|
2381 |
+
|
2382 |
+
/*
|
2383 |
+
{metadocument}
|
2384 |
+
<function>
|
2385 |
+
<name>Process</name>
|
2386 |
+
<type>BOOLEAN</type>
|
2387 |
+
<documentation>
|
2388 |
+
<purpose>Process the OAuth protocol interaction with the OAuth
|
2389 |
+
server.</purpose>
|
2390 |
+
<usage>Call this function when you need to retrieve the OAuth access
|
2391 |
+
token. Check the <variablelink>access_token</variablelink> to
|
2392 |
+
determine if the access token was obtained successfully.</usage>
|
2393 |
+
<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
|
2394 |
+
the OAuth protocol was processed without errors.</returnvalue>
|
2395 |
+
</documentation>
|
2396 |
+
<do>
|
2397 |
+
{/metadocument}
|
2398 |
+
*/
|
2399 |
+
Function Process() {
|
2400 |
+
if (!$this->CheckAccessToken($redirect_url)) return false;
|
2401 |
+
if (IsSet($redirect_url)) {
|
2402 |
+
$this->Redirect($redirect_url);
|
2403 |
+
$this->exit = true;
|
2404 |
+
}
|
2405 |
+
|
2406 |
+
return true;
|
2407 |
+
}
|
2408 |
+
|
2409 |
+
/*
|
2410 |
+
{metadocument}
|
2411 |
+
</do>
|
2412 |
+
</function>
|
2413 |
+
{/metadocument}
|
2414 |
+
*/
|
2415 |
+
|
2416 |
+
/*
|
2417 |
+
{metadocument}
|
2418 |
+
<function>
|
2419 |
+
<name>Finalize</name>
|
2420 |
+
<type>BOOLEAN</type>
|
2421 |
+
<documentation>
|
2422 |
+
<purpose>Cleanup any resources that may have been used during the
|
2423 |
+
OAuth protocol processing or execution of API calls.</purpose>
|
2424 |
+
<usage>Always call this function as the last step after calling the
|
2425 |
+
functions <functionlink>Process</functionlink> or
|
2426 |
+
<functionlink>CallAPI</functionlink>.</usage>
|
2427 |
+
<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
|
2428 |
+
the function cleaned up any resources successfully.</returnvalue>
|
2429 |
+
</documentation>
|
2430 |
+
<argument>
|
2431 |
+
<name>success</name>
|
2432 |
+
<type>BOOLEAN</type>
|
2433 |
+
<documentation>
|
2434 |
+
<purpose>Pass the last success state returned by the class or any
|
2435 |
+
external code processing the class function results.</purpose>
|
2436 |
+
</documentation>
|
2437 |
+
</argument>
|
2438 |
+
<do>
|
2439 |
+
{/metadocument}
|
2440 |
+
*/
|
2441 |
+
Function Finalize($success) {
|
2442 |
+
return ($success);
|
2443 |
+
}
|
2444 |
+
/*
|
2445 |
+
{metadocument}
|
2446 |
+
</do>
|
2447 |
+
</function>
|
2448 |
+
{/metadocument}
|
2449 |
+
*/
|
2450 |
+
|
2451 |
+
/*
|
2452 |
+
{metadocument}
|
2453 |
+
<function>
|
2454 |
+
<name>Output</name>
|
2455 |
+
<type>VOID</type>
|
2456 |
+
<documentation>
|
2457 |
+
<purpose>Display the results of the OAuth protocol processing.</purpose>
|
2458 |
+
<usage>Only call this function if you are debugging the OAuth
|
2459 |
+
authorization process and you need to view what was its
|
2460 |
+
results.</usage>
|
2461 |
+
</documentation>
|
2462 |
+
<do>
|
2463 |
+
{/metadocument}
|
2464 |
+
*/
|
2465 |
+
Function Output() {
|
2466 |
+
if (strlen($this->authorization_error) || strlen($this->access_token_error) || strlen($this->access_token)) {
|
2467 |
+
?>
|
2468 |
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
2469 |
+
<html>
|
2470 |
+
<head>
|
2471 |
+
<title>OAuth client result</title>
|
2472 |
+
</head>
|
2473 |
+
<body>
|
2474 |
+
<h1>OAuth client result</h1>
|
2475 |
+
<?php
|
2476 |
+
if (strlen($this->authorization_error)) {
|
2477 |
+
?>
|
2478 |
+
<p>It was not possible to authorize the application.<?php
|
2479 |
+
if ($this->debug) {
|
2480 |
+
?>
|
2481 |
+
<br>Authorization error: <?php echo HtmlSpecialChars($this->authorization_error);
|
2482 |
+
}
|
2483 |
+
?></p>
|
2484 |
+
<?php
|
2485 |
+
} elseif (strlen($this->access_token_error)) {
|
2486 |
+
?>
|
2487 |
+
<p>It was not possible to use the application access token.
|
2488 |
+
<?php
|
2489 |
+
if ($this->debug) {
|
2490 |
+
?>
|
2491 |
+
<br>Error: <?php echo HtmlSpecialChars($this->access_token_error);
|
2492 |
+
}
|
2493 |
+
?></p>
|
2494 |
+
<?php
|
2495 |
+
} elseif (strlen($this->access_token)) {
|
2496 |
+
?>
|
2497 |
+
<p>The application authorization was obtained successfully.
|
2498 |
+
<?php
|
2499 |
+
if ($this->debug) {
|
2500 |
+
?>
|
2501 |
+
<br>Access token: <?php echo HtmlSpecialChars($this->access_token);
|
2502 |
+
if (IsSet($this->access_token_secret)) {
|
2503 |
+
?>
|
2504 |
+
<br>Access token secret: <?php echo HtmlSpecialChars($this->access_token_secret);
|
2505 |
+
}
|
2506 |
+
}
|
2507 |
+
?></p>
|
2508 |
+
<?php
|
2509 |
+
if (strlen($this->access_token_expiry)) {
|
2510 |
+
?>
|
2511 |
+
<p>Access token expiry: <?php echo $this->access_token_expiry; ?> UTC</p>
|
2512 |
+
<?php
|
2513 |
+
}
|
2514 |
+
}
|
2515 |
+
?>
|
2516 |
+
</body>
|
2517 |
+
</html>
|
2518 |
+
<?php
|
2519 |
+
}
|
2520 |
+
}
|
2521 |
+
/*
|
2522 |
+
{metadocument}
|
2523 |
+
</do>
|
2524 |
+
</function>
|
2525 |
+
{/metadocument}
|
2526 |
+
*/
|
2527 |
+
|
2528 |
+
}
|
2529 |
+
|
2530 |
+
/*
|
2531 |
+
|
2532 |
+
{metadocument}
|
2533 |
+
</class>
|
2534 |
+
{/metadocument}
|
2535 |
+
|
2536 |
+
*/
|
{nextend/library/libraries/oauth → Nextend/Framework/Misc/OAuth}/oauth_configuration.json
RENAMED
File without changes
|
Nextend/Framework/Misc/Str.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Misc;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Misc\String\MultiByte;
|
8 |
+
use Nextend\Framework\Misc\String\SingleByte;
|
9 |
+
use Nextend\Framework\Misc\String\StringInterface;
|
10 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
11 |
+
|
12 |
+
class Str {
|
13 |
+
|
14 |
+
use SingletonTrait;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @var StringInterface
|
18 |
+
*/
|
19 |
+
private static $engine;
|
20 |
+
|
21 |
+
protected function init() {
|
22 |
+
if (function_exists('mb_strpos')) {
|
23 |
+
self::$engine = new MultiByte();
|
24 |
+
} else {
|
25 |
+
self::$engine = new SingleByte();
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
public static function strpos($haystack, $needle, $offset = 0) {
|
30 |
+
return self::$engine->strpos($haystack, $needle, $offset);
|
31 |
+
}
|
32 |
+
|
33 |
+
public static function substr($string, $start, $length = null) {
|
34 |
+
return self::$engine->substr($string, $start, $length);
|
35 |
+
}
|
36 |
+
|
37 |
+
public static function strlen($string) {
|
38 |
+
return self::$engine->strlen($string);
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
Str::getInstance();
|
Nextend/Framework/Misc/String/MultiByte.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc\String;
|
4 |
+
|
5 |
+
class MultiByte implements StringInterface {
|
6 |
+
|
7 |
+
public function strpos($haystack, $needle, $offset = 0) {
|
8 |
+
return mb_strpos($haystack, $needle, $offset);
|
9 |
+
}
|
10 |
+
|
11 |
+
public function substr($string, $start, $length = null) {
|
12 |
+
return mb_substr($string, $start, $length);
|
13 |
+
}
|
14 |
+
|
15 |
+
public function strlen($string) {
|
16 |
+
return mb_strlen($string);
|
17 |
+
}
|
18 |
+
}
|
Nextend/Framework/Misc/String/SingleByte.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc\String;
|
4 |
+
|
5 |
+
class SingleByte implements StringInterface {
|
6 |
+
|
7 |
+
public function strpos($haystack, $needle, $offset = 0) {
|
8 |
+
return strpos($haystack, $needle, $offset);
|
9 |
+
}
|
10 |
+
|
11 |
+
public function substr($string, $start, $length = null) {
|
12 |
+
return substr($string, $start, $length);
|
13 |
+
}
|
14 |
+
|
15 |
+
public function strlen($string) {
|
16 |
+
return strlen($string);
|
17 |
+
}
|
18 |
+
}
|
Nextend/Framework/Misc/String/StringInterface.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Misc\String;
|
5 |
+
|
6 |
+
|
7 |
+
interface StringInterface {
|
8 |
+
|
9 |
+
public function strpos($haystack, $needle, $offset = 0);
|
10 |
+
|
11 |
+
public function substr($string, $start, $length = null);
|
12 |
+
|
13 |
+
public function strlen($string);
|
14 |
+
}
|
Nextend/Framework/Misc/Zip/Creator.php
ADDED
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc\Zip;
|
4 |
+
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Zip file creation class.
|
8 |
+
* Makes zip files.
|
9 |
+
*
|
10 |
+
* @access public
|
11 |
+
* @package PhpMyAdmin
|
12 |
+
* @see Official ZIP file format: http://www.pkware.com/support/zip-app-note
|
13 |
+
*/
|
14 |
+
class Creator {
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Whether to echo zip as it's built or return as string from -> file
|
18 |
+
*
|
19 |
+
* @var boolean $doWrite
|
20 |
+
*/
|
21 |
+
var $doWrite = false;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Array to store compressed data
|
25 |
+
*
|
26 |
+
* @var array $datasec
|
27 |
+
*/
|
28 |
+
var $datasec = array();
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Central directory
|
32 |
+
*
|
33 |
+
* @var array $ctrl_dir
|
34 |
+
*/
|
35 |
+
var $ctrl_dir = array();
|
36 |
+
|
37 |
+
/**
|
38 |
+
* End of central directory record
|
39 |
+
*
|
40 |
+
* @var string $eof_ctrl_dir
|
41 |
+
*/
|
42 |
+
var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Last offset position
|
46 |
+
*
|
47 |
+
* @var integer $old_offset
|
48 |
+
*/
|
49 |
+
var $old_offset = 0;
|
50 |
+
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Sets member variable this -> doWrite to true
|
54 |
+
* - Should be called immediately after class instantiantion
|
55 |
+
* - If set to true, then ZIP archive are echo'ed to STDOUT as each
|
56 |
+
* file is added via this -> addfile(), and central directories are
|
57 |
+
* echoed to STDOUT on final call to this -> file(). Also,
|
58 |
+
* this -> file() returns an empty string so it is safe to issue a
|
59 |
+
* "echo $zipfile;" command
|
60 |
+
*
|
61 |
+
* @access public
|
62 |
+
*
|
63 |
+
* @return void
|
64 |
+
*/
|
65 |
+
function setDoWrite() {
|
66 |
+
$this->doWrite = true;
|
67 |
+
} // end of the 'setDoWrite()' method
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Converts an Unix timestamp to a four byte DOS date and time format (date
|
71 |
+
* in high two bytes, time in low two bytes allowing magnitude comparison).
|
72 |
+
*
|
73 |
+
* @param integer $unixtime the current Unix timestamp
|
74 |
+
*
|
75 |
+
* @return integer the current date in a four byte DOS format
|
76 |
+
*
|
77 |
+
* @access private
|
78 |
+
*/
|
79 |
+
function unix2DosTime($unixtime = 0) {
|
80 |
+
$timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);
|
81 |
+
|
82 |
+
if ($timearray['year'] < 1980) {
|
83 |
+
$timearray['year'] = 1980;
|
84 |
+
$timearray['mon'] = 1;
|
85 |
+
$timearray['mday'] = 1;
|
86 |
+
$timearray['hours'] = 0;
|
87 |
+
$timearray['minutes'] = 0;
|
88 |
+
$timearray['seconds'] = 0;
|
89 |
+
} // end if
|
90 |
+
|
91 |
+
return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
|
92 |
+
} // end of the 'unix2DosTime()' method
|
93 |
+
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Adds "file" to archive
|
97 |
+
*
|
98 |
+
* @param string $data file contents
|
99 |
+
* @param string $name name of the file in the archive (may contains the path)
|
100 |
+
* @param integer $time the current timestamp
|
101 |
+
*
|
102 |
+
* @access public
|
103 |
+
*
|
104 |
+
* @return void
|
105 |
+
*/
|
106 |
+
function addFile($data, $name, $time = 0) {
|
107 |
+
$name = str_replace('\\', '/', $name);
|
108 |
+
|
109 |
+
$hexdtime = pack('V', $this->unix2DosTime($time));
|
110 |
+
|
111 |
+
$fr = "\x50\x4b\x03\x04";
|
112 |
+
$fr .= "\x14\x00"; // ver needed to extract
|
113 |
+
$fr .= "\x00\x00"; // gen purpose bit flag
|
114 |
+
$fr .= "\x08\x00"; // compression method
|
115 |
+
$fr .= $hexdtime; // last mod time and date
|
116 |
+
|
117 |
+
// "local file header" segment
|
118 |
+
$unc_len = strlen($data);
|
119 |
+
$crc = crc32($data);
|
120 |
+
$zdata = gzcompress($data);
|
121 |
+
$zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
|
122 |
+
$c_len = strlen($zdata);
|
123 |
+
$fr .= pack('V', $crc); // crc32
|
124 |
+
$fr .= pack('V', $c_len); // compressed filesize
|
125 |
+
$fr .= pack('V', $unc_len); // uncompressed filesize
|
126 |
+
$fr .= pack('v', strlen($name)); // length of filename
|
127 |
+
$fr .= pack('v', 0); // extra field length
|
128 |
+
$fr .= $name;
|
129 |
+
|
130 |
+
// "file data" segment
|
131 |
+
$fr .= $zdata;
|
132 |
+
|
133 |
+
// echo this entry on the fly, ...
|
134 |
+
if ($this->doWrite) {
|
135 |
+
echo $fr;
|
136 |
+
} else { // ... OR add this entry to array
|
137 |
+
$this->datasec[] = $fr;
|
138 |
+
}
|
139 |
+
|
140 |
+
// now add to central directory record
|
141 |
+
$cdrec = "\x50\x4b\x01\x02";
|
142 |
+
$cdrec .= "\x00\x00"; // version made by
|
143 |
+
$cdrec .= "\x14\x00"; // version needed to extract
|
144 |
+
$cdrec .= "\x00\x00"; // gen purpose bit flag
|
145 |
+
$cdrec .= "\x08\x00"; // compression method
|
146 |
+
$cdrec .= $hexdtime; // last mod time & date
|
147 |
+
$cdrec .= pack('V', $crc); // crc32
|
148 |
+
$cdrec .= pack('V', $c_len); // compressed filesize
|
149 |
+
$cdrec .= pack('V', $unc_len); // uncompressed filesize
|
150 |
+
$cdrec .= pack('v', strlen($name)); // length of filename
|
151 |
+
$cdrec .= pack('v', 0); // extra field length
|
152 |
+
$cdrec .= pack('v', 0); // file comment length
|
153 |
+
$cdrec .= pack('v', 0); // disk number start
|
154 |
+
$cdrec .= pack('v', 0); // internal file attributes
|
155 |
+
$cdrec .= pack('V', 32); // external file attributes
|
156 |
+
// - 'archive' bit set
|
157 |
+
|
158 |
+
$cdrec .= pack('V', $this->old_offset); // relative offset of local header
|
159 |
+
$this->old_offset += strlen($fr);
|
160 |
+
|
161 |
+
$cdrec .= $name;
|
162 |
+
|
163 |
+
// optional extra field, file comment goes here
|
164 |
+
// save to central directory
|
165 |
+
$this->ctrl_dir[] = $cdrec;
|
166 |
+
} // end of the 'addFile()' method
|
167 |
+
|
168 |
+
|
169 |
+
/**
|
170 |
+
* Echo central dir if ->doWrite==true, else build string to return
|
171 |
+
*
|
172 |
+
* @return string if ->doWrite {empty string} else the ZIP file contents
|
173 |
+
*
|
174 |
+
* @access public
|
175 |
+
*/
|
176 |
+
function file() {
|
177 |
+
$ctrldir = implode('', $this->ctrl_dir);
|
178 |
+
$header = $ctrldir . $this->eof_ctrl_dir . pack('v', sizeof($this->ctrl_dir)) . //total #of entries "on this disk"
|
179 |
+
pack('v', sizeof($this->ctrl_dir)) . //total #of entries overall
|
180 |
+
pack('V', strlen($ctrldir)) . //size of central dir
|
181 |
+
pack('V', $this->old_offset) . //offset to start of central dir
|
182 |
+
"\x00\x00"; //.zip file comment length
|
183 |
+
|
184 |
+
if ($this->doWrite) { // Send central directory & end ctrl dir to STDOUT
|
185 |
+
echo $header;
|
186 |
+
|
187 |
+
return ""; // Return empty string
|
188 |
+
} else { // Return entire ZIP archive as string
|
189 |
+
$data = implode('', $this->datasec);
|
190 |
+
|
191 |
+
return $data . $header;
|
192 |
+
}
|
193 |
+
} // end of the 'file()' method
|
194 |
+
}
|
Nextend/Framework/Misc/Zip/Reader.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc\Zip;
|
4 |
+
|
5 |
+
use Nextend\Framework\Misc\Zip\Reader\Custom;
|
6 |
+
use Nextend\Framework\Misc\Zip\Reader\ZipExtension;
|
7 |
+
|
8 |
+
class Reader {
|
9 |
+
|
10 |
+
public static function read($path) {
|
11 |
+
|
12 |
+
if (function_exists('zip_open') && function_exists('zip_read') && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
|
13 |
+
$reader = new ZipExtension();
|
14 |
+
} else {
|
15 |
+
$reader = new Custom();
|
16 |
+
}
|
17 |
+
|
18 |
+
return $reader->read($path);
|
19 |
+
}
|
20 |
+
}
|
Nextend/Framework/Misc/Zip/Reader/Custom.php
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc\Zip\Reader;
|
4 |
+
|
5 |
+
use Nextend\Framework\Misc\Zip\ReaderInterface;
|
6 |
+
use Nextend\Framework\Notification\Notification;
|
7 |
+
|
8 |
+
class Custom implements ReaderInterface {
|
9 |
+
|
10 |
+
private $fileHandle;
|
11 |
+
|
12 |
+
private $file;
|
13 |
+
|
14 |
+
public function read($path) {
|
15 |
+
$this->file = $path;
|
16 |
+
|
17 |
+
return $this->extract();
|
18 |
+
}
|
19 |
+
|
20 |
+
private function extract() {
|
21 |
+
$extractedData = array();
|
22 |
+
|
23 |
+
if (!is_readable(dirname($this->file))) {
|
24 |
+
Notification::error(sprintf(n2_('%s is not readable'), dirname($this->file)));
|
25 |
+
|
26 |
+
return false;
|
27 |
+
}
|
28 |
+
|
29 |
+
if (!$this->file || !is_file($this->file)) return false;
|
30 |
+
$filesize = sprintf('%u', filesize($this->file));
|
31 |
+
|
32 |
+
$this->fileHandle = fopen($this->file, 'rb');
|
33 |
+
|
34 |
+
$EofCentralDirData = $this->_findEOFCentralDirectoryRecord($filesize);
|
35 |
+
if (!is_array($EofCentralDirData)) return false;
|
36 |
+
$centralDirectoryHeaderOffset = $EofCentralDirData['centraldiroffset'];
|
37 |
+
for ($i = 0; $i < $EofCentralDirData['totalentries']; $i++) {
|
38 |
+
rewind($this->fileHandle);
|
39 |
+
fseek($this->fileHandle, $centralDirectoryHeaderOffset);
|
40 |
+
$centralDirectoryData = $this->_readCentralDirectoryData();
|
41 |
+
$centralDirectoryHeaderOffset += 46 + $centralDirectoryData['filenamelength'] + $centralDirectoryData['extrafieldlength'] + $centralDirectoryData['commentlength'];
|
42 |
+
if (!is_array($centralDirectoryData) || substr($centralDirectoryData['filename'], -1) == '/') continue;
|
43 |
+
$data = $this->_readLocalFileHeaderAndData($centralDirectoryData);
|
44 |
+
if (!$data) continue;
|
45 |
+
|
46 |
+
$dir = dirname($centralDirectoryData['filename']);
|
47 |
+
$fileName = basename($centralDirectoryData['filename']);
|
48 |
+
if ($dir != '.' && $dir != '') {
|
49 |
+
if (!isset($extractedData[$dir])) {
|
50 |
+
$extractedData[$dir] = array();
|
51 |
+
}
|
52 |
+
$extractedData[$dir][$fileName] = $data;
|
53 |
+
} else {
|
54 |
+
$extractedData[$fileName] = $data;
|
55 |
+
}
|
56 |
+
}
|
57 |
+
fclose($this->fileHandle);
|
58 |
+
|
59 |
+
return $extractedData;
|
60 |
+
}
|
61 |
+
|
62 |
+
private function _findEOFCentralDirectoryRecord($filesize) {
|
63 |
+
fseek($this->fileHandle, $filesize - 22);
|
64 |
+
$EofCentralDirSignature = unpack('Vsignature', fread($this->fileHandle, 4));
|
65 |
+
if ($EofCentralDirSignature['signature'] != 0x06054b50) {
|
66 |
+
$maxLength = 65535 + 22;
|
67 |
+
$maxLength > $filesize && $maxLength = $filesize;
|
68 |
+
fseek($this->fileHandle, $filesize - $maxLength);
|
69 |
+
$searchPos = ftell($this->fileHandle);
|
70 |
+
while ($searchPos < $filesize) {
|
71 |
+
fseek($this->fileHandle, $searchPos);
|
72 |
+
$sigData = unpack('Vsignature', fread($this->fileHandle, 4));
|
73 |
+
if ($sigData['signature'] == 0x06054b50) {
|
74 |
+
break;
|
75 |
+
}
|
76 |
+
$searchPos++;
|
77 |
+
}
|
78 |
+
}
|
79 |
+
$EofCentralDirData = unpack('vdisknum/vdiskstart/vcentraldirnum/vtotalentries/Vcentraldirsize/Vcentraldiroffset/vcommentlength', fread($this->fileHandle, 18));
|
80 |
+
|
81 |
+
return $EofCentralDirData;
|
82 |
+
}
|
83 |
+
|
84 |
+
private function _readCentralDirectoryData() {
|
85 |
+
$centralDirectorySignature = unpack('Vsignature', fread($this->fileHandle, 4));
|
86 |
+
if ($centralDirectorySignature['signature'] != 0x02014b50) return false;
|
87 |
+
$centralDirectoryData = fread($this->fileHandle, 42);
|
88 |
+
$centralDirectoryData = unpack('vmadeversion/vextractversion/vflag/vcompressmethod/vmodtime/vmoddate/Vcrc/Vcompressedsize/Vuncompressedsize/vfilenamelength/vextrafieldlength/vcommentlength/vdiskstart/vinternal/Vexternal/Vlocalheaderoffset', $centralDirectoryData);
|
89 |
+
$centralDirectoryData['filenamelength'] && $centralDirectoryData['filename'] = fread($this->fileHandle, $centralDirectoryData['filenamelength']);
|
90 |
+
|
91 |
+
return $centralDirectoryData;
|
92 |
+
}
|
93 |
+
|
94 |
+
private function _readLocalFileHeaderAndData($centralDirectoryData) {
|
95 |
+
fseek($this->fileHandle, $centralDirectoryData['localheaderoffset']);
|
96 |
+
$localFileHeaderSignature = unpack('Vsignature', fread($this->fileHandle, 4));
|
97 |
+
if ($localFileHeaderSignature['signature'] != 0x04034b50) return false;
|
98 |
+
$localFileHeaderData = fread($this->fileHandle, 26);
|
99 |
+
$localFileHeaderData = unpack('vextractversion/vflag/vcompressmethod/vmodtime/vmoddate/Vcrc/Vcompressedsize/Vuncompressedsize/vfilenamelength/vextrafieldlength', $localFileHeaderData);
|
100 |
+
$localFileHeaderData['filenamelength'] && $localFileHeaderData['filename'] = fread($this->fileHandle, $localFileHeaderData['filenamelength']);
|
101 |
+
if (!$this->_checkLocalFileHeaderAndCentralDir($localFileHeaderData, $centralDirectoryData)) return false;
|
102 |
+
|
103 |
+
if ($localFileHeaderData['flag'] & 1) return false;
|
104 |
+
$compressedData = fread($this->fileHandle, $localFileHeaderData['compressedsize']);
|
105 |
+
$data = $this->_unCompressData($compressedData, $localFileHeaderData['compressmethod']);
|
106 |
+
|
107 |
+
if (crc32($data) != $localFileHeaderData['crc'] || strlen($data) != $localFileHeaderData['uncompressedsize']) return false;
|
108 |
+
|
109 |
+
return $data;
|
110 |
+
}
|
111 |
+
|
112 |
+
private function _unCompressData($data, $compressMethod) {
|
113 |
+
if (!$compressMethod) return $data;
|
114 |
+
switch ($compressMethod) {
|
115 |
+
case 8 :
|
116 |
+
$data = gzinflate($data);
|
117 |
+
break;
|
118 |
+
default :
|
119 |
+
return false;
|
120 |
+
break;
|
121 |
+
}
|
122 |
+
|
123 |
+
return $data;
|
124 |
+
}
|
125 |
+
|
126 |
+
private function _checkLocalFileHeaderAndCentralDir($localFileHeaderData, $centralDirectoryData) {
|
127 |
+
return true;
|
128 |
+
}
|
129 |
+
}
|
Nextend/Framework/Misc/Zip/Reader/ZipExtension.php
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc\Zip\Reader;
|
4 |
+
|
5 |
+
use Nextend\Framework\Misc\Zip\ReaderInterface;
|
6 |
+
|
7 |
+
class ZipExtension implements ReaderInterface {
|
8 |
+
|
9 |
+
public function read($path) {
|
10 |
+
$zip = zip_open($path);
|
11 |
+
if (!is_resource($zip)) {
|
12 |
+
return array();
|
13 |
+
}
|
14 |
+
$data = array();
|
15 |
+
while ($entry = zip_read($zip)) {
|
16 |
+
|
17 |
+
zip_entry_open($zip, $entry, "r");
|
18 |
+
|
19 |
+
$this->recursiveRead($data, explode('/', zip_entry_name($entry)), zip_entry_read($entry, zip_entry_filesize($entry)));
|
20 |
+
|
21 |
+
zip_entry_close($entry);
|
22 |
+
}
|
23 |
+
|
24 |
+
zip_close($zip);
|
25 |
+
|
26 |
+
return $data;
|
27 |
+
}
|
28 |
+
|
29 |
+
private function recursiveRead(&$data, $parts, $content) {
|
30 |
+
if (count($parts) == 1) {
|
31 |
+
$data[$parts[0]] = $content;
|
32 |
+
} else {
|
33 |
+
if (!isset($data[$parts[0]])) {
|
34 |
+
$data[$parts[0]] = array();
|
35 |
+
}
|
36 |
+
$this->recursiveRead($data[array_shift($parts)], $parts, $content);
|
37 |
+
}
|
38 |
+
}
|
39 |
+
}
|
Nextend/Framework/Misc/Zip/ReaderInterface.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Misc\Zip;
|
4 |
+
|
5 |
+
|
6 |
+
interface ReaderInterface {
|
7 |
+
|
8 |
+
public function read($path);
|
9 |
+
}
|
{nextend/library → Nextend/Framework/Misc}/cacert.pem
RENAMED
File without changes
|
Nextend/Framework/Model/AbstractModel.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Model;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
8 |
+
|
9 |
+
abstract class AbstractModel {
|
10 |
+
|
11 |
+
use MVCHelperTrait;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* AbstractModel constructor.
|
15 |
+
*
|
16 |
+
* @param MVCHelperTrait $helper
|
17 |
+
*/
|
18 |
+
public function __construct($helper) {
|
19 |
+
|
20 |
+
$this->setMVCHelper($helper);
|
21 |
+
$this->init();
|
22 |
+
}
|
23 |
+
|
24 |
+
protected function init() {
|
25 |
+
|
26 |
+
}
|
27 |
+
}
|
Nextend/Framework/Model/AbstractModelTable.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Model;
|
4 |
+
|
5 |
+
|
6 |
+
use Nextend\Framework\Database\AbstractPlatformConnectorTable;
|
7 |
+
|
8 |
+
abstract class AbstractModelTable extends AbstractModel {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var AbstractPlatformConnectorTable
|
12 |
+
*/
|
13 |
+
protected $table;
|
14 |
+
|
15 |
+
protected function init() {
|
16 |
+
|
17 |
+
$this->table = $this->createConnectorTable();
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @return AbstractPlatformConnectorTable
|
22 |
+
*/
|
23 |
+
protected abstract function createConnectorTable();
|
24 |
+
|
25 |
+
public function getTableName() {
|
26 |
+
return $this->table->getTableName();
|
27 |
+
}
|
28 |
+
}
|
Nextend/Framework/Model/ApplicationSection.php
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Model;
|
4 |
+
|
5 |
+
class ApplicationSection {
|
6 |
+
|
7 |
+
private $application = 'system';
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Quick cache implementation to prevent duplicate queries. It might have bugs.
|
11 |
+
*
|
12 |
+
* @var array
|
13 |
+
*/
|
14 |
+
protected $cache = array();
|
15 |
+
|
16 |
+
public function __construct($application) {
|
17 |
+
$this->application = $application;
|
18 |
+
}
|
19 |
+
|
20 |
+
public function getById($id, $section) {
|
21 |
+
return Section::getById($id, $section);
|
22 |
+
}
|
23 |
+
|
24 |
+
public function setById($id, $value) {
|
25 |
+
$this->cache = array();
|
26 |
+
|
27 |
+
return Section::setById($id, $value);
|
28 |
+
}
|
29 |
+
|
30 |
+
public function get($section, $referenceKey = null, $default = null) {
|
31 |
+
|
32 |
+
if (isset($this->cache[$section . '///' . $referenceKey])) {
|
33 |
+
return $this->cache[$section . '///' . $referenceKey];
|
34 |
+
}
|
35 |
+
|
36 |
+
$attributes = array(
|
37 |
+
"application" => $this->application,
|
38 |
+
"section" => $section
|
39 |
+
);
|
40 |
+
|
41 |
+
if ($referenceKey !== null) {
|
42 |
+
$attributes['referencekey'] = $referenceKey;
|
43 |
+
}
|
44 |
+
$result = Section::$tableSectionStorage->findByAttributes($attributes);
|
45 |
+
if (is_array($result)) {
|
46 |
+
$this->cache[$section . '///' . $referenceKey] = $result['value'];
|
47 |
+
|
48 |
+
return $result['value'];
|
49 |
+
}
|
50 |
+
|
51 |
+
return $default;
|
52 |
+
}
|
53 |
+
|
54 |
+
public function getAll($section, $referenceKey = null) {
|
55 |
+
return Section::getAll($this->application, $section, $referenceKey);
|
56 |
+
}
|
57 |
+
|
58 |
+
public function set($section, $referenceKey, $value) {
|
59 |
+
if (isset($this->cache[$section . '///' . $referenceKey])) {
|
60 |
+
unset($this->cache[$section . '///' . $referenceKey]);
|
61 |
+
}
|
62 |
+
|
63 |
+
Section::set($this->application, $section, $referenceKey, $value);
|
64 |
+
}
|
65 |
+
|
66 |
+
public function add($section, $referenceKey, $value) {
|
67 |
+
if (isset($this->cache[$section . '///' . $referenceKey])) {
|
68 |
+
unset($this->cache[$section . '///' . $referenceKey]);
|
69 |
+
}
|
70 |
+
|
71 |
+
return Section::add($this->application, $section, $referenceKey, $value);
|
72 |
+
}
|
73 |
+
|
74 |
+
public function delete($section, $referenceKey = null) {
|
75 |
+
if (isset($this->cache[$section . '///' . $referenceKey])) {
|
76 |
+
unset($this->cache[$section . '///' . $referenceKey]);
|
77 |
+
}
|
78 |
+
|
79 |
+
return Section::delete($this->application, $section, $referenceKey);
|
80 |
+
}
|
81 |
+
|
82 |
+
public function deleteById($id) {
|
83 |
+
return Section::deleteById($id);
|
84 |
+
}
|
85 |
+
}
|
Nextend/Framework/Model/Section.php
ADDED
@@ -0,0 +1,175 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Model;
|
4 |
+
|
5 |
+
use Nextend\Framework\Database\AbstractPlatformConnectorTable;
|
6 |
+
use Nextend\Framework\Database\Database;
|
7 |
+
use Nextend\Framework\Plugin;
|
8 |
+
|
9 |
+
class Section {
|
10 |
+
|
11 |
+
/** @var AbstractPlatformConnectorTable */
|
12 |
+
public static $tableSectionStorage;
|
13 |
+
|
14 |
+
public function __construct() {
|
15 |
+
|
16 |
+
self::$tableSectionStorage = Database::getTable("nextend2_section_storage");
|
17 |
+
}
|
18 |
+
|
19 |
+
public static function get($application, $section, $referenceKey = null) {
|
20 |
+
$attributes = array(
|
21 |
+
"application" => $application,
|
22 |
+
"section" => $section
|
23 |
+
);
|
24 |
+
|
25 |
+
if ($referenceKey !== null) {
|
26 |
+
$attributes['referencekey'] = $referenceKey;
|
27 |
+
}
|
28 |
+
|
29 |
+
return self::$tableSectionStorage->findByAttributes($attributes);
|
30 |
+
}
|
31 |
+
|
32 |
+
public static function getById($id, $section = null) {
|
33 |
+
static $cache = array();
|
34 |
+
if ($id === 0) {
|
35 |
+
return null;
|
36 |
+
}
|
37 |
+
if (!isset($cache[$section])) {
|
38 |
+
$cache[$section] = array();
|
39 |
+
} else if (isset($cache[$section][$id])) {
|
40 |
+
return $cache[$section][$id];
|
41 |
+
}
|
42 |
+
|
43 |
+
$cache[$section][$id] = null;
|
44 |
+
if ($section) {
|
45 |
+
Plugin::doAction($section, array(
|
46 |
+
$id,
|
47 |
+
&$cache[$section][$id]
|
48 |
+
));
|
49 |
+
if ($cache[$section][$id]) {
|
50 |
+
return $cache[$section][$id];
|
51 |
+
}
|
52 |
+
}
|
53 |
+
|
54 |
+
$cache[$section][$id] = self::$tableSectionStorage->findByAttributes(array(
|
55 |
+
"id" => $id
|
56 |
+
));
|
57 |
+
if ($section && $cache[$section][$id]['section'] != $section) {
|
58 |
+
$cache[$section][$id] = null;
|
59 |
+
|
60 |
+
return $cache[$section][$id];
|
61 |
+
}
|
62 |
+
|
63 |
+
return $cache[$section][$id];
|
64 |
+
}
|
65 |
+
|
66 |
+
public static function getAll($application, $section, $referenceKey = null) {
|
67 |
+
$attributes = array(
|
68 |
+
"application" => $application,
|
69 |
+
"section" => $section
|
70 |
+
);
|
71 |
+
|
72 |
+
if ($referenceKey !== null) {
|
73 |
+
$attributes['referencekey'] = $referenceKey;
|
74 |
+
}
|
75 |
+
|
76 |
+
$rows = self::$tableSectionStorage->findAllByAttributes($attributes, array(
|
77 |
+
"id",
|
78 |
+
"referencekey",
|
79 |
+
"value",
|
80 |
+
"system",
|
81 |
+
"editable"
|
82 |
+
));
|
83 |
+
|
84 |
+
Plugin::doAction($application . $section, array(
|
85 |
+
$referenceKey,
|
86 |
+
&$rows
|
87 |
+
));
|
88 |
+
|
89 |
+
return $rows;
|
90 |
+
}
|
91 |
+
|
92 |
+
public static function add($application, $section, $referenceKey, $value, $system = 0, $editable = 1) {
|
93 |
+
$row = array(
|
94 |
+
"application" => $application,
|
95 |
+
"section" => $section,
|
96 |
+
"value" => $value,
|
97 |
+
"system" => $system,
|
98 |
+
"editable" => $editable
|
99 |
+
);
|
100 |
+
|
101 |
+
if ($referenceKey !== null) {
|
102 |
+
$row["referencekey"] = $referenceKey;
|
103 |
+
}
|
104 |
+
|
105 |
+
self::$tableSectionStorage->insert($row);
|
106 |
+
|
107 |
+
return self::$tableSectionStorage->insertId();
|
108 |
+
}
|
109 |
+
|
110 |
+
|
111 |
+
public static function set($application, $section, $referenceKey, $value, $system = 0, $editable = 1) {
|
112 |
+
|
113 |
+
$result = self::getAll($application, $section, $referenceKey);
|
114 |
+
|
115 |
+
if (empty($result)) {
|
116 |
+
return self::add($application, $section, $referenceKey, $value, $system, $editable);
|
117 |
+
} else {
|
118 |
+
$attributes = array(
|
119 |
+
"application" => $application,
|
120 |
+
"section" => $section
|
121 |
+
);
|
122 |
+
|
123 |
+
if ($referenceKey !== null) {
|
124 |
+
$attributes['referencekey'] = $referenceKey;
|
125 |
+
}
|
126 |
+
self::$tableSectionStorage->update(array('value' => $value), $attributes);
|
127 |
+
|
128 |
+
return true;
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
public static function setById($id, $value) {
|
133 |
+
|
134 |
+
$result = self::getById($id);
|
135 |
+
|
136 |
+
if ($result !== null && $result['editable']) {
|
137 |
+
self::$tableSectionStorage->update(array('value' => $value), array(
|
138 |
+
"id" => $id
|
139 |
+
));
|
140 |
+
|
141 |
+
return true;
|
142 |
+
}
|
143 |
+
|
144 |
+
return false;
|
145 |
+
}
|
146 |
+
|
147 |
+
public static function delete($application, $section, $referenceKey = null) {
|
148 |
+
|
149 |
+
$attributes = array(
|
150 |
+
"application" => $application,
|
151 |
+
"section" => $section,
|
152 |
+
"system" => 0
|
153 |
+
);
|
154 |
+
|
155 |
+
if ($referenceKey !== null) {
|
156 |
+
$attributes['referencekey'] = $referenceKey;
|
157 |
+
}
|
158 |
+
|
159 |
+
self::$tableSectionStorage->deleteByAttributes($attributes);
|
160 |
+
|
161 |
+
return true;
|
162 |
+
}
|
163 |
+
|
164 |
+
public static function deleteById($id) {
|
165 |
+
|
166 |
+
self::$tableSectionStorage->deleteByAttributes(array(
|
167 |
+
"id" => $id,
|
168 |
+
"system" => 0
|
169 |
+
));
|
170 |
+
|
171 |
+
return true;
|
172 |
+
}
|
173 |
+
}
|
174 |
+
|
175 |
+
new Section();
|
Nextend/Framework/Model/StorageSectionManager.php
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Model;
|
5 |
+
|
6 |
+
|
7 |
+
class StorageSectionManager {
|
8 |
+
|
9 |
+
/** @var ApplicationSection[] */
|
10 |
+
private static $storageTypes = array();
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @param $type
|
14 |
+
*
|
15 |
+
* @return ApplicationSection
|
16 |
+
*/
|
17 |
+
public static function getStorage($type) {
|
18 |
+
|
19 |
+
if (!isset(self::$storageTypes[$type])) {
|
20 |
+
self::$storageTypes[$type] = new ApplicationSection($type);
|
21 |
+
}
|
22 |
+
|
23 |
+
return self::$storageTypes[$type];
|
24 |
+
}
|
25 |
+
}
|
Nextend/Framework/Notification/Notification.php
ADDED
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Notification;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
use Nextend\Framework\Platform\Platform;
|
7 |
+
use Nextend\Framework\Plugin;
|
8 |
+
use Nextend\Framework\Session\Session;
|
9 |
+
|
10 |
+
class Notification {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var bool|array
|
14 |
+
*/
|
15 |
+
private static $error = false;
|
16 |
+
/**
|
17 |
+
* @var bool|array
|
18 |
+
*/
|
19 |
+
private static $success = false;
|
20 |
+
/**
|
21 |
+
* @var bool|array
|
22 |
+
*/
|
23 |
+
private static $notice = false;
|
24 |
+
|
25 |
+
private static $flushed = false;
|
26 |
+
|
27 |
+
public function __construct() {
|
28 |
+
|
29 |
+
Plugin::addAction('beforeSessionSave', array(
|
30 |
+
'\\Nextend\\Framework\\Notification\\Notification',
|
31 |
+
'storeInSession'
|
32 |
+
));
|
33 |
+
}
|
34 |
+
|
35 |
+
|
36 |
+
private static function loadSessionError() {
|
37 |
+
if (self::$error === false) {
|
38 |
+
if (Platform::isAdmin()) {
|
39 |
+
self::$error = Session::get('error', array());
|
40 |
+
} else {
|
41 |
+
self::$error = array();
|
42 |
+
}
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
private static function loadSessionSuccess() {
|
47 |
+
if (self::$success === false) {
|
48 |
+
if (Platform::isAdmin()) {
|
49 |
+
self::$success = Session::get('success', array());
|
50 |
+
} else {
|
51 |
+
self::$success = array();
|
52 |
+
}
|
53 |
+
}
|
54 |
+
}
|
55 |
+
|
56 |
+
private static function loadSessionNotice() {
|
57 |
+
if (self::$notice === false) {
|
58 |
+
if (Platform::isAdmin()) {
|
59 |
+
self::$notice = Session::get('notice', array());
|
60 |
+
} else {
|
61 |
+
self::$notice = array();
|
62 |
+
}
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
public static function hasErrors() {
|
67 |
+
|
68 |
+
self::loadSessionError();
|
69 |
+
|
70 |
+
return !empty(self::$error);
|
71 |
+
}
|
72 |
+
|
73 |
+
public static function error($message = '', $parameters = array()) {
|
74 |
+
self::loadSessionError();
|
75 |
+
self::$error[] = array(
|
76 |
+
$message,
|
77 |
+
$parameters
|
78 |
+
);
|
79 |
+
}
|
80 |
+
|
81 |
+
public static function displayPlainErrors() {
|
82 |
+
|
83 |
+
if (Platform::isAdmin() && is_array(self::$error) && count(self::$error)) {
|
84 |
+
foreach (self::$error as $error) {
|
85 |
+
echo '<div style="border: 1px solid red; margin-bottom: 20px; padding: 10px 20px; max-width: 400px;">' . $error[0] . '</div>';
|
86 |
+
}
|
87 |
+
self::$error = array();
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
public static function success($message = '', $parameters = array()) {
|
92 |
+
self::loadSessionSuccess();
|
93 |
+
self::$success[] = array(
|
94 |
+
$message,
|
95 |
+
$parameters
|
96 |
+
);
|
97 |
+
}
|
98 |
+
|
99 |
+
public static function notice($message = '', $parameters = array()) {
|
100 |
+
self::loadSessionNotice();
|
101 |
+
self::$notice[] = array(
|
102 |
+
$message,
|
103 |
+
$parameters
|
104 |
+
);
|
105 |
+
}
|
106 |
+
|
107 |
+
public static function show() {
|
108 |
+
|
109 |
+
self::loadSessionError();
|
110 |
+
|
111 |
+
if (is_array(self::$error) && count(self::$error)) {
|
112 |
+
foreach (self::$error as $error) {
|
113 |
+
Js::addInline("N2Classes.Notification.error(" . json_encode($error[0]) . ", " . json_encode($error[1]) . ");");
|
114 |
+
}
|
115 |
+
self::$error = array();
|
116 |
+
}
|
117 |
+
|
118 |
+
self::loadSessionSuccess();
|
119 |
+
|
120 |
+
if (is_array(self::$success) && count(self::$success)) {
|
121 |
+
foreach (self::$success as $success) {
|
122 |
+
|
123 |
+
Js::addInline("N2Classes.Notification.success(" . json_encode($success[0]) . ", " . json_encode($success[1]) . ");");
|
124 |
+
}
|
125 |
+
self::$success = array();
|
126 |
+
}
|
127 |
+
|
128 |
+
self::loadSessionNotice();
|
129 |
+
|
130 |
+
if (is_array(self::$notice) && count(self::$notice)) {
|
131 |
+
foreach (self::$notice as $notice) {
|
132 |
+
|
133 |
+
Js::addInline("N2Classes.Notification.notice(" . json_encode($notice[0]) . ", " . json_encode($notice[1]) . ");");
|
134 |
+
}
|
135 |
+
self::$notice = array();
|
136 |
+
}
|
137 |
+
|
138 |
+
self::$flushed = true;
|
139 |
+
|
140 |
+
}
|
141 |
+
|
142 |
+
public static function showAjax() {
|
143 |
+
|
144 |
+
self::loadSessionError();
|
145 |
+
$messages = array();
|
146 |
+
|
147 |
+
if (is_array(self::$error) && count(self::$error)) {
|
148 |
+
$messages['error'] = array();
|
149 |
+
foreach (self::$error as $error) {
|
150 |
+
$messages['error'][] = $error;
|
151 |
+
}
|
152 |
+
self::$error = array();
|
153 |
+
}
|
154 |
+
|
155 |
+
self::loadSessionSuccess();
|
156 |
+
|
157 |
+
if (is_array(self::$success) && count(self::$success)) {
|
158 |
+
$messages['success'] = array();
|
159 |
+
foreach (self::$success as $success) {
|
160 |
+
$messages['success'][] = $success;
|
161 |
+
}
|
162 |
+
self::$success = array();
|
163 |
+
}
|
164 |
+
|
165 |
+
self::loadSessionNotice();
|
166 |
+
|
167 |
+
if (is_array(self::$notice) && count(self::$notice)) {
|
168 |
+
$messages['notice'] = array();
|
169 |
+
foreach (self::$notice as $notice) {
|
170 |
+
$messages['notice'][] = $notice;
|
171 |
+
}
|
172 |
+
self::$notice = array();
|
173 |
+
}
|
174 |
+
|
175 |
+
self::$flushed = true;
|
176 |
+
if (count($messages)) {
|
177 |
+
return $messages;
|
178 |
+
}
|
179 |
+
|
180 |
+
return false;
|
181 |
+
}
|
182 |
+
|
183 |
+
public static function storeInSession() {
|
184 |
+
if (self::$flushed) {
|
185 |
+
Session::delete('error');
|
186 |
+
Session::delete('success');
|
187 |
+
Session::delete('notice');
|
188 |
+
} else {
|
189 |
+
Session::set('error', self::$error);
|
190 |
+
Session::set('success', self::$success);
|
191 |
+
Session::set('notice', self::$notice);
|
192 |
+
}
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
new Notification();
|
Nextend/Framework/PageFlow.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework;
|
5 |
+
|
6 |
+
|
7 |
+
class PageFlow {
|
8 |
+
|
9 |
+
public static function markApplicationEnd() {
|
10 |
+
|
11 |
+
Plugin::doAction('exit');
|
12 |
+
}
|
13 |
+
|
14 |
+
public static function exitApplication() {
|
15 |
+
|
16 |
+
self::markApplicationEnd();
|
17 |
+
|
18 |
+
exit;
|
19 |
+
}
|
20 |
+
|
21 |
+
public static function cleanOutputBuffers() {
|
22 |
+
$handlers = ob_list_handlers();
|
23 |
+
while (count($handlers) > 0 && $handlers[count($handlers) - 1] != 'ob_gzhandler' && $handlers[count($handlers) - 1] != 'zlib output compression') {
|
24 |
+
ob_end_clean();
|
25 |
+
$handlers = ob_list_handlers();
|
26 |
+
}
|
27 |
+
}
|
28 |
+
}
|
Nextend/Framework/Parser/Color.php
ADDED
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Parser;
|
4 |
+
|
5 |
+
|
6 |
+
/**
|
7 |
+
*
|
8 |
+
* Color values manipulation utilities. Provides methods to convert from and to
|
9 |
+
* Hex, RGB, HSV and HSL color representattions.
|
10 |
+
*
|
11 |
+
* Several color conversion logic are based on pseudo-code from
|
12 |
+
* http://www.easyrgb.com/math.php
|
13 |
+
*
|
14 |
+
* @category Lux
|
15 |
+
*
|
16 |
+
* @package Lux_Color
|
17 |
+
*
|
18 |
+
* @author Rodrigo Moraes <rodrigo.moraes@gmail.com>
|
19 |
+
*
|
20 |
+
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
|
21 |
+
*
|
22 |
+
* @version $Id$
|
23 |
+
*
|
24 |
+
*/
|
25 |
+
class Color {
|
26 |
+
|
27 |
+
public static function colorToRGBA($value) {
|
28 |
+
$rgba = self::hex2rgba($value);
|
29 |
+
|
30 |
+
return 'RGBA(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ')';
|
31 |
+
}
|
32 |
+
|
33 |
+
public static function hex2alpha($value) {
|
34 |
+
if (strlen($value) == 6) {
|
35 |
+
return 127;
|
36 |
+
}
|
37 |
+
|
38 |
+
return intval(hexdec(substr($value, 6, 2)) / 2);
|
39 |
+
}
|
40 |
+
|
41 |
+
public static function hex2opacity($value) {
|
42 |
+
return self::hex2alpha($value) / 127;
|
43 |
+
}
|
44 |
+
|
45 |
+
public static function colorToSVG($value) {
|
46 |
+
$rgba = self::hex2rgba($value);
|
47 |
+
|
48 |
+
return array(
|
49 |
+
substr($value, 0, 6),
|
50 |
+
round($rgba[3] / 127, 2)
|
51 |
+
);
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
*
|
56 |
+
* Converts hexadecimal colors to RGB.
|
57 |
+
*
|
58 |
+
* @param string $hex Hexadecimal value. Accepts values with 3 or 6 numbers,
|
59 |
+
* with or without #, e.g., CCC, #CCC, CCCCCC or #CCCCCC.
|
60 |
+
*
|
61 |
+
* @return array RGB values: 0 => R, 1 => G, 2 => B
|
62 |
+
*
|
63 |
+
*/
|
64 |
+
public static function hex2rgb($hex) {
|
65 |
+
|
66 |
+
|
67 |
+
// Remove #.
|
68 |
+
if (strpos($hex, '#') === 0) {
|
69 |
+
$hex = substr($hex, 1);
|
70 |
+
}
|
71 |
+
if (strlen($hex) == 3) {
|
72 |
+
$hex .= $hex;
|
73 |
+
}
|
74 |
+
if (strlen($hex) != 6) {
|
75 |
+
return false;
|
76 |
+
}
|
77 |
+
|
78 |
+
// Convert each tuple to decimal.
|
79 |
+
$r = hexdec(substr($hex, 0, 2));
|
80 |
+
$g = hexdec(substr($hex, 2, 2));
|
81 |
+
$b = hexdec(substr($hex, 4, 2));
|
82 |
+
|
83 |
+
return array(
|
84 |
+
$r,
|
85 |
+
$g,
|
86 |
+
$b
|
87 |
+
);
|
88 |
+
}
|
89 |
+
|
90 |
+
public static function hex2rgba($hex) {
|
91 |
+
|
92 |
+
|
93 |
+
// Remove #.
|
94 |
+
if (strpos($hex, '#') === 0) {
|
95 |
+
$hex = substr($hex, 1);
|
96 |
+
}
|
97 |
+
if (strlen($hex) == 6) {
|
98 |
+
$hex .= 'ff';
|
99 |
+
}
|
100 |
+
if (strlen($hex) != 8) {
|
101 |
+
return false;
|
102 |
+
}
|
103 |
+
|
104 |
+
// Convert each tuple to decimal.
|
105 |
+
$r = hexdec(substr($hex, 0, 2));
|
106 |
+
$g = hexdec(substr($hex, 2, 2));
|
107 |
+
$b = hexdec(substr($hex, 4, 2));
|
108 |
+
$a = intval(hexdec(substr($hex, 6, 2)) / 2);
|
109 |
+
|
110 |
+
return array(
|
111 |
+
$r,
|
112 |
+
$g,
|
113 |
+
$b,
|
114 |
+
$a
|
115 |
+
);
|
116 |
+
}
|
117 |
+
|
118 |
+
public static function hex82hex($hex) {
|
119 |
+
|
120 |
+
|
121 |
+
// Remove #.
|
122 |
+
if (strpos($hex, '#') === 0) {
|
123 |
+
$hex = substr($hex, 1);
|
124 |
+
}
|
125 |
+
if (strlen($hex) == 6) {
|
126 |
+
$hex .= 'ff';
|
127 |
+
}
|
128 |
+
if (strlen($hex) != 8) {
|
129 |
+
return false;
|
130 |
+
}
|
131 |
+
|
132 |
+
return array(
|
133 |
+
substr($hex, 0, 6),
|
134 |
+
substr($hex, 6, 2)
|
135 |
+
);
|
136 |
+
}
|
137 |
+
|
138 |
+
}
|
Nextend/Framework/Parser/Common.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Parser;
|
4 |
+
|
5 |
+
class Common {
|
6 |
+
|
7 |
+
/**
|
8 |
+
* @param $str
|
9 |
+
* @param bool $concat
|
10 |
+
*
|
11 |
+
* @return array
|
12 |
+
*/
|
13 |
+
public static function parse($str, $concat = false) {
|
14 |
+
|
15 |
+
$v = explode("|*|", $str);
|
16 |
+
for ($i = 0; $i < count($v); $i++) {
|
17 |
+
if (strpos($v[$i], "||") !== false) {
|
18 |
+
if ($concat === false) $v[$i] = explode("||", $v[$i]); else $v[$i] = str_replace("||", $concat, $v[$i]);
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
+
return count($v) == 1 ? $v[0] : $v;
|
23 |
+
}
|
24 |
+
}
|
Nextend/Framework/Parser/Font.php
ADDED
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Parser;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Fonts\Google\Google;
|
6 |
+
|
7 |
+
class Font {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @var array
|
11 |
+
*/
|
12 |
+
private $_font;
|
13 |
+
|
14 |
+
public function __construct($font) {
|
15 |
+
$this->_font = json_decode($font, true);
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @param string $tab
|
20 |
+
*
|
21 |
+
* @return string
|
22 |
+
*/
|
23 |
+
public function printTab($tab = '') {
|
24 |
+
if ($tab == '') $tab = $this->_font['firsttab'];
|
25 |
+
$style = '';
|
26 |
+
if (isset($this->_font[$tab])) {
|
27 |
+
$tab = &$this->_font[$tab];
|
28 |
+
$extra = '';
|
29 |
+
if (isset($tab['extra'])) {
|
30 |
+
$extra = $tab['extra'];
|
31 |
+
unset($tab['extra']);
|
32 |
+
}
|
33 |
+
foreach ($tab AS $k => $v) {
|
34 |
+
$style .= $this->parse($k, $v);
|
35 |
+
}
|
36 |
+
$style .= $this->parse('extra', $extra);
|
37 |
+
}
|
38 |
+
|
39 |
+
return $style;
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* @param $target
|
44 |
+
* @param string $source
|
45 |
+
*/
|
46 |
+
public function mixinTab($target, $source = '') {
|
47 |
+
if ($source == '') $source = $this->_font['firsttab'];
|
48 |
+
$this->_font[$target] = array_merge($this->_font[$source], $this->_font[$target]);
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* @param $property
|
53 |
+
* @param $value
|
54 |
+
*
|
55 |
+
* @return mixed
|
56 |
+
*/
|
57 |
+
public function parse($property, $value) {
|
58 |
+
$fn = 'parse' . $property;
|
59 |
+
|
60 |
+
return $this->$fn($value);
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* @param $v
|
65 |
+
*
|
66 |
+
* @return string
|
67 |
+
*/
|
68 |
+
public function parseColor($v) {
|
69 |
+
|
70 |
+
$hex = Color::hex82hex($v);
|
71 |
+
|
72 |
+
if ($hex[1] == 'ff') {
|
73 |
+
return 'color: #' . $hex[0] . ';';
|
74 |
+
}
|
75 |
+
|
76 |
+
$rgba = Color::hex2rgba($v);
|
77 |
+
|
78 |
+
return 'color: RGBA(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ');';
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* @param $v
|
83 |
+
*
|
84 |
+
* @return string
|
85 |
+
*/
|
86 |
+
public function parseSize($v) {
|
87 |
+
return 'font-size:' . Common::parse($v, '') . ';';
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* @param $v
|
92 |
+
*
|
93 |
+
* @return string
|
94 |
+
*/
|
95 |
+
public function parseTShadow($v) {
|
96 |
+
$v = Common::parse($v);
|
97 |
+
$rgba = Color::hex2rgba($v[3]);
|
98 |
+
if ($v[0] == 0 && $v[1] == 0 && $v[2] == 0) return 'text-shadow: none;';
|
99 |
+
|
100 |
+
return 'text-shadow: ' . $v[0] . 'px ' . $v[1] . 'px ' . $v[2] . 'px RGBA(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ');';
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* @param $v
|
105 |
+
*
|
106 |
+
* @return string
|
107 |
+
*/
|
108 |
+
public function parseAfont($v) {
|
109 |
+
return 'font-family: ' . $this->loadFont($v) . ';';
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* @param $v
|
114 |
+
*
|
115 |
+
* @return string
|
116 |
+
*/
|
117 |
+
public function parseLineHeight($v) {
|
118 |
+
if ($v == '') return '';
|
119 |
+
|
120 |
+
return 'line-height: ' . $v . ';';
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* @param $v
|
125 |
+
*
|
126 |
+
* @return string
|
127 |
+
*/
|
128 |
+
public function parseBold($v) {
|
129 |
+
if ($v == '1') return 'font-weight: bold;';
|
130 |
+
|
131 |
+
return 'font-weight: normal;';
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* @param $v
|
136 |
+
*
|
137 |
+
* @return string
|
138 |
+
*/
|
139 |
+
public function parseItalic($v) {
|
140 |
+
if ($v == '1') return 'font-style: italic;';
|
141 |
+
|
142 |
+
return 'font-style: normal;';
|
143 |
+
}
|
144 |
+
|
145 |
+
/**
|
146 |
+
* @param $v
|
147 |
+
*
|
148 |
+
* @return string
|
149 |
+
*/
|
150 |
+
public function parseUnderline($v) {
|
151 |
+
if ($v == '1') return 'text-decoration: underline;';
|
152 |
+
|
153 |
+
return 'text-decoration: none;';
|
154 |
+
}
|
155 |
+
|
156 |
+
/**
|
157 |
+
* @param $v
|
158 |
+
*
|
159 |
+
* @return string
|
160 |
+
*/
|
161 |
+
public function parsePaddingLeft($v) {
|
162 |
+
return '';
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* @param $v
|
167 |
+
*
|
168 |
+
* @return string
|
169 |
+
*/
|
170 |
+
public function parseAlign($v) {
|
171 |
+
return 'text-align: ' . $v . ';';
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* @param $v
|
176 |
+
*
|
177 |
+
* @return string
|
178 |
+
*/
|
179 |
+
public function parseReset($v) {
|
180 |
+
return '';
|
181 |
+
}
|
182 |
+
|
183 |
+
public function parseExtra($v) {
|
184 |
+
return $v;
|
185 |
+
}
|
186 |
+
|
187 |
+
/**
|
188 |
+
* @param $families
|
189 |
+
*
|
190 |
+
* @return mixed
|
191 |
+
*/
|
192 |
+
public function loadFont($families) {
|
193 |
+
preg_match_all("/google\(.*?family=(.*?)\);\)/", $families, $out, PREG_SET_ORDER);
|
194 |
+
foreach ($out AS $f) {
|
195 |
+
preg_match('/(.*?)(:(.*?))?(&subset=(.*))?$/', $f[1], $g);
|
196 |
+
$family = str_replace('+', ' ', $g[1]);
|
197 |
+
$styles = 400;
|
198 |
+
if (isset($g[3]) && !empty($g[3])) {
|
199 |
+
$styles = $g[3];
|
200 |
+
}
|
201 |
+
$subset = 'latin';
|
202 |
+
if (isset($g[5])) {
|
203 |
+
$subset = $g[5];
|
204 |
+
}
|
205 |
+
Google::addSubset($subset);
|
206 |
+
foreach (explode(',', $styles) AS $style) {
|
207 |
+
Google::addFont($family, $style);
|
208 |
+
}
|
209 |
+
$families = str_replace($f[0], "'" . $family . "'", $families);
|
210 |
+
}
|
211 |
+
|
212 |
+
return $families;
|
213 |
+
}
|
214 |
+
}
|
Nextend/Framework/Parser/Link.php
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Parser;
|
4 |
+
|
5 |
+
use Nextend\Framework\Parser\Link\ParserInterface;
|
6 |
+
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
|
7 |
+
|
8 |
+
class Link {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var ParserInterface[]
|
12 |
+
*/
|
13 |
+
private static $parsers = array();
|
14 |
+
|
15 |
+
public static $registeredNamespaces = array(
|
16 |
+
'\\Nextend\\Framework\\Parser\\Link\\',
|
17 |
+
'\\Nextend\\SmartSlider3\\Parser\\Link\\'
|
18 |
+
);
|
19 |
+
|
20 |
+
public static function parse($url, &$attributes, $isEditor = false) {
|
21 |
+
if ($url == '#' || $isEditor) {
|
22 |
+
$attributes['onclick'] = "return false;";
|
23 |
+
} else {
|
24 |
+
preg_match('/^([a-zA-Z]+)\[(.*)]$/', $url, $matches);
|
25 |
+
if (!empty($matches)) {
|
26 |
+
$matches[1] = ucfirst($matches[1]);
|
27 |
+
$parser = self::getParser($matches[1]);
|
28 |
+
if ($parser) {
|
29 |
+
$url = $parser->parse($matches[2], $attributes);
|
30 |
+
}
|
31 |
+
} else {
|
32 |
+
$url = ResourceTranslator::toUrl($url);
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
return $url;
|
37 |
+
}
|
38 |
+
|
39 |
+
public static function getParser($className) {
|
40 |
+
if (!isset(self::$parsers[$className])) {
|
41 |
+
|
42 |
+
foreach (self::$registeredNamespaces AS $namespace) {
|
43 |
+
$class = $namespace . $className;
|
44 |
+
if (class_exists($class)) {
|
45 |
+
self::$parsers[$className] = new $class();
|
46 |
+
break;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
if (!isset(self::$parsers[$className])) {
|
50 |
+
self::$parsers[$className] = false;
|
51 |
+
}
|
52 |
+
}
|
53 |
+
|
54 |
+
return self::$parsers[$className];
|
55 |
+
}
|
56 |
+
}
|
Nextend/Framework/Parser/Link/ParserInterface.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Parser\Link;
|
4 |
+
|
5 |
+
interface ParserInterface {
|
6 |
+
|
7 |
+
public function parse($argument, &$attributes);
|
8 |
+
}
|
Nextend/Framework/Parser/Link/ScrollTo.php
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Parser\Link;
|
4 |
+
|
5 |
+
use Nextend\Framework\Asset\Js\Js;
|
6 |
+
use Nextend\SmartSlider3\Settings;
|
7 |
+
|
8 |
+
class ScrollTo implements ParserInterface {
|
9 |
+
|
10 |
+
public function __construct() {
|
11 |
+
|
12 |
+
Js::addInline('window.n2ScrollSpeed=' . json_encode(intval(Settings::get('smooth-scroll-speed', 400))) . ';');
|
13 |
+
}
|
14 |
+
|
15 |
+
public function parse($argument, &$attributes) {
|
16 |
+
|
17 |
+
switch ($argument) {
|
18 |
+
case 'top':
|
19 |
+
$onclick = 'n2ss.scroll(event, "top");';
|
20 |
+
break;
|
21 |
+
case 'bottom':
|
22 |
+
$onclick = 'n2ss.scroll(event, "bottom");';
|
23 |
+
break;
|
24 |
+
case 'beforeSlider':
|
25 |
+
$onclick = 'n2ss.scroll(event, "before", N2Classes.$(this).closest(".n2-ss-slider").addBack());';
|
26 |
+
break;
|
27 |
+
case 'afterSlider':
|
28 |
+
$onclick = 'n2ss.scroll(event, "after", N2Classes.$(this).closest(".n2-ss-slider").addBack());';
|
29 |
+
break;
|
30 |
+
case 'nextSlider':
|
31 |
+
$onclick = 'n2ss.scroll(event, "next", this, ".n2-ss-slider");';
|
32 |
+
break;
|
33 |
+
case 'previousSlider':
|
34 |
+
$onclick = 'n2ss.scroll(event, "previous", this, ".n2-ss-slider");';
|
35 |
+
break;
|
36 |
+
default:
|
37 |
+
if (is_numeric($argument)) {
|
38 |
+
$onclick = 'n2ss.scroll(event, "element", "#n2-ss-' . $argument . '");';
|
39 |
+
} else {
|
40 |
+
$onclick = 'n2ss.scroll(event, "element", "' . $argument . '");';
|
41 |
+
}
|
42 |
+
break;
|
43 |
+
}
|
44 |
+
$attributes['onclick'] = $onclick;
|
45 |
+
|
46 |
+
return '#';
|
47 |
+
}
|
48 |
+
}
|
Nextend/Framework/Parser/Link/ScrollToAlias.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Parser\Link;
|
4 |
+
|
5 |
+
use Nextend\Framework\Parser\Link;
|
6 |
+
|
7 |
+
class ScrollToAlias implements ParserInterface {
|
8 |
+
|
9 |
+
public function parse($argument, &$attributes) {
|
10 |
+
|
11 |
+
return Link::getParser('ScrollTo')
|
12 |
+
->parse('[data-alias=\"' . $argument . '\"]', $attributes);
|
13 |
+
}
|
14 |
+
}
|
Nextend/Framework/Parser/Style.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Parser;
|
4 |
+
|
5 |
+
use Nextend\Framework\Misc\Base64;
|
6 |
+
|
7 |
+
class Style {
|
8 |
+
|
9 |
+
private $_style;
|
10 |
+
|
11 |
+
public function __construct($style) {
|
12 |
+
$decoded = $style;
|
13 |
+
if ($decoded[0] != '{') {
|
14 |
+
$decoded = Base64::decode($decoded);
|
15 |
+
}
|
16 |
+
|
17 |
+
$this->_style = json_decode($decoded, true);
|
18 |
+
}
|
19 |
+
|
20 |
+
public function printTab($tab = '') {
|
21 |
+
$style = '';
|
22 |
+
if (isset($this->_style[$tab])) {
|
23 |
+
$tab = &$this->_style[$tab];
|
24 |
+
$extra = '';
|
25 |
+
if (isset($tab['extra'])) {
|
26 |
+
$extra = $tab['extra'];
|
27 |
+
unset($tab['extra']);
|
28 |
+
}
|
29 |
+
foreach ($tab AS $k => $v) {
|
30 |
+
$style .= $this->parse($k, $v);
|
31 |
+
}
|
32 |
+
$style .= $this->parse('extra', $extra);
|
33 |
+
}
|
34 |
+
|
35 |
+
return $style;
|
36 |
+
}
|
37 |
+
|
38 |
+
public function parse($property, $value) {
|
39 |
+
$fn = 'parse' . $property;
|
40 |
+
|
41 |
+
return $this->$fn($value);
|
42 |
+
}
|
43 |
+
|
44 |
+
public function parseBackgroundColor($v) {
|
45 |
+
$hex = Color::hex82hex($v);
|
46 |
+
if ($hex[1] == 'ff') {
|
47 |
+
return 'background: #' . $hex[0] . ';';
|
48 |
+
}
|
49 |
+
|
50 |
+
$rgba = Color::hex2rgba($v);
|
51 |
+
|
52 |
+
return 'background: RGBA(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ');';
|
53 |
+
}
|
54 |
+
|
55 |
+
public function parsePadding($v) {
|
56 |
+
$padding = explode('|*|', $v);
|
57 |
+
$unit = array_pop($padding);
|
58 |
+
$padding[] = '';
|
59 |
+
|
60 |
+
return 'padding:' . implode($unit . ' ', $padding) . ';';
|
61 |
+
}
|
62 |
+
|
63 |
+
public function parseBoxShadow($v) {
|
64 |
+
$boxShadow = explode('|*|', $v);
|
65 |
+
|
66 |
+
if ($boxShadow[0] == '0' && $boxShadow[1] == '0' && $boxShadow[2] == '0' && $boxShadow[3] == '0') {
|
67 |
+
return 'box-shadow: none;';
|
68 |
+
} else {
|
69 |
+
$rgba = Color::hex2rgba($boxShadow[4]);
|
70 |
+
|
71 |
+
return 'box-shadow: ' . $boxShadow[0] . 'px ' . $boxShadow[1] . 'px ' . $boxShadow[2] . 'px ' . $boxShadow[3] . 'px RGBA(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ');';
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
public function parseBorder($v) {
|
76 |
+
$border = explode('|*|', $v);
|
77 |
+
$style = 'border-width: ' . $border[0] . 'px';
|
78 |
+
$style .= 'border-style: ' . $border[1] . ';';
|
79 |
+
$rgba = Color::hex2rgba($border[2]);
|
80 |
+
$style .= 'border-color: #' . substr($border[2], 0, 6) . "; border-color: RGBA(" . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ');';
|
81 |
+
|
82 |
+
return $style;
|
83 |
+
}
|
84 |
+
|
85 |
+
public function parseBorderRadius($v) {
|
86 |
+
$radius = explode('|*|', $v);
|
87 |
+
$radius[] = '';
|
88 |
+
|
89 |
+
return 'border-radius:' . $v . 'px;';
|
90 |
+
}
|
91 |
+
|
92 |
+
public function parseExtra($v) {
|
93 |
+
return str_replace("\n", '', $v);
|
94 |
+
}
|
95 |
+
}
|
Nextend/Framework/Pattern/GetAssetsPathTrait.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Pattern;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Platform\Platform;
|
8 |
+
use Nextend\Framework\Url\Url;
|
9 |
+
|
10 |
+
trait GetAssetsPathTrait {
|
11 |
+
|
12 |
+
use GetPathTrait;
|
13 |
+
|
14 |
+
public static function getAssetsPath() {
|
15 |
+
|
16 |
+
return Platform::filterAssetsPath(self::getPath() . '/Assets');
|
17 |
+
}
|
18 |
+
|
19 |
+
public static function getAssetsUri() {
|
20 |
+
return Url::pathToUri(self::getAssetsPath());
|
21 |
+
}
|
22 |
+
}
|
Nextend/Framework/Pattern/GetPathTrait.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Pattern;
|
4 |
+
|
5 |
+
use ReflectionClass;
|
6 |
+
|
7 |
+
trait GetPathTrait {
|
8 |
+
|
9 |
+
public static function getPath() {
|
10 |
+
|
11 |
+
$reflection = new ReflectionClass(static::class);
|
12 |
+
|
13 |
+
return dirname($reflection->getFileName());
|
14 |
+
}
|
15 |
+
}
|
Nextend/Framework/Pattern/MVCHelperTrait.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Pattern;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Application\AbstractApplication;
|
8 |
+
use Nextend\Framework\Application\AbstractApplicationType;
|
9 |
+
use Nextend\Framework\Router\Router;
|
10 |
+
|
11 |
+
trait MVCHelperTrait {
|
12 |
+
|
13 |
+
/** @var MVCHelperTrait */
|
14 |
+
protected $MVCHelper;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @return Router
|
18 |
+
*/
|
19 |
+
public function getRouter() {
|
20 |
+
return $this->MVCHelper->getRouter();
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @param array|string $url
|
25 |
+
* @param bool $isPost
|
26 |
+
* @param bool $isAjax
|
27 |
+
*
|
28 |
+
* @return string
|
29 |
+
*/
|
30 |
+
public function createUrl($url, $isPost = false, $isAjax = false) {
|
31 |
+
return $this->MVCHelper->getRouter()
|
32 |
+
->createUrl($url, $isPost, $isAjax);
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @param array|string $url
|
37 |
+
*
|
38 |
+
* @return string
|
39 |
+
*/
|
40 |
+
public function createAjaxUrl($url) {
|
41 |
+
return $this->MVCHelper->getRouter()
|
42 |
+
->createAjaxUrl($url);
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @return AbstractApplication
|
47 |
+
*/
|
48 |
+
public function getApplication() {
|
49 |
+
|
50 |
+
return $this->MVCHelper->getApplication();
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @return AbstractApplicationType
|
55 |
+
*/
|
56 |
+
public function getApplicationType() {
|
57 |
+
return $this->MVCHelper->getApplicationType();
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @param MVCHelperTrait $helper
|
62 |
+
*
|
63 |
+
*/
|
64 |
+
protected function setMVCHelper($helper) {
|
65 |
+
$this->MVCHelper = $helper;
|
66 |
+
|
67 |
+
if (!method_exists($helper, 'getRouter') || !method_exists($helper, 'getApplication') || !method_exists($helper, 'getApplicationType')) {
|
68 |
+
debug_print_backtrace();
|
69 |
+
echo 'Object should has MVCHelperTrait';
|
70 |
+
exit;
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* @return MVCHelperTrait
|
76 |
+
*/
|
77 |
+
public function getMVCHelper() {
|
78 |
+
return $this->MVCHelper;
|
79 |
+
}
|
80 |
+
}
|
Nextend/Framework/Pattern/OrderableTrait.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Pattern;
|
4 |
+
|
5 |
+
trait OrderableTrait {
|
6 |
+
|
7 |
+
protected $ordering = 1000000;
|
8 |
+
|
9 |
+
public function getOrdering() {
|
10 |
+
return $this->ordering;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @param OrderableTrait[] $items
|
15 |
+
*/
|
16 |
+
public static function uasort(&$items) {
|
17 |
+
uasort($items, array(
|
18 |
+
OrderableTrait::class,
|
19 |
+
'compare'
|
20 |
+
));
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @param OrderableTrait $a
|
25 |
+
* @param OrderableTrait $b
|
26 |
+
*
|
27 |
+
* @return int
|
28 |
+
*/
|
29 |
+
public static function compare($a, $b) {
|
30 |
+
return $a->getOrdering() - $b->getOrdering();
|
31 |
+
}
|
32 |
+
}
|
Nextend/Framework/Pattern/PluggableFactoryTrait.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Pattern;
|
4 |
+
|
5 |
+
trait PluggableFactoryTrait {
|
6 |
+
|
7 |
+
use SingletonTrait;
|
8 |
+
|
9 |
+
private static $types = array();
|
10 |
+
|
11 |
+
public static function addType($name, $className) {
|
12 |
+
self::$types[$name] = $className;
|
13 |
+
}
|
14 |
+
|
15 |
+
public static function getType($name) {
|
16 |
+
|
17 |
+
if (isset(self::$types[$name])) {
|
18 |
+
return self::$types[$name];
|
19 |
+
}
|
20 |
+
|
21 |
+
return false;
|
22 |
+
}
|
23 |
+
|
24 |
+
public static function getTypes() {
|
25 |
+
|
26 |
+
return self::$types;
|
27 |
+
}
|
28 |
+
}
|
Nextend/Framework/Pattern/PluggableTrait.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Pattern;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Plugin;
|
8 |
+
|
9 |
+
trait PluggableTrait {
|
10 |
+
|
11 |
+
protected function makePluggable($id) {
|
12 |
+
|
13 |
+
Plugin::doAction('PluggableFactory' . $id, array($this));
|
14 |
+
}
|
15 |
+
}
|
Nextend/Framework/Pattern/SingletonTrait.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Pattern;
|
5 |
+
|
6 |
+
|
7 |
+
trait SingletonTrait {
|
8 |
+
|
9 |
+
protected static $instance;
|
10 |
+
|
11 |
+
final public static function getInstance() {
|
12 |
+
return isset(static::$instance) ? static::$instance : static::$instance = new static;
|
13 |
+
}
|
14 |
+
|
15 |
+
final private function __construct() {
|
16 |
+
$this->init();
|
17 |
+
}
|
18 |
+
|
19 |
+
protected function init() {
|
20 |
+
}
|
21 |
+
|
22 |
+
final private function __wakeup() {
|
23 |
+
}
|
24 |
+
|
25 |
+
final private function __clone() {
|
26 |
+
}
|
27 |
+
}
|
Nextend/Framework/Pattern/VisualManagerTrait.php
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Pattern;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Plugin;
|
8 |
+
|
9 |
+
trait VisualManagerTrait {
|
10 |
+
|
11 |
+
/** @var MVCHelperTrait */
|
12 |
+
protected $MVCHelper;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* StyleManager constructor.
|
16 |
+
*
|
17 |
+
* @param MVCHelperTrait $MVCHelper
|
18 |
+
*/
|
19 |
+
public function __construct($MVCHelper) {
|
20 |
+
$this->MVCHelper = $MVCHelper;
|
21 |
+
|
22 |
+
Plugin::addAction('afterApplicationContent', array(
|
23 |
+
$this,
|
24 |
+
'display'
|
25 |
+
));
|
26 |
+
}
|
27 |
+
|
28 |
+
public abstract function display();
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @param MVCHelperTrait $MVCHelper
|
32 |
+
*/
|
33 |
+
public static function enqueue($MVCHelper) {
|
34 |
+
static $enqueued;
|
35 |
+
|
36 |
+
if (!$enqueued) {
|
37 |
+
new self($MVCHelper);
|
38 |
+
$enqueued = true;
|
39 |
+
}
|
40 |
+
}
|
41 |
+
}
|
Nextend/Framework/Platform/AbstractPlatform.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Platform;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Pattern\GetAssetsPathTrait;
|
8 |
+
|
9 |
+
abstract class AbstractPlatform {
|
10 |
+
|
11 |
+
use GetAssetsPathTrait;
|
12 |
+
|
13 |
+
protected $isAdmin = false;
|
14 |
+
|
15 |
+
protected $hasPosts = false;
|
16 |
+
|
17 |
+
public function isAdmin() {
|
18 |
+
|
19 |
+
return $this->isAdmin;
|
20 |
+
}
|
21 |
+
|
22 |
+
public function setIsAdmin($isAdmin){
|
23 |
+
$this->isAdmin = $isAdmin;
|
24 |
+
}
|
25 |
+
|
26 |
+
public abstract function getName();
|
27 |
+
|
28 |
+
public abstract function getLabel();
|
29 |
+
|
30 |
+
public abstract function getVersion();
|
31 |
+
|
32 |
+
public function hasPosts() {
|
33 |
+
return $this->hasPosts;
|
34 |
+
}
|
35 |
+
|
36 |
+
public abstract function getSiteUrl();
|
37 |
+
|
38 |
+
public function getCharset() {
|
39 |
+
return 'UTF-8';
|
40 |
+
}
|
41 |
+
|
42 |
+
public function getMysqlDate() {
|
43 |
+
return date("Y-m-d H:i:s");
|
44 |
+
}
|
45 |
+
|
46 |
+
public function getTimestamp() {
|
47 |
+
|
48 |
+
return time();
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* @return string
|
53 |
+
*/
|
54 |
+
public abstract function getPublicDirectory();
|
55 |
+
|
56 |
+
public function getUserEmail() {
|
57 |
+
|
58 |
+
return '';
|
59 |
+
}
|
60 |
+
|
61 |
+
public function needStrongerCss() {
|
62 |
+
|
63 |
+
return false;
|
64 |
+
}
|
65 |
+
|
66 |
+
public function getDebug() {
|
67 |
+
|
68 |
+
return array();
|
69 |
+
}
|
70 |
+
|
71 |
+
public function filterAssetsPath($assetsPath) {
|
72 |
+
|
73 |
+
return $assetsPath;
|
74 |
+
}
|
75 |
+
}
|
Nextend/Framework/Platform/Platform.php
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Platform;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
8 |
+
|
9 |
+
class Platform {
|
10 |
+
|
11 |
+
use SingletonTrait;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var AbstractPlatform
|
15 |
+
*/
|
16 |
+
private static $platform;
|
17 |
+
|
18 |
+
public function __construct() {
|
19 |
+
self::$platform = new WordPress\PlatformWordPress();
|
20 |
+
}
|
21 |
+
|
22 |
+
public static function getName() {
|
23 |
+
return self::$platform->getName();
|
24 |
+
}
|
25 |
+
|
26 |
+
public static function getLabel() {
|
27 |
+
return self::$platform->getLabel();
|
28 |
+
}
|
29 |
+
|
30 |
+
public static function getVersion() {
|
31 |
+
return self::$platform->getVersion();
|
32 |
+
}
|
33 |
+
|
34 |
+
public static function isAdmin() {
|
35 |
+
return self::$platform->isAdmin();
|
36 |
+
}
|
37 |
+
|
38 |
+
public static function setIsAdmin($isAdmin) {
|
39 |
+
self::$platform->setIsAdmin($isAdmin);
|
40 |
+
}
|
41 |
+
|
42 |
+
public static function hasPosts() {
|
43 |
+
return self::$platform->hasPosts();
|
44 |
+
}
|
45 |
+
|
46 |
+
public static function getSiteUrl() {
|
47 |
+
return self::$platform->getSiteUrl();
|
48 |
+
}
|
49 |
+
|
50 |
+
public static function getCharset() {
|
51 |
+
return self::$platform->getCharset();
|
52 |
+
}
|
53 |
+
|
54 |
+
public static function getMysqlDate() {
|
55 |
+
return self::$platform->getMysqlDate();
|
56 |
+
}
|
57 |
+
|
58 |
+
public static function getTimestamp() {
|
59 |
+
return self::$platform->getTimestamp();
|
60 |
+
}
|
61 |
+
|
62 |
+
public static function getPublicDirectory() {
|
63 |
+
return self::$platform->getPublicDirectory();
|
64 |
+
}
|
65 |
+
|
66 |
+
public static function getUserEmail() {
|
67 |
+
return self::$platform->getUserEmail();
|
68 |
+
}
|
69 |
+
|
70 |
+
public static function needStrongerCss() {
|
71 |
+
return self::$platform->needStrongerCss();
|
72 |
+
}
|
73 |
+
|
74 |
+
public static function getDebug() {
|
75 |
+
|
76 |
+
return self::$platform->getDebug();
|
77 |
+
}
|
78 |
+
|
79 |
+
public static function filterAssetsPath($assetsPath) {
|
80 |
+
|
81 |
+
return self::$platform->filterAssetsPath($assetsPath);
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
Platform::getInstance();
|
Nextend/Framework/Platform/WordPress/PlatformWordPress.php
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Platform\WordPress;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
8 |
+
use Nextend\Framework\Platform\AbstractPlatform;
|
9 |
+
use Nextend\Framework\Url\Url;
|
10 |
+
|
11 |
+
class PlatformWordPress extends AbstractPlatform {
|
12 |
+
|
13 |
+
protected $hasPosts = true;
|
14 |
+
|
15 |
+
public function __construct() {
|
16 |
+
|
17 |
+
if (is_admin()) {
|
18 |
+
$this->isAdmin = true;
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
+
public function getName() {
|
23 |
+
|
24 |
+
return 'wordpress';
|
25 |
+
}
|
26 |
+
|
27 |
+
public function getLabel() {
|
28 |
+
|
29 |
+
return 'WordPress';
|
30 |
+
}
|
31 |
+
|
32 |
+
public function getVersion() {
|
33 |
+
global $wp_version;
|
34 |
+
|
35 |
+
return $wp_version;
|
36 |
+
}
|
37 |
+
|
38 |
+
public function getSiteUrl() {
|
39 |
+
|
40 |
+
return str_replace(array(
|
41 |
+
'http://',
|
42 |
+
'https://'
|
43 |
+
), '//', site_url('/'));
|
44 |
+
}
|
45 |
+
|
46 |
+
public function getCharset() {
|
47 |
+
|
48 |
+
return get_option('blog_charset');
|
49 |
+
}
|
50 |
+
|
51 |
+
public function getMysqlDate() {
|
52 |
+
|
53 |
+
return current_time('mysql');
|
54 |
+
}
|
55 |
+
|
56 |
+
public function getTimestamp() {
|
57 |
+
|
58 |
+
return current_time('timestamp');
|
59 |
+
}
|
60 |
+
|
61 |
+
public function filterAssetsPath($assetsPath) {
|
62 |
+
|
63 |
+
return str_replace(SMARTSLIDER3_LIBRARY_PATH, NEXTEND_SMARTSLIDER_3 . 'Public', $assetsPath);
|
64 |
+
}
|
65 |
+
|
66 |
+
public function getPublicDirectory() {
|
67 |
+
|
68 |
+
$upload_dir = wp_upload_dir();
|
69 |
+
|
70 |
+
if (!stream_is_local($upload_dir['basedir'])) {
|
71 |
+
return $upload_dir['basedir'];
|
72 |
+
}
|
73 |
+
|
74 |
+
return Filesystem::convertToRealDirectorySeparator(str_replace('//', '/', $upload_dir['basedir']));
|
75 |
+
}
|
76 |
+
|
77 |
+
public function getUserEmail() {
|
78 |
+
|
79 |
+
return wp_get_current_user()->user_email;
|
80 |
+
}
|
81 |
+
|
82 |
+
public function needStrongerCss() {
|
83 |
+
|
84 |
+
/**
|
85 |
+
* If Divi plugin installed without Divi theme we must use stronger CSS selectors
|
86 |
+
*/
|
87 |
+
if (!$this->isAdmin() && function_exists('et_is_builder_plugin_active') && et_is_builder_plugin_active()) {
|
88 |
+
return true;
|
89 |
+
}
|
90 |
+
|
91 |
+
return false;
|
92 |
+
}
|
93 |
+
|
94 |
+
public function getDebug() {
|
95 |
+
$debug = array('');
|
96 |
+
|
97 |
+
|
98 |
+
$debug[] = 'Path to uri:';
|
99 |
+
$uris = Url::getUris();
|
100 |
+
$paths = Filesystem::getPaths();
|
101 |
+
foreach ($uris as $i => $uri) {
|
102 |
+
$debug[] = $paths[$i] . ' => ' . $uri;
|
103 |
+
}
|
104 |
+
|
105 |
+
$debug[] = '';
|
106 |
+
$debug[] = 'wp_upload_dir() => ';
|
107 |
+
foreach (wp_upload_dir() as $k => $v) {
|
108 |
+
$debug[] = $k . ': ' . $v;
|
109 |
+
}
|
110 |
+
$debug[] = '<=';
|
111 |
+
$debug[] = '';
|
112 |
+
|
113 |
+
$theme = wp_get_theme();
|
114 |
+
$parentTheme = $theme->parent();
|
115 |
+
if ($parentTheme) {
|
116 |
+
$debug[] = 'Parent theme: ' . $theme->get('Name') . " is version " . $theme->get('Version');
|
117 |
+
}
|
118 |
+
$debug[] = 'Theme: ' . $theme->get('Name') . " is version " . $theme->get('Version');
|
119 |
+
|
120 |
+
|
121 |
+
$plugins = get_plugins();
|
122 |
+
$notActive = array();
|
123 |
+
|
124 |
+
$debug[] = '';
|
125 |
+
$debug[] = 'Activated Plugins:';
|
126 |
+
foreach ($plugins as $plugin => $pluginData) {
|
127 |
+
if (is_plugin_active($plugin)) {
|
128 |
+
$debug[] = ' - ' . $plugin . ' - ' . $pluginData['Version'] . ' - ' . $pluginData['Name'];
|
129 |
+
} else {
|
130 |
+
$notActive[$plugin] = $pluginData;
|
131 |
+
}
|
132 |
+
}
|
133 |
+
|
134 |
+
$debug[] = '';
|
135 |
+
$debug[] = '';
|
136 |
+
$debug[] = 'NOT Activated Plugins:';
|
137 |
+
foreach ($notActive as $plugin => $pluginData) {
|
138 |
+
$debug[] = ' - ' . $plugin . ' - ' . $pluginData['Version'] . ' - ' . $pluginData['Name'];
|
139 |
+
}
|
140 |
+
|
141 |
+
return $debug;
|
142 |
+
}
|
143 |
+
}
|
Nextend/Framework/Plugin.php
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework;
|
5 |
+
|
6 |
+
class Plugin {
|
7 |
+
|
8 |
+
private static $classes = array();
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @param $eventName
|
12 |
+
* @param callable $callable
|
13 |
+
*/
|
14 |
+
public static function addAction($eventName, $callable) {
|
15 |
+
if (!isset(self::$classes[$eventName])) self::$classes[$eventName] = array();
|
16 |
+
self::$classes[$eventName][] = $callable;
|
17 |
+
}
|
18 |
+
|
19 |
+
static function addFilter($eventName, $callable) {
|
20 |
+
if (!isset(self::$classes[$eventName])) self::$classes[$eventName] = array();
|
21 |
+
self::$classes[$eventName][] = $callable;
|
22 |
+
}
|
23 |
+
|
24 |
+
public static function applyFilters($eventName, $value, $args = array()) {
|
25 |
+
if (self::hasAction($eventName)) {
|
26 |
+
foreach (self::$classes[$eventName] AS $callable) {
|
27 |
+
if (is_callable($callable)) {
|
28 |
+
$value = call_user_func_array($callable, array_merge(array($value), $args));
|
29 |
+
}
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
return $value;
|
34 |
+
}
|
35 |
+
|
36 |
+
public static function doAction($eventName, $args = array()) {
|
37 |
+
if (self::hasAction($eventName)) {
|
38 |
+
foreach (self::$classes[$eventName] AS $callable) {
|
39 |
+
if (is_callable($callable)) {
|
40 |
+
call_user_func_array($callable, $args);
|
41 |
+
}
|
42 |
+
}
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
public static function hasAction($eventName) {
|
47 |
+
if (isset(self::$classes[$eventName])) {
|
48 |
+
return true;
|
49 |
+
}
|
50 |
+
|
51 |
+
return false;
|
52 |
+
}
|
53 |
+
}
|
Nextend/Framework/Request/Parser/AbstractRequestParser.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Request\Parser;
|
5 |
+
|
6 |
+
|
7 |
+
abstract class AbstractRequestParser {
|
8 |
+
|
9 |
+
public abstract function parseData($data);
|
10 |
+
|
11 |
+
}
|
Nextend/Framework/Request/Parser/JoomlaRequestParser.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Request\Parser;
|
4 |
+
|
5 |
+
class JoomlaRequestParser extends AbstractRequestParser {
|
6 |
+
|
7 |
+
public function parseData($data) {
|
8 |
+
return $data;
|
9 |
+
}
|
10 |
+
}
|
Nextend/Framework/Request/Parser/WordPressRequestParser.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Request\Parser;
|
4 |
+
|
5 |
+
class WordPressRequestParser extends AbstractRequestParser {
|
6 |
+
|
7 |
+
public function parseData($data) {
|
8 |
+
if (is_array($data)) {
|
9 |
+
return $this->stripslashesRecursive($data);
|
10 |
+
}
|
11 |
+
|
12 |
+
return stripslashes($data);
|
13 |
+
}
|
14 |
+
|
15 |
+
private function stripslashesRecursive($array) {
|
16 |
+
foreach ($array as $key => $value) {
|
17 |
+
$array[$key] = is_array($value) ? $this->stripslashesRecursive($value) : stripslashes($value);
|
18 |
+
}
|
19 |
+
|
20 |
+
return $array;
|
21 |
+
}
|
22 |
+
}
|
Nextend/Framework/Request/Request.php
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Request;
|
5 |
+
|
6 |
+
use Nextend\Framework\PageFlow;
|
7 |
+
|
8 |
+
class Request {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var Storage
|
12 |
+
*/
|
13 |
+
public static $REQUEST;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @var Storage
|
17 |
+
*/
|
18 |
+
public static $GET;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @var Storage
|
22 |
+
*/
|
23 |
+
public static $POST;
|
24 |
+
|
25 |
+
private static $requestUri;
|
26 |
+
|
27 |
+
public static $isAjax = false;
|
28 |
+
|
29 |
+
public function __construct() {
|
30 |
+
self::$REQUEST = new Storage($_REQUEST);
|
31 |
+
self::$GET = new Storage($_GET);
|
32 |
+
self::$POST = new Storage($_POST);
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @param array|string $url
|
37 |
+
* @param integer $statusCode
|
38 |
+
* @param bool $terminate
|
39 |
+
*/
|
40 |
+
public static function redirect($url, $statusCode = 302, $terminate = true) {
|
41 |
+
|
42 |
+
header('Location: ' . $url, true, $statusCode);
|
43 |
+
if ($terminate) {
|
44 |
+
PageFlow::exitApplication();
|
45 |
+
}
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
new Request();
|
Nextend/Framework/Request/Storage.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Request;
|
4 |
+
|
5 |
+
use Nextend\Framework\Request\Parser\AbstractRequestParser;
|
6 |
+
use Nextend\Framework\Request\Parser\JoomlaRequestParser;
|
7 |
+
use Nextend\Framework\Request\Parser\WordPressRequestParser;
|
8 |
+
|
9 |
+
class Storage {
|
10 |
+
|
11 |
+
public $originalStorage;
|
12 |
+
public $storage;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @var AbstractRequestParser
|
16 |
+
*/
|
17 |
+
public $parserInstance;
|
18 |
+
|
19 |
+
public function __construct($data) {
|
20 |
+
$this->parserInstance = new WordPressRequestParser();
|
21 |
+
|
22 |
+
|
23 |
+
$this->originalStorage = $data;
|
24 |
+
$this->storage = array();
|
25 |
+
}
|
26 |
+
|
27 |
+
public function set($var, $val) {
|
28 |
+
$this->storage[$var] = $val;
|
29 |
+
}
|
30 |
+
|
31 |
+
protected function get($var, $default = false) {
|
32 |
+
if (isset($this->storage[$var])) {
|
33 |
+
return $this->storage[$var];
|
34 |
+
} else if (isset($this->originalStorage[$var])) {
|
35 |
+
|
36 |
+
$this->storage[$var] = $this->parserInstance->parseData($this->originalStorage[$var]);
|
37 |
+
|
38 |
+
return $this->storage[$var];
|
39 |
+
}
|
40 |
+
|
41 |
+
return $default;
|
42 |
+
}
|
43 |
+
|
44 |
+
public function getVar($var, $default = null) {
|
45 |
+
return $this->get($var, $default);
|
46 |
+
}
|
47 |
+
|
48 |
+
public function getInt($var, $default = 0) {
|
49 |
+
return intval($this->get($var, $default));
|
50 |
+
}
|
51 |
+
|
52 |
+
public function getCmd($var, $default = '') {
|
53 |
+
return preg_replace("/[^\w_]/", "", $this->get($var, $default));
|
54 |
+
}
|
55 |
+
|
56 |
+
public function exists($var) {
|
57 |
+
|
58 |
+
if (isset($this->storage[$var])) {
|
59 |
+
return true;
|
60 |
+
} else if (isset($this->originalStorage[$var])) {
|
61 |
+
return true;
|
62 |
+
}
|
63 |
+
|
64 |
+
return false;
|
65 |
+
}
|
66 |
+
}
|
Nextend/Framework/ResourceTranslator/ResourceIdentifier.php
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\ResourceTranslator;
|
4 |
+
|
5 |
+
class ResourceIdentifier {
|
6 |
+
|
7 |
+
/**
|
8 |
+
* @var string
|
9 |
+
*/
|
10 |
+
protected $rawKeyword = '';
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var string
|
14 |
+
*/
|
15 |
+
protected $keyword = '';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @var string
|
19 |
+
*/
|
20 |
+
protected $path = '';
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var string
|
24 |
+
*/
|
25 |
+
protected $url = '';
|
26 |
+
|
27 |
+
public function __construct($keyword, $path, $url) {
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Keyword must start and end with `$` sign
|
31 |
+
*/
|
32 |
+
if (strlen($keyword) == 0) {
|
33 |
+
$keyword = '$';
|
34 |
+
} else {
|
35 |
+
if ($keyword[0] != '$') {
|
36 |
+
$keyword = '$' . $keyword;
|
37 |
+
}
|
38 |
+
|
39 |
+
if ($keyword[strlen($keyword) - 1] != '$') {
|
40 |
+
$keyword .= '$';
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
$this->rawKeyword = $keyword;
|
45 |
+
$this->keyword = $keyword . '/';
|
46 |
+
$this->path = rtrim($path, '/\\') . DIRECTORY_SEPARATOR;
|
47 |
+
$this->url = rtrim($url, '/') . '/';
|
48 |
+
}
|
49 |
+
|
50 |
+
public function getRawKeyword() {
|
51 |
+
return $this->rawKeyword;
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* @return string
|
56 |
+
*/
|
57 |
+
public function getKeyword() {
|
58 |
+
return $this->keyword;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* @return string
|
63 |
+
*/
|
64 |
+
public function getPath() {
|
65 |
+
return $this->path;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @return string
|
70 |
+
*/
|
71 |
+
public function getUrl() {
|
72 |
+
return $this->url;
|
73 |
+
}
|
74 |
+
}
|
Nextend/Framework/ResourceTranslator/ResourceTranslator.php
ADDED
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\ResourceTranslator;
|
4 |
+
|
5 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
6 |
+
use Nextend\Framework\Image\Image;
|
7 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
8 |
+
use Nextend\Framework\Settings;
|
9 |
+
use Nextend\Framework\Url\Url;
|
10 |
+
|
11 |
+
class ResourceTranslator {
|
12 |
+
|
13 |
+
use SingletonTrait;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @var ResourceIdentifier[]
|
17 |
+
*/
|
18 |
+
private static $resources = array();
|
19 |
+
|
20 |
+
private static $isProtocolRelative = true;
|
21 |
+
|
22 |
+
private static $resourceIdentifierKeywords = array();
|
23 |
+
|
24 |
+
protected function init() {
|
25 |
+
|
26 |
+
self::$isProtocolRelative = !!Settings::get('protocol-relative', 1);
|
27 |
+
|
28 |
+
self::createResource('$', Filesystem::getBasePath(), Url::getBaseUri());
|
29 |
+
|
30 |
+
Image::getInstance();
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* @param string $keyword
|
35 |
+
* @param string $path
|
36 |
+
* @param string $url
|
37 |
+
*/
|
38 |
+
public static function createResource($keyword, $path, $url) {
|
39 |
+
|
40 |
+
$resourceIdentifier = new ResourceIdentifier($keyword, $path, self::convertUrl($url));
|
41 |
+
|
42 |
+
array_unshift(self::$resources, $resourceIdentifier);
|
43 |
+
|
44 |
+
self::$resourceIdentifierKeywords[] = $resourceIdentifier->getKeyword();
|
45 |
+
}
|
46 |
+
|
47 |
+
public static function isResource($resourcePath) {
|
48 |
+
|
49 |
+
return preg_match(self::getResourceIdentifierRegexp(), $resourcePath);
|
50 |
+
}
|
51 |
+
|
52 |
+
public static function toUrl($resourcePath) {
|
53 |
+
|
54 |
+
foreach (self::$resources AS $resourceIdentifier) {
|
55 |
+
|
56 |
+
$keyword = $resourceIdentifier->getKeyword();
|
57 |
+
if (strpos($resourcePath, $keyword) === 0) {
|
58 |
+
|
59 |
+
return $resourceIdentifier->getUrl() . substr($resourcePath, strlen($keyword));
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
return $resourcePath;
|
64 |
+
}
|
65 |
+
|
66 |
+
public static function toPath($resourcePath) {
|
67 |
+
|
68 |
+
foreach (self::$resources AS $resourceIdentifier) {
|
69 |
+
|
70 |
+
$keyword = $resourceIdentifier->getKeyword();
|
71 |
+
if (strpos($resourcePath, $keyword) === 0) {
|
72 |
+
|
73 |
+
return $resourceIdentifier->getPath() . substr($resourcePath, strlen($keyword));
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
return $resourcePath;
|
78 |
+
}
|
79 |
+
|
80 |
+
public static function urlToResource($url) {
|
81 |
+
|
82 |
+
$url = self::convertUrl($url);
|
83 |
+
|
84 |
+
foreach (self::$resources AS $resourceIdentifier) {
|
85 |
+
|
86 |
+
if (strpos($url, $resourceIdentifier->getUrl()) === 0) {
|
87 |
+
|
88 |
+
return $resourceIdentifier->getKeyword() . substr($url, strlen($resourceIdentifier->getUrl()));
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
return $url;
|
93 |
+
}
|
94 |
+
|
95 |
+
public static function pathToResource($path) {
|
96 |
+
|
97 |
+
foreach (self::$resources AS $resourceIdentifier) {
|
98 |
+
|
99 |
+
if (strpos($path, $resourceIdentifier->getPath()) === 0) {
|
100 |
+
|
101 |
+
return $resourceIdentifier->getKeyword() . substr($path, strlen($resourceIdentifier->getPath()));
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
return $path;
|
106 |
+
}
|
107 |
+
|
108 |
+
/**
|
109 |
+
* @return bool
|
110 |
+
*/
|
111 |
+
public static function isProtocolRelative() {
|
112 |
+
|
113 |
+
return self::$isProtocolRelative;
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* @return string[]
|
118 |
+
*/
|
119 |
+
public static function getResourceIdentifierKeywords() {
|
120 |
+
|
121 |
+
$keywords = array();
|
122 |
+
foreach (self::$resources AS $resourceIdentifier) {
|
123 |
+
|
124 |
+
$keywords[] = $resourceIdentifier->getKeyword();
|
125 |
+
}
|
126 |
+
|
127 |
+
return $keywords;
|
128 |
+
}
|
129 |
+
|
130 |
+
public static function getResourceIdentifierUrls() {
|
131 |
+
|
132 |
+
$urls = array();
|
133 |
+
foreach (self::$resources AS $resourceIdentifier) {
|
134 |
+
|
135 |
+
$urls[] = $resourceIdentifier->getUrl();
|
136 |
+
}
|
137 |
+
|
138 |
+
return $urls;
|
139 |
+
}
|
140 |
+
|
141 |
+
public static function exportData() {
|
142 |
+
|
143 |
+
$data = array();
|
144 |
+
|
145 |
+
foreach (self::$resources AS $resourceIdentifier) {
|
146 |
+
|
147 |
+
$data[$resourceIdentifier->getKeyword()] = $resourceIdentifier->getUrl();
|
148 |
+
}
|
149 |
+
|
150 |
+
return $data;
|
151 |
+
}
|
152 |
+
|
153 |
+
private static function convertUrl($url) {
|
154 |
+
|
155 |
+
if (self::$isProtocolRelative) {
|
156 |
+
|
157 |
+
return preg_replace('/^http(s)?:\/\//', '//', $url);
|
158 |
+
}
|
159 |
+
|
160 |
+
return $url;
|
161 |
+
}
|
162 |
+
|
163 |
+
private static function getResourceIdentifierRegexp() {
|
164 |
+
|
165 |
+
return '/^' . join('|', array_map(function ($keyword) {
|
166 |
+
return preg_quote($keyword, '/');
|
167 |
+
}, self::$resourceIdentifierKeywords)) . '/';
|
168 |
+
}
|
169 |
+
}
|
170 |
+
|
171 |
+
ResourceTranslator::getInstance();
|
Nextend/Framework/Response/ResponseAjax.php
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Response;
|
4 |
+
|
5 |
+
use Nextend\Framework\Application\AbstractApplicationType;
|
6 |
+
use Nextend\Framework\Notification\Notification;
|
7 |
+
use Nextend\Framework\PageFlow;
|
8 |
+
|
9 |
+
class ResponseAjax {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var AbstractApplicationType
|
13 |
+
*/
|
14 |
+
private $appType;
|
15 |
+
|
16 |
+
private $isError = false;
|
17 |
+
|
18 |
+
private $response = array(
|
19 |
+
'data' => null,
|
20 |
+
'notification' => array()
|
21 |
+
);
|
22 |
+
|
23 |
+
public function __construct($appType) {
|
24 |
+
$this->appType = $appType;
|
25 |
+
}
|
26 |
+
|
27 |
+
public function error($showNotification = true) {
|
28 |
+
$this->isError = true;
|
29 |
+
$this->respond(null, $showNotification);
|
30 |
+
}
|
31 |
+
|
32 |
+
public function respond($data = null, $showNotification = true) {
|
33 |
+
$this->response['data'] = $data;
|
34 |
+
|
35 |
+
self::fix_output_buffer();
|
36 |
+
|
37 |
+
if ($showNotification) {
|
38 |
+
$this->response['notification'] = Notification::showAjax();
|
39 |
+
}
|
40 |
+
header("Content-Type: application/json");
|
41 |
+
if ($this->isError) {
|
42 |
+
header("HTTP/1.0 403 Forbidden");
|
43 |
+
}
|
44 |
+
echo json_encode($this->response);
|
45 |
+
|
46 |
+
PageFlow::exitApplication();
|
47 |
+
}
|
48 |
+
|
49 |
+
public function redirect($url) {
|
50 |
+
|
51 |
+
self::fix_output_buffer();
|
52 |
+
|
53 |
+
$this->response['redirect'] = $url;
|
54 |
+
echo json_encode($this->response);
|
55 |
+
|
56 |
+
PageFlow::exitApplication();
|
57 |
+
}
|
58 |
+
|
59 |
+
private static function fix_output_buffer() {
|
60 |
+
|
61 |
+
$ob_list_handlers = ob_list_handlers();
|
62 |
+
$ob_list_handlers_count = count($ob_list_handlers);
|
63 |
+
|
64 |
+
$exclude = array(
|
65 |
+
'ob_gzhandler',
|
66 |
+
'zlib output compression'
|
67 |
+
);
|
68 |
+
|
69 |
+
if ($ob_list_handlers_count && !in_array($ob_list_handlers[$ob_list_handlers_count - 1], $exclude)) {
|
70 |
+
ob_clean();
|
71 |
+
}
|
72 |
+
}
|
73 |
+
}
|
Nextend/Framework/Router/Base/PlatformRouter.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Router\Base;
|
4 |
+
|
5 |
+
use Nextend\Framework\Router\Router;
|
6 |
+
|
7 |
+
class PlatformRouter {
|
8 |
+
|
9 |
+
protected $router;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Router constructor.
|
13 |
+
*
|
14 |
+
* @param $router Router
|
15 |
+
*/
|
16 |
+
public function __construct($router) {
|
17 |
+
$this->router = $router;
|
18 |
+
}
|
19 |
+
|
20 |
+
public function setMultiSite() {
|
21 |
+
|
22 |
+
}
|
23 |
+
|
24 |
+
public function unSetMultiSite() {
|
25 |
+
|
26 |
+
}
|
27 |
+
}
|
Nextend/Framework/Router/Router.php
ADDED
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Router;
|
4 |
+
|
5 |
+
use Nextend\Framework\Form\Form;
|
6 |
+
use Nextend\Framework\Router\Base\PlatformRouter;
|
7 |
+
use Nextend\Framework\Router\WordPress\WordPressRouter;
|
8 |
+
use Nextend\Framework\Url\UrlHelper;
|
9 |
+
|
10 |
+
class Router {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var Base\PlatformRouter
|
14 |
+
*/
|
15 |
+
private $platformRouter;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @var string
|
19 |
+
*/
|
20 |
+
protected $baseUrl;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var bool|string
|
24 |
+
*/
|
25 |
+
protected $baseUrlAjax;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @var bool|string
|
29 |
+
*/
|
30 |
+
protected $networkUrl = false;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Router constructor.
|
34 |
+
*
|
35 |
+
* @param string $baseUrl
|
36 |
+
* @param string|bool $baseUrlAjax
|
37 |
+
* @param string|bool $networkUrl
|
38 |
+
*/
|
39 |
+
public function __construct($baseUrl, $baseUrlAjax = false, $networkUrl = false) {
|
40 |
+
$this->platformRouter = new WordPressRouter($this);
|
41 |
+
|
42 |
+
$this->baseUrl = $baseUrl;
|
43 |
+
|
44 |
+
if ($baseUrlAjax === false) {
|
45 |
+
$baseUrlAjax = UrlHelper::add_query_arg(array('nextendajax' => 1), $this->baseUrl);
|
46 |
+
}
|
47 |
+
$this->baseUrlAjax = $baseUrlAjax;
|
48 |
+
|
49 |
+
$this->networkUrl = $networkUrl;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @return string
|
54 |
+
*/
|
55 |
+
public function getBaseUrl() {
|
56 |
+
return $this->baseUrl;
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @param string $baseUrl
|
61 |
+
*/
|
62 |
+
public function setBaseUrl($baseUrl) {
|
63 |
+
$this->baseUrl = $baseUrl;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* @return bool|string
|
68 |
+
*/
|
69 |
+
public function getNetworkUrl() {
|
70 |
+
|
71 |
+
return $this->networkUrl;
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* @param array|string $url
|
76 |
+
* @param bool $isPost
|
77 |
+
* @param bool $isAjax
|
78 |
+
*
|
79 |
+
* @return string
|
80 |
+
*/
|
81 |
+
public function createUrl($url, $isPost = false, $isAjax = false) {
|
82 |
+
//create url from array
|
83 |
+
// [0] = controller/method
|
84 |
+
// [1] = query parameters
|
85 |
+
if (is_array($url)) {
|
86 |
+
$href = $this->route($url[0], (isset($url[1]) ? $url[1] : array()), $isPost, $isAjax);
|
87 |
+
} elseif (filter_var($url, FILTER_VALIDATE_URL)) {
|
88 |
+
//completed url, no mods, just fun
|
89 |
+
$href = $url;
|
90 |
+
} elseif (strpos($url, "/") !== false) {
|
91 |
+
//create url from string
|
92 |
+
//format: controller/method
|
93 |
+
$href = $this->route($url, array(), $isPost, $isAjax);
|
94 |
+
} else {
|
95 |
+
//fake link, replace to hashtag
|
96 |
+
$href = "#";
|
97 |
+
}
|
98 |
+
|
99 |
+
return $href;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* @param array|string $url
|
104 |
+
*
|
105 |
+
* @return string
|
106 |
+
*/
|
107 |
+
public function createAjaxUrl($url) {
|
108 |
+
|
109 |
+
return $this->createUrl($url, false, true);
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* @param $url
|
114 |
+
* @param array $queryArgs
|
115 |
+
* @param bool $isPost
|
116 |
+
* @param bool $isAjax
|
117 |
+
*
|
118 |
+
* @return string
|
119 |
+
*/
|
120 |
+
private function route($url, $queryArgs = array(), $isPost = false, $isAjax = false) {
|
121 |
+
|
122 |
+
if ($isAjax) {
|
123 |
+
$baseUrl = $this->baseUrlAjax;
|
124 |
+
} else {
|
125 |
+
$baseUrl = $this->baseUrl;
|
126 |
+
}
|
127 |
+
|
128 |
+
$parsedAction = explode("/", $url);
|
129 |
+
|
130 |
+
$queryArgs = array(
|
131 |
+
'nextendcontroller' => strtolower(trim($parsedAction[0])),
|
132 |
+
'nextendaction' => strtolower(trim($parsedAction[1]))
|
133 |
+
) + $queryArgs;
|
134 |
+
|
135 |
+
if ($isPost || $isAjax) {
|
136 |
+
$queryArgs += Form::tokenizeUrl();
|
137 |
+
}
|
138 |
+
|
139 |
+
return UrlHelper::add_query_arg($queryArgs, $baseUrl);
|
140 |
+
}
|
141 |
+
|
142 |
+
public function setMultiSite() {
|
143 |
+
|
144 |
+
$this->platformRouter->setMultiSite();
|
145 |
+
}
|
146 |
+
|
147 |
+
public function unSetMultiSite() {
|
148 |
+
|
149 |
+
$this->platformRouter->unSetMultiSite();
|
150 |
+
}
|
151 |
+
}
|
Nextend/Framework/Router/WordPress/WordPressRouter.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Router\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Router\Base;
|
6 |
+
|
7 |
+
class WordPressRouter extends Base\PlatformRouter {
|
8 |
+
|
9 |
+
private $originalBaseUrl = '';
|
10 |
+
|
11 |
+
public function setMultiSite() {
|
12 |
+
if (is_multisite()) {
|
13 |
+
$this->originalBaseUrl = $this->router->getBaseUrl();
|
14 |
+
$this->router->setBaseUrl($this->router->getNetworkUrl());
|
15 |
+
}
|
16 |
+
}
|
17 |
+
|
18 |
+
public function unSetMultiSite() {
|
19 |
+
if (is_multisite()) {
|
20 |
+
$this->router->setBaseUrl($this->originalBaseUrl);
|
21 |
+
}
|
22 |
+
}
|
23 |
+
}
|
Nextend/Framework/Sanitize.php
ADDED
@@ -0,0 +1,609 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework;
|
4 |
+
|
5 |
+
use Nextend\Framework\Platform\Platform;
|
6 |
+
|
7 |
+
global $allowedentitynames;
|
8 |
+
/**
|
9 |
+
* @var string[] $allowedentitynames Array of KSES allowed HTML entitity names.
|
10 |
+
* @since 1.0.0
|
11 |
+
*/
|
12 |
+
$allowedentitynames = is_array($allowedentitynames) ? $allowedentitynames : array(
|
13 |
+
'nbsp',
|
14 |
+
'iexcl',
|
15 |
+
'cent',
|
16 |
+
'pound',
|
17 |
+
'curren',
|
18 |
+
'yen',
|
19 |
+
'brvbar',
|
20 |
+
'sect',
|
21 |
+
'uml',
|
22 |
+
'copy',
|
23 |
+
'ordf',
|
24 |
+
'laquo',
|
25 |
+
'not',
|
26 |
+
'shy',
|
27 |
+
'reg',
|
28 |
+
'macr',
|
29 |
+
'deg',
|
30 |
+
'plusmn',
|
31 |
+
'acute',
|
32 |
+
'micro',
|
33 |
+
'para',
|
34 |
+
'middot',
|
35 |
+
'cedil',
|
36 |
+
'ordm',
|
37 |
+
'raquo',
|
38 |
+
'iquest',
|
39 |
+
'Agrave',
|
40 |
+
'Aacute',
|
41 |
+
'Acirc',
|
42 |
+
'Atilde',
|
43 |
+
'Auml',
|
44 |
+
'Aring',
|
45 |
+
'AElig',
|
46 |
+
'Ccedil',
|
47 |
+
'Egrave',
|
48 |
+
'Eacute',
|
49 |
+
'Ecirc',
|
50 |
+
'Euml',
|
51 |
+
'Igrave',
|
52 |
+
'Iacute',
|
53 |
+
'Icirc',
|
54 |
+
'Iuml',
|
55 |
+
'ETH',
|
56 |
+
'Ntilde',
|
57 |
+
'Ograve',
|
58 |
+
'Oacute',
|
59 |
+
'Ocirc',
|
60 |
+
'Otilde',
|
61 |
+
'Ouml',
|
62 |
+
'times',
|
63 |
+
'Oslash',
|
64 |
+
'Ugrave',
|
65 |
+
'Uacute',
|
66 |
+
'Ucirc',
|
67 |
+
'Uuml',
|
68 |
+
'Yacute',
|
69 |
+
'THORN',
|
70 |
+
'szlig',
|
71 |
+
'agrave',
|
72 |
+
'aacute',
|
73 |
+
'acirc',
|
74 |
+
'atilde',
|
75 |
+
'auml',
|
76 |
+
'aring',
|
77 |
+
'aelig',
|
78 |
+
'ccedil',
|
79 |
+
'egrave',
|
80 |
+
'eacute',
|
81 |
+
'ecirc',
|
82 |
+
'euml',
|
83 |
+
'igrave',
|
84 |
+
'iacute',
|
85 |
+
'icirc',
|
86 |
+
'iuml',
|
87 |
+
'eth',
|
88 |
+
'ntilde',
|
89 |
+
'ograve',
|
90 |
+
'oacute',
|
91 |
+
'ocirc',
|
92 |
+
'otilde',
|
93 |
+
'ouml',
|
94 |
+
'divide',
|
95 |
+
'oslash',
|
96 |
+
'ugrave',
|
97 |
+
'uacute',
|
98 |
+
'ucirc',
|
99 |
+
'uuml',
|
100 |
+
'yacute',
|
101 |
+
'thorn',
|
102 |
+
'yuml',
|
103 |
+
'quot',
|
104 |
+
'amp',
|
105 |
+
'lt',
|
106 |
+
'gt',
|
107 |
+
'apos',
|
108 |
+
'OElig',
|
109 |
+
'oelig',
|
110 |
+
'Scaron',
|
111 |
+
'scaron',
|
112 |
+
'Yuml',
|
113 |
+
'circ',
|
114 |
+
'tilde',
|
115 |
+
'ensp',
|
116 |
+
'emsp',
|
117 |
+
'thinsp',
|
118 |
+
'zwnj',
|
119 |
+
'zwj',
|
120 |
+
'lrm',
|
121 |
+
'rlm',
|
122 |
+
'ndash',
|
123 |
+
'mdash',
|
124 |
+
'lsquo',
|
125 |
+
'rsquo',
|
126 |
+
'sbquo',
|
127 |
+
'ldquo',
|
128 |
+
'rdquo',
|
129 |
+
'bdquo',
|
130 |
+
'dagger',
|
131 |
+
'Dagger',
|
132 |
+
'permil',
|
133 |
+
'lsaquo',
|
134 |
+
'rsaquo',
|
135 |
+
'euro',
|
136 |
+
'fnof',
|
137 |
+
'Alpha',
|
138 |
+
'Beta',
|
139 |
+
'Gamma',
|
140 |
+
'Delta',
|
141 |
+
'Epsilon',
|
142 |
+
'Zeta',
|
143 |
+
'Eta',
|
144 |
+
'Theta',
|
145 |
+
'Iota',
|
146 |
+
'Kappa',
|
147 |
+
'Lambda',
|
148 |
+
'Mu',
|
149 |
+
'Nu',
|
150 |
+
'Xi',
|
151 |
+
'Omicron',
|
152 |
+
'Pi',
|
153 |
+
'Rho',
|
154 |
+
'Sigma',
|
155 |
+
'Tau',
|
156 |
+
'Upsilon',
|
157 |
+
'Phi',
|
158 |
+
'Chi',
|
159 |
+
'Psi',
|
160 |
+
'Omega',
|
161 |
+
'alpha',
|
162 |
+
'beta',
|
163 |
+
'gamma',
|
164 |
+
'delta',
|
165 |
+
'epsilon',
|
166 |
+
'zeta',
|
167 |
+
'eta',
|
168 |
+
'theta',
|
169 |
+
'iota',
|
170 |
+
'kappa',
|
171 |
+
'lambda',
|
172 |
+
'mu',
|
173 |
+
'nu',
|
174 |
+
'xi',
|
175 |
+
'omicron',
|
176 |
+
'pi',
|
177 |
+
'rho',
|
178 |
+
'sigmaf',
|
179 |
+
'sigma',
|
180 |
+
'tau',
|
181 |
+
'upsilon',
|
182 |
+
'phi',
|
183 |
+
'chi',
|
184 |
+
'psi',
|
185 |
+
'omega',
|
186 |
+
'thetasym',
|
187 |
+
'upsih',
|
188 |
+
'piv',
|
189 |
+
'bull',
|
190 |
+
'hellip',
|
191 |
+
'prime',
|
192 |
+
'Prime',
|
193 |
+
'oline',
|
194 |
+
'frasl',
|
195 |
+
'weierp',
|
196 |
+
'image',
|
197 |
+
'real',
|
198 |
+
'trade',
|
199 |
+
'alefsym',
|
200 |
+
'larr',
|
201 |
+
'uarr',
|
202 |
+
'rarr',
|
203 |
+
'darr',
|
204 |
+
'harr',
|
205 |
+
'crarr',
|
206 |
+
'lArr',
|
207 |
+
'uArr',
|
208 |
+
'rArr',
|
209 |
+
'dArr',
|
210 |
+
'hArr',
|
211 |
+
'forall',
|
212 |
+
'part',
|
213 |
+
'exist',
|
214 |
+
'empty',
|
215 |
+
'nabla',
|
216 |
+
'isin',
|
217 |
+
'notin',
|
218 |
+
'ni',
|
219 |
+
'prod',
|
220 |
+
'sum',
|
221 |
+
'minus',
|
222 |
+
'lowast',
|
223 |
+
'radic',
|
224 |
+
'prop',
|
225 |
+
'infin',
|
226 |
+
'ang',
|
227 |
+
'and',
|
228 |
+
'or',
|
229 |
+
'cap',
|
230 |
+
'cup',
|
231 |
+
'int',
|
232 |
+
'sim',
|
233 |
+
'cong',
|
234 |
+
'asymp',
|
235 |
+
'ne',
|
236 |
+
'equiv',
|
237 |
+
'le',
|
238 |
+
'ge',
|
239 |
+
'sub',
|
240 |
+
'sup',
|
241 |
+
'nsub',
|
242 |
+
'sube',
|
243 |
+
'supe',
|
244 |
+
'oplus',
|
245 |
+
'otimes',
|
246 |
+
'perp',
|
247 |
+
'sdot',
|
248 |
+
'lceil',
|
249 |
+
'rceil',
|
250 |
+
'lfloor',
|
251 |
+
'rfloor',
|
252 |
+
'lang',
|
253 |
+
'rang',
|
254 |
+
'loz',
|
255 |
+
'spades',
|
256 |
+
'clubs',
|
257 |
+
'hearts',
|
258 |
+
'diams',
|
259 |
+
'sup1',
|
260 |
+
'sup2',
|
261 |
+
'sup3',
|
262 |
+
'frac14',
|
263 |
+
'frac12',
|
264 |
+
'frac34',
|
265 |
+
'there4',
|
266 |
+
);
|
267 |
+
|
268 |
+
class Sanitize {
|
269 |
+
|
270 |
+
private static function getCharset() {
|
271 |
+
|
272 |
+
return Platform::getCharset();
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Checks for invalid UTF8 in a string.
|
277 |
+
*
|
278 |
+
* @param string $string The text which is to be checked.
|
279 |
+
* @param bool $strip Optional. Whether to attempt to strip out invalid UTF8. Default is false.
|
280 |
+
*
|
281 |
+
* @return string The checked text.
|
282 |
+
* @since 2.8.0
|
283 |
+
*
|
284 |
+
* @staticvar bool $is_utf8
|
285 |
+
* @staticvar bool $utf8_pcre
|
286 |
+
*
|
287 |
+
*/
|
288 |
+
private static function check_invalid_utf8($string, $strip = false) {
|
289 |
+
$string = (string)$string;
|
290 |
+
|
291 |
+
if (0 === strlen($string)) {
|
292 |
+
return '';
|
293 |
+
}
|
294 |
+
|
295 |
+
// Store the site charset as a static to avoid multiple calls to get_option()
|
296 |
+
static $is_utf8 = null;
|
297 |
+
if (!isset($is_utf8)) {
|
298 |
+
$is_utf8 = in_array(self::getCharset(), array(
|
299 |
+
'utf8',
|
300 |
+
'utf-8',
|
301 |
+
'UTF8',
|
302 |
+
'UTF-8'
|
303 |
+
));
|
304 |
+
}
|
305 |
+
if (!$is_utf8) {
|
306 |
+
return $string;
|
307 |
+
}
|
308 |
+
|
309 |
+
// Check for support for utf8 in the installed PCRE library once and store the result in a static
|
310 |
+
static $utf8_pcre = null;
|
311 |
+
if (!isset($utf8_pcre)) {
|
312 |
+
$utf8_pcre = @preg_match('/^./u', 'a');
|
313 |
+
}
|
314 |
+
// We can't demand utf8 in the PCRE installation, so just return the string in those cases
|
315 |
+
if (!$utf8_pcre) {
|
316 |
+
return $string;
|
317 |
+
}
|
318 |
+
|
319 |
+
// preg_match fails when it encounters invalid UTF8 in $string
|
320 |
+
if (1 === @preg_match('/^./us', $string)) {
|
321 |
+
return $string;
|
322 |
+
}
|
323 |
+
|
324 |
+
// Attempt to strip the bad chars if requested (not recommended)
|
325 |
+
if ($strip && function_exists('iconv')) {
|
326 |
+
return iconv('utf-8', 'utf-8', $string);
|
327 |
+
}
|
328 |
+
|
329 |
+
return '';
|
330 |
+
}
|
331 |
+
|
332 |
+
/**
|
333 |
+
* Converts a number of special characters into their HTML entities.
|
334 |
+
*
|
335 |
+
* Specifically deals with: &, <, >, ", and '.
|
336 |
+
*
|
337 |
+
* $quote_style can be set to ENT_COMPAT to encode " to
|
338 |
+
* ", or ENT_QUOTES to do both. Default is ENT_NOQUOTES where no quotes are encoded.
|
339 |
+
*
|
340 |
+
* @param string $string The text which is to be encoded.
|
341 |
+
* @param int|string $quote_style Optional. Converts double quotes if set to ENT_COMPAT,
|
342 |
+
* both single and double if set to ENT_QUOTES or none if set to ENT_NOQUOTES.
|
343 |
+
* Also compatible with old values; converting single quotes if set to 'single',
|
344 |
+
* double if set to 'double' or both if otherwise set.
|
345 |
+
* Default is ENT_NOQUOTES.
|
346 |
+
* @param string|bool $charset Optional. The character encoding of the string. Default is false.
|
347 |
+
* @param bool $double_encode Optional. Whether to encode existing html entities. Default is false.
|
348 |
+
*
|
349 |
+
* @return string The encoded text with HTML entities.
|
350 |
+
* @since 1.2.2
|
351 |
+
* @access private
|
352 |
+
*
|
353 |
+
* @staticvar string $_charset
|
354 |
+
*
|
355 |
+
*/
|
356 |
+
private static function _specialchars($string, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false) {
|
357 |
+
$string = (string)$string;
|
358 |
+
|
359 |
+
if (0 === strlen($string)) return '';
|
360 |
+
|
361 |
+
// Don't bother if there are no specialchars - saves some processing
|
362 |
+
if (!preg_match('/[&<>"\']/', $string)) return $string;
|
363 |
+
|
364 |
+
// Account for the previous behaviour of the function when the $quote_style is not an accepted value
|
365 |
+
if (empty($quote_style)) $quote_style = ENT_NOQUOTES; else if (!in_array($quote_style, array(
|
366 |
+
0,
|
367 |
+
2,
|
368 |
+
3,
|
369 |
+
'single',
|
370 |
+
'double'
|
371 |
+
), true)) $quote_style = ENT_QUOTES;
|
372 |
+
|
373 |
+
// Store the site charset as a static to avoid multiple calls to wp_load_alloptions()
|
374 |
+
if (!$charset) {
|
375 |
+
static $_charset = null;
|
376 |
+
if (!isset($_charset)) {
|
377 |
+
$_charset = self::getCharset();
|
378 |
+
}
|
379 |
+
$charset = $_charset;
|
380 |
+
}
|
381 |
+
|
382 |
+
if (in_array($charset, array(
|
383 |
+
'utf8',
|
384 |
+
'utf-8',
|
385 |
+
'UTF8'
|
386 |
+
))) $charset = 'UTF-8';
|
387 |
+
|
388 |
+
$_quote_style = $quote_style;
|
389 |
+
|
390 |
+
if ($quote_style === 'double') {
|
391 |
+
$quote_style = ENT_COMPAT;
|
392 |
+
$_quote_style = ENT_COMPAT;
|
393 |
+
} else if ($quote_style === 'single') {
|
394 |
+
$quote_style = ENT_NOQUOTES;
|
395 |
+
}
|
396 |
+
|
397 |
+
if (!$double_encode) {
|
398 |
+
// Guarantee every &entity; is valid, convert &garbage; into &garbage;
|
399 |
+
// This is required for PHP < 5.4.0 because ENT_HTML401 flag is unavailable.
|
400 |
+
$string = self::kses_normalize_entities($string);
|
401 |
+
}
|
402 |
+
|
403 |
+
$string = @htmlspecialchars($string, $quote_style, $charset, $double_encode);
|
404 |
+
|
405 |
+
// Back-compat.
|
406 |
+
if ('single' === $_quote_style) $string = str_replace("'", ''', $string);
|
407 |
+
|
408 |
+
return $string;
|
409 |
+
}
|
410 |
+
|
411 |
+
/**
|
412 |
+
* Converts and fixes HTML entities.
|
413 |
+
*
|
414 |
+
* This function normalizes HTML entities. It will convert `AT&T` to the correct
|
415 |
+
* `AT&T`, `:` to `:`, `&#XYZZY;` to `&#XYZZY;` and so on.
|
416 |
+
*
|
417 |
+
* @param string $string Content to normalize entities
|
418 |
+
*
|
419 |
+
* @return string Content with normalized entities
|
420 |
+
* @since 1.0.0
|
421 |
+
*
|
422 |
+
*/
|
423 |
+
private static function kses_normalize_entities($string) {
|
424 |
+
// Disarm all entities by converting & to &
|
425 |
+
$string = str_replace('&', '&', $string);
|
426 |
+
|
427 |
+
// Change back the allowed entities in our entity whitelist
|
428 |
+
$string = preg_replace_callback('/&([A-Za-z]{2,8}[0-9]{0,2});/', array(
|
429 |
+
self::class,
|
430 |
+
'kses_named_entities'
|
431 |
+
), $string);
|
432 |
+
$string = preg_replace_callback('/&#(0*[0-9]{1,7});/', array(
|
433 |
+
self::class,
|
434 |
+
'kses_normalize_entities2'
|
435 |
+
), $string);
|
436 |
+
$string = preg_replace_callback('/&#[Xx](0*[0-9A-Fa-f]{1,6});/', array(
|
437 |
+
self::class,
|
438 |
+
'kses_normalize_entities3'
|
439 |
+
), $string);
|
440 |
+
|
441 |
+
return $string;
|
442 |
+
}
|
443 |
+
|
444 |
+
/**
|
445 |
+
* Callback for kses_normalize_entities() regular expression.
|
446 |
+
*
|
447 |
+
* This function only accepts valid named entity references, which are finite,
|
448 |
+
* case-sensitive, and highly scrutinized by HTML and XML validators.
|
449 |
+
*
|
450 |
+
* @param array $matches preg_replace_callback() matches array
|
451 |
+
*
|
452 |
+
* @return string Correctly encoded entity
|
453 |
+
* @since 3.0.0
|
454 |
+
*
|
455 |
+
* @global array $allowedentitynames
|
456 |
+
*
|
457 |
+
*/
|
458 |
+
public static function kses_named_entities($matches) {
|
459 |
+
global $allowedentitynames;
|
460 |
+
|
461 |
+
if (empty($matches[1])) return '';
|
462 |
+
|
463 |
+
$i = $matches[1];
|
464 |
+
|
465 |
+
return (!in_array($i, $allowedentitynames)) ? "&$i;" : "&$i;";
|
466 |
+
}
|
467 |
+
|
468 |
+
/**
|
469 |
+
* Callback for kses_normalize_entities() regular expression.
|
470 |
+
*
|
471 |
+
* This function helps kses_normalize_entities() to only accept 16-bit
|
472 |
+
* values and nothing more for `&#number;` entities.
|
473 |
+
*
|
474 |
+
* @access private
|
475 |
+
*
|
476 |
+
* @param array $matches preg_replace_callback() matches array
|
477 |
+
*
|
478 |
+
* @return string Correctly encoded entity
|
479 |
+
* @since 1.0.0
|
480 |
+
*
|
481 |
+
*/
|
482 |
+
public static function kses_normalize_entities2($matches) {
|
483 |
+
if (empty($matches[1])) return '';
|
484 |
+
|
485 |
+
$i = $matches[1];
|
486 |
+
if (self::valid_unicode($i)) {
|
487 |
+
$i = str_pad(ltrim($i, '0'), 3, '0', STR_PAD_LEFT);
|
488 |
+
$i = "&#$i;";
|
489 |
+
} else {
|
490 |
+
$i = "&#$i;";
|
491 |
+
}
|
492 |
+
|
493 |
+
return $i;
|
494 |
+
}
|
495 |
+
|
496 |
+
/**
|
497 |
+
* Callback for kses_normalize_entities() for regular expression.
|
498 |
+
*
|
499 |
+
* This function helps kses_normalize_entities() to only accept valid Unicode
|
500 |
+
* numeric entities in hex form.
|
501 |
+
*
|
502 |
+
* @access private
|
503 |
+
*
|
504 |
+
* @param array $matches preg_replace_callback() matches array
|
505 |
+
*
|
506 |
+
* @return string Correctly encoded entity
|
507 |
+
*/
|
508 |
+
public static function kses_normalize_entities3($matches) {
|
509 |
+
if (empty($matches[1])) return '';
|
510 |
+
|
511 |
+
$hexchars = $matches[1];
|
512 |
+
|
513 |
+
return (!self::valid_unicode(hexdec($hexchars))) ? "&#x$hexchars;" : '&#x' . ltrim($hexchars, '0') . ';';
|
514 |
+
}
|
515 |
+
|
516 |
+
/**
|
517 |
+
* Helper function to determine if a Unicode value is valid.
|
518 |
+
*
|
519 |
+
* @param int $i Unicode value
|
520 |
+
*
|
521 |
+
* @return bool True if the value was a valid Unicode number
|
522 |
+
*/
|
523 |
+
private static function valid_unicode($i) {
|
524 |
+
return ($i == 0x9 || $i == 0xa || $i == 0xd || ($i >= 0x20 && $i <= 0xd7ff) || ($i >= 0xe000 && $i <= 0xfffd) || ($i >= 0x10000 && $i <= 0x10ffff));
|
525 |
+
}
|
526 |
+
|
527 |
+
/**
|
528 |
+
* Escape single quotes, htmlspecialchar " < > &, and fix line endings.
|
529 |
+
*
|
530 |
+
* Escapes text strings for echoing in JS. It is intended to be used for inline JS
|
531 |
+
* (in a tag attribute, for example onclick="..."). Note that the strings have to
|
532 |
+
* be in single quotes. The {@see 'js_escape'} filter is also applied here.
|
533 |
+
*
|
534 |
+
* @param string $text The text to be escaped.
|
535 |
+
*
|
536 |
+
* @return string Escaped text.
|
537 |
+
* @since 2.8.0
|
538 |
+
*
|
539 |
+
*/
|
540 |
+
public static function esc_js($text) {
|
541 |
+
$safe_text = self::check_invalid_utf8($text);
|
542 |
+
$safe_text = self::_specialchars($safe_text, ENT_COMPAT);
|
543 |
+
$safe_text = preg_replace('/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes($safe_text));
|
544 |
+
$safe_text = str_replace("\r", '', $safe_text);
|
545 |
+
$safe_text = str_replace("\n", '\\n', addslashes($safe_text));
|
546 |
+
|
547 |
+
return $safe_text;
|
548 |
+
}
|
549 |
+
|
550 |
+
/**
|
551 |
+
* Escaping for HTML blocks.
|
552 |
+
*
|
553 |
+
* @param string $text
|
554 |
+
*
|
555 |
+
* @return string
|
556 |
+
* @since 2.8.0
|
557 |
+
*
|
558 |
+
*/
|
559 |
+
public static function esc_html($text) {
|
560 |
+
$safe_text = self::check_invalid_utf8($text);
|
561 |
+
$safe_text = self::_specialchars($safe_text, ENT_QUOTES);
|
562 |
+
|
563 |
+
return $safe_text;
|
564 |
+
}
|
565 |
+
|
566 |
+
/**
|
567 |
+
* Escaping for HTML attributes.
|
568 |
+
*
|
569 |
+
* @param string $text
|
570 |
+
*
|
571 |
+
* @return string
|
572 |
+
* @since 2.8.0
|
573 |
+
*
|
574 |
+
*/
|
575 |
+
public static function esc_attr($text) {
|
576 |
+
$safe_text = self::check_invalid_utf8($text);
|
577 |
+
$safe_text = self::_specialchars($safe_text, ENT_QUOTES);
|
578 |
+
|
579 |
+
return $safe_text;
|
580 |
+
}
|
581 |
+
|
582 |
+
/**
|
583 |
+
* Escaping for textarea values.
|
584 |
+
*
|
585 |
+
* @param string $text
|
586 |
+
*
|
587 |
+
* @return string
|
588 |
+
* @since 3.1.0
|
589 |
+
*
|
590 |
+
*/
|
591 |
+
public static function esc_textarea($text) {
|
592 |
+
$safe_text = htmlspecialchars($text, ENT_QUOTES, self::getCharset());
|
593 |
+
|
594 |
+
return $safe_text;
|
595 |
+
}
|
596 |
+
|
597 |
+
public static function esc_css_value($text) {
|
598 |
+
$safe_text = self::check_invalid_utf8($text);
|
599 |
+
|
600 |
+
return preg_replace_callback('/<\/style.*?>/i', array(
|
601 |
+
self::class,
|
602 |
+
'esc_css_value_callback'
|
603 |
+
), $safe_text);
|
604 |
+
}
|
605 |
+
|
606 |
+
public static function esc_css_value_callback($a) {
|
607 |
+
return self::esc_html($a[0]);
|
608 |
+
}
|
609 |
+
}
|
Nextend/Framework/Session/AbstractStorage.php
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Session;
|
4 |
+
|
5 |
+
use Nextend\Framework\Plugin;
|
6 |
+
|
7 |
+
abstract class AbstractStorage {
|
8 |
+
|
9 |
+
protected static $expire = 86400; // 1 day
|
10 |
+
|
11 |
+
protected static $salt = 'nextendSalt';
|
12 |
+
|
13 |
+
protected $hash;
|
14 |
+
|
15 |
+
protected $storage = array();
|
16 |
+
|
17 |
+
public $storageChanged = false;
|
18 |
+
|
19 |
+
public function __construct($userIdentifier) {
|
20 |
+
|
21 |
+
$this->register();
|
22 |
+
if (!isset($_COOKIE['nextendsession']) || substr($_COOKIE['nextendsession'], 0, 2) != 'n2' || !preg_match('/^[a-f0-9]{32}$/', substr($_COOKIE['nextendsession'], 2))) {
|
23 |
+
$this->hash = 'n2' . md5(self::$salt . $userIdentifier);
|
24 |
+
setcookie('nextendsession', $this->hash, time() + self::$expire, $_SERVER["HTTP_HOST"]);
|
25 |
+
$_COOKIE['nextendsession'] = $this->hash;
|
26 |
+
} else {
|
27 |
+
$this->hash = $_COOKIE['nextendsession'];
|
28 |
+
}
|
29 |
+
|
30 |
+
$this->load();
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Load the whole session
|
35 |
+
* $this->storage = json_decode(result for $this->hash);
|
36 |
+
*/
|
37 |
+
protected abstract function load();
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Store the whole session
|
41 |
+
* $this->hash json_encode($this->storage);
|
42 |
+
*/
|
43 |
+
protected abstract function store();
|
44 |
+
|
45 |
+
public function get($key, $default = '') {
|
46 |
+
return isset($this->storage[$key]) ? $this->storage[$key] : $default;
|
47 |
+
}
|
48 |
+
|
49 |
+
public function set($key, $value) {
|
50 |
+
$this->storageChanged = true;
|
51 |
+
|
52 |
+
$this->storage[$key] = $value;
|
53 |
+
}
|
54 |
+
|
55 |
+
public function delete($key) {
|
56 |
+
$this->storageChanged = true;
|
57 |
+
unset($this->storage[$key]);
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Register our method for PHP shut down
|
62 |
+
*/
|
63 |
+
protected function register() {
|
64 |
+
Plugin::addAction('exit', array(
|
65 |
+
$this,
|
66 |
+
'shutdown'
|
67 |
+
));
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* When PHP shuts down, we have to save our session's data if the data changed
|
72 |
+
*/
|
73 |
+
public function shutdown() {
|
74 |
+
Plugin::doAction('beforeSessionSave');
|
75 |
+
if ($this->storageChanged) {
|
76 |
+
$this->store();
|
77 |
+
}
|
78 |
+
}
|
79 |
+
}
|
Nextend/Framework/Session/Session.php
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Session;
|
4 |
+
|
5 |
+
|
6 |
+
use Nextend\Framework\Session\Joomla\JoomlaStorage;
|
7 |
+
use Nextend\Framework\Session\WordPress\WordPressStorage;
|
8 |
+
|
9 |
+
class Session {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var $storage AbstractStorage
|
13 |
+
*/
|
14 |
+
private static $storage = false;
|
15 |
+
|
16 |
+
private static function getStorage() {
|
17 |
+
if (!self::$storage) {
|
18 |
+
self::$storage = new WordPressStorage();
|
19 |
+
}
|
20 |
+
|
21 |
+
return self::$storage;
|
22 |
+
}
|
23 |
+
|
24 |
+
public static function get($key, $default = null) {
|
25 |
+
return self::getStorage()
|
26 |
+
->get($key, $default);
|
27 |
+
}
|
28 |
+
|
29 |
+
public static function set($key, $value) {
|
30 |
+
|
31 |
+
self::getStorage()
|
32 |
+
->set($key, $value);
|
33 |
+
}
|
34 |
+
|
35 |
+
public static function delete($key) {
|
36 |
+
|
37 |
+
self::getStorage()
|
38 |
+
->delete($key);
|
39 |
+
}
|
40 |
+
}
|
Nextend/Framework/Session/WordPress/WordPressStorage.php
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Session\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Session\AbstractStorage;
|
6 |
+
use function delete_transient;
|
7 |
+
use function get_current_user_id;
|
8 |
+
use function get_transient;
|
9 |
+
use function set_transient;
|
10 |
+
|
11 |
+
class WordPressStorage extends AbstractStorage {
|
12 |
+
|
13 |
+
public function __construct() {
|
14 |
+
parent::__construct(get_current_user_id());
|
15 |
+
}
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Load the whole session
|
19 |
+
*/
|
20 |
+
protected function load() {
|
21 |
+
$stored = get_transient($this->hash);
|
22 |
+
|
23 |
+
if (!is_array($stored)) {
|
24 |
+
$stored = array();
|
25 |
+
}
|
26 |
+
$this->storage = $stored;
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Store the whole session
|
31 |
+
*/
|
32 |
+
protected function store() {
|
33 |
+
if (count($this->storage) > 0) {
|
34 |
+
set_transient($this->hash, $this->storage, self::$expire);
|
35 |
+
} else {
|
36 |
+
delete_transient($this->hash);
|
37 |
+
}
|
38 |
+
}
|
39 |
+
}
|
Nextend/Framework/Settings.php
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Model\Section;
|
8 |
+
|
9 |
+
class Settings {
|
10 |
+
|
11 |
+
private static $data;
|
12 |
+
|
13 |
+
public function __construct() {
|
14 |
+
|
15 |
+
$config = array(
|
16 |
+
'jquery' => 1,
|
17 |
+
'gsap' => 1,
|
18 |
+
'async' => 0,
|
19 |
+
'combine-js' => 0,
|
20 |
+
'minify-js' => 0,
|
21 |
+
'scriptattributes' => '',
|
22 |
+
'javascript-inline' => 'head',
|
23 |
+
'protocol-relative' => 1,
|
24 |
+
'force-english-backend' => 0,
|
25 |
+
'show-joomla-admin-footer' => 0,
|
26 |
+
'frontend-accessibility' => 1,
|
27 |
+
'curl' => 1,
|
28 |
+
'curl-clean-proxy' => 0,
|
29 |
+
'css-mode' => 'normal',
|
30 |
+
'icon-fa' => 1,
|
31 |
+
);
|
32 |
+
if (!defined('NEXTEND_INSTALL')) {
|
33 |
+
global $wpdb;
|
34 |
+
if ($wpdb->get_var("SHOW TABLES LIKE '" . $wpdb->prefix . "nextend2_section_storage'") != $wpdb->prefix . 'nextend2_section_storage') {
|
35 |
+
define('NEXTEND_INSTALL', 1);
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
|
40 |
+
if (!defined('NEXTEND_INSTALL')) {
|
41 |
+
foreach (Section::getAll('system', 'global') AS $data) {
|
42 |
+
$config[$data['referencekey']] = $data['value'];
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
self::$data = new Data\Data();
|
47 |
+
self::$data->loadArray($config);
|
48 |
+
}
|
49 |
+
|
50 |
+
public static function get($key, $default = '') {
|
51 |
+
return self::$data->get($key, $default);
|
52 |
+
}
|
53 |
+
|
54 |
+
public static function getAll() {
|
55 |
+
return self::$data->toArray();
|
56 |
+
}
|
57 |
+
|
58 |
+
public static function set($key, $value) {
|
59 |
+
self::$data->set($key, $value);
|
60 |
+
Section::set('system', 'global', $key, $value, 1, 1);
|
61 |
+
}
|
62 |
+
|
63 |
+
public static function setAll($data) {
|
64 |
+
if (is_array($data)) {
|
65 |
+
foreach ($data as $key => $value) {
|
66 |
+
if (self::$data->get($key, null) !== null) {
|
67 |
+
self::set($key, $value);
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
return true;
|
72 |
+
}
|
73 |
+
|
74 |
+
return false;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
new Settings();
|
Nextend/Framework/Style/Block/StyleManager/BlockStyleManager.php
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Style\Block\StyleManager;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\Js\Js;
|
8 |
+
use Nextend\Framework\Localization\Localization;
|
9 |
+
use Nextend\Framework\Style\ModelStyle;
|
10 |
+
use Nextend\Framework\Style\StyleRenderer;
|
11 |
+
use Nextend\Framework\Visual\AbstractBlockVisual;
|
12 |
+
use Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonApply;
|
13 |
+
use Nextend\SmartSlider3\Application\Admin\Layout\Block\Forms\Button\BlockButtonCancel;
|
14 |
+
|
15 |
+
class BlockStyleManager extends AbstractBlockVisual {
|
16 |
+
|
17 |
+
/** @var ModelStyle */
|
18 |
+
protected $model;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @return ModelStyle
|
22 |
+
*/
|
23 |
+
public function getModel() {
|
24 |
+
return $this->model;
|
25 |
+
}
|
26 |
+
|
27 |
+
public function display() {
|
28 |
+
|
29 |
+
$this->model = new ModelStyle($this);
|
30 |
+
|
31 |
+
$this->renderTemplatePart('Index');
|
32 |
+
}
|
33 |
+
|
34 |
+
public function displayTopBar() {
|
35 |
+
|
36 |
+
$buttonCancel = new BlockButtonCancel($this);
|
37 |
+
$buttonCancel->addClass('n2_fullscreen_editor__cancel');
|
38 |
+
$buttonCancel->display();
|
39 |
+
|
40 |
+
$buttonApply = new BlockButtonApply($this);
|
41 |
+
$buttonApply->addClass('n2_fullscreen_editor__save');
|
42 |
+
$buttonApply->display();
|
43 |
+
}
|
44 |
+
|
45 |
+
public function displayContent() {
|
46 |
+
$model = $this->getModel();
|
47 |
+
|
48 |
+
Js::addFirstCode("
|
49 |
+
N2Classes.CSSRendererStyle.rendererModes = " . json_encode(StyleRenderer::$mode) . ";
|
50 |
+
N2Classes.CSSRendererStyle.pre = " . json_encode(StyleRenderer::$pre) . ";
|
51 |
+
new N2Classes.NextendStyleManager();
|
52 |
+
");
|
53 |
+
|
54 |
+
$model->renderForm();
|
55 |
+
}
|
56 |
+
}
|
Nextend/Framework/Style/Block/StyleManager/Index.phtml
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Style\Block\StyleManager;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* @var BlockStyleManager $this
|
7 |
+
*/
|
8 |
+
?>
|
9 |
+
<div id="n2-lightbox-style" class="n2_fullscreen_editor">
|
10 |
+
<div class="n2_fullscreen_editor__overlay"></div>
|
11 |
+
<div class="n2_fullscreen_editor__window">
|
12 |
+
<div class="n2_fullscreen_editor__nav_bar">
|
13 |
+
<div class="n2_fullscreen_editor__nav_bar_label">
|
14 |
+
<?php n2_e('Style manager'); ?>
|
15 |
+
</div>
|
16 |
+
<div class="n2_fullscreen_editor__nav_bar_actions">
|
17 |
+
<?php $this->displayTopBar(); ?>
|
18 |
+
</div>
|
19 |
+
</div>
|
20 |
+
<div class="n2_fullscreen_editor__content">
|
21 |
+
<div class="n2_fullscreen_editor__content_content n2_container_scrollable">
|
22 |
+
<?php $this->displayContent(); ?>
|
23 |
+
</div>
|
24 |
+
</div>
|
25 |
+
</div>
|
26 |
+
</div>
|
Nextend/Framework/Style/ControllerAjaxStyle.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Style;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Controller\Admin\AdminVisualManagerAjaxController;
|
8 |
+
|
9 |
+
class ControllerAjaxStyle extends AdminVisualManagerAjaxController {
|
10 |
+
|
11 |
+
protected $type = 'style';
|
12 |
+
|
13 |
+
public function getModel() {
|
14 |
+
|
15 |
+
return new ModelStyle($this);
|
16 |
+
}
|
17 |
+
}
|
Nextend/Framework/Style/ModelCss.php
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Style;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Model\AbstractModel;
|
8 |
+
use Nextend\Framework\Model\StorageSectionManager;
|
9 |
+
|
10 |
+
class ModelCss extends AbstractModel {
|
11 |
+
|
12 |
+
public $storage;
|
13 |
+
|
14 |
+
protected function init() {
|
15 |
+
|
16 |
+
$this->storage = StorageSectionManager::getStorage('system');
|
17 |
+
}
|
18 |
+
|
19 |
+
public function addVisual($type, $visual) {
|
20 |
+
|
21 |
+
$visualId = $this->storage->add($type, '', $visual);
|
22 |
+
|
23 |
+
$visual = $this->storage->getById($visualId, $type);
|
24 |
+
if (!empty($visual) && $visual['section'] == $type) {
|
25 |
+
return $visual;
|
26 |
+
}
|
27 |
+
|
28 |
+
return false;
|
29 |
+
}
|
30 |
+
|
31 |
+
public function deleteVisual($type, $id) {
|
32 |
+
$visual = $this->storage->getById($id, $type);
|
33 |
+
if (!empty($visual) && $visual['section'] == $type) {
|
34 |
+
$this->storage->deleteById($id);
|
35 |
+
|
36 |
+
return $visual;
|
37 |
+
}
|
38 |
+
|
39 |
+
return false;
|
40 |
+
}
|
41 |
+
|
42 |
+
public function changeVisual($type, $id, $value) {
|
43 |
+
if ($this->storage->setById($id, $value)) {
|
44 |
+
return $this->storage->getById($id, $type);
|
45 |
+
}
|
46 |
+
|
47 |
+
return false;
|
48 |
+
}
|
49 |
+
|
50 |
+
public function getVisuals($type) {
|
51 |
+
return $this->storage->getAll($type);
|
52 |
+
}
|
53 |
+
|
54 |
+
}
|
Nextend/Framework/Style/ModelStyle.php
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Style;
|
4 |
+
|
5 |
+
use Nextend\Framework\Form\Container\ContainerTable;
|
6 |
+
use Nextend\Framework\Form\Element\Button;
|
7 |
+
use Nextend\Framework\Form\Element\MarginPadding;
|
8 |
+
use Nextend\Framework\Form\Element\Mixed;
|
9 |
+
use Nextend\Framework\Form\Element\Tab;
|
10 |
+
use Nextend\Framework\Form\Element\Text\Color;
|
11 |
+
use Nextend\Framework\Form\Element\Text\NumberAutoComplete;
|
12 |
+
use Nextend\Framework\Form\Element\Textarea;
|
13 |
+
use Nextend\Framework\Form\Element\Unit;
|
14 |
+
use Nextend\Framework\Form\Form;
|
15 |
+
use Nextend\Framework\Visual\ModelVisual;
|
16 |
+
|
17 |
+
class ModelStyle extends ModelVisual {
|
18 |
+
|
19 |
+
protected $type = 'style';
|
20 |
+
|
21 |
+
public function renderForm() {
|
22 |
+
|
23 |
+
$form = new Form($this, 'n2-style-editor');
|
24 |
+
|
25 |
+
$table = new ContainerTable($form->getContainer(), 'style', n2_('Style settings'));
|
26 |
+
|
27 |
+
$table->setFieldsetPositionEnd();
|
28 |
+
|
29 |
+
new Button($table->getFieldsetLabel(), 'style-clear-tab', false, n2_('Clear tab'));
|
30 |
+
|
31 |
+
new Tab($table->getFieldsetLabel(), 'style-state');
|
32 |
+
|
33 |
+
$row1 = $table->createRow('style-row-1');
|
34 |
+
|
35 |
+
new Color($row1, 'backgroundcolor', n2_('Background color'), '000000FF', array(
|
36 |
+
'alpha' => true
|
37 |
+
));
|
38 |
+
|
39 |
+
new NumberAutoComplete($row1, 'opacity', n2_('Opacity'), '100', array(
|
40 |
+
'values' => array(
|
41 |
+
0,
|
42 |
+
50,
|
43 |
+
90,
|
44 |
+
100
|
45 |
+
),
|
46 |
+
'unit' => '%',
|
47 |
+
'wide' => 3
|
48 |
+
));
|
49 |
+
|
50 |
+
$padding = new MarginPadding($row1, 'padding', n2_('Padding'), '0|*|0|*|0|*|0|*|px');
|
51 |
+
for ($i = 1; $i < 5; $i++) {
|
52 |
+
new NumberAutoComplete($padding, 'padding-' . $i, false, '', array(
|
53 |
+
'values' => array(
|
54 |
+
0,
|
55 |
+
5,
|
56 |
+
10,
|
57 |
+
20,
|
58 |
+
30
|
59 |
+
),
|
60 |
+
'wide' => 3
|
61 |
+
));
|
62 |
+
}
|
63 |
+
|
64 |
+
new Unit($padding, 'padding-5', '', '', array(
|
65 |
+
'units' => array(
|
66 |
+
'px',
|
67 |
+
'em',
|
68 |
+
'%'
|
69 |
+
)
|
70 |
+
));
|
71 |
+
|
72 |
+
new Mixed\Border($row1, 'border', n2_('Border'), '0|*|solid|*|000000ff');
|
73 |
+
|
74 |
+
new NumberAutoComplete($row1, 'borderradius', n2_('Border radius'), '0', array(
|
75 |
+
'values' => array(
|
76 |
+
0,
|
77 |
+
3,
|
78 |
+
5,
|
79 |
+
10,
|
80 |
+
99
|
81 |
+
),
|
82 |
+
'unit' => 'px',
|
83 |
+
'wide' => 3
|
84 |
+
));
|
85 |
+
|
86 |
+
|
87 |
+
new Mixed\BoxShadow($row1, 'boxshadow', n2_('Box shadow'), '0|*|0|*|0|*|0|*|000000ff');
|
88 |
+
|
89 |
+
new Textarea($row1, 'extracss', 'CSS', '', array(
|
90 |
+
'width' => 200,
|
91 |
+
'height' => 26
|
92 |
+
));
|
93 |
+
|
94 |
+
$previewTable = new ContainerTable($form->getContainer(), 'style-preview', n2_('Preview'));
|
95 |
+
|
96 |
+
$previewTable->setFieldsetPositionEnd();
|
97 |
+
|
98 |
+
new Color($previewTable->getFieldsetLabel(), 'preview-background', false, 'ced3d5');
|
99 |
+
|
100 |
+
$form->render();
|
101 |
+
}
|
102 |
+
}
|
Nextend/Framework/Style/Style.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Style;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Parser\Color;
|
8 |
+
|
9 |
+
class Style {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @param string $tab
|
13 |
+
*
|
14 |
+
* @return string
|
15 |
+
*/
|
16 |
+
public function style($tab) {
|
17 |
+
$style = '';
|
18 |
+
$extra = '';
|
19 |
+
if (isset($tab['extra'])) {
|
20 |
+
$extra = $tab['extra'];
|
21 |
+
unset($tab['extra']);
|
22 |
+
}
|
23 |
+
foreach ($tab AS $k => $v) {
|
24 |
+
$style .= $this->parse($k, $v);
|
25 |
+
}
|
26 |
+
$style .= $this->parse('extra', $extra);
|
27 |
+
|
28 |
+
return $style;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @param $property
|
33 |
+
* @param $value
|
34 |
+
*
|
35 |
+
* @return mixed
|
36 |
+
*/
|
37 |
+
public function parse($property, $value) {
|
38 |
+
$fn = 'parse' . $property;
|
39 |
+
|
40 |
+
return $this->$fn($value);
|
41 |
+
}
|
42 |
+
|
43 |
+
public function parseBackgroundColor($v) {
|
44 |
+
$hex = Color::hex82hex($v);
|
45 |
+
if ($hex[1] == 'ff') {
|
46 |
+
return 'background: #' . $hex[0] . ';';
|
47 |
+
}
|
48 |
+
|
49 |
+
$rgba = Color::hex2rgba($v);
|
50 |
+
|
51 |
+
return 'background: RGBA(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ');';
|
52 |
+
}
|
53 |
+
|
54 |
+
public function parseOpacity($v) {
|
55 |
+
return 'opacity:' . (intval($v) / 100) . ';';
|
56 |
+
}
|
57 |
+
|
58 |
+
public function parsePadding($v) {
|
59 |
+
$padding = explode('|*|', $v);
|
60 |
+
$unit = array_pop($padding);
|
61 |
+
$padding[] = '';
|
62 |
+
|
63 |
+
return 'padding:' . implode($unit . ' ', $padding) . ';';
|
64 |
+
}
|
65 |
+
|
66 |
+
public function parseBoxShadow($v) {
|
67 |
+
$boxShadow = explode('|*|', $v);
|
68 |
+
|
69 |
+
if ($boxShadow[0] == '0' && $boxShadow[1] == '0' && $boxShadow[2] == '0' && $boxShadow[3] == '0') {
|
70 |
+
return 'box-shadow: none;';
|
71 |
+
} else {
|
72 |
+
$rgba = Color::hex2rgba($boxShadow[4]);
|
73 |
+
|
74 |
+
return 'box-shadow: ' . $boxShadow[0] . 'px ' . $boxShadow[1] . 'px ' . $boxShadow[2] . 'px ' . $boxShadow[3] . 'px RGBA(' . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ');';
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
public function parseBorder($v) {
|
79 |
+
$border = explode('|*|', $v);
|
80 |
+
$style = 'border-width: ' . $border[0] . 'px;';
|
81 |
+
$style .= 'border-style: ' . $border[1] . ';';
|
82 |
+
$rgba = Color::hex2rgba($border[2]);
|
83 |
+
$style .= 'border-color: #' . substr($border[2], 0, 6) . "; border-color: RGBA(" . $rgba[0] . ',' . $rgba[1] . ',' . $rgba[2] . ',' . round($rgba[3] / 127, 2) . ');';
|
84 |
+
|
85 |
+
return $style;
|
86 |
+
}
|
87 |
+
|
88 |
+
public function parseBorderRadius($v) {
|
89 |
+
return 'border-radius:' . $v . 'px;';
|
90 |
+
}
|
91 |
+
|
92 |
+
public function parseExtra($v) {
|
93 |
+
return $v;
|
94 |
+
}
|
95 |
+
}
|
Nextend/Framework/Style/StyleManager.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Style;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Pattern\VisualManagerTrait;
|
8 |
+
use Nextend\Framework\Style\Block\StyleManager\BlockStyleManager;
|
9 |
+
|
10 |
+
class StyleManager {
|
11 |
+
|
12 |
+
use VisualManagerTrait;
|
13 |
+
|
14 |
+
public function display() {
|
15 |
+
|
16 |
+
$fontManagerBlock = new BlockStyleManager($this->MVCHelper);
|
17 |
+
$fontManagerBlock->display();
|
18 |
+
}
|
19 |
+
}
|
Nextend/Framework/Style/StyleParser.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Style;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Misc\Base64;
|
8 |
+
use Nextend\Framework\Model\Section;
|
9 |
+
|
10 |
+
class StyleParser {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @param $data
|
14 |
+
*
|
15 |
+
* @return string
|
16 |
+
*/
|
17 |
+
public static function parse($data) {
|
18 |
+
if (empty($data)) {
|
19 |
+
return '';
|
20 |
+
} else if (is_numeric($data)) {
|
21 |
+
/**
|
22 |
+
* Linked style
|
23 |
+
*/
|
24 |
+
|
25 |
+
$style = Section::getById($data, 'style');
|
26 |
+
|
27 |
+
if (!$style) {
|
28 |
+
/**
|
29 |
+
* Linked style not exists anymore
|
30 |
+
*/
|
31 |
+
return '';
|
32 |
+
}
|
33 |
+
|
34 |
+
|
35 |
+
if (is_string($style['value'])) {
|
36 |
+
/**
|
37 |
+
* Old format when value stored as Base64
|
38 |
+
*/
|
39 |
+
$decoded = $style['value'];
|
40 |
+
if ($decoded[0] != '{') {
|
41 |
+
$decoded = Base64::decode($decoded);
|
42 |
+
}
|
43 |
+
|
44 |
+
return $decoded;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Value stored as array
|
49 |
+
*/
|
50 |
+
$value = json_encode($style['value']);
|
51 |
+
if ($value == false) {
|
52 |
+
return '';
|
53 |
+
}
|
54 |
+
|
55 |
+
return $value;
|
56 |
+
} else if ($data[0] != '{') {
|
57 |
+
return Base64::decode($data);
|
58 |
+
}
|
59 |
+
|
60 |
+
return $data;
|
61 |
+
}
|
62 |
+
|
63 |
+
}
|
Nextend/Framework/Style/StyleRenderer.php
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Style;
|
4 |
+
|
5 |
+
use Nextend\Framework\Settings;
|
6 |
+
|
7 |
+
class StyleRenderer {
|
8 |
+
|
9 |
+
public static $pre = '';
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var Style
|
13 |
+
*/
|
14 |
+
public static $style;
|
15 |
+
|
16 |
+
public static $mode;
|
17 |
+
|
18 |
+
public static function render($style, $mode, $pre = '') {
|
19 |
+
self::$pre = $pre;
|
20 |
+
|
21 |
+
if (!empty($style)) {
|
22 |
+
|
23 |
+
$value = json_decode($style, true);
|
24 |
+
if ($value) {
|
25 |
+
$selector = 'n2-style-' . md5($style) . '-' . $mode;
|
26 |
+
|
27 |
+
return array(
|
28 |
+
$selector . ' ',
|
29 |
+
self::renderStyle($mode, $pre, $selector, $value['data'])
|
30 |
+
);
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
return false;
|
35 |
+
}
|
36 |
+
|
37 |
+
private static function renderStyle($mode, $pre, $selector, $tabs) {
|
38 |
+
$search = array(
|
39 |
+
'@pre',
|
40 |
+
'@selector'
|
41 |
+
);
|
42 |
+
$replace = array(
|
43 |
+
$pre,
|
44 |
+
'.' . $selector
|
45 |
+
);
|
46 |
+
$tabs[0] = array_merge(array(
|
47 |
+
'backgroundcolor' => 'ffffff00',
|
48 |
+
'opacity' => 100,
|
49 |
+
'padding' => '0|*|0|*|0|*|0|*|px',
|
50 |
+
'boxshadow' => '0|*|0|*|0|*|0|*|000000ff',
|
51 |
+
'border' => '0|*|solid|*|000000ff',
|
52 |
+
'borderradius' => '0',
|
53 |
+
'extra' => '',
|
54 |
+
), $tabs[0]);
|
55 |
+
|
56 |
+
foreach ($tabs AS $k => $tab) {
|
57 |
+
$search[] = '@tab' . $k;
|
58 |
+
$replace[] = self::$style->style($tab);
|
59 |
+
}
|
60 |
+
|
61 |
+
$template = '';
|
62 |
+
foreach (self::$mode[$mode]['selectors'] AS $s => $style) {
|
63 |
+
if (!in_array($style, $search) || !empty($replace[array_search($style, $search)])) {
|
64 |
+
$template .= $s . "{" . $style . "}";
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
return str_replace($search, $replace, $template);
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
|
73 |
+
$frontendAccessibility = intval(Settings::get('frontend-accessibility', 1));
|
74 |
+
|
75 |
+
StyleRenderer::$mode = array(
|
76 |
+
'0' => array(
|
77 |
+
'id' => '0',
|
78 |
+
'label' => n2_('Single'),
|
79 |
+
'tabs' => array(
|
80 |
+
n2_('Text')
|
81 |
+
),
|
82 |
+
'renderOptions' => array(
|
83 |
+
'combined' => false
|
84 |
+
),
|
85 |
+
'preview' => '<div class="{styleClassName}">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>',
|
86 |
+
'selectors' => array(
|
87 |
+
'@pre@selector' => '@tab'
|
88 |
+
)
|
89 |
+
),
|
90 |
+
'simple' => array(
|
91 |
+
'id' => 'simple',
|
92 |
+
'label' => n2_('Simple'),
|
93 |
+
'tabs' => array(
|
94 |
+
n2_('Normal')
|
95 |
+
),
|
96 |
+
'renderOptions' => array(
|
97 |
+
'combined' => true
|
98 |
+
),
|
99 |
+
'preview' => '<div class="{styleClassName}" style="width: 200px; height:100px;"></div>',
|
100 |
+
'selectors' => array(
|
101 |
+
'@pre@selector' => '@tab0'
|
102 |
+
)
|
103 |
+
),
|
104 |
+
'box' => array(
|
105 |
+
'id' => 'box',
|
106 |
+
'label' => n2_('Box'),
|
107 |
+
'tabs' => array(
|
108 |
+
n2_('Normal'),
|
109 |
+
n2_('Hover')
|
110 |
+
),
|
111 |
+
'renderOptions' => array(
|
112 |
+
'combined' => true
|
113 |
+
),
|
114 |
+
'preview' => '<div class="{styleClassName}" style="width: 200px; height:100px;"></div>',
|
115 |
+
'selectors' => array(
|
116 |
+
'@pre@selector' => '@tab0',
|
117 |
+
'@pre@selector:HOVER' => '@tab1'
|
118 |
+
)
|
119 |
+
),
|
120 |
+
'button' => array(
|
121 |
+
'id' => 'button',
|
122 |
+
'label' => n2_('Button'),
|
123 |
+
'tabs' => array(
|
124 |
+
n2_('Normal'),
|
125 |
+
n2_('Hover')
|
126 |
+
),
|
127 |
+
'renderOptions' => array(
|
128 |
+
'combined' => true
|
129 |
+
),
|
130 |
+
'preview' => '<div><a style="display:inline-block; margin:20px;" class="{styleClassName}" href="#" onclick="return false;">Button</a></div>',
|
131 |
+
'selectors' => $frontendAccessibility ? array(
|
132 |
+
'@pre@selector' => '@tab0',
|
133 |
+
'@pre@selector:Hover, @pre@selector:ACTIVE, @pre@selector:FOCUS' => '@tab1'
|
134 |
+
) : array(
|
135 |
+
'@pre@selector, @pre@selector:FOCUS' => '@tab0',
|
136 |
+
'@pre@selector:Hover, @pre@selector:ACTIVE' => '@tab1'
|
137 |
+
)
|
138 |
+
),
|
139 |
+
'heading' => array(
|
140 |
+
'id' => 'heading',
|
141 |
+
'label' => n2_('Heading'),
|
142 |
+
'tabs' => array(
|
143 |
+
n2_('Normal'),
|
144 |
+
n2_('Hover')
|
145 |
+
),
|
146 |
+
'renderOptions' => array(
|
147 |
+
'combined' => true
|
148 |
+
),
|
149 |
+
'preview' => '<div class="{styleClassName}">Heading</div>',
|
150 |
+
'selectors' => $frontendAccessibility ? array(
|
151 |
+
'@pre@selector' => '@tab0',
|
152 |
+
'@pre@selector:Hover, @pre@selector:ACTIVE, @pre@selector:FOCUS' => '@tab1'
|
153 |
+
) : array(
|
154 |
+
'@pre@selector, @pre@selector:FOCUS' => '@tab0',
|
155 |
+
'@pre@selector:Hover, @pre@selector:ACTIVE' => '@tab1'
|
156 |
+
)
|
157 |
+
),
|
158 |
+
'heading-active' => array(
|
159 |
+
'id' => 'heading-active',
|
160 |
+
'label' => n2_('Heading active'),
|
161 |
+
'tabs' => array(
|
162 |
+
n2_('Normal'),
|
163 |
+
n2_('Active')
|
164 |
+
),
|
165 |
+
'renderOptions' => array(
|
166 |
+
'combined' => true
|
167 |
+
),
|
168 |
+
'preview' => '<div class="{styleClassName}">Heading</div>',
|
169 |
+
'selectors' => array(
|
170 |
+
'@pre@selector' => '@tab0',
|
171 |
+
'@pre@selector.n2-active' => '@tab1'
|
172 |
+
)
|
173 |
+
),
|
174 |
+
'dot' => array(
|
175 |
+
'id' => 'dot',
|
176 |
+
'label' => n2_('Dot'),
|
177 |
+
'tabs' => array(
|
178 |
+
n2_('Normal'),
|
179 |
+
n2_('Active')
|
180 |
+
),
|
181 |
+
'renderOptions' => array(
|
182 |
+
'combined' => true
|
183 |
+
),
|
184 |
+
'preview' => '<div><div class="{styleClassName}" style="display: inline-block; margin: 3px;"></div><div class="{styleClassName} n2-active" style="display: inline-block; margin: 3px;"></div><div class="{styleClassName}" style="display: inline-block; margin: 3px;"></div></div>',
|
185 |
+
'selectors' => array(
|
186 |
+
'@pre@selector' => '@tab0',
|
187 |
+
'@pre@selector.n2-active, @pre@selector:HOVER, @pre@selector:FOCUS' => '@tab1'
|
188 |
+
)
|
189 |
+
),
|
190 |
+
'highlight' => array(
|
191 |
+
'id' => 'highlight',
|
192 |
+
'label' => n2_('Highlight'),
|
193 |
+
'tabs' => array(
|
194 |
+
n2_('Normal'),
|
195 |
+
n2_('Highlight'),
|
196 |
+
n2_('Hover')
|
197 |
+
),
|
198 |
+
'renderOptions' => array(
|
199 |
+
'combined' => true
|
200 |
+
),
|
201 |
+
'preview' => '<div class="{fontClassName}">' . n2_('Button') . '</div>',
|
202 |
+
'selectors' => $frontendAccessibility ? array(
|
203 |
+
'@pre@selector' => '@tab0',
|
204 |
+
'@pre@selector .n2-highlighted' => '@tab1',
|
205 |
+
'@pre@selector .n2-highlighted:HOVER, @pre@selector .n2-highlighted:ACTIVE, @pre@selector .n2-highlighted:FOCUS' => '@tab2'
|
206 |
+
) : array(
|
207 |
+
'@pre@selector' => '@tab0',
|
208 |
+
'@pre@selector .n2-highlighted, @pre@selector .n2-highlighted:FOCUS' => '@tab1',
|
209 |
+
'@pre@selector .n2-highlighted:HOVER, @pre@selector .n2-highlighted:ACTIVE' => '@tab2'
|
210 |
+
)
|
211 |
+
),
|
212 |
+
);
|
213 |
+
|
214 |
+
|
215 |
+
StyleRenderer::$style = new Style();
|
Nextend/Framework/Style/StyleStorage.php
ADDED
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Style;
|
4 |
+
|
5 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
6 |
+
use Nextend\Framework\Plugin;
|
7 |
+
|
8 |
+
class StyleStorage {
|
9 |
+
|
10 |
+
use SingletonTrait;
|
11 |
+
|
12 |
+
private $sets = array();
|
13 |
+
|
14 |
+
private $styles = array();
|
15 |
+
|
16 |
+
private $stylesBySet = array();
|
17 |
+
|
18 |
+
private $stylesById = array();
|
19 |
+
|
20 |
+
protected function init() {
|
21 |
+
|
22 |
+
|
23 |
+
Plugin::addAction('systemstyleset', array(
|
24 |
+
$this,
|
25 |
+
'styleSet'
|
26 |
+
));
|
27 |
+
Plugin::addAction('systemstyle', array(
|
28 |
+
$this,
|
29 |
+
'styles'
|
30 |
+
));
|
31 |
+
Plugin::addAction('style', array(
|
32 |
+
$this,
|
33 |
+
'style'
|
34 |
+
));
|
35 |
+
}
|
36 |
+
|
37 |
+
private function load() {
|
38 |
+
static $loaded;
|
39 |
+
if (!$loaded) {
|
40 |
+
Plugin::doAction('styleStorage', array(
|
41 |
+
&$this->sets,
|
42 |
+
&$this->styles
|
43 |
+
));
|
44 |
+
|
45 |
+
for ($i = 0; $i < count($this->styles); $i++) {
|
46 |
+
if (!isset($this->stylesBySet[$this->styles[$i]['referencekey']])) {
|
47 |
+
$this->stylesBySet[$this->styles[$i]['referencekey']] = array();
|
48 |
+
}
|
49 |
+
$this->stylesBySet[$this->styles[$i]['referencekey']][] = &$this->styles[$i];
|
50 |
+
$this->stylesById[$this->styles[$i]['id']] = &$this->styles[$i];
|
51 |
+
}
|
52 |
+
$loaded = true;
|
53 |
+
}
|
54 |
+
}
|
55 |
+
|
56 |
+
public function styleSet($referenceKey, &$sets) {
|
57 |
+
|
58 |
+
$this->load();
|
59 |
+
|
60 |
+
for ($i = count($this->sets) - 1; $i >= 0; $i--) {
|
61 |
+
$this->sets[$i]['system'] = 1;
|
62 |
+
$this->sets[$i]['editable'] = 0;
|
63 |
+
array_unshift($sets, $this->sets[$i]);
|
64 |
+
}
|
65 |
+
|
66 |
+
}
|
67 |
+
|
68 |
+
public function styles($referenceKey, &$styles) {
|
69 |
+
|
70 |
+
$this->load();
|
71 |
+
|
72 |
+
if (isset($this->stylesBySet[$referenceKey])) {
|
73 |
+
$_styles = &$this->stylesBySet[$referenceKey];
|
74 |
+
for ($i = count($_styles) - 1; $i >= 0; $i--) {
|
75 |
+
$_styles[$i]['system'] = 1;
|
76 |
+
$_styles[$i]['editable'] = 0;
|
77 |
+
array_unshift($styles, $_styles[$i]);
|
78 |
+
}
|
79 |
+
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
public function style($id, &$style) {
|
84 |
+
|
85 |
+
$this->load();
|
86 |
+
|
87 |
+
if (isset($this->stylesById[$id])) {
|
88 |
+
$this->stylesById[$id]['system'] = 1;
|
89 |
+
$this->stylesById[$id]['editable'] = 0;
|
90 |
+
$style = $this->stylesById[$id];
|
91 |
+
}
|
92 |
+
}
|
93 |
+
}
|
Nextend/Framework/Translation/AbstractTranslation.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Translation;
|
4 |
+
|
5 |
+
abstract class AbstractTranslation {
|
6 |
+
|
7 |
+
public function _($text) {
|
8 |
+
return $text;
|
9 |
+
}
|
10 |
+
|
11 |
+
public function getLocale() {
|
12 |
+
return 'en_US';
|
13 |
+
}
|
14 |
+
}
|
Nextend/Framework/Translation/Translation.php
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Translation;
|
4 |
+
|
5 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
6 |
+
|
7 |
+
class Translation {
|
8 |
+
|
9 |
+
use SingletonTrait;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var AbstractTranslation
|
13 |
+
*/
|
14 |
+
private static $platformTranslation;
|
15 |
+
|
16 |
+
public function __construct() {
|
17 |
+
self::$platformTranslation = new WordPress\WordPressTranslation();
|
18 |
+
}
|
19 |
+
|
20 |
+
public static function _($text) {
|
21 |
+
return self::$platformTranslation->_($text);
|
22 |
+
}
|
23 |
+
|
24 |
+
public static function getCurrentLocale() {
|
25 |
+
return self::$platformTranslation->getLocale();
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
Translation::getInstance();
|
Nextend/Framework/Translation/WordPress/WordPressTranslation.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Translation\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Translation\AbstractTranslation;
|
6 |
+
|
7 |
+
class WordPressTranslation extends AbstractTranslation {
|
8 |
+
|
9 |
+
public function __construct() {
|
10 |
+
|
11 |
+
if (defined('QTRANSLATE_FILE')) {
|
12 |
+
add_filter('nextend_translation', 'qtranxf_useCurrentLanguageIfNotFoundShowAvailable', 0);
|
13 |
+
}
|
14 |
+
}
|
15 |
+
|
16 |
+
public function _($text) {
|
17 |
+
return apply_filters('nextend_translation', $text);
|
18 |
+
}
|
19 |
+
|
20 |
+
public function getLocale() {
|
21 |
+
return is_admin() && function_exists('get_user_locale') ? get_user_locale() : get_locale();
|
22 |
+
}
|
23 |
+
}
|
Nextend/Framework/Url/AbstractPlatformUrl.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Url;
|
4 |
+
|
5 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
6 |
+
|
7 |
+
abstract class AbstractPlatformUrl {
|
8 |
+
|
9 |
+
public $uris = array();
|
10 |
+
|
11 |
+
protected $siteUrl;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var string It can be relative or absolute uri. It must not end with /
|
15 |
+
* @example https://asd.com/wordpress
|
16 |
+
* @example /wordpress
|
17 |
+
*/
|
18 |
+
protected $_baseuri;
|
19 |
+
|
20 |
+
protected $_currentbase = '';
|
21 |
+
|
22 |
+
protected $scheme = 'http';
|
23 |
+
|
24 |
+
public function getUris() {
|
25 |
+
|
26 |
+
return $this->uris;
|
27 |
+
}
|
28 |
+
|
29 |
+
protected function getUriByIndex($i, $protocol = true) {
|
30 |
+
if (!$protocol) {
|
31 |
+
return preg_replace('/^http:/', '', $this->uris[$i]);
|
32 |
+
}
|
33 |
+
|
34 |
+
return $this->uris[$i];
|
35 |
+
}
|
36 |
+
|
37 |
+
public function setBaseUri($uri) {
|
38 |
+
$this->_baseuri = $uri;
|
39 |
+
}
|
40 |
+
|
41 |
+
public function getSiteUri() {
|
42 |
+
return $this->siteUrl;
|
43 |
+
}
|
44 |
+
|
45 |
+
public function getBaseUri() {
|
46 |
+
|
47 |
+
return $this->_baseuri;
|
48 |
+
}
|
49 |
+
|
50 |
+
public function getFullUri() {
|
51 |
+
|
52 |
+
return $this->_baseuri;
|
53 |
+
}
|
54 |
+
|
55 |
+
public function pathToUri($path, $protocol = true) {
|
56 |
+
|
57 |
+
$from = array();
|
58 |
+
$to = array();
|
59 |
+
|
60 |
+
$basePath = Filesystem::getBasePath();
|
61 |
+
if ($basePath != '/' && $basePath != "\\") {
|
62 |
+
$from[] = $basePath;
|
63 |
+
$to[] = '';
|
64 |
+
}
|
65 |
+
$from[] = DIRECTORY_SEPARATOR;
|
66 |
+
$to[] = '/';
|
67 |
+
|
68 |
+
return ($protocol ? $this->_baseuri : preg_replace('/^http:/', '', $this->_baseuri)) . str_replace($from, $to, str_replace('/', DIRECTORY_SEPARATOR, $path));
|
69 |
+
}
|
70 |
+
|
71 |
+
public function ajaxUri($query = '') {
|
72 |
+
|
73 |
+
return $this->_baseuri;
|
74 |
+
}
|
75 |
+
|
76 |
+
public function fixrelative($uri) {
|
77 |
+
if (substr($uri, 0, 1) == '/' || strpos($uri, '://') !== false) return $uri;
|
78 |
+
|
79 |
+
return $this->_baseuri . $uri;
|
80 |
+
}
|
81 |
+
|
82 |
+
public function relativetoabsolute($uri) {
|
83 |
+
|
84 |
+
if (strpos($uri, '://') !== false) return $uri;
|
85 |
+
if (!empty($this->_baseuri) && strpos($uri, $this->_baseuri) === 0) {
|
86 |
+
$uri = substr($uri, strlen($this->_baseuri));
|
87 |
+
}
|
88 |
+
|
89 |
+
return $this->_currentbase . $uri;
|
90 |
+
}
|
91 |
+
|
92 |
+
public function addScheme($url) {
|
93 |
+
return $this->scheme . ':' . $url;
|
94 |
+
}
|
95 |
+
}
|
Nextend/Framework/Url/Url.php
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Url;
|
4 |
+
|
5 |
+
use Nextend\Framework\Url\Joomla\JoomlaUrl;
|
6 |
+
use Nextend\Framework\Url\WordPress\WordPressUrl;
|
7 |
+
|
8 |
+
class Url {
|
9 |
+
|
10 |
+
/**
|
11 |
+
* @var AbstractPlatformUrl
|
12 |
+
*/
|
13 |
+
private static $platformUrl;
|
14 |
+
|
15 |
+
public function __construct() {
|
16 |
+
self::$platformUrl = new WordPressUrl();
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @return AbstractPlatformUrl
|
21 |
+
*/
|
22 |
+
public static function get() {
|
23 |
+
|
24 |
+
return self::$platformUrl;
|
25 |
+
}
|
26 |
+
|
27 |
+
public static function getUris() {
|
28 |
+
|
29 |
+
return self::$platformUrl->getUris();
|
30 |
+
}
|
31 |
+
|
32 |
+
public static function setBaseUri($uri) {
|
33 |
+
self::$platformUrl->setBaseUri($uri);
|
34 |
+
}
|
35 |
+
|
36 |
+
public static function getSiteUri() {
|
37 |
+
return self::$platformUrl->getSiteUri();
|
38 |
+
}
|
39 |
+
|
40 |
+
public static function getBaseUri() {
|
41 |
+
|
42 |
+
return self::$platformUrl->getBaseUri();
|
43 |
+
}
|
44 |
+
|
45 |
+
public static function getFullUri() {
|
46 |
+
|
47 |
+
return self::$platformUrl->getFullUri();
|
48 |
+
}
|
49 |
+
|
50 |
+
public static function pathToUri($path, $protocol = true) {
|
51 |
+
|
52 |
+
return self::$platformUrl->pathToUri($path, $protocol);
|
53 |
+
}
|
54 |
+
|
55 |
+
public static function ajaxUri($query = '') {
|
56 |
+
|
57 |
+
return self::$platformUrl->ajaxUri($query);
|
58 |
+
}
|
59 |
+
|
60 |
+
public static function fixrelative($uri) {
|
61 |
+
|
62 |
+
return self::$platformUrl->fixrelative($uri);
|
63 |
+
}
|
64 |
+
|
65 |
+
public static function relativetoabsolute($uri) {
|
66 |
+
|
67 |
+
return self::$platformUrl->relativetoabsolute($uri);
|
68 |
+
}
|
69 |
+
|
70 |
+
public static function addScheme($url) {
|
71 |
+
|
72 |
+
return self::$platformUrl->addScheme($url);
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
new Url();
|
Nextend/Framework/Url/UrlHelper.php
ADDED
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Url;
|
5 |
+
|
6 |
+
|
7 |
+
class UrlHelper {
|
8 |
+
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Retrieves a modified URL query string.
|
12 |
+
*
|
13 |
+
* You can rebuild the URL and append query variables to the URL query by using this function.
|
14 |
+
* There are two ways to use this function; either a single key and value, or an associative array.
|
15 |
+
*
|
16 |
+
* Using a single key and value:
|
17 |
+
*
|
18 |
+
* add_query_arg( 'key', 'value', 'http://example.com' );
|
19 |
+
*
|
20 |
+
* Using an associative array:
|
21 |
+
*
|
22 |
+
* add_query_arg( array(
|
23 |
+
* 'key1' => 'value1',
|
24 |
+
* 'key2' => 'value2',
|
25 |
+
* ), 'http://example.com' );
|
26 |
+
*
|
27 |
+
* Omitting the URL from either use results in the current URL being used
|
28 |
+
* (the value of `$_SERVER['REQUEST_URI']`).
|
29 |
+
*
|
30 |
+
* Values are expected to be encoded appropriately with urlencode() or rawurlencode().
|
31 |
+
*
|
32 |
+
* Setting any query variable's value to boolean false removes the key (see remove_query_arg()).
|
33 |
+
*
|
34 |
+
* Important: The return value of add_query_arg() is not escaped by default. Output should be
|
35 |
+
* late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
|
36 |
+
* (XSS) attacks.
|
37 |
+
*
|
38 |
+
* @param string|array $key Either a query variable key, or an associative array of query variables.
|
39 |
+
* @param string $value Optional. Either a query variable value, or a URL to act upon.
|
40 |
+
* @param string $url Optional. A URL to act upon.
|
41 |
+
*
|
42 |
+
* @return string New URL query string (unescaped).
|
43 |
+
*
|
44 |
+
*/
|
45 |
+
public static function add_query_arg() {
|
46 |
+
$args = func_get_args();
|
47 |
+
if (is_array($args[0])) {
|
48 |
+
if (count($args) < 2 || false === $args[1]) {
|
49 |
+
$uri = $_SERVER['REQUEST_URI'];
|
50 |
+
} else {
|
51 |
+
$uri = $args[1];
|
52 |
+
}
|
53 |
+
} else {
|
54 |
+
if (count($args) < 3 || false === $args[2]) {
|
55 |
+
$uri = $_SERVER['REQUEST_URI'];
|
56 |
+
} else {
|
57 |
+
$uri = $args[2];
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
if ($frag = strstr($uri, '#')) {
|
62 |
+
$uri = substr($uri, 0, -strlen($frag));
|
63 |
+
} else {
|
64 |
+
$frag = '';
|
65 |
+
}
|
66 |
+
|
67 |
+
if (0 === stripos($uri, 'http://')) {
|
68 |
+
$protocol = 'http://';
|
69 |
+
$uri = substr($uri, 7);
|
70 |
+
} elseif (0 === stripos($uri, 'https://')) {
|
71 |
+
$protocol = 'https://';
|
72 |
+
$uri = substr($uri, 8);
|
73 |
+
} else {
|
74 |
+
$protocol = '';
|
75 |
+
}
|
76 |
+
|
77 |
+
if (strpos($uri, '?') !== false) {
|
78 |
+
list($base, $query) = explode('?', $uri, 2);
|
79 |
+
$base .= '?';
|
80 |
+
} elseif ($protocol || strpos($uri, '=') === false) {
|
81 |
+
$base = $uri . '?';
|
82 |
+
$query = '';
|
83 |
+
} else {
|
84 |
+
$base = '';
|
85 |
+
$query = $uri;
|
86 |
+
}
|
87 |
+
|
88 |
+
self::wp_parse_str($query, $qs);
|
89 |
+
$qs = self::urlencode_deep($qs); // this re-URL-encodes things that were already in the query string
|
90 |
+
if (is_array($args[0])) {
|
91 |
+
foreach ($args[0] as $k => $v) {
|
92 |
+
$qs[$k] = $v;
|
93 |
+
}
|
94 |
+
} else {
|
95 |
+
$qs[$args[0]] = $args[1];
|
96 |
+
}
|
97 |
+
|
98 |
+
foreach ($qs as $k => $v) {
|
99 |
+
if ($v === false) {
|
100 |
+
unset($qs[$k]);
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
$ret = self::build_query($qs);
|
105 |
+
$ret = trim($ret, '?');
|
106 |
+
$ret = preg_replace('#=(&|$)#', '$1', $ret);
|
107 |
+
$ret = $protocol . $base . $ret . $frag;
|
108 |
+
$ret = rtrim($ret, '?');
|
109 |
+
|
110 |
+
return $ret;
|
111 |
+
}
|
112 |
+
|
113 |
+
private static function wp_parse_str($string, &$array) {
|
114 |
+
parse_str($string, $array);
|
115 |
+
if (version_compare(PHP_VERSION, '7.4.0', '<')) {
|
116 |
+
if (get_magic_quotes_gpc()) {
|
117 |
+
$array = self::stripslashes_deep($array);
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
+
}
|
122 |
+
|
123 |
+
static function urlencode_deep($value) {
|
124 |
+
return self::map_deep($value, 'urlencode');
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Build URL query based on an associative and, or indexed array.
|
129 |
+
*
|
130 |
+
* This is a convenient function for easily building url queries. It sets the
|
131 |
+
* separator to '&' and uses _http_build_query() function.
|
132 |
+
*
|
133 |
+
* @param array $data URL-encode key/value pairs.
|
134 |
+
*
|
135 |
+
* @return string URL-encoded string.
|
136 |
+
* @link https://secure.php.net/manual/en/function.http-build-query.php for more on what
|
137 |
+
* http_build_query() does.
|
138 |
+
*
|
139 |
+
* @since 2.3.0
|
140 |
+
*
|
141 |
+
* @see _http_build_query() Used to build the query
|
142 |
+
*/
|
143 |
+
private static function build_query($data) {
|
144 |
+
return self::_http_build_query($data, null, '&', '', false);
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* From php.net (modified by Mark Jaquith to behave like the native PHP5 function).
|
149 |
+
*
|
150 |
+
* @param array|object $data An array or object of data. Converted to array.
|
151 |
+
* @param string $prefix Optional. Numeric index. If set, start parameter numbering with it.
|
152 |
+
* Default null.
|
153 |
+
* @param string $sep Optional. Argument separator; defaults to 'arg_separator.output'.
|
154 |
+
* Default null.
|
155 |
+
* @param string $key Optional. Used to prefix key name. Default empty.
|
156 |
+
* @param bool $urlencode Optional. Whether to use urlencode() in the result. Default true.
|
157 |
+
*
|
158 |
+
* @return string The query string.
|
159 |
+
* @since 3.2.0
|
160 |
+
* @access private
|
161 |
+
*
|
162 |
+
* @see https://secure.php.net/manual/en/function.http-build-query.php
|
163 |
+
*
|
164 |
+
*/
|
165 |
+
private static function _http_build_query($data, $prefix = null, $sep = null, $key = '', $urlencode = true) {
|
166 |
+
$ret = array();
|
167 |
+
|
168 |
+
foreach ((array)$data as $k => $v) {
|
169 |
+
if ($urlencode) {
|
170 |
+
$k = urlencode($k);
|
171 |
+
}
|
172 |
+
if (is_int($k) && $prefix != null) {
|
173 |
+
$k = $prefix . $k;
|
174 |
+
}
|
175 |
+
if (!empty($key)) {
|
176 |
+
$k = $key . '%5B' . $k . '%5D';
|
177 |
+
}
|
178 |
+
if ($v === null) {
|
179 |
+
continue;
|
180 |
+
} elseif ($v === false) {
|
181 |
+
$v = '0';
|
182 |
+
}
|
183 |
+
|
184 |
+
if (is_array($v) || is_object($v)) {
|
185 |
+
array_push($ret, self::_http_build_query($v, '', $sep, $k, $urlencode));
|
186 |
+
} elseif ($urlencode) {
|
187 |
+
array_push($ret, $k . '=' . urlencode($v));
|
188 |
+
} else {
|
189 |
+
array_push($ret, $k . '=' . $v);
|
190 |
+
}
|
191 |
+
}
|
192 |
+
|
193 |
+
if (null === $sep) {
|
194 |
+
$sep = ini_get('arg_separator.output');
|
195 |
+
}
|
196 |
+
|
197 |
+
return implode($sep, $ret);
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Parses a string into variables to be stored in an array.
|
202 |
+
*
|
203 |
+
* Uses {@link https://secure.php.net/parse_str parse_str()} and stripslashes if
|
204 |
+
* {@link https://secure.php.net/magic_quotes magic_quotes_gpc} is on.
|
205 |
+
*
|
206 |
+
* @param string $string The string to be parsed.
|
207 |
+
* @param array $array Variables will be stored in this array.
|
208 |
+
*
|
209 |
+
* @since 2.2.1
|
210 |
+
*
|
211 |
+
*/
|
212 |
+
private static function parse_str($string, &$array) {
|
213 |
+
parse_str($string, $array);
|
214 |
+
if (version_compare(PHP_VERSION, '7.4.0', '<')) {
|
215 |
+
if (get_magic_quotes_gpc()) {
|
216 |
+
$array = self::stripslashes_deep($array);
|
217 |
+
}
|
218 |
+
}
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Navigates through an array, object, or scalar, and removes slashes from the values.
|
223 |
+
*
|
224 |
+
* @param mixed $value The value to be stripped.
|
225 |
+
*
|
226 |
+
* @return mixed Stripped value.
|
227 |
+
* @since 2.0.0
|
228 |
+
*
|
229 |
+
*/
|
230 |
+
private static function stripslashes_deep($value) {
|
231 |
+
return self::map_deep($value, array(
|
232 |
+
self::class,
|
233 |
+
'stripslashes_from_strings_only'
|
234 |
+
));
|
235 |
+
}
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Callback function for `stripslashes_deep()` which strips slashes from strings.
|
239 |
+
*
|
240 |
+
* @param mixed $value The array or string to be stripped.
|
241 |
+
*
|
242 |
+
* @return mixed $value The stripped value.
|
243 |
+
* @since 4.4.0
|
244 |
+
*
|
245 |
+
*/
|
246 |
+
public static function stripslashes_from_strings_only($value) {
|
247 |
+
return is_string($value) ? stripslashes($value) : $value;
|
248 |
+
}
|
249 |
+
|
250 |
+
/**
|
251 |
+
* Maps a function to all non-iterable elements of an array or an object.
|
252 |
+
*
|
253 |
+
* This is similar to `array_walk_recursive()` but acts upon objects too.
|
254 |
+
*
|
255 |
+
* @param mixed $value The array, object, or scalar.
|
256 |
+
* @param callable $callback The function to map onto $value.
|
257 |
+
*
|
258 |
+
* @return mixed The value with the callback applied to all non-arrays and non-objects inside it.
|
259 |
+
* @since 4.4.0
|
260 |
+
*
|
261 |
+
*/
|
262 |
+
private static function map_deep($value, $callback) {
|
263 |
+
if (is_array($value)) {
|
264 |
+
foreach ($value as $index => $item) {
|
265 |
+
$value[$index] = self::map_deep($item, $callback);
|
266 |
+
}
|
267 |
+
} elseif (is_object($value)) {
|
268 |
+
$object_vars = get_object_vars($value);
|
269 |
+
foreach ($object_vars as $property_name => $property_value) {
|
270 |
+
$value->$property_name = self::map_deep($property_value, $callback);
|
271 |
+
}
|
272 |
+
} else {
|
273 |
+
$value = call_user_func($callback, $value);
|
274 |
+
}
|
275 |
+
|
276 |
+
return $value;
|
277 |
+
}
|
278 |
+
}
|
Nextend/Framework/Url/WordPress/WordPressUrl.php
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\Url\WordPress;
|
4 |
+
|
5 |
+
use Nextend\Framework\Filesystem\Filesystem;
|
6 |
+
use Nextend\Framework\Url\AbstractPlatformUrl;
|
7 |
+
use function content_url;
|
8 |
+
use function wp_upload_dir;
|
9 |
+
|
10 |
+
class WordPressUrl extends AbstractPlatformUrl {
|
11 |
+
|
12 |
+
function __construct() {
|
13 |
+
|
14 |
+
$this->siteUrl = site_url();
|
15 |
+
|
16 |
+
$this->uris[] = $this->siteUrl;
|
17 |
+
|
18 |
+
$this->_baseuri = content_url();
|
19 |
+
|
20 |
+
if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') {
|
21 |
+
$this->_baseuri = str_replace('http://', 'https://', $this->_baseuri);
|
22 |
+
}
|
23 |
+
|
24 |
+
$this->scheme = parse_url($this->_baseuri, PHP_URL_SCHEME);
|
25 |
+
|
26 |
+
$this->uris[] = $this->_baseuri;
|
27 |
+
|
28 |
+
$this->uris[] = set_url_scheme(plugins_url());
|
29 |
+
|
30 |
+
|
31 |
+
$wp_upload_dir = wp_upload_dir();
|
32 |
+
$uploadUri = rtrim($wp_upload_dir['baseurl'], "/\\");
|
33 |
+
if (strpos($this->_baseuri, $uploadUri) !== 0) {
|
34 |
+
if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') {
|
35 |
+
$uploadUri = str_replace('http://', 'https://', $uploadUri);
|
36 |
+
}
|
37 |
+
$this->uris[] = $uploadUri;
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
public function ajaxUri($query = '') {
|
42 |
+
return site_url('/wp-admin/admin-ajax.php?action=' . $query);
|
43 |
+
}
|
44 |
+
|
45 |
+
public function pathToUri($path, $protocol = true) {
|
46 |
+
$paths = Filesystem::getPaths();
|
47 |
+
|
48 |
+
for ($i = count($paths) - 1; $i >= 0; $i--) {
|
49 |
+
$_path = $paths[$i];
|
50 |
+
if (substr($path, 0, strlen($_path)) == $_path) {
|
51 |
+
|
52 |
+
return $this->getUriByIndex($i, $protocol) . str_replace(array(
|
53 |
+
$_path,
|
54 |
+
DIRECTORY_SEPARATOR
|
55 |
+
), array(
|
56 |
+
'',
|
57 |
+
'/'
|
58 |
+
), str_replace('/', DIRECTORY_SEPARATOR, $path));
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
if (substr($path, 0, 1) == '/') {
|
63 |
+
return $this->getBaseUri() . $path;
|
64 |
+
}
|
65 |
+
|
66 |
+
return $path;
|
67 |
+
}
|
68 |
+
}
|
Nextend/Framework/View/AbstractBlock.php
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\View;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Pattern\GetPathTrait;
|
8 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
9 |
+
|
10 |
+
abstract class AbstractBlock {
|
11 |
+
|
12 |
+
use GetPathTrait;
|
13 |
+
use MVCHelperTrait;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* AbstractBlock constructor.
|
17 |
+
*
|
18 |
+
* @param MVCHelperTrait $MVCHelper
|
19 |
+
*/
|
20 |
+
final public function __construct($MVCHelper) {
|
21 |
+
|
22 |
+
$this->setMVCHelper($MVCHelper);
|
23 |
+
|
24 |
+
$this->init();
|
25 |
+
}
|
26 |
+
|
27 |
+
protected function init() {
|
28 |
+
|
29 |
+
}
|
30 |
+
|
31 |
+
protected function renderTemplatePart($templateName) {
|
32 |
+
|
33 |
+
include self::getPath() . '/' . $templateName . '.phtml';
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Returns the HTML code of the display method
|
38 |
+
*
|
39 |
+
* @return string
|
40 |
+
*/
|
41 |
+
public function toHTML() {
|
42 |
+
|
43 |
+
ob_start();
|
44 |
+
|
45 |
+
$this->display();
|
46 |
+
|
47 |
+
return ob_get_clean();
|
48 |
+
}
|
49 |
+
|
50 |
+
public abstract function display();
|
51 |
+
}
|
Nextend/Framework/View/AbstractLayout.php
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\View;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Pattern\GetPathTrait;
|
8 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
9 |
+
|
10 |
+
abstract class AbstractLayout {
|
11 |
+
|
12 |
+
use GetPathTrait;
|
13 |
+
use MVCHelperTrait;
|
14 |
+
|
15 |
+
/** @var AbstractView */
|
16 |
+
protected $view;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var AbstractBlock[]|string[]|array[]
|
20 |
+
*/
|
21 |
+
protected $contentBlocks = array();
|
22 |
+
|
23 |
+
protected $state = array();
|
24 |
+
|
25 |
+
/**
|
26 |
+
* AbstractLayout constructor.
|
27 |
+
*
|
28 |
+
* @param AbstractView $view
|
29 |
+
*
|
30 |
+
*/
|
31 |
+
public function __construct($view) {
|
32 |
+
$this->view = $view;
|
33 |
+
|
34 |
+
$this->setMVCHelper($view);
|
35 |
+
|
36 |
+
$this->getApplicationType()
|
37 |
+
->setLayout($this);
|
38 |
+
|
39 |
+
$this->enqueueAssets();
|
40 |
+
}
|
41 |
+
|
42 |
+
protected function enqueueAssets() {
|
43 |
+
|
44 |
+
$this->getApplicationType()
|
45 |
+
->enqueueAssets();
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @param string $html
|
50 |
+
*/
|
51 |
+
public function addContent($html) {
|
52 |
+
|
53 |
+
$this->contentBlocks[] = $html;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* @param AbstractBlock $block
|
58 |
+
*/
|
59 |
+
public function addContentBlock($block) {
|
60 |
+
|
61 |
+
$this->contentBlocks[] = $block;
|
62 |
+
}
|
63 |
+
|
64 |
+
public function displayContent() {
|
65 |
+
foreach ($this->contentBlocks AS $content) {
|
66 |
+
if (is_string($content)) {
|
67 |
+
echo $content;
|
68 |
+
} else if (is_array($content)) {
|
69 |
+
echo call_user_func_array($content[0], $content[1]);
|
70 |
+
} else {
|
71 |
+
$content->display();
|
72 |
+
}
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
public function setState($name, $value) {
|
77 |
+
$this->state[$name] = $value;
|
78 |
+
}
|
79 |
+
|
80 |
+
public abstract function render();
|
81 |
+
}
|
Nextend/Framework/View/AbstractView.php
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\View;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Controller\AbstractController;
|
8 |
+
use Nextend\Framework\Pattern\GetPathTrait;
|
9 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
10 |
+
|
11 |
+
abstract class AbstractView {
|
12 |
+
|
13 |
+
use GetPathTrait;
|
14 |
+
use MVCHelperTrait;
|
15 |
+
|
16 |
+
/** @var AbstractController */
|
17 |
+
protected $controller;
|
18 |
+
|
19 |
+
/** @var AbstractLayout */
|
20 |
+
protected $layout;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* AbstractView constructor.
|
24 |
+
*
|
25 |
+
* @param AbstractController $controller
|
26 |
+
*
|
27 |
+
*/
|
28 |
+
public function __construct($controller) {
|
29 |
+
$this->controller = $controller;
|
30 |
+
|
31 |
+
$this->setMVCHelper($controller);
|
32 |
+
}
|
33 |
+
|
34 |
+
protected function render($templateName) {
|
35 |
+
ob_start();
|
36 |
+
include self::getPath() . '/Template/' . $templateName . '.phtml';
|
37 |
+
|
38 |
+
return ob_get_clean();
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @return AbstractController
|
43 |
+
*/
|
44 |
+
public function getController() {
|
45 |
+
return $this->controller;
|
46 |
+
}
|
47 |
+
|
48 |
+
public abstract function display();
|
49 |
+
}
|
Nextend/Framework/View/AbstractViewAjax.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\View;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Controller\AbstractController;
|
8 |
+
use Nextend\Framework\Pattern\GetPathTrait;
|
9 |
+
use Nextend\Framework\Pattern\MVCHelperTrait;
|
10 |
+
|
11 |
+
abstract class AbstractViewAjax {
|
12 |
+
|
13 |
+
use GetPathTrait;
|
14 |
+
use MVCHelperTrait;
|
15 |
+
|
16 |
+
/** @var AbstractController */
|
17 |
+
protected $controller;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* AbstractViewAjax constructor.
|
21 |
+
*
|
22 |
+
* @param AbstractController $controller
|
23 |
+
*
|
24 |
+
*/
|
25 |
+
public function __construct($controller) {
|
26 |
+
$this->controller = $controller;
|
27 |
+
|
28 |
+
$this->setMVCHelper($controller);
|
29 |
+
}
|
30 |
+
|
31 |
+
protected function render($templateName) {
|
32 |
+
ob_start();
|
33 |
+
include self::getPath() . '/Template/' . $templateName . '.phtml';
|
34 |
+
|
35 |
+
return ob_get_clean();
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @return string
|
40 |
+
*/
|
41 |
+
public abstract function display();
|
42 |
+
}
|
Nextend/Framework/View/Html.php
ADDED
@@ -0,0 +1,319 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Nextend\Framework\View;
|
4 |
+
|
5 |
+
use Nextend\Framework\Settings;
|
6 |
+
|
7 |
+
class Html {
|
8 |
+
|
9 |
+
private static $closeSingleTags = true;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var boolean whether to render special attributes value. Defaults to true. Can be set to false for HTML5.
|
13 |
+
* @since 1.1.13
|
14 |
+
*/
|
15 |
+
private static $renderSpecialAttributesValue = true;
|
16 |
+
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Decodes special HTML entities back to the corresponding characters.
|
20 |
+
* This is the opposite of {@link encode()}.
|
21 |
+
*
|
22 |
+
* @param string $text data to be decoded
|
23 |
+
*
|
24 |
+
* @return string the decoded data
|
25 |
+
* @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php
|
26 |
+
* @since 1.1.8
|
27 |
+
*/
|
28 |
+
public static function decode($text) {
|
29 |
+
return htmlspecialchars_decode($text, ENT_QUOTES);
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Generates an HTML element.
|
34 |
+
*
|
35 |
+
* @param string $tag the tag name
|
36 |
+
* @param array $htmlOptions the element attributes. The values will be HTML-encoded using {@link encode()}.
|
37 |
+
* If an 'encode' attribute is given and its value is false,
|
38 |
+
* the rest of the attribute values will NOT be HTML-encoded.
|
39 |
+
* Since version 1.1.5, attributes whose value is null will not be rendered.
|
40 |
+
* @param mixed $content the content to be enclosed between open and close element tags. It will not be
|
41 |
+
* HTML-encoded. If false, it means there is no body content.
|
42 |
+
* @param boolean $closeTag whether to generate the close tag.
|
43 |
+
*
|
44 |
+
* @return string the generated HTML element tag
|
45 |
+
*/
|
46 |
+
public static function tag($tag, $htmlOptions = array(), $content = "", $closeTag = true) {
|
47 |
+
$html = '<' . $tag . self::renderAttributes($htmlOptions);
|
48 |
+
if ($content === false) return $closeTag && self::$closeSingleTags ? $html . ' />' : $html . '>'; else
|
49 |
+
return $closeTag ? $html . '>' . $content . '</' . $tag . '>' : $html . '>' . $content;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Generates an open HTML element.
|
54 |
+
*
|
55 |
+
* @param string $tag the tag name
|
56 |
+
* @param array $htmlOptions the element attributes. The values will be HTML-encoded using {@link encode()}.
|
57 |
+
* If an 'encode' attribute is given and its value is false,
|
58 |
+
* the rest of the attribute values will NOT be HTML-encoded.
|
59 |
+
* Since version 1.1.5, attributes whose value is null will not be rendered.
|
60 |
+
*
|
61 |
+
* @return string the generated HTML element tag
|
62 |
+
*/
|
63 |
+
public static function openTag($tag, $htmlOptions = array()) {
|
64 |
+
return '<' . $tag . self::renderAttributes($htmlOptions) . '>';
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Generates a close HTML element.
|
69 |
+
*
|
70 |
+
* @param string $tag the tag name
|
71 |
+
*
|
72 |
+
* @return string the generated HTML element tag
|
73 |
+
*/
|
74 |
+
public static function closeTag($tag) {
|
75 |
+
return '</' . $tag . '>';
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Generates an image tag.
|
80 |
+
*
|
81 |
+
* @param string $src the image URL
|
82 |
+
* @param string $alt the alternative text display
|
83 |
+
* @param array $htmlOptions additional HTML attributes (see {@link tag}).
|
84 |
+
*
|
85 |
+
* @return string the generated image tag
|
86 |
+
*/
|
87 |
+
public static function image($src, $alt = '', $htmlOptions = array()) {
|
88 |
+
$htmlOptions['src'] = $src;
|
89 |
+
$htmlOptions['alt'] = $alt;
|
90 |
+
|
91 |
+
return self::tag('img', $htmlOptions, false);
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Renders the HTML tag attributes.
|
96 |
+
* Since version 1.1.5, attributes whose value is null will not be rendered.
|
97 |
+
* Special attributes, such as 'checked', 'disabled', 'readonly', will be rendered
|
98 |
+
* properly based on their corresponding boolean value.
|
99 |
+
*
|
100 |
+
* @param array $htmlOptions attributes to be rendered
|
101 |
+
*
|
102 |
+
* @return string the rendering result
|
103 |
+
*/
|
104 |
+
public static function renderAttributes($htmlOptions = array()) {
|
105 |
+
static $specialAttributes = array(
|
106 |
+
'autofocus' => 1,
|
107 |
+
'autoplay' => 1,
|
108 |
+
'controls' => 1,
|
109 |
+
'declare' => 1,
|
110 |
+
'default' => 1,
|
111 |
+
'disabled' => 1,
|
112 |
+
'ismap' => 1,
|
113 |
+
'loop' => 1,
|
114 |
+
'muted' => 1,
|
115 |
+
'playsinline' => 1,
|
116 |
+
'webkit-playsinline' => 1,
|
117 |
+
'nohref' => 1,
|
118 |
+
'noresize' => 1,
|
119 |
+
'novalidate' => 1,
|
120 |
+
'open' => 1,
|
121 |
+
'reversed' => 1,
|
122 |
+
'scoped' => 1,
|
123 |
+
'seamless' => 1,
|
124 |
+
'selected' => 1,
|
125 |
+
'typemustmatch' => 1,
|
126 |
+
'lazyload' => 1,
|
127 |
+
), $specialAttributesNoValue = array(
|
128 |
+
'defer' => 1,
|
129 |
+
'async' => 1
|
130 |
+
);
|
131 |
+
|
132 |
+
if ($htmlOptions === array()) return '';
|
133 |
+
|
134 |
+
$html = '';
|
135 |
+
if (isset($htmlOptions['encode'])) {
|
136 |
+
$raw = !$htmlOptions['encode'];
|
137 |
+
unset($htmlOptions['encode']);
|
138 |
+
} else
|
139 |
+
$raw = false;
|
140 |
+
|
141 |
+
foreach ($htmlOptions as $name => $value) {
|
142 |
+
if (isset($specialAttributes[$name])) {
|
143 |
+
if ($value) {
|
144 |
+
$html .= ' ' . $name;
|
145 |
+
if (self::$renderSpecialAttributesValue) $html .= '="' . $name . '"';
|
146 |
+
}
|
147 |
+
} else if (isset($specialAttributesNoValue[$name])) {
|
148 |
+
$html .= ' ' . $name;
|
149 |
+
} else if ($value !== null) $html .= ' ' . $name . '="' . ($raw ? $value : self::encode($value)) . '"';
|
150 |
+
}
|
151 |
+
|
152 |
+
return $html;
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* @param $text
|
157 |
+
*
|
158 |
+
* @return string
|
159 |
+
*/
|
160 |
+
public static function encode($text) {
|
161 |
+
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
|
162 |
+
}
|
163 |
+
|
164 |
+
public static function link($name, $url = '#', $htmlOptions = array()) {
|
165 |
+
$htmlOptions["href"] = $url;
|
166 |
+
//$htmlOptions["encode"] = false;
|
167 |
+
|
168 |
+
$url = self::openTag("a", $htmlOptions);
|
169 |
+
if (isset($htmlOptions["encode"]) && $htmlOptions["encode"]) {
|
170 |
+
$url .= self::encode($name);
|
171 |
+
} else {
|
172 |
+
$url .= $name;
|
173 |
+
}
|
174 |
+
|
175 |
+
$url .= self::closeTag("a");
|
176 |
+
|
177 |
+
return $url;
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Insert stylesheet
|
182 |
+
*
|
183 |
+
* @param string $script
|
184 |
+
* @param bool $file
|
185 |
+
* @param array $scriptOptions
|
186 |
+
*
|
187 |
+
* @return string
|
188 |
+
*/
|
189 |
+
public static function style($script, $file = false, $scriptOptions = array()) {
|
190 |
+
if ($file) {
|
191 |
+
$options = array(
|
192 |
+
"rel" => "stylesheet",
|
193 |
+
"type" => "text/css",
|
194 |
+
"href" => $script
|
195 |
+
);
|
196 |
+
$options = array_merge($options, $scriptOptions);
|
197 |
+
|
198 |
+
return self::tag('link', $options, false);
|
199 |
+
}
|
200 |
+
|
201 |
+
return self::tag("style", $scriptOptions + array(
|
202 |
+
"type" => "text/css"
|
203 |
+
), $script);
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Insert script
|
208 |
+
*
|
209 |
+
* @param string $script
|
210 |
+
* @param bool $file
|
211 |
+
*
|
212 |
+
* @return string
|
213 |
+
*/
|
214 |
+
public static function script($script, $file = false) {
|
215 |
+
if ($file) {
|
216 |
+
return self::tag('script', array(
|
217 |
+
'type' => 'text/javascript',
|
218 |
+
'src' => $script
|
219 |
+
) + self::getScriptAttributes(), '');
|
220 |
+
}
|
221 |
+
|
222 |
+
return self::tag('script', array(
|
223 |
+
'type' => 'text/javascript',
|
224 |
+
'encode' => false
|
225 |
+
), $script);
|
226 |
+
}
|
227 |
+
|
228 |
+
public static function scriptFile($script, $attributes = array()) {
|
229 |
+
return self::tag('script', array(
|
230 |
+
'type' => 'text/javascript',
|
231 |
+
'src' => $script
|
232 |
+
) + self::getScriptAttributes() + $attributes, '');
|
233 |
+
}
|
234 |
+
|
235 |
+
private static function getScriptAttributes() {
|
236 |
+
static $attributes = null;
|
237 |
+
if ($attributes === null) {
|
238 |
+
if (class_exists('\\Nextend\\Framework\\Settings', false)) {
|
239 |
+
$value = trim(html_entity_decode(strip_tags(Settings::get('scriptattributes', ''))));
|
240 |
+
$_attributes = explode(' ', str_replace('\'', "", str_replace("\"", "", $value)));
|
241 |
+
if (!empty($value) && !empty($_attributes)) {
|
242 |
+
foreach ($_attributes AS $attr) {
|
243 |
+
if (strpos($attr, '=') !== false) {
|
244 |
+
$atts = explode("=", $attr);
|
245 |
+
if (count($atts) <= 2) {
|
246 |
+
$attributes[$atts[0]] = $atts[1];
|
247 |
+
} else {
|
248 |
+
$attributes[$attr] = $attr;
|
249 |
+
}
|
250 |
+
} else {
|
251 |
+
$attributes[$attr] = $attr;
|
252 |
+
}
|
253 |
+
}
|
254 |
+
} else {
|
255 |
+
$attributes = array();
|
256 |
+
}
|
257 |
+
} else {
|
258 |
+
return array();
|
259 |
+
}
|
260 |
+
}
|
261 |
+
|
262 |
+
return $attributes;
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* @param array $array1
|
267 |
+
* @param array $array2 [optional]
|
268 |
+
* @param array $_ [optional]
|
269 |
+
*
|
270 |
+
* @return array the resulting array.
|
271 |
+
* @since 4.0
|
272 |
+
* @since 5.0
|
273 |
+
*/
|
274 |
+
public static function mergeAttributes($array1, $array2 = null, $_ = null) {
|
275 |
+
$arguments = func_get_args();
|
276 |
+
$target = array_shift($arguments);
|
277 |
+
foreach ($arguments AS $array) {
|
278 |
+
if (isset($array['style'])) {
|
279 |
+
if (!isset($target['style'])) $target['style'] = '';
|
280 |
+
$target['style'] .= $array['style'];
|
281 |
+
unset($array['style']);
|
282 |
+
}
|
283 |
+
if (isset($array['class'])) {
|
284 |
+
if (!isset($target['class'])) $target['class'] = '';
|
285 |
+
$target['class'] .= ' ' . $array['class'];
|
286 |
+
unset($array['class']);
|
287 |
+
}
|
288 |
+
|
289 |
+
$target = array_merge($target, $array);
|
290 |
+
}
|
291 |
+
|
292 |
+
return $target;
|
293 |
+
}
|
294 |
+
|
295 |
+
public static function addExcludeLazyLoadAttributes($target) {
|
296 |
+
|
297 |
+
return self::mergeAttributes($target, self::getExcludeLazyLoadAttributes());
|
298 |
+
}
|
299 |
+
|
300 |
+
public static function getExcludeLazyLoadAttributes() {
|
301 |
+
static $attrs;
|
302 |
+
if ($attrs === null) {
|
303 |
+
$attrs = array(
|
304 |
+
'data-no-lazy' => 1,
|
305 |
+
'data-hack' => 'data-lazy-src'
|
306 |
+
);
|
307 |
+
|
308 |
+
if (class_exists('\FlorianBrinkmann\LazyLoadResponsiveImages\Plugin', false)) {
|
309 |
+
$attrs['data-no-lazyload'] = 1;
|
310 |
+
}
|
311 |
+
|
312 |
+
if (function_exists('thb_lazy_images_filter') || defined('WP_SMUSH_VERSION')) {
|
313 |
+
$attrs['class'] = 'no-lazyload';
|
314 |
+
}
|
315 |
+
}
|
316 |
+
|
317 |
+
return $attrs;
|
318 |
+
}
|
319 |
+
}
|
Nextend/Framework/Visual/AbstractBlockVisual.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Visual;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Localization\Localization;
|
8 |
+
use Nextend\Framework\View\AbstractBlock;
|
9 |
+
|
10 |
+
abstract class AbstractBlockVisual extends AbstractBlock {
|
11 |
+
|
12 |
+
}
|
Nextend/Framework/Visual/ModelVisual.php
ADDED
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\Visual;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Model\AbstractModel;
|
8 |
+
use Nextend\Framework\Model\ApplicationSection;
|
9 |
+
use Nextend\Framework\Model\StorageSectionManager;
|
10 |
+
|
11 |
+
class ModelVisual extends AbstractModel {
|
12 |
+
|
13 |
+
protected $type = '';
|
14 |
+
|
15 |
+
/** @var ApplicationSection */
|
16 |
+
protected $storage;
|
17 |
+
|
18 |
+
protected function init() {
|
19 |
+
|
20 |
+
$this->storage = StorageSectionManager::getStorage('system');
|
21 |
+
}
|
22 |
+
|
23 |
+
public function getType() {
|
24 |
+
return $this->type;
|
25 |
+
}
|
26 |
+
|
27 |
+
public function renderSetsForm() {
|
28 |
+
|
29 |
+
}
|
30 |
+
|
31 |
+
public function getSets() {
|
32 |
+
return $this->storage->getAll($this->type . 'set');
|
33 |
+
}
|
34 |
+
|
35 |
+
public function getSetByVisualId($visualId) {
|
36 |
+
$visual = $this->storage->getById($visualId, $this->type);
|
37 |
+
if (!empty($visual)) {
|
38 |
+
return array(
|
39 |
+
'setId' => $visual['referencekey'],
|
40 |
+
'visuals' => $this->getVisuals($visual['referencekey'])
|
41 |
+
);
|
42 |
+
}
|
43 |
+
|
44 |
+
return false;
|
45 |
+
}
|
46 |
+
|
47 |
+
public function createSet($name) {
|
48 |
+
|
49 |
+
$setId = $this->storage->add($this->type . 'set', '', $name);
|
50 |
+
|
51 |
+
$set = $this->storage->getById($setId, $this->type . 'set');
|
52 |
+
if (!empty($set) && $set['section'] == $this->type . 'set') {
|
53 |
+
return $set;
|
54 |
+
}
|
55 |
+
|
56 |
+
return false;
|
57 |
+
}
|
58 |
+
|
59 |
+
public function renameSet($setId, $name) {
|
60 |
+
$set = $this->storage->getById($setId, $this->type . 'set');
|
61 |
+
if (!empty($set) && $set['section'] == $this->type . 'set' && $set['editable']) {
|
62 |
+
if ($this->storage->setById($setId, $name)) {
|
63 |
+
$set['value'] = $name;
|
64 |
+
|
65 |
+
return $set;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
|
69 |
+
return false;
|
70 |
+
}
|
71 |
+
|
72 |
+
public function deleteSet($setId) {
|
73 |
+
$set = $this->storage->getById($setId, $this->type . 'set');
|
74 |
+
if (!empty($set) && $set['section'] == $this->type . 'set' && $set['editable'] && $set['system'] == 0) {
|
75 |
+
if ($this->storage->deleteById($setId)) {
|
76 |
+
return $set;
|
77 |
+
}
|
78 |
+
}
|
79 |
+
|
80 |
+
return false;
|
81 |
+
}
|
82 |
+
|
83 |
+
public function addVisual($setId, $visual) {
|
84 |
+
|
85 |
+
$visualId = $this->storage->add($this->type, $setId, $visual);
|
86 |
+
|
87 |
+
$visual = $this->storage->getById($visualId, $this->type);
|
88 |
+
if (!empty($visual) && $visual['section'] == $this->type) {
|
89 |
+
return $visual;
|
90 |
+
}
|
91 |
+
|
92 |
+
return false;
|
93 |
+
}
|
94 |
+
|
95 |
+
public function deleteVisual($id) {
|
96 |
+
$visual = $this->storage->getById($id, $this->type);
|
97 |
+
if (!empty($visual) && $visual['section'] == $this->type) {
|
98 |
+
$this->storage->deleteById($id);
|
99 |
+
|
100 |
+
return $visual;
|
101 |
+
}
|
102 |
+
|
103 |
+
return false;
|
104 |
+
}
|
105 |
+
|
106 |
+
public function changeVisual($id, $value) {
|
107 |
+
if ($this->storage->setById($id, $value)) {
|
108 |
+
return $this->storage->getById($id, $this->type);
|
109 |
+
}
|
110 |
+
|
111 |
+
return false;
|
112 |
+
}
|
113 |
+
|
114 |
+
public function getVisuals($setId) {
|
115 |
+
return $this->storage->getAll($this->type, $setId);
|
116 |
+
}
|
117 |
+
}
|
Nextend/Framework/WordPress/AssetInjector.php
ADDED
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace Nextend\Framework\WordPress;
|
5 |
+
|
6 |
+
|
7 |
+
use Nextend\Framework\Asset\AssetManager;
|
8 |
+
use Nextend\Framework\Pattern\SingletonTrait;
|
9 |
+
use Nextend\WordPress\OutputBuffer;
|
10 |
+
|
11 |
+
class AssetInjector {
|
12 |
+
|
13 |
+
use SingletonTrait;
|
14 |
+
|
15 |
+
protected $js = '';
|
16 |
+
protected $css = '';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var OutputBuffer
|
20 |
+
*/
|
21 |
+
protected $outputBuffer;
|
22 |
+
|
23 |
+
private $htmlCommentTokens = array();
|
24 |
+
|
25 |
+
protected function init() {
|
26 |
+
|
27 |
+
$this->outputBuffer = OutputBuffer::getInstance();
|
28 |
+
if (defined('SMART_SLIDER_OB_START') && SMART_SLIDER_OB_START >= 0) {
|
29 |
+
$this->outputBuffer->setExtraObStart(SMART_SLIDER_OB_START);
|
30 |
+
}
|
31 |
+
|
32 |
+
$this->addInjectCSSComment();
|
33 |
+
|
34 |
+
add_filter('wordpress_prepare_output', array(
|
35 |
+
$this,
|
36 |
+
'prepareOutput'
|
37 |
+
));
|
38 |
+
}
|
39 |
+
|
40 |
+
public function prepareOutput($buffer) {
|
41 |
+
static $once = false;
|
42 |
+
if (!$once) {
|
43 |
+
$once = true;
|
44 |
+
$this->finalizeCssJs();
|
45 |
+
|
46 |
+
if (!empty($this->css)) {
|
47 |
+
if (strpos($buffer, '<!--n2css-->') !== false) {
|
48 |
+
$buffer = str_replace('<!--n2css-->', $this->css, $buffer);
|
49 |
+
|
50 |
+
$this->css = '';
|
51 |
+
} else {
|
52 |
+
$parts = preg_split('/<\/head[\s]*>/i', $buffer, 2);
|
53 |
+
// There might be no head and it would result a notice.
|
54 |
+
if (count($parts) == 2) {
|
55 |
+
list($head, $body) = $parts;
|
56 |
+
/**
|
57 |
+
* We must tokenize the HTML comments in the head to prepare for condition CSS/scripts
|
58 |
+
* Eg.: <!--[if lt IE 9]><link rel='stylesheet' href='ie8.css?ver=1.0' type='text/css' media='all' /> <![endif]-->
|
59 |
+
*/
|
60 |
+
$head = preg_replace_callback('/<!--.*?-->/s', array(
|
61 |
+
$this,
|
62 |
+
'tokenizeHtmlComments'
|
63 |
+
), $head);
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Find the first <script> tag with src attribute
|
67 |
+
*/
|
68 |
+
$pattern = '/<script[^>]+src=[\'"][^>"\']*[\'"]/si';
|
69 |
+
if (preg_match($pattern, $head, $matches)) {
|
70 |
+
|
71 |
+
$splitBy = $matches[0];
|
72 |
+
|
73 |
+
$headParts = preg_split($pattern, $head, 2);
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Find the last stylesheet before the first script
|
77 |
+
*/
|
78 |
+
if (preg_match_all('/<link[^>]*rel=[\'"]stylesheet[\'"][^>]*>/si', $headParts[0], $matches, PREG_SET_ORDER)) {
|
79 |
+
/**
|
80 |
+
* If there is a match we insert our stylesheet after that.
|
81 |
+
*/
|
82 |
+
$match = array_pop($matches);
|
83 |
+
$lastStylesheet = $match[0];
|
84 |
+
|
85 |
+
$headParts[0] = str_replace($lastStylesheet, $lastStylesheet . $this->css, $headParts[0]);
|
86 |
+
|
87 |
+
$this->css = '';
|
88 |
+
} else {
|
89 |
+
/**
|
90 |
+
* No stylesheet found, so we insert our stylesheet before the first <script>.
|
91 |
+
*/
|
92 |
+
$headParts[0] .= $this->css;
|
93 |
+
|
94 |
+
$this->css = '';
|
95 |
+
}
|
96 |
+
|
97 |
+
$head = implode($splitBy, $headParts);
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Restore HTML comments
|
101 |
+
*/
|
102 |
+
$head = preg_replace_callback('/<!--TOKEN([0-9]+)-->/', array(
|
103 |
+
$this,
|
104 |
+
'restoreHtmlComments'
|
105 |
+
), $head);
|
106 |
+
|
107 |
+
$buffer = $head . '</head>' . $body;
|
108 |
+
}
|
109 |
+
}
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
if ($this->css != '' || $this->js != '') {
|
114 |
+
$parts = preg_split('/<\/head[\s]*>/', $buffer, 2);
|
115 |
+
|
116 |
+
return implode($this->css . $this->js . '</head>', $parts);
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
return $buffer;
|
121 |
+
}
|
122 |
+
|
123 |
+
public function tokenizeHtmlComments($matches) {
|
124 |
+
|
125 |
+
$index = count($this->htmlCommentTokens);
|
126 |
+
|
127 |
+
$this->htmlCommentTokens[$index] = $matches[0];
|
128 |
+
|
129 |
+
return '<!--TOKEN' . $index . '-->';
|
130 |
+
}
|
131 |
+
|
132 |
+
public function restoreHtmlComments($matches) {
|
133 |
+
|
134 |
+
return $this->htmlCommentTokens[$matches[1]];
|
135 |
+
}
|
136 |
+
|
137 |
+
private function finalizeCssJs() {
|
138 |
+
static $finalized = false;
|
139 |
+
if (!$finalized) {
|
140 |
+
$finalized = true;
|
141 |
+
|
142 |
+
if (class_exists('\\Nextend\\Framework\\Asset\\AssetManager', false)) {
|
143 |
+
$this->css = AssetManager::getCSS();
|
144 |
+
$this->js = AssetManager::getJs();
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
return true;
|
149 |
+
}
|
150 |
+
|
151 |
+
public function addInjectCSSComment() {
|
152 |
+
|
153 |
+
remove_action('wp_print_scripts', array(
|
154 |
+
$this,
|
155 |
+
'injectCSSComment'
|
156 |
+
));
|
157 |
+
}
|
158 |
+
|
159 |
+
public function removeInjectCSSComment() {
|
160 |
+
|
161 |
+
add_action('wp_print_scripts', array(
|
162 |
+
$this,
|
163 |
+
'injectCSSComment'
|
164 |
+
));
|
165 |
+
}
|
166 |
+
|
167 |
+
public function injectCSSComment() {
|
168 |
+
static $once;
|
169 |
+
if (!$once) {
|
170 |
+
echo "<!--n2css-->";
|
171 |
+
$once = true;
|
172 |
+
}
|
173 |
+
}
|
174 |
+
}
|
Nextend/Languages/de_DE.mo
ADDED
Binary file
|
Nextend/Languages/de_DE.po
ADDED
@@ -0,0 +1,11206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
msgid ""
|
2 |
+
msgstr ""
|
3 |
+
"Project-Id-Version: Smart Slider 3 translation\n"
|
4 |
+
"POT-Creation-Date: 2020-05-13 11:01+0200\n"
|
5 |
+
"PO-Revision-Date: 2020-05-13 11:01+0200\n"
|
6 |
+
"Last-Translator: \n"
|
7 |
+
"Language-Team: \n"
|
8 |
+
"Language: de\n"
|
9 |
+
"MIME-Version: 1.0\n"
|
10 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
11 |
+
"Content-Transfer-Encoding: 8bit\n"
|
12 |
+
"X-Generator: Poedit 2.3.1\n"
|
13 |
+
"X-Poedit-Basepath: ..\n"
|
14 |
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
15 |
+
"X-Poedit-SourceCharset: UTF-8\n"
|
16 |
+
"X-Poedit-KeywordsList: n2_;n2_e;n2_n:1,2;n2_en:1,2;n2_x:1,2c;n2_ex:1,2c\n"
|
17 |
+
"X-Poedit-SearchPath-0: .\n"
|
18 |
+
"X-Poedit-SearchPathExcluded-0: Framework/Asset/Builder/cache\n"
|
19 |
+
|
20 |
+
#: Framework/Api.php:117 Framework/Misc/HttpClient.php:81
|
21 |
+
msgid "Debug error"
|
22 |
+
msgstr ""
|
23 |
+
|
24 |
+
#: Framework/Api.php:136 Framework/Misc/HttpClient.php:106
|
25 |
+
msgid "CURL disabled in your php.ini configuration. Please enable it!"
|
26 |
+
msgstr ""
|
27 |
+
|
28 |
+
#: Framework/Api.php:144 Framework/Misc/HttpClient.php:112
|
29 |
+
msgid "Unable to contact with the licensing server, please try again later!"
|
30 |
+
msgstr ""
|
31 |
+
|
32 |
+
#: Framework/Asset/Js/Js.php:70
|
33 |
+
msgid "jquery.framework"
|
34 |
+
msgstr ""
|
35 |
+
|
36 |
+
#: Framework/Asset/Predefined.php:28
|
37 |
+
msgctxt "Default Google font family for admin"
|
38 |
+
msgid "Montserrat"
|
39 |
+
msgstr ""
|
40 |
+
|
41 |
+
#: Framework/Asset/Predefined.php:29
|
42 |
+
msgctxt "Default Google font charset for admin"
|
43 |
+
msgid "latin"
|
44 |
+
msgstr ""
|
45 |
+
|
46 |
+
#: Framework/Browse/ControllerAjaxBrowse.php:84
|
47 |
+
msgid "You are not allowed to upload!"
|
48 |
+
msgstr ""
|
49 |
+
|
50 |
+
#: Framework/Browse/ControllerAjaxBrowse.php:97
|
51 |
+
msgid "Folder is missing!"
|
52 |
+
msgstr ""
|
53 |
+
|
54 |
+
#: Framework/Content/Joomla/JoomlaContent.php:131
|
55 |
+
msgid "Menu item"
|
56 |
+
msgstr ""
|
57 |
+
|
58 |
+
#: Framework/Controller/AbstractController.php:146
|
59 |
+
#: Framework/Controller/AjaxController.php:41
|
60 |
+
msgid "You are not authorised to view this resource."
|
61 |
+
msgstr ""
|
62 |
+
|
63 |
+
#: Framework/Controller/AbstractController.php:161
|
64 |
+
#: Framework/Controller/AjaxController.php:50
|
65 |
+
#, php-format
|
66 |
+
msgid "Missing parameter: %s"
|
67 |
+
msgstr ""
|
68 |
+
|
69 |
+
#: Framework/Controller/AbstractController.php:176
|
70 |
+
#: Framework/Controller/AjaxController.php:57
|
71 |
+
msgid "Database error"
|
72 |
+
msgstr ""
|
73 |
+
|
74 |
+
#: Framework/Controller/AbstractController.php:191
|
75 |
+
msgid "Security token mismatch"
|
76 |
+
msgstr ""
|
77 |
+
|
78 |
+
#: Framework/Controller/Admin/AdminVisualManagerAjaxController.php:34
|
79 |
+
#: Framework/Controller/Admin/AdminVisualManagerAjaxController.php:96
|
80 |
+
#: Framework/Controller/Admin/AdminVisualManagerAjaxController.php:176
|
81 |
+
#: Framework/Image/ControllerAjaxImage.php:34
|
82 |
+
#: Framework/Image/ControllerAjaxImage.php:73
|
83 |
+
#: Framework/Image/ControllerAjaxImage.php:109
|
84 |
+
#: SmartSlider3/Application/Admin/Visuals/ControllerAjaxCss.php:33
|
85 |
+
#: SmartSlider3/Application/Admin/Visuals/ControllerAjaxCss.php:99
|
86 |
+
msgid "Unexpected error"
|
87 |
+
msgstr ""
|
88 |
+
|
89 |
+
#: Framework/Controller/Admin/AdminVisualManagerAjaxController.php:57
|
90 |
+
#: Framework/Controller/Admin/AdminVisualManagerAjaxController.php:77
|
91 |
+
msgid "Set is not editable"
|
92 |
+
msgstr ""
|
93 |
+
|
94 |
+
#: Framework/Controller/Admin/AdminVisualManagerAjaxController.php:116
|
95 |
+
msgid "Visual do not exists"
|
96 |
+
msgstr ""
|
97 |
+
|
98 |
+
#: Framework/Controller/Admin/AdminVisualManagerAjaxController.php:136
|
99 |
+
#: Framework/Controller/Admin/AdminVisualManagerAjaxController.php:156
|
100 |
+
#: Framework/Image/ControllerAjaxImage.php:91
|
101 |
+
#: SmartSlider3/Application/Admin/Visuals/ControllerAjaxCss.php:53
|
102 |
+
#: SmartSlider3/Application/Admin/Visuals/ControllerAjaxCss.php:76
|
103 |
+
msgid "Not editable"
|
104 |
+
msgstr ""
|
105 |
+
|
106 |
+
#: Framework/Controller/AjaxController.php:32
|
107 |
+
msgid "Security token mismatch. Please refresh the page!"
|
108 |
+
msgstr ""
|
109 |
+
|
110 |
+
#: Framework/Database/WordPress/WordPressConnector.php:105
|
111 |
+
msgid "Unexpected database error."
|
112 |
+
msgstr ""
|
113 |
+
|
114 |
+
#: Framework/Database/WordPress/WordPressConnector.php:107
|
115 |
+
msgid "Try to repair database"
|
116 |
+
msgstr ""
|
117 |
+
|
118 |
+
#: Framework/Database/WordPress/WordPressConnector.php:109
|
119 |
+
#, php-format
|
120 |
+
msgid ""
|
121 |
+
"If you see this message after the repair database process, please "
|
122 |
+
"%1$scontact us%2$s with the log:"
|
123 |
+
msgstr ""
|
124 |
+
|
125 |
+
#: Framework/Font/FontRenderer.php:103 Framework/Font/FontRenderer.php:105
|
126 |
+
#: Framework/Font/FontRenderer.php:117 Framework/Font/FontRenderer.php:119
|
127 |
+
#: Framework/Font/FontRenderer.php:133 Framework/Font/FontRenderer.php:152
|
128 |
+
#: Framework/Font/FontRenderer.php:187 Framework/Font/FontRenderer.php:205
|
129 |
+
#: Framework/Font/FontRenderer.php:221 Framework/Font/FontRenderer.php:237
|
130 |
+
#: Framework/Font/FontRenderer.php:255 Framework/Style/StyleRenderer.php:80
|
131 |
+
#: SmartSlider3/Renderable/Item/Heading/ItemHeading.php:148
|
132 |
+
#: SmartSlider3/Renderable/Item/Text/Assets/text.js:20
|
133 |
+
#: SmartSlider3/Renderable/Item/Text/ItemText.php:53
|
134 |
+
#: SmartSlider3/Renderable/Item/Text/ItemText.php:134
|
135 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:244
|
136 |
+
#: SmartSlider3Pro/Renderable/Item/Input/ItemInput.php:149
|
137 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:142
|
138 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowGrow/ArrowGrow.php:64
|
139 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowText/ArrowText.php:51
|
140 |
+
#: SmartSlider3Pro/Widget/Bullet/BulletNumbers/BulletNumbers.php:58
|
141 |
+
#: SmartSlider3Pro/Widget/Bullet/BulletText/BulletText.php:58
|
142 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/AddLayer/AddLayer.phtml:28
|
143 |
+
msgid "Text"
|
144 |
+
msgstr "Text"
|
145 |
+
|
146 |
+
#: Framework/Font/FontRenderer.php:131 Framework/Font/FontRenderer.php:134
|
147 |
+
#: Framework/Font/FontRenderer.php:153 Framework/Font/FontRenderer.php:189
|
148 |
+
#: Framework/Font/FontRenderer.php:206 Framework/Font/FontRenderer.php:239
|
149 |
+
#: Framework/Font/FontRenderer.php:257 Framework/Style/StyleRenderer.php:109
|
150 |
+
#: Framework/Style/StyleRenderer.php:125 Framework/Style/StyleRenderer.php:144
|
151 |
+
#: Framework/Style/StyleRenderer.php:196
|
152 |
+
#: SmartSlider3/Widget/Arrow/ArrowImage/ArrowImage.php:74
|
153 |
+
#: SmartSlider3/Widget/Arrow/ArrowImage/ArrowImage.php:108
|
154 |
+
#: SmartSlider3/Widget/Bullet/BulletTransition/BulletTransition.php:42
|
155 |
+
#: SmartSlider3/Widget/Thumbnail/Basic/ThumbnailBasic.php:63
|
156 |
+
#: SmartSlider3Pro/Application/Admin/Slider/ViewSliderParticle.php:139
|
157 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:171
|
158 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:187
|
159 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:206
|
160 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:258
|
161 |
+
#: SmartSlider3Pro/Widget/Bullet/BulletNumbers/BulletNumbers.php:45
|
162 |
+
#: SmartSlider3Pro/Widget/Bullet/BulletText/BulletText.php:44
|
163 |
+
msgid "Hover"
|
164 |
+
msgstr "Hover"
|
165 |
+
|
166 |
+
#: Framework/Font/FontRenderer.php:139 Framework/Style/StyleRenderer.php:141
|
167 |
+
#: SmartSlider3/Renderable/Item/Heading/Assets/heading.js:20
|
168 |
+
#: SmartSlider3/Renderable/Item/Heading/ItemHeading.php:53
|
169 |
+
#: SmartSlider3/Renderable/Item/Heading/ItemHeading.php:148
|
170 |
+
#: SmartSlider3/Storage.php:65
|
171 |
+
#: SmartSlider3Pro/Renderable/Item/HighlightedHeading/ItemHighlightedHeading.php:302
|
172 |
+
#: SmartSlider3Pro/Renderable/Item/HighlightedHeading/ItemHighlightedHeading.php:306
|
173 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:99
|
174 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:245
|
175 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:260
|
176 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:203
|
177 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/AddLayer/AddLayer.phtml:27
|
178 |
+
msgid "Heading"
|
179 |
+
msgstr "Heading"
|
180 |
+
|
181 |
+
#: Framework/Font/FontRenderer.php:150 Framework/Font/FontRenderer.php:188
|
182 |
+
#: Framework/Font/FontRenderer.php:238
|
183 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsColumn.php:58
|
184 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsColumn.php:60
|
185 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsRow.php:85
|
186 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsRow.php:87
|
187 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsSlide.php:75
|
188 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsSlide.php:77
|
189 |
+
#: SmartSlider3/Renderable/Item/Button/ItemButton.php:157
|
190 |
+
#: SmartSlider3/Renderable/Item/Button/ItemButton.php:158
|
191 |
+
#: SmartSlider3/Renderable/Item/Heading/ItemHeading.php:170
|
192 |
+
#: SmartSlider3/Renderable/Item/Heading/ItemHeading.php:171
|
193 |
+
#: SmartSlider3/Renderable/Item/Image/ItemImage.php:134
|
194 |
+
#: SmartSlider3/Renderable/Item/Image/ItemImage.php:135
|
195 |
+
#: SmartSlider3/Renderable/Item/Image/ItemImage.php:181
|
196 |
+
#: SmartSlider3/Storage.php:877
|
197 |
+
#: SmartSlider3Pro/Form/Element/ParticleSkin.php:18
|
198 |
+
#: SmartSlider3Pro/Renderable/Item/AnimatedHeading/ItemAnimatedHeading.php:169
|
199 |
+
#: SmartSlider3Pro/Renderable/Item/AnimatedHeading/ItemAnimatedHeading.php:170
|
200 |
+
#: SmartSlider3Pro/Renderable/Item/Area/ItemArea.php:188
|
201 |
+
#: SmartSlider3Pro/Renderable/Item/Area/ItemArea.php:189
|
202 |
+
#: SmartSlider3Pro/Renderable/Item/Caption/ItemCaption.php:180
|
203 |
+
#: SmartSlider3Pro/Renderable/Item/Caption/ItemCaption.php:181
|
204 |
+
#: SmartSlider3Pro/Renderable/Item/HighlightedHeading/ItemHighlightedHeading.php:218
|
205 |
+
#: SmartSlider3Pro/Renderable/Item/HighlightedHeading/ItemHighlightedHeading.php:219
|
206 |
+
#: SmartSlider3Pro/Renderable/Item/Icon2/ItemIcon2.php:114
|
207 |
+
#: SmartSlider3Pro/Renderable/Item/Icon2/ItemIcon2.php:115
|
208 |
+
#: SmartSlider3Pro/Renderable/Item/ImageArea/ItemImageArea.php:136
|
209 |
+
#: SmartSlider3Pro/Renderable/Item/ImageArea/ItemImageArea.php:137
|
210 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:276
|
211 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:277
|
212 |
+
#: SmartSlider3Pro/Renderable/Item/Transition/ItemTransition.php:138
|
213 |
+
#: SmartSlider3Pro/Renderable/Item/Transition/ItemTransition.php:139
|
214 |
+
msgid "Link"
|
215 |
+
msgstr "Link"
|
216 |
+
|
217 |
+
#: Framework/Font/FontRenderer.php:158 Framework/Font/FontRenderer.php:262
|
218 |
+
#: Framework/Style/StyleRenderer.php:122 Framework/Style/StyleRenderer.php:201
|
219 |
+
#: SmartSlider3/Renderable/Item/Button/Assets/button.js:20
|
220 |
+
#: SmartSlider3/Renderable/Item/Button/ItemButton.php:50
|
221 |
+
#: SmartSlider3/Renderable/Item/Button/ItemButton.php:141
|
222 |
+
#: SmartSlider3/Storage.php:290 SmartSlider3/Widget/Group/Autoplay.php:49
|
223 |
+
#: SmartSlider3Pro/Renderable/Item/Input/ItemInput.php:91
|
224 |
+
#: SmartSlider3Pro/Renderable/Item/Input/ItemInput.php:95
|
225 |
+
#: SmartSlider3Pro/Renderable/Item/Input/ItemInput.php:157
|
226 |
+
#: SmartSlider3Pro/Renderable/Item/Input/ItemInput.php:216
|
227 |
+
#: SmartSlider3Pro/Renderable/Item/Input/ItemInput.php:220
|
228 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:184
|
229 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:263
|
230 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/AddLayer/AddLayer.phtml:30
|
231 |
+
msgid "Button"
|
232 |
+
msgstr "Button"
|
233 |
+
|
234 |
+
#: Framework/Font/FontRenderer.php:169
|
235 |
+
msgid "Accordion slide title"
|
236 |
+
msgstr ""
|
237 |
+
|
238 |
+
#: Framework/Font/FontRenderer.php:171
|
239 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:71
|
240 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:72
|
241 |
+
#: Framework/Form/Element/Select/FontWeight.php:13
|
242 |
+
#: Framework/Form/Element/Select/FontWeight.php:18
|
243 |
+
#: Framework/Style/StyleRenderer.php:94 Framework/Style/StyleRenderer.php:108
|
244 |
+
#: Framework/Style/StyleRenderer.php:124 Framework/Style/StyleRenderer.php:143
|
245 |
+
#: Framework/Style/StyleRenderer.php:162 Framework/Style/StyleRenderer.php:178
|
246 |
+
#: Framework/Style/StyleRenderer.php:194
|
247 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderGeneral.php:140
|
248 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderOptimize.php:62
|
249 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSlides.php:149
|
250 |
+
#: SmartSlider3/Slider/SliderType/Block/SliderTypeBlockAdmin.php:61
|
251 |
+
#: SmartSlider3/Slider/SliderType/Block/SliderTypeBlockAdmin.php:72
|
252 |
+
#: SmartSlider3/Slider/SliderType/Block/SliderTypeBlockAdmin.php:173
|
253 |
+
#: SmartSlider3/Slider/SliderType/Block/SliderTypeBlockAdmin.php:184
|
254 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:153
|
255 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:186
|
256 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:197
|
257 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:377
|
258 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:411
|
259 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:427
|
260 |
+
#: SmartSlider3Pro/SplitText/ModelSplitText.php:62
|
261 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:156
|
262 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:170
|
263 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:186
|
264 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:205
|
265 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:224
|
266 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:240
|
267 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:256
|
268 |
+
msgid "Normal"
|
269 |
+
msgstr "Normal"
|
270 |
+
|
271 |
+
#: Framework/Font/FontRenderer.php:172 Framework/Font/FontRenderer.php:222
|
272 |
+
#: Framework/Style/StyleRenderer.php:163 Framework/Style/StyleRenderer.php:179
|
273 |
+
#: SmartSlider3Pro/Slider/SliderType/Showcase/SliderTypeShowcaseAdmin.php:353
|
274 |
+
#: SmartSlider3Pro/Slider/SliderType/Showcase/SliderTypeShowcaseAdmin.php:396
|
275 |
+
#: SmartSlider3Pro/Slider/SliderType/Showcase/SliderTypeShowcaseAdmin.php:441
|
276 |
+
#: SmartSlider3Pro/Slider/SliderType/Showcase/SliderTypeShowcaseAdmin.php:477
|
277 |
+
#: SmartSlider3Pro/Slider/SliderType/Showcase/SliderTypeShowcaseAdmin.php:513
|
278 |
+
#: SmartSlider3Pro/Slider/SliderType/Showcase/SliderTypeShowcaseAdmin.php:554
|
279 |
+
#: SmartSlider3Pro/Slider/SliderType/Showcase/SliderTypeShowcaseAdmin.php:596
|
280 |
+
#: SmartSlider3Pro/Slider/SliderType/Showcase/SliderTypeShowcaseAdmin.php:638
|
281 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:225
|
282 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:241
|
283 |
+
msgid "Active"
|
284 |
+
msgstr "Aktiv"
|
285 |
+
|
286 |
+
#: Framework/Font/FontRenderer.php:177
|
287 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsSlide.php:57
|
288 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowReveal/ArrowReveal.php:79
|
289 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowReveal/Assets/Admin/arrow.js:11
|
290 |
+
msgid "Slide title"
|
291 |
+
msgstr ""
|
292 |
+
|
293 |
+
#: Framework/Font/FontRenderer.php:185
|
294 |
+
msgid "Paragraph"
|
295 |
+
msgstr ""
|
296 |
+
|
297 |
+
#: Framework/Font/FontRenderer.php:219 Framework/Style/StyleRenderer.php:176
|
298 |
+
#: SmartSlider3/Widget/Bullet/BulletTransition/BulletTransition.php:49
|
299 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:238
|
300 |
+
#: SmartSlider3Pro/Widget/Bullet/BulletNumbers/BulletNumbers.php:51
|
301 |
+
#: SmartSlider3Pro/Widget/Bullet/BulletText/BulletText.php:51
|
302 |
+
msgid "Dot"
|
303 |
+
msgstr ""
|
304 |
+
|
305 |
+
#: Framework/Font/FontRenderer.php:235 SmartSlider3/Storage.php:529
|
306 |
+
#: SmartSlider3Pro/Renderable/Item/HtmlList/Assets/list.js:20
|
307 |
+
#: SmartSlider3Pro/Renderable/Item/HtmlList/ItemHtmlList.php:56
|
308 |
+
#: SmartSlider3Pro/Renderable/Item/HtmlList/ItemHtmlList.php:76
|
309 |
+
#: SmartSlider3Pro/Renderable/Item/HtmlList/ItemHtmlList.php:80
|
310 |
+
#: SmartSlider3Pro/Renderable/Item/HtmlList/ItemHtmlList.php:160
|
311 |
+
msgid "List"
|
312 |
+
msgstr "Liste"
|
313 |
+
|
314 |
+
#: Framework/Font/FontRenderer.php:253 Framework/Font/FontRenderer.php:256
|
315 |
+
#: Framework/Style/StyleRenderer.php:192 Framework/Style/StyleRenderer.php:195
|
316 |
+
#: SmartSlider3Pro/Renderable/Item/HighlightedHeading/ItemHighlightedHeading.php:234
|
317 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:254
|
318 |
+
#: SmartSlider3Pro/SplitText/SplitTextRenderer.php:257
|
319 |
+
msgid "Highlight"
|
320 |
+
msgstr ""
|
321 |
+
|
322 |
+
#: Framework/Font/FontSettings.php:30
|
323 |
+
msgctxt "Default font"
|
324 |
+
msgid "Roboto,Arial"
|
325 |
+
msgstr ""
|
326 |
+
|
327 |
+
#: Framework/Font/ModelFont.php:28
|
328 |
+
msgid "Font settings"
|
329 |
+
msgstr ""
|
330 |
+
|
331 |
+
#: Framework/Font/ModelFont.php:32 Framework/Style/ModelStyle.php:29
|
332 |
+
msgid "Clear tab"
|
333 |
+
msgstr ""
|
334 |
+
|
335 |
+
#: Framework/Font/ModelFont.php:37
|
336 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:48
|
337 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:50
|
338 |
+
msgid "Family"
|
339 |
+
msgstr ""
|
340 |
+
|
341 |
+
#: Framework/Font/ModelFont.php:40
|
342 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsColumn.php:170
|
343 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:54
|
344 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsRow.php:197
|
345 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsSlide.php:302
|
346 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabAnimation.php:438
|
347 |
+
#: SmartSlider3/Form/Element/BackgroundImage.php:31
|
348 |
+
#: SmartSlider3/Renderable/Item/Vimeo/ItemVimeo.php:201
|
349 |
+
#: SmartSlider3/Widget/Arrow/ArrowImage/ArrowImage.php:71
|
350 |
+
#: SmartSlider3/Widget/Arrow/ArrowImage/ArrowImage.php:105
|
351 |
+
#: SmartSlider3/Widget/Autoplay/AutoplayImage/AutoplayImage.php:53
|
352 |
+
#: SmartSlider3/Widget/Autoplay/AutoplayImage/AutoplayImage.php:83
|
353 |
+
#: SmartSlider3Pro/Application/Admin/Slider/ViewSliderParticle.php:119
|
354 |
+
#: SmartSlider3Pro/Application/Admin/Slider/ViewSliderShapeDivider.php:105
|
355 |
+
#: SmartSlider3Pro/Application/Admin/Slider/ViewSliderShapeDivider.php:164
|
356 |
+
#: SmartSlider3Pro/Renderable/Item/Area/ItemArea.php:112
|
357 |
+
#: SmartSlider3Pro/Renderable/Item/Area/ItemArea.php:158
|
358 |
+
#: SmartSlider3Pro/Renderable/Item/CircleCounter/ItemCircleCounter.php:137
|
359 |
+
#: SmartSlider3Pro/Renderable/Item/HighlightedHeading/ItemHighlightedHeading.php:245
|
360 |
+
#: SmartSlider3Pro/Renderable/Item/Icon2/ItemIcon2.php:94
|
361 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:240
|
362 |
+
#: SmartSlider3Pro/Renderable/Item/ProgressBar/ItemProgressBar.php:138
|
363 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowGrow/ArrowGrow.php:40
|
364 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowGrow/ArrowGrow.php:54
|
365 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowImageBar/ArrowImageBar.php:43
|
366 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowImageBar/ArrowImageBar.php:57
|
367 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowReveal/ArrowReveal.php:59
|
368 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowReveal/ArrowReveal.php:74
|
369 |
+
#: SmartSlider3Pro/Widget/FullScreen/FullScreenImage/FullScreenImage.php:53
|
370 |
+
#: SmartSlider3Pro/Widget/FullScreen/FullScreenImage/FullScreenImage.php:76
|
371 |
+
msgid "Color"
|
372 |
+
msgstr "Farbe"
|
373 |
+
|
374 |
+
#: Framework/Font/ModelFont.php:44
|
375 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:413
|
376 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:416
|
377 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:418
|
378 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:52
|
379 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsColumn.php:192
|
380 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsCommon.php:84
|
381 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsCommon.php:216
|
382 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsContent.php:166
|
383 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:58
|
384 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:59
|
385 |
+
#: SmartSlider3/Renderable/Item/Button/ItemButton.php:182
|
386 |
+
#: SmartSlider3/Renderable/Item/Image/ItemImage.php:150
|
387 |
+
#: SmartSlider3/Slider/SliderType/Block/SliderTypeBlockAdmin.php:88
|
388 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:217
|
389 |
+
#: SmartSlider3/Widget/Thumbnail/Basic/ThumbnailBasic.php:129
|
390 |
+
#: SmartSlider3/Widget/Thumbnail/Basic/ThumbnailBasic.php:132
|
391 |
+
#: SmartSlider3/Widget/Thumbnail/Basic/ThumbnailBasic.php:149
|
392 |
+
#: SmartSlider3/Widget/Thumbnail/Basic/ThumbnailBasic.php:202
|
393 |
+
#: SmartSlider3/Widget/Thumbnail/Basic/ThumbnailBasic.php:204
|
394 |
+
#: SmartSlider3Pro/Renderable/Item/Area/ItemArea.php:174
|
395 |
+
#: SmartSlider3Pro/Renderable/Item/CircleCounter/ItemCircleCounter.php:143
|
396 |
+
#: SmartSlider3Pro/Renderable/Item/Icon2/ItemIcon2.php:101
|
397 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:232
|
398 |
+
#: SmartSlider3Pro/Slider/SliderType/Carousel/SliderTypeCarouselAdmin.php:191
|
399 |
+
#: SmartSlider3Pro/Slider/SliderType/Showcase/SliderTypeShowcaseAdmin.php:92
|
400 |
+
#: SmartSlider3Pro/Widget/Indicator/IndicatorPie/IndicatorPie.php:31
|
401 |
+
msgid "Size"
|
402 |
+
msgstr "Größe"
|
403 |
+
|
404 |
+
#: Framework/Font/ModelFont.php:46
|
405 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:63
|
406 |
+
msgid "Font weight"
|
407 |
+
msgstr ""
|
408 |
+
|
409 |
+
#: Framework/Font/ModelFont.php:47
|
410 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:79
|
411 |
+
msgid "Decoration"
|
412 |
+
msgstr ""
|
413 |
+
|
414 |
+
#: Framework/Font/ModelFont.php:48
|
415 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:65
|
416 |
+
msgid "Line height"
|
417 |
+
msgstr ""
|
418 |
+
|
419 |
+
#: Framework/Font/ModelFont.php:59
|
420 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:77
|
421 |
+
#: SmartSlider3Pro/Renderable/Item/Html/ItemHtml.php:68
|
422 |
+
msgid "Text align"
|
423 |
+
msgstr ""
|
424 |
+
|
425 |
+
#: Framework/Font/ModelFont.php:63
|
426 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:91
|
427 |
+
msgid "Letter spacing"
|
428 |
+
msgstr ""
|
429 |
+
|
430 |
+
#: Framework/Font/ModelFont.php:74
|
431 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:103
|
432 |
+
msgid "Word spacing"
|
433 |
+
msgstr ""
|
434 |
+
|
435 |
+
#: Framework/Font/ModelFont.php:84
|
436 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:114
|
437 |
+
msgid "Transform"
|
438 |
+
msgstr ""
|
439 |
+
|
440 |
+
#: Framework/Font/ModelFont.php:86 Framework/Form/Element/Mixed/Border.php:39
|
441 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsColumn.php:163
|
442 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:116
|
443 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsRow.php:190
|
444 |
+
#: SmartSlider3/Generator/Joomla/JoomlaContent/Sources/JoomlaContentArticle.php:91
|
445 |
+
#: SmartSlider3/Generator/Joomla/JoomlaContent/Sources/JoomlaContentCategory.php:46
|
446 |
+
#: SmartSlider3/Generator/WordPress/Posts/Sources/PostsAllCustomPosts.php:105
|
447 |
+
#: SmartSlider3/Generator/WordPress/Posts/Sources/PostsCustomPosts.php:187
|
448 |
+
#: SmartSlider3/Generator/WordPress/Posts/Sources/PostsPosts.php:85
|
449 |
+
#: SmartSlider3/Platform/WordPress/Integration/ACF/AcfFieldSmartSlider3.php:105
|
450 |
+
#: SmartSlider3/Platform/WordPress/Integration/BeaverBuilder/BeaverBuilder.php:167
|
451 |
+
#: SmartSlider3/Platform/WordPress/Widget/WidgetSmartSlider3.php:126
|
452 |
+
#: SmartSlider3/Slider/ResponsiveType/FullWidth/ResponsiveTypeFullWidthAdmin.php:44
|
453 |
+
#: SmartSlider3/Widget/Arrow/ArrowImage/ArrowImage.php:131
|
454 |
+
#: SmartSlider3Pro/Application/Admin/Slider/ViewSliderShapeDivider.php:150
|
455 |
+
#: SmartSlider3Pro/Application/Admin/Slider/ViewSliderShapeDivider.php:208
|
456 |
+
#: SmartSlider3Pro/Generator/Common/ImagesInFolder/Sources/ImagesInFolderImages.php:102
|
457 |
+
#: SmartSlider3Pro/Generator/Common/ImagesInFolder/Sources/ImagesInFolderSubfolders.php:101
|
458 |
+
#: SmartSlider3Pro/Generator/Common/ImagesInFolder/Sources/ImagesInFolderVideos.php:92
|
459 |
+
#: SmartSlider3Pro/Generator/Common/Vimeo/Sources/VimeoAlbum.php:35
|
460 |
+
#: SmartSlider3Pro/Generator/Joomla/Cobalt/Sources/CobaltRecords.php:62
|
461 |
+
#: SmartSlider3Pro/Generator/Joomla/Djclassifieds/Sources/DjclassifiedsItems.php:84
|
462 |
+
#: SmartSlider3Pro/Generator/Joomla/Easyblog/Sources/EasyblogPosts.php:51
|
463 |
+
#: SmartSlider3Pro/Generator/Joomla/Easydiscuss/Sources/EasydiscussDiscussions.php:46
|
464 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialAlbums.php:75
|
465 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialEvents.php:64
|
466 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialGroups.php:57
|
467 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialPages.php:62
|
468 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialPages.php:70
|
469 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialUsers.php:80
|
470 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialVideos.php:45
|
471 |
+
#: SmartSlider3Pro/Generator/Joomla/Eshop/Sources/EshopProducts.php:76
|
472 |
+
#: SmartSlider3Pro/Generator/Joomla/Eventsbooking/Sources/EventsbookingEvents.php:78
|
473 |
+
#: SmartSlider3Pro/Generator/Joomla/Flexicontent/Sources/FlexicontentItems.php:54
|
474 |
+
#: SmartSlider3Pro/Generator/Joomla/Hikashop/Sources/HikashopProducts.php:55
|
475 |
+
#: SmartSlider3Pro/Generator/Joomla/Ignitegallery/Sources/IgnitegalleryImages.php:38
|
476 |
+
#: SmartSlider3Pro/Generator/Joomla/Jauction/Sources/JauctionAuctions.php:52
|
477 |
+
#: SmartSlider3Pro/Generator/Joomla/Jcart/Sources/JcartProducts.php:118
|
478 |
+
#: SmartSlider3Pro/Generator/Joomla/Jevents/Sources/JeventsEvents.php:86
|
479 |
+
#: SmartSlider3Pro/Generator/Joomla/Jevents/Sources/JeventsRepeatingevents.php:69
|
480 |
+
#: SmartSlider3Pro/Generator/Joomla/Jmarket/Sources/JmarketProducts.php:51
|
481 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Sources/JomsocialActivities.php:78
|
482 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Sources/JomsocialEvents.php:69
|
483 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Sources/JomsocialGroups.php:56
|
484 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Sources/JomsocialVideos.php:56
|
485 |
+
#: SmartSlider3Pro/Generator/Joomla/Joomshopping/Elements/JoomshoppingLabels.php:28
|
486 |
+
#: SmartSlider3Pro/Generator/Joomla/Joomshopping/Sources/JoomshoppingProducts.php:63
|
487 |
+
#: SmartSlider3Pro/Generator/Joomla/Jreviews/Sources/JreviewsComments.php:62
|
488 |
+
#: SmartSlider3Pro/Generator/Joomla/K2/Sources/K2Items.php:61
|
489 |
+
#: SmartSlider3Pro/Generator/Joomla/Mijoshop/Sources/MijoshopProducts.php:51
|
490 |
+
#: SmartSlider3Pro/Generator/Joomla/Phocagallery/Sources/PhocagalleryImages.php:45
|
491 |
+
#: SmartSlider3Pro/Generator/Joomla/Redshop/Sources/RedshopProducts.php:56
|
492 |
+
#: SmartSlider3Pro/Generator/Joomla/Rseventspro/Sources/RseventsproEvents.php:84
|
493 |
+
#: SmartSlider3Pro/Generator/Joomla/Virtuemart/Sources/VirtuemartProducts.php:66
|
494 |
+
#: SmartSlider3Pro/Generator/Joomla/Zoo/Sources/ZooItems.php:56
|
495 |
+
#: SmartSlider3Pro/Generator/WordPress/MultisitePost/Sources/MultisitePostPosts.php:38
|
496 |
+
#: SmartSlider3Pro/Generator/WordPress/WebdoradoPhotoGallery/Sources/WebdoradoPhotoGalleryImages.php:36
|
497 |
+
#: SmartSlider3Pro/Renderable/Item/Area/ItemArea.php:151
|
498 |
+
#: SmartSlider3Pro/Renderable/Item/HighlightedHeading/ItemHighlightedHeading.php:137
|
499 |
+
#: SmartSlider3Pro/Renderable/Item/Video/ItemVideo.php:223
|
500 |
+
#: SmartSlider3Pro/Slider/ResponsiveType/FullPage/ResponsiveTypeFullPageAdmin.php:39
|
501 |
+
msgid "None"
|
502 |
+
msgstr "Keine"
|
503 |
+
|
504 |
+
#: Framework/Font/ModelFont.php:87
|
505 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:117
|
506 |
+
msgid "Capitalize"
|
507 |
+
msgstr ""
|
508 |
+
|
509 |
+
#: Framework/Font/ModelFont.php:88
|
510 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:118
|
511 |
+
msgid "Uppercase"
|
512 |
+
msgstr ""
|
513 |
+
|
514 |
+
#: Framework/Font/ModelFont.php:89
|
515 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:119
|
516 |
+
msgid "Lowercase"
|
517 |
+
msgstr ""
|
518 |
+
|
519 |
+
#: Framework/Font/ModelFont.php:93
|
520 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsItemCommon.php:123
|
521 |
+
msgid "Text shadow"
|
522 |
+
msgstr ""
|
523 |
+
|
524 |
+
#: Framework/Font/ModelFont.php:100 Framework/Image/ModelImage.php:35
|
525 |
+
#: Framework/Image/ModelImage.php:58 Framework/Style/ModelStyle.php:94
|
526 |
+
#: SmartSlider3/Application/Admin/Assets/js/common/modal/modals/hotkey.js:83
|
527 |
+
#: SmartSlider3/Application/Admin/Assets/js/slider/slider.js:61
|
528 |
+
#: SmartSlider3/Application/Admin/Assets/js/slider/trash.js:111
|
529 |
+
#: SmartSlider3/Application/Admin/Generator/ViewGeneratorEdit.php:77
|
530 |
+
#: SmartSlider3/Application/Admin/Preview/ViewPreviewIndex.php:38
|
531 |
+
#: SmartSlider3/Application/Admin/Slider/ViewSliderEdit.php:115
|
532 |
+
#: SmartSlider3/Application/Admin/Slides/ViewSlidesEdit.php:213
|
533 |
+
#: SmartSlider3/BackgroundAnimation/ModelBackgroundAnimation.php:41
|
534 |
+
#: SmartSlider3Pro/Application/Admin/Slider/ViewSliderEditGroup.php:78
|
535 |
+
#: SmartSlider3Pro/PostBackgroundAnimation/ModelPostBackgroundAnimation.php:45
|
536 |
+
#: SmartSlider3Pro/SplitText/ModelSplitText.php:225
|
537 |
+
msgid "Preview"
|
538 |
+
msgstr "Vorschau"
|
539 |
+
|
540 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:54
|
541 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:55
|
542 |
+
msgid "Frontend"
|
543 |
+
msgstr ""
|
544 |
+
|
545 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:56
|
546 |
+
msgid "You can load Google Fonts on the frontend."
|
547 |
+
msgstr ""
|
548 |
+
|
549 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:58
|
550 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:59
|
551 |
+
msgid "Backend"
|
552 |
+
msgstr ""
|
553 |
+
|
554 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:60
|
555 |
+
msgid "You can load Google Fonts in the backend."
|
556 |
+
msgstr ""
|
557 |
+
|
558 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:63
|
559 |
+
#: Framework/Form/Element/Style.php:50
|
560 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsColumn.php:161
|
561 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsRow.php:188
|
562 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabStyle.php:20
|
563 |
+
#: SmartSlider3/Widget/Autoplay/AutoplayImage/AutoplayImage.php:57
|
564 |
+
#: SmartSlider3/Widget/Group/Bullet.php:95
|
565 |
+
#: SmartSlider3Pro/Renderable/Item/Area/ItemArea.php:149
|
566 |
+
#: SmartSlider3Pro/Renderable/Item/HighlightedHeading/ItemHighlightedHeading.php:306
|
567 |
+
#: SmartSlider3Pro/Renderable/Item/HtmlList/ItemHtmlList.php:160
|
568 |
+
#: SmartSlider3Pro/Renderable/Item/HtmlList/ItemHtmlList.php:163
|
569 |
+
#: SmartSlider3Pro/Widget/Indicator/IndicatorPie/IndicatorPie.php:47
|
570 |
+
msgid "Style"
|
571 |
+
msgstr "Stil"
|
572 |
+
|
573 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:66
|
574 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:68
|
575 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:70
|
576 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:72
|
577 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:74
|
578 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:76
|
579 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:78
|
580 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:80
|
581 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:82
|
582 |
+
msgctxt "Font style"
|
583 |
+
msgid "Italic"
|
584 |
+
msgstr ""
|
585 |
+
|
586 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:85
|
587 |
+
msgid "Character set"
|
588 |
+
msgstr ""
|
589 |
+
|
590 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:87
|
591 |
+
msgctxt "Character set"
|
592 |
+
msgid "Latin"
|
593 |
+
msgstr ""
|
594 |
+
|
595 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:88
|
596 |
+
msgctxt "Character set"
|
597 |
+
msgid "Latin Extended"
|
598 |
+
msgstr ""
|
599 |
+
|
600 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:89
|
601 |
+
msgctxt "Character set"
|
602 |
+
msgid "Greek"
|
603 |
+
msgstr ""
|
604 |
+
|
605 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:90
|
606 |
+
msgctxt "Character set"
|
607 |
+
msgid "Greek Extended"
|
608 |
+
msgstr ""
|
609 |
+
|
610 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:91
|
611 |
+
msgctxt "Character set"
|
612 |
+
msgid "Cyrillic"
|
613 |
+
msgstr ""
|
614 |
+
|
615 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:92
|
616 |
+
msgctxt "Character set"
|
617 |
+
msgid "Devanagari"
|
618 |
+
msgstr ""
|
619 |
+
|
620 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:93
|
621 |
+
msgctxt "Character set"
|
622 |
+
msgid "Arabic"
|
623 |
+
msgstr ""
|
624 |
+
|
625 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:94
|
626 |
+
msgctxt "Character set"
|
627 |
+
msgid "Khmer"
|
628 |
+
msgstr ""
|
629 |
+
|
630 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:95
|
631 |
+
msgctxt "Character set"
|
632 |
+
msgid "Telugu"
|
633 |
+
msgstr ""
|
634 |
+
|
635 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:96
|
636 |
+
msgctxt "Character set"
|
637 |
+
msgid "Vietnamese"
|
638 |
+
msgstr ""
|
639 |
+
|
640 |
+
#: Framework/Font/Sources/GoogleFonts/GoogleFonts.php:101
|
641 |
+
msgctxt "Default font sets"
|
642 |
+
msgid "latin"
|
643 |
+
msgstr ""
|
644 |
+
|
645 |
+
#: Framework/Form/Element/Breakpoint.php:39
|
646 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:411
|
647 |
+
#: SmartSlider3/Widget/Bullet/BulletTransition/BulletTransition.php:75
|
648 |
+
#: SmartSlider3/Widget/Thumbnail/Basic/ThumbnailBasic.php:194
|
649 |
+
#: SmartSlider3Pro/Slider/SliderType/Accordion/SliderTypeAccordionAdmin.php:52
|
650 |
+
#: SmartSlider3Pro/Widget/Bullet/BulletNumbers/BulletNumbers.php:80
|
651 |
+
#: SmartSlider3Pro/Widget/Bullet/BulletText/BulletText.php:80
|
652 |
+
msgid "Orientation"
|
653 |
+
msgstr "Orientierung"
|
654 |
+
|
655 |
+
#: Framework/Form/Element/Breakpoint.php:41
|
656 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:411
|
657 |
+
#: SmartSlider3/Renderable/Item/Vimeo/ItemVimeo.php:209
|
658 |
+
msgid "Portrait"
|
659 |
+
msgstr "Portrait"
|
660 |
+
|
661 |
+
#: Framework/Form/Element/Breakpoint.php:42
|
662 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:411
|
663 |
+
msgid "Landscape"
|
664 |
+
msgstr "Landscape"
|
665 |
+
|
666 |
+
#: Framework/Form/Element/Breakpoint.php:51
|
667 |
+
#: Framework/Form/Element/Breakpoint.php:86 Framework/Image/ModelImage.php:40
|
668 |
+
#: SmartSlider3/Application/Admin/Assets/js/common/modal/modals/hotkey.js:86
|
669 |
+
#: SmartSlider3/Application/Admin/Assets/js/fragment/components/ComponentCommonAbstract.js:228
|
670 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:20
|
671 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:161
|
672 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:162
|
673 |
+
#: SmartSlider3/Application/Admin/Assets/js/slide/edit.js:181
|
674 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderAnimations.php:112
|
675 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:97
|
676 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:224
|
677 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:296
|
678 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:517
|
679 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSlides.php:156
|
680 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/SlideBox/BlockSlideBox.php:167
|
681 |
+
#: SmartSlider3/Renderable/Item/Text/ItemText.php:157
|
682 |
+
#: SmartSlider3/Renderable/Item/Text/ItemText.php:161
|
683 |
+
#: SmartSlider3/Widget/Group/AbstractWidgetGroup.php:97
|
684 |
+
#: SmartSlider3Pro/Slider/SliderType/Carousel/SliderTypeCarouselAdmin.php:150
|
685 |
+
msgid "Mobile"
|
686 |
+
msgstr "Mobil"
|
687 |
+
|
688 |
+
#: Framework/Form/Element/Breakpoint.php:56
|
689 |
+
#: SmartSlider3/Application/Admin/Assets/js/fragment/components/ComponentCommonAbstract.js:229
|
690 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:21
|
691 |
+
#: SmartSlider3/Application/Admin/Assets/js/slide/edit.js:177
|
692 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:101
|
693 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:208
|
694 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:288
|
695 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:492
|
696 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/SlideBox/BlockSlideBox.php:163
|
697 |
+
#: SmartSlider3/Widget/Group/AbstractWidgetGroup.php:103
|
698 |
+
msgid "Large mobile"
|
699 |
+
msgstr ""
|
700 |
+
|
701 |
+
#: Framework/Form/Element/Breakpoint.php:61
|
702 |
+
#: Framework/Form/Element/Breakpoint.php:91 Framework/Image/ModelImage.php:38
|
703 |
+
#: SmartSlider3/Application/Admin/Assets/js/common/modal/modals/hotkey.js:85
|
704 |
+
#: SmartSlider3/Application/Admin/Assets/js/fragment/components/ComponentCommonAbstract.js:226
|
705 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:18
|
706 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:163
|
707 |
+
#: SmartSlider3/Application/Admin/Assets/js/slide/edit.js:172
|
708 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:106
|
709 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:191
|
710 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:281
|
711 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:467
|
712 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSlides.php:155
|
713 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/SlideBox/BlockSlideBox.php:159
|
714 |
+
#: SmartSlider3/Renderable/Item/Text/ItemText.php:145
|
715 |
+
#: SmartSlider3/Renderable/Item/Text/ItemText.php:149
|
716 |
+
#: SmartSlider3/Widget/Group/AbstractWidgetGroup.php:112
|
717 |
+
#: SmartSlider3Pro/Slider/SliderType/Carousel/SliderTypeCarouselAdmin.php:126
|
718 |
+
msgid "Tablet"
|
719 |
+
msgstr "Tablet"
|
720 |
+
|
721 |
+
#: Framework/Form/Element/Breakpoint.php:66
|
722 |
+
#: SmartSlider3/Application/Admin/Assets/js/fragment/components/ComponentCommonAbstract.js:227
|
723 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:19
|
724 |
+
#: SmartSlider3/Application/Admin/Assets/js/slide/edit.js:168
|
725 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:110
|
726 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:176
|
727 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:273
|
728 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:442
|
729 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/SlideBox/BlockSlideBox.php:155
|
730 |
+
#: SmartSlider3/Widget/Group/AbstractWidgetGroup.php:118
|
731 |
+
msgid "Large tablet"
|
732 |
+
msgstr ""
|
733 |
+
|
734 |
+
#: Framework/Form/Element/Breakpoint.php:71
|
735 |
+
#: Framework/Form/Element/Breakpoint.php:96 Framework/Image/ModelImage.php:31
|
736 |
+
#: SmartSlider3/Application/Admin/Assets/js/common/modal/modals/hotkey.js:84
|
737 |
+
#: SmartSlider3/Application/Admin/Assets/js/fragment/components/ComponentCommonAbstract.js:224
|
738 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:16
|
739 |
+
#: SmartSlider3/Application/Admin/Assets/js/slide/edit.js:163
|
740 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:115
|
741 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:158
|
742 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/SlideBox/BlockSlideBox.php:151
|
743 |
+
#: SmartSlider3/Widget/Group/AbstractWidgetGroup.php:127
|
744 |
+
#: SmartSlider3Pro/Slider/SliderType/Carousel/SliderTypeCarouselAdmin.php:102
|
745 |
+
#: SmartSlider3/Application/Admin/Preview/Template/Index.phtml:29
|
746 |
+
msgid "Desktop"
|
747 |
+
msgstr "Desktop"
|
748 |
+
|
749 |
+
#: Framework/Form/Element/Breakpoint.php:76
|
750 |
+
#: SmartSlider3/Application/Admin/Assets/js/fragment/components/ComponentCommonAbstract.js:225
|
751 |
+
#: SmartSlider3/Application/Admin/Assets/js/preview.js:17
|
752 |
+
#: SmartSlider3/Application/Admin/Assets/js/slide/edit.js:159
|
753 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:119
|
754 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:143
|
755 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:266
|
756 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderSize.php:416
|
757 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/SlideBox/BlockSlideBox.php:147
|
758 |
+
#: SmartSlider3/Widget/Group/AbstractWidgetGroup.php:133
|
759 |
+
msgid "Large desktop"
|
760 |
+
msgstr ""
|
761 |
+
|
762 |
+
#: Framework/Form/Element/Button/ButtonMoreLess.php:13
|
763 |
+
#: Framework/Form/Element/Button/ButtonMoreLess.php:19
|
764 |
+
msgid "More"
|
765 |
+
msgstr ""
|
766 |
+
|
767 |
+
#: Framework/Form/Element/Button/ButtonMoreLess.php:20
|
768 |
+
msgid "Less"
|
769 |
+
msgstr ""
|
770 |
+
|
771 |
+
#: Framework/Form/Element/Button/ButtonRecordViewer.php:13
|
772 |
+
msgid "View records"
|
773 |
+
msgstr "Aufzeichnungen ansehen"
|
774 |
+
|
775 |
+
#: Framework/Form/Element/Font.php:40
|
776 |
+
#: SmartSlider3Pro/Renderable/Item/Caption/ItemCaption.php:169
|
777 |
+
#: SmartSlider3Pro/Renderable/Item/Caption/ItemCaption.php:176
|
778 |
+
#: SmartSlider3Pro/Renderable/Item/CircleCounter/ItemCircleCounter.php:191
|
779 |
+
#: SmartSlider3Pro/Renderable/Item/CircleCounter/ItemCircleCounter.php:194
|
780 |
+
#: SmartSlider3Pro/Renderable/Item/Counter/ItemCounter.php:146
|
781 |
+
#: SmartSlider3Pro/Renderable/Item/Counter/ItemCounter.php:149
|
782 |
+
#: SmartSlider3Pro/Renderable/Item/HighlightedHeading/ItemHighlightedHeading.php:302
|
783 |
+
#: SmartSlider3Pro/Renderable/Item/ProgressBar/ItemProgressBar.php:175
|
784 |
+
#: SmartSlider3Pro/Renderable/Item/ProgressBar/ItemProgressBar.php:179
|
785 |
+
#: SmartSlider3Pro/Slider/SliderType/Accordion/SliderTypeAccordionAdmin.php:161
|
786 |
+
#: SmartSlider3Pro/Widget/Arrow/ArrowReveal/ArrowReveal.php:85
|
787 |
+
msgid "Font"
|
788 |
+
msgstr "Schriftart"
|
789 |
+
|
790 |
+
#: Framework/Form/Element/Message/Warning.php:14
|
791 |
+
msgid "Warning"
|
792 |
+
msgstr ""
|
793 |
+
|
794 |
+
#: Framework/Form/Element/Mixed/Border.php:40
|
795 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsColumn.php:166
|
796 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsRow.php:193
|
797 |
+
#: SmartSlider3Pro/Renderable/Item/Area/ItemArea.php:154
|
798 |
+
msgid "Dotted"
|
799 |
+
msgstr ""
|
800 |
+
|
801 |
+
#: Framework/Form/Element/Mixed/Border.php:41
|
802 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsColumn.php:165
|
803 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsRow.php:192
|
804 |
+
#: SmartSlider3Pro/Renderable/Item/Area/ItemArea.php:153
|
805 |
+
msgid "Dashed"
|
806 |
+
msgstr ""
|
807 |
+
|
808 |
+
#: Framework/Form/Element/Mixed/Border.php:42
|
809 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsColumn.php:164
|
810 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsRow.php:191
|
811 |
+
#: SmartSlider3Pro/Renderable/Item/Area/ItemArea.php:152
|
812 |
+
msgid "Solid"
|
813 |
+
msgstr ""
|
814 |
+
|
815 |
+
#: Framework/Form/Element/Mixed/Border.php:43
|
816 |
+
msgid "Double"
|
817 |
+
msgstr ""
|
818 |
+
|
819 |
+
#: Framework/Form/Element/Mixed/Border.php:44
|
820 |
+
msgid "Groove"
|
821 |
+
msgstr ""
|
822 |
+
|
823 |
+
#: Framework/Form/Element/Mixed/Border.php:45
|
824 |
+
msgid "Ridge"
|
825 |
+
msgstr ""
|
826 |
+
|
827 |
+
#: Framework/Form/Element/Mixed/Border.php:46
|
828 |
+
msgid "Inset"
|
829 |
+
msgstr ""
|
830 |
+
|
831 |
+
#: Framework/Form/Element/Mixed/Border.php:47
|
832 |
+
msgid "Outset"
|
833 |
+
msgstr ""
|
834 |
+
|
835 |
+
#: Framework/Form/Element/Mixed/GeneratorOrder.php:20
|
836 |
+
msgid "Field"
|
837 |
+
msgstr "Feld"
|
838 |
+
|
839 |
+
#: Framework/Form/Element/Mixed/GeneratorOrder.php:22
|
840 |
+
#: SmartSlider3/Generator/Joomla/JoomlaContent/Sources/JoomlaContentArticle.php:87
|
841 |
+
#: SmartSlider3/Generator/Joomla/JoomlaContent/Sources/JoomlaContentCategory.php:42
|
842 |
+
#: SmartSlider3/Generator/WordPress/Posts/Sources/PostsAllCustomPosts.php:101
|
843 |
+
#: SmartSlider3/Generator/WordPress/Posts/Sources/PostsCustomPosts.php:183
|
844 |
+
#: SmartSlider3/Generator/WordPress/Posts/Sources/PostsCustomPosts.php:206
|
845 |
+
#: SmartSlider3/Generator/WordPress/Posts/Sources/PostsPosts.php:81
|
846 |
+
#: SmartSlider3Pro/Generator/Common/ImagesInFolder/Sources/ImagesInFolderImages.php:98
|
847 |
+
#: SmartSlider3Pro/Generator/Common/ImagesInFolder/Sources/ImagesInFolderSubfolders.php:97
|
848 |
+
#: SmartSlider3Pro/Generator/Common/ImagesInFolder/Sources/ImagesInFolderVideos.php:88
|
849 |
+
#: SmartSlider3Pro/Generator/Common/Vimeo/Sources/VimeoAlbum.php:31
|
850 |
+
#: SmartSlider3Pro/Generator/Joomla/Cobalt/Sources/CobaltRecords.php:58
|
851 |
+
#: SmartSlider3Pro/Generator/Joomla/Djclassifieds/Sources/DjclassifiedsItems.php:80
|
852 |
+
#: SmartSlider3Pro/Generator/Joomla/Easyblog/Sources/EasyblogPosts.php:47
|
853 |
+
#: SmartSlider3Pro/Generator/Joomla/Easydiscuss/Sources/EasydiscussDiscussions.php:42
|
854 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialAlbums.php:71
|
855 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialEvents.php:60
|
856 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialGroups.php:53
|
857 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialPages.php:66
|
858 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialUsers.php:76
|
859 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialVideos.php:41
|
860 |
+
#: SmartSlider3Pro/Generator/Joomla/Eshop/Sources/EshopProducts.php:72
|
861 |
+
#: SmartSlider3Pro/Generator/Joomla/Eventsbooking/Sources/EventsbookingEvents.php:74
|
862 |
+
#: SmartSlider3Pro/Generator/Joomla/Flexicontent/Sources/FlexicontentItems.php:50
|
863 |
+
#: SmartSlider3Pro/Generator/Joomla/Hikashop/Sources/HikashopProducts.php:51
|
864 |
+
#: SmartSlider3Pro/Generator/Joomla/Ignitegallery/Sources/IgnitegalleryImages.php:34
|
865 |
+
#: SmartSlider3Pro/Generator/Joomla/Jauction/Sources/JauctionAuctions.php:48
|
866 |
+
#: SmartSlider3Pro/Generator/Joomla/Jcart/Sources/JcartProducts.php:114
|
867 |
+
#: SmartSlider3Pro/Generator/Joomla/Jevents/Sources/JeventsEvents.php:82
|
868 |
+
#: SmartSlider3Pro/Generator/Joomla/Jevents/Sources/JeventsRepeatingevents.php:65
|
869 |
+
#: SmartSlider3Pro/Generator/Joomla/Jmarket/Sources/JmarketProducts.php:47
|
870 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Sources/JomsocialActivities.php:74
|
871 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Sources/JomsocialEvents.php:65
|
872 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Sources/JomsocialGroups.php:52
|
873 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Sources/JomsocialVideos.php:52
|
874 |
+
#: SmartSlider3Pro/Generator/Joomla/Joomshopping/Sources/JoomshoppingProducts.php:59
|
875 |
+
#: SmartSlider3Pro/Generator/Joomla/Jreviews/Sources/JreviewsComments.php:58
|
876 |
+
#: SmartSlider3Pro/Generator/Joomla/K2/Sources/K2Items.php:57
|
877 |
+
#: SmartSlider3Pro/Generator/Joomla/Mijoshop/Sources/MijoshopProducts.php:47
|
878 |
+
#: SmartSlider3Pro/Generator/Joomla/Phocagallery/Sources/PhocagalleryImages.php:41
|
879 |
+
#: SmartSlider3Pro/Generator/Joomla/Redshop/Sources/RedshopProducts.php:52
|
880 |
+
#: SmartSlider3Pro/Generator/Joomla/Rseventspro/Sources/RseventsproEvents.php:80
|
881 |
+
#: SmartSlider3Pro/Generator/Joomla/Virtuemart/Sources/VirtuemartProducts.php:62
|
882 |
+
#: SmartSlider3Pro/Generator/Joomla/Zoo/Sources/ZooItems.php:52
|
883 |
+
#: SmartSlider3Pro/Generator/WordPress/AllInOneEventCalendar/Sources/AllinOneEventCalendarEvents.php:68
|
884 |
+
#: SmartSlider3Pro/Generator/WordPress/EventsManager/Sources/EventsManagerEvents.php:91
|
885 |
+
#: SmartSlider3Pro/Generator/WordPress/MultisitePost/Sources/MultisitePostPosts.php:34
|
886 |
+
#: SmartSlider3Pro/Generator/WordPress/TheEventsCalendar/Sources/TheEventsCalendarEvents.php:76
|
887 |
+
#: SmartSlider3Pro/Generator/WordPress/WebdoradoPhotoGallery/Sources/WebdoradoPhotoGalleryImages.php:32
|
888 |
+
#: SmartSlider3Pro/Generator/WordPress/WebdoradoPhotoGallery/Sources/WebdoradoPhotoGalleryImages.php:41
|
889 |
+
#: SmartSlider3Pro/Generator/WordPress/WooCommerce/Sources/WooCommerceProductsByFilter.php:82
|
890 |
+
msgid "Order"
|
891 |
+
msgstr "Reihenfolge"
|
892 |
+
|
893 |
+
#: Framework/Form/Element/Mixed/GeneratorOrder.php:24
|
894 |
+
msgid "Ascending"
|
895 |
+
msgstr "Aufsteigend"
|
896 |
+
|
897 |
+
#: Framework/Form/Element/Mixed/GeneratorOrder.php:25
|
898 |
+
msgid "Descending"
|
899 |
+
msgstr "Absteigend"
|
900 |
+
|
901 |
+
#: Framework/Form/Element/OnOff.php:22
|
902 |
+
#: Framework/Form/Element/Select/Gradient.php:15
|
903 |
+
#: SmartSlider3/Application/Admin/Assets/js/common/ui.js:145
|
904 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderAnimations.php:117
|
905 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderAnimations.php:124
|
906 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderAutoplay.php:96
|
907 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderAutoplay.php:107
|
908 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsCommon.php:290
|
909 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsCommon.php:307
|
910 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:165
|
911 |
+
#: SmartSlider3Pro/Application/Admin/Slider/ViewSliderParticle.php:141
|
912 |
+
#: SmartSlider3Pro/Application/Admin/Slider/ViewSliderParticle.php:150
|
913 |
+
#: SmartSlider3Pro/Renderable/Item/Input/ItemInput.php:180
|
914 |
+
msgid "Off"
|
915 |
+
msgstr "Aus"
|
916 |
+
|
917 |
+
#: Framework/Form/Element/OnOff.php:22
|
918 |
+
#: SmartSlider3/Application/Admin/Assets/js/common/ui.js:146
|
919 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsCommon.php:308
|
920 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:166
|
921 |
+
msgid "On"
|
922 |
+
msgstr "An"
|
923 |
+
|
924 |
+
#: Framework/Form/Element/Select.php:48
|
925 |
+
msgid ""
|
926 |
+
"Hold down the ctrl (Windows) or command (MAC) button to select multiple "
|
927 |
+
"options."
|
928 |
+
msgstr ""
|
929 |
+
|
930 |
+
#: Framework/Form/Element/Select/FillMode.php:15
|
931 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsSlide.php:239
|
932 |
+
#: SmartSlider3/Slider/SliderType/Block/SliderTypeBlockAdmin.php:107
|
933 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:240
|
934 |
+
#: SmartSlider3Pro/Renderable/Item/ImageArea/ItemImageArea.php:130
|
935 |
+
#: SmartSlider3Pro/Renderable/Item/Video/ItemVideo.php:208
|
936 |
+
msgid "Fill"
|
937 |
+
msgstr "Fülle"
|
938 |
+
|
939 |
+
#: Framework/Form/Element/Select/FillMode.php:16
|
940 |
+
msgid "Blur fit"
|
941 |
+
msgstr ""
|
942 |
+
|
943 |
+
#: Framework/Form/Element/Select/FillMode.php:17
|
944 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsSlide.php:240
|
945 |
+
#: SmartSlider3/Slider/SliderType/Block/SliderTypeBlockAdmin.php:108
|
946 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:241
|
947 |
+
#: SmartSlider3Pro/Renderable/Item/ImageArea/ItemImageArea.php:131
|
948 |
+
#: SmartSlider3Pro/Renderable/Item/Video/ItemVideo.php:209
|
949 |
+
msgid "Fit"
|
950 |
+
msgstr "Fit"
|
951 |
+
|
952 |
+
#: Framework/Form/Element/Select/FillMode.php:18
|
953 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsRow.php:79
|
954 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsRow.php:80
|
955 |
+
msgid "Stretch"
|
956 |
+
msgstr "Strecken"
|
957 |
+
|
958 |
+
#: Framework/Form/Element/Select/FillMode.php:19
|
959 |
+
#: SmartSlider3/Application/Admin/Assets/js/element/widgetposition.js:81
|
960 |
+
#: SmartSlider3/Application/Admin/Assets/js/element/widgetposition.js:102
|
961 |
+
#: SmartSlider3/Application/Admin/FormManager/Slider/SliderGeneral.php:142
|
962 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsSlide.php:241
|
963 |
+
#: SmartSlider3/Slider/SliderType/Block/SliderTypeBlockAdmin.php:109
|
964 |
+
#: SmartSlider3/Slider/SliderType/Simple/SliderTypeSimpleAdmin.php:242
|
965 |
+
#: SmartSlider3/Storage.php:710
|
966 |
+
#: SmartSlider3/Widget/Bar/BarHorizontal/BarHorizontal.php:103
|
967 |
+
#: SmartSlider3/Widget/Bullet/BulletTransition/BulletTransition.php:71
|
968 |
+
#: SmartSlider3/Widget/Thumbnail/Basic/ThumbnailBasic.php:71
|
969 |
+
#: SmartSlider3Pro/Renderable/Item/Caption/ItemCaption.php:235
|
970 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:333
|
971 |
+
#: SmartSlider3Pro/Slider/SliderType/Carousel/SliderTypeCarouselAdmin.php:307
|
972 |
+
#: SmartSlider3Pro/SplitText/ModelSplitText.php:67
|
973 |
+
#: SmartSlider3Pro/Widget/Bullet/BulletNumbers/BulletNumbers.php:76
|
974 |
+
#: SmartSlider3Pro/Widget/Bullet/BulletText/BulletText.php:76
|
975 |
+
msgid "Center"
|
976 |
+
msgstr "Mitte"
|
977 |
+
|
978 |
+
#: Framework/Form/Element/Select/FillMode.php:20
|
979 |
+
msgid "Tile"
|
980 |
+
msgstr ""
|
981 |
+
|
982 |
+
#: Framework/Form/Element/Select/FillMode.php:26
|
983 |
+
msgid "Slider's default"
|
984 |
+
msgstr ""
|
985 |
+
|
986 |
+
#: Framework/Form/Element/Select/Filter.php:17
|
987 |
+
#: SmartSlider3/Generator/Joomla/JoomlaContent/Elements/JoomlaContentAccessLevels.php:28
|
988 |
+
#: SmartSlider3/Generator/Joomla/JoomlaContent/Elements/JoomlaContentCategories.php:40
|
989 |
+
#: SmartSlider3/Generator/Joomla/JoomlaContent/Elements/JoomlaContentTags.php:21
|
990 |
+
#: SmartSlider3/Generator/WordPress/Posts/Elements/PostsAllTaxonomies.php:23
|
991 |
+
#: SmartSlider3/Generator/WordPress/Posts/Elements/PostsCategories.php:40
|
992 |
+
#: SmartSlider3/Generator/WordPress/Posts/Elements/PostsPostTypes.php:14
|
993 |
+
#: SmartSlider3/Generator/WordPress/Posts/Elements/PostsTags.php:17
|
994 |
+
#: SmartSlider3/Generator/WordPress/Posts/Elements/PostsTaxonomies.php:23
|
995 |
+
#: SmartSlider3Pro/Generator/Common/Flickr/Sources/FlickrPhotosSearch.php:39
|
996 |
+
#: SmartSlider3Pro/Generator/Joomla/Cobalt/Elements/CobaltCategories.php:39
|
997 |
+
#: SmartSlider3Pro/Generator/Joomla/Djclassifieds/Elements/DjclassifiedsCategories.php:36
|
998 |
+
#: SmartSlider3Pro/Generator/Joomla/Djclassifieds/Elements/DjclassifiedsLocations.php:36
|
999 |
+
#: SmartSlider3Pro/Generator/Joomla/Djclassifieds/Elements/DjclassifiedsTypes.php:15
|
1000 |
+
#: SmartSlider3Pro/Generator/Joomla/Easyblog/Elements/EasyblogCategories.php:30
|
1001 |
+
#: SmartSlider3Pro/Generator/Joomla/Easyblog/Elements/EasyblogTags.php:19
|
1002 |
+
#: SmartSlider3Pro/Generator/Joomla/Easydiscuss/Elements/EasydiscussCategories.php:30
|
1003 |
+
#: SmartSlider3Pro/Generator/Joomla/Easydiscuss/Elements/EasydiscussTags.php:19
|
1004 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Elements/EasysocialCategories.php:34
|
1005 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialEvents.php:47
|
1006 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialGroups.php:43
|
1007 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialPages.php:49
|
1008 |
+
#: SmartSlider3Pro/Generator/Joomla/Easysocial/Sources/EasysocialPages.php:58
|
1009 |
+
#: SmartSlider3Pro/Generator/Joomla/Eshop/Elements/EshopCategories.php:35
|
1010 |
+
#: SmartSlider3Pro/Generator/Joomla/Eshop/Elements/EshopManufacturers.php:20
|
1011 |
+
#: SmartSlider3Pro/Generator/Joomla/Eshop/Elements/EshopTags.php:20
|
1012 |
+
#: SmartSlider3Pro/Generator/Joomla/Eventsbooking/Elements/EventsbookingCategories.php:29
|
1013 |
+
#: SmartSlider3Pro/Generator/Joomla/Eventsbooking/Elements/EventsbookingLocations.php:17
|
1014 |
+
#: SmartSlider3Pro/Generator/Joomla/Eventsbooking/Sources/EventsbookingEvents.php:60
|
1015 |
+
#: SmartSlider3Pro/Generator/Joomla/Flexicontent/Elements/FlexicontentCategories.php:40
|
1016 |
+
#: SmartSlider3Pro/Generator/Joomla/Flexicontent/Elements/FlexicontentTags.php:19
|
1017 |
+
#: SmartSlider3Pro/Generator/Joomla/Hikashop/Elements/HikashopBrands.php:32
|
1018 |
+
#: SmartSlider3Pro/Generator/Joomla/Hikashop/Elements/HikashopCategories.php:32
|
1019 |
+
#: SmartSlider3Pro/Generator/Joomla/Hikashop/Elements/HikashopTags.php:18
|
1020 |
+
#: SmartSlider3Pro/Generator/Joomla/Hikashop/Elements/HikashopWarehouses.php:18
|
1021 |
+
#: SmartSlider3Pro/Generator/Joomla/Ignitegallery/Elements/IgnitegalleryCategories.php:33
|
1022 |
+
#: SmartSlider3Pro/Generator/Joomla/Jauction/Elements/JauctionCategories.php:35
|
1023 |
+
#: SmartSlider3Pro/Generator/Joomla/Jauction/Elements/JauctionLanguages.php:21
|
1024 |
+
#: SmartSlider3Pro/Generator/Joomla/Jcart/Elements/JcartCategories.php:33
|
1025 |
+
#: SmartSlider3Pro/Generator/Joomla/Jcart/Elements/JcartLanguages.php:22
|
1026 |
+
#: SmartSlider3Pro/Generator/Joomla/Jevents/Elements/JeventsCalendars.php:17
|
1027 |
+
#: SmartSlider3Pro/Generator/Joomla/Jevents/Elements/JeventsCategories.php:34
|
1028 |
+
#: SmartSlider3Pro/Generator/Joomla/Jevents/Sources/JeventsEvents.php:72
|
1029 |
+
#: SmartSlider3Pro/Generator/Joomla/Jmarket/Elements/JmarketCategories.php:35
|
1030 |
+
#: SmartSlider3Pro/Generator/Joomla/Jmarket/Elements/JmarketLanguages.php:21
|
1031 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Elements/JomsocialCategories.php:31
|
1032 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Elements/JomsocialEvents.php:17
|
1033 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Elements/JomsocialGroupcategories.php:31
|
1034 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Elements/JomsocialGroups.php:17
|
1035 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Elements/JomsocialProfiles.php:17
|
1036 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Elements/JomsocialVideotype.php:17
|
1037 |
+
#: SmartSlider3Pro/Generator/Joomla/Jomsocial/Sources/JomsocialGroups.php:46
|
1038 |
+
#: SmartSlider3Pro/Generator/Joomla/Joomshopping/Elements/JoomshoppingCategories.php:42
|
1039 |
+
#: SmartSlider3Pro/Generator/Joomla/Joomshopping/Elements/JoomshoppingLabels.php:27
|
1040 |
+
#: SmartSlider3Pro/Generator/Joomla/Joomshopping/Elements/JoomshoppingManufacturers.php:27
|
1041 |
+
#: SmartSlider3Pro/Generator/Joomla/Jreviews/Elements/JreviewsArticles.php:21
|
1042 |
+
#: SmartSlider3Pro/Generator/Joomla/Jreviews/Elements/JreviewsCategories.php:36
|
1043 |
+
#: SmartSlider3Pro/Generator/Joomla/K2/Elements/K2Categories.php:29
|
1044 |
+
#: SmartSlider3Pro/Generator/Joomla/K2/Elements/K2Tags.php:18
|
1045 |
+
#: SmartSlider3Pro/Generator/Joomla/Mijoshop/Elements/MijoshopCategories.php:49
|
1046 |
+
#: SmartSlider3Pro/Generator/Joomla/Mijoshop/Elements/MijoshopManufacturers.php:18
|
1047 |
+
#: SmartSlider3Pro/Generator/Joomla/Phocagallery/Elements/PhocagalleryCategories.php:35
|
1048 |
+
#: SmartSlider3Pro/Generator/Joomla/Phocagallery/Elements/PhocagalleryTags.php:18
|
1049 |
+
#: SmartSlider3Pro/Generator/Joomla/Redshop/Elements/RedshopCategories.php:37
|
1050 |
+
#: SmartSlider3Pro/Generator/Joomla/Redshop/Elements/RedshopManufacturers.php:18
|
1051 |
+
#: SmartSlider3Pro/Generator/Joomla/Redshop/Elements/RedshopSuppliers.php:18
|
1052 |
+
#: SmartSlider3Pro/Generator/Joomla/Rseventspro/Elements/RseventsproCategories.php:39
|
1053 |
+
#: SmartSlider3Pro/Generator/Joomla/Rseventspro/Elements/RseventsproGroups.php:17
|
1054 |
+
#: SmartSlider3Pro/Generator/Joomla/Rseventspro/Elements/RseventsproLocations.php:17
|
1055 |
+
#: SmartSlider3Pro/Generator/Joomla/Rseventspro/Elements/RseventsproTags.php:17
|
1056 |
+
#: SmartSlider3Pro/Generator/Joomla/Virtuemart/Elements/VirtuemartCategories.php:34
|
1057 |
+
#: SmartSlider3Pro/Generator/Joomla/Virtuemart/Elements/VirtuemartManufacturers.php:21
|
1058 |
+
#: SmartSlider3Pro/Generator/Joomla/Zoo/Elements/ZooCategories.php:24
|
1059 |
+
#: SmartSlider3Pro/Generator/Joomla/Zoo/Elements/ZooTags.php:17
|
1060 |
+
#: SmartSlider3Pro/Generator/WordPress/AllInOneEventCalendar/Elements/AllInOneEventCalendarCategories.php:34
|
1061 |
+
#: SmartSlider3Pro/Generator/WordPress/AllInOneEventCalendar/Elements/AllInOneEventCalendarTags.php:35
|
1062 |
+
#: SmartSlider3Pro/Generator/WordPress/EventsManager/Elements/EventsManagerCategories.php:34
|
1063 |
+
#: SmartSlider3Pro/Generator/WordPress/EventsManager/Elements/EventsManagerLocations.php:31
|
1064 |
+
#: SmartSlider3Pro/Generator/WordPress/EventsManager/Elements/EventsManagerTags.php:33
|
1065 |
+
#: SmartSlider3Pro/Generator/WordPress/MultisitePost/Elements/MultisitePostCategories.php:38
|
1066 |
+
#: SmartSlider3Pro/Generator/WordPress/TheEventsCalendar/Elements/TheEventsCalendarCategories.php:34
|
1067 |
+
#: SmartSlider3Pro/Generator/WordPress/TheEventsCalendar/Elements/TheEventsCalendarOrganizers.php:31
|
1068 |
+
#: SmartSlider3Pro/Generator/WordPress/TheEventsCalendar/Elements/TheEventsCalendarTags.php:35
|
1069 |
+
#: SmartSlider3Pro/Generator/WordPress/TheEventsCalendar/Elements/TheEventsCalendarVenues.php:31
|
1070 |
+
#: SmartSlider3Pro/Generator/WordPress/WebdoradoPhotoGallery/Elements/WebdoradoPhotoGalleryGalleries.php:14
|
1071 |
+
#: SmartSlider3Pro/Generator/WordPress/WebdoradoPhotoGallery/Elements/WebdoradoPhotoGalleryTags.php:14
|
1072 |
+
#: SmartSlider3Pro/Generator/WordPress/WooCommerce/Elements/WooCommerceTags.php:28
|
1073 |
+
#: SmartSlider3Pro/Generator/WordPress/WooCommerce/Sources/WooCommerceProductsByFilter.php:63
|
1074 |
+
msgid "All"
|
1075 |
+
msgstr "Alle"
|
1076 |
+
|
1077 |
+
#: Framework/Form/Element/Select/Filter.php:19
|
1078 |
+
#, php-format
|
1079 |
+
msgid "Not %s"
|
1080 |
+
msgstr ""
|
1081 |
+
|
1082 |
+
#: Framework/Form/Element/Select/FontWeight.php:14
|
1083 |
+
#: Framework/Form/Element/Select/FontWeight.php:21
|
1084 |
+
msgid "Bold"
|
1085 |
+
msgstr ""
|
1086 |
+
|
1087 |
+
#: Framework/Form/Element/Select/FontWeight.php:16
|
1088 |
+
msgid "Extra light"
|
1089 |
+
msgstr ""
|
1090 |
+
|
1091 |
+
#: Framework/Form/Element/Select/FontWeight.php:17
|
1092 |
+
#: SmartSlider3Pro/Slider/SliderType/Accordion/SliderTypeAccordionAdmin.php:77
|
1093 |
+
msgid "Light"
|
1094 |
+
msgstr "Hell"
|
1095 |
+
|
1096 |
+
#: Framework/Form/Element/Select/FontWeight.php:20
|
1097 |
+
msgid "Semi bold"
|
1098 |
+
msgstr ""
|
1099 |
+
|
1100 |
+
#: Framework/Form/Element/Select/FontWeight.php:22
|
1101 |
+
msgid "Extra bold"
|
1102 |
+
msgstr ""
|
1103 |
+
|
1104 |
+
#: Framework/Form/Element/Select/LinkTarget.php:13
|
1105 |
+
msgid "Self"
|
1106 |
+
msgstr ""
|
1107 |
+
|
1108 |
+
#: Framework/Form/Element/Select/LinkTarget.php:14
|
1109 |
+
msgid "New"
|
1110 |
+
msgstr ""
|
1111 |
+
|
1112 |
+
#: Framework/Form/Element/Select/LinkTarget.php:15
|
1113 |
+
#: SmartSlider3/Application/Admin/Assets/js/fragment/components/ComponentAbstract.js:1150
|
1114 |
+
msgid "Parent"
|
1115 |
+
msgstr ""
|
1116 |
+
|
1117 |
+
#: Framework/Form/Element/Select/LinkTarget.php:16
|
1118 |
+
#: SmartSlider3/Application/Admin/Assets/js/element/widgetposition.js:75
|
1119 |
+
#: SmartSlider3/Application/Admin/Assets/js/element/widgetposition.js:78
|
1120 |
+
#: SmartSlider3/Application/Admin/Assets/js/element/widgetposition.js:81
|
1121 |
+
#: SmartSlider3/Application/Admin/Assets/js/element/widgetposition.js:84
|
1122 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsCommon.php:176
|
1123 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabAnimation.php:468
|
1124 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabAnimation.php:472
|
1125 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabAnimation.php:480
|
1126 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabAnimation.php:481
|
1127 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabAnimation.php:482
|
1128 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabAnimation.php:483
|
1129 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabAnimation.php:488
|
1130 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabAnimation.php:511
|
1131 |
+
#: SmartSlider3/Application/Admin/Settings/ViewSettingsGeneral.php:238
|
1132 |
+
#: SmartSlider3/Form/Element/Group/WidgetPosition.php:106
|
1133 |
+
#: SmartSlider3/Storage.php:979
|
1134 |
+
#: SmartSlider3Pro/Application/Admin/Assets/js/element/shapedividermanager.js:140
|
1135 |
+
#: SmartSlider3Pro/Application/Admin/Slider/ViewSliderShapeDivider.php:73
|
1136 |
+
#: SmartSlider3Pro/LayerAnimation/LayerAnimationStorage.php:199
|
1137 |
+
#: SmartSlider3Pro/Renderable/Item/Caption/ItemCaption.php:217
|
1138 |
+
#: SmartSlider3Pro/Renderable/Item/Caption/ItemCaption.php:234
|
1139 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:295
|
1140 |
+
#: SmartSlider3Pro/Renderable/Item/ImageBox/ItemImageBox.php:332
|
1141 |
+
#: SmartSlider3Pro/Slider/ResponsiveType/FullPage/ResponsiveTypeFullPageAdmin.php:105
|
1142 |
+
msgid "Top"
|
1143 |
+
msgstr "Oben"
|
1144 |
+
|
1145 |
+
#: Framework/Form/Element/Select/SelectFile.php:36
|
1146 |
+
#: Framework/Form/Element/Select/Skin.php:27
|
1147 |
+
#: SmartSlider3/Application/Admin/Generator/Template/CreateStep1Groups.phtml:43
|
1148 |
+
#: SmartSlider3/Application/Admin/Generator/Template/CreateStep3Sources.phtml:23
|
1149 |
+
msgid "Choose"
|
1150 |
+
msgstr "Wählen"
|
1151 |
+
|
1152 |
+
#: Framework/Form/Element/Text/FieldImageResponsive.php:27
|
1153 |
+
msgid "Select images for devices"
|
1154 |
+
msgstr ""
|
1155 |
+
|
1156 |
+
#: Framework/Form/Element/Text/Url.php:33
|
1157 |
+
msgid "Select a page or a blog post from your WordPress site."
|
1158 |
+
msgstr ""
|
1159 |
+
|
1160 |
+
#: Framework/Form/Element/Text/Url.php:38
|
1161 |
+
msgid "Select article or menu item from your site."
|
1162 |
+
msgstr ""
|
1163 |
+
|
1164 |
+
#: Framework/Form/Fieldset/LayerWindow/FieldsetDesign.php:16
|
1165 |
+
#: Framework/Form/Fieldset/LayerWindow/FieldsetLayerWindowStyleMode.php:18
|
1166 |
+
msgid "Reset to normal state"
|
1167 |
+
msgstr ""
|
1168 |
+
|
1169 |
+
#: Framework/Form/Joomla/Element/Select/MenuItems.php:18
|
1170 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsCommon.php:61
|
1171 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsCommon.php:150
|
1172 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Settings/LayerWindowSettingsSlide.php:132
|
1173 |
+
#: SmartSlider3/Application/Admin/Layout/Block/Slide/LayerWindow/Tab/TabAnimation.php:507
|
1174 |
+
#: SmartSlider3/Renderable/Item/Vimeo/ItemVimeo.php:169
|
1175 |
+
#: SmartSlider3/Renderable/Item/Vimeo/ItemVimeo.php:216
|
1176 |
+
#: SmartSlider3/Renderable/Item/YouTube/ItemYouTube.php:175
|
1177 |
+
#: SmartSlider3/Slider/SliderType/Block/SliderTypeBlockAdmin.php:58
|
1178 |
+
#: SmartSlider3/Slider/SliderType/Block/SliderTypeBlockAdmin.php:69
|
1179 |
+
#: SmartS
|