diff --git a/app/_config/elements.yml b/app/_config/elements.yml
index a8755e7..f4f9dfd 100644
--- a/app/_config/elements.yml
+++ b/app/_config/elements.yml
@@ -26,6 +26,7 @@ SilverStripe\CMS\Model\SiteTree:
- Dynamic\Elements\Elements\ElementTestimonials
- Site\Elements\TeamMembersElement
- Site\Elements\SliderElement
+ - DNADesign\ElementalVirtual\Model\ElementVirtual
DNADesign\ElementalList\Model\ElementList:
default_global_elements: false
diff --git a/app/_config/extensions.yml b/app/_config/extensions.yml
index 7b0767c..10d6644 100644
--- a/app/_config/extensions.yml
+++ b/app/_config/extensions.yml
@@ -5,7 +5,7 @@ SilverStripe\SiteConfig\SiteConfig:
SilverStripe\SiteTree\SiteTree:
extensions:
- - SiteTreeExtension
+ - Site\Extensions\SiteTreeExtension
SilverStripe\Blog\Model\BlogPost:
extensions:
diff --git a/app/_config/googlemapfield.yml b/app/_config/googlemapfield.yml
index 16f16b4..940666d 100644
--- a/app/_config/googlemapfield.yml
+++ b/app/_config/googlemapfield.yml
@@ -1,3 +1,4 @@
BetterBrief\GoogleMapField:
default_options:
api_key: 'YOUR_API_KEY'
+ show_search_box: true
diff --git a/app/client/src/js/_components/_ui.form.basics.js b/app/client/src/js/_components/_ui.form.basics.js
index ae2d41a..c32caaa 100644
--- a/app/client/src/js/_components/_ui.form.basics.js
+++ b/app/client/src/js/_components/_ui.form.basics.js
@@ -22,30 +22,77 @@ const FormBasics = (($) => {
const $fields = $element.find('input,textarea,select');
const $selectFields = $element.find('select:not([readonly])');
const $radioOptions = $element.find('input[type="radio"]');
+ const separator = ', ';
$selectFields.each((i, el) => {
const $el = $(el);
+ const maxOptions = $el.data('max-options') || false;
- $el.selectpicker({
+ $el.selectpicker($.extend({
iconBase: 'fas',
tickIcon: 'fa-check',
- liveSearch: $el.data('live-search'),
- noneSelectedText: $el.data('none-selected-text') || 'Nothing selected',
- maxOptions: $el.data('max-options') || false,
+ virtualScroll: false,
+ dropupAuto: 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 += '' + opt +
+ ' ';
+ });
+
+ $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
+ $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').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) => {
const $el = $(el);
diff --git a/app/client/src/js/_components/_ui.form.croppie.js b/app/client/src/js/_components/_ui.form.croppie.js
index d18b5c5..9caeb59 100644
--- a/app/client/src/js/_components/_ui.form.croppie.js
+++ b/app/client/src/js/_components/_ui.form.croppie.js
@@ -2,6 +2,7 @@
import $ from 'jquery';
+import MainUI from "../_main";
import Events from '../_events';
import SpinnerUI from './_ui.spinner';
@@ -33,7 +34,7 @@ const CroppieUI = (($) => {
const ui = this;
const $el = $(element);
- ui._element = element;
+ ui.$el = $el;
$el.data(DATA_KEY, this);
ui.input = $el.find('input[type="file"]');
@@ -42,10 +43,14 @@ const CroppieUI = (($) => {
ui.width = ui.input.data('width');
ui.height = ui.input.data('height');
- $el.append('
');
+ $el.append(
+ ''
+ );
//$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);
ui.uploadCrop.croppie({
@@ -62,11 +67,23 @@ const CroppieUI = (($) => {
ui.input.on('change', (e) => {
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) {
const ui = this;
- const $el = $(ui._element);
+ const $el = ui.$el;
const $form = $el.closest('form');
if (input.files && input.files[0]) {
@@ -79,6 +96,7 @@ const CroppieUI = (($) => {
});
ui.uploadCrop.show();
+ ui.uploadCropWrap.show();
}
reader.readAsDataURL(input.files[0]);
@@ -87,6 +105,10 @@ const CroppieUI = (($) => {
//$(input).val('');
SpinnerUI.show();
+ if (!ui.uploadCrop.hasClass('ready')) {
+ return true;
+ }
+
ui.uploadCrop.croppie('result', {
type: 'blob',
size: {
@@ -129,13 +151,25 @@ const CroppieUI = (($) => {
$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['link'] !== 'undefined') {
- G.location = json['link'];
- } else {
- //G.location.reload(false);
+ if (typeof json['status'] !== 'undefined') {
+ if (json['status'] === 'success') {
+ MainUI.alert(json['message'], json['status']);
+
+ if (typeof json['link'] !== 'undefined') {
+ setTimeout(() => {
+ G.location = json['link'];
+ }, 2000);
+ } else {
+ //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 {
$(form).replaceWith(data);
//G.location.reload(false);
diff --git a/app/client/src/js/_components/_ui.nocaptcha.js b/app/client/src/js/_components/_ui.nocaptcha.js
new file mode 100644
index 0000000..16ee7ce
--- /dev/null
+++ b/app/client/src/js/_components/_ui.nocaptcha.js
@@ -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;
diff --git a/app/client/src/js/_components/_ui.video.preview.js b/app/client/src/js/_components/_ui.video.preview.js
new file mode 100644
index 0000000..aed94f2
--- /dev/null
+++ b/app/client/src/js/_components/_ui.video.preview.js
@@ -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(``);
+ }
+
+ 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;
diff --git a/app/client/src/scss/_layout.scss b/app/client/src/scss/_layout.scss
index 788e79e..45a407d 100644
--- a/app/client/src/scss/_layout.scss
+++ b/app/client/src/scss/_layout.scss
@@ -62,3 +62,10 @@ body.shrink {}
}
}
}
+
+.bootstrap-select .dropdown-toggle .filter-option .option {
+ background: #dedede;
+ padding: .2rem .5rem;
+ margin: .2rem;
+ color: #212529;
+}
diff --git a/app/src/Extensions/ElementImageWidget.php b/app/src/Extensions/ElementImageWidget.php
index c5162c4..a81694c 100644
--- a/app/src/Extensions/ElementImageWidget.php
+++ b/app/src/Extensions/ElementImageWidget.php
@@ -80,15 +80,7 @@ class ElementImageWidget extends DataExtension
public function getWidth()
{
- $columnSize = $this->owner->getColumnSizeRecursive();
- if (!$columnSize) {
- return false;
- }
-
- $max = Config::inst()->get(ElementRows::class, 'container_max_width');
- $size = 12 / $columnSize;
-
- return $max / $size;
+ return $this->owner->getColumnWidthRecursive();
}
public function getHeight()
diff --git a/app/src/Extensions/ElementRows.php b/app/src/Extensions/ElementRows.php
index c6f4944..b3d6cbc 100644
--- a/app/src/Extensions/ElementRows.php
+++ b/app/src/Extensions/ElementRows.php
@@ -98,7 +98,7 @@ class ElementRows extends DataExtension
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()
@@ -153,15 +153,47 @@ class ElementRows extends DataExtension
if ($object->isColumn() && $object->getField('Size')) {
return (int) $object->getField('Size');
- } else {
+ }
+
+ $parent = $object->Parent()->getOwnerPage();
+
+ if (is_a($parent, 'Page')) {
+ return ($this->owner->getField('ContainerType') === 'container-fluid') ? false : self::colsNumber();
+ }
+
+ 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();
- if (is_a($parent, 'Page')) {
- return ($this->owner->getField('ContainerType') === 'container-fluid') ? false : 12;
- }
-
- return $object->getColumnSizeRecursive($parent);
+ 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()
diff --git a/app/src/Extensions/PlaceholderFormExtension.php b/app/src/Extensions/PlaceholderFormExtension.php
index 7168ddb..ed8243f 100644
--- a/app/src/Extensions/PlaceholderFormExtension.php
+++ b/app/src/Extensions/PlaceholderFormExtension.php
@@ -7,7 +7,7 @@ use SilverStripe\Forms\CompositeField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TextField;
-class UserFormExtension extends Extension
+class PlaceholderFormExtension extends Extension
{
public function updateFormFields(FieldList $fields)
{
@@ -18,7 +18,7 @@ class UserFormExtension extends Extension
private function setPlaceholder($field)
{
- if(is_a($field, TextField::class)) {
+ if (is_a($field, TextField::class)) {
$field->setAttribute(
'placeholder',
$field->Title()
@@ -27,7 +27,7 @@ class UserFormExtension extends Extension
$field->setTitle('');
}
- if(is_a($field, CompositeField::class)) {
+ if (is_a($field, CompositeField::class)) {
$children = $field->getChildren();
foreach ($children as $child) {
$this->setPlaceholder($child);
diff --git a/app/src/Extensions/SiteConfigExtension.php b/app/src/Extensions/SiteConfigExtension.php
index 620df96..4b32a0a 100644
--- a/app/src/Extensions/SiteConfigExtension.php
+++ b/app/src/Extensions/SiteConfigExtension.php
@@ -5,6 +5,7 @@ namespace Site\Extensions;
use Innoweb\Sitemap\Pages\SitemapPage;
use SilverStripe\AssetAdmin\Forms\UploadField;
use SilverStripe\Assets\Image;
+use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Forms\TextareaField;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DataExtension;
@@ -21,7 +22,8 @@ class SiteConfigExtension extends DataExtension
'Longitude' => 'Varchar(255)',
'Latitude' => 'Varchar(255)',
'MapZoom' => 'Int',
- 'MapAPIKey' => 'Varchar(255)'
+ 'MapAPIKey' => 'Varchar(255)',
+ 'Description' => 'Varchar(255)',
];
private static $has_one = [
@@ -57,12 +59,17 @@ class SiteConfigExtension extends DataExtension
SitemapPage::get()->map()->toArray()
));
+ $tab->push(TextareaField::create('Description', 'Website Description'));
+
$mapTab = $fields->findOrMakeTab('Root.GoogleMaps');
$mapTab->push(TextField::create('MapAPIKey'));
$mapTab->push(TextField::create('MapZoom'));
$mapTab->push(GoogleMapField::create(
$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">'
.' Get Directions';
}
+
+ public function getLatestBlogPosts()
+ {
+ return BlogPost::get()->sort('PublishDate DESC');
+ }
}
diff --git a/app/src/.Shop/CheckoutMapComponent.php b/app/src/Shop/CheckoutMapComponent.php
similarity index 100%
rename from app/src/.Shop/CheckoutMapComponent.php
rename to app/src/Shop/CheckoutMapComponent.php
diff --git a/app/src/.Shop/CheckoutNoDeliveryConfig.php b/app/src/Shop/CheckoutNoDeliveryConfig.php
similarity index 100%
rename from app/src/.Shop/CheckoutNoDeliveryConfig.php
rename to app/src/Shop/CheckoutNoDeliveryConfig.php
diff --git a/app/src/Shop/_manifest_exclude b/app/src/Shop/_manifest_exclude
new file mode 100644
index 0000000..c309c9d
--- /dev/null
+++ b/app/src/Shop/_manifest_exclude
@@ -0,0 +1 @@
+Remove it in case u need silvershop module
diff --git a/app/src/Templates/DeferedRequirements.php b/app/src/Templates/DeferedRequirements.php
index 96fcd42..bc463bb 100644
--- a/app/src/Templates/DeferedRequirements.php
+++ b/app/src/Templates/DeferedRequirements.php
@@ -9,6 +9,7 @@ use SilverStripe\Core\Config\Config;
use SilverStripe\Control\Director;
use SilverStripe\Core\Path;
use SilverStripe\Core\Manifest\ManifestFileFinder;
+use SilverStripe\CMS\Controllers\CMSMain;
class DeferedRequirements implements TemplateGlobalProvider
{
@@ -35,9 +36,14 @@ class DeferedRequirements implements TemplateGlobalProvider
public static function Auto($class = false)
{
+ if (is_a(Controller::curr(), CMSMain::class)) {
+ return;
+ }
+
$config = Config::inst()->get(self::class);
$projectName = WebpackTemplateProvider::projectName();
$mainTheme = WebpackTemplateProvider::mainTheme();
+ $mainTheme = $mainTheme ? $mainTheme : $projectName;
// Initialization
Requirements::block(THIRDPARTY_DIR.'/jquery/jquery.js');
@@ -54,6 +60,7 @@ class DeferedRequirements implements TemplateGlobalProvider
if (!$config['nofontawesome']) {
DeferedRequirements::loadCSS('//use.fontawesome.com/releases/v5.4.0/css/all.css');
}
+
DeferedRequirements::loadCSS($mainTheme.'.css');
DeferedRequirements::loadJS($mainTheme.'.js');
@@ -82,17 +89,17 @@ class DeferedRequirements implements TemplateGlobalProvider
// Controller requirements
$themePath = Path::join($dir, 'css', $mainTheme.'_'.$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');
- } else if (file_exists($projectPath)) {
+ } elseif (file_exists($projectPath)) {
DeferedRequirements::loadCSS($projectName.'_'.$class . '.css');
}
$themePath = Path::join($dir, 'js', $mainTheme.'_'.$class . '.js');
$projectPath = Path::join($dir, 'js', $projectName.'_'.$class . '.js');
- if ($mainTheme && file_exists($themePath)){
+ if ($mainTheme && file_exists($themePath)) {
DeferedRequirements::loadJS($mainTheme.'_'.$class . '.js');
- } else if (file_exists($projectPath)) {
+ } elseif (file_exists($projectPath)) {
DeferedRequirements::loadJS($projectName.'_'.$class . '.js');
}
diff --git a/webpack.config.common.js b/webpack.config.common.js
index ac74373..e8ee053 100755
--- a/webpack.config.common.js
+++ b/webpack.config.common.js
@@ -3,12 +3,22 @@
*/
const webpack = require('webpack');
-const conf = require('./webpack.configuration');
+const commonVariables = require('./webpack.configuration');
+const conf = commonVariables.configuration;
const path = require('path');
const filesystem = require('fs');
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) => {
@@ -21,6 +31,11 @@ const _addAppFiles = (theme) => {
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 dirPath = path.resolve(__dirname, dir);
let results = [];
@@ -30,7 +45,7 @@ const _addAppFiles = (theme) => {
return;
}
- const filePath = `${dirPath}/${file}`;
+ const filePath = path.join(dirPath, file);
const stat = filesystem.statSync(filePath);
if (stat && stat.isDirectory() && includeSubFolders) {
@@ -65,20 +80,9 @@ const _addAppFiles = (theme) => {
_addAppFiles(conf.APPDIR);
// add themes
-if (conf.THEMESDIR) {
- const dir = path.resolve(__dirname, conf.THEMESDIR);
-
- 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));
- }
- });
- }
-}
+commonVariables.themes.forEach((theme) => {
+ _addAppFiles(theme);
+});
module.exports = {
entry: includes,
@@ -120,15 +124,7 @@ module.exports = {
}],
},
resolve: {
- 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')
- ],
+ modules: modules,
alias: {
'jquery': require.resolve('jquery'),
'jQuery': require.resolve('jquery'),
diff --git a/webpack.config.dev.js b/webpack.config.dev.js
index 8ee472a..4bfb218 100755
--- a/webpack.config.dev.js
+++ b/webpack.config.dev.js
@@ -7,7 +7,8 @@ const autoprefixer = require('autoprefixer');
const webpack = require('webpack');
const merge = require('webpack-merge');
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 PORT = process.env.PORT || conf.PORT;
@@ -101,6 +102,7 @@ const config = merge.strategy({
historyApiFallback: true,
hot: false,
clientLogLevel: 'info',
+ disableHostCheck: true,
contentBase: [
path.resolve(__dirname, 'public'),
path.resolve(__dirname, 'public', 'resources'),
diff --git a/webpack.config.prod.js b/webpack.config.prod.js
index 893d7a3..7882c08 100755
--- a/webpack.config.prod.js
+++ b/webpack.config.prod.js
@@ -3,16 +3,81 @@
*/
const webpack = require('webpack');
-const conf = require('./webpack.configuration');
+const commonVariables = require('./webpack.configuration');
+const conf = commonVariables.configuration;
const merge = require('webpack-merge');
const common = require('./webpack.config.common.js');
+const filesystem = require('fs');
const path = require('path');
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-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, {
devtool: '',
@@ -98,42 +163,5 @@ module.exports = merge(common, {
}, ]
},
- 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
- }
- }),
- ],
+ plugins: plugins,
});
diff --git a/webpack.configuration.js b/webpack.configuration.js
index 5235dc1..3b6648c 100755
--- a/webpack.configuration.js
+++ b/webpack.configuration.js
@@ -3,8 +3,31 @@
*/
const path = require('path');
+const filesystem = require('fs');
const fs = require('fs');
const yaml = require('js-yaml');
+
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,
+};