This commit is contained in:
2024-05-20 15:37:46 +03:00
commit 00b7dbd0b7
10404 changed files with 3285853 additions and 0 deletions

View File

@ -0,0 +1,230 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item;
use Nextend\Framework\Data\Data;
use Nextend\Framework\Font\FontParser;
use Nextend\Framework\Form\ContainerInterface;
use Nextend\Framework\Model\Section;
use Nextend\Framework\Pattern\GetAssetsPathTrait;
use Nextend\Framework\Pattern\OrderableTrait;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\Framework\Style\StyleParser;
use Nextend\SmartSlider3\BackupSlider\ExportSlider;
use Nextend\SmartSlider3\BackupSlider\ImportSlider;
use Nextend\SmartSlider3\Renderable\AbstractRenderableOwner;
use Nextend\SmartSlider3\Slider\Admin\AdminSlider;
abstract class AbstractItem {
use GetAssetsPathTrait, OrderableTrait;
protected $layerProperties = array();
protected $fonts = array();
protected $styles = array();
/**
* AbstractItem constructor.
*
* @param ItemFactory $factory
*/
public function __construct($factory) {
$this->initDefault();
$factory->addItem($this);
}
private function initDefault() {
foreach ($this->fonts as &$fontData) {
$this->loadDefaultFont($fontData['defaultName'], $fontData['value']);
}
foreach ($this->styles as &$styleData) {
$this->loadDefaultStyle($styleData['defaultName'], $styleData['value']);
}
}
protected function loadDefaultFont($name, &$value) {
$res = Section::get('smartslider', 'default', $name);
if (is_array($res)) {
$value = $res['value'];
}
$value = FontParser::parse($value);
}
protected function loadDefaultStyle($name, &$value) {
$res = Section::get('smartslider', 'default', $name);
if (is_array($res)) {
$value = $res['value'];
}
$value = StyleParser::parse($value);
}
/**
* @param $id
* @param $itemData
* @param $layer
*
* @return AbstractItemFrontend
*/
public abstract function createFrontend($id, $itemData, $layer);
/**
* @return string
*/
public abstract function getTitle();
/**
* @return string
*/
public abstract function getIcon();
/**
* @return string
*/
public function getGroup() {
return n2_x('Basic', 'Layer group');
}
public function getLayerProperties() {
return $this->layerProperties;
}
public function isLegacy() {
return false;
}
public function getValues() {
$values = array();
foreach ($this->fonts as $name => $fontData) {
$values[$name] = $fontData['value'];
}
foreach ($this->styles as $name => $styleData) {
$values[$name] = $styleData['value'];
}
return $values;
}
/**
* @param $slide AbstractRenderableOwner
* @param $data Data
*
* @return Data
*/
public function getFilled($slide, $data) {
$this->upgradeData($data);
return $data;
}
/**
* @param Data $data
*/
public function upgradeData($data) {
}
/**
* Fix linked fonts/styles for the editor
*
* @param Data $data
*/
public function adminNormalizeFontsStyles($data) {
foreach ($this->fonts as $name => $fontData) {
$data->set($name, FontParser::parse($data->get($name)));
}
foreach ($this->styles as $name => $styleData) {
$data->set($name, StyleParser::parse($data->get($name)));
}
}
/**
* @param ExportSlider $export
* @param Data $data
*/
public function prepareExport($export, $data) {
$this->upgradeData($data);
}
/**
* @param ImportSlider $import
* @param Data $data
*
* @return Data
*/
public function prepareImport($import, $data) {
$this->upgradeData($data);
return $data;
}
/**
* @param Data $data
*
* @return Data
*/
public function prepareSample($data) {
$this->upgradeData($data);
return $data;
}
public function fixImage($image) {
return ResourceTranslator::toUrl($image);
}
public function fixLightbox($url) {
preg_match('/^([a-zA-Z]+)\[(.*)](.*)/', $url, $matches);
if (!empty($matches) && $matches[1] == 'lightbox') {
$images = explode(',', $matches[2]);
$newImages = array();
foreach ($images as $image) {
$newImages[] = ResourceTranslator::toUrl($image);
}
$url = 'lightbox[' . implode(',', $newImages) . ']' . $matches[3];
}
return $url;
}
/**
* @param AdminSlider $renderable
*/
public function loadResources($renderable) {
}
/**
* @return string
*/
public abstract function getType();
protected function isBuiltIn() {
return false;
}
/**
* @param ContainerInterface $container
*/
public abstract function renderFields($container);
/**
* @param ContainerInterface $container
*/
public function globalDefaultItemFontAndStyle($container) {
}
}

View File

@ -0,0 +1,119 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item;
use Nextend\Framework\Data\Data;
use Nextend\Framework\Parser\Link;
use Nextend\Framework\Pattern\GetAssetsPathTrait;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\Renderable\Component\ComponentLayer;
abstract class AbstractItemFrontend {
use GetAssetsPathTrait;
/** @var AbstractItem */
protected $item;
protected $id;
/** @var ComponentLayer */
protected $layer;
/** @var Data */
public $data;
protected $isEditor = false;
/**
*
* @param AbstractItem $item
* @param string $id
* @param array $itemData
* @param ComponentLayer $layer
*/
public function __construct($item, $id, $itemData, $layer) {
$this->item = $item;
$this->id = $id;
$this->data = new Data($itemData);
$this->layer = $layer;
$this->fillDefault($item->getValues());
}
private function fillDefault($defaults) {
$this->item->upgradeData($this->data);
$this->data->fillDefault($defaults);
}
public abstract function render();
public function renderAdmin() {
$this->isEditor = true;
/**
* Fix linked fonts/styles for the editor
*/
$this->item->adminNormalizeFontsStyles($this->data);
$rendered = $this->renderAdminTemplate();
$json = $this->data->toJson();
return Html::tag("div", array(
"class" => "n2-ss-item n2-ss-item-" . $this->item->getType(),
"data-item" => $this->item->getType(),
"data-itemvalues" => $json
), $rendered);
}
protected abstract function renderAdminTemplate();
public function needHeight() {
return false;
}
public function isAuto() {
return false;
}
protected function hasLink() {
$link = $this->data->get('href', '#');
if (($link != '#' && !empty($link))) {
return true;
}
return false;
}
protected function getLink($content, $attributes = array(), $renderEmpty = false) {
$link = $this->data->get('href', '#');
$target = $this->data->get('href-target', '#');
$rel = $this->data->get('href-rel', '#');
$class = $this->data->get('href-class', '');
if (($link != '#' && !empty($link)) || $renderEmpty === true) {
$link = Link::parse($this->layer->getOwner()
->fill($link), $attributes, $this->isEditor);
if (!empty($target) && $target != '_self') {
$attributes['target'] = $target;
}
if (!empty($rel)) {
$attributes['rel'] = $rel;
}
if (!empty($class)) {
$attributes['class'] = $class;
}
return Html::link($content, $link, $attributes);
}
return $content;
}
}

View File

@ -0,0 +1,172 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Button;
use Nextend\Framework\Form\Container\ContainerTable;
use Nextend\Framework\Form\Element\Font;
use Nextend\Framework\Form\Element\Hidden\HiddenFont;
use Nextend\Framework\Form\Element\Hidden\HiddenStyle;
use Nextend\Framework\Form\Element\Icon;
use Nextend\Framework\Form\Element\OnOff;
use Nextend\Framework\Form\Element\Select;
use Nextend\Framework\Form\Element\Select\LinkTarget;
use Nextend\Framework\Form\Element\Style;
use Nextend\Framework\Form\Element\Text;
use Nextend\Framework\Form\Element\Text\NumberSlider;
use Nextend\Framework\Form\Element\Text\Url;
use Nextend\Framework\Form\Fieldset;
use Nextend\Framework\Parser\Common;
use Nextend\SmartSlider3\Renderable\Item\AbstractItem;
class ItemButton extends AbstractItem {
protected $ordering = 4;
protected $fonts = array(
'font' => array(
'defaultName' => 'item-button-font',
'value' => '{"data":[{"color":"ffffffff","size":"14||px","align":"center"}, {"extra":""}]}'
)
);
protected $styles = array(
'style' => array(
'defaultName' => 'item-button-style',
'value' => '{"data":[{"backgroundcolor":"5cba3cff","padding":"10|*|30|*|10|*|30|*|px"}, {"extra":""}]}'
)
);
protected function isBuiltIn() {
return true;
}
public function getType() {
return 'button';
}
public function getTitle() {
return n2_('Button');
}
public function getIcon() {
return 'ssi_32 ssi_32--button';
}
public function createFrontend($id, $itemData, $layer) {
return new ItemButtonFrontend($this, $id, $itemData, $layer);
}
public function globalDefaultItemFontAndStyle($container) {
$table = new ContainerTable($container, $this->getType(), $this->getTitle());
$row1 = $table->createRow($this->getType() . '-1');
new Font($row1, 'item-button-font', false, $this->fonts['font']['value'], array(
'mode' => 'link'
));
new Style($row1, 'item-button-style', false, $this->styles['style']['value'], array(
'mode' => 'button'
));
}
public function getValues() {
return parent::getValues() + array(
'content' => n2_x('MORE', 'Button layer default text'),
'nowrap' => 1,
'fullwidth' => 0,
'href' => '#',
'href-target' => '_self',
'href-rel' => '',
'class' => '',
'icon' => '',
'iconsize' => '100',
'iconspacing' => '30',
'iconplacement' => 'left',
);
}
public function upgradeData($data) {
$linkV1 = $data->get('link', '');
if (!empty($linkV1)) {
list($link, $target, $rel) = array_pad((array)Common::parse($linkV1), 3, '');
$data->un_set('link');
$data->set('href', $link);
$data->set('href-target', $target);
$data->set('href-rel', $rel);
}
}
public function getFilled($slide, $data) {
$data = parent::getFilled($slide, $data);
$data->set('content', $slide->fill($data->get('content', '')));
$data->set('href', $slide->fill($data->get('href', '#|*|')));
return $data;
}
public function prepareExport($export, $data) {
parent::prepareExport($export, $data);
$export->addVisual($data->get('font'));
$export->addVisual($data->get('style'));
$export->addLightbox($data->get('href'));
}
public function prepareImport($import, $data) {
$data = parent::prepareImport($import, $data);
$data->set('font', $import->fixSection($data->get('font')));
$data->set('style', $import->fixSection($data->get('style')));
$data->set('href', $import->fixLightbox($data->get('href')));
return $data;
}
public function loadResources($renderable) {
parent::loadResources($renderable);
$renderable->addLess(self::getAssetsPath() . "/button.n2less", array(
"sliderid" => $renderable->elementId
));
}
public function renderFields($container) {
$settings = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-button', n2_('General'));
new Text($settings, 'content', n2_('Label'), n2_('Button'), array(
'style' => 'width:302px;'
));
new HiddenFont($settings, 'font', false, '', array(
'mode' => 'link'
));
new HiddenStyle($settings, 'style', false, '', array(
'mode' => 'button'
));
new OnOff($settings, 'fullwidth', n2_('Full width'), 1);
new OnOff($settings, 'nowrap', n2_('No wrap'), 1, array(
'tipLabel' => n2_('No wrap'),
'tipDescription' => n2_('Prevents the text from breaking into more lines')
));
$link = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-button-link', n2_('Link'));
new Url($link, 'href', n2_('Link'), '', array(
'relatedFields' => array(
'item_buttonhref-target',
'item_buttonhref-rel'
),
'width' => 248
));
new LinkTarget($link, 'href-target', n2_('Target window'));
new Text($link, 'href-rel', n2_('Rel'), '', array(
'style' => 'width:195px;',
'tipLabel' => n2_('Rel'),
'tipDescription' => sprintf(n2_('Enter the %1$s rel attribute %2$s that represents the relationship between the current document and the linked document. Multiple rel attributes can be separated with space. E.g. nofollow noopener noreferrer'), '<a href="https://www.w3schools.com/TAGS/att_a_rel.asp" target="_blank">', '</a>')
));
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Button;
use Nextend\Framework\Icon\Icon;
use Nextend\Framework\Sanitize;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\Renderable\AbstractRenderableOwner;
use Nextend\SmartSlider3\Renderable\Item\AbstractItemFrontend;
class ItemButtonFrontend extends AbstractItemFrontend {
public function render() {
return $this->getHtml();
}
public function renderAdminTemplate() {
return $this->getHtml();
}
private function getHtml() {
$owner = $this->layer->getOwner();
$this->loadResources($owner);
$font = $owner->addFont($this->data->get('font'), 'link');
$html = Html::openTag("div", array(
"class" => "n2-ss-button-container n2-ss-item-content n2-ow " . $font . ($this->data->get('nowrap', 1) ? ' n2-ss-nowrap' : '') . ($this->isAuto() ? ' n2-ss-button-container--non-full-width' : '')
));
$content = '<div>' . Sanitize::filter_allowed_html($owner->fill($this->data->get("content"))) . '</div>';
$attrs = array();
$style = $owner->addStyle($this->data->get('style'), 'heading');
$html .= $this->getLink('<div>' . $content . '</div>', $attrs + array(
"class" => "{$style} n2-ow " . $owner->fill($this->data->get('class', ''))
), true);
$html .= Html::closeTag("div");
return $html;
}
/**
* @param AbstractRenderableOwner $owner
*/
public function loadResources($owner) {
$owner->addLess(self::getAssetsPath() . "/button.n2less", array(
"sliderid" => $owner->getElementID()
));
}
public function isAuto() {
return !$this->data->get('fullwidth', 0);
}
}

View File

@ -0,0 +1,193 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Heading;
use Nextend\Framework\Form\Container\ContainerTable;
use Nextend\Framework\Form\Element\Font;
use Nextend\Framework\Form\Element\Hidden\HiddenFont;
use Nextend\Framework\Form\Element\Hidden\HiddenStyle;
use Nextend\Framework\Form\Element\MixedField;
use Nextend\Framework\Form\Element\OnOff;
use Nextend\Framework\Form\Element\Select;
use Nextend\Framework\Form\Element\Select\LinkTarget;
use Nextend\Framework\Form\Element\Style;
use Nextend\Framework\Form\Element\Text;
use Nextend\Framework\Form\Element\Text\Number;
use Nextend\Framework\Form\Element\Text\NumberAutoComplete;
use Nextend\Framework\Form\Element\Text\Url;
use Nextend\Framework\Form\Element\Textarea;
use Nextend\Framework\Form\Fieldset;
use Nextend\Framework\Parser\Common;
use Nextend\SmartSlider3\Renderable\Item\AbstractItem;
use Nextend\SmartSlider3Pro\Form\Element\SplitTextAnimation;
class ItemHeading extends AbstractItem {
protected $ordering = 1;
protected $fonts = array(
'font' => array(
'defaultName' => 'item-heading-font',
'value' => '{"data":[{"color":"ffffffff","size":"36||px","align":"inherit"},{"extra":""}]}'
)
);
protected $styles = array(
'style' => array(
'defaultName' => 'item-heading-style',
'value' => ''
)
);
protected function isBuiltIn() {
return true;
}
public function getType() {
return 'heading';
}
public function getTitle() {
return n2_('Heading');
}
public function getIcon() {
return 'ssi_32 ssi_32--heading';
}
public function createFrontend($id, $itemData, $layer) {
return new ItemHeadingFrontend($this, $id, $itemData, $layer);
}
public function getValues() {
return parent::getValues() + array(
'priority' => 'div',
'fullwidth' => 1,
'nowrap' => 0,
'heading' => n2_('Heading layer'),
'title' => '',
'href' => '#',
'href-target' => '_self',
'href-rel' => '',
'split-text-transform-origin' => '50|*|50|*|0',
'split-text-backface-visibility' => 1,
'split-text-animation-in' => '',
'split-text-delay-in' => 0,
'split-text-animation-out' => '',
'split-text-delay-out' => 0,
'class' => ''
);
}
public function upgradeData($data) {
$linkV1 = $data->get('link', '');
if (!empty($linkV1)) {
list($link, $target, $rel) = array_pad((array)Common::parse($linkV1), 3, '');
$data->un_set('link');
if (is_array($link)) {
$data->set('href', implode('', $link));
} else {
$data->set('href', $link);
}
$data->set('href-target', $target);
$data->set('href-rel', $rel);
}
}
public function getFilled($slide, $data) {
$data = parent::getFilled($slide, $data);
$data->set('heading', $slide->fill($data->get('heading', '')));
$data->set('href', $slide->fill($data->get('href', '#|*|')));
return $data;
}
public function prepareExport($export, $data) {
parent::prepareExport($export, $data);
$export->addVisual($data->get('font'));
$export->addVisual($data->get('style'));
$export->addLightbox($data->get('href'));
}
public function prepareImport($import, $data) {
$data = parent::prepareImport($import, $data);
$data->set('font', $import->fixSection($data->get('font')));
$data->set('style', $import->fixSection($data->get('style')));
$data->set('href', $import->fixLightbox($data->get('href')));
return $data;
}
public function globalDefaultItemFontAndStyle($container) {
$table = new ContainerTable($container, $this->getType(), $this->getTitle());
$row1 = $table->createRow($this->getType() . '-1');
new Font($row1, 'item-heading-font', false, $this->fonts['font']['value'], array(
'mode' => 'hover'
));
new Style($row1, 'item-heading-style', false, $this->styles['style']['value'], array(
'mode' => 'heading'
));
}
public function renderFields($container) {
$settings = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-heading', n2_('General'));
new Textarea($settings, 'heading', n2_('Text'), n2_('Heading'), array(
'width' => 314
));
new Select($settings, 'priority', 'Tag', 'div', array(
'options' => array(
'div' => 'div',
'1' => 'H1',
'2' => 'H2',
'3' => 'H3',
'4' => 'H4',
'5' => 'H5',
'6' => 'H6'
)
));
new OnOff($settings, 'fullwidth', n2_('Full width'), 1);
new OnOff($settings, 'nowrap', n2_('No wrap'), 0, array(
'tipLabel' => n2_('No wrap'),
'tipDescription' => n2_('Prevents the text from breaking into more lines')
));
$link = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-heading-link', n2_('Link'));
new Url($link, 'href', n2_('Link'), '', array(
'width' => 248,
'relatedFields' => array(
'item_headinghref-target',
'item_headinghref-rel'
)
));
new LinkTarget($link, 'href-target', n2_('Target window'));
new Text($link, 'href-rel', n2_('Rel'), '', array(
'style' => 'width:195px;',
'tipLabel' => n2_('Rel'),
'tipDescription' => sprintf(n2_('Enter the %1$s rel attribute %2$s that represents the relationship between the current document and the linked document. Multiple rel attributes can be separated with space. E.g. nofollow noopener noreferrer'), '<a href="https://www.w3schools.com/TAGS/att_a_rel.asp" target="_blank">', '</a>')
));
new HiddenFont($settings, 'font', false, '', array(
'mode' => 'hover'
));
new HiddenStyle($settings, 'style', false, '', array(
'mode' => 'heading'
));
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Heading;
use Nextend\Framework\Misc\Base64;
use Nextend\Framework\Sanitize;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\Renderable\Item\AbstractItemFrontend;
class ItemHeadingFrontend extends AbstractItemFrontend {
public function render() {
return $this->getHtml();
}
private function getHtml() {
$owner = $this->layer->getOwner();
$attributes = array();
$font = $owner->addFont($this->data->get('font'), 'hover');
$style = $owner->addStyle($this->data->get('style'), 'heading');
$linkAttributes = array(
'class' => 'n2-ow'
);
if ($this->isEditor) {
$linkAttributes['onclick'] = 'return false;';
}
$title = $this->data->get('title', '');
if (!empty($title)) {
$attributes['title'] = $title;
}
$href = $this->data->get('href', '');
if (!empty($href) && $href != '#') {
$linkAttributes['class'] .= ' ' . $font . $style;
$font = '';
$style = '';
}
$linkAttributes['style'] = "display:" . ($this->data->get('fullwidth', 1) ? 'block' : 'inline-block') . ";";
$strippedHtml = Sanitize::filter_allowed_html($owner->fill($this->data->get('heading', '')));
return $this->heading($this->data->get('priority', 'div'), $attributes + array(
"id" => $this->id,
"class" => $font . $style . " " . $owner->fill($this->data->get('class', '')) . ' n2-ss-item-content n2-ss-text n2-ow',
"style" => "display:" . ($this->data->get('fullwidth', 1) ? 'block' : 'inline-block') . ";" . ($this->data->get('nowrap', 0) ? 'white-space:nowrap;' : '')
), $this->getLink(str_replace("\n", '<br>', $strippedHtml), $linkAttributes));
}
private function heading($type, $attributes, $content) {
if (is_numeric($type) && $type > 0) {
return Html::tag("h{$type}", $attributes, $content);
}
return Html::tag("div", $attributes, $content);
}
public function renderAdminTemplate() {
return $this->getHtml();
}
public function isAuto() {
return !$this->data->get('fullwidth', 1);
}
}

View File

@ -0,0 +1,179 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Image;
use Nextend\Framework\Form\Container\ContainerTable;
use Nextend\Framework\Form\Element\Hidden;
use Nextend\Framework\Form\Element\MixedField;
use Nextend\Framework\Form\Element\OnOff;
use Nextend\Framework\Form\Element\Select\LinkTarget;
use Nextend\Framework\Form\Element\Style;
use Nextend\Framework\Form\Element\Text;
use Nextend\Framework\Form\Element\Text\FieldImage;
use Nextend\Framework\Form\Element\Text\Url;
use Nextend\Framework\Form\Fieldset;
use Nextend\Framework\Parser\Common;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\SmartSlider3\Renderable\Item\AbstractItem;
class ItemImage extends AbstractItem {
protected $ordering = 3;
protected $layerProperties = array("desktopportraitwidth" => "300");
protected $styles = array(
'style' => array(
'defaultName' => 'item-image-style',
'value' => ''
)
);
protected function isBuiltIn() {
return true;
}
public function getType() {
return 'image';
}
public function getTitle() {
return n2_('Image');
}
public function getIcon() {
return 'ssi_32 ssi_32--image';
}
public function createFrontend($id, $itemData, $layer) {
return new ItemImageFrontend($this, $id, $itemData, $layer);
}
public function globalDefaultItemFontAndStyle($container) {
$table = new ContainerTable($container, $this->getType(), $this->getTitle());
$row1 = $table->createRow($this->getType() . '-1');
new Style($row1, 'item-image-style', false, $this->styles['style']['value'], array(
'mode' => 'box'
));
}
public function getValues() {
return parent::getValues() + array(
'image' => '$ss3-frontend$/images/placeholder/image.png',
'alt' => '',
'title' => '',
'href' => '#',
'href-target' => '_self',
'href-rel' => '',
'href-class' => '',
'size' => 'auto|*|auto',
'cssclass' => '',
'image-optimize' => 1
);
}
public function upgradeData($data) {
$linkV1 = $data->get('link', '');
if (!empty($linkV1)) {
list($link, $target, $rel) = array_pad((array)Common::parse($linkV1), 3, '');
$data->un_set('link');
$data->set('href', $link);
$data->set('href-target', $target);
$data->set('href-rel', $rel);
}
}
public function getFilled($slide, $data) {
$data = parent::getFilled($slide, $data);
$data->set('image', $slide->fill($data->get('image', '')));
$data->set('alt', $slide->fill($data->get('alt', '')));
$data->set('title', $slide->fill($data->get('title', '')));
$data->set('href', $slide->fill($data->get('href', '#|*|')));
return $data;
}
public function prepareExport($export, $data) {
parent::prepareExport($export, $data);
$export->addImage($data->get('image'));
$export->addVisual($data->get('style'));
$export->addLightbox($data->get('href'));
}
public function prepareImport($import, $data) {
$data = parent::prepareImport($import, $data);
$data->set('image', $import->fixImage($data->get('image')));
$data->set('style', $import->fixSection($data->get('style')));
$data->set('href', $import->fixLightbox($data->get('href')));
return $data;
}
public function prepareSample($data) {
$data->set('image', ResourceTranslator::toUrl($data->get('image')));
return $data;
}
public function renderFields($container) {
$settings = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-image', n2_('General'));
new FieldImage($settings, 'image', n2_('Image'), '', array(
'relatedAlt' => 'item_imagealt',
'width' => 220
));
$link = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-image-link', n2_('Link'));
new Url($link, 'href', n2_('Link'), '', array(
'style' => 'width:236px;',
'relatedFields' => array(
'item_imagehref-target',
'item_imagehref-rel'
),
'width' => 248
));
new LinkTarget($link, 'href-target', n2_('Target window'));
new Text($link, 'href-rel', n2_('Rel'), '', array(
'style' => 'width:195px;',
'tipLabel' => n2_('Rel'),
'tipDescription' => sprintf(n2_('Enter the %1$s rel attribute %2$s that represents the relationship between the current document and the linked document. Multiple rel attributes can be separated with space. E.g. nofollow noopener noreferrer'), '<a href="https://www.w3schools.com/TAGS/att_a_rel.asp" target="_blank">', '</a>')
));
$size = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-image-misc', n2_('Size'));
$misc = new MixedField($size, 'size', false, 'auto|*|auto');
new Text($misc, 'size-1', n2_('Width'), '', array(
'style' => 'width:60px;',
'tipLabel' => n2_('Width'),
'tipDescription' => sprintf(n2_('Fix width for the %1$s.'), $this->getTitle())
));
new Text($misc, 'size-2', n2_('Height'), '', array(
'style' => 'width:60px;',
'tipLabel' => n2_('Height'),
'tipDescription' => sprintf(n2_('Fix height for the %1$s.'), $this->getTitle())
));
$seo = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-image-seo', n2_('SEO'));
new Text($seo, 'alt', 'SEO - ' . n2_('Alt tag'), '', array(
'style' => 'width:133px;'
));
new Text($seo, 'title', 'SEO - ' . n2_('Title'), '', array(
'style' => 'width:133px;'
));
$dev = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-image-dev', n2_('Advanced'));
new Text($dev, 'href-class', n2_('CSS Class') . ' - ' . n2_('Link'), '', array(
'tipLabel' => n2_('CSS Class'),
'tipDescription' => sprintf(n2_('Class on the %s element.'), '&lt;a&gt;'),
'tipLink' => 'https://smartslider.helpscoutdocs.com/article/1833-image-layer#advanced',
'style' => 'width:133px;'
));
}
}

View File

@ -0,0 +1,87 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Image;
use Nextend\Framework\Parser\Common;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\Renderable\Item\AbstractItemFrontend;
class ItemImageFrontend extends AbstractItemFrontend {
public function render() {
return $this->getHtml();
}
public function renderAdminTemplate() {
return $this->getHtml();
}
private function getHtml() {
$owner = $this->layer->getOwner();
$styles = array();
$linkStyles = array();
$size = (array)Common::parse($this->data->get('size', ''));
for ($i = 0; $i < 2; $i++) {
if (is_numeric($size[$i])) {
$size[$i] = $size[$i] . 'px';
}
}
if (!empty($size[0]) && $size[0] != 'auto') {
$styles[] = 'width:' . $size[0];
if ($this->hasLink() && substr($size[0], -1) == '%') {
$linkStyles[] = 'width:100%';
}
if (empty($size[1]) || $size[1] == 'auto') {
$styles[] = 'height:auto';
}
}
if (!empty($size[1]) && $size[1] != 'auto') {
if (empty($size[0]) || $size[0] == 'auto') {
$styles[] = 'width:auto';
}
$styles[] = 'height:' . $size[1];
}
$imageUrl = $this->data->get('image', '');
if (empty($imageUrl)) {
return '';
}
$image = $owner->fill($this->data->get('image', ''));
$imageAttributes = array(
"id" => $this->id,
"alt" => $owner->fill($this->data->get('alt', '')),
"class" => $owner->fill($this->data->get('cssclass', ''))
);
if (!empty($styles)) {
$imageAttributes['style'] = implode(';', $styles);
}
$linkAttributes = array();
if (!empty($linkStyles)) {
$linkAttributes['style'] = implode(';', $linkStyles);
}
$title = $owner->fill($this->data->get('title', ''));
if (!empty($title)) {
$imageAttributes['title'] = $title;
}
$html = $owner->renderImage($this, $image, $imageAttributes);
$style = $owner->addStyle($this->data->get('style'), 'heading');
return Html::tag("div", array(
"class" => $style . ' n2-ss-item-image-content n2-ss-item-content n2-ow-all'
), $this->getLink($html, $linkAttributes));
}
}

View File

@ -0,0 +1,192 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item;
use Exception;
use Nextend\Framework\Data\Data;
use Nextend\Framework\Pattern\OrderableTrait;
use Nextend\Framework\Pattern\PluggableTrait;
use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\SmartSlider3\BackupSlider\ExportSlider;
use Nextend\SmartSlider3\BackupSlider\ImportSlider;
use Nextend\SmartSlider3\Renderable\AbstractRenderableOwner;
use Nextend\SmartSlider3\Renderable\Component\ComponentLayer;
use Nextend\SmartSlider3\Renderable\Item\Button\ItemButton;
use Nextend\SmartSlider3\Renderable\Item\Heading\ItemHeading;
use Nextend\SmartSlider3\Renderable\Item\Image\ItemImage;
use Nextend\SmartSlider3\Renderable\Item\Missing\ItemMissing;
use Nextend\SmartSlider3\Renderable\Item\Text\ItemText;
use Nextend\SmartSlider3\Renderable\Item\Vimeo\ItemVimeo;
use Nextend\SmartSlider3\Renderable\Item\YouTube\ItemYouTube;
class ItemFactory {
use SingletonTrait, PluggableTrait, OrderableTrait;
public static $i = array();
/** @var AbstractItem[][] */
private static $itemGroups = array();
/**
* @var AbstractItem[]
*/
private static $items = array();
/**
* @return AbstractItem[]
*/
public static function getItems() {
return self::$items;
}
/**
* @param $type
*
* @return AbstractItem
*/
public static function getItem($type) {
return self::$items[$type];
}
/**
* @return AbstractItem[][]
*/
public static function getItemGroups() {
return self::$itemGroups;
}
/**
* @param ComponentLayer $layer
* @param array $itemData
*
* @return AbstractItemFrontend
* @throws Exception
*/
public static function create($layer, $itemData) {
if (!isset($itemData['type'])) {
throw new Exception('Error with itemData: ' . $itemData);
}
$type = $itemData['type'];
if ($type == 'missing') {
$type = $itemData['values']['type'];
}
if (!isset(self::$items[$type])) {
$itemData['values']['type'] = $type;
$type = 'missing';
}
/** @var AbstractItem $factory */
$factory = self::$items[$type];
$elementID = $layer->getOwner()
->getElementID();
if (!isset(self::$i[$elementID])) {
self::$i[$elementID] = 0;
}
self::$i[$elementID]++;
$id = $elementID . 'item' . self::$i[$elementID];
return $factory->createFrontend($id, $itemData['values'], $layer);
}
/**
* @param AbstractRenderableOwner $slide
* @param array $item
*/
public static function getFilled($slide, &$item) {
$type = $item['type'];
if (isset(self::$items[$type])) {
$item['values'] = self::$items[$type]->getFilled($slide, new Data($item['values']))
->toArray();
}
}
/**
* @param ExportSlider $export
* @param $item
*/
public static function prepareExport($export, $item) {
$type = $item['type'];
if (isset(self::$items[$type])) {
self::$items[$type]->prepareExport($export, new Data($item['values']));
}
}
/**
* @param ImportSlider $import
* @param $item
*
* @return mixed
*/
public static function prepareImport($import, $item) {
$type = $item['type'];
if (isset(self::$items[$type])) {
$item['values'] = self::$items[$type]->prepareImport($import, new Data($item['values']))
->toArray();
}
return $item;
}
public static function prepareSample($item) {
$type = $item['type'];
if (isset(self::$items[$type])) {
$item['values'] = self::$items[$type]->prepareSample(new Data($item['values']))
->toArray();
}
return $item;
}
/**
* @param AbstractItem $item
*/
public function addItem($item) {
self::$items[$item->getType()] = $item;
}
protected function init() {
new ItemHeading($this);
new ItemButton($this);
new ItemImage($this);
new ItemText($this);
new ItemVimeo($this);
new ItemYouTube($this);
$this->makePluggable('RenderableItem');
self::uasort(self::$items);
self::$itemGroups[n2_x('Basic', 'Layer group')] = array();
self::$itemGroups[n2_x('Media', 'Layer group')] = array();
foreach (self::$items as $type => $item) {
$group = $item->getGroup();
if (!isset(self::$itemGroups[$group])) {
self::$itemGroups[$group] = array();
}
self::$itemGroups[$group][$type] = $item;
}
new ItemMissing($this);
}
}
ItemFactory::getInstance();

View File

@ -0,0 +1,28 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Missing;
use Nextend\SmartSlider3\Renderable\Item\AbstractItem;
class ItemMissing extends AbstractItem {
public function createFrontend($id, $itemData, $layer) {
return new ItemMissingFrontend($this, $id, $itemData, $layer);
}
public function getTitle() {
return n2_x('Missing', 'Layer');
}
public function getIcon() {
return '';
}
public function getType() {
return 'missing';
}
public function renderFields($container) {
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Missing;
use Nextend\SmartSlider3\Renderable\Item\AbstractItemFrontend;
class ItemMissingFrontend extends AbstractItemFrontend {
public function render() {
return '';
}
protected function renderAdminTemplate() {
return '<div>' . sprintf(n2_('Missing layer type: %s'), $this->data->get('type')) . '</div>';
}
}

View File

@ -0,0 +1,169 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Text;
use Nextend\Framework\Data\Data;
use Nextend\Framework\Form\Container\ContainerTable;
use Nextend\Framework\Form\Element\Font;
use Nextend\Framework\Form\Element\Hidden\HiddenFont;
use Nextend\Framework\Form\Element\Hidden\HiddenStyle;
use Nextend\Framework\Form\Element\OnOff;
use Nextend\Framework\Form\Element\RichTextarea;
use Nextend\Framework\Form\Element\Style;
use Nextend\Framework\Form\Fieldset;
use Nextend\SmartSlider3\Renderable\Item\AbstractItem;
class ItemText extends AbstractItem {
protected $ordering = 2;
protected $layerProperties = array(
"desktopportraitleft" => 0,
"desktopportraittop" => 0,
"desktopportraitwidth" => 400,
"desktopportraitalign" => "left",
"desktopportraitvalign" => "top"
);
protected $fonts = array(
'font' => array(
'defaultName' => 'item-text-font',
'value' => '{"data":[{"color":"ffffffff","size":"14||px","align":"inherit"},{"color":"1890d7ff"},{"color":"1890d7ff"}]}'
)
);
protected $styles = array(
'style' => array(
'defaultName' => 'item-text-style',
'value' => ''
)
);
protected function isBuiltIn() {
return true;
}
public function getType() {
return 'text';
}
public function getTitle() {
return n2_('Text');
}
public function getIcon() {
return 'ssi_32 ssi_32--text';
}
public function createFrontend($id, $itemData, $layer) {
return new ItemTextFrontend($this, $id, $itemData, $layer);
}
public function globalDefaultItemFontAndStyle($container) {
$table = new ContainerTable($container, $this->getType(), $this->getTitle());
$row1 = $table->createRow($this->getType() . '-1');
new Font($row1, 'item-text-font', false, $this->fonts['font']['value'], array(
'mode' => 'paragraph'
));
new Style($row1, 'item-text-style', false, $this->styles['style']['value'], array(
'mode' => 'heading'
));
}
public function getValues() {
return parent::getValues() + array(
'content' => 'Lorem ipsum dolor sit amet, <a href="#">consectetur adipiscing</a> 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.',
'content-tablet-enabled' => 0,
'contenttablet' => '',
'content-mobile-enabled' => 0,
'contentmobile' => ''
);
}
/**
* @param Data $data
*/
public function upgradeData($data) {
if (!$data->has('content-tablet-enabled')) {
if ($data->get('contenttablet', '') != '') {
$data->set('content-tablet-enabled', 1);
}
}
if (!$data->has('content-mobile-enabled')) {
if ($data->get('contentmobile', '') != '') {
$data->set('content-mobile-enabled', 1);
}
}
}
public function getFilled($slide, $data) {
$data = parent::getFilled($slide, $data);
$data->set('content', $slide->fill($data->get('content', '')));
$data->set('contenttablet', $slide->fill($data->get('contenttablet', '')));
$data->set('contentmobile', $slide->fill($data->get('contentmobile', '')));
return $data;
}
public function prepareExport($export, $data) {
parent::prepareExport($export, $data);
$export->addVisual($data->get('font'));
$export->addVisual($data->get('style'));
}
public function prepareImport($import, $data) {
$data = parent::prepareImport($import, $data);
$data->set('font', $import->fixSection($data->get('font')));
$data->set('style', $import->fixSection($data->get('style')));
return $data;
}
public function renderFields($container) {
$settings = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-text', n2_('General'));
new RichTextarea($settings, 'content', n2_('Text'), '', array(
'fieldStyle' => 'height: 120px; width: 314px;resize: vertical;'
));
new HiddenFont($settings, 'font', false, '', array(
'mode' => 'paragraph'
));
new HiddenStyle($settings, 'style', false, '', array(
'mode' => 'heading'
));
new OnOff($settings, 'content-tablet-enabled', n2_('Tablet'), 0, array(
'relatedFieldsOn' => array(
'item_textcontenttablet'
),
'tipLabel' => n2_('Tablet'),
'tipDescription' => n2_('Custom text for tablet')
));
new RichTextarea($settings, 'contenttablet', n2_('Tablet text'), '', array(
'fieldStyle' => 'height: 120px; width: 314px;resize: vertical;'
));
new OnOff($settings, 'content-mobile-enabled', n2_('Mobile'), 0, array(
'relatedFieldsOn' => array(
'item_textcontentmobile'
),
'tipLabel' => n2_('Mobile'),
'tipDescription' => n2_('Custom text for mobile')
));
new RichTextarea($settings, 'contentmobile', n2_('Mobile text'), '', array(
'fieldStyle' => 'height: 120px; width: 314px;resize: vertical;'
));
}
}

View File

@ -0,0 +1,432 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Text;
use Nextend\Framework\Platform\Platform;
use Nextend\Framework\Sanitize;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\Renderable\Item\AbstractItemFrontend;
use function Nextend\Framework\Sanitize;
class ItemTextFrontend extends AbstractItemFrontend {
public function render() {
return $this->getHtml();
}
public function renderAdminTemplate() {
return $this->getHtml();
}
private function getHTML() {
$owner = $this->layer->getOwner();
$font = $owner->addFont($this->data->get('font'), 'paragraph');
$style = $owner->addStyle($this->data->get('style'), 'heading');
$tagName = 'p';
if (Platform::needStrongerCSS()) {
$tagName = 'ss-p';
}
$html = '';
$content = str_replace(array(
'<p>',
'</p>'
), array(
'<' . $tagName . ' class="' . $font . ' ' . $style . ' ">',
'</' . $tagName . '>'
), $this->wpautop(Sanitize::filter_allowed_html($this->closeTags($owner->fill($this->data->get('content', ''))), '<p>')));
$class = '';
$hasMobile = false;
if ($this->data->get('content-mobile-enabled')) {
$hasMobile = true;
$html .= Html::tag('div', array(
'data-hide-desktoplandscape' => 1,
'data-hide-desktopportrait' => 1,
'data-hide-tabletlandscape' => 1,
'data-hide-tabletportrait' => 1
), str_replace(array(
'<p>',
'</p>'
), array(
'<' . $tagName . ' class="' . $font . ' ' . $style . ' ">',
'</' . $tagName . '>'
), $this->wpautop(Sanitize::filter_allowed_html($this->closeTags($owner->fill($this->data->get('contentmobile', ''))), '<p>'))));
}
$hasTablet = false;
if ($this->data->get('content-tablet-enabled')) {
$hasTablet = true;
$attributes = array(
'class' => $class,
'data-hide-desktoplandscape' => 1,
'data-hide-desktopportrait' => 1,
);
if ($hasMobile) {
$attributes['data-hide-mobilelandscape'] = 1;
$attributes['data-hide-mobileportrait'] = 1;
} else {
$hasMobile = true;
}
$html .= Html::tag('div', $attributes, str_replace(array(
'<p>',
'</p>'
), array(
'<' . $tagName . ' class="' . $font . ' ' . $style . '">',
'</' . $tagName . '>'
), $this->wpautop(Sanitize::filter_allowed_html($this->closeTags($owner->fill($this->data->get('contenttablet', '')))), '<p>')));
$class = '';
}
$attributes = array(
'class' => $class
);
if ($hasMobile) {
$attributes['data-hide-mobilelandscape'] = 1;
$attributes['data-hide-mobileportrait'] = 1;
}
if ($hasTablet) {
$attributes['data-hide-tabletlandscape'] = 1;
$attributes['data-hide-tabletportrait'] = 1;
}
$html .= Html::tag('div', $attributes, $content);
return Html::tag('div', array(
'class' => 'n2-ss-item-content n2-ss-text n2-ow-all'
), $html);
}
public function closeTags($html) {
$html = str_replace(array(
'<>',
'</>'
), array(
'',
''
), $html);
// Put all opened tags into an array
preg_match_all('#<([a-z]+)(?: .*)?(?<![/| ])>#iU', $html, $result);
$openedtags = $result[1]; #put all closed tags into an array
preg_match_all('#</([a-z]+)>#iU', $html, $result);
$closedtags = $result[1];
$len_opened = count($openedtags);
# Check if all tags are closed
if (count($closedtags) == $len_opened) {
return $html;
}
$openedtags = array_reverse($openedtags);
# close tags
for ($i = 0; $i < $len_opened; $i++) {
if (!in_array($openedtags[$i], $closedtags)) {
if ($openedtags[$i] != 'br') {
// Ignores <br> tags to avoid unnessary spacing
// at the end of the string
$html .= '</' . $openedtags[$i] . '>';
}
} else {
unset($closedtags[array_search($openedtags[$i], $closedtags)]);
}
}
return $html;
}
private function wpautop($pee, $br = true) {
$pre_tags = array();
if (trim($pee) === '') {
return '';
}
// Just to make things a little easier, pad the end.
$pee = $pee . "\n";
/*
* Pre tags shouldn't be touched by autop.
* Replace pre tags with placeholders and bring them back after autop.
*/
if (strpos($pee, '<pre') !== false) {
$pee_parts = explode('</pre>', $pee);
$last_pee = array_pop($pee_parts);
$pee = '';
$i = 0;
foreach ($pee_parts as $pee_part) {
$start = strpos($pee_part, '<pre');
// Malformed HTML?
if (false === $start) {
$pee .= $pee_part;
continue;
}
$name = "<pre wp-pre-tag-$i></pre>";
$pre_tags[$name] = substr($pee_part, $start) . '</pre>';
$pee .= substr($pee_part, 0, $start) . $name;
$i++;
}
$pee .= $last_pee;
}
// Change multiple <br>'s into two line breaks, which will turn into paragraphs.
$pee = preg_replace('|<br\s*/?>\s*<br\s*/?>|', "\n\n", $pee);
$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)';
// Add a double line break above block-level opening tags.
$pee = preg_replace('!(<' . $allblocks . '[\s/>])!', "\n\n$1", $pee);
// Add a double line break below block-level closing tags.
$pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
// Add a double line break after hr tags, which are self closing.
$pee = preg_replace('!(<hr\s*?/?>)!', "$1\n\n", $pee);
// Standardize newline characters to "\n".
$pee = str_replace(array(
"\r\n",
"\r"
), "\n", $pee);
// Find newlines in all elements and add placeholders.
$pee = self::wp_replace_in_html_tags($pee, array("\n" => ' <!-- wpnl --> '));
// Collapse line breaks before and after <option> elements so they don't get autop'd.
if (strpos($pee, '<option') !== false) {
$pee = preg_replace('|\s*<option|', '<option', $pee);
$pee = preg_replace('|</option>\s*|', '</option>', $pee);
}
/*
* Collapse line breaks inside <object> elements, before <param> and <embed> elements
* so they don't get autop'd.
*/
if (strpos($pee, '</object>') !== false) {
$pee = preg_replace('|(<object[^>]*>)\s*|', '$1', $pee);
$pee = preg_replace('|\s*</object>|', '</object>', $pee);
$pee = preg_replace('%\s*(</?(?:param|embed)[^>]*>)\s*%', '$1', $pee);
}
/*
* Collapse line breaks inside <audio> and <video> elements,
* before and after <source> and <track> elements.
*/
if (strpos($pee, '<source') !== false || strpos($pee, '<track') !== false) {
$pee = preg_replace('%([<\[](?:audio|video)[^>\]]*[>\]])\s*%', '$1', $pee);
$pee = preg_replace('%\s*([<\[]/(?:audio|video)[>\]])%', '$1', $pee);
$pee = preg_replace('%\s*(<(?:source|track)[^>]*>)\s*%', '$1', $pee);
}
// Collapse line breaks before and after <figcaption> elements.
if (strpos($pee, '<figcaption') !== false) {
$pee = preg_replace('|\s*(<figcaption[^>]*>)|', '$1', $pee);
$pee = preg_replace('|</figcaption>\s*|', '</figcaption>', $pee);
}
// Remove more than two contiguous line breaks.
$pee = preg_replace("/\n\n+/", "\n\n", $pee);
// Split up the contents into an array of strings, separated by double line breaks.
$pees = preg_split('/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY);
// Reset $pee prior to rebuilding.
$pee = '';
// Rebuild the content as a string, wrapping every bit with a <p>.
foreach ($pees as $tinkle) {
$pee .= '<p>' . trim($tinkle, "\n") . "</p>\n";
}
// Under certain strange conditions it could create a P of entirely whitespace.
$pee = preg_replace('|<p>\s*</p>|', '', $pee);
// Add a closing <p> inside <div>, <address>, or <form> tag if missing.
$pee = preg_replace('!<p>([^<]+)</(div|address|form)>!', '<p>$1</p></$2>', $pee);
// If an opening or closing block element tag is wrapped in a <p>, unwrap it.
$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', '$1', $pee);
// In some cases <li> may get wrapped in <p>, fix them.
$pee = preg_replace('|<p>(<li.+?)</p>|', '$1', $pee);
// If a <blockquote> is wrapped with a <p>, move it inside the <blockquote>.
$pee = preg_replace('|<p><blockquote([^>]*)>|i', '<blockquote$1><p>', $pee);
$pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
// If an opening or closing block element tag is preceded by an opening <p> tag, remove it.
$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', '$1', $pee);
// If an opening or closing block element tag is followed by a closing <p> tag, remove it.
$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', '$1', $pee);
// Optionally insert line breaks.
if ($br) {
// Replace newlines that shouldn't be touched with a placeholder.
$pee = preg_replace_callback('/<(script|style|svg).*?<\/\\1>/s', array(
$this,
'_autop_newline_preservation_helper'
), $pee);
// Normalize <br>
$pee = str_replace(array(
'<br>',
'<br/>'
), '<br />', $pee);
// Replace any new line characters that aren't preceded by a <br /> with a <br />.
$pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee);
// Replace newline placeholders with newlines.
$pee = str_replace('<WPPreserveNewline />', "\n", $pee);
}
// If a <br /> tag is after an opening or closing block tag, remove it.
$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', '$1', $pee);
// If a <br /> tag is before a subset of opening or closing block tags, remove it.
$pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
$pee = preg_replace("|\n</p>$|", '</p>', $pee);
// Replace placeholder <pre> tags with their original content.
if (!empty($pre_tags)) {
$pee = str_replace(array_keys($pre_tags), array_values($pre_tags), $pee);
}
// Restore newlines in all elements.
if (false !== strpos($pee, '<!-- wpnl -->')) {
$pee = str_replace(array(
' <!-- wpnl --> ',
'<!-- wpnl -->'
), "\n", $pee);
}
return $pee;
}
/**
* Replace characters or phrases within HTML elements only.
*
* @param string $haystack The text which has to be formatted.
* @param array $replace_pairs In the form array('from' => 'to', ...).
*
* @return string The formatted text.
* @since 4.2.3
*
*/
private function wp_replace_in_html_tags($haystack, $replace_pairs) {
// Find all elements.
$textarr = self::wp_html_split($haystack);
$changed = false;
// Optimize when searching for one item.
if (1 === count($replace_pairs)) {
// Extract $needle and $replace.
foreach ($replace_pairs as $needle => $replace) {
}
// Loop through delimiters (elements) only.
for ($i = 1, $c = count($textarr); $i < $c; $i += 2) {
if (false !== strpos($textarr[$i], $needle)) {
$textarr[$i] = str_replace($needle, $replace, $textarr[$i]);
$changed = true;
}
}
} else {
// Extract all $needles.
$needles = array_keys($replace_pairs);
// Loop through delimiters (elements) only.
for ($i = 1, $c = count($textarr); $i < $c; $i += 2) {
foreach ($needles as $needle) {
if (false !== strpos($textarr[$i], $needle)) {
$textarr[$i] = strtr($textarr[$i], $replace_pairs);
$changed = true;
// After one strtr() break out of the foreach loop and look at next element.
break;
}
}
}
}
if ($changed) {
$haystack = implode($textarr);
}
return $haystack;
}
/**
* Separate HTML elements and comments from the text.
*
* @param string $input The text which has to be formatted.
*
* @return string[] Array of the formatted text.
* @since 4.2.4
*
*/
private function wp_html_split($input) {
return preg_split(self::get_html_split_regex(), $input, -1, PREG_SPLIT_DELIM_CAPTURE);
}
/**
* Retrieve the regular expression for an HTML element.
*
* @return string The regular expression
* @since 4.4.0
*
*/
private function get_html_split_regex() {
static $regex;
if (!isset($regex)) {
// phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- don't remove regex indentation
$comments = '!' // Start of comment, after the <.
. '(?:' // Unroll the loop: Consume everything until --> is found.
. '-(?!->)' // Dash not followed by end of comment.
. '[^\-]*+' // Consume non-dashes.
. ')*+' // Loop possessively.
. '(?:-->)?'; // End of comment. If not found, match all input.
$cdata = '!\[CDATA\[' // Start of comment, after the <.
. '[^\]]*+' // Consume non-].
. '(?:' // Unroll the loop: Consume everything until ]]> is found.
. '](?!]>)' // One ] not followed by end of comment.
. '[^\]]*+' // Consume non-].
. ')*+' // Loop possessively.
. '(?:]]>)?'; // End of comment. If not found, match all input.
$escaped = '(?=' // Is the element escaped?
. '!--' . '|' . '!\[CDATA\[' . ')' . '(?(?=!-)' // If yes, which type?
. $comments . '|' . $cdata . ')';
$regex = '/(' // Capture the entire match.
. '<' // Find start of element.
. '(?' // Conditional expression follows.
. $escaped // Find end of escaped element.
. '|' // ...else...
. '[^>]*>?' // Find end of normal element.
. ')' . ')/';
// phpcs:enable
}
return $regex;
}
public function _autop_newline_preservation_helper($matches) {
return str_replace("\n", '<WPPreserveNewline />', $matches[0]);
}
}

View File

@ -0,0 +1,254 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Vimeo;
use Nextend\Framework\Form\Element\Message\Notice;
use Nextend\Framework\Form\Element\Message\Warning;
use Nextend\Framework\Form\Element\OnOff;
use Nextend\Framework\Form\Element\Select;
use Nextend\Framework\Form\Element\Text;
use Nextend\Framework\Form\Element\Text\Color;
use Nextend\Framework\Form\Element\Text\FieldImage;
use Nextend\Framework\Form\Element\Text\Number;
use Nextend\Framework\Form\Fieldset;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\SmartSlider3\Renderable\Item\AbstractItem;
class ItemVimeo extends AbstractItem {
protected $ordering = 20;
protected $layerProperties = array(
"desktopportraitwidth" => 300,
"desktopportraitheight" => 'auto'
);
protected function isBuiltIn() {
return true;
}
public function getType() {
return 'vimeo';
}
public function getTitle() {
return 'Vimeo';
}
public function getIcon() {
return 'ssi_32 ssi_32--vimeo';
}
public function getGroup() {
return n2_x('Media', 'Layer group');
}
/**
* @param Data $data
*/
public function upgradeData($data) {
if (!$data->has('aspect-ratio')) {
$data->set('aspect-ratio', 'fill');
}
}
public function createFrontend($id, $itemData, $layer) {
return new ItemVimeoFrontend($this, $id, $itemData, $layer);
}
public function getValues() {
return parent::getValues() + array(
'vimeourl' => '75251217',
'privateid' => '',
'image' => '$ss3-frontend$/images/placeholder/video.png',
'aspect-ratio' => '16:9',
'autoplay' => 0,
'ended' => '',
'title' => 1,
'byline' => 1,
'portrait' => 0,
'color' => '00adef',
'loop' => 0,
'start' => 0,
'playbutton' => 1,
'playbuttonwidth' => 48,
'playbuttonheight' => 48,
'playbuttonimage' => '',
'scroll-pause' => 'partly-visible',
);
}
public function getFilled($slide, $data) {
$data = parent::getFilled($slide, $data);
$data->set('image', $slide->fill($data->get('image', '')));
$data->set('vimeourl', $slide->fill($data->get('vimeourl', '')));
return $data;
}
public function prepareExport($export, $data) {
parent::prepareExport($export, $data);
$export->addImage($data->get('image'));
$export->addImage($data->get('playbuttonimage'));
}
public function prepareImport($import, $data) {
$data = parent::prepareImport($import, $data);
$data->set('image', $import->fixImage($data->get('image')));
$data->set('playbuttonimage', $import->fixImage($data->get('playbuttonimage')));
return $data;
}
public function prepareSample($data) {
$data->set('image', ResourceTranslator::toUrl($data->get('image')));
return $data;
}
public function renderFields($container) {
$settings = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-vimeo', n2_('General'));
new Text($settings, 'vimeourl', n2_('Vimeo url or Video ID'), '', array(
'style' => 'width:302px;'
));
new FieldImage($settings, 'image', n2_('Cover image'), '', array(
'width' => 220
));
new Select($settings, 'aspect-ratio', n2_('Aspect ratio'), '16:9', array(
'options' => array(
'16:9' => '16:9',
'16:10' => '16:10',
'4:3' => '4:3',
'custom' => n2_('Custom'),
'fill' => n2_('Fill layer height')
),
'relatedValueFields' => array(
array(
'values' => array(
'custom'
),
'field' => array(
'item_vimeoaspect-ratio-width',
'item_vimeoaspect-ratio-height'
)
),
array(
'values' => array(
'fill'
),
'field' => array(
'item_vimeoaspect-ratio-notice'
)
)
)
));
new Text\Number($settings, 'aspect-ratio-width', n2_('Width'), '16', array(
'wide' => 4,
'min' => 1
));
new Text\Number($settings, 'aspect-ratio-height', n2_('Height'), '9', array(
'wide' => 4,
'min' => 1
));
new Notice($settings, 'aspect-ratio-notice', n2_('Fill layer height'), n2_('Set on Style tab.'));
$misc = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-vimeo-misc', n2_('Video settings'));
new Warning($misc, 'slide-background-notice', sprintf(n2_('Video autoplaying has a lot of limitations made by browsers. %1$sLearn about them.%2$s'), '<a href="https://smartslider.helpscoutdocs.com/article/1919-video-autoplay-handling" target="_blank">', '</a>'));
new OnOff($misc, 'autoplay', n2_('Autoplay'), 0, array(
'relatedFieldsOn' => array(
'item_vimeoautoplay-notice'
)
));
new Select($misc, 'ended', n2_('When ended'), '', array(
'options' => array(
'' => n2_('Do nothing'),
'next' => n2_('Go to next slide')
)
));
new Number($misc, 'start', n2_('Start time'), 0, array(
'min' => 0,
'unit' => 'sec',
'wide' => 5
));
new Select($misc, 'volume', n2_('Volume'), 1, array(
'options' => array(
'0' => n2_('Mute'),
'0.25' => '25%',
'0.5' => '50%',
'0.75' => '75%',
'1' => '100%',
'-1' => n2_('Default')
)
));
new Select($misc, 'scroll-pause', n2_('Pause on scroll'), 'partly-visible', array(
'options' => array(
'' => n2_('Never'),
'partly-visible' => n2_('When partly visible'),
'not-visible' => n2_('When not visible'),
),
'tipLabel' => n2_('Pause on scroll'),
'tipDescription' => n2_('You can pause the video when the visitor scrolls away from the slider')
));
new OnOff($misc, 'reset', n2_('Restart on slide change'), 0, array(
'tipLabel' => n2_('Restart on slide change'),
'tipDescription' => n2_('Starts the video from the beginning when the slide is viewed again.')
));
$display = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-youtube-display', n2_('Display'));
new Color($display, 'color', n2_('Color'), 0, array(
'tipLabel' => n2_('Color'),
'tipDescription' => n2_('Only works on videos of Vimeo Pro users.')
));
new OnOff($display, 'background', n2_('Remove controls'), 0, array(
'tipLabel' => n2_('Remove controls'),
'tipDescription' => n2_('Removes the controls of the video, but it only works on videos of Vimeo Pro users.')
));
new OnOff($display, 'title', n2_('Title'), 1, array(
'tipLabel' => n2_('Title'),
'tipDescription' => n2_('Hides the title of the video, but only if video owner allows it.')
));
new OnOff($display, 'byline', n2_('Users byline'), 1, array(
'tipLabel' => n2_('Users byline'),
'tipDescription' => n2_('Hides the user\'s byline of the video, but only if video owner allows it.')
));
new OnOff($display, 'portrait', n2_('Portrait'), 1, array(
'tipLabel' => n2_('Portrait'),
'tipDescription' => n2_('Hides the profile image of the author, but only if video owner allows it. ')
));
new Select($display, 'quality', n2_('Quality'), '-1', array(
'options' => array(
'270p' => '270p',
'360p' => '360p',
'720p' => '720p',
'1080p' => '1080p',
'-1' => n2_('Default')
),
'tipLabel' => n2_('Quality'),
'tipDescription' => n2_('Only works on videos of Vimeo Pro users.')
));
new Text($display, 'iframe-title', n2_('Iframe title'));
}
}

View File

@ -0,0 +1,156 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\Vimeo;
use Nextend\Framework\FastImageSize\FastImageSize;
use Nextend\Framework\Image\Image;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\Renderable\Item\AbstractItemFrontend;
use Nextend\SmartSlider3\Settings;
class ItemVimeoFrontend extends AbstractItemFrontend {
public function render() {
$owner = $this->layer->getOwner();
$url = $owner->fill($this->data->get("vimeourl"));
$urlParts = explode('?', $url);
$privateID = '';
if (preg_match('/https?:\/\/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)/', $urlParts[0], $matches)) {
$videoID = $matches[3];
$privateID = str_replace($matches, '', $urlParts[0]);
} else {
$videoID = preg_replace('/\D/', '', $urlParts[0]);
}
$this->data->set("vimeocode", $videoID);
if (isset($urlParts[1])) {
$parsedUrl = parse_url('https://player.vimeo.com/video/' . $videoID . '?' . $urlParts[1]);
parse_str($parsedUrl['query'], $query);
if (isset($query['h'])) {
$privateID = $query['h'];
}
}
$this->data->set("privateid", $privateID);
$hasImage = 0;
$coverImageUrl = $owner->fill($this->data->get('image'));
$coverImage = '';
if (!empty($coverImageUrl)) {
$coverImageElement = $owner->renderImage($this, $coverImageUrl, array(
'class' => 'n2_ss_video_cover',
'alt' => n2_('Play')
), array(
'class' => 'n2-ow-all'
));
$hasImage = 1;
$playImage = '';
if ($this->data->get('playbutton', 1) == 1) {
$playWidth = intval($this->data->get('playbuttonwidth', '48'));
$playHeight = intval($this->data->get('playbuttonheight', '48'));
if ($playWidth > 0 && $playHeight > 0) {
$attributes = Html::addExcludeLazyLoadAttributes(array(
'style' => '',
'class' => 'n2_ss_video_play_btn'
));
if ($playWidth != 48) {
$attributes['style'] .= 'width:' . $playWidth . 'px;';
}
if ($playHeight != 48) {
$attributes['style'] .= 'height:' . $playHeight . 'px;';
}
$playButtonImage = $this->data->get('playbuttonimage', '');
if (!empty($playButtonImage)) {
$image = $this->data->get('playbuttonimage', '');
FastImageSize::initAttributes($image, $attributes);
$src = ResourceTranslator::toUrl($image);
} else {
$image = '$ss3-frontend$/images/play.svg';
FastImageSize::initAttributes($image, $attributes);
$src = Image::SVGToBase64($image);
}
$playImage = Html::image($src, 'Play', $attributes);
}
}
$coverImage = Html::tag('div', array(
'class' => 'n2_ss_video_player__cover',
'data-force-pointer' => ''
), $coverImageElement . $playImage);
}
$this->data->set('privacy-enhanced', intval(Settings::get('youtube-privacy-enhanced', 0)));
$owner->addScript('new _N2.FrontendItemVimeo(this, "' . $this->id . '", "' . $owner->getElementID() . '", ' . $this->data->toJSON() . ', ' . $hasImage . ', ' . $owner->fill($this->data->get('start', '0')) . ');');
$aspectRatio = $this->data->get('aspect-ratio', '16:9');
$style = '';
if ($aspectRatio == 'custom') {
$style = 'style="padding-top:' . ($this->data->get('aspect-ratio-height', '9') / $this->data->get('aspect-ratio-width', '16') * 100) . '%"';
}
return Html::tag('div', array(
'id' => $this->id,
'class' => 'n2_ss_video_player n2-ss-item-content n2-ow-all',
'data-aspect-ratio' => $aspectRatio
), '<div class="n2_ss_video_player__placeholder" ' . $style . '></div>' . $coverImage);
}
public function renderAdminTemplate() {
$aspectRatio = $this->data->get('aspect-ratio', '16:9');
$owner = $this->layer->getOwner();
$style = '';
if ($aspectRatio == 'custom') {
$style = 'style="padding-top:' . ($this->data->get('aspect-ratio-height', '9') / $this->data->get('aspect-ratio-width', '16') * 100) . '%"';
}
$playButtonImage = $this->data->get('playbuttonimage', '');
if (!empty($playButtonImage)) {
$playButtonImage = ResourceTranslator::toUrl($playButtonImage);
} else {
$playButtonImage = Image::SVGToBase64('$ss3-frontend$/images/play.svg');
}
$playButtonStyle = '';
$playButtonWidth = intval($this->data->get('playbuttonwidth', '48'));
$playButtonHeight = intval($this->data->get('playbuttonheight', '48'));
if ($playButtonWidth > 0) {
$playButtonStyle .= 'width:' . $playButtonWidth . 'px;';
}
if ($playButtonHeight > 0) {
$playButtonStyle .= 'height:' . $playButtonHeight . 'px;';
}
$playButton = Html::image($playButtonImage, n2_('Play'), Html::addExcludeLazyLoadAttributes(array(
'class' => 'n2_ss_video_play_btn',
'style' => $playButtonStyle
)));
return Html::tag('div', array(
"class" => 'n2_ss_video_player n2-ow-all',
'data-aspect-ratio' => $aspectRatio,
"style" => 'background: URL(' . ResourceTranslator::toUrl($owner->fill($this->data->getIfEmpty('image', '$ss3-frontend$/images/placeholder/video.png'))) . ') no-repeat 50% 50%; background-size: cover;'
), '<div class="n2_ss_video_player__placeholder" ' . $style . '></div>' . '<div class="n2_ss_video_player__cover">' . $playButton . '</div>');
}
}

View File

@ -0,0 +1,244 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\YouTube;
use Nextend\Framework\Data\Data;
use Nextend\Framework\Form\Element\Message\Notice;
use Nextend\Framework\Form\Element\Message\Warning;
use Nextend\Framework\Form\Element\OnOff;
use Nextend\Framework\Form\Element\Select;
use Nextend\Framework\Form\Element\Text;
use Nextend\Framework\Form\Element\Text\FieldImage;
use Nextend\Framework\Form\Element\Text\Number;
use Nextend\Framework\Form\Fieldset;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\SmartSlider3\Renderable\Item\AbstractItem;
class ItemYouTube extends AbstractItem {
protected $ordering = 20;
protected $layerProperties = array(
"desktopportraitwidth" => 300,
"desktopportraitheight" => 'auto'
);
protected function isBuiltIn() {
return true;
}
public function getType() {
return 'youtube';
}
public function getTitle() {
return 'YouTube';
}
public function getIcon() {
return 'ssi_32 ssi_32--youtube';
}
public function getGroup() {
return n2_x('Media', 'Layer group');
}
/**
* @param Data $data
*/
public function upgradeData($data) {
if (!$data->has('aspect-ratio')) {
$data->set('aspect-ratio', 'fill');
}
}
public function createFrontend($id, $itemData, $layer) {
return new ItemYouTubeFrontend($this, $id, $itemData, $layer);
}
public function getValues() {
return parent::getValues() + array(
'code' => 'qesNtYIBDfs',
'aspect-ratio' => '16:9',
'youtubeurl' => 'https://www.youtube.com/watch?v=3PPtkRU7D74',
'image' => '$ss3-frontend$/images/placeholder/video.png',
'autoplay' => 0,
'ended' => '',
'controls' => 1,
'defaultimage' => 'hqdefault',
'related' => '1',
'center' => 0,
'loop' => 0,
'modestbranding' => 1,
'reset' => 0,
'start' => '0',
'playbutton' => 1,
'playbuttonwidth' => 48,
'playbuttonheight' => 48,
'playbuttonimage' => '',
'scroll-pause' => 'partly-visible',
);
}
public function getFilled($slide, $data) {
$data = parent::getFilled($slide, $data);
$data->set('image', $slide->fill($data->get('image', '')));
$data->set('youtubeurl', $slide->fill($data->get('youtubeurl', '')));
return $data;
}
public function prepareExport($export, $data) {
parent::prepareExport($export, $data);
$export->addImage($data->get('image'));
$export->addImage($data->get('playbuttonimage'));
}
public function prepareImport($import, $data) {
$data = parent::prepareImport($import, $data);
$data->set('image', $import->fixImage($data->get('image')));
$data->set('playbuttonimage', $import->fixImage($data->get('playbuttonimage')));
return $data;
}
public function prepareSample($data) {
$data->set('image', ResourceTranslator::toUrl($data->get('image')));
return $data;
}
public function renderFields($container) {
$settings = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-youtube', n2_('General'));
new Text($settings, 'youtubeurl', n2_('YouTube URL or Video ID'), '', array(
'style' => 'width:302px;'
));
new FieldImage($settings, 'image', n2_('Cover image'), '', array(
'width' => 220
));
new Select($settings, 'aspect-ratio', n2_('Aspect ratio'), '16:9', array(
'options' => array(
'16:9' => '16:9',
'16:10' => '16:10',
'4:3' => '4:3',
'custom' => n2_('Custom'),
'fill' => n2_('Fill layer height')
),
'relatedValueFields' => array(
array(
'values' => array(
'custom'
),
'field' => array(
'item_youtubeaspect-ratio-width',
'item_youtubeaspect-ratio-height'
)
),
array(
'values' => array(
'fill'
),
'field' => array(
'item_youtubeaspect-ratio-notice'
)
)
)
));
new Text\Number($settings, 'aspect-ratio-width', n2_('Width'), '16', array(
'wide' => 4,
'min' => 1
));
new Text\Number($settings, 'aspect-ratio-height', n2_('Height'), '9', array(
'wide' => 4,
'min' => 1
));
new Notice($settings, 'aspect-ratio-notice', n2_('Fill layer height'), n2_('Set on Style tab.'));
$misc = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-youtube-misc', n2_('Video settings'));
new Warning($misc, 'slide-background-notice', sprintf(n2_('Video autoplaying has a lot of limitations made by browsers. %1$sLearn about them.%2$s'), '<a href="https://smartslider.helpscoutdocs.com/article/1919-video-autoplay-handling" target="_blank">', '</a>'));
new OnOff($misc, 'autoplay', n2_('Autoplay'), 0, array(
'relatedFieldsOn' => array(
'item_youtubeautoplay-notice'
)
));
new Select($misc, 'ended', n2_('When ended'), '', array(
'options' => array(
'' => n2_('Do nothing'),
'next' => n2_('Go to next slide')
)
));
new Number($misc, 'start', n2_('Start time'), 0, array(
'min' => 0,
'unit' => 'sec',
'wide' => 5
));
new Number($misc, 'end', n2_('End time'), 0, array(
'min' => 0,
'unit' => 'sec',
'wide' => 5
));
new Select($misc, 'volume', n2_('Volume'), 1, array(
'options' => array(
'0' => n2_('Mute'),
'0.25' => '25%',
'0.5' => '50%',
'0.75' => '75%',
'1' => '100%',
'-1' => n2_('Default')
)
));
new Select($misc, 'scroll-pause', n2_('Pause on scroll'), 'partly-visible', array(
'options' => array(
'' => n2_('Never'),
'partly-visible' => n2_('When partly visible'),
'not-visible' => n2_('When not visible'),
),
'tipLabel' => n2_('Pause on scroll'),
'tipDescription' => n2_('You can pause the video when the visitor scrolls away from the slider')
));
new OnOff($misc, 'loop', n2_x('Loop', 'Video/Audio play'), 0, array(
'relatedFieldsOff' => array(
'item_youtubeended'
)
));
new OnOff($misc, 'reset', n2_('Restart on slide change'), 0, array(
'tipLabel' => n2_('Restart on slide change'),
'tipDescription' => n2_('Starts the video from the beginning when the slide is viewed again.')
));
$display = new Fieldset\LayerWindow\FieldsetLayerWindow($container, 'item-youtube-display', n2_('Display'));
new OnOff($display, 'controls', n2_('Controls'), 1);
new OnOff($display, 'center', n2_('Centered'), 0, array(
'tipLabel' => n2_('Centered'),
'tipDescription' => n2_('Scales up and crops the video to cover the whole layer.'),
'tipLink' => 'https://smartslider.helpscoutdocs.com/article/1846-youtube-layer#centered'
));
new Select($display, 'related', n2_('Show related videos'), 1, array(
'options' => array(
'0' => n2_('Anywhere'),
'1' => n2_('Same channel')
),
'tipLabel' => n2_('Show related videos'),
'tipDescription' => n2_('YouTube no longer allows hiding the related videos at the end of the video. This setting defines whether the videos should come from the same channel as the video that was just played or from any other channel.'),
'tipLink' => 'https://smartslider.helpscoutdocs.com/article/1846-youtube-layer#show-related-videos',
));
}
}

View File

@ -0,0 +1,186 @@
<?php
namespace Nextend\SmartSlider3\Renderable\Item\YouTube;
use Nextend\Framework\Data\Data;
use Nextend\Framework\FastImageSize\FastImageSize;
use Nextend\Framework\Image\Image;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
use Nextend\Framework\View\Html;
use Nextend\SmartSlider3\Renderable\Item\AbstractItemFrontend;
use Nextend\SmartSlider3\Settings;
class ItemYouTubeFrontend extends AbstractItemFrontend {
public function render() {
$owner = $this->layer->getOwner();
/**
* @var Data
*/
$this->data->fillDefault(array(
'image' => '',
'aspect-ratio' => '16:9',
'start' => 0,
'volume' => -1,
'autoplay' => 0,
'ended' => '',
'controls' => 1,
'center' => 0,
'loop' => 0,
'reset' => 0,
'related' => 1,
));
$aspectRatio = $this->data->get('aspect-ratio', '16:9');
if ($aspectRatio != 'fill') {
$this->data->set('center', 0);
}
$rawYTUrl = $owner->fill($this->data->get('youtubeurl', ''));
$url_parts = parse_url($rawYTUrl);
if (!empty($url_parts['query'])) {
parse_str($url_parts['query'], $query);
if (isset($query['v'])) {
unset($query['v']);
}
$this->data->set("query", $query);
}
$youTubeUrl = $this->parseYoutubeUrl($rawYTUrl);
$start = $owner->fill($this->data->get('start', ''));
$this->data->set("youtubecode", $youTubeUrl);
$this->data->set("start", $start);
$end = $owner->fill($this->data->get('end', ''));
$this->data->set("youtubecode", $youTubeUrl);
$this->data->set("end", $end);
$hasImage = 0;
$coverImageUrl = $owner->fill($this->data->get('image'));
$coverImage = '';
if (!empty($coverImageUrl)) {
$coverImageElement = $owner->renderImage($this, $coverImageUrl, array(
'class' => 'n2_ss_video_cover',
'alt' => n2_('Play')
), array(
'class' => 'n2-ow-all'
));
$hasImage = 1;
$playImage = '';
if ($this->data->get('playbutton', 1) == 1) {
$playWidth = intval($this->data->get('playbuttonwidth', '48'));
$playHeight = intval($this->data->get('playbuttonheight', '48'));
if ($playWidth > 0 && $playHeight > 0) {
$attributes = Html::addExcludeLazyLoadAttributes(array(
'style' => '',
'class' => 'n2_ss_video_play_btn'
));
if ($playWidth != 48) {
$attributes['style'] .= 'width:' . $playWidth . 'px;';
}
if ($playHeight != 48) {
$attributes['style'] .= 'height:' . $playHeight . 'px;';
}
$playButtonImage = $this->data->get('playbuttonimage', '');
if (!empty($playButtonImage)) {
$image = $this->data->get('playbuttonimage', '');
FastImageSize::initAttributes($image, $attributes);
$src = ResourceTranslator::toUrl($image);
} else {
$image = '$ss3-frontend$/images/play.svg';
FastImageSize::initAttributes($image, $attributes);
$src = Image::SVGToBase64($image);
}
$playImage = Html::image($src, 'Play', $attributes);
}
}
$coverImage = Html::tag('div', array(
'class' => 'n2_ss_video_player__cover',
'data-force-pointer' => ''
), $coverImageElement . $playImage);
}
$this->data->set('privacy-enhanced', intval(Settings::get('youtube-privacy-enhanced', 0)));
$owner->addScript('new _N2.FrontendItemYouTube(this, "' . $this->id . '", ' . $this->data->toJSON() . ', ' . $hasImage . ');');
$style = '';
if ($aspectRatio == 'custom') {
$style = 'style="padding-top:' . ($this->data->get('aspect-ratio-height', '9') / $this->data->get('aspect-ratio-width', '16') * 100) . '%"';
}
return Html::tag('div', array(
'id' => $this->id,
'class' => 'n2_ss_video_player n2-ss-item-content n2-ow-all',
'data-aspect-ratio' => $aspectRatio
), '<div class="n2_ss_video_player__placeholder" ' . $style . '></div>' . Html::tag('div', array(
'id' => $this->id . '-frame',
), '') . $coverImage);
}
public function renderAdminTemplate() {
$aspectRatio = $this->data->get('aspect-ratio', '16:9');
$style = '';
if ($aspectRatio == 'custom') {
$style = 'style="padding-top:' . ($this->data->get('aspect-ratio-height', '9') / $this->data->get('aspect-ratio-width', '16') * 100) . '%"';
}
$image = $this->layer->getOwner()
->fill($this->data->get('image'));
$this->data->set('image', $image);
$playButtonImage = $this->data->get('playbuttonimage', '');
if (!empty($playButtonImage)) {
$playButtonImage = ResourceTranslator::toUrl($playButtonImage);
} else {
$playButtonImage = Image::SVGToBase64('$ss3-frontend$/images/play.svg');
}
$playButtonStyle = '';
$playButtonWidth = intval($this->data->get('playbuttonwidth', '48'));
$playButtonHeight = intval($this->data->get('playbuttonheight', '48'));
if ($playButtonWidth > 0) {
$playButtonStyle .= 'width:' . $playButtonWidth . 'px;';
}
if ($playButtonHeight > 0) {
$playButtonStyle .= 'height:' . $playButtonWidth . 'px;';
}
$playButton = Html::image($playButtonImage, n2_('Play'), Html::addExcludeLazyLoadAttributes(array(
'class' => 'n2_ss_video_play_btn',
'style' => $playButtonStyle
)));
return Html::tag('div', array(
'class' => 'n2_ss_video_player n2-ow-all',
'data-aspect-ratio' => $aspectRatio,
"style" => 'background: URL(' . ResourceTranslator::toUrl($this->data->getIfEmpty('image', '$ss3-frontend$/images/placeholder/video.png')) . ') no-repeat 50% 50%; background-size: cover;'
), '<div class="n2_ss_video_player__placeholder" ' . $style . '></div>' . ($this->data->get('playbutton', 1) ? '<div class="n2_ss_video_player__cover">' . $playButton . '</div>' : ''));
}
private function parseYoutubeUrl($youTubeUrl) {
preg_match('#^(?:https?://)?(?:www\.)?(?:youtu\.be/|youtube(?:-nocookie)?\.com(?:/embed/|/shorts/|/v/|/watch\?v=|/watch\?.+&v=))([\w-]{11})(?:.+)?$#x', $youTubeUrl, $matches);
if ($matches && isset($matches[1]) && strlen($matches[1]) == 11) {
return $matches[1];
}
return $youTubeUrl;
}
}