IMPROVEMENT: Video slides

This commit is contained in:
Tony Air 2019-08-27 22:25:05 +07:00
parent e6972464de
commit b34f9c58cc
20 changed files with 303 additions and 59 deletions

View File

@ -1,15 +1,10 @@
--- ---
Name: webapp Name: webapp
--- ---
SilverStripe\Core\Manifest\ModuleManifest: SilverStripe\Core\Manifest\ModuleManifest:
project: app project: app
SilverStripe\View\SSViewer:
source_file_comments: true
themes:
- '$public'
- '$default'
Page: Page:
default_container_class: 'container' default_container_class: 'container'

View File

@ -11,15 +11,21 @@ SilverStripe\Blog\Model\BlogPost:
extensions: extensions:
- Site\Extensions\BlogPostExtension - Site\Extensions\BlogPostExtension
Sheadawson\Linkable\Models\EmbeddedObject:
extensions:
- Site\Extensions\EmbeddedObjectExtension
Dynamic\FlexSlider\Model\SlideImage: Dynamic\FlexSlider\Model\SlideImage:
extensions: extensions:
- Site\Extensions\SlideImageExtension - Site\Extensions\SlideImageExtension
SilverStripe\Core\Injector\Injector: SilverStripe\Core\Injector\Injector:
SilverStripe\UserForms\Model\UserDefinedForm: SilverStripe\UserForms\Model\UserDefinedForm:
class: Site\Extensions\CMSMain_HiddenClass class: Site\Extensions\CMSMain_HiddenClass
SilverStripe\Security\MemberAuthenticator\LostPasswordHandler: SilverStripe\Security\MemberAuthenticator\LostPasswordHandler:
class: Site\Extensions\LostPasswordHandlerExtension class: Site\Extensions\LostPasswordHandlerExtension
Sheadawson\Linkable\Forms\EmbeddedObjectField:
class: Site\Extensions\EmbedObjectField
# User Forms # User Forms
SilverStripe\UserForms\Form\UserForm: SilverStripe\UserForms\Form\UserForm:

9
app/_config/themes.yml Normal file
View File

@ -0,0 +1,9 @@
---
Name: webapp-themes
---
SilverStripe\View\SSViewer:
source_file_comments: true
themes:
- '$public'
- '$default'

View File

@ -53,6 +53,37 @@ const CarouselUI = (($) => {
// init carousel // init carousel
$e.carousel(); $e.carousel();
const $youtubeSlides = $e.find('iframe[src^="https://www.youtube.com/embed/"]');
$e.on('slide.bs.carousel', () => {
if ($youtubeSlides.length) {
$youtubeSlides.each((i, e) => {
const $e = $(e);
try {
$e.data('player', new YT.Player(e, {
events: {
'onReady': () => {
$e.data('player').pauseVideo();
}
}
}));
$e.data('player').pauseVideo();
} catch (e) {}
});
}
});
$e.find('.carousel-control-prev').on('click', (e) => {
e.preventDefault();
$e.carousel('prev');
});
$e.find('.carousel-control-next').on('click', (e) => {
e.preventDefault();
$e.carousel('next');
});
// init touch swipes // init touch swipes
$e.hammer().bind('swipeleft', (event) => { $e.hammer().bind('swipeleft', (event) => {
$(event.target).carousel('next'); $(event.target).carousel('next');
@ -70,7 +101,7 @@ const CarouselUI = (($) => {
$(event.target).carousel('prev'); $(event.target).carousel('prev');
}); });
$e.hammer().bind('tap', (event) => { $e.find('.carousel-item').hammer().bind('tap', (event) => {
$(event.target).carousel('next'); $(event.target).carousel('next');
}); });
}); });

View File

@ -82,7 +82,7 @@ const FormValidateField = (($) => {
isHtml(str) { isHtml(str) {
const doc = new DOMParser().parseFromString(str, "text/html"); const doc = new DOMParser().parseFromString(str, "text/html");
return Array.from(doc.body.childNodes).some(node => node.nodeType === 1); return Array.from(doc.body.childNodes).some((node) => node.nodeType === 1);
} }
valideURL(str) { valideURL(str) {

View File

@ -246,6 +246,11 @@ const MainUI = (($) => {
if (W.URLDetails['hash'].indexOf('printpage') > -1) { if (W.URLDetails['hash'].indexOf('printpage') > -1) {
W.print(); W.print();
} }
// load youtube API
if ($('iframe[src^="https://www.youtube.com/embed/"]').length) {
$Body.append('<script src="https://www.youtube.com/iframe_api"></script>');
}
} }
static updateLocation(url) { static updateLocation(url) {

View File

@ -2,12 +2,32 @@
* Bootstrap carousel improvement * Bootstrap carousel improvement
*/ */
.carousel-item { /*.carousel-item {
&.active { &.active {
display: flex !important; display: flex !important;
justify-content: center; justify-content: center;
align-items: flex-start; align-items: flex-start;
} }
}*/
.carousel-slide {
display: flex;
justify-content: center;
align-items: flex-start;
.video {
width: 100%;
iframe {
width: 100% !important;
height: auto !important;
}
}
.img {
display: block;
width: 100%;
}
} }
.carousel-control-prev, .carousel-control-prev,

View File

@ -204,3 +204,35 @@ button, input, optgroup, select, textarea,
z-index: 1; z-index: 1;
} }
} }
// dark dropdowns
.dropdown-menu.bg-dark {
border-color: $dark;
.nav-link {
color: $navbar-dark-color;
@include hover-focus {
color: $navbar-dark-hover-color;
}
&.disabled {
color: $navbar-dark-disabled-color;
}
}
.show > .nav-link,
.active > .nav-link,
.nav-link.show,
.nav-link.active {
color: $navbar-dark-active-color;
}
.dropdown-item {
@include hover-focus {
color: $navbar-dark-brand-hover-color;
background: $dark;
}
}
}

View File

@ -21,9 +21,12 @@ $bg-alt: $yellow;
$body-color: $gray-900; $body-color: $gray-900;
$navbar-light-active-color: $blue; $navbar-light-active-color: $blue;
$navbar-dark-hover-background: $dark;
$navbar-dark-active-background: $dark;
$dropdown-border-color: $white; $dropdown-border-color: $white;
$footer-size: 16rem; $footer-size: 18.5rem;
$footer-bar-size: 2.5rem; $footer-bar-size: 2.5rem;
/* /*

View File

@ -21,3 +21,6 @@ en:
EMPTY: "Please prove you are human - check the Captcha box." EMPTY: "Please prove you are human - check the Captcha box."
NOSCRIPT: "You must enable JavaScript to submit this form" NOSCRIPT: "You must enable JavaScript to submit this form"
VALIDATE_ERROR: "Captcha could not be validated" VALIDATE_ERROR: "Captcha could not be validated"
Dynamic\FlexSlider\Model\SlideImage:
SINGULARNAME: 'Slide'
PLURALNAME: 'Slides'

View File

@ -14,6 +14,7 @@ use Dynamic\FlexSlider\ORM\FlexSlider;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\CheckboxField; use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\LiteralField; use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\NumericField;
use SilverStripe\Forms\ReadonlyField; use SilverStripe\Forms\ReadonlyField;
use Symbiote\GridFieldExtensions\GridFieldEditableColumns; use Symbiote\GridFieldExtensions\GridFieldEditableColumns;
@ -27,6 +28,10 @@ class SliderElement extends ElementSlideshow
private static $table_name = 'SliderElement'; private static $table_name = 'SliderElement';
private static $db = [
'Interval' => 'Int',
];
private static $extensions = [ private static $extensions = [
FlexSlider::class, FlexSlider::class,
]; ];
@ -60,6 +65,10 @@ class SliderElement extends ElementSlideshow
'CarouselThumbnailCt', 'CarouselThumbnailCt',
]); ]);
$fields->addFieldsToTab('Root.Settings', [
NumericField::create('Interval', 'Auto-play Interval'),
]);
$grid = $fields->dataFieldByName('Slides'); $grid = $fields->dataFieldByName('Slides');
if ($grid) { if ($grid) {
$config = $grid->getConfig(); $config = $grid->getConfig();
@ -99,4 +108,13 @@ class SliderElement extends ElementSlideshow
return $this->items; return $this->items;
} }
public function onBeforeWrite()
{
parent::onBeforeWrite();
if(!$this->getField('Interval')){
$this->setField('Interval', 5000);
}
}
} }

View File

@ -200,7 +200,7 @@ class ElementRows extends DataExtension
{ {
return $this->owner->getField('ExtraClass') return $this->owner->getField('ExtraClass')
.( .(
$this->isColumn() $this->isColumn()
? ' '.Config::inst()->get(self::class, 'column_class').$this->owner->getField('Size') ? ' '.Config::inst()->get(self::class, 'column_class').$this->owner->getField('Size')
: '' : ''
); );

View File

@ -0,0 +1,42 @@
<?php
namespace Site\Extensions;
use Sheadawson\Linkable\Forms\EmbeddedObjectField;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\CompositeField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\ORM\FieldType\DBHTMLText;
class EmbedObjectField extends EmbeddedObjectField
{
/**
* @param array $properties
* @return mixed|DBHTMLText
*/
public function FieldHolder($properties = [])
{
$name = $this->getName();
$fields = [
CheckboxField::create(
$name . '[autoplay]',
_t(self::CLASS.'AUTOPLAY', 'Autoplay video?')
)->setValue($this->object->Autoplay),
CheckboxField::create(
$name . '[loop]',
_t(self::CLASS.'LOOP', 'Loop video?')
)->setValue($this->object->Loop)
];
return CompositeField::create(array_merge([
LiteralField::create(
$name.'Options',
parent::FieldHolder($properties)
)
], $fields));
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace Site\Extensions;
use SilverStripe\ORM\DataExtension;
class EmbeddedObjectExtension extends DataExtension
{
private static $db = [
'Autoplay' => 'Boolean(0)',
'Loop' => 'Boolean(0)',
];
public function Embed()
{
$this->owner->Embed();
$this->setEmbedParams();
return $this->owner;
}
public function setEmbedParams($params = [])
{
// YouTube params
if(stripos($this->owner->EmbedHTML, 'https://www.youtube.com/embed/') > 0) {
$params = array_merge([
'feature=oembed',
'wmode=transparent',
'enablejsapi=1',
'disablekb=1',
'iv_load_policy=3',
'modestbranding=1',
'rel=0',
'showinfo=0',
], $params);
if ($this->owner->Autoplay) {
$params[] = 'autoplay=1';
}
if ($this->owner->Loop) {
$params[] = 'loop=1';
}
$this->owner->EmbedHTML = preg_replace(
'/src="([A-z0-9:\/\.]+)\??(.*?)"/',
'src="${1}?' . implode('&', $params) . '"',
$this->owner->EmbedHTML
);
}
}
public function onBeforeWrite()
{
parent::onBeforeWrite();
$this->setEmbedParams();
}
}

View File

@ -12,11 +12,11 @@ use SilverStripe\UserForms\Model\EditableFormField;
class UserDefinedFormExtension extends DataExtension class UserDefinedFormExtension extends DataExtension
{ {
private static $db = [ /*private static $db = [
'CustomThankYouCode' => 'HTMLText', 'CustomThankYouCode' => 'HTMLText',
'RedirectOnComplete' => 'Boolean(0)', 'RedirectOnComplete' => 'Boolean(0)',
'RedirectOnCompleteURL' => 'Varchar(255)', 'RedirectOnCompleteURL' => 'Varchar(255)',
]; ];*/
private static $many_many = [ private static $many_many = [
'SubmissionColumns' => EditableFormField::class, 'SubmissionColumns' => EditableFormField::class,
@ -44,7 +44,7 @@ class UserDefinedFormExtension extends DataExtension
/*$tab->push(CheckboxField::create('RedirectOnComplete')); /*$tab->push(CheckboxField::create('RedirectOnComplete'));
$tab->push(TextField::create('RedirectOnCompleteURL'));*/ $tab->push(TextField::create('RedirectOnCompleteURL'));*/
$tab->push(TextareaField::create('CustomThankYouCode')); //$tab->push(TextareaField::create('CustomThankYouCode'));
$grid = $fields->dataFieldByName('Submissions'); $grid = $fields->dataFieldByName('Submissions');
@ -65,7 +65,7 @@ class UserDefinedFormExtension extends DataExtension
$name = $col->getField('Name'); $name = $col->getField('Name');
$columns[$name] = [ $columns[$name] = [
'title' => $title, 'title' => $title,
'callback' => function($item) use ($name) { 'callback' => function ($item) use ($name) {
return $item->relField($name); return $item->relField($name);
} }
]; ];

View File

@ -9,7 +9,6 @@ use SilverStripe\Core\Config\Config;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\Core\Path; use SilverStripe\Core\Path;
use SilverStripe\Core\Manifest\ManifestFileFinder; use SilverStripe\Core\Manifest\ManifestFileFinder;
use SilverStripe\CMS\Controllers\CMSMain;
class DeferedRequirements implements TemplateGlobalProvider class DeferedRequirements implements TemplateGlobalProvider
{ {
@ -36,15 +35,21 @@ class DeferedRequirements implements TemplateGlobalProvider
public static function Auto($class = false) public static function Auto($class = false)
{ {
if (is_a(Controller::curr(), CMSMain::class)) {
return;
}
$config = Config::inst()->get(self::class); $config = Config::inst()->get(self::class);
$projectName = WebpackTemplateProvider::projectName(); $projectName = WebpackTemplateProvider::projectName();
$mainTheme = WebpackTemplateProvider::mainTheme(); $mainTheme = WebpackTemplateProvider::mainTheme();
$mainTheme = $mainTheme ? $mainTheme : $projectName; $mainTheme = $mainTheme ? $mainTheme : $projectName;
$dir = Path::join(
Director::publicFolder(),
ManifestFileFinder::RESOURCES_DIR,
$projectName,
'client',
'dist'
);
$cssPath = Path::join($dir, 'css');
$jsPath = Path::join($dir, 'js');
// Initialization // Initialization
Requirements::block(THIRDPARTY_DIR.'/jquery/jquery.js'); Requirements::block(THIRDPARTY_DIR.'/jquery/jquery.js');
/*if (defined('FONT_AWESOME_DIR')) { /*if (defined('FONT_AWESOME_DIR')) {
@ -60,7 +65,6 @@ class DeferedRequirements implements TemplateGlobalProvider
if (!$config['nofontawesome']) { if (!$config['nofontawesome']) {
DeferedRequirements::loadCSS('//use.fontawesome.com/releases/v5.4.0/css/all.css'); DeferedRequirements::loadCSS('//use.fontawesome.com/releases/v5.4.0/css/all.css');
} }
DeferedRequirements::loadCSS($mainTheme.'.css'); DeferedRequirements::loadCSS($mainTheme.'.css');
DeferedRequirements::loadJS($mainTheme.'.js'); DeferedRequirements::loadJS($mainTheme.'.js');
@ -78,25 +82,18 @@ class DeferedRequirements implements TemplateGlobalProvider
} }
$class = str_replace('\\', '.', $class); $class = str_replace('\\', '.', $class);
$dir = Path::join(
Director::publicFolder(),
ManifestFileFinder::RESOURCES_DIR,
$projectName,
'client',
'dist'
);
// Controller requirements // Controller requirements
$themePath = Path::join($dir, 'css', $mainTheme.'_'.$class . '.css'); $themePath = Path::join($cssPath, $mainTheme.'_'.$class . '.css');
$projectPath = Path::join($dir, 'css', $projectName.'_'.$class . '.css'); $projectPath = Path::join($cssPath, $projectName.'_'.$class . '.css');
if ($mainTheme && file_exists($themePath)) { if ($mainTheme && file_exists($themePath)) {
DeferedRequirements::loadCSS($mainTheme.'_'.$class . '.css'); DeferedRequirements::loadCSS($mainTheme.'_'.$class . '.css');
} elseif (file_exists($projectPath)) { } elseif (file_exists($projectPath)) {
DeferedRequirements::loadCSS($projectName.'_'.$class . '.css'); DeferedRequirements::loadCSS($projectName.'_'.$class . '.css');
} }
$themePath = Path::join($dir, 'js', $mainTheme.'_'.$class . '.js'); $themePath = Path::join($jsPath, $mainTheme.'_'.$class . '.js');
$projectPath = Path::join($dir, 'js', $projectName.'_'.$class . '.js'); $projectPath = Path::join($jsPath, $projectName.'_'.$class . '.js');
if ($mainTheme && file_exists($themePath)) { if ($mainTheme && file_exists($themePath)) {
DeferedRequirements::loadJS($mainTheme.'_'.$class . '.js'); DeferedRequirements::loadJS($mainTheme.'_'.$class . '.js');
} elseif (file_exists($projectPath)) { } elseif (file_exists($projectPath)) {

View File

@ -1,25 +1,27 @@
<% with $SiteConfig %> <% with $SiteConfig %>
<div class="container"> <div class="wrapper">
<h2>Contact Us</h2> <div class="container">
<div class="field row"> <h2>Contact Us</h2>
<div class="title col-sm-4">Address:</div> <div class="field row">
<div class="value col-sm-8">$Address</div> <div class="title col-sm-4">Address:</div>
</div> <div class="value col-sm-8">$Address</div>
</div>
<div class="field row"> <div class="field row">
<div class="title col-sm-4">Phone:</div> <div class="title col-sm-4">Phone:</div>
<div class="value col-sm-8">$PhoneNumber</div> <div class="value col-sm-8">$PhoneNumber</div>
</div> </div>
<div class="field row"> <div class="field row">
<div class="title col-sm-4">Email:</div> <div class="title col-sm-4">Email:</div>
<div class="value col-sm-8">$PublicEmail</div> <div class="value col-sm-8">$PublicEmail</div>
</div> </div>
<% include Objects\SocialLinks %> <% include Objects\SocialLinks %>
</div>
</div> </div>
<div class="copyright"> <div class="copyright footer">
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">

View File

@ -12,7 +12,7 @@
</button> </button>
<div class="collapse navbar-collapse" id="{$NavID}Content"> <div class="collapse navbar-collapse" id="{$NavID}Content">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav mr-auto w-100 nav-fill">
<% loop $Navigation %> <% loop $Navigation %>
<% include NavItem %> <% include NavItem %>
<% end_loop %> <% end_loop %>

View File

@ -18,7 +18,7 @@
</main> </main>
</div> </div>
<footer id="Footer" class="site-footer"> <footer id="Footer" class="site-footer footer">
<% include Footer %> <% include Footer %>
</footer> </footer>

View File

@ -3,17 +3,38 @@
<% end_if %> <% end_if %>
<% if $SlideShow %> <% if $SlideShow %>
<div id="Carousel{$ID}" class="carousel slide js-carousel d-none d-sm-block"<% if $SlideShow.count > 1 %> data-indicators="true" data-arrows="true"<% end_if %>> <div id="Carousel{$ID}" class="carousel slide js-carousel d-none d-sm-block parallax"<% if $SlideShow.count > 1 %><% if $Interval %> data-interval="$Interval"<% end_if %> data-indicators="true" data-arrows="true"<% end_if %>>
<div class="carousel-inner"> <div class="carousel-inner">
<% loop $SlideShow %> <% loop $SlideShow %>
<div class="carousel-item<% if $First %> active<% end_if %>"> <div class="carousel-item<% if $First %> active<% end_if %>">
<% if $PageLink %><a href="$PageLink.Link" title="$PageLink.MenuTitle.XML" class="btn-primary"><% end_if %>
<% if $Image %>
<img class="d-block w-100" src="$Image.Fill(1200,600).URL" alt="<% if $Headline %>$Headline<% end_if %>">
<% end_if %>
<% if $PageLink %></a><% end_if %>
<div class="carousel-caption">
<% if $Video || $Image %>
<div class="carousel-slide">
<% if $Video %>
<div class="video">
$Video.EmbedHTML.RAW
</div>
<% end_if %>
<% if $PageLink %><a href="$PageLink.Link" title="$PageLink.MenuTitle.XML" class="btn-primary"><% end_if %>
<% if $Image %>
<span class="img parallax-image">
<img class="d-block w-100" src="$Image.Fill(1200,600).URL" alt="<% if $Headline %>$Headline<% end_if %>">
</span>
<% end_if %>
<% if $PageLink %></a><% end_if %>
</div>
<% end_if %>
<% if not $Video && not $Image %>
<div class="carousel-slide">
<% else %>
<div class="carousel-caption">
<% end_if %>
<div class="carousel-caption-container"> <div class="carousel-caption-container">
<% if $Headline %><h2 class="carousel-title">$Headline</h2><% end_if %> <% if $Headline %><h2 class="carousel-title">$Headline</h2><% end_if %>
<% if $Description %><p class="carousel-content">$Description</p><% end_if %> <% if $Description %><p class="carousel-content">$Description</p><% end_if %>