From ce7490bc901d3eacc5459964d7ccf33ef49114c6 Mon Sep 17 00:00:00 2001 From: Tony Air Date: Mon, 2 Jul 2018 08:54:18 +0700 Subject: [PATCH] Bunch of structural upgrades and module integrations --- app/_config.php | 5 +- app/_config/captcha.yml | 13 + app/_config/elements.yml | 46 +- app/_config/extensions.yml | 12 + .../src/js/_components/_ui.form.storage.js | 175 +- app/client/src/js/main.js | 2 +- app/client/src/scss/_bootstrap_variables.scss | 10 - app/client/src/scss/_layout.scss | 11 - app/client/src/scss/_typography.scss | 7 +- app/client/src/scss/_variables.scss | 36 +- app/client/src/scss/app.scss | 88 +- app/client/src/scss/types/editor.scss | 2 +- app/composer.json | 11 + app/src/Elements/TeamMembersElement.php | 30 + app/src/Extensions/BlogPostExtension.php | 40 + app/src/Extensions/ElementContentWidget.php | 41 + app/src/Extensions/ElementImageWidget.php | 111 + app/src/Extensions/ElementRows.php | 131 +- app/src/Extensions/HiddenType.php | 17 + app/src/Extensions/SiteConfigExtension.php | 35 +- app/src/Extensions/SiteTreeExtension.php | 28 + app/src/Extensions/SocialExtension.php | 63 + app/src/Models/TeamMember.php | 54 + app/src/Pages/HomePage.php | 1 + app/src/Pages/HomePageController.php | 1 + app/src/Pages/PageController.php | 5 + app/src/Pages/TeamPage.php | 42 + app/src/Pages/TeamPageController.php | 15 + .../Elemental/Layout/ElementHolder.ss | 5 + .../Elemental/Models/ElementContent.ss | 18 + .../ElementalUserForms/Model/ElementForm.ss | 10 + .../Blog/Elements/ElementBlogPosts.ss | 14 + .../Elements/Elements/ElementTestimonials.ss | 14 + .../Elements/Image/Elements/ElementImage.ss | 26 +- app/templates/Includes/BlogPostInfo.ss | 25 + app/templates/Includes/Content.ss | 10 +- app/templates/Includes/FlexSlider.ss | 24 +- app/templates/Includes/Footer.ss | 65 + app/templates/Includes/Header.ss | 26 + .../Includes/{Head.ss => MetaHead.ss} | 0 app/templates/Includes/NavItem.ss | 4 +- app/templates/Includes/Navigation.ss | 12 +- app/templates/Objects/HCard.ss | 33 + app/templates/Objects/SocialLinks.ss | 32 + app/templates/Objects/Testimonial.ss | 16 + app/templates/Page.ss | 43 +- .../Sheadawson/Linkable/Models/Link.ss | 10 + .../Sheadawson/Linkable/Models/Link_button.ss | 3 + .../Linkable/Models/Link_buttonghost.ss | 3 + .../SilverStripe/Blog/Includes/EntryMeta.ss | 46 + .../SilverStripe/Blog/Model/Layout/Blog.ss | 45 + .../Blog/Model/Layout/BlogPost.ss | 35 + .../Blog/Model/Layout/Blog_profile.ss | 23 + .../Site/Elements/TeamMembersElement.ss | 17 + composer.json | 21 +- package-lock.json | 3985 +++++++++++++---- package.json | 3 +- webpack.config.common.js | 2 +- webpack.config.prod.js | 11 +- 59 files changed, 4432 insertions(+), 1181 deletions(-) create mode 100644 app/_config/captcha.yml delete mode 100644 app/client/src/scss/_bootstrap_variables.scss create mode 100644 app/composer.json create mode 100644 app/src/Elements/TeamMembersElement.php create mode 100644 app/src/Extensions/BlogPostExtension.php create mode 100644 app/src/Extensions/ElementContentWidget.php create mode 100644 app/src/Extensions/ElementImageWidget.php create mode 100644 app/src/Extensions/HiddenType.php create mode 100644 app/src/Extensions/SiteTreeExtension.php create mode 100644 app/src/Extensions/SocialExtension.php create mode 100644 app/src/Models/TeamMember.php create mode 100644 app/src/Pages/TeamPage.php create mode 100644 app/src/Pages/TeamPageController.php create mode 100644 app/templates/DNADesign/Elemental/Layout/ElementHolder.ss create mode 100644 app/templates/DNADesign/Elemental/Models/ElementContent.ss create mode 100644 app/templates/DNADesign/ElementalUserForms/Model/ElementForm.ss create mode 100644 app/templates/Dynamic/Elements/Blog/Elements/ElementBlogPosts.ss create mode 100644 app/templates/Dynamic/Elements/Elements/ElementTestimonials.ss create mode 100644 app/templates/Includes/BlogPostInfo.ss create mode 100644 app/templates/Includes/Footer.ss create mode 100644 app/templates/Includes/Header.ss rename app/templates/Includes/{Head.ss => MetaHead.ss} (100%) create mode 100644 app/templates/Objects/HCard.ss create mode 100644 app/templates/Objects/SocialLinks.ss create mode 100644 app/templates/Objects/Testimonial.ss create mode 100644 app/templates/Sheadawson/Linkable/Models/Link.ss create mode 100644 app/templates/Sheadawson/Linkable/Models/Link_button.ss create mode 100644 app/templates/Sheadawson/Linkable/Models/Link_buttonghost.ss create mode 100644 app/templates/SilverStripe/Blog/Includes/EntryMeta.ss create mode 100644 app/templates/SilverStripe/Blog/Model/Layout/Blog.ss create mode 100644 app/templates/SilverStripe/Blog/Model/Layout/BlogPost.ss create mode 100644 app/templates/SilverStripe/Blog/Model/Layout/Blog_profile.ss create mode 100644 app/templates/Site/Elements/TeamMembersElement.ss diff --git a/app/_config.php b/app/_config.php index 3901d65..6d8a13e 100644 --- a/app/_config.php +++ b/app/_config.php @@ -12,7 +12,10 @@ HtmlEditorConfig::get('cms')->enablePlugins([ 'charmap', 'visualblocks', 'lists', - 'charcount' => ModuleResourceLoader::resourceURL('drmartingonzo/ss-tinymce-charcount:client/dist/js/bundle.js'), + 'charcount' => ModuleResourceLoader::resourceURL( + 'drmartingonzo/ss-tinymce-charcount:client/dist/js/bundle.js' + ), ]); FulltextSearchable::enable(); + diff --git a/app/_config/captcha.yml b/app/_config/captcha.yml new file mode 100644 index 0000000..191373a --- /dev/null +++ b/app/_config/captcha.yml @@ -0,0 +1,13 @@ +SilverStripe\SpamProtection\Extension\FormSpamProtectionExtension: + default_spam_protector: UndefinedOffset\NoCaptcha\Forms\NocaptchaProtector + +UndefinedOffset\NoCaptcha\Forms\NocaptchaField: + site_key: "YOUR_SITE_KEY" #Your site key (required) + secret_key: "YOUR_SECRET_KEY" #Your secret key (required) + verify_ssl: true #Allows you to disable php-curl's SSL peer verification by setting this to false (optional, defaults to true) + default_theme: "light" #Default theme color (optional, light or dark, defaults to light) + default_type: "image" #Default captcha type (optional, image or audio, defaults to image) + default_size: "normal" #Default size (optional, normal, compact or invisible, defaults to normal) + default_badge: "bottomright" #Default badge position (bottomright, bottomleft or inline, defaults to bottomright) + proxy_server: "" #Your proxy server address (optional) + proxy_auth: "" #Your proxy server authentication information (optional) \ No newline at end of file diff --git a/app/_config/elements.yml b/app/_config/elements.yml index 75b7a89..b463ec5 100644 --- a/app/_config/elements.yml +++ b/app/_config/elements.yml @@ -1,3 +1,10 @@ +--- +Name: webapp-elemental +After: + - elemental + - elemental-list +--- + Page: extensions: - DNADesign\Elemental\Extensions\ElementalPageExtension @@ -5,7 +12,42 @@ Page: DNADesign\Elemental\Models\BaseElement: default_global_elements: true extensions: - - Site\Extensions\ElementRows + - Site\Extensions\ElementRows + +SilverStripe\CMS\Model\SiteTree: + allowed_elements: + - DNADesign\ElementalList\Model\ElementList + - DNADesign\Elemental\Models\ElementContent + - DNADesign\ElementalUserForms\Model\ElementForm + - Dynamic\Elements\Image\Elements\ElementImage + - Dynamic\Elements\Blog\Elements\ElementBlogPosts + - Dynamic\Elements\FlexSlider\Elements\ElementSlideshow + - Dynamic\Elements\Oembed\Elements\ElementOembed + - Dynamic\Elements\Elements\ElementTestimonials + - Site\Elements\TeamMembersElement DNADesign\ElementalList\Model\ElementList: - default_global_elements: false \ No newline at end of file + default_global_elements: false + allowed_elements: + - DNADesign\ElementalList\Model\ElementList + - DNADesign\Elemental\Models\ElementContent + - DNADesign\ElementalUserForms\Model\ElementForm + - Dynamic\Elements\Image\Elements\ElementImage + - Dynamic\Elements\Blog\Elements\ElementBlogPosts + - Dynamic\Elements\FlexSlider\Elements\ElementSlideshow + - Dynamic\Elements\Oembed\Elements\ElementOembed + - Dynamic\Elements\Elements\ElementTestimonials + - Site\Elements\TeamMembersElement + styles: + whiteframe: 'White Frame' + greybg: 'Grey Background' + noframe: 'No Frame' + +DNADesign\Elemental\Models\ElementContent: + extensions: + - Site\Extensions\ElementContentWidget + +Dynamic\Elements\Image\Elements\ElementImage: + extensions: + - Site\Extensions\ElementImageWidget + diff --git a/app/_config/extensions.yml b/app/_config/extensions.yml index c76095f..d1b6168 100644 --- a/app/_config/extensions.yml +++ b/app/_config/extensions.yml @@ -1,4 +1,16 @@ SilverStripe\SiteConfig\SiteConfig: extensions: - Site\Extensions\SiteConfigExtension + - Site\Extensions\SocialExtension +SilverStripe\SiteTree\SiteTree: + extensions: + - SiteTreeExtension + +SilverStripe\Blog\Model\BlogPost: + extensions: + - Site\Extensions\BlogPostExtension + +SilverStripe\Core\Injector\Injector: + SilverStripe\UserForms\Model\UserDefinedForm: + class: Site\Extensions\CMSMain_HiddenClass diff --git a/app/client/src/js/_components/_ui.form.storage.js b/app/client/src/js/_components/_ui.form.storage.js index 5abbb3b..8c9a0cb 100644 --- a/app/client/src/js/_components/_ui.form.storage.js +++ b/app/client/src/js/_components/_ui.form.storage.js @@ -2,102 +2,115 @@ import $ from 'jquery'; import Events from "../_events"; const FormStorage = (($) => { - // Constants - const NAME = 'jsFormStorage'; - const DATA_KEY = NAME; - const STORAGE = window.localStorage; + // Constants + const NAME = 'jsFormStorage'; + const DATA_KEY = NAME; + const STORAGE = window.localStorage; - class FormStorage { - // Constructor - constructor(element) { - this._element = element; - const $element = $(this._element); - const $elements = $element.find('input,textarea'); + class FormStorage { + // Constructor + constructor(element) { + this._element = element; + const $element = $(this._element); + const $elements = $element.find('input,textarea'); + const setRangeValues = function(el) { + let $el = $(el); + $el.siblings('.value').text($el.val()); + }; - $element.addClass(`${NAME}-active`); + $element.addClass(`${NAME}-active`); - // restore form data from localStorage - $elements.each(function () { - const id = $(this).attr('id'); - const type = $(this).attr('type'); - const val = STORAGE.getItem(NAME + id); + // restore form data from localStorage + $elements.each(function() { + const id = $(this).attr('id'); + const type = $(this).attr('type'); + const val = STORAGE.getItem(NAME + id); - if (id && val && type) { - if (type && (type === 'checkbox' || type === 'radio')) { - $(this).prop('checked', val); - } else { - $(this).val(val); - } - } - }); + if (id && val && type) { + if (type && (type === 'checkbox' || type === 'radio')) { + $(this).prop('checked', val); + } else { + $(this).val(val); + } + } + }); - // store form data into localStorage - $elements.change(function () { - const id = $(this).attr('id'); - const type = $(this).attr('type'); - let val = $(this).val(); + // range fields - if (type && (type === 'checkbox' || type === 'radio')) { - val = !!$(this).is(':checked'); + $('input[type="range"]').each(function() { + setRangeValues(this); + }); + $('input[type="range"]').change(function() { + setRangeValues(this); + }); + + // store form data into localStorage + $elements.change(function() { + const id = $(this).attr('id'); + const type = $(this).attr('type'); + let val = $(this).val(); + + if (type && (type === 'checkbox' || type === 'radio')) { + val = !!$(this).is(':checked'); + } + + if (id && type && type !== 'password') { + STORAGE.setItem(NAME + id, val); + } + }); + + $element.submit(() => { + $element.data(DATA_KEY).clear(); + }); + + $element.find('button,[type="submit"],[type="clear"]').click(() => { + $element.data(DATA_KEY).clear(); + }); } - if (id && type && type !== 'password') { - STORAGE.setItem(NAME + id, val); + // Public methods + dispose() { + const $element = $(this._element); + + $element.removeClass(`${NAME}-active`); + $.removeData(this._element, DATA_KEY); + this._element = null; } - }); - $element.submit(() => { - $element.data(DATA_KEY).clear(); - }); + clear() { + STORAGE.clear(); + } - $element.find('button,[type="submit"],[type="clear"]').click(() => { - $element.data(DATA_KEY).clear(); - }); + static _jQueryInterface() { + if (typeof window.localStorage !== 'undefined') { + return this.each(function() { + // attach functionality to element + const $element = $(this); + let data = $element.data(DATA_KEY); + + if (!data) { + data = new FormStorage(this); + $element.data(DATA_KEY, data); + } + }); + } + } } - // Public methods - dispose() { - const $element = $(this._element); + // jQuery interface + $.fn[NAME] = FormStorage._jQueryInterface; + $.fn[NAME].Constructor = FormStorage; + $.fn[NAME].noConflict = function() { + $.fn[NAME] = JQUERY_NO_CONFLICT; + return FormStorage._jQueryInterface; + }; - $element.removeClass(`${NAME}-active`); - $.removeData(this._element, DATA_KEY); - this._element = null; - } + // auto-apply + $(window).on(`${Events.AJAX} ${Events.LOADED}`, () => { + $('form').jsFormStorage(); + }); - clear() { - STORAGE.clear(); - } - - static _jQueryInterface() { - if (typeof window.localStorage !== 'undefined') { - return this.each(function () { - // attach functionality to element - const $element = $(this); - let data = $element.data(DATA_KEY); - - if (!data) { - data = new FormStorage(this); - $element.data(DATA_KEY, data); - } - }); - } - } - } - - // jQuery interface - $.fn[NAME] = FormStorage._jQueryInterface; - $.fn[NAME].Constructor = FormStorage; - $.fn[NAME].noConflict = function () { - $.fn[NAME] = JQUERY_NO_CONFLICT; - return FormStorage._jQueryInterface; - }; - - // auto-apply - $(window).on(`${Events.AJAX} ${Events.LOADED}`, () => { - $('form').jsFormStorage(); - }); - - return FormStorage; + return FormStorage; })($); export default FormStorage; diff --git a/app/client/src/js/main.js b/app/client/src/js/main.js index eca03a6..b89e3f4 100644 --- a/app/client/src/js/main.js +++ b/app/client/src/js/main.js @@ -300,4 +300,4 @@ const MainUI = (($) => { return MainUI; })($); -export default MainUI; \ No newline at end of file +export default MainUI; diff --git a/app/client/src/scss/_bootstrap_variables.scss b/app/client/src/scss/_bootstrap_variables.scss deleted file mode 100644 index cfbe4f3..0000000 --- a/app/client/src/scss/_bootstrap_variables.scss +++ /dev/null @@ -1,10 +0,0 @@ -// bootstrap minify bugfix: -$navbar-dark-toggler-icon-bg: none; -$navbar-light-toggler-icon-bg: none; - -// IE > 9 -$enable-flex: true; - -@import "~bootstrap/scss/functions"; -@import "~bootstrap/scss/variables"; -@import "~bootstrap/scss/mixins"; \ No newline at end of file diff --git a/app/client/src/scss/_layout.scss b/app/client/src/scss/_layout.scss index 38a8a40..9722f34 100644 --- a/app/client/src/scss/_layout.scss +++ b/app/client/src/scss/_layout.scss @@ -1,14 +1,3 @@ /** * Your custom style */ - -@import "_components/ui.carousel"; - -// hide default page title cuz elemental object will be used to display titles -h1 { - display: none; -} - -img { - max-width: 100%; -} diff --git a/app/client/src/scss/_typography.scss b/app/client/src/scss/_typography.scss index 549bf46..359d8a6 100644 --- a/app/client/src/scss/_typography.scss +++ b/app/client/src/scss/_typography.scss @@ -1,5 +1,8 @@ -@import "./_variables"; +h1, h2, h3, h4, h5, h6, +.h1, .h2, .h3, .h4, .h5, .h6 { + color: $dark-blue; +} .typography { @import "./types/editor"; -} \ No newline at end of file +} diff --git a/app/client/src/scss/_variables.scss b/app/client/src/scss/_variables.scss index a66c035..4ce314c 100644 --- a/app/client/src/scss/_variables.scss +++ b/app/client/src/scss/_variables.scss @@ -1,5 +1,35 @@ -@import "_bootstrap_variables"; - /* * Your custom variables - */ \ No newline at end of file + */ + +$font-family-base: "Lato", sans-serif; + +$grid-gutter-height: 8rem; + +$gray-900: #212529; +$white: #fff; +$blue: #016cb1; +$yellow: #ecac02; + +$dark-blue: #113362; + +$body-color: $gray-900; +$navbar-light-active-color: $blue; + +$dropdown-border-color: $white; + +/* + * bootstrap includes + * keep it at the end + */ + +// bootstrap minify bugfix: +$navbar-dark-toggler-icon-bg: none; +$navbar-light-toggler-icon-bg: none; + +// IE > 9 +$enable-flex: true; + +@import "~bootstrap/scss/functions"; +@import "~bootstrap/scss/variables"; +@import "~bootstrap/scss/mixins"; diff --git a/app/client/src/scss/app.scss b/app/client/src/scss/app.scss index 787d798..68d9211 100644 --- a/app/client/src/scss/app.scss +++ b/app/client/src/scss/app.scss @@ -1,6 +1,7 @@ -// Bootstrap -@import "_bootstrap_variables"; +// Your custom variables +@import "_variables"; +// Bootstrap @import "~bootstrap/scss/root"; @import "~bootstrap/scss/reboot"; @import "~bootstrap/scss/type"; @@ -45,10 +46,87 @@ $lightbox-link-hover-color: $link-hover-color; @import "~meta-lightbox/scss/meta-lightbox"; @import "~meta-lightbox/scss/meta-lightbox-theme"; +@import "_components/ui.carousel"; -// Your custom variables -@import "_variables"; +/* + * some basic styles + */ + +// hide default page title cuz elemental object will be used to display titles +h1 { + display: none; +} + +// don't let images be wider than the parent layer +iframe, +img { + max-width: 100%; +} + +a:hover, +a:focus { + opacity: .8; +} + +// transactions +.transition, +a, a img, +button, input, optgroup, select, textarea, +.btn, +.alert, +.dropdown, +[data-target], +.container, +.container-fluid, +.row, +[class="col-*"] { + transition: all 0.4s ease; +} + +// stick navbar to top using mobile layout +#Header { + position: relative; + padding-top: $grid-gutter-height / 2; + padding-bottom: 1rem; + + @media (min-width: map-get($grid-breakpoints, "lg")) { + padding-top: 1rem; + padding-bottom: 0; + } +} + +#Navigation { + position: fixed; + top: 0; + left: 0; + width: 100%; + + @media (min-width: map-get($grid-breakpoints, "lg")) { + position: relative; + margin-top: 1rem; + } +} + +// add top/bottom paddings for basic elements +.page-content > .element { + position: relative; + padding: ($grid-gutter-height / 2) 0; + + // remove paddings of the slideshow + &.dynamic__elements__image__elements__elementimage, + &.dynamic__elements__flexslider__elements__elementslideshow { + padding: 0; + } +} + +// remove container paddings for the slideshow +.dynamic__elements__image__elements__elementimage, +.dynamic__elements__flexslider__elements__elementslideshow { + .container-fluid { + padding: 0; + } +} // Your custom UI @import "_typography"; -@import "_layout"; \ No newline at end of file +@import "_layout"; diff --git a/app/client/src/scss/types/editor.scss b/app/client/src/scss/types/editor.scss index 2385ddd..5ccefe7 100644 --- a/app/client/src/scss/types/editor.scss +++ b/app/client/src/scss/types/editor.scss @@ -1 +1 @@ -@import "../_variables"; \ No newline at end of file +@import "../_variables"; diff --git a/app/composer.json b/app/composer.json new file mode 100644 index 0000000..b7bcacb --- /dev/null +++ b/app/composer.json @@ -0,0 +1,11 @@ +{ + "autoload": { + "psr-4": { + "Site\\": "app/src/" + }, + "classmap": [ + "app/src/Pages/Page.php", + "app/src/Pages/PageController.php" + ] + } +} diff --git a/app/src/Elements/TeamMembersElement.php b/app/src/Elements/TeamMembersElement.php new file mode 100644 index 0000000..2befdfc --- /dev/null +++ b/app/src/Elements/TeamMembersElement.php @@ -0,0 +1,30 @@ +sort('RAND()'); + } +} \ No newline at end of file diff --git a/app/src/Extensions/BlogPostExtension.php b/app/src/Extensions/BlogPostExtension.php new file mode 100644 index 0000000..79a1d8b --- /dev/null +++ b/app/src/Extensions/BlogPostExtension.php @@ -0,0 +1,40 @@ +owner->getField('Summary'); + if($summary){ + return $summary; + } + + BaseElement:: + $element = ElementContent::get()->filter([ + 'ParentID' => $this->owner->ElementalArea()->ID, + 'HTML:not' => [null], + ])->first(); + + if($element){ + return $element->dbObject('HTML')->Summary($wordsToDisplay); + } + + return false; + } +} \ No newline at end of file diff --git a/app/src/Extensions/ElementContentWidget.php b/app/src/Extensions/ElementContentWidget.php new file mode 100644 index 0000000..8687582 --- /dev/null +++ b/app/src/Extensions/ElementContentWidget.php @@ -0,0 +1,41 @@ + 'Varchar(255)', + ]; + + private static $has_one = [ + 'BlockLink' => Link::class, + ]; + + public function updateCMSFields(FieldList $fields) + { + parent::updateCMSFields($fields); + + $tab = $fields->findOrMakeTab('Root.Main'); + $tab->push( + FontAwesomeField::create('BlockIcon') + ); + + $tab->push( + LinkField::create('BlockLinkID', 'Link') + ); + } +} \ No newline at end of file diff --git a/app/src/Extensions/ElementImageWidget.php b/app/src/Extensions/ElementImageWidget.php new file mode 100644 index 0000000..c5162c4 --- /dev/null +++ b/app/src/Extensions/ElementImageWidget.php @@ -0,0 +1,111 @@ + 'Small (300px)', + '400' => 'Medium (400px)', + '600' => 'Big (600px)', + ]; + + private static $db = [ + 'ImageHeight' => 'Float', + 'Content' => 'HTMLText', + ]; + + private static $has_one = [ + 'ImageLink' => Link::class, + ]; + + public function updateCMSFields(FieldList $fields) + { + parent::updateCMSFields($fields); + + $fields->insertBefore( + 'Image', + LinkField::create('ImageLinkID', 'Link') + ); + + $this->owner->ImageHeight = $this->getHeight(); + + $heights = Config::inst()->get(__CLASS__, 'available_heights'); + if (count($heights)) { + $fields->replaceField( + 'ImageHeight', + DropdownField::create( + 'ImageHeight', + 'Image Height', + $heights, + $this->getHeight() + )->setEmptyString('(unspecified)') + ); + } else { + $fields->dataFieldByName('ImageHeight') + ->setValue($this->getHeight()); + } + } + + public function ImageResized() + { + $image = $this->owner->Image(); + $width = $this->getWidth(); + $height = $this->getHeight(); + + if (!$width) { + return $height > 0 + ? $image->ScaleHeight($height) + : $image; + } + + return $height > 0 + ? $image->Fill($width, $height) + : $image->ScaleWidth($width); + } + + 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; + } + + public function getHeight() + { + $height = $this->owner->getField('ImageHeight'); + if ($height > 0) { + return $height; + } + + $sibling = $this->owner->getSibling(false, [ + 'ImageHeight:GreaterThan' => '0' + ]); + + if ($sibling && $sibling->getField('ImageHeight')) { + return $sibling->getField('ImageHeight'); + } + + return 0; + } +} diff --git a/app/src/Extensions/ElementRows.php b/app/src/Extensions/ElementRows.php index 456247e..0f3a373 100644 --- a/app/src/Extensions/ElementRows.php +++ b/app/src/Extensions/ElementRows.php @@ -8,64 +8,82 @@ namespace Site\Extensions; - use DNADesign\ElementalList\Model\ElementList; +use Dynamic\Elements\Image\Elements\ElementImage; use SilverStripe\Forms\DropdownField; use SilverStripe\ORM\DataExtension; use SilverStripe\Forms\FieldList; -use SilverStripe\ORM\FieldType\DBEnum; class ElementRows extends DataExtension { + private static $container_max_width = 1140; private static $column_class = 'col-md-'; + private static $container_styles = [ - 'container' => 'Fixed container', - 'container-fluid' => 'Fluid Container', + 'container' => 'Fixed container', + 'container-fluid' => 'Fluid Container', ]; private static $db = [ - 'Size' => 'Enum("1,2,3,4,5,6,7,8,9,10,11,12","6")', + 'ContainerType' => 'Varchar(254)', + 'Size' => 'Enum("1,2,3,4,5,6,7,8,9,10,11,12","6")', ]; public function updateCMSFields(FieldList $fields) { + parent::updateCMSFields($fields); + $tab = $fields->findOrMakeTab('Root.Main'); - if($this->isRoot() && $this->isList()) { - $styleDropdown = $fields->dataFieldByName('Style'); - if ($styleDropdown) { - $styleDropdown->setSource(self::$container_styles); - } else { - $styleDropdown = DropdownField::create( - 'Style', - _t(__CLASS__.'.STYLE', 'Style variation'), - self::$container_styles - ); - $fields->insertBefore($styleDropdown, 'ExtraClass'); - } + // container type + if ($this->isRoot()) { + $tab->push(DropdownField::create( + 'ContainerType', + _t(__CLASS__.'.CONTAINERTYPE', 'Container Type'), + self::$container_styles + )); + } else { + $fields->removeByName('ContainerType'); } - if($this->isColumn()) { + // column size + if ($this->isColumn()) { $sizes = $this->owner->dbObject('Size'); $defaultSize = $sizes->getDefaultValue(); $sizeDropdown = DropdownField::create( 'Size', - 'Column Size (12 cols grid, ex. for 3 equal cols: 12/3 = 4 is the size that you need)', - $sizes->enumValues() + _t( + __CLASS__.'.SIZE', + 'Column Size' + ), + array_combine( + array_values($sizes->enumValues()), + [ + '8.3%', + '16.6%', + '25%', + '33%', + '41.6%', + '50%', + '58.3%', + '66.4%', + '74.7%', + '83%', + '91.3%', + '100%', + ] + ) ); $tab->push($sizeDropdown); // set default size - if(!$this->owner->getField('Size')){ - $sibling = $this->owner->Parent() - ->Elements() - ->exclude('ID', $this->owner->ID) - ->last(); + if (!$this->owner->getField('Size')) { + $sibling = $this->getSibling(); $sizeDropdown->setValue($sibling ? $sibling->getField('Size') : $defaultSize); } - }else{ + } else { $fields->removeByName('Size'); } } @@ -77,7 +95,7 @@ class ElementRows extends DataExtension public function isRow() { - if(!$this->isList()){ + if (!$this->isList()) { return false; } @@ -86,7 +104,7 @@ class ElementRows extends DataExtension public function isColumn() { - if(!$this->isRoot() && !$this->isRow()){ + if (!$this->isRoot()) { return true; } @@ -96,35 +114,66 @@ class ElementRows extends DataExtension public function isRoot() { $parent = $this->owner->Parent()->getOwnerPage(); - if(is_a($parent, 'Page')){ + if (is_a($parent, 'Page')) { return true; } return false; } + public function getSibling($any = true, $filter = [], $exclude = []) + { + $class = $any ? $this->owner->baseClass() : $this->owner->ClassName; + + return $class::get()->filter(array_merge( + ['ParentID' => $this->owner->Parent()->ID], + $filter + ))->exclude(array_merge( + ['ID' => $this->owner->ID], + $exclude + ))->last(); + } + + public function getColumnSizeRecursive($object = null) + { + $object = $object ? $object : $this->owner; + + 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 : 12; + } + + return $object->getColumnSizeRecursive($parent); + } + } + public function ExtraClass() { - return $this->isColumn() - ? self::$column_class.$this->owner->getField('Size') - : ''; + return $this->owner->getField('ExtraClass') + .( + $this->isColumn() + ? ' col '.self::$column_class.$this->owner->getField('Size') + : '' + ); } /* * if it's root element and it doesn't contain any container styles * add the first one */ - public function updateStyleVariant(&$style) + public function ContainerClass() { - $style = $this->owner->getField('Style'); + $type = $this->owner->getField('ContainerType'); $container_styles = array_keys(self::$container_styles); - if( - $this->isRoot() - && $this->isList() - && !in_array($style, $container_styles) - ){ - $style = $container_styles[0]; + if (!$type && $this->isRoot()) { + $type = $container_styles[0]; } + + return $type; } -} \ No newline at end of file +} diff --git a/app/src/Extensions/HiddenType.php b/app/src/Extensions/HiddenType.php new file mode 100644 index 0000000..96f6100 --- /dev/null +++ b/app/src/Extensions/HiddenType.php @@ -0,0 +1,17 @@ + 'Varchar(255)', - ]; - - private static $has_one = [ - 'PhoneNumber' => Link::class + 'ShortDescription' => 'Text', + 'ExtraCode' => 'Text', ]; private static $many_many = [ - 'Navigation' => SiteTree::class + 'Navigation' => SiteTree::class, + 'Services' => SiteTree::class, + 'QuickLinks' => SiteTree::class, ]; public function updateCMSFields(FieldList $fields) @@ -33,10 +30,20 @@ class SiteConfigExtension extends DataExtension 'Navigation', SiteTree::class )); - $tab->push( - LinkField::create('PhoneNumberID', 'Phone Number') - ->setAllowedTypes(['Phone']) - ); - $tab->push(TextField::create('Address')); + + $tab->push(TreeMultiselectField::create( + 'Services', + 'Services', + SiteTree::class + )); + $tab->push(TreeMultiselectField::create( + 'QuickLinks', + 'QuickLinks', + SiteTree::class + )); + + $tab->push(TextareaField::create('ShortDescription')); + + $tab->push(TextareaField::create('ExtraCode', 'Extra site-wide HTML code')); } } diff --git a/app/src/Extensions/SiteTreeExtension.php b/app/src/Extensions/SiteTreeExtension.php new file mode 100644 index 0000000..a571b3a --- /dev/null +++ b/app/src/Extensions/SiteTreeExtension.php @@ -0,0 +1,28 @@ + 'Text', + ]; + + public function updateCMSFields(FieldList $fields) + { + $tab = $fields->findOrMakeTab('Root.Settings'); + + $tab->push(Textarea::create( + 'ExtraCode', + 'Extra page specific HTML code' + )); + } +} diff --git a/app/src/Extensions/SocialExtension.php b/app/src/Extensions/SocialExtension.php new file mode 100644 index 0000000..c7d212b --- /dev/null +++ b/app/src/Extensions/SocialExtension.php @@ -0,0 +1,63 @@ + 'Varchar(255)', + ]; + + private static $has_one = [ + 'Facebook' => Link::class, + 'LinkedIn' => Link::class, + 'GooglePlus' => Link::class, + 'Instagram' => Link::class, + 'Twitter' => Link::class, + 'PublicEmail' => Link::class, + 'PhoneNumber' => Link::class, + ]; + + public function updateCMSFields(FieldList $fields) + { + parent::updateCMSFields($fields); + + $linkFields = [ + LinkField::create('FacebookID'), + LinkField::create('LinkedInID'), + LinkField::create('GooglePlusID'), + LinkField::create('InstagramID'), + LinkField::create('TwitterID'), + ]; + + foreach ($linkFields as $field) { + $field->setAllowedTypes(['URL']); + } + + $fields->findOrMakeTab('Root.Social'); +UserDefinedForm:: + $fields->addFieldsToTab('Root.Social', [ + LinkField::create('PublicEmailID', 'Public Email') + ->setAllowedTypes(['Email']), + LinkField::create('PhoneNumberID', 'Phone Number') + ->setAllowedTypes(['Phone']), + TextField::create('Address'), + ]); + + $fields->addFieldsToTab('Root.Social', $linkFields); + } +} \ No newline at end of file diff --git a/app/src/Models/TeamMember.php b/app/src/Models/TeamMember.php new file mode 100644 index 0000000..489f385 --- /dev/null +++ b/app/src/Models/TeamMember.php @@ -0,0 +1,54 @@ + 'Varchar(254)', + 'LastName' => 'Varchar(254)', + 'Company' => 'Varchar(254)', + 'Position' => 'Varchar(254)', + ]; + + private static $has_one = [ + 'Photo' => Image::class, + 'Page' => TeamPage::class, + ]; + + private static $extensions = [ + SocialExtension::class, + Versioned::class, + ]; + + private static $owns = [ + 'Photo', + ]; + + private static $summary_fields = [ + 'Company', + 'FirstName', + 'LastName', + 'Position', + ]; + + public function getTitle() + { + return $this->getField('Company').' | '.$this->getField('FirstName').' '.$this->getField('LastName'); + } +} \ No newline at end of file diff --git a/app/src/Pages/HomePage.php b/app/src/Pages/HomePage.php index 5d334bd..f7f85b2 100644 --- a/app/src/Pages/HomePage.php +++ b/app/src/Pages/HomePage.php @@ -1,6 +1,7 @@ TeamMember::class, + ]; + + private static $owns = [ + 'Members', + ]; + + public function getCMSFields() + { + $fields = parent::getCMSFields(); + + $fields->addFieldToTab( + 'Root.Members', + GridField::create( + 'Members', + '', + $this->Members(), + GridFieldConfig_RecordEditor::create() + ) + ); + + return $fields; + } +} \ No newline at end of file diff --git a/app/src/Pages/TeamPageController.php b/app/src/Pages/TeamPageController.php new file mode 100644 index 0000000..e610518 --- /dev/null +++ b/app/src/Pages/TeamPageController.php @@ -0,0 +1,15 @@ + $StyleVariant<% end_if %><% if $ExtraClass %> $ExtraClass<% end_if %>" id="$Anchor"> +
+ $Element +
+ diff --git a/app/templates/DNADesign/Elemental/Models/ElementContent.ss b/app/templates/DNADesign/Elemental/Models/ElementContent.ss new file mode 100644 index 0000000..2ecdd9a --- /dev/null +++ b/app/templates/DNADesign/Elemental/Models/ElementContent.ss @@ -0,0 +1,18 @@ +
+ <% if $BlockIcon %> + + <% end_if %> + <% if $ShowTitle %> +

$Title

+ <% end_if %> + +
+ $HTML +
+ + <% if $BlockLink %> + + $BlockLink.Title + + <% end_if %> +
diff --git a/app/templates/DNADesign/ElementalUserForms/Model/ElementForm.ss b/app/templates/DNADesign/ElementalUserForms/Model/ElementForm.ss new file mode 100644 index 0000000..7b0d5b3 --- /dev/null +++ b/app/templates/DNADesign/ElementalUserForms/Model/ElementForm.ss @@ -0,0 +1,10 @@ +
+
+
+ <% if $Title && $ShowTitle %> +

$Title

+ <% end_if %> + $Form +
+
+
diff --git a/app/templates/Dynamic/Elements/Blog/Elements/ElementBlogPosts.ss b/app/templates/Dynamic/Elements/Blog/Elements/ElementBlogPosts.ss new file mode 100644 index 0000000..f940aa8 --- /dev/null +++ b/app/templates/Dynamic/Elements/Blog/Elements/ElementBlogPosts.ss @@ -0,0 +1,14 @@ +<% if $Title && $ShowTitle %>

$Title

<% end_if %> +<% if $Content %>
$Content
<% end_if %> + +<% if $PostsList %> +
+ <% loop $PostsList %> +
+ <% include BlogPostInfo %> +
+ <% end_loop %> +
+ <%-- p>View all posts

+<% end_if %> + diff --git a/app/templates/Dynamic/Elements/Elements/ElementTestimonials.ss b/app/templates/Dynamic/Elements/Elements/ElementTestimonials.ss new file mode 100644 index 0000000..d043b32 --- /dev/null +++ b/app/templates/Dynamic/Elements/Elements/ElementTestimonials.ss @@ -0,0 +1,14 @@ +<% if $Title && $ShowTitle %>

$Title

<% end_if %> +<% if $Content %>
$Content
<% end_if %> + +<% if $TestimonialsList %> +
+ <% loop $TestimonialsList %> + <% if $Content || $Name || $Affiliation %> +
+ <% include Objects\Testimonial %> +
+ <% end_if %> + <% end_loop %> +
+<% end_if %> \ No newline at end of file diff --git a/app/templates/Dynamic/Elements/Image/Elements/ElementImage.ss b/app/templates/Dynamic/Elements/Image/Elements/ElementImage.ss index 3671843..60a9b9a 100644 --- a/app/templates/Dynamic/Elements/Image/Elements/ElementImage.ss +++ b/app/templates/Dynamic/Elements/Image/Elements/ElementImage.ss @@ -1,4 +1,24 @@ -<% if $ShowTitle %>

$Title

<% end_if %> -<% if $Image %> - $Title.ATT +<% if $ImageResized %> +
+ <% if $ImageLink %><% end_if %> + $Title.ATT + <% if $ImageLink %><% end_if %> +
<% end_if %> + +
+
+ <% if $ShowTitle %>

$Title

<% end_if %> + + <% if $Content %> +
$Content
+ <% end_if %> + + <% if $ImageLink %> + + $ImageLink.Title + + + <% end_if %> +
+
\ No newline at end of file diff --git a/app/templates/Includes/BlogPostInfo.ss b/app/templates/Includes/BlogPostInfo.ss new file mode 100644 index 0000000..1e00a80 --- /dev/null +++ b/app/templates/Includes/BlogPostInfo.ss @@ -0,0 +1,25 @@ +
+
+
$PublishDate.Format("d")
+
$PublishDate.Format("MMM")
+
+ <% if $FeaturedImage %> + + <% end_if %> + + <% include SilverStripe\\Blog\\EntryMeta %> + +
+ + $Title + +
+ +
+ $Summary +
+ + Read More » +
\ No newline at end of file diff --git a/app/templates/Includes/Content.ss b/app/templates/Includes/Content.ss index 375aec4..b855e20 100644 --- a/app/templates/Includes/Content.ss +++ b/app/templates/Includes/Content.ss @@ -9,6 +9,12 @@ $Form <% end_if %> + + <% if $ExtraCode %> +
+ $ExtraCode +
+ <% end_if %> - - \ No newline at end of file + + diff --git a/app/templates/Includes/FlexSlider.ss b/app/templates/Includes/FlexSlider.ss index 107a3be..35b02a3 100644 --- a/app/templates/Includes/FlexSlider.ss +++ b/app/templates/Includes/FlexSlider.ss @@ -3,22 +3,24 @@