diff --git a/admin/client/dist/images/cms_content_header.png b/admin/client/dist/images/cms_content_header.png new file mode 100644 index 0000000..d815a26 Binary files /dev/null and b/admin/client/dist/images/cms_content_header.png differ diff --git a/admin/client/dist/js/bundle.js b/admin/client/dist/js/bundle.js index 7fb6569..984692c 100644 --- a/admin/client/dist/js/bundle.js +++ b/admin/client/dist/js/bundle.js @@ -1 +1 @@ -!function(t){function e(i){if(n[i])return n[i].exports;var a=n[i]={i:i,l:!1,exports:{}};return t[i].call(a.exports,a,a.exports,e),a.l=!0,a.exports}var n={};e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,i){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:i})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="/silverware/admin/client/dist/",e(e.s=5)}([function(t,e){t.exports=jQuery},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var i=n(0);n.n(i).a.entwine("ss.tab.badges",function(t){t("div.ss-tabset").entwine({onmatch:function(){this._super();var e=this;if(this.attr("data-number-badges")){var n=t.parseJSON(this.attr("data-number-badges"));t.each(n,function(t,n){if(n){var i=e.findTab(t);i.length&&i.append(''+n+"")}})}},findTab:function(t){return this.find(this.getTabId(t))},getTabId:function(t){return"a#tab-"+t.replace(".","_")}})})},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var i=n(0);n.n(i).a.entwine("ss",function(t){t("*[class*=class-]").entwine({onmatch:function(){this._super(),t(this).attr("class",t(this).attr("class").replace(/\\/g,"_"))}})})},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var i=n(0);n.n(i).a.entwine("ss.autocompletefield",function(t){t(".field.autocomplete input.text").entwine({onmatch:function(){this._super(),this.initField(),this.initClear()},onfocusin:function(){this.getValue()>=this.getMinLength()&&t(this).autocomplete("search")},initField:function(){var e=this;t(this).autocomplete({source:e.getSourceURL(),minLength:e.getMinLength(),delay:e.getDelay(),change:function(t,n){e.update(t,n)},select:function(t,n){e.update(t,n)}})},initClear:function(){var e=this;t(this).parent().find("a.clear").click(function(t){t.preventDefault(),e.clearValue()})},setValue:function(e){t(this).val(e)},getValue:function(){return t(this).val()},getSourceURL:function(){return t(this).attr("data-source-url")},getMinLength:function(){return t(this).attr("data-min-length")},isFreeTextAllowed:function(){return!!t(this).attr("data-free-text")},getDelay:function(){return t(this).attr("data-delay")},getEmptyValue:function(){return t(this).attr("data-empty-value")},getHiddenInput:function(){return t(this).parent().find(":hidden")},getValueWrapper:function(){return t(this).parent().find(".value-wrapper")},getValueElement:function(){return t(this).parent().find(".value-wrapper > .value")},update:function(t,e){var n=this.getValue();n&&(e.item?this.updateValue(e.item.value,e.item.label):this.isFreeTextAllowed()&&this.updateValue(n))},updateValue:function(t,e){e||(e=t),this.getHiddenInput().val()!==t&&(this.getHiddenInput().val(t),this.getValueElement().text(e),this.getValueWrapper().addClass("has-value"))},clearValue:function(){this.getHiddenInput().val(""),this.getValueElement().text(this.getEmptyValue()),this.getValueWrapper().removeClass("has-value")}})})},function(t,e){},function(t,e,n){n(4),n(2),n(1),n(3)}]); \ No newline at end of file +!function(t){function e(i){if(n[i])return n[i].exports;var a=n[i]={i:i,l:!1,exports:{}};return t[i].call(a.exports,a,a.exports,e),a.l=!0,a.exports}var n={};e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,i){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:i})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="/silverware/admin/client/dist/",e(e.s=6)}([function(t,e){t.exports=jQuery},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var i=n(0);n.n(i).a.entwine("ss.tab.badges",function(t){t("div.ss-tabset").entwine({onmatch:function(){this._super();var e=this;if(this.attr("data-number-badges")){var n=t.parseJSON(this.attr("data-number-badges"));t.each(n,function(t,n){if(n){var i=e.findTab(t);i.length&&i.append(''+n+"")}})}},findTab:function(t){return this.find(this.getTabId(t))},getTabId:function(t){return"a#tab-"+t.replace(".","_")}})})},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var i=n(0);n.n(i).a.entwine("ss",function(t){t("*[class*=class-]").entwine({onmatch:function(){this._super(),t(this).attr("class",t(this).attr("class").replace(/\\/g,"_"))}})})},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var i=n(0);n.n(i).a.entwine("ss.autocompletefield",function(t){t(".field.autocomplete input.text").entwine({onmatch:function(){this._super(),this.initField(),this.initClear()},onfocusin:function(){this.getValue()>=this.getMinLength()&&t(this).autocomplete("search")},initField:function(){var e=this;t(this).autocomplete({source:e.getSourceURL(),minLength:e.getMinLength(),delay:e.getDelay(),change:function(t,n){e.update(t,n)},select:function(t,n){e.update(t,n)}})},initClear:function(){var e=this;t(this).parent().find("a.clear").click(function(t){t.preventDefault(),e.clearValue()})},setValue:function(e){t(this).val(e)},getValue:function(){return t(this).val()},getSourceURL:function(){return t(this).attr("data-source-url")},getMinLength:function(){return t(this).attr("data-min-length")},isFreeTextAllowed:function(){return!!t(this).attr("data-free-text")},getDelay:function(){return t(this).attr("data-delay")},getEmptyValue:function(){return t(this).attr("data-empty-value")},getHiddenInput:function(){return t(this).parent().find(":hidden")},getValueWrapper:function(){return t(this).parent().find(".value-wrapper")},getValueElement:function(){return t(this).parent().find(".value-wrapper > .value")},update:function(t,e){var n=this.getValue();n&&(e.item?this.updateValue(e.item.value,e.item.label):this.isFreeTextAllowed()&&this.updateValue(n))},updateValue:function(t,e){e||(e=t),this.getHiddenInput().val()!==t&&(this.getHiddenInput().val(t),this.getValueElement().text(e),this.getValueWrapper().addClass("has-value"))},clearValue:function(){this.getHiddenInput().val(""),this.getValueElement().text(this.getEmptyValue()),this.getValueWrapper().removeClass("has-value")}})})},function(t,e){},,function(t,e,n){n(4),n(2),n(1),n(3)}]); \ No newline at end of file diff --git a/admin/client/dist/js/preview.js b/admin/client/dist/js/preview.js new file mode 100644 index 0000000..50bd97f --- /dev/null +++ b/admin/client/dist/js/preview.js @@ -0,0 +1 @@ +!function(n){function t(e){if(r[e])return r[e].exports;var o=r[e]={i:e,l:!1,exports:{}};return n[e].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};t.m=n,t.c=r,t.i=function(n){return n},t.d=function(n,r,e){t.o(n,r)||Object.defineProperty(n,r,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var r=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(r,"a",r),r},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="/silverware/admin/client/dist/",t(t.s=7)}({5:function(n,t){},7:function(n,t,r){r(5)}}); \ No newline at end of file diff --git a/admin/client/dist/styles/preview.css b/admin/client/dist/styles/preview.css new file mode 100644 index 0000000..2a6b405 --- /dev/null +++ b/admin/client/dist/styles/preview.css @@ -0,0 +1 @@ +.cms-preview-component{overflow:hidden}.cms-preview-component .cms-preview-wrapper{top:0;left:0;right:0;bottom:0;position:absolute}.cms-preview-component .cms-preview-wrapper>header{min-height:53px;padding-left:1.2308rem;white-space:nowrap;font-size:.846rem;background-repeat:repeat;background-position:0 100%;background-color:#f0f2f4;background-image:url(/silverware/admin/client/dist/images/cms_content_header.png)}.cms-preview-component .cms-preview-wrapper>header>h1{margin:0;color:#4f5861;font-size:1.2em;font-weight:400;line-height:53px}.cms-preview-component .cms-preview-wrapper>header>h1 i,.cms-preview-component .cms-preview-wrapper>header>h1 span.class{color:#66727d}.cms-preview-component .cms-preview-wrapper>div.component{top:53px;bottom:0;width:100%;height:auto;padding:1.2308rem;overflow-x:hidden;overflow-y:auto;position:absolute;background-color:#f6f7f8}.cms-preview-component .cms-preview-wrapper>div.component>div.preview{background-color:#fff;box-shadow:0 5px 10px rgba(0,0,0,.2)} \ No newline at end of file diff --git a/admin/client/src/bundles/preview.js b/admin/client/src/bundles/preview.js new file mode 100644 index 0000000..7f18074 --- /dev/null +++ b/admin/client/src/bundles/preview.js @@ -0,0 +1,6 @@ +/* SilverWare Preview Bundle +===================================================================================================================== */ + +// Load Styles: + +require('styles/preview.scss'); diff --git a/admin/client/src/styles/bundle.scss b/admin/client/src/styles/bundle.scss index 4ebe010..c364931 100644 --- a/admin/client/src/styles/bundle.scss +++ b/admin/client/src/styles/bundle.scss @@ -1,9 +1,10 @@ /* SilverWare Admin Bundle ===================================================================================================================== */ -// Import Admin Variables: +// Import Admin Styles: @import "~admin/styles/variables"; +@import "~admin/styles/legacy/themes/default"; // Import Local Variables: diff --git a/admin/client/src/styles/preview.scss b/admin/client/src/styles/preview.scss new file mode 100644 index 0000000..3657deb --- /dev/null +++ b/admin/client/src/styles/preview.scss @@ -0,0 +1,15 @@ +/* SilverWare Admin Bundle +===================================================================================================================== */ + +// Import Admin Styles: + +@import "~admin/styles/variables"; +@import "~admin/styles/legacy/themes/default"; + +// Import Local Variables: + +@import "variables"; + +// Import Styles: + +@import "preview/ComponentPreview"; diff --git a/admin/client/src/styles/preview/ComponentPreview.scss b/admin/client/src/styles/preview/ComponentPreview.scss new file mode 100644 index 0000000..648d1ef --- /dev/null +++ b/admin/client/src/styles/preview/ComponentPreview.scss @@ -0,0 +1,67 @@ +/* Component Preview Styles +===================================================================================================================== */ + +.cms-preview-component { + + overflow: hidden; + + .cms-preview-wrapper { + + top: 0; + left: 0; + right: 0; + bottom: 0; + position: absolute; + + > header { + + min-height: $toolbar-total-height; + padding-left: $spacer; + white-space: nowrap; + font-size: $font-size-xs; + + background: { + repeat: repeat; + position: left bottom; + color: $color-darker-bg; + image: url("~admin/images/textures/cms_content_header.png"); + } + + > h1 { + + margin: 0; + color: $color-text-default; + font-size: 1.2em; + font-weight: normal; + line-height: $toolbar-total-height; + + i, span.class { + color: $color-text; + } + + } + + } + + > div.component { + + top: $toolbar-total-height; + bottom: 0; + width: 100%; + height: auto; + padding: $spacer; + overflow-x: hidden; + overflow-y: auto; + position: absolute; + background-color: $tab-panel-texture-color; + + > div.preview { + background-color: $white; + box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.20); + } + + } + + } + +} diff --git a/src/Components/BaseComponent.php b/src/Components/BaseComponent.php index 4fbe163..d68a469 100644 --- a/src/Components/BaseComponent.php +++ b/src/Components/BaseComponent.php @@ -240,16 +240,6 @@ public function getShowTitle() return !$this->HideTitle; } - /** - * Answers the base template used to render the receiver. - * - * @return string|array|SSViewer - */ - public function getBaseTemplate() - { - return self::class; - } - /** * Renders the component for the HTML template. * @@ -262,7 +252,7 @@ public function renderSelf($layout = null, $title = null) { return $this->getController()->customise([ 'Content' => $this->renderContent($layout, $title) - ])->renderWith($this->getBaseTemplate()); + ])->renderWith(self::class); } /** diff --git a/src/Model/Component.php b/src/Model/Component.php index b4f7708..f3a1bca 100644 --- a/src/Model/Component.php +++ b/src/Model/Component.php @@ -361,6 +361,16 @@ public function providePermissions() ]; } + /** + * Answers the type of component as a string. + * + * @return string + */ + public function getComponentType() + { + return $this->i18n_singular_name(); + } + /** * Answers the default style ID for the HTML template. * @@ -698,16 +708,6 @@ public function tag($content = null) return $this->getOpeningTag() . $content . $this->getClosingTag(); } - /** - * Answers the template used to render the receiver. - * - * @return string|array|SSViewer - */ - public function getTemplate() - { - return static::class; - } - /** * Renders the component for the HTML template. * @@ -722,7 +722,7 @@ public function renderSelf($layout = null, $title = null) 'Self' => $this, 'Title' => $title, 'Layout' => $layout - ])->renderWith($this->getTemplate()); + ])->renderWith(static::class); } /** @@ -743,4 +743,14 @@ public function renderChildren($layout = null, $title = null) return $html; } + + /** + * Renders the component for preview within the CMS. + * + * @return DBHTMLText|string + */ + public function renderPreview() + { + return $this->renderSelf(); + } } diff --git a/src/Model/ComponentController.php b/src/Model/ComponentController.php index 8ffff2c..98fe25c 100644 --- a/src/Model/ComponentController.php +++ b/src/Model/ComponentController.php @@ -18,6 +18,10 @@ namespace SilverWare\Model; use SilverStripe\CMS\Controllers\ContentController; +use SilverStripe\View\Requirements; +use SilverStripe\View\SSViewer; +use Page; +use PageController; /** * An extension of the content controller class for a SilverWare component controller. @@ -30,4 +34,31 @@ */ class ComponentController extends ContentController { + /** + * Answers a viewer object to render the template for the current page. + * + * @param $action string + * + * @return SSViewer + */ + public function getViewer($action) + { + // Answer Viewer Object (from parent): + + if (!$this->isCMSPreview()) { + return parent::getViewer($action); + } + + // Load Page Requirements (uses theme): + + PageController::create(Page::create())->doInit(); + + // Load Preview Requirements: + + Requirements::css(SILVERWARE_DIR . '/admin/client/dist/styles/preview.css'); + + // Answer Viewer Object (for CMS preview): + + return new SSViewer(sprintf('%s\CMSPreview', Component::class)); + } } diff --git a/src/View/Renderable.php b/src/View/Renderable.php index 6401233..d260668 100644 --- a/src/View/Renderable.php +++ b/src/View/Renderable.php @@ -395,6 +395,16 @@ public function cleanStyleClasses($string) return preg_replace('/[^a-zA-Z0-9_-]+|[\s]+/', ' ', trim($string)); } + /** + * Answers true if the receiver is being previewed within the CMS. + * + * @return boolean + */ + public function isCMSPreview() + { + return (isset($_GET['CMSPreview']) && $_GET['CMSPreview']); + } + /** * Answers true if the object uses a render cache. * diff --git a/templates/SilverWare/Model/Component/CMSPreview.ss b/templates/SilverWare/Model/Component/CMSPreview.ss new file mode 100644 index 0000000..673ac80 --- /dev/null +++ b/templates/SilverWare/Model/Component/CMSPreview.ss @@ -0,0 +1,25 @@ + + + + + <% base_tag %> + + + + $MetaTags(false)$Title + + +
+
+

+ + <%t SilverWare\Model\Component.PREVIEW 'Preview' %> + ($ComponentType) +

+
+
+
$renderPreview.RAW
+
+
+ + diff --git a/templates/SilverWare/Model/Panel.ss b/templates/SilverWare/Model/Panel.ss new file mode 100644 index 0000000..ac1b269 --- /dev/null +++ b/templates/SilverWare/Model/Panel.ss @@ -0,0 +1 @@ +<% loop $AllChildren %>$Me<% end_loop %> diff --git a/webpack.config.js b/webpack.config.js index 6ed0733..af997e3 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -159,7 +159,8 @@ const config = (env) => { return [ { entry: { - 'bundle': path.resolve(PATHS.ADMIN.BUNDLES, 'bundle.js') + 'bundle': path.resolve(PATHS.ADMIN.BUNDLES, 'bundle.js'), + 'preview': path.resolve(PATHS.ADMIN.BUNDLES, 'preview.js') }, output: { path: PATHS.ADMIN.DIST,