mirror of
https://github.com/a2nt/silverstripe-webpack.git
synced 2024-10-22 17:05:31 +02:00
JS improvements
This commit is contained in:
parent
4231243674
commit
18af5420d5
@ -26,6 +26,7 @@ SilverStripe\CMS\Model\SiteTree:
|
|||||||
- Dynamic\Elements\Elements\ElementTestimonials
|
- Dynamic\Elements\Elements\ElementTestimonials
|
||||||
- Site\Elements\TeamMembersElement
|
- Site\Elements\TeamMembersElement
|
||||||
- Site\Elements\SliderElement
|
- Site\Elements\SliderElement
|
||||||
|
- DNADesign\ElementalVirtual\Model\ElementVirtual
|
||||||
|
|
||||||
DNADesign\ElementalList\Model\ElementList:
|
DNADesign\ElementalList\Model\ElementList:
|
||||||
default_global_elements: false
|
default_global_elements: false
|
||||||
|
@ -5,7 +5,7 @@ SilverStripe\SiteConfig\SiteConfig:
|
|||||||
|
|
||||||
SilverStripe\SiteTree\SiteTree:
|
SilverStripe\SiteTree\SiteTree:
|
||||||
extensions:
|
extensions:
|
||||||
- SiteTreeExtension
|
- Site\Extensions\SiteTreeExtension
|
||||||
|
|
||||||
SilverStripe\Blog\Model\BlogPost:
|
SilverStripe\Blog\Model\BlogPost:
|
||||||
extensions:
|
extensions:
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
BetterBrief\GoogleMapField:
|
BetterBrief\GoogleMapField:
|
||||||
default_options:
|
default_options:
|
||||||
api_key: 'YOUR_API_KEY'
|
api_key: 'YOUR_API_KEY'
|
||||||
|
show_search_box: true
|
||||||
|
@ -22,30 +22,77 @@ const FormBasics = (($) => {
|
|||||||
const $fields = $element.find('input,textarea,select');
|
const $fields = $element.find('input,textarea,select');
|
||||||
const $selectFields = $element.find('select:not([readonly])');
|
const $selectFields = $element.find('select:not([readonly])');
|
||||||
const $radioOptions = $element.find('input[type="radio"]');
|
const $radioOptions = $element.find('input[type="radio"]');
|
||||||
|
const separator = ', ';
|
||||||
|
|
||||||
$selectFields.each((i, el) => {
|
$selectFields.each((i, el) => {
|
||||||
const $el = $(el);
|
const $el = $(el);
|
||||||
|
const maxOptions = $el.data('max-options') || false;
|
||||||
|
|
||||||
$el.selectpicker({
|
$el.selectpicker($.extend({
|
||||||
iconBase: 'fas',
|
iconBase: 'fas',
|
||||||
tickIcon: 'fa-check',
|
tickIcon: 'fa-check',
|
||||||
liveSearch: $el.data('live-search'),
|
virtualScroll: false,
|
||||||
noneSelectedText: $el.data('none-selected-text') || 'Nothing selected',
|
dropupAuto: false,
|
||||||
maxOptions: $el.data('max-options') || false,
|
size: 10,
|
||||||
|
maxOptions: maxOptions,
|
||||||
|
}, $el.data(), {
|
||||||
|
multipleSeparator: separator,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// wrap options
|
||||||
|
$el.on('rendered.bs.select', () => {
|
||||||
|
if (!$el.val().length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const $container = $el.parent().find('.filter-option-inner-inner');
|
||||||
|
const val = $container.text();
|
||||||
|
const vals = val.split(separator);
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
vals.forEach((opt) => {
|
||||||
|
const $opt = $el.find('option').filter((i, e) => {
|
||||||
|
return $(e).text() === opt;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
html += '<span class="option" data-val=' + $opt.attr('value') + '>' + opt +
|
||||||
|
' <i class="fas fa-times btn-remove"></i></span>';
|
||||||
|
});
|
||||||
|
|
||||||
|
$container.html(html);
|
||||||
|
|
||||||
|
// remove value
|
||||||
|
$container.find('.option').on('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const $opt = $(e.currentTarget);
|
||||||
|
const val = $opt.data('val').toString();
|
||||||
|
//$opt.remove();
|
||||||
|
|
||||||
|
let vals = $el.selectpicker('val');
|
||||||
|
const i = vals.indexOf(val);
|
||||||
|
if (i > -1) {
|
||||||
|
vals.splice(i, 1);
|
||||||
|
$el.selectpicker('val', vals);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// FIX: hidden picker
|
// FIX: hidden picker
|
||||||
|
$el.selectpicker('render');
|
||||||
|
$el.selectpicker('refresh');
|
||||||
|
$el.selectpicker('toggle');
|
||||||
|
document.activeElement.blur();
|
||||||
|
|
||||||
|
//$el.selectpicker('show');
|
||||||
|
//$el.selectpicker('hide');
|
||||||
|
|
||||||
|
/*$el.parents('.field.dropdown').find('.dropdown-toggle').click();
|
||||||
$el.parents('.field.dropdown').find('.dropdown-toggle').click();
|
$el.parents('.field.dropdown').find('.dropdown-toggle').click();
|
||||||
$el.parents('.field.dropdown').find('.dropdown-toggle').click();
|
$el.parents('.field.dropdown').find('.dropdown-toggle').blur();*/
|
||||||
$el.parents('.field.dropdown').find('.dropdown-toggle').blur();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// FIX: hidden picker click
|
|
||||||
if ($selectFields.length) {
|
|
||||||
setTimeout(() => {
|
|
||||||
$(window).scrollTop(0, 0);
|
|
||||||
}, 600);
|
|
||||||
}
|
|
||||||
|
|
||||||
$fields.each((e, el) => {
|
$fields.each((e, el) => {
|
||||||
const $el = $(el);
|
const $el = $(el);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
|
||||||
|
import MainUI from "../_main";
|
||||||
import Events from '../_events';
|
import Events from '../_events';
|
||||||
import SpinnerUI from './_ui.spinner';
|
import SpinnerUI from './_ui.spinner';
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ const CroppieUI = (($) => {
|
|||||||
const ui = this;
|
const ui = this;
|
||||||
const $el = $(element);
|
const $el = $(element);
|
||||||
|
|
||||||
ui._element = element;
|
ui.$el = $el;
|
||||||
$el.data(DATA_KEY, this);
|
$el.data(DATA_KEY, this);
|
||||||
|
|
||||||
ui.input = $el.find('input[type="file"]');
|
ui.input = $el.find('input[type="file"]');
|
||||||
@ -42,10 +43,14 @@ const CroppieUI = (($) => {
|
|||||||
ui.width = ui.input.data('width');
|
ui.width = ui.input.data('width');
|
||||||
ui.height = ui.input.data('height');
|
ui.height = ui.input.data('height');
|
||||||
|
|
||||||
$el.append('<div class="cropper-wrap"><div class="cropper-container"></div></div>');
|
$el.append(
|
||||||
|
'<div class="cropper-wrap"><div class="cropper-container"></div>' +
|
||||||
|
'<a href="#" class="btn-remove"><i class="fas fa-times"></i> Remove</a></div>'
|
||||||
|
);
|
||||||
//$el.append(ui.inputData);
|
//$el.append(ui.inputData);
|
||||||
|
|
||||||
ui.uploadCrop = $el.find('.cropper-container');
|
ui.uploadCropWrap = $el.find('.cropper-wrap');
|
||||||
|
ui.uploadCrop = ui.uploadCropWrap.find('.cropper-container');
|
||||||
|
|
||||||
const ratio = ui.width / (ui.uploadCrop.width() - 32);
|
const ratio = ui.width / (ui.uploadCrop.width() - 32);
|
||||||
ui.uploadCrop.croppie({
|
ui.uploadCrop.croppie({
|
||||||
@ -62,11 +67,23 @@ const CroppieUI = (($) => {
|
|||||||
ui.input.on('change', (e) => {
|
ui.input.on('change', (e) => {
|
||||||
this.readFile(e.currentTarget);
|
this.readFile(e.currentTarget);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$el.find('.btn-remove').on('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
ui.uploadCrop.removeClass('ready');
|
||||||
|
$el.find('.croppie-image').remove();
|
||||||
|
|
||||||
|
ui.$el.find('input[type="file"]').val('');
|
||||||
|
ui.$el.find('input[type="file"]').change();
|
||||||
|
|
||||||
|
ui.uploadCropWrap.hide();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
readFile(input) {
|
readFile(input) {
|
||||||
const ui = this;
|
const ui = this;
|
||||||
const $el = $(ui._element);
|
const $el = ui.$el;
|
||||||
const $form = $el.closest('form');
|
const $form = $el.closest('form');
|
||||||
|
|
||||||
if (input.files && input.files[0]) {
|
if (input.files && input.files[0]) {
|
||||||
@ -79,6 +96,7 @@ const CroppieUI = (($) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ui.uploadCrop.show();
|
ui.uploadCrop.show();
|
||||||
|
ui.uploadCropWrap.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.readAsDataURL(input.files[0]);
|
reader.readAsDataURL(input.files[0]);
|
||||||
@ -87,6 +105,10 @@ const CroppieUI = (($) => {
|
|||||||
//$(input).val('');
|
//$(input).val('');
|
||||||
SpinnerUI.show();
|
SpinnerUI.show();
|
||||||
|
|
||||||
|
if (!ui.uploadCrop.hasClass('ready')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ui.uploadCrop.croppie('result', {
|
ui.uploadCrop.croppie('result', {
|
||||||
type: 'blob',
|
type: 'blob',
|
||||||
size: {
|
size: {
|
||||||
@ -129,12 +151,24 @@ const CroppieUI = (($) => {
|
|||||||
$form.find('select[name="' + k + '"],input[name="' + k + '"],textarea[name="' + k + '"]').setError(true, json[k]);
|
$form.find('select[name="' + k + '"],input[name="' + k + '"],textarea[name="' + k + '"]').setError(true, json[k]);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
if (typeof json['status'] !== 'undefined' && json['status'] === 'success') {
|
if (typeof json['status'] !== 'undefined') {
|
||||||
|
if (json['status'] === 'success') {
|
||||||
|
MainUI.alert(json['message'], json['status']);
|
||||||
|
|
||||||
if (typeof json['link'] !== 'undefined') {
|
if (typeof json['link'] !== 'undefined') {
|
||||||
|
setTimeout(() => {
|
||||||
G.location = json['link'];
|
G.location = json['link'];
|
||||||
|
}, 2000);
|
||||||
} else {
|
} else {
|
||||||
//G.location.reload(false);
|
//G.location.reload(false);
|
||||||
}
|
}
|
||||||
|
} else if (json['status'] === 'error') {
|
||||||
|
MainUI.alert(json['message'], json['status']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof json['form'] !== 'undefined') {
|
||||||
|
$(form).replaceWith(json['form']);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$(form).replaceWith(data);
|
$(form).replaceWith(data);
|
||||||
|
72
app/client/src/js/_components/_ui.nocaptcha.js
Normal file
72
app/client/src/js/_components/_ui.nocaptcha.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import $ from 'jquery';
|
||||||
|
import Events from '../_events';
|
||||||
|
import Spinner from './_ui.spinner';
|
||||||
|
|
||||||
|
const NoCaptcha = (($) => {
|
||||||
|
// Constants
|
||||||
|
const W = window;
|
||||||
|
const D = document;
|
||||||
|
const $Body = $('body');
|
||||||
|
|
||||||
|
const NAME = 'NoCaptcha';
|
||||||
|
|
||||||
|
class NoCaptcha {
|
||||||
|
static init() {
|
||||||
|
const ui = this;
|
||||||
|
ui.dispose();
|
||||||
|
|
||||||
|
console.log(`Initializing: ${NAME}`);
|
||||||
|
this.renderCaptcha();
|
||||||
|
}
|
||||||
|
|
||||||
|
static dispose() {
|
||||||
|
console.log(`Destroying: ${NAME}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
static renderCaptcha() {
|
||||||
|
console.log(`Rendering Captcha: ${NAME}`);
|
||||||
|
|
||||||
|
if (typeof grecaptcha === 'undefined') {
|
||||||
|
console.log('Captcha API isn\'t available yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
const $_noCaptchaFields = $('.g-recaptcha');
|
||||||
|
|
||||||
|
const submitListener = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
grecaptcha.execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
$_noCaptchaFields.each((i, field) => {
|
||||||
|
const $field = $(field);
|
||||||
|
|
||||||
|
if ($field.data('widgetid')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const $form = $field.data('form') ? $('#' + $field.data('form')) : $field.parents('form');
|
||||||
|
|
||||||
|
//For the invisible captcha we need to setup some callback listeners
|
||||||
|
if ($field.data('size') === 'invisible' && !$field.data('callback')) {
|
||||||
|
$form.on('submit', submitListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
const widget_id = grecaptcha.render(field, $field.data());
|
||||||
|
$field.data('widgetid', widget_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(W).on(`${Events.AJAX}`, () => {
|
||||||
|
NoCaptcha.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
W.NoCaptcha = NoCaptcha;
|
||||||
|
W.noCaptchaFieldRender = NoCaptcha.renderCaptcha;
|
||||||
|
|
||||||
|
return NoCaptcha;
|
||||||
|
})($);
|
||||||
|
|
||||||
|
export default NoCaptcha;
|
105
app/client/src/js/_components/_ui.video.preview.js
Normal file
105
app/client/src/js/_components/_ui.video.preview.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import $ from 'jquery';
|
||||||
|
|
||||||
|
import MainUI from "../_main";
|
||||||
|
import Events from '../_events';
|
||||||
|
import SpinnerUI from './_ui.spinner';
|
||||||
|
|
||||||
|
const VideoPreviewUI = (($) => {
|
||||||
|
|
||||||
|
const NAME = 'jsVideoPreviewUI';
|
||||||
|
const DATA_KEY = NAME;
|
||||||
|
|
||||||
|
const G = window;
|
||||||
|
const D = document;
|
||||||
|
|
||||||
|
class VideoPreviewUI {
|
||||||
|
|
||||||
|
constructor(el) {
|
||||||
|
console.log(`Initializing: ${NAME}`);
|
||||||
|
|
||||||
|
const ui = this;
|
||||||
|
ui.$_el = $(el);
|
||||||
|
ui.innerHTML = ui.$_el[0].innerHTML;
|
||||||
|
|
||||||
|
ui.$_el.data(DATA_KEY, this);
|
||||||
|
const href = ui.$_el.attr('href') || ui.$_el.data('href');
|
||||||
|
let video;
|
||||||
|
|
||||||
|
if (video = href.match(/(youtube|youtube-nocookie|youtu|vimeo)\.(com|be)\/(watch\?v=([\w-]+)|([\w-]+))/)) {
|
||||||
|
let video_id;
|
||||||
|
|
||||||
|
if (video[1] === 'youtube' || video[1] === 'youtube-nocookie') {
|
||||||
|
video_id = video[4];
|
||||||
|
}
|
||||||
|
if (video[1] === 'youtu') {
|
||||||
|
video_id = video[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (video[1] == 'vimeo') {
|
||||||
|
video_id = video[3];
|
||||||
|
ui.$_el.addClass('loading');
|
||||||
|
$.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url: 'https://vimeo.com/api/v2/video/' + video_id + '.json',
|
||||||
|
jsonp: 'callback',
|
||||||
|
dataType: 'jsonp',
|
||||||
|
success: function(data) {
|
||||||
|
const thumbnail_src = data[0].thumbnail_large;
|
||||||
|
ui.show(thumbnail_src);
|
||||||
|
ui.$_el.removeClass('loading');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (video_id) {
|
||||||
|
ui.show(`//i3.ytimg.com/vi/${video_id}/0.jpg`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
show(src) {
|
||||||
|
const ui = this;
|
||||||
|
ui.$_el[0].innerHTML = '';
|
||||||
|
ui.$_el.append(`<img src="${src}" alt="Video" />`);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dispose() {
|
||||||
|
console.log(`Destroying: ${NAME}`);
|
||||||
|
ui.$_el[0].innerHTML = ui.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _jQueryInterface() {
|
||||||
|
return this.each((i, el) => {
|
||||||
|
// attach functionality to element
|
||||||
|
const $el = $(el);
|
||||||
|
let data = $el.data(DATA_KEY);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
data = new VideoPreviewUI(el);
|
||||||
|
$el.data(DATA_KEY, data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// jQuery interface
|
||||||
|
$.fn[NAME] = VideoPreviewUI._jQueryInterface;
|
||||||
|
$.fn[NAME].Constructor = VideoPreviewUI;
|
||||||
|
$.fn[NAME].noConflict = () => {
|
||||||
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
||||||
|
return VideoPreviewUI._jQueryInterface;
|
||||||
|
};
|
||||||
|
|
||||||
|
// auto-apply
|
||||||
|
$(window).on(`${Events.AJAX} ${Events.LOADED}`, () => {
|
||||||
|
$('[data-video-preview="true"]').jsVideoPreviewUI();
|
||||||
|
});
|
||||||
|
|
||||||
|
return VideoPreviewUI;
|
||||||
|
})($);
|
||||||
|
|
||||||
|
export default VideoPreviewUI;
|
@ -62,3 +62,10 @@ body.shrink {}
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bootstrap-select .dropdown-toggle .filter-option .option {
|
||||||
|
background: #dedede;
|
||||||
|
padding: .2rem .5rem;
|
||||||
|
margin: .2rem;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
@ -80,15 +80,7 @@ class ElementImageWidget extends DataExtension
|
|||||||
|
|
||||||
public function getWidth()
|
public function getWidth()
|
||||||
{
|
{
|
||||||
$columnSize = $this->owner->getColumnSizeRecursive();
|
return $this->owner->getColumnWidthRecursive();
|
||||||
if (!$columnSize) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$max = Config::inst()->get(ElementRows::class, 'container_max_width');
|
|
||||||
$size = 12 / $columnSize;
|
|
||||||
|
|
||||||
return $max / $size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHeight()
|
public function getHeight()
|
||||||
|
@ -98,7 +98,7 @@ class ElementRows extends DataExtension
|
|||||||
|
|
||||||
public function getWidthPercetage()
|
public function getWidthPercetage()
|
||||||
{
|
{
|
||||||
return $this->isColumn() ? $this->owner->getField('Size') / 12 * 100 : false;
|
return $this->isColumn() ? $this->owner->getField('Size') / self::colsNumber() * 100 : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isList()
|
public function isList()
|
||||||
@ -153,15 +153,47 @@ class ElementRows extends DataExtension
|
|||||||
|
|
||||||
if ($object->isColumn() && $object->getField('Size')) {
|
if ($object->isColumn() && $object->getField('Size')) {
|
||||||
return (int) $object->getField('Size');
|
return (int) $object->getField('Size');
|
||||||
} else {
|
}
|
||||||
|
|
||||||
$parent = $object->Parent()->getOwnerPage();
|
$parent = $object->Parent()->getOwnerPage();
|
||||||
|
|
||||||
if (is_a($parent, 'Page')) {
|
if (is_a($parent, 'Page')) {
|
||||||
return ($this->owner->getField('ContainerType') === 'container-fluid') ? false : 12;
|
return ($this->owner->getField('ContainerType') === 'container-fluid') ? false : self::colsNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $object->getColumnSizeRecursive($parent);
|
return $object->getColumnSizeRecursive($parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getColumnWidthRecursive($object = null, $max = null)
|
||||||
|
{
|
||||||
|
$max = $max ? $max : self::maxWidth();
|
||||||
|
|
||||||
|
$object = $object ? $object : $this->owner;
|
||||||
|
|
||||||
|
if(!$object->isRoot()){
|
||||||
|
$size = $object->getField('Size');
|
||||||
|
$max = $size ? $max / (self::colsNumber() / $size) : $max;
|
||||||
|
$parent = $object->Parent()->getOwnerPage();
|
||||||
|
|
||||||
|
return $this->getColumnWidthRecursive($parent, $max);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function colsNumber()
|
||||||
|
{
|
||||||
|
$db = Config::inst()->get(self::class, 'db');
|
||||||
|
$sizes = $db['Size'];
|
||||||
|
$sizes = preg_replace('!Enum\("([0-9,]+)","([0-9]+)"\)!i','$1', $sizes);
|
||||||
|
$sizes = explode(',',$sizes);
|
||||||
|
|
||||||
|
return max($sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function maxWidth()
|
||||||
|
{
|
||||||
|
return Config::inst()->get(self::class, 'container_max_width');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ExtraClass()
|
public function ExtraClass()
|
||||||
|
@ -7,7 +7,7 @@ use SilverStripe\Forms\CompositeField;
|
|||||||
use SilverStripe\Forms\FieldList;
|
use SilverStripe\Forms\FieldList;
|
||||||
use SilverStripe\Forms\TextField;
|
use SilverStripe\Forms\TextField;
|
||||||
|
|
||||||
class UserFormExtension extends Extension
|
class PlaceholderFormExtension extends Extension
|
||||||
{
|
{
|
||||||
public function updateFormFields(FieldList $fields)
|
public function updateFormFields(FieldList $fields)
|
||||||
{
|
{
|
||||||
@ -18,7 +18,7 @@ class UserFormExtension extends Extension
|
|||||||
|
|
||||||
private function setPlaceholder($field)
|
private function setPlaceholder($field)
|
||||||
{
|
{
|
||||||
if(is_a($field, TextField::class)) {
|
if (is_a($field, TextField::class)) {
|
||||||
$field->setAttribute(
|
$field->setAttribute(
|
||||||
'placeholder',
|
'placeholder',
|
||||||
$field->Title()
|
$field->Title()
|
||||||
@ -27,7 +27,7 @@ class UserFormExtension extends Extension
|
|||||||
$field->setTitle('');
|
$field->setTitle('');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_a($field, CompositeField::class)) {
|
if (is_a($field, CompositeField::class)) {
|
||||||
$children = $field->getChildren();
|
$children = $field->getChildren();
|
||||||
foreach ($children as $child) {
|
foreach ($children as $child) {
|
||||||
$this->setPlaceholder($child);
|
$this->setPlaceholder($child);
|
||||||
|
@ -5,6 +5,7 @@ namespace Site\Extensions;
|
|||||||
use Innoweb\Sitemap\Pages\SitemapPage;
|
use Innoweb\Sitemap\Pages\SitemapPage;
|
||||||
use SilverStripe\AssetAdmin\Forms\UploadField;
|
use SilverStripe\AssetAdmin\Forms\UploadField;
|
||||||
use SilverStripe\Assets\Image;
|
use SilverStripe\Assets\Image;
|
||||||
|
use SilverStripe\Blog\Model\BlogPost;
|
||||||
use SilverStripe\Forms\TextareaField;
|
use SilverStripe\Forms\TextareaField;
|
||||||
use SilverStripe\Forms\TextField;
|
use SilverStripe\Forms\TextField;
|
||||||
use SilverStripe\ORM\DataExtension;
|
use SilverStripe\ORM\DataExtension;
|
||||||
@ -21,7 +22,8 @@ class SiteConfigExtension extends DataExtension
|
|||||||
'Longitude' => 'Varchar(255)',
|
'Longitude' => 'Varchar(255)',
|
||||||
'Latitude' => 'Varchar(255)',
|
'Latitude' => 'Varchar(255)',
|
||||||
'MapZoom' => 'Int',
|
'MapZoom' => 'Int',
|
||||||
'MapAPIKey' => 'Varchar(255)'
|
'MapAPIKey' => 'Varchar(255)',
|
||||||
|
'Description' => 'Varchar(255)',
|
||||||
];
|
];
|
||||||
|
|
||||||
private static $has_one = [
|
private static $has_one = [
|
||||||
@ -57,12 +59,17 @@ class SiteConfigExtension extends DataExtension
|
|||||||
SitemapPage::get()->map()->toArray()
|
SitemapPage::get()->map()->toArray()
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$tab->push(TextareaField::create('Description', 'Website Description'));
|
||||||
|
|
||||||
$mapTab = $fields->findOrMakeTab('Root.GoogleMaps');
|
$mapTab = $fields->findOrMakeTab('Root.GoogleMaps');
|
||||||
$mapTab->push(TextField::create('MapAPIKey'));
|
$mapTab->push(TextField::create('MapAPIKey'));
|
||||||
$mapTab->push(TextField::create('MapZoom'));
|
$mapTab->push(TextField::create('MapZoom'));
|
||||||
$mapTab->push(GoogleMapField::create(
|
$mapTab->push(GoogleMapField::create(
|
||||||
$this->owner,
|
$this->owner,
|
||||||
'Location'
|
'Location',
|
||||||
|
[
|
||||||
|
'show_search_box' => true,
|
||||||
|
]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,4 +87,9 @@ class SiteConfigExtension extends DataExtension
|
|||||||
.$this->owner->getField('Longitude').'" class="btn btn-primary btn-directions" target="_blank">'
|
.$this->owner->getField('Longitude').'" class="btn btn-primary btn-directions" target="_blank">'
|
||||||
.'<i class="fas fa-road"></i> Get Directions</a>';
|
.'<i class="fas fa-road"></i> Get Directions</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getLatestBlogPosts()
|
||||||
|
{
|
||||||
|
return BlogPost::get()->sort('PublishDate DESC');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
1
app/src/Shop/_manifest_exclude
Normal file
1
app/src/Shop/_manifest_exclude
Normal file
@ -0,0 +1 @@
|
|||||||
|
Remove it in case u need silvershop module
|
@ -9,6 +9,7 @@ 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
|
||||||
{
|
{
|
||||||
@ -35,9 +36,14 @@ 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;
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
Requirements::block(THIRDPARTY_DIR.'/jquery/jquery.js');
|
Requirements::block(THIRDPARTY_DIR.'/jquery/jquery.js');
|
||||||
@ -54,6 +60,7 @@ 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');
|
||||||
|
|
||||||
@ -82,17 +89,17 @@ class DeferedRequirements implements TemplateGlobalProvider
|
|||||||
// Controller requirements
|
// Controller requirements
|
||||||
$themePath = Path::join($dir, 'css', $mainTheme.'_'.$class . '.css');
|
$themePath = Path::join($dir, 'css', $mainTheme.'_'.$class . '.css');
|
||||||
$projectPath = Path::join($dir, 'css', $projectName.'_'.$class . '.css');
|
$projectPath = Path::join($dir, 'css', $projectName.'_'.$class . '.css');
|
||||||
if ($mainTheme && file_exists($themePath)){
|
if ($mainTheme && file_exists($themePath)) {
|
||||||
DeferedRequirements::loadCSS($mainTheme.'_'.$class . '.css');
|
DeferedRequirements::loadCSS($mainTheme.'_'.$class . '.css');
|
||||||
} else if (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($dir, 'js', $mainTheme.'_'.$class . '.js');
|
||||||
$projectPath = Path::join($dir, 'js', $projectName.'_'.$class . '.js');
|
$projectPath = Path::join($dir, 'js', $projectName.'_'.$class . '.js');
|
||||||
if ($mainTheme && file_exists($themePath)){
|
if ($mainTheme && file_exists($themePath)) {
|
||||||
DeferedRequirements::loadJS($mainTheme.'_'.$class . '.js');
|
DeferedRequirements::loadJS($mainTheme.'_'.$class . '.js');
|
||||||
} else if (file_exists($projectPath)) {
|
} elseif (file_exists($projectPath)) {
|
||||||
DeferedRequirements::loadJS($projectName.'_'.$class . '.js');
|
DeferedRequirements::loadJS($projectName.'_'.$class . '.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,12 +3,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const conf = require('./webpack.configuration');
|
const commonVariables = require('./webpack.configuration');
|
||||||
|
const conf = commonVariables.configuration;
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const filesystem = require('fs');
|
const filesystem = require('fs');
|
||||||
|
|
||||||
const includes = {};
|
const includes = {};
|
||||||
|
const modules = [
|
||||||
|
path.resolve(__dirname, 'public'),
|
||||||
|
path.resolve(__dirname, conf.APPDIR, 'client', 'src'),
|
||||||
|
path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'js'),
|
||||||
|
path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'scss'),
|
||||||
|
path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'img'),
|
||||||
|
path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'thirdparty'),
|
||||||
|
path.resolve(__dirname, 'node_modules')
|
||||||
|
];
|
||||||
|
|
||||||
const _addAppFiles = (theme) => {
|
const _addAppFiles = (theme) => {
|
||||||
|
|
||||||
@ -21,6 +31,11 @@ const _addAppFiles = (theme) => {
|
|||||||
includes[`${themeName}`] = path.join(dirPath, conf.SRC, 'scss', 'app.scss');
|
includes[`${themeName}`] = path.join(dirPath, conf.SRC, 'scss', 'app.scss');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modules.push(path.join(dirPath, 'client', 'src', 'js'));
|
||||||
|
modules.push(path.join(dirPath, 'client', 'src', 'scss'));
|
||||||
|
modules.push(path.join(dirPath, 'client', 'src', 'img'));
|
||||||
|
modules.push(path.join(dirPath, 'client', 'src', 'thirdparty'));
|
||||||
|
|
||||||
const _getAllFilesFromFolder = function(dir, includeSubFolders = true) {
|
const _getAllFilesFromFolder = function(dir, includeSubFolders = true) {
|
||||||
const dirPath = path.resolve(__dirname, dir);
|
const dirPath = path.resolve(__dirname, dir);
|
||||||
let results = [];
|
let results = [];
|
||||||
@ -30,7 +45,7 @@ const _addAppFiles = (theme) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = `${dirPath}/${file}`;
|
const filePath = path.join(dirPath, file);
|
||||||
const stat = filesystem.statSync(filePath);
|
const stat = filesystem.statSync(filePath);
|
||||||
|
|
||||||
if (stat && stat.isDirectory() && includeSubFolders) {
|
if (stat && stat.isDirectory() && includeSubFolders) {
|
||||||
@ -65,20 +80,9 @@ const _addAppFiles = (theme) => {
|
|||||||
_addAppFiles(conf.APPDIR);
|
_addAppFiles(conf.APPDIR);
|
||||||
|
|
||||||
// add themes
|
// add themes
|
||||||
if (conf.THEMESDIR) {
|
commonVariables.themes.forEach((theme) => {
|
||||||
const dir = path.resolve(__dirname, conf.THEMESDIR);
|
_addAppFiles(theme);
|
||||||
|
});
|
||||||
if (filesystem.existsSync(dir)) {
|
|
||||||
filesystem.readdirSync(dir).forEach((file) => {
|
|
||||||
filePath = `${dir}/${file}`;
|
|
||||||
const stat = filesystem.statSync(filePath);
|
|
||||||
|
|
||||||
if (stat && stat.isDirectory()) {
|
|
||||||
_addAppFiles(path.join(conf.THEMESDIR, file));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: includes,
|
entry: includes,
|
||||||
@ -120,15 +124,7 @@ module.exports = {
|
|||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
modules: [
|
modules: modules,
|
||||||
path.resolve(__dirname, 'public'),
|
|
||||||
path.resolve(__dirname, conf.APPDIR, 'client', 'src'),
|
|
||||||
path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'js'),
|
|
||||||
path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'scss'),
|
|
||||||
path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'img'),
|
|
||||||
path.resolve(__dirname, conf.APPDIR, 'client', 'src', 'thirdparty'),
|
|
||||||
path.resolve(__dirname, 'node_modules')
|
|
||||||
],
|
|
||||||
alias: {
|
alias: {
|
||||||
'jquery': require.resolve('jquery'),
|
'jquery': require.resolve('jquery'),
|
||||||
'jQuery': require.resolve('jquery'),
|
'jQuery': require.resolve('jquery'),
|
||||||
|
@ -7,7 +7,8 @@ const autoprefixer = require('autoprefixer');
|
|||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const merge = require('webpack-merge');
|
const merge = require('webpack-merge');
|
||||||
const common = require('./webpack.config.common.js');
|
const common = require('./webpack.config.common.js');
|
||||||
const conf = require('./webpack.configuration');
|
const commonVariables = require('./webpack.configuration');
|
||||||
|
const conf = commonVariables.configuration;
|
||||||
|
|
||||||
const IP = process.env.IP || conf.HOSTNAME;
|
const IP = process.env.IP || conf.HOSTNAME;
|
||||||
const PORT = process.env.PORT || conf.PORT;
|
const PORT = process.env.PORT || conf.PORT;
|
||||||
@ -101,6 +102,7 @@ const config = merge.strategy({
|
|||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
hot: false,
|
hot: false,
|
||||||
clientLogLevel: 'info',
|
clientLogLevel: 'info',
|
||||||
|
disableHostCheck: true,
|
||||||
contentBase: [
|
contentBase: [
|
||||||
path.resolve(__dirname, 'public'),
|
path.resolve(__dirname, 'public'),
|
||||||
path.resolve(__dirname, 'public', 'resources'),
|
path.resolve(__dirname, 'public', 'resources'),
|
||||||
|
@ -3,16 +3,81 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const conf = require('./webpack.configuration');
|
const commonVariables = require('./webpack.configuration');
|
||||||
|
const conf = commonVariables.configuration;
|
||||||
const merge = require('webpack-merge');
|
const merge = require('webpack-merge');
|
||||||
const common = require('./webpack.config.common.js');
|
const common = require('./webpack.config.common.js');
|
||||||
|
|
||||||
|
const filesystem = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const autoprefixer = require('autoprefixer');
|
const autoprefixer = require('autoprefixer');
|
||||||
|
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
|
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
|
||||||
|
|
||||||
|
let plugins = [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': {
|
||||||
|
'NODE_ENV': JSON.stringify('production')
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
minimize: true,
|
||||||
|
debug: false
|
||||||
|
}),
|
||||||
|
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||||
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
|
sourceMap: false,
|
||||||
|
comments: false
|
||||||
|
}),
|
||||||
|
new ExtractTextPlugin({
|
||||||
|
filename: 'css/[name].css',
|
||||||
|
allChunks: true
|
||||||
|
}),
|
||||||
|
|
||||||
|
new FaviconsWebpackPlugin({
|
||||||
|
logo: path.join(__dirname, conf.APPDIR, conf.SRC, 'favicon.png'),
|
||||||
|
prefix: '/icons/',
|
||||||
|
statsFilename: path.join(conf.APPDIR, conf.DIST, 'icons', 'iconstats.json'),
|
||||||
|
icons: {
|
||||||
|
android: true,
|
||||||
|
appleIcon: true,
|
||||||
|
appleStartup: true,
|
||||||
|
coast: true,
|
||||||
|
favicons: true,
|
||||||
|
firefox: true,
|
||||||
|
opengraph: true,
|
||||||
|
twitter: true,
|
||||||
|
yandex: true,
|
||||||
|
windows: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
// add themes favicons
|
||||||
|
commonVariables.themes.forEach((theme) => {
|
||||||
|
const faviconPath = path.join(__dirname, theme, conf.SRC, 'favicon.png');
|
||||||
|
if (filesystem.existsSync(faviconPath)) {
|
||||||
|
plugins.push(new FaviconsWebpackPlugin({
|
||||||
|
logo: faviconPath,
|
||||||
|
prefix: '/' + theme + '-icons/',
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = merge(common, {
|
module.exports = merge(common, {
|
||||||
devtool: '',
|
devtool: '',
|
||||||
|
|
||||||
@ -98,42 +163,5 @@ module.exports = merge(common, {
|
|||||||
}, ]
|
}, ]
|
||||||
},
|
},
|
||||||
|
|
||||||
plugins: [
|
plugins: plugins,
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env': {
|
|
||||||
'NODE_ENV': JSON.stringify('production')
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
|
||||||
minimize: true,
|
|
||||||
debug: false
|
|
||||||
}),
|
|
||||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
|
||||||
sourceMap: false,
|
|
||||||
comments: false
|
|
||||||
}),
|
|
||||||
new ExtractTextPlugin({
|
|
||||||
filename: 'css/[name].css',
|
|
||||||
allChunks: true
|
|
||||||
}),
|
|
||||||
|
|
||||||
new FaviconsWebpackPlugin({
|
|
||||||
logo: path.join(__dirname, conf.APPDIR, conf.SRC, 'favicon.png'),
|
|
||||||
prefix: '/icons/',
|
|
||||||
statsFilename: path.join(conf.APPDIR, conf.DIST, 'icons', 'iconstats.json'),
|
|
||||||
icons: {
|
|
||||||
android: true,
|
|
||||||
appleIcon: true,
|
|
||||||
appleStartup: true,
|
|
||||||
coast: true,
|
|
||||||
favicons: true,
|
|
||||||
firefox: true,
|
|
||||||
opengraph: true,
|
|
||||||
twitter: true,
|
|
||||||
yandex: true,
|
|
||||||
windows: true
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
@ -3,8 +3,31 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const filesystem = require('fs');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
|
|
||||||
const conf = yaml.safeLoad(fs.readFileSync(path.join(__dirname, 'app/_config/webpack.yml'), 'utf8'));
|
const conf = yaml.safeLoad(fs.readFileSync(path.join(__dirname, 'app/_config/webpack.yml'), 'utf8'));
|
||||||
|
|
||||||
module.exports = conf['Site\\Templates\\WebpackTemplateProvider'];
|
let themes = [];
|
||||||
|
// add themes
|
||||||
|
if (conf['Site\\Templates\\WebpackTemplateProvider'].THEMESDIR) {
|
||||||
|
const themeDir = conf['Site\\Templates\\WebpackTemplateProvider'].THEMESDIR;
|
||||||
|
const dir = path.resolve(__dirname, themeDir);
|
||||||
|
|
||||||
|
if (filesystem.existsSync(dir)) {
|
||||||
|
filesystem.readdirSync(dir).forEach((file) => {
|
||||||
|
filePath = path.join(themeDir, file);
|
||||||
|
const stat = filesystem.statSync(filePath);
|
||||||
|
|
||||||
|
if (stat && stat.isDirectory()) {
|
||||||
|
themes.push(filePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
configuration: conf['Site\\Templates\\WebpackTemplateProvider'],
|
||||||
|
themes: themes,
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user