From 12175b29db5eb94941b5c6f2fe461d154f5b9521 Mon Sep 17 00:00:00 2001 From: alekseybobkov Date: Thu, 16 Oct 2014 20:47:23 -0700 Subject: [PATCH] Multiple updates in the back-end widgets and styles --- modules/backend/assets/css/october.css | 99 +++++++++++++++++++ .../images/secondary-tab-shape-content.svg | 16 +++ modules/backend/assets/js/october.tab.js | 2 + .../assets/less/controls/fancylayout.less | 99 +++++++++++++++++++ modules/backend/formwidgets/CodeEditor.php | 2 +- .../richeditor/assets/css/richeditor.css | 4 +- .../richeditor/assets/js/richeditor.js | 2 +- .../richeditor/assets/less/richeditor.less | 4 +- modules/cms/classes/CmsCompoundObject.php | 32 ++++-- modules/cms/classes/Controller.php | 16 ++- modules/cms/classes/Page.php | 5 + modules/cms/twig/PlaceholderNode.php | 25 ++++- modules/cms/twig/PlaceholderTokenParser.php | 42 +++++++- 13 files changed, 321 insertions(+), 27 deletions(-) create mode 100644 modules/backend/assets/images/secondary-tab-shape-content.svg diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css index 9b44fa50e..26d3ed5f7 100644 --- a/modules/backend/assets/css/october.css +++ b/modules/backend/assets/css/october.css @@ -12894,6 +12894,99 @@ div.popover-overlay { -o-transform: scale(1, 1); transform: scale(1, 1); } +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs { + background: #f9f9f9; +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li { + margin-left: -19px; +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li:first-child, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li:first-child { + margin-left: 0; + padding-left: 8px; +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a { + padding: 8px 16px 0 16px; + font-weight: 400; + color: #2b3e50; + opacity: 0.6; + filter: alpha(opacity=60); +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title { + position: relative; + display: inline-block; + padding: 4px 5px 9px 5px; + font-size: 13px; + z-index: 100; + height: 25px!important; + background-color: transparent; +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title:before, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title:before, +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title:after, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title:after { + content: ' '; + position: absolute; + background: transparent url(../images/secondary-tab-shape-content.svg) no-repeat left top; + width: 15px; + height: 25px; + top: 0; + z-index: 100; + display: none; +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title:before, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title:before { + left: -15px; +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title:after, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title:after { + right: -15px; + background-position: -60px 0; +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title span, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li a > span.title span { + height: 18px; + font-size: 12px; +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li.active a, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li.active a { + opacity: 1; + filter: alpha(opacity=100); +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li.active a > span.title, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li.active a > span.title { + background-color: white; +} +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li.active a > span.title:before, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li.active a > span.title:before, +.fancy-layout .control-tabs.secondary.content-tabs > div > ul.nav-tabs > li.active a > span.title:after, +.fancy-layout.control-tabs.secondary.content-tabs > div > ul.nav-tabs > li.active a > span.title:after { + display: block; +} +.fancy-layout .control-tabs.secondary.content-tabs .tab-collapse-icon.primary, +.fancy-layout.control-tabs.secondary.content-tabs .tab-collapse-icon.primary { + color: #808c8d; +} +.fancy-layout .control-tabs.secondary.content-tabs.primary-collapsed .tab-collapse-icon.primary, +.fancy-layout.control-tabs.secondary.content-tabs.primary-collapsed .tab-collapse-icon.primary { + color: white; +} +.fancy-layout .control-tabs.secondary.content-tabs.primary-collapsed > div > ul.nav-tabs, +.fancy-layout.control-tabs.secondary.content-tabs.primary-collapsed > div > ul.nav-tabs { + background: #e67e22; +} +.fancy-layout .control-tabs.secondary.content-tabs.primary-collapsed > div > ul.nav-tabs > li a, +.fancy-layout.control-tabs.secondary.content-tabs.primary-collapsed > div > ul.nav-tabs > li a { + color: white; +} +.fancy-layout .control-tabs.secondary.content-tabs.primary-collapsed > div > ul.nav-tabs > li.active a, +.fancy-layout.control-tabs.secondary.content-tabs.primary-collapsed > div > ul.nav-tabs > li.active a { + color: #2b3e50; +} .fancy-layout .control-tabs.primary > div > ul.nav-tabs, .fancy-layout.control-tabs.primary > div > ul.nav-tabs { background: #7f8c8d; @@ -13167,6 +13260,12 @@ div.popover-overlay { border-top-right-radius: 0; border-top-left-radius: 0; } +.fancy-layout .content-tabs .field-richeditor .redactor-box .redactor-toolbar { + margin: 20px 20px 0 20px!important; + -webkit-border-radius: 3px !important; + -moz-border-radius: 3px !important; + border-radius: 3px !important; +} body.side-panel-not-fixed .fancy-layout .field-richeditor { border-left: none; } diff --git a/modules/backend/assets/images/secondary-tab-shape-content.svg b/modules/backend/assets/images/secondary-tab-shape-content.svg new file mode 100644 index 000000000..164511a94 --- /dev/null +++ b/modules/backend/assets/images/secondary-tab-shape-content.svg @@ -0,0 +1,16 @@ + + + +]> + + + + + + + + diff --git a/modules/backend/assets/js/october.tab.js b/modules/backend/assets/js/october.tab.js index a094a6433..6c9a8bebe 100644 --- a/modules/backend/assets/js/october.tab.js +++ b/modules/backend/assets/js/october.tab.js @@ -150,6 +150,8 @@ return false })) + pane.data('tab', li) + this.$el.trigger('initTab.oc.tab', [{'pane': pane, 'tab': li}]) } diff --git a/modules/backend/assets/less/controls/fancylayout.less b/modules/backend/assets/less/controls/fancylayout.less index da24c8e02..52b01a3a3 100644 --- a/modules/backend/assets/less/controls/fancylayout.less +++ b/modules/backend/assets/less/controls/fancylayout.less @@ -214,6 +214,98 @@ .scaleAxes(1, 1); } } + + &.content-tabs { + > div > ul.nav-tabs { + background: @color-body-bg; + + > li { + margin-left: -19px; + + &:first-child { + margin-left: 0; + padding-left: 8px; + } + + a { + padding: 8px 16px 0 16px; + font-weight: 400; + color: #2b3e50; + .opacity(0.6); + + > span.title { + position: relative; + display: inline-block; + padding: 4px 5px 9px 5px; + font-size: 13px; + z-index: 100; + height: 25px!important; + background-color: transparent; + + &:before, &:after { + content: ' '; + position: absolute; + background: transparent url(../images/secondary-tab-shape-content.svg) no-repeat left top; + width: 15px; + height: 25px; + top: 0; + z-index: 100; + display: none; + } + + &:before { + left: -15px; + } + + &:after { + right: -15px; + background-position: -60px 0; + } + + span { + height: 18px; + font-size: 12px; + } + } + } + + &.active a { + .opacity(1); + + > span.title { + background-color: white; + &:before, &:after { + display: block; + } + } + } + } + } + + .tab-collapse-icon.primary { + color: #808c8d; + } + + &.primary-collapsed { + .tab-collapse-icon.primary { + color: white; + } + + > div > ul.nav-tabs { + background: @color-fancy-form-tabless-fields-bg; + + > li { + a { + color: white; + } + + &.active a { + color: #2b3e50; + } + } + } + } + } } &.primary { @@ -459,6 +551,13 @@ .border-top-radius(0); } } + + .content-tabs .field-richeditor { + .redactor-box .redactor-toolbar { + margin: 20px 20px 0 20px!important; + .border-radius(3px)!important; + } + } } body.side-panel-not-fixed { diff --git a/modules/backend/formwidgets/CodeEditor.php b/modules/backend/formwidgets/CodeEditor.php index 89419b9cf..a52fadc63 100644 --- a/modules/backend/formwidgets/CodeEditor.php +++ b/modules/backend/formwidgets/CodeEditor.php @@ -88,7 +88,7 @@ class CodeEditor extends FormWidgetBase } /** - * Prepares the list data + * Prepares the widget data */ public function prepareVars() { diff --git a/modules/backend/formwidgets/richeditor/assets/css/richeditor.css b/modules/backend/formwidgets/richeditor/assets/css/richeditor.css index fde1cb191..df4d6abf6 100644 --- a/modules/backend/formwidgets/richeditor/assets/css/richeditor.css +++ b/modules/backend/formwidgets/richeditor/assets/css/richeditor.css @@ -1303,12 +1303,12 @@ body .redactor-box-fullscreen { } .redactor-toolbar, .redactor-dropdown { - z-index: 1350 !important; + z-index: 410 !important; } #redactor-modal-overlay, #redactor-modal-box, #redactor-modal { - z-index: 1351 !important; + z-index: 420 !important; } .redactor-toolbar { background: #dddddd; diff --git a/modules/backend/formwidgets/richeditor/assets/js/richeditor.js b/modules/backend/formwidgets/richeditor/assets/js/richeditor.js index a3b8ef3be..5ae2a4ee0 100644 --- a/modules/backend/formwidgets/richeditor/assets/js/richeditor.js +++ b/modules/backend/formwidgets/richeditor/assets/js/richeditor.js @@ -99,7 +99,7 @@ return if (this.$el.hasClass('stretch')) { - var height = $toolbar.height() + var height = $toolbar.outerHeight(true) $editor.css('top', height+1) $codeEditor.css('top', height) } diff --git a/modules/backend/formwidgets/richeditor/assets/less/richeditor.less b/modules/backend/formwidgets/richeditor/assets/less/richeditor.less index 5386d532f..bb2838a78 100644 --- a/modules/backend/formwidgets/richeditor/assets/less/richeditor.less +++ b/modules/backend/formwidgets/richeditor/assets/less/richeditor.less @@ -51,12 +51,12 @@ } .redactor-toolbar, .redactor-dropdown { - z-index: @richeditor-zindex + 1050 !important; + z-index: @richeditor-zindex + 110 !important; } #redactor-modal-overlay, #redactor-modal-box, #redactor-modal { - z-index: @richeditor-zindex + 1051 !important; + z-index: @richeditor-zindex + 120 !important; } .redactor-toolbar { diff --git a/modules/cms/classes/CmsCompoundObject.php b/modules/cms/classes/CmsCompoundObject.php index f7de93fb8..ef0399a0d 100644 --- a/modules/cms/classes/CmsCompoundObject.php +++ b/modules/cms/classes/CmsCompoundObject.php @@ -60,6 +60,8 @@ class CmsCompoundObject extends CmsObject protected $viewBagCache = false; + protected $originalData = []; + protected static $objectComponentPropertyMap = null; /** @@ -82,6 +84,10 @@ class CmsCompoundObject extends CmsObject $obj->code = $parsedData['code']; $obj->markup = $parsedData['markup']; + $obj->originalData['settings'] = $obj->settings; + $obj->originalData['code'] = $obj->code; + $obj->originalData['markup'] = $obj->markup; + $obj->parseComponentSettings(); $obj->parseSettings(); @@ -207,11 +213,14 @@ class CmsCompoundObject extends CmsObject $content[] = FileHelper::formatIniString($this->settings); if ($this->code) { - $code = preg_replace('/^\<\?php/', '', $this->code); - $code = preg_replace('/^\<\?/', '', $code); - $code = preg_replace('/\?>$/', '', $code); + if ($this->wrapCodeToPhpTags() && $this->originalData['code'] != $this->code) { + $code = preg_replace('/^\<\?php/', '', $this->code); + $code = preg_replace('/^\<\?/', '', $code); + $code = preg_replace('/\?>$/', '', $code); - $content[] = 'code.PHP_EOL.'?>'; + $content[] = 'code.PHP_EOL.'?>'; + } else + $content[] = $this->code; } $content[] = $this->markup; @@ -358,16 +367,18 @@ class CmsCompoundObject extends CmsObject * This method is used by the system internally and shouldn't * participate in the front-end request processing. * @link http://twig.sensiolabs.org/doc/internals.html Twig internals + * @param mixed $markup Specifies the markup content. + * Use FALSE to load the content from the markup section. * @return Twig_Node_Module A node tree */ - public function getTwigNodeTree() + public function getTwigNodeTree($markup = false) { $loader = new TwigLoader(); $twig = new Twig_Environment($loader, []); $twig->addExtension(new CmsTwigExtension()); $twig->addExtension(new SystemTwigExtension); - $stream = $twig->tokenize($this->markup, 'getTwigNodeTree'); + $stream = $twig->tokenize($markup === false ? $this->markup : $markup, 'getTwigNodeTree'); return $twig->parse($stream); } @@ -417,4 +428,13 @@ class CmsCompoundObject extends CmsObject throw new ValidationException($validation); } } + + /** + * Determines if the content of the code section should be wrapped to PHP tags. + * @return boolean + */ + protected function wrapCodeToPhpTags() + { + return true; + } } \ No newline at end of file diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 82d16e2fc..df4555bc7 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -250,11 +250,17 @@ class Controller extends BaseController /* * Render the page */ - CmsException::mask($this->page, 400); - $this->loader->setObject($this->page); - $template = $this->twig->loadTemplate($this->page->getFullPath()); - $this->pageContents = $template->render($this->vars); - CmsException::unmask(); + Event::fire('cms.page.beforeTwigRender', [$page, $this->loader, $this->twig], true); + + $apiResult = Event::fire('cms.page.getRenderedContents', [$this->page], true); + if (!strlen($apiResult)) { + CmsException::mask($this->page, 400); + $this->loader->setObject($this->page); + $template = $this->twig->loadTemplate($this->page->getFullPath()); + $this->pageContents = $template->render($this->vars); + CmsException::unmask(); + } else + $this->pageContents = $apiResult; /* * Render the layout diff --git a/modules/cms/classes/Page.php b/modules/cms/classes/Page.php index 50e767432..301b440d1 100644 --- a/modules/cms/classes/Page.php +++ b/modules/cms/classes/Page.php @@ -13,6 +13,11 @@ use Lang; */ class Page extends CmsCompoundObject { + /** + * @var array The API bag allows the API handler code to bind arbitrary data to the page object. + */ + public $apiBag = []; + protected $settingsValidationRules = [ 'title' => 'required', 'url' => ['required', 'regex:/^\/[a-z0-9\/\:_\-\*\[\]\+\?\|\.]*$/i'] diff --git a/modules/cms/twig/PlaceholderNode.php b/modules/cms/twig/PlaceholderNode.php index 6b25e4235..240d522a3 100644 --- a/modules/cms/twig/PlaceholderNode.php +++ b/modules/cms/twig/PlaceholderNode.php @@ -12,13 +12,16 @@ use Twig_NodeInterface; */ class PlaceholderNode extends Twig_Node { - public function __construct($name, $body, $lineno, $tag = 'placeholder') + public function __construct($name, $paramValues, $body, $lineno, $tag = 'placeholder') { $nodes = []; if ($body) $nodes['default'] = $body; + + $attributes = $paramValues; + $attributes['name'] = $name; - parent::__construct($nodes, ['name'=>$name], $lineno, $tag); + parent::__construct($nodes, $attributes, $lineno, $tag); } /** @@ -46,14 +49,26 @@ class PlaceholderNode extends Twig_Node ->raw("] = ob_get_clean();"); } + $isText = $this->hasAttribute('type') && $this->getAttribute('type') == 'text'; + + $compiler->addDebugInfo($this); + + if (!$isText) + $compiler->write("echo \$this->env->getExtension('CMS')->displayBlock("); + else + $compiler->write("echo twig_escape_filter(\$this->env, \$this->env->getExtension('CMS')->displayBlock("); + $compiler - ->addDebugInfo($this) - ->write("echo \$this->env->getExtension('CMS')->displayBlock(") ->raw("'".$this->getAttribute('name')."', ") ->raw("\$context[") ->raw("'".$varId."'") ->raw("]") - ->raw(");\n") + ->raw(")"); + + if (!$isText) + $compiler->raw(";\n"); + else + $compiler->raw(");\n"); ; $compiler diff --git a/modules/cms/twig/PlaceholderTokenParser.php b/modules/cms/twig/PlaceholderTokenParser.php index c66502680..20370ab2f 100644 --- a/modules/cms/twig/PlaceholderTokenParser.php +++ b/modules/cms/twig/PlaceholderTokenParser.php @@ -1,7 +1,9 @@ parser->getStream(); $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); $body = null; + $params = []; if ($stream->test(Twig_Token::NAME_TYPE, 'default')) { $stream->next(); - $stream->expect(Twig_Token::BLOCK_END_TYPE); + $params = $this->loadParams($stream); + $body = $this->parser->subparse([$this, 'decidePlaceholderEnd'], true); $stream->expect(Twig_Token::BLOCK_END_TYPE); - } else { - $stream->expect(Twig_Token::BLOCK_END_TYPE); - } + } else + $params = $this->loadParams($stream); - return new PlaceholderNode($name, $body, $token->getLine(), $this->getTag()); + return new PlaceholderNode($name, $params, $body, $token->getLine(), $this->getTag()); } public function decidePlaceholderEnd(Twig_Token $token) @@ -51,6 +54,35 @@ class PlaceholderTokenParser extends Twig_TokenParser return $token->test('endplaceholder'); } + protected function loadParams($stream) + { + $params = []; + + $end = false; + while (!$end) { + $current = $stream->next(); + + switch ($current->getType()) { + case Twig_Token::NAME_TYPE: + $paramName = $current->getValue(); + $stream->expect(Twig_Token::OPERATOR_TYPE, '='); + $current = $stream->next(); + $params[$paramName] = $current->getValue(); + break; + + case Twig_Token::BLOCK_END_TYPE: + $end = true; + break; + + default: + throw new Twig_Error_Syntax(sprintf('Invalid syntax in the placeholder tag. Line %s', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename()); + break; + } + } + + return $params; + } + /** * Gets the tag name associated with this token parser. *