Example #1
0
 /**
  * Converts an array of Metadata trees to actual content that can be rendered.
  *
  * @param self[]    $metadata The metadata to be converted.
  * @param Component $parent   The content will be assigned to this component and will inherit its context.
  * @param bool      $prepend  When true, children are prepended to the existing content, or the the beginning of a
  *                            collection property.
  */
 public static function compile(array $metadata, Component $parent, $prepend = false)
 {
     foreach ($metadata as $item) {
         if (!$item instanceof self) {
             $parent->addChild($item->cloneWithContext($parent->context), $prepend);
             continue;
         }
         $tag = $item->getTagName();
         $propName = lcfirst($tag);
         // Insert metadata
         if ($parent->props && !$parent instanceof self && $parent->props->defines($propName)) {
             if ($parent->props->getTypeOf($propName) == type::collection) {
                 $comp = new self($parent->context, $tag, $parent->props->getRelatedTypeOf($propName), $item->props->getAll(), $item->bindings);
                 if ($prepend) {
                     array_unshift($parent->props->{$propName}, $comp);
                 } else {
                     array_push($parent->props->{$propName}, $comp);
                 }
             } else {
                 $comp = new self($parent->context, $tag, $parent->props->getTypeOf($propName), $item->props->getAll(), $item->bindings);
                 $parent->props->set($propName, $comp);
             }
         } else {
             $comp = $tag === 'Text' ? Text::from($parent->context, $item->value) : $parent->context->createComponentFromTag($tag, $parent, $item->props->getAll(), $item->bindings);
             $parent->addChild($comp, $prepend);
         }
         // Now, compile the children.
         self::compile($item->getChildren(), $comp);
     }
 }
 /**
  * Returns the value converted to a the data type required by the specified property.
  *
  * @param string $name
  * @param mixed  $v
  * @return bool|float|int|null|string|\Traversable
  * @throws ComponentException
  */
 function typecastPropertyValue($name, $v)
 {
     if ($this->isScalar($name) && $this->isEnum($name)) {
         $this->validateEnum($name, $v);
     }
     $type = $this->getTypeOf($name);
     if ($type && !type::validate($type, $v)) {
         throw new ComponentException($this->component, sprintf("%s is not a valid value for the <kbd>{$name}</kbd> property, which is of type <kbd>%s</kbd>", is_scalar($v) ? sprintf("The %s<kbd>%s</kbd>", typeOf($v), var_export($v, true)) : sprintf("A value of PHP type <kbd>%s</kbd>", typeOf($v)), type::getNameOf($type)));
     }
     // A special case for content type properties:
     // Convert a content property specified as attribute=string to a format equivalent to the one generated by
     // <subtag>string</subtag>
     if ($type == type::content && is_string($v)) {
         $content = new Metadata($this->component->context, $name, type::metadata);
         $content->setChildren([Text::from($this->component->context, $v)]);
         return $content;
     }
     return type::typecast($type, $v);
 }
 function getDefaultValue($name)
 {
     if (!$this->macroInstance) {
         $this->noMacro();
     }
     $param = $this->macroInstance->getParameter($name, $found);
     if (!$found) {
         throw new ComponentException($this->component, "Undefined macro parameter <kbd>{$name}</kbd>.\n<p>Available parameters: <b>" . implode(', ', $this->component->props->getPropertyNames()) . '</b>');
     }
     $v = $param->getComputedPropValue('default');
     if (isset($v) && $v !== '' && $param->props->type == 'content') {
         $meta = new Metadata($this->macroInstance->context, ucfirst($name), type::content);
         $meta->attachTo($this->component);
         $meta->addChild(Text::from($this->macroInstance->context, $v));
         return $meta;
     }
     return $v;
 }
Example #4
0
 private function text_addComponent($content, $trim = self::NO_TRIM)
 {
     $context = $this->current->context;
     if ($context->condenseLiterals) {
         switch ($trim) {
             case self::TRIM_LEFT:
                 $content = preg_replace(self::TRIM_LEFT_CONTENT, '', $content);
                 break;
             case self::TRIM_RIGHT:
                 $content = preg_replace(self::TRIM_RIGHT_CONTENT, '', $content);
                 break;
             case self::TRIM:
                 $content = preg_replace(self::TRIM_LITERAL_CONTENT, '', $content);
                 break;
         }
     }
     if ($content != '') {
         if (isset($this->currentScalarProperty)) {
             $this->currentScalarValue .= $content;
             //Note: data binding will be taken care of later.
         } else {
             if ($content[0] == '{') {
                 $lit = Text::from($context);
                 $lit->setBindings(['value' => new Expression($content)]);
             } else {
                 $lit = Text::from($context, $content);
             }
             $this->current->addChild($lit);
         }
     }
 }
 protected function render()
 {
     $prop = $this->props;
     $inputFlds = $this->getClonedChildren();
     if (empty($inputFlds)) {
         throw new ComponentException($this, "<b>field</b> parameter must define <b>one or more</b> component instances.", true);
     }
     // Treat the first child component specially
     /** @var Component $input */
     $input = $inputFlds[0];
     $append = $this->getChildren('append');
     $prepend = $this->getChildren('prepend');
     $fldId = $input->props->get('id', $prop->name);
     if ($fldId) {
         foreach ($inputFlds as $counter => $c) {
             if ($c->isPropertySet('hidden') && !$c->getComputedPropValue('hidden')) {
                 break;
             }
         }
         // Special case for the HtmlEditor component.
         if ($input->className == 'HtmlEditor') {
             $forId = $fldId . "-{$counter}_field";
             $click = "\$('#{$fldId}-{$counter} .redactor_editor').focus()";
         } else {
             $forId = $fldId . "-{$counter}";
             $click = $prop->multilang ? "focusMultiInput(this)" : null;
         }
     } else {
         $forId = $click = null;
     }
     if ($input->className == 'Input') {
         if ($prop->type && !$input->props->type) {
             $input->props->type = $prop->type;
         }
         switch ($input->props->type) {
             case 'date':
             case 'time':
             case 'datetime':
                 $btn = Button::create($this, ['class' => 'btn btn-default', 'icon' => 'glyphicon glyphicon-calendar', 'script' => "\$('#{$input->props->id}-0').data('DateTimePicker').show()", 'tabIndex' => -1]);
                 $append = [$btn];
         }
     }
     if (exists($prop->icon)) {
         $append = [Text::from($this->context, "<i class=\"{$prop->icon}\"></i>")];
     }
     $this->beginContent();
     // Output a LABEL
     $label = $prop->label;
     if (!empty($label)) {
         $this->tag('label', ['class' => enum(' ', $prop->labelClass, $prop->required ? 'required' : ''), 'for' => $forId, 'onclick' => $click], $label);
     }
     // Output child components
     $hasGroup = $append || $prepend || $prop->groupClass || $prop->multilang;
     if ($hasGroup) {
         $this->begin('div', ['id' => "{$forId}-group", 'class' => enum(' ', when($append || $prepend || $prop->multilang, 'input-group'), $prop->groupClass)]);
     }
     $this->beginContent();
     if ($prepend) {
         $this->renderAddOns($prepend);
     }
     if ($prop->multilang) {
         foreach ($inputFlds as $i => $input) {
             foreach ($prop->languages as $lang) {
                 $this->outputField($input, $i, $fldId, $prop->name, $lang);
             }
         }
     } else {
         foreach ($inputFlds as $i => $input) {
             $this->outputField($input, $i, $fldId, $prop->name);
         }
     }
     if ($append) {
         $this->renderAddOns($append);
     }
     $shortLang = substr($prop->lang, -2);
     if ($prop->multilang) {
         echo html([h('span.input-group-btn', [h('button.btn btn-default dropdown-toggle', ["id" => "langMenuBtn_{$forId}", 'type' => "button", 'data-toggle' => "dropdown", 'aria-haspopup' => "true", 'aria-expanded' => "false"], [h('i.fa fa-flag'), h('span.lang', $shortLang), h('span.caret')]), h("ul.dropdown-menu dropdown-menu-right", ['id' => "langMenu_{$forId}", "aria-labelledby" => "langMenuBtn_{$forId}"], map($prop->languages, function ($l) use($forId) {
             return h('li', [h('a', ['tabindex' => "1", 'href' => "javascript:selenia.setLang('{$l['name']}','#{$forId}-group')"], $l['label'])]);
         }))])]);
     }
     if ($hasGroup) {
         $this->end();
     }
 }