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
---
SilverStripe\Core\Manifest\ModuleManifest:
project: app
SilverStripe\View\SSViewer:
source_file_comments: true
themes:
- '$public'
- '$default'
Page:
default_container_class: 'container'

View File

@ -11,15 +11,21 @@ SilverStripe\Blog\Model\BlogPost:
extensions:
- Site\Extensions\BlogPostExtension
Sheadawson\Linkable\Models\EmbeddedObject:
extensions:
- Site\Extensions\EmbeddedObjectExtension
Dynamic\FlexSlider\Model\SlideImage:
extensions:
- Site\Extensions\SlideImageExtension
- Site\Extensions\SlideImageExtension
SilverStripe\Core\Injector\Injector:
SilverStripe\UserForms\Model\UserDefinedForm:
class: Site\Extensions\CMSMain_HiddenClass
SilverStripe\Security\MemberAuthenticator\LostPasswordHandler:
class: Site\Extensions\LostPasswordHandlerExtension
Sheadawson\Linkable\Forms\EmbeddedObjectField:
class: Site\Extensions\EmbedObjectField
# User Forms
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
$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
$e.hammer().bind('swipeleft', (event) => {
$(event.target).carousel('next');
@ -70,7 +101,7 @@ const CarouselUI = (($) => {
$(event.target).carousel('prev');
});
$e.hammer().bind('tap', (event) => {
$e.find('.carousel-item').hammer().bind('tap', (event) => {
$(event.target).carousel('next');
});
});

View File

@ -82,7 +82,7 @@ const FormValidateField = (($) => {
isHtml(str) {
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) {

View File

@ -246,6 +246,11 @@ const MainUI = (($) => {
if (W.URLDetails['hash'].indexOf('printpage') > -1) {
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) {

View File

@ -2,12 +2,32 @@
* Bootstrap carousel improvement
*/
.carousel-item {
/*.carousel-item {
&.active {
display: flex !important;
justify-content: center;
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,

View File

@ -204,3 +204,35 @@ button, input, optgroup, select, textarea,
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;
$navbar-light-active-color: $blue;
$navbar-dark-hover-background: $dark;
$navbar-dark-active-background: $dark;
$dropdown-border-color: $white;
$footer-size: 16rem;
$footer-size: 18.5rem;
$footer-bar-size: 2.5rem;
/*

View File

@ -21,3 +21,6 @@ en:
EMPTY: "Please prove you are human - check the Captcha box."
NOSCRIPT: "You must enable JavaScript to submit this form"
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\Forms\CheckboxField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\NumericField;
use SilverStripe\Forms\ReadonlyField;
use Symbiote\GridFieldExtensions\GridFieldEditableColumns;
@ -27,6 +28,10 @@ class SliderElement extends ElementSlideshow
private static $table_name = 'SliderElement';
private static $db = [
'Interval' => 'Int',
];
private static $extensions = [
FlexSlider::class,
];
@ -60,6 +65,10 @@ class SliderElement extends ElementSlideshow
'CarouselThumbnailCt',
]);
$fields->addFieldsToTab('Root.Settings', [
NumericField::create('Interval', 'Auto-play Interval'),
]);
$grid = $fields->dataFieldByName('Slides');
if ($grid) {
$config = $grid->getConfig();
@ -99,4 +108,13 @@ class SliderElement extends ElementSlideshow
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')
.(
$this->isColumn()
$this->isColumn()
? ' '.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
{
private static $db = [
/*private static $db = [
'CustomThankYouCode' => 'HTMLText',
'RedirectOnComplete' => 'Boolean(0)',
'RedirectOnCompleteURL' => 'Varchar(255)',
];
];*/
private static $many_many = [
'SubmissionColumns' => EditableFormField::class,
@ -44,7 +44,7 @@ class UserDefinedFormExtension extends DataExtension
/*$tab->push(CheckboxField::create('RedirectOnComplete'));
$tab->push(TextField::create('RedirectOnCompleteURL'));*/
$tab->push(TextareaField::create('CustomThankYouCode'));
//$tab->push(TextareaField::create('CustomThankYouCode'));
$grid = $fields->dataFieldByName('Submissions');
@ -65,7 +65,7 @@ class UserDefinedFormExtension extends DataExtension
$name = $col->getField('Name');
$columns[$name] = [
'title' => $title,
'callback' => function($item) use ($name) {
'callback' => function ($item) use ($name) {
return $item->relField($name);
}
];

View File

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

View File

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

View File

@ -12,7 +12,7 @@
</button>
<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 %>
<% include NavItem %>
<% end_loop %>

View File

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

View File

@ -3,17 +3,38 @@
<% end_if %>
<% 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">
<% loop $SlideShow %>
<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">
<% if $Headline %><h2 class="carousel-title">$Headline</h2><% end_if %>
<% if $Description %><p class="carousel-content">$Description</p><% end_if %>