mirror of
https://github.com/a2nt/silverstripe-webpack.git
synced 2024-10-22 17:05:31 +02:00
Video shortcodes, Webpack Image compression, other improvements
This commit is contained in:
parent
75ef9f569f
commit
fdcc1be513
@ -3,7 +3,10 @@
|
||||
use SilverStripe\Forms\HTMLEditor\HtmlEditorConfig;
|
||||
use SilverStripe\Core\Manifest\ModuleResourceLoader;
|
||||
use SilverStripe\ORM\Search\FulltextSearchable;
|
||||
use SilverStripe\View\Parsers\ShortcodeParser;
|
||||
use Site\Extensions\EmbedShortcodeProvider;
|
||||
|
||||
// setup TinyMCE editor
|
||||
$config = HtmlEditorConfig::get('cms');
|
||||
$config->enablePlugins([
|
||||
'template',
|
||||
@ -29,3 +32,9 @@ $config->setOption(
|
||||
);
|
||||
|
||||
FulltextSearchable::enable();
|
||||
|
||||
// replace embed parser
|
||||
$parser = ShortcodeParser::get('default');
|
||||
$parser->unregister('embed');
|
||||
$parser->register('embed', [EmbedShortcodeProvider::class, 'handle_shortcode']);
|
||||
|
||||
|
@ -7,6 +7,8 @@ Site\Templates\DeferredRequirements:
|
||||
version: false
|
||||
static_domain: false
|
||||
deferred: true
|
||||
jquery_version: '3.4.1'
|
||||
fontawesome_version: '5.10.2'
|
||||
|
||||
SilverStripe\View\Requirements:
|
||||
disable_flush_combined: true
|
||||
|
@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
import '../scss/app.scss';
|
||||
import $ from 'jquery';
|
||||
import './_consts';
|
||||
|
||||
// import Bootstrap
|
||||
import 'popper.js';
|
||||
@ -9,21 +8,7 @@ import 'bootstrap/js/dist/alert';
|
||||
import 'bootstrap/js/dist/button';
|
||||
import 'bootstrap/js/dist/carousel';
|
||||
import 'bootstrap/js/dist/collapse';
|
||||
|
||||
import 'hammerjs/hammer';
|
||||
import 'jquery-hammerjs/jquery.hammer';
|
||||
|
||||
// Routie
|
||||
//import 'pouchdb/dist/pouchdb';
|
||||
//import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/routes/index';
|
||||
|
||||
// conflicts with _components/_ui.hover.js (shows dropdown on hover)
|
||||
//import 'bootstrap/js/dist/dropdown';
|
||||
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.hover';
|
||||
|
||||
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.carousel';
|
||||
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.menu';
|
||||
|
||||
import 'bootstrap/js/dist/dropdown';
|
||||
import 'bootstrap/js/dist/modal';
|
||||
import 'bootstrap/js/dist/tooltip';
|
||||
import 'bootstrap/js/dist/popover';
|
||||
@ -31,57 +16,37 @@ import 'bootstrap/js/dist/scrollspy';
|
||||
import 'bootstrap/js/dist/tab';
|
||||
//
|
||||
|
||||
import Spinner from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.spinner';
|
||||
//import Multislider from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.multislider';
|
||||
|
||||
// Flyout UI
|
||||
//import Flyout from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.flyout';
|
||||
|
||||
// Offcanvas menu
|
||||
//import 'offcanvas-bootstrap/dist/js/bootstrap.offcanvas';
|
||||
|
||||
import '../scss/app.scss';
|
||||
|
||||
import '@a2nt/meta-lightbox/src/js/meta-lightbox';
|
||||
// youtube video preview image
|
||||
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.video.preview';
|
||||
|
||||
// MainUI
|
||||
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_main';
|
||||
|
||||
// Uncomment it to enable meta-lightbox zooming on hover
|
||||
//import 'jquery-zoom/jquery.zoom';
|
||||
|
||||
// Toggle bootstrap form fields
|
||||
//import FormToggleUI from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.fields.toggle';
|
||||
|
||||
// Bootstrap Date & Time fields
|
||||
//import FormDatetime from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.datetime';
|
||||
|
||||
// Stepped forms functionality
|
||||
//import FormStepped from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.stepped';
|
||||
|
||||
// Forms validation functionality
|
||||
//import FormValidate from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.validate';
|
||||
|
||||
// Store forms data into localStorage
|
||||
//import FormStorage from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.storage';
|
||||
|
||||
// client-side images cropping
|
||||
//import FormCroppie from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.croppie';
|
||||
|
||||
// Google NoCaptcha fields
|
||||
//import NoCaptcha from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.nocaptcha';
|
||||
|
||||
// youtube video preview image
|
||||
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.video.preview';
|
||||
|
||||
// Meta Lightbox
|
||||
import '@a2nt/meta-lightbox/src/js/index';
|
||||
|
||||
//import Confirmation from 'bootstrap-confirmation2/dist/bootstrap-confirmation';
|
||||
//import Table from 'bootstrap-table/dist/bootstrap-table';
|
||||
|
||||
// AJAX UI
|
||||
//import AjaxUI from '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.ajax';
|
||||
|
||||
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_main';
|
||||
import './_layout';
|
||||
// Forms UI
|
||||
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.basics';
|
||||
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.validate';
|
||||
import '@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/js/_components/_ui.form.stepped';
|
||||
|
||||
// Import fonts and images
|
||||
function importAll(r) {
|
||||
return r.keys().map(r);
|
||||
return r.keys().map(r);
|
||||
}
|
||||
|
||||
const images = importAll(require.context('../img/', false, /\.(png|jpe?g|svg)$/));
|
||||
const fontAwesome = importAll(require.context('font-awesome', false, /\.(otf|eot|svg|ttf|woff|woff2)$/));
|
||||
const images = importAll(
|
||||
require.context('../img/', false, /\.(png|jpe?g|svg)$/),
|
||||
);
|
||||
const fontAwesome = importAll(
|
||||
require.context('font-awesome', false, /\.(otf|eot|svg|ttf|woff|woff2)$/),
|
||||
);
|
||||
|
||||
// Your custom JS
|
||||
import './_layout';
|
||||
|
@ -10,27 +10,29 @@
|
||||
|
||||
.bootstrap-select .dropdown-toggle .filter-option .option {
|
||||
background: #dedede;
|
||||
padding: .2rem .5rem;
|
||||
margin: .2rem;
|
||||
padding: 0.2rem 0.5rem;
|
||||
margin: 0.2rem;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
// shrink elements on scroll
|
||||
body.shrink {}
|
||||
body.shrink {
|
||||
}
|
||||
|
||||
// sticky footer
|
||||
@media (min-width: map-get($grid-breakpoints, "sm")) {
|
||||
html, body {
|
||||
@media (min-width: map-get($grid-breakpoints, 'sm')) {
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
min-height: 100%;
|
||||
padding-bottom: $footer-size + $footer-bar-size + $grid-gutter-height / 2;
|
||||
padding-bottom: $footer-size + $footer-bar-size + $grid-gutter-height /
|
||||
2;
|
||||
|
||||
//padding-top: $grid-gutter-height;
|
||||
|
||||
}
|
||||
|
||||
.footer {
|
||||
@ -97,12 +99,6 @@ body.shrink {}
|
||||
background-color: $dark;
|
||||
color: darken($white, 5%);
|
||||
|
||||
.container,
|
||||
.container-fluid {
|
||||
padding-top: $grid-gutter-height / 2;
|
||||
padding-bottom: $grid-gutter-height / 2;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $white;
|
||||
}
|
||||
@ -114,22 +110,16 @@ body.shrink {}
|
||||
.footer {
|
||||
background-color: darken($dark, 5%);
|
||||
|
||||
.container,
|
||||
.container-fluid {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
padding-right: .5rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 0 .5rem;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: map-get($grid-breakpoints, "sm")) {
|
||||
@media (min-width: map-get($grid-breakpoints, 'sm')) {
|
||||
.wrapper {
|
||||
padding-bottom: $footer-bar-size;
|
||||
}
|
||||
|
@ -2,19 +2,45 @@
|
||||
* Your custom variables
|
||||
*/
|
||||
|
||||
$grid-breakpoints: (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1390px, xxxl: 1590px);
|
||||
$container-max-widths: (sm: 540px, md: 720px, lg: 960px, xl: 1140px, xxl: 1330px, xxxl: 1560px);
|
||||
$grid-breakpoints: (
|
||||
xs: 0,
|
||||
sm: 576px,
|
||||
md: 768px,
|
||||
lg: 992px,
|
||||
xl: 1200px,
|
||||
xxl: 1390px,
|
||||
xxxl: 1590px,
|
||||
);
|
||||
$container-max-widths: (
|
||||
sm: 540px,
|
||||
md: 720px,
|
||||
lg: 960px,
|
||||
xl: 1140px,
|
||||
xxl: 1330px,
|
||||
xxxl: 1560px,
|
||||
);
|
||||
|
||||
$font-family-base: "Lato", sans-serif;
|
||||
$font-family-base: 'Lato', sans-serif;
|
||||
|
||||
$grid-gutter-width: 2rem;
|
||||
$grid-gutter-height: 2rem;
|
||||
$grid-gutter-element-height: $grid-gutter-height * 2;
|
||||
|
||||
@import "~@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/scss/_variables";
|
||||
@import '~@a2nt/ss-bootstrap-ui-webpack-boilerplate/src/scss/_variables';
|
||||
|
||||
// Add your site-wide + content editor typography styling
|
||||
|
||||
h1, h2, h3, h4, h5, h6,
|
||||
.h1, .h2, .h3, .h4, .h5, .h6 {
|
||||
color: $dark;
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
.h1,
|
||||
.h2,
|
||||
.h3,
|
||||
.h4,
|
||||
.h5,
|
||||
.h6 {
|
||||
color: $headings-color;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
|
||||
use SilverStripe\Forms\NumericField;
|
||||
use Site\Controllers\MapElementController;
|
||||
use Site\Extensions\MapExtension;
|
||||
use SilverStripe\Forms\GridField\GridFieldDataColumns;
|
||||
|
||||
class MapElement extends ElementContent
|
||||
{
|
||||
@ -60,10 +61,16 @@ class MapElement extends ElementContent
|
||||
'Locations',
|
||||
'Locations',
|
||||
$this->owner->Locations(),
|
||||
GridFieldConfig_RelationEditor::create(100)
|
||||
$cfg = GridFieldConfig_RelationEditor::create(100)
|
||||
)
|
||||
]);
|
||||
|
||||
$cfg->getComponentByType(GridFieldDataColumns::class)->setFieldFormatting([
|
||||
'ShowAtMap' => static function ($v, $obj) {
|
||||
return $v ? 'YES' : 'NO';
|
||||
}
|
||||
]);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ use SilverStripe\Forms\CheckboxField;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\ORM\DataExtension;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\LiteralField;
|
||||
|
||||
class ElementRows extends DataExtension
|
||||
{
|
||||
@ -95,6 +96,15 @@ class ElementRows extends DataExtension
|
||||
} else {
|
||||
$fields->removeByName('Size');
|
||||
}
|
||||
|
||||
$tab = $fields->findOrMakeTab('Root.Settings')
|
||||
->push(LiteralField::create(
|
||||
'ClassName',
|
||||
'<div class="form-group field text">'
|
||||
.'<div class="form__field-label">Class</div>'
|
||||
.'<div class="form__field-holder">'.$this->owner->getField('ClassName').'</div>'
|
||||
.'</div>'
|
||||
));
|
||||
}
|
||||
|
||||
public function getWidthPercetage()
|
||||
|
52
app/src/Extensions/EmbedShortcodeProvider.php
Normal file
52
app/src/Extensions/EmbedShortcodeProvider.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Site\Extensions;
|
||||
|
||||
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\View\HTML;
|
||||
|
||||
class EmbedShortcodeProvider extends \SilverStripe\View\Shortcodes\EmbedShortcodeProvider
|
||||
{
|
||||
/**
|
||||
* Build video embed tag
|
||||
*
|
||||
* @param array $arguments
|
||||
* @param string $content Raw HTML content
|
||||
* @return string
|
||||
*/
|
||||
protected static function videoEmbed($arguments, $content)
|
||||
{
|
||||
// Ensure outer div has given width (but leave height auto)
|
||||
if (!empty($arguments['width'])) {
|
||||
$arguments['style'] = 'width:' . (int) $arguments['width'] . 'px';
|
||||
//.';height:' . (int) $arguments['height'] . 'px';
|
||||
}
|
||||
|
||||
// Convert caption to <p>
|
||||
if (!empty($arguments['caption'])) {
|
||||
$xmlCaption = Convert::raw2xml($arguments['caption']);
|
||||
$content .= "\n<p class=\"caption\">{$xmlCaption}</p>";
|
||||
}
|
||||
|
||||
// Convert arguments to data-*argument_name*
|
||||
foreach ($arguments as $k => $v) {
|
||||
if($k === 'class' || $k === 'style') {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($arguments[$k]);
|
||||
$arguments['data-'.$k] = $v;
|
||||
}
|
||||
|
||||
$arguments['class'] .= ' embed-youtube embed-responsive embed-responsive-16by9';
|
||||
|
||||
$iframe = strpos($content, 'iframe');
|
||||
if($iframe >= 0) {
|
||||
$content = substr($content, 0, $iframe+6).' class="embed-responsive-item" '.substr($content, $iframe +7);
|
||||
}
|
||||
|
||||
return HTML::createTag('div', $arguments, $content);
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
|
||||
namespace Site\Extensions;
|
||||
|
||||
|
||||
use SilverStripe\ORM\DataExtension;
|
||||
|
||||
class EmbeddedObjectExtension extends DataExtension
|
||||
@ -25,7 +24,15 @@ class EmbeddedObjectExtension extends DataExtension
|
||||
public function setEmbedParams($params = [])
|
||||
{
|
||||
// YouTube params
|
||||
if(stripos($this->owner->EmbedHTML, 'https://www.youtube.com/embed/') > 0) {
|
||||
if (stripos($this->owner->EmbedHTML, 'https://www.youtube.com/embed/') > 0) {
|
||||
$url = $this->owner->getField('SourceURL');
|
||||
preg_match(
|
||||
'/^(?:http(?:s)?:\/\/)?(?:www\.)?(?:m\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?v(?:i)?=|(?:embed|v|vi|user)\/))([^\?&"\'>]+)/',
|
||||
$url,
|
||||
$matches
|
||||
);
|
||||
$videoID = $matches[1];
|
||||
|
||||
$params = array_merge([
|
||||
'feature=oembed',
|
||||
'wmode=transparent',
|
||||
@ -48,7 +55,7 @@ class EmbeddedObjectExtension extends DataExtension
|
||||
|
||||
$this->owner->EmbedHTML = preg_replace(
|
||||
'/src="([A-z0-9:\/\.]+)\??(.*?)"/',
|
||||
'src="${1}?' . implode('&', $params) . '"',
|
||||
'src="https://www.youtube.com/embed/'.$videoID.'?' . implode('&', $params) . '"',
|
||||
$this->owner->EmbedHTML
|
||||
);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ use SilverStripe\Forms\CompositeField;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
|
||||
use SilverStripe\Forms\GridField\GridFieldDataColumns;
|
||||
use SilverStripe\Forms\NumericField;
|
||||
use SilverStripe\ORM\DataExtension;
|
||||
use Site\Models\MapPin;
|
||||
@ -42,19 +43,28 @@ class MapExtension extends DataExtension
|
||||
'Locations',
|
||||
'Locations',
|
||||
$this->owner->Locations(),
|
||||
GridFieldConfig_RelationEditor::create(100)
|
||||
$cfg = GridFieldConfig_RelationEditor::create(100)
|
||||
)
|
||||
]);
|
||||
|
||||
$cfg->getComponentByType(GridFieldDataColumns::class)->setFieldFormatting([
|
||||
'ShowAtMap' => static function ($v, $obj) {
|
||||
return $v ? 'YES' : 'NO';
|
||||
}
|
||||
]);
|
||||
|
||||
$fields->findOrMakeTab('Root.MapPins')->setTitle('Locations');
|
||||
}
|
||||
|
||||
public function getGeoJSON(): string
|
||||
{
|
||||
$locs = $this->owner->Locations()->filter('ShowAtMap', true);
|
||||
|
||||
$pins = [];
|
||||
foreach ($this->owner->Locations() as $off) {
|
||||
foreach ($locs as $off) {
|
||||
$pins[] = $off->getGeo();
|
||||
}
|
||||
|
||||
return json_encode([
|
||||
'type' => 'MarkerCollection',
|
||||
'features' => $pins
|
||||
|
@ -49,7 +49,9 @@ class SiteConfigExtension extends DataExtension
|
||||
'Navigation',
|
||||
'Navigation',
|
||||
SiteTree::class
|
||||
),
|
||||
)->setDisableFunction(static function ($el) {
|
||||
return $el->getField('ParentID') !== 0;
|
||||
}),
|
||||
TextareaField::create('Description', 'Website Description'),
|
||||
TextareaField::create('ExtraCode', 'Extra site-wide HTML code'),
|
||||
DropdownField::create(
|
||||
|
@ -24,6 +24,7 @@ class MapPin extends DataObject
|
||||
|
||||
private static $db = [
|
||||
'Title' => 'Varchar(255)',
|
||||
'ShowAtMap' => 'Boolean(1)',
|
||||
];
|
||||
|
||||
private static $has_one = [
|
||||
@ -43,6 +44,12 @@ class MapPin extends DataObject
|
||||
|
||||
private static $default_sort = 'Title ASC, ID DESC';
|
||||
|
||||
private static $summary_fields = [
|
||||
'Title',
|
||||
'Address',
|
||||
'ShowAtMap',
|
||||
];
|
||||
|
||||
public function getCMSFields()
|
||||
{
|
||||
$fields = parent::getCMSFields();
|
||||
@ -63,6 +70,7 @@ class MapPin extends DataObject
|
||||
$fields->removeByName(['Map', 'LatLngOverride', 'Lng','Lat']);
|
||||
|
||||
$fields->addFieldsToTab('Root.Main', [
|
||||
CheckboxField::create('ShowAtMap', 'Show at the map?'),
|
||||
CheckboxField::create('LatLngOverride', 'Override Latitude and Longitude?')
|
||||
->setDescription('Check this box and save to be able to edit the latitude and longitude manually.'),
|
||||
MapboxField::create('Map', 'Choose a location', 'Lat', 'Lng'),
|
||||
|
@ -50,7 +50,7 @@ class PageController extends ContentController
|
||||
|
||||
public function ElementalArea()
|
||||
{
|
||||
if($this->CurrentElement() || $this->getAction() !== 'index') {
|
||||
if ($this->CurrentElement() || $this->getAction() !== 'index') {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ class PageController extends ContentController
|
||||
{
|
||||
$controller_curr = Controller::curr();
|
||||
|
||||
if(is_a($controller_curr, ElementFormController::class)) {
|
||||
if (is_a($controller_curr, ElementFormController::class)) {
|
||||
return $controller_curr;
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ class PageController extends ContentController
|
||||
public function SearchResults()
|
||||
{
|
||||
$term = $this->search_term;
|
||||
if(!$term) {
|
||||
if (!$term) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ class PageController extends ContentController
|
||||
|
||||
foreach ($elements as $element) {
|
||||
$page = Page::get()->filter('ElementalAreaID', $element->getField('ParentID'))->first();
|
||||
if(!$page) {
|
||||
if (!$page) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -177,4 +177,9 @@ class PageController extends ContentController
|
||||
{
|
||||
return DBDatetime::now();
|
||||
}
|
||||
|
||||
public function isDev()
|
||||
{
|
||||
return Director::isDev();
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ class DeferredRequirements implements TemplateGlobalProvider
|
||||
private static $static_domain;
|
||||
private static $version;
|
||||
private static $nojquery = false;
|
||||
private static $jquery_version = '3.4.1';
|
||||
private static $nofontawesome = false;
|
||||
private static $fontawesome_version = '5.10.2';
|
||||
private static $custom_requirements = [];
|
||||
|
||||
/**
|
||||
@ -60,12 +62,19 @@ class DeferredRequirements implements TemplateGlobalProvider
|
||||
|
||||
// Main libs
|
||||
if (!$config['nojquery']) {
|
||||
self::loadJS('//ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js');
|
||||
self::loadJS(
|
||||
'//ajax.googleapis.com/ajax/libs/jquery/'
|
||||
.$config['jquery_version'].'/jquery.min.js'
|
||||
);
|
||||
}
|
||||
// App libs
|
||||
if (!$config['nofontawesome']) {
|
||||
self::loadCSS('//use.fontawesome.com/releases/v5.4.0/css/all.css');
|
||||
self::loadCSS(
|
||||
'//use.fontawesome.com/releases/v'
|
||||
.$config['fontawesome_version'].'/css/all.css'
|
||||
);
|
||||
}
|
||||
|
||||
self::loadCSS($mainTheme.'.css');
|
||||
self::loadJS($mainTheme.'.js');
|
||||
|
||||
@ -176,17 +185,16 @@ class DeferredRequirements implements TemplateGlobalProvider
|
||||
return $url;
|
||||
}
|
||||
|
||||
$version = $config['version'];
|
||||
$version = $version
|
||||
? strpos($url, '?') // inner URL
|
||||
? '&'.$version // add param
|
||||
: '?'.$version // new param
|
||||
: ''; // no version defined
|
||||
$path = WebpackTemplateProvider::toPublicPath($url);
|
||||
|
||||
$absolutePath = Director::getAbsFile($path);
|
||||
$hash = sha1_file($absolutePath);
|
||||
|
||||
$version = $config['version'] ? '&v='.$config['version'] : '';
|
||||
//$static_domain = $config['static_domain'];
|
||||
//$static_domain = $static_domain ?: '';
|
||||
|
||||
return WebpackTemplateProvider::toPublicPath($url.$version);
|
||||
return Controller::join_links(WebpackTemplateProvider::toPublicPath($url), '?m='.$hash.$version);
|
||||
}
|
||||
|
||||
public static function config(): array
|
||||
|
@ -1,36 +1,28 @@
|
||||
<?php
|
||||
/** @noinspection PhpUnusedPrivateFieldInspection */
|
||||
|
||||
/**
|
||||
* Directs assets requests to Webpack server or to static files
|
||||
*/
|
||||
/** @noinspection PhpUnusedPrivateFieldInspection */
|
||||
|
||||
namespace Site\Templates;
|
||||
|
||||
use SilverStripe\Core\Manifest\ModuleManifest;
|
||||
use SilverStripe\View\SSViewer;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\View\TemplateGlobalProvider;
|
||||
use SilverStripe\View\Requirements;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Core\Path;
|
||||
|
||||
class WebpackTemplateProvider implements TemplateGlobalProvider
|
||||
class DeferredRequirements implements TemplateGlobalProvider
|
||||
{
|
||||
/**
|
||||
* @var int port number
|
||||
*/
|
||||
private static $port = 3000;
|
||||
|
||||
/**
|
||||
* @var string host name
|
||||
*/
|
||||
private static $hostname = 'localhost';
|
||||
|
||||
/**
|
||||
* @var string assets static files directory
|
||||
*/
|
||||
private static $dist = 'client/dist';
|
||||
private static $css = [];
|
||||
private static $js = [];
|
||||
private static $deferred = false;
|
||||
private static $static_domain;
|
||||
private static $version;
|
||||
private static $nojquery = false;
|
||||
private static $jquery_version = '3.4.1';
|
||||
private static $nofontawesome = false;
|
||||
private static $fontawesome_version = '5.11.0';
|
||||
private static $custom_requirements = [];
|
||||
|
||||
/**
|
||||
* @return array
|
||||
@ -38,97 +30,172 @@ class WebpackTemplateProvider implements TemplateGlobalProvider
|
||||
public static function get_template_global_variables(): array
|
||||
{
|
||||
return [
|
||||
'WebpackDevServer' => 'isActive',
|
||||
'WebpackCSS' => 'loadCSS',
|
||||
'WebpackJS' => 'loadJS',
|
||||
'ResourcesURL' => 'resourcesURL',
|
||||
'ProjectName' => 'themeName',
|
||||
'AutoRequirements' => 'Auto',
|
||||
'DeferedCSS' => 'loadCSS',
|
||||
'DeferedJS' => 'loadJS',
|
||||
'WebpackActive' => '_webpackActive',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load CSS file
|
||||
* @param $path
|
||||
*/
|
||||
public static function loadCSS($path): void
|
||||
public static function Auto($class = false): string
|
||||
{
|
||||
if (self::isActive()) {
|
||||
return;
|
||||
$config = Config::inst()->get(self::class);
|
||||
$projectName = WebpackTemplateProvider::projectName();
|
||||
$mainTheme = WebpackTemplateProvider::mainTheme();
|
||||
$mainTheme = $mainTheme ?: $projectName;
|
||||
|
||||
$dir = Path::join(
|
||||
Director::publicFolder(),
|
||||
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')) {
|
||||
Requirements::block(FONT_AWESOME_DIR.'/css/lib/font-awesome.min.css');
|
||||
}*/
|
||||
Requirements::set_force_js_to_bottom(true);
|
||||
|
||||
// Main libs
|
||||
if (!$config['nojquery']) {
|
||||
self::loadJS(
|
||||
'//ajax.googleapis.com/ajax/libs/jquery/'
|
||||
.$config['jquery_version'].'/jquery.min.js'
|
||||
);
|
||||
}
|
||||
// App libs
|
||||
if (!$config['nofontawesome']) {
|
||||
self::loadCSS(
|
||||
'//use.fontawesome.com/releases/v'
|
||||
.$config['fontawesome_version'].'/css/all.css'
|
||||
);
|
||||
}
|
||||
|
||||
Requirements::css(self::_getPath($path));
|
||||
self::loadCSS($mainTheme.'.css');
|
||||
self::loadJS($mainTheme.'.js');
|
||||
|
||||
// Custom controller requirements
|
||||
$curr_class = $class ?: get_class(Controller::curr());
|
||||
if (isset($config['custom_requirements'][$curr_class])) {
|
||||
foreach ($config['custom_requirements'][$curr_class] as $file) {
|
||||
if (strpos($file, '.css')) {
|
||||
self::loadCSS($file);
|
||||
}
|
||||
if (strpos($file, '.js')) {
|
||||
self::loadJS($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$curr_class = str_replace('\\', '.', $curr_class);
|
||||
|
||||
// Controller requirements
|
||||
$themePath = Path::join($cssPath, $mainTheme.'_'.$curr_class . '.css');
|
||||
$projectPath = Path::join($cssPath, $projectName.'_'.$curr_class . '.css');
|
||||
if ($mainTheme && file_exists($themePath)) {
|
||||
self::loadCSS($mainTheme.'_'.$curr_class . '.css');
|
||||
} elseif (file_exists($projectPath)) {
|
||||
self::loadCSS($projectName.'_'.$curr_class . '.css');
|
||||
}
|
||||
|
||||
$themePath = Path::join($jsPath, $mainTheme.'_'.$curr_class . '.js');
|
||||
$projectPath = Path::join($jsPath, $projectName.'_'.$curr_class . '.js');
|
||||
if ($mainTheme && file_exists($themePath)) {
|
||||
self::loadJS($mainTheme.'_'.$curr_class . '.js');
|
||||
} elseif (file_exists($projectPath)) {
|
||||
self::loadJS($projectName.'_'.$curr_class . '.js');
|
||||
}
|
||||
|
||||
return self::forTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load JS file
|
||||
* @param $path
|
||||
*/
|
||||
public static function loadJS($path): void
|
||||
public static function loadCSS($css): void
|
||||
{
|
||||
Requirements::javascript(self::_getPath($path), ['type' => '']);
|
||||
$external = (mb_strpos($css, '//') === 0 || mb_strpos($css, 'http') === 0);
|
||||
if ($external || (self::getDeferred() && !self::_webpackActive())) {
|
||||
self::$css[] = $css;
|
||||
} else {
|
||||
WebpackTemplateProvider::loadCSS($css);
|
||||
}
|
||||
}
|
||||
|
||||
public static function projectName(): string
|
||||
public static function loadJS($js): void
|
||||
{
|
||||
return Config::inst()->get(ModuleManifest::class, 'project');
|
||||
/*$external = (mb_substr($js, 0, 2) === '//' || mb_substr($js, 0, 4) === 'http');
|
||||
if ($external || (self::getDeferred() && !self::_webpackActive())) {*/
|
||||
// webpack supposed to load external JS
|
||||
if (self::getDeferred() && !self::_webpackActive()) {
|
||||
self::$js[] = $js;
|
||||
} else {
|
||||
WebpackTemplateProvider::loadJS($js);
|
||||
}
|
||||
}
|
||||
|
||||
public static function mainTheme()
|
||||
protected static function _webpackActive(): bool
|
||||
{
|
||||
$themes = Config::inst()->get(SSViewer::class, 'themes');
|
||||
return is_array($themes) && $themes[0] !== '$public' && $themes[0] !== '$default' ? $themes[0] : false;
|
||||
return WebpackTemplateProvider::isActive();
|
||||
}
|
||||
|
||||
public static function resourcesURL($link = null): string
|
||||
public static function setDeferred($bool): void
|
||||
{
|
||||
return Controller::join_links(Director::baseURL(), '/resources/'.self::projectName().'/client/dist/img/', $link);
|
||||
Config::inst()->set(__CLASS__, 'deferred', $bool);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if dev mode is enabled and if webpack server is online
|
||||
* @return bool
|
||||
*/
|
||||
public static function isActive(): bool
|
||||
public static function getDeferred(): bool
|
||||
{
|
||||
$cfg = self::config();
|
||||
return Director::isDev() && @fsockopen(
|
||||
$cfg['HOSTNAME'],
|
||||
$cfg['PORT']
|
||||
);
|
||||
return self::config()['deferred'];
|
||||
}
|
||||
|
||||
protected static function _getPath($path): string
|
||||
public static function forTemplate(): string
|
||||
{
|
||||
return self::isActive() && strpos($path, '//') === false ?
|
||||
self::_toDevServerPath($path) :
|
||||
self::toPublicPath($path);
|
||||
$result = '';
|
||||
self::$css = array_unique(self::$css);
|
||||
foreach (self::$css as $css) {
|
||||
$result .= '<i class="defer-cs" data-load="' . self::get_url($css) . '"></i>';
|
||||
}
|
||||
|
||||
self::$js = array_unique(self::$js);
|
||||
foreach (self::$js as $js) {
|
||||
$result .= '<i class="defer-sc" data-load="' . self::get_url($js) . '"></i>';
|
||||
}
|
||||
|
||||
$result .=
|
||||
'<script>function lsc(a,b){var c=document.createElement("script");c.readyState'
|
||||
.'?c.onreadystatechange=function(){"loaded"!=c.readyState&&"complete"!=c.readyState||(c.onreadystatechange=null,b())}'
|
||||
.':c.onload=function(){b()},c.src=a,document.getElementsByTagName("body")[0].appendChild(c)}'
|
||||
.'function lscd(a){a<s.length-1&&(a++,lsc(s.item(a).getAttribute("data-load"),function(){lscd(a)}))}'
|
||||
.'for(var s=document.getElementsByClassName("defer-cs"),i=0;i<s.length;i++){var b=document.createElement("link");b.rel="stylesheet",'
|
||||
.'b.type="text/css",b.href=s.item(i).getAttribute("data-load"),b.media="all";var c=document.getElementsByTagName("body")[0];'
|
||||
.'c.appendChild(b)}var s=document.getElementsByClassName("defer-sc"),i=0;if(s.item(i)!==null)lsc(s.item(i).getAttribute("data-load"),function(){lscd(i)});'
|
||||
.'</script>';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected static function _toDevServerPath($path): string
|
||||
private static function get_url($url): string
|
||||
{
|
||||
$cfg = self::config();
|
||||
return sprintf(
|
||||
'%s%s:%s/%s',
|
||||
Director::protocol(),
|
||||
$cfg['HOSTNAME'],
|
||||
$cfg['PORT'],
|
||||
basename($path)
|
||||
);
|
||||
}
|
||||
$config = self::config();
|
||||
|
||||
public static function toPublicPath($path): string
|
||||
{
|
||||
$cfg = self::config();
|
||||
return strpos($path, '//') === false ?
|
||||
Controller::join_links(
|
||||
RESOURCES_DIR,
|
||||
self::projectName(),
|
||||
$cfg['DIST'],
|
||||
(strpos($path, '.css') ? 'css' : 'js'),
|
||||
$path
|
||||
)
|
||||
: $path;
|
||||
// external URL
|
||||
if (strpos($url, '//') !== false) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$path = WebpackTemplateProvider::toPublicPath($url);
|
||||
|
||||
$absolutePath = Director::getAbsFile($path);
|
||||
$hash = sha1_file($absolutePath);
|
||||
|
||||
$version = $config['version'] ? '&v='.$config['version'] : '';
|
||||
//$static_domain = $config['static_domain'];
|
||||
//$static_domain = $static_domain ?: '';
|
||||
|
||||
return Controller::join_links(WebpackTemplateProvider::toPublicPath($url), '?m='.$hash.$version);
|
||||
}
|
||||
|
||||
public static function config(): array
|
||||
|
37
app/src/Widgets/ContentWidget.php
Normal file
37
app/src/Widgets/ContentWidget.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Site\Widgets;
|
||||
|
||||
use Sheadawson\Linkable\Forms\LinkField;
|
||||
use Sheadawson\Linkable\Models\Link;
|
||||
use SilverStripe\AssetAdmin\Forms\UploadField;
|
||||
use SilverStripe\Assets\Image;
|
||||
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
|
||||
use SilverStripe\Widgets\Model\Widget;
|
||||
|
||||
if (!class_exists(Widget::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
class ContentWidget extends Widget
|
||||
{
|
||||
private static $title = 'Content';
|
||||
private static $cmsTitle = 'Content';
|
||||
private static $description = 'Shows text content.';
|
||||
private static $icon = '<i class="icon font-icon-block-content"></i>';
|
||||
private static $table_name = 'ContentWidget';
|
||||
|
||||
private static $db = [
|
||||
'Text' => 'HTMLText',
|
||||
];
|
||||
|
||||
public function getCMSFields()
|
||||
{
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->push(HTMLEditorField::create('Text'));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
60
app/src/Widgets/ElementWidget.php
Normal file
60
app/src/Widgets/ElementWidget.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Site\Widgets;
|
||||
|
||||
use DNADesign\Elemental\Models\BaseElement;
|
||||
use DNADesign\ElementalList\Model\ElementList;
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\Forms\TreeDropdownField;
|
||||
use SilverStripe\Widgets\Model\Widget;
|
||||
|
||||
if (!class_exists(Widget::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
class ElementWidget extends Widget
|
||||
{
|
||||
private static $title = 'Virtual Element';
|
||||
private static $cmsTitle = 'Virtual Element';
|
||||
private static $description = 'Adds existing element to side bar';
|
||||
private static $icon = '<i class="icon font-icon-block-banner"></i>';
|
||||
private static $table_name = 'ElementWidget';
|
||||
|
||||
private static $has_one = [
|
||||
'Element' => BaseElement::class,
|
||||
];
|
||||
|
||||
public function getCMSFields()
|
||||
{
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$fields->push(
|
||||
DropdownField::create(
|
||||
'ElementID',
|
||||
'Displayed Element',
|
||||
BaseElement::get()
|
||||
->filter(['AvailableGlobally' => true])
|
||||
->exclude(['ClassName' => ElementList::class])
|
||||
)
|
||||
/*TreeDropdownField::create(
|
||||
'ElementID',
|
||||
'Displayed Element',
|
||||
SiteTree::class
|
||||
)->setFilterFunction(static function($el){
|
||||
return (bool) $el->getField('ElementalArea')->Elements()->count();
|
||||
})*/
|
||||
);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function SimpleClassName()
|
||||
{
|
||||
$el = $this->getField('Element');
|
||||
var_dump($el);
|
||||
die();
|
||||
return $el->getSimpleClassName();
|
||||
}
|
||||
}
|
@ -3,10 +3,6 @@
|
||||
|
||||
namespace Site\Widgets;
|
||||
|
||||
use Sheadawson\Linkable\Forms\LinkField;
|
||||
use Sheadawson\Linkable\Models\Link;
|
||||
use SilverStripe\AssetAdmin\Forms\UploadField;
|
||||
use SilverStripe\Assets\Image;
|
||||
use SilverStripe\Widgets\Model\Widget;
|
||||
|
||||
if (!class_exists(Widget::class)) {
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
namespace Site\Widgets;
|
||||
|
||||
|
||||
use DNADesign\Elemental\Controllers\ElementalAreaController;
|
||||
use DNADesign\Elemental\Forms\ElementalAreaConfig;
|
||||
use DNADesign\Elemental\Forms\ElementalAreaField;
|
||||
@ -67,10 +66,10 @@ class WidgetAreaField extends GridField
|
||||
'Title' => 'Title',
|
||||
'Enabled' => 'Enabled',
|
||||
])->setFieldFormatting([
|
||||
'Icon' => static function($v, Widget $item) {
|
||||
'Icon' => static function ($v, Widget $item) {
|
||||
return '<span style="font-size:2rem">'.$item::config()->get('icon').'</span>';
|
||||
},
|
||||
'Enabled' => static function($v, Widget $item) {
|
||||
'Enabled' => static function ($v, Widget $item) {
|
||||
return $item->getField('Enabled') ? 'Yes' : 'No';
|
||||
},
|
||||
]);
|
||||
@ -141,7 +140,7 @@ class WidgetAreaField extends GridField
|
||||
// Extract the ID
|
||||
$elementId = (int) substr($form, $idPrefixLength);
|
||||
|
||||
/** @var BaseElement $element */
|
||||
// @var BaseElement $element
|
||||
$element = $this->getArea()->Widgets()->byID($elementId);
|
||||
|
||||
if (!$element) {
|
||||
|
@ -3,11 +3,11 @@
|
||||
|
||||
namespace Site\Widgets;
|
||||
|
||||
|
||||
use DNADesign\Elemental\Forms\ElementalAreaField;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Widgets\Forms\WidgetAreaEditor;
|
||||
use SilverStripe\Widgets\Model\Widget;
|
||||
use SilverStripe\Widgets\Model\WidgetArea;
|
||||
|
||||
class WidgetPageExtension extends \SilverStripe\Widgets\Extensions\WidgetPageExtension
|
||||
{
|
||||
@ -34,4 +34,16 @@ class WidgetPageExtension extends \SilverStripe\Widgets\Extensions\WidgetPageExt
|
||||
$available
|
||||
));
|
||||
}
|
||||
|
||||
public function onBeforeWrite()
|
||||
{
|
||||
parent::onBeforeWrite();
|
||||
|
||||
if (!$this->owner->getField('SideBarID')) {
|
||||
$area = WidgetArea::create();
|
||||
$area->write();
|
||||
|
||||
$this->owner->setField('SideBarID', $area->ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,19 +8,17 @@
|
||||
|
||||
<% if $ShowTitle || $Content || $ImageLink %>
|
||||
<div class="image-element__caption img-content">
|
||||
<div class="container">
|
||||
<% if $ShowTitle %><h3 class="image-element__title title">$Title</h3><% end_if %>
|
||||
<% if $ShowTitle %><h3 class="image-element__title title">$Title</h3><% end_if %>
|
||||
|
||||
<% if $Content %>
|
||||
<div class="image-element__content typography">$Content</div>
|
||||
<% end_if %>
|
||||
<% if $Content %>
|
||||
<div class="image-element__content typography">$Content</div>
|
||||
<% end_if %>
|
||||
|
||||
<% if $ImageLink %>
|
||||
<a href="$ImageLink.URL" class="image-element__btn btn btn-default">
|
||||
$ImageLink.Title
|
||||
<i class="fas fa-caret-right"></i>
|
||||
</a>
|
||||
<% end_if %>
|
||||
</div>
|
||||
<% if $ImageLink %>
|
||||
<a href="$ImageLink.URL" class="image-element__btn btn btn-default">
|
||||
$ImageLink.Title
|
||||
<i class="fas fa-caret-right"></i>
|
||||
</a>
|
||||
<% end_if %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
@ -1,23 +1,49 @@
|
||||
<div class="page-content">
|
||||
<h1 class="element page-header $DefaultContainer<% if $ElementalArea.Elements.Count < 1 %> no-elements<% end_if %>">
|
||||
$Title
|
||||
</h1>
|
||||
<div class="page-content page-content-main">
|
||||
<div class="
|
||||
element
|
||||
page-header-element
|
||||
<% if $ElementalArea.Elements.Count < 1 %>
|
||||
d-block no-elements
|
||||
<% else_if not $ElementalArea.Elements.First.ShowTitle && $ElementalArea.Elements.First.ClassName != Site\Elements\SliderElement %>
|
||||
d-block
|
||||
<% end_if %>
|
||||
">
|
||||
<div class="$DefaultContainer">
|
||||
<h1 class="page-header">
|
||||
$Title
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if $CurrentElement %>
|
||||
$CurrentElement
|
||||
<div class="current-element">
|
||||
$CurrentElement
|
||||
</div>
|
||||
<% else %>
|
||||
$ElementalArea
|
||||
<div class="elemental-area">
|
||||
$ElementalArea
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
<% if $Form %>
|
||||
<div class="element $DefaultContainer">
|
||||
$Form
|
||||
<div class="page-form-element element">
|
||||
<div class="element_container">
|
||||
<div class="$DefaultContainer">
|
||||
$Form
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
<% if $ExtraCode %>
|
||||
<div class="element $DefaultContainer extra-code extra-code-page">
|
||||
$ExtraCode
|
||||
<div class="page-extra-code">
|
||||
<div class="element">
|
||||
<div class="element_container">
|
||||
<div class="$DefaultContainer">
|
||||
$ExtraCode
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end_if %>
|
||||
</div>
|
||||
|
@ -13,5 +13,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<% if $isDev || $WebpackActive %>
|
||||
<div id="DevOriginal"></div>
|
||||
<% end_if %>
|
||||
|
||||
<%-- Site Wide Alert Message --%>
|
||||
<% include SiteWideMessage %>
|
||||
|
@ -1,34 +1,36 @@
|
||||
<% with $SiteConfig %>
|
||||
<div class="wrapper">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<a href="/" class="logo2">
|
||||
<img src="$ResourcesURL('logo2.png')" alt="{$Title}" />
|
||||
</a>
|
||||
<div class="element">
|
||||
<div class="footer__container $Top.DefaultContainer">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<a href="/" class="logo2">
|
||||
<img src="$ResourcesURL('logo2.png')" alt="{$Title}" />
|
||||
</a>
|
||||
|
||||
<div class="field">
|
||||
<div class="fn">$Title</div>
|
||||
<address>
|
||||
$Address<br/>
|
||||
$Suburb, $State $ZipCode
|
||||
</address>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
T: $PhoneNumber
|
||||
</div>
|
||||
|
||||
<% if $PublicEmail %>
|
||||
<div class="field">
|
||||
E: $PublicEmail
|
||||
<div class="fn">$Title</div>
|
||||
<address>
|
||||
$Address<br/>
|
||||
$Suburb, $State $ZipCode
|
||||
</address>
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
<% include Objects\SocialLinks %>
|
||||
</div>
|
||||
<div class="col-sm-6 text-right">
|
||||
<div class="field">
|
||||
T: $PhoneNumber
|
||||
</div>
|
||||
|
||||
<% if $PublicEmail %>
|
||||
<div class="field">
|
||||
E: $PublicEmail
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
<% include Objects\SocialLinks %>
|
||||
</div>
|
||||
<div class="col-sm-6 text-right">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,35 +1,29 @@
|
||||
<div class="element">
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<a id="Logo" href="/"><img src="{$ResourcesURL('logo.png')}" alt="{$SiteConfig.Title}" /></a>
|
||||
</div>
|
||||
<div class="col-sm-8 text-right">
|
||||
<div class="btn-group btn-group-lg" role="group">
|
||||
<a href="#" class="btn btn-success">Contact</a>
|
||||
<a href="#" class="btn btn-warning">Donate</a>
|
||||
<a href="#" class="btn btn-secondary">
|
||||
<i class="fas fa-search"></i>
|
||||
<span class="sr-only">Search</span>
|
||||
</a>
|
||||
<div class="element__container $DefaultContainer">
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<a id="Logo" href="/"><img src="{$ResourcesURL('logo.png')}" alt="{$SiteConfig.Title}" /></a>
|
||||
</div>
|
||||
<% with $SiteConfig %>
|
||||
<% if $PhoneNumber %>
|
||||
<span class="phone-number">
|
||||
$PhoneNumber
|
||||
</span>
|
||||
<div class="col-sm-8 text-right">
|
||||
<% with $SiteConfig %>
|
||||
<% if $PhoneNumber %>
|
||||
<span class="phone-number">
|
||||
$PhoneNumber
|
||||
</span>
|
||||
<% end_if %>
|
||||
<% if $PublicEmail %>
|
||||
<span class="public-email">
|
||||
$PublicEmail
|
||||
</span>
|
||||
<% end_if %>
|
||||
<% end_with %>
|
||||
<%-- if $SearchForm %>
|
||||
<div id="SearchFormContainer">$SearchForm</div>
|
||||
<% end_if --%>
|
||||
<% if $SiteConfig.Navigation %>
|
||||
<% include Navigation Navigation=$SiteConfig.Navigation, NavID="Navigation" %>
|
||||
<% end_if %>
|
||||
<% if $PublicEmail %>
|
||||
<span class="public-email">
|
||||
$PublicEmail
|
||||
</span>
|
||||
<% end_if %>
|
||||
<% end_with %>
|
||||
<%-- if $SearchForm %>
|
||||
<div id="SearchFormContainer">$SearchForm</div>
|
||||
<% end_if --%>
|
||||
<% if $SiteConfig.Navigation %>
|
||||
<% include Navigation Navigation=$SiteConfig.Navigation, NavID="Navigation" %>
|
||||
<% end_if %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -32,6 +32,8 @@ $MetaTags
|
||||
<link rel="author" type="text/plain" href="{$AbsoluteBaseURL}humans.txt" />
|
||||
<link rel="sitemap" type="application/xml" title="Sitemap" href="{$AbsoluteBaseURL}sitemap.xml" />
|
||||
|
||||
|
||||
<link rel="preconnect" href="https://use.fontawesome.com/" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link rel="preconnect" href="https://maps.google.com" />
|
||||
<link rel="preconnect" href="https://ajax.googleapis.com" />
|
||||
|
@ -4,7 +4,8 @@
|
||||
class="nav-link dropdown-toggle"
|
||||
id="NavItem{$ID}"
|
||||
role="button"
|
||||
data-toggle="dropdown"
|
||||
data-toggle="hover"
|
||||
data-allow-click="true"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
href="{$Link}"
|
||||
|
@ -1,30 +1,30 @@
|
||||
<div class="sc-links">
|
||||
<% if $Facebook %>
|
||||
<a href="$Facebook.URL" title="Facebook" target="_blank">
|
||||
<a href="$Facebook.LinkURL" title="Facebook" target="_blank">
|
||||
<i class="fab fa-facebook"></i>
|
||||
<i class="sr-only">Facebook</i>
|
||||
</a>
|
||||
<% end_if %>
|
||||
<% if $LinkedIn %>
|
||||
<a href="$LinkedIn.URL" title="LinkedIn" target="_blank">
|
||||
<a href="$LinkedIn.LinkURL" title="LinkedIn" target="_blank">
|
||||
<i class="fab fa-linkedin"></i>
|
||||
<i class="sr-only">LinkedIn</i>
|
||||
</a>
|
||||
<% end_if %>
|
||||
<% if $GooglePlus %>
|
||||
<a href="$GooglePlus.URL" title="Google+" target="_blank">
|
||||
<a href="$GooglePlus.LinkURL" title="Google+" target="_blank">
|
||||
<i class="fab fa-google-plus-g"></i>
|
||||
<i class="sr-only">Google+</i>
|
||||
</a>
|
||||
<% end_if %>
|
||||
<% if $Instagram %>
|
||||
<a href="$Instagram.URL" title="Instagram" target="_blank">
|
||||
<a href="$Instagram.LinkURL" title="Instagram" target="_blank">
|
||||
<i class="fab fa-instagram"></i>
|
||||
<i class="sr-only">Instagram</i>
|
||||
</a>
|
||||
<% end_if %>
|
||||
<% if $Twitter %>
|
||||
<a href="$Twitter.URL" title="Twitter" target="_blank">
|
||||
<a href="$Twitter.LinkURL" title="Twitter" target="_blank">
|
||||
<i class="fab fa-twitter"></i>
|
||||
<i class="sr-only">Twitter</i>
|
||||
</a>
|
||||
|
@ -10,31 +10,49 @@
|
||||
|
||||
<div class="wrapper">
|
||||
<header id="Header">
|
||||
<div class="$DefaultContainer">
|
||||
<% include Header %>
|
||||
</div>
|
||||
<% include Header %>
|
||||
</header>
|
||||
|
||||
<main id="MainContent" data-ajax-region="LayoutAjax">
|
||||
<% if $ParentID %>
|
||||
$Breadcrumbs
|
||||
<div id="PageBreadcumbs">
|
||||
$Breadcrumbs
|
||||
</div>
|
||||
<% else_if $ClassName != 'Site\Pages\HomePage' %>
|
||||
<div id="PageBreadcumbs">
|
||||
<nav class="breadcrumbs $DefaultContainer" aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="/">Home</a>
|
||||
</li>
|
||||
|
||||
<li class="breadcrumb-item current active" aria-current="page">
|
||||
<a href="$Link" class="breadcrumb-2">
|
||||
$MenuTitle
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
<% if $SideBarView && $SideBarView.Widgets.Count %>
|
||||
<div class="$DefaultContainer">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
$Layout
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="sidebar page-content">
|
||||
$SideBarView
|
||||
<div class="content-holder">
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
$Layout
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="page-content-sidebar page-content">
|
||||
$SideBarView
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="content-holder">
|
||||
$Layout
|
||||
</div>
|
||||
<% end_if %>
|
||||
</main>
|
||||
</div>
|
||||
|
@ -4,13 +4,13 @@
|
||||
<% if $Address2 %>
|
||||
<div class="addr2">{$Address2}</div>
|
||||
<% end_if %>
|
||||
<% if $City || $PostalCode %>
|
||||
<% if $City || $Suburb || $PostalCode || $Postcode %>
|
||||
<div class="city">
|
||||
{$City}, {$State} {$PostalCode}
|
||||
{$City}{$Suburb}, {$State} {$PostalCode}{$Postcode}
|
||||
</div>
|
||||
<% end_if %>
|
||||
<% if $Country %>
|
||||
<div class="d-none">{$Country}</div>
|
||||
<div class="country d-none">{$Country}</div>
|
||||
<% end_if %>
|
||||
<% if $PhoneNumber %>
|
||||
<% with $PhoneNumber %>
|
||||
|
3
app/templates/Site/Widgets/ContentWidget.ss
Normal file
3
app/templates/Site/Widgets/ContentWidget.ss
Normal file
@ -0,0 +1,3 @@
|
||||
<% if $Text %>
|
||||
<div class="typography">$Text</div>
|
||||
<% end_if %>
|
9
app/templates/Site/Widgets/ElementWidget.ss
Normal file
9
app/templates/Site/Widgets/ElementWidget.ss
Normal file
@ -0,0 +1,9 @@
|
||||
<% if $Element %>
|
||||
<% with $Element %>
|
||||
<div class="element $SimpleClassName.LowerCase<% if $StyleVariant %> $StyleVariant<% end_if %><% if $ExtraClass %> $ExtraClass<% end_if %>" id="$Anchor">
|
||||
<div class="element-container<% if $ContainerClass %> $ContainerClass<% end_if %>">
|
||||
$forTemplate
|
||||
</div>
|
||||
</div>
|
||||
<% end_with %>
|
||||
<% end_if %>
|
@ -1,6 +1,15 @@
|
||||
<% if $Submenu %>
|
||||
<nav>
|
||||
<ul class="nav flex-column">
|
||||
<% with $Page.Level(1) %>
|
||||
<li class="nav-item-level1 nav-item {$CSSClass} $ExtraClass <% if $isCurrent || $isSection %> active<% end_if %>">
|
||||
<b class="nav-link">
|
||||
$MenuTitle.XML
|
||||
<% if $isCurrent || $isSection %><i class="sr-only">(current)</i><% end_if %>
|
||||
</b>
|
||||
</li>
|
||||
<% end_with %>
|
||||
|
||||
<% loop $Submenu %>
|
||||
<% include NavItem %>
|
||||
<% end_loop %>
|
||||
|
@ -69,6 +69,11 @@
|
||||
"foundation-emails": "^2.2.1",
|
||||
"gijgo": "^1.9.13",
|
||||
"html-webpack-plugin": "^4.0.0-beta.11",
|
||||
"imagemin-gifsicle": "^7.0.0",
|
||||
"imagemin-jpegtran": "^6.0.0",
|
||||
"imagemin-optipng": "^7.1.0",
|
||||
"imagemin-svgo": "^7.0.0",
|
||||
"imagemin-webpack": "^5.1.1",
|
||||
"jquery": "^3.4.1",
|
||||
"jquery-hammerjs": "^2.0.0",
|
||||
"jquery-hoverintent": "*",
|
||||
|
@ -17,20 +17,21 @@ const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
|
||||
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const ImageminPlugin = require('imagemin-webpack');
|
||||
|
||||
let plugins = [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
'NODE_ENV': JSON.stringify('production')
|
||||
}
|
||||
NODE_ENV: JSON.stringify('production'),
|
||||
},
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: true,
|
||||
debug: false
|
||||
debug: false,
|
||||
}),
|
||||
new ExtractTextPlugin({
|
||||
filename: 'css/[name].css',
|
||||
allChunks: true
|
||||
allChunks: true,
|
||||
}),
|
||||
|
||||
new FaviconsWebpackPlugin({
|
||||
@ -51,8 +52,8 @@ let plugins = [
|
||||
opengraph: true,
|
||||
twitter: true,
|
||||
yandex: true,
|
||||
windows: true
|
||||
}
|
||||
windows: true,
|
||||
},
|
||||
}),
|
||||
new OptimizeCssAssetsPlugin({
|
||||
//assetNameRegExp: /\.optimize\.css$/g,
|
||||
@ -71,38 +72,73 @@ let plugins = [
|
||||
discardOverridden: true,
|
||||
discardDuplicates: true,
|
||||
discardComments: {
|
||||
removeAll: true
|
||||
removeAll: true,
|
||||
},
|
||||
},
|
||||
canPrint: true
|
||||
canPrint: true,
|
||||
}),
|
||||
new ImageminPlugin({
|
||||
bail: false, // Ignore errors on corrupted images
|
||||
cache: true,
|
||||
filter: (source, sourcePath) => {
|
||||
if (source.byteLength < 512000) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
imageminOptions: {
|
||||
plugins: [
|
||||
['gifsicle', { interlaced: true }],
|
||||
['jpegtran', { progressive: true }],
|
||||
['optipng', { optimizationLevel: 5 }],
|
||||
[
|
||||
'svgo',
|
||||
{
|
||||
plugins: [
|
||||
{
|
||||
removeViewBox: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
// add themes favicons
|
||||
commonVariables.themes.forEach((theme) => {
|
||||
commonVariables.themes.forEach(theme => {
|
||||
const faviconPath = path.join(__dirname, theme, conf.SRC, 'favicon.png');
|
||||
if (filesystem.existsSync(faviconPath)) {
|
||||
plugins.push(new FaviconsWebpackPlugin({
|
||||
title: 'Webpack App',
|
||||
logo: faviconPath,
|
||||
prefix: '/' + theme + '-icons/',
|
||||
emitStats: false,
|
||||
persistentCache: true,
|
||||
inject: false,
|
||||
statsFilename: path.join(conf.APPDIR, conf.DIST, theme + '-icons', 'iconstats.json'),
|
||||
icons: {
|
||||
android: true,
|
||||
appleIcon: true,
|
||||
appleStartup: true,
|
||||
coast: true,
|
||||
favicons: true,
|
||||
firefox: true,
|
||||
opengraph: true,
|
||||
twitter: true,
|
||||
yandex: true,
|
||||
windows: true
|
||||
}
|
||||
}));
|
||||
plugins.push(
|
||||
new FaviconsWebpackPlugin({
|
||||
title: 'Webpack App',
|
||||
logo: faviconPath,
|
||||
prefix: '/' + theme + '-icons/',
|
||||
emitStats: false,
|
||||
persistentCache: true,
|
||||
inject: false,
|
||||
statsFilename: path.join(
|
||||
conf.APPDIR,
|
||||
conf.DIST,
|
||||
theme + '-icons',
|
||||
'iconstats.json',
|
||||
),
|
||||
icons: {
|
||||
android: true,
|
||||
appleIcon: true,
|
||||
appleStartup: true,
|
||||
coast: true,
|
||||
favicons: true,
|
||||
firefox: true,
|
||||
opengraph: true,
|
||||
twitter: true,
|
||||
yandex: true,
|
||||
windows: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@ -110,9 +146,10 @@ module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
optimization: {
|
||||
namedModules: true, // NamedModulesPlugin()
|
||||
splitChunks: { // CommonsChunkPlugin()
|
||||
splitChunks: {
|
||||
// CommonsChunkPlugin()
|
||||
name: 'vendor',
|
||||
minChunks: 2
|
||||
minChunks: 2,
|
||||
},
|
||||
noEmitOnErrors: true, // NoEmitOnErrorsPlugin
|
||||
concatenateModules: true, //ModuleConcatenationPlugin
|
||||
@ -129,7 +166,7 @@ module.exports = merge(common, {
|
||||
},
|
||||
},
|
||||
}),
|
||||
]
|
||||
],
|
||||
},
|
||||
|
||||
devtool: '',
|
||||
@ -141,66 +178,78 @@ module.exports = merge(common, {
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.s?css$/,
|
||||
use: ExtractTextPlugin.extract({
|
||||
fallback: "style-loader",
|
||||
use: [{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
sourceMap: false
|
||||
}
|
||||
}, {
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
sourceMap: false,
|
||||
plugins: [
|
||||
autoprefixer()
|
||||
]
|
||||
}
|
||||
}, {
|
||||
loader: 'resolve-url-loader'
|
||||
}, {
|
||||
loader: 'sass-loader',
|
||||
options: {
|
||||
sourceMap: false
|
||||
}
|
||||
}, ]
|
||||
})
|
||||
}, {
|
||||
test: /fontawesome([^.]+).(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
|
||||
use: [{
|
||||
rules: [
|
||||
{
|
||||
test: /\.s?css$/,
|
||||
use: ExtractTextPlugin.extract({
|
||||
fallback: 'style-loader',
|
||||
use: [
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
sourceMap: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
sourceMap: false,
|
||||
plugins: [autoprefixer()],
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'resolve-url-loader',
|
||||
},
|
||||
{
|
||||
loader: 'sass-loader',
|
||||
options: {
|
||||
sourceMap: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /fontawesome([^.]+).(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'fonts/',
|
||||
publicPath: '../fonts/',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|otf|eot|svg|woff(2)?)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'fonts/',
|
||||
publicPath: '../fonts/',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|jpeg|gif|svg)$/,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'fonts/',
|
||||
publicPath: '../fonts/'
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
test: /\.(ttf|otf|eot|svg|woff(2)?)$/,
|
||||
use: [{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'fonts/',
|
||||
publicPath: '../fonts/'
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
test: /\.(png|jpg|jpeg|gif|svg)$/,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'img/',
|
||||
publicPath: '../img/'
|
||||
outputPath: 'img/',
|
||||
publicPath: '../img/',
|
||||
/*,
|
||||
name(file) {
|
||||
//return 'public/[path][name].[ext]';
|
||||
return '[hash].[ext]';
|
||||
},*/
|
||||
},
|
||||
},
|
||||
}, ]
|
||||
],
|
||||
},
|
||||
|
||||
plugins: plugins,
|
||||
|
Loading…
Reference in New Issue
Block a user