diff --git a/CHANGELOG.md b/CHANGELOG.md index 21160df1f..ae04f1d2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +* **Build 89** (2014-05-22) + - Components have a new override method `onRender()` called before a component is rendered. + - The `{% component %} tag now supports passing parameters that override the component properties when they are rendered. + - Calling `addJs()` and `addCss()` in components without a starting slash (/) will now reference the component directory, instead of the theme. + * **Build 87** (2014-05-21) - Plugins can now be disabled manually by config (see config cms.disablePlugins). - Plugins with missing dependancies are disabled by the system. diff --git a/modules/backend/widgets/ReportContainer.php b/modules/backend/widgets/ReportContainer.php index 1e1febf55..0254b1fdb 100644 --- a/modules/backend/widgets/ReportContainer.php +++ b/modules/backend/widgets/ReportContainer.php @@ -87,9 +87,9 @@ class ReportContainer extends WidgetBase $this->addJs('js/reportcontainer.js'); } - /* - * Event handelrs - */ + // + // Event handlers + // public function onUpdateWidget() { @@ -97,8 +97,8 @@ class ReportContainer extends WidgetBase $widget = $this->findWidgetByAlias($alias); $this->saveWidgetProperties($alias, $widget->setProperties( - json_decode(Request::input('fields'), true) - )); + json_decode(Request::input('fields'), true) + )); return [ '#'.$alias => $widget->render() @@ -204,9 +204,9 @@ class ReportContainer extends WidgetBase $this->setWidgetsToUserPreferences($widgets); } - /* - * Methods for the internal use - */ + // + // Methods for the internal use + // protected function loadWidgets() { @@ -286,16 +286,17 @@ class ReportContainer extends WidgetBase 'validationPattern' => '^[0-9]+$', 'validationMessage' => 'Please enter the widget width as a number between 1 and 10.', 'options' => [ - 1=>'1 column', - 2=>'2 columns', - 3=>'3 columns', - 4=>'4 columns', - 5=>'5 columns', - 6=>'6 columns', - 7=>'7 columns', - 8=>'8 columns', - 9=>'9 columns', - 10=>'10 columns'] + 1 => '1 column', + 2 => '2 columns', + 3 => '3 columns', + 4 => '4 columns', + 5 => '5 columns', + 6 => '6 columns', + 7 => '7 columns', + 8 => '8 columns', + 9 => '9 columns', + 10 => '10 columns' + ] ]; $result[] = $property; diff --git a/modules/cms/classes/ComponentBase.php b/modules/cms/classes/ComponentBase.php index b8bbe556f..7d92e0723 100644 --- a/modules/cms/classes/ComponentBase.php +++ b/modules/cms/classes/ComponentBase.php @@ -5,7 +5,6 @@ use Lang; use Config; use Cms\Classes\CodeBase; use Cms\Classes\CmsException; -use System\Traits\PropertyContainer; use October\Rain\Extension\Extendable; /** @@ -16,7 +15,8 @@ use October\Rain\Extension\Extendable; */ abstract class ComponentBase extends Extendable { - use PropertyContainer; + use \System\Traits\AssetMaker; + use \System\Traits\PropertyContainer; /** * @var string A unique identifier for this component. @@ -69,6 +69,7 @@ abstract class ComponentBase extends Extendable $className = Str::normalizeClassName(get_called_class()); $this->dirName = strtolower(str_replace('\\', '/', $className)); + $this->assetPath = Config::get('cms.pluginsDir') . dirname(dirname($this->dirName)); parent::__construct(); } @@ -83,7 +84,7 @@ abstract class ComponentBase extends Extendable */ public function getPath() { - return base_path() . Config::get('cms.pluginsDir') . '/' . $this->dirName; + return base_path() . Config::get('cms.pluginsDir') . $this->dirName; } /** @@ -91,6 +92,11 @@ abstract class ComponentBase extends Extendable */ public function onRun() {} + /** + * Executed when this component is rendered on a page or layout. + */ + public function onRender() {} + /** * Dynamically handle calls into the controller instance. * @param string $method diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index c68aabb8c..d41951833 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -536,8 +536,14 @@ class Controller extends BaseController * Renders a component's default content. * @return string Returns the component default contents. */ - public function renderComponent($name) + public function renderComponent($name, $parameters = []) { + if ($componentObj = $this->findComponentByName($name)) { + $componentObj->setProperties(array_merge($componentObj->getProperties(), $parameters)); + if ($result = $componentObj->onRender()) + return $result; + } + return $this->renderPartial($name.'::default'); } diff --git a/modules/cms/twig/ComponentNode.php b/modules/cms/twig/ComponentNode.php index 5b8e80e04..ce18c2c39 100644 --- a/modules/cms/twig/ComponentNode.php +++ b/modules/cms/twig/ComponentNode.php @@ -1,8 +1,8 @@ $name], [], $lineno, $tag); + parent::__construct(['nodes' => $nodes], ['names' => $paramNames], $lineno, $tag); } /** @@ -24,11 +24,23 @@ class ComponentNode extends Twig_Node */ public function compile(Twig_Compiler $compiler) { + $compiler->addDebugInfo($this); + + $compiler->write("\$context['__cms_component_params'] = [];\n"); + + for ($i = 1; $i < count($this->getNode('nodes')); $i++) { + $compiler->write("\$context['__cms_component_params']['".$this->getAttribute('names')[$i-1]."'] = "); + $compiler->subcompile($this->getNode('nodes')->getNode($i)); + $compiler->write(";\n"); + } + $compiler - ->addDebugInfo($this) ->write("echo \$this->env->getExtension('CMS')->componentFunction(") - ->subcompile($this->getNode('name')) + ->subcompile($this->getNode('nodes')->getNode(0)) + ->write(", \$context['__cms_component_params']") ->write(");\n") ; + + $compiler->write("unset(\$context['__cms_component_params']);\n"); } } \ No newline at end of file diff --git a/modules/cms/twig/ComponentTokenParser.php b/modules/cms/twig/ComponentTokenParser.php index 28f5721bc..f090b1516 100644 --- a/modules/cms/twig/ComponentTokenParser.php +++ b/modules/cms/twig/ComponentTokenParser.php @@ -1,7 +1,9 @@ getLine(); $stream = $this->parser->getStream(); + $name = $this->parser->getExpressionParser()->parseExpression(); - $stream->expect(Twig_Token::BLOCK_END_TYPE); - return new ComponentNode($name, $token->getLine(), $this->getTag()); + $paramNames = []; + $nodes = [$name]; + + $end = false; + while (!$end) { + $current = $stream->next(); + + switch ($current->getType()) { + case Twig_Token::NAME_TYPE: + $paramNames[] = $current->getValue(); + $stream->expect(Twig_Token::OPERATOR_TYPE, '='); + $nodes[] = $this->parser->getExpressionParser()->parseExpression(); + break; + + case Twig_Token::BLOCK_END_TYPE: + $end = true; + break; + + default: + throw new Twig_Error_Syntax(sprintf('Invalid syntax in the partial tag. Line %s', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename()); + break; + } + } + + return new ComponentNode(new Twig_Node($nodes), $paramNames, $token->getLine(), $this->getTag()); } /** diff --git a/modules/cms/twig/Extension.php b/modules/cms/twig/Extension.php index bfd142415..4003b50f5 100644 --- a/modules/cms/twig/Extension.php +++ b/modules/cms/twig/Extension.php @@ -167,11 +167,13 @@ class Extension extends Twig_Extension /** * Renders a component's default content. + * @param string $name Specifies the component name. + * @param array $parameters A optional list of parameters to pass to the component. * @return string Returns the component default contents. */ - public function componentFunction($name) + public function componentFunction($name, $parameters = []) { - return $this->controller->renderComponent($name); + return $this->controller->renderComponent($name, $parameters); } /** diff --git a/modules/cms/twig/PartialTokenParser.php b/modules/cms/twig/PartialTokenParser.php index d431adb8a..5c7d7e0fc 100644 --- a/modules/cms/twig/PartialTokenParser.php +++ b/modules/cms/twig/PartialTokenParser.php @@ -1,8 +1,8 @@ getCurrent()->getLine(), $stream->getFilename()); - break; } } diff --git a/modules/system/traits/PropertyContainer.php b/modules/system/traits/PropertyContainer.php index 893348d8f..fdc92fd8b 100644 --- a/modules/system/traits/PropertyContainer.php +++ b/modules/system/traits/PropertyContainer.php @@ -42,7 +42,7 @@ trait PropertyContainer } /** - * Defines the properties used by this class. + * Defines the properties used by this class. * This method should be used as an override in the extended class. */ public function defineProperties()