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( + '
' + + ' Remove
' + ); //$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(`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; 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, +};