/** * Build a widget for a given property. * * @param EnvironmentInterface $environment The environment. * * @param PropertyInterface $property The property. * * @param ModelInterface $model The current model. * * @return \Widget */ public function buildWidget(EnvironmentInterface $environment, PropertyInterface $property, ModelInterface $model) { $dispatcher = $environment->getEventDispatcher(); $propertyName = $property->getName(); $propExtra = $property->getExtra(); $defName = $environment->getDataDefinition()->getName(); $strClass = $this->getWidgetClass($property); $event = new DecodePropertyValueForWidgetEvent($environment, $model); $event->setProperty($propertyName)->setValue($model->getProperty($propertyName)); $dispatcher->dispatch($event::NAME, $event); $varValue = $event->getValue(); $propExtra['required'] = $varValue == '' && !empty($propExtra['mandatory']); $propExtra['tableless'] = true; $arrConfig = array('inputType' => $property->getWidgetType(), 'label' => array($property->getLabel(), $property->getDescription()), 'options' => $this->getOptionsForWidget($environment, $property, $model), 'eval' => $propExtra); if (isset($propExtra['reference'])) { $arrConfig['reference'] = $propExtra['reference']; } $event = new GetAttributesFromDcaEvent($arrConfig, $property->getName(), $varValue, $propertyName, $defName, new DcCompat($environment, $model, $propertyName)); $dispatcher->dispatch(ContaoEvents::WIDGET_GET_ATTRIBUTES_FROM_DCA, $event); $preparedConfig = $event->getResult(); $widget = new $strClass($preparedConfig, new DcCompat($environment, $model, $propertyName)); $widget->currentRecord = $model->getId(); $event = new ManipulateWidgetEvent($environment, $model, $property, $widget); $dispatcher->dispatch(ManipulateWidgetEvent::NAME, $event); return $widget; }
/** * Append wizard icons. * * @param PropertyInterface $propInfo The property for which the wizards shall be generated. * * @param EnvironmentInterface $environment The environment. * * @return string * * @SuppressWarnings(PHPMD.Superglobals) * @SuppressWarnings(PHPMD.CamelCaseVariableName) */ public static function getWizard($propInfo, EnvironmentInterface $environment) { $wizard = ''; $dispatcher = $environment->getEventDispatcher(); $translator = $environment->getTranslator(); $propExtra = $propInfo->getExtra(); $assetsPath = 'assets/mootools/colorpicker/' . $GLOBALS['TL_ASSETS']['COLORPICKER'] . '/images/'; if (array_key_exists('colorpicker', $propExtra) && $propExtra['colorpicker']) { $pickerText = $translator->translate('colorpicker', 'MSC'); $event = new GenerateHtmlEvent('pickcolor.gif', $pickerText, sprintf('style="%s" title="%s" id="moo_%s"', 'vertical-align:top;cursor:pointer', specialchars($pickerText), $propInfo->getName())); $dispatcher->dispatch(ContaoEvents::IMAGE_GET_HTML, $event); // Support single fields as well (see contao/core#5240) $strKey = $propExtra['multiple'] ? $propInfo->getName() . '_0' : $propInfo->getName(); $wizard .= sprintf(' %1$s <script>var cl;window.addEvent("domready", function() { new MooRainbow("moo_%2$s", {' . 'id: "ctrl_%3$s", startColor: ((cl = $("ctrl_%3$s").value.hexToRgb(true)) ? cl : [255, 0, 0]),' . 'imgPath: "%4$s", onComplete: function(color) {$("ctrl_%3$s").value = color.hex.replace("#", "");}});' . '});</script>', $event->getHtml(), $propInfo->getName(), $strKey, $assetsPath); } return $wizard; }
/** * Handle a property in a cloned model. * * @param ModelInterface $model The cloned model. * * @param PropertyInterface $property The property to handle. * * @param DataProviderInterface $dataProvider The data provider the model originates from. * * @return void */ private function handleClonedModelProperty(ModelInterface $model, PropertyInterface $property, DataProviderInterface $dataProvider) { $extra = $property->getExtra(); $propName = $property->getName(); // Check doNotCopy. if (isset($extra['doNotCopy']) && $extra['doNotCopy'] === true) { $model->setProperty($propName, null); return; } // Check uniqueness. if (isset($extra['unique']) && $extra['unique'] === true && !$dataProvider->isUniqueValue($propName, $model->getProperty($propName))) { // Implicit "do not copy" unique values, they cannot be unique anymore. $model->setProperty($propName, null); } }
/** * Build a widget for a given property. * * @param PropertyInterface $property The property. * * @param ModelInterface $model The current model. * * @return \Widget * * @throws DcGeneralRuntimeException When not running in TL_MODE BE. * * @SuppressWarnings(PHPMD.Superglobals) * @SuppressWarnings(PHPMD.CamelCaseVariableName) */ public function buildWidget(PropertyInterface $property, ModelInterface $model) { if (TL_MODE !== 'BE') { throw new DcGeneralRuntimeException(sprintf('WidgetBuilder only supports TL_MODE "BE". Running in TL_MODE "%s".', TL_MODE)); } $environment = $this->getEnvironment(); $dispatcher = $environment->getEventDispatcher(); $propertyName = $property->getName(); $propExtra = $property->getExtra(); $defName = $environment->getDataDefinition()->getName(); $strClass = $this->getWidgetClass($property); $event = new DecodePropertyValueForWidgetEvent($environment, $model); $event->setProperty($propertyName)->setValue($model->getProperty($propertyName)); $dispatcher->dispatch($event::NAME, $event); $varValue = $event->getValue(); if (isset($propExtra['rgxp']) && in_array($propExtra['rgxp'], array('date', 'time', 'datim')) && empty($propExtra['mandatory']) && is_numeric($varValue) && $varValue == 0) { $varValue = ''; } $propExtra['required'] = $varValue == '' && !empty($propExtra['mandatory']); $arrConfig = array('inputType' => $property->getWidgetType(), 'label' => array($property->getLabel(), $property->getDescription()), 'options' => $this->getOptionsForWidget($property, $model), 'eval' => $propExtra); if (isset($propExtra['reference'])) { $arrConfig['reference'] = $propExtra['reference']; } $event = new GetAttributesFromDcaEvent($arrConfig, $property->getName(), $varValue, $propertyName, $defName, new DcCompat($environment, $model, $propertyName)); $dispatcher->dispatch(ContaoEvents::WIDGET_GET_ATTRIBUTES_FROM_DCA, $event); $arrPrepared = $event->getResult(); if ($arrConfig['inputType'] == 'checkbox' && isset($GLOBALS['TL_DCA'][$defName]['subpalettes']) && is_array($GLOBALS['TL_DCA'][$defName]['subpalettes']) && in_array($propertyName, array_keys($GLOBALS['TL_DCA'][$defName]['subpalettes'])) && $arrConfig['eval']['submitOnChange']) { // We have to override the onclick, do not append to it as Contao adds it's own code here in // \Widget::getAttributesFromDca() which kills our sub palette handling! $arrPrepared['onclick'] = "Backend.autoSubmit('" . $defName . "');"; } $objWidget = new $strClass($arrPrepared, new DcCompat($environment, $model, $propertyName)); // OH: what is this? source: DataContainer 232. $objWidget->currentRecord = $model->getId(); $objWidget->xlabel .= $this->getXLabel($property); $event = new ManipulateWidgetEvent($environment, $model, $property, $objWidget); $dispatcher->dispatch(ManipulateWidgetEvent::NAME, $event); return $objWidget; }
/** * Get special labels. * * @param PropertyInterface $propInfo The property for which the X label shall be generated. * * @return string */ protected function getXLabel($propInfo) { $strXLabel = ''; $environment = $this->getEnvironment(); $defName = $environment->getDataDefinition()->getName(); $translator = $environment->getTranslator(); // Toggle line wrap (textarea). if ($propInfo->getWidgetType() === 'textarea' && !array_key_exists('rte', $propInfo->getExtra())) { $event = new GenerateHtmlEvent('wrap.gif', $translator->translate('wordWrap', 'MSC'), sprintf('title="%s" class="toggleWrap" onclick="Backend.toggleWrap(\'ctrl_%s\');"', specialchars($translator->translate('wordWrap', 'MSC')), $propInfo->getName())); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $event); $strXLabel .= ' ' . $event->getHtml(); } // Add the help wizard. if ($propInfo->getExtra() && array_key_exists('helpwizard', $propInfo->getExtra())) { $event = new GenerateHtmlEvent('about.gif', $translator->translate('helpWizard', 'MSC'), 'style="vertical-align:text-bottom;"'); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $event); $strXLabel .= sprintf(' <a href="contao/help.php?table=%s&field=%s" title="%s" onclick="Backend.openWindow(this, 600, 500); return false;">%s</a>', $defName, $propInfo->getName(), specialchars($translator->translate('helpWizard', 'MSC')), $event->getHtml()); } // Add the popup file manager. if ($propInfo->getWidgetType() === 'fileTree') { // In Contao 3 it is always a file picker - no need for the button. if (version_compare(VERSION, '3.0', '<')) { $event = new GenerateHtmlEvent('filemanager.gif', $translator->translate('fileManager', 'MSC'), 'style="vertical-align:text-bottom;"'); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $event); $strXLabel .= sprintf(' <a href="contao/files.php" title="%s" onclick="Backend.getScrollOffset(); Backend.openWindow(this, 750, 500); return false;">%s</a>', specialchars($translator->translate('fileManager', 'MSC')), $event->getHtml()); } } elseif ($propInfo->getWidgetType() === 'tableWizard') { $urlEvent = new AddToUrlEvent('key=table'); $importTableEvent = new GenerateHtmlEvent('tablewizard.gif', $translator->translate('importTable.0', $defName), 'style="vertical-align:text-bottom;"'); $shrinkEvent = new GenerateHtmlEvent('demagnify.gif', $translator->translate('shrink.0', $defName), sprintf('title="%s" style="vertical-align:text-bottom; cursor:pointer;" onclick="Backend.tableWizardResize(0.9);"', specialchars($translator->translate('shrink.1', $defName)))); $expandEvent = new GenerateHtmlEvent('magnify.gif', $translator->translate('expand.0', $defName), sprintf('title="%s" style="vertical-align:text-bottom; cursor:pointer;" onclick="Backend.tableWizardResize(1.1);"', specialchars($translator->translate('expand.1', $defName)))); $environment->getEventPropagator()->propagate(ContaoEvents::BACKEND_ADD_TO_URL, $urlEvent); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $importTableEvent); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $shrinkEvent); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $expandEvent); $strXLabel .= sprintf(' <a href="%s" title="%s" onclick="Backend.getScrollOffset();">%s</a> %s%s', ampersand($urlEvent->getUrl()), specialchars($translator->translate('importTable.1', $defName)), $importTableEvent->getHtml(), $shrinkEvent->getHtml(), $expandEvent->getHtml()); } elseif ($propInfo->getWidgetType() === 'listWizard') { $urlEvent = new AddToUrlEvent('key=list'); $importListEvent = new GenerateHtmlEvent('tablewizard.gif', $translator->translate('importList.0', $defName), 'style="vertical-align:text-bottom;"'); $environment->getEventPropagator()->propagate(ContaoEvents::BACKEND_ADD_TO_URL, $urlEvent); $environment->getEventPropagator()->propagate(ContaoEvents::IMAGE_GET_HTML, $importListEvent); $strXLabel .= sprintf(' <a href="%s" title="%s" onclick="Backend.getScrollOffset();">%s</a>', ampersand($urlEvent->getUrl()), specialchars($translator->translate('importList.1', $defName)), $importListEvent->getHtml()); } return $strXLabel; }
/** * Create a widget for naming contexts. Use the language and translation information from the MetaModel. * * @param EnvironmentInterface $environment The environment. * * @param PropertyInterface $property The property. * * @param IMetaModel $metaModel The MetaModel. * * @param string $languageLabel The label to use for the language indicator. * * @param string $valueLabel The label to use for the input field. * * @param bool $isTextArea If true, the widget will become a textarea, false otherwise. * * @param array $arrValues The values for the widget, needed to highlight the fallback language. * * @return void */ public static function prepareLanguageAwareWidget(EnvironmentInterface $environment, PropertyInterface $property, IMetaModel $metaModel, $languageLabel, $valueLabel, $isTextArea, $arrValues) { if (!$metaModel->isTranslated()) { $extra = $property->getExtra(); $extra['tl_class'] .= 'w50'; $property->setWidgetType('text')->setExtra($extra); return; } $fallback = $metaModel->getFallbackLanguage(); $languages = self::buildLanguageArray($metaModel, $environment->getTranslator()); $neededKeys = array_keys($languages); // Ensure we have values for all languages present. if (array_diff_key(array_keys($arrValues), $neededKeys)) { foreach ($neededKeys as $langCode) { $arrValues[$langCode] = ''; } } $rowClasses = array(); foreach (array_keys($arrValues) as $langCode) { $rowClasses[] = $langCode == $fallback ? 'fallback_language' : 'normal_language'; } $extra = $property->getExtra(); $extra['minCount'] = $extra['maxCount'] = count($languages); $extra['disableSorting'] = true; $extra['tl_class'] = 'clr'; $extra['columnFields'] = array('langcode' => array('label' => $languageLabel, 'exclude' => true, 'inputType' => 'justtextoption', 'options' => $languages, 'eval' => array('rowClasses' => $rowClasses, 'valign' => 'center', 'style' => 'min-width:75px;display:block;')), 'value' => array('label' => $valueLabel, 'exclude' => true, 'inputType' => $isTextArea ? 'textarea' : 'text', 'eval' => array('rowClasses' => $rowClasses, 'style' => 'width:400px;', 'rows' => 3))); $property->setWidgetType('multiColumnWizard')->setExtra($extra); }
/** * Build a widget for a given property. * * @param PropertyInterface $property The property. * * @param ModelInterface $model The current model. * * @return \Widget * * @throws DcGeneralRuntimeException When not running in TL_MODE BE. * * @SuppressWarnings(PHPMD.Superglobals) * @SuppressWarnings(PHPMD.CamelCaseVariableName) */ public function buildWidget(PropertyInterface $property, ModelInterface $model) { if (TL_MODE !== 'BE') { throw new DcGeneralRuntimeException(sprintf('WidgetBuilder only supports TL_MODE "BE". Running in TL_MODE "%s".', TL_MODE)); } $environment = $this->getEnvironment(); $dispatcher = $environment->getEventDispatcher(); $propertyName = $property->getName(); $propExtra = $property->getExtra(); $defName = $environment->getDataDefinition()->getName(); $strClass = $this->getWidgetClass($property); $event = new DecodePropertyValueForWidgetEvent($environment, $model); $event->setProperty($propertyName)->setValue($model->getProperty($propertyName)); $dispatcher->dispatch($event::NAME, $event); $varValue = $event->getValue(); if (isset($propExtra['rgxp']) && in_array($propExtra['rgxp'], array('date', 'time', 'datim')) && empty($propExtra['mandatory']) && is_numeric($varValue) && $varValue == 0) { /* FIXME TEMPORARY WORKAROUND! To be fixed in the core: @see \Widget::getAttributesFromDca() */ $varValue = ''; } // OH: why not $required = $mandatory always? source: DataContainer 226. // OH: the whole prepareForWidget(..) thing is an only mess // Widgets should parse the configuration by themselves, depending on what they need. $propExtra['required'] = $varValue == '' && !empty($propExtra['mandatory']); $arrConfig = array('inputType' => $property->getWidgetType(), 'label' => array($property->getLabel(), $property->getDescription()), 'options' => $this->getOptionsForWidget($property, $model), 'eval' => $propExtra); if (isset($propExtra['reference'])) { $arrConfig['reference'] = $propExtra['reference']; } $event = new GetAttributesFromDcaEvent($arrConfig, $property->getName(), $varValue, $propertyName, $defName, new DcCompat($environment, $model, $propertyName)); $dispatcher->dispatch(ContaoEvents::WIDGET_GET_ATTRIBUTES_FROM_DCA, $event); $arrPrepared = $event->getResult(); // Bugfix CS: ajax subpalettes are really broken. // Therefore we reset to the default checkbox behaviour here and submit the entire form. // This way, the javascript needed by the widget (wizards) will be correctly evaluated. if ($arrConfig['inputType'] == 'checkbox' && isset($GLOBALS['TL_DCA'][$defName]['subpalettes']) && is_array($GLOBALS['TL_DCA'][$defName]['subpalettes']) && in_array($propertyName, array_keys($GLOBALS['TL_DCA'][$defName]['subpalettes'])) && $arrConfig['eval']['submitOnChange']) { // We have to override the onclick, do not append to it as Contao adds it's own code here in // \Widget::getAttributesFromDca() which kills our sub palette handling! $arrPrepared['onclick'] = "Backend.autoSubmit('" . $defName . "');"; } $objWidget = new $strClass($arrPrepared, new DcCompat($environment, $model, $propertyName)); // OH: what is this? source: DataContainer 232. $objWidget->currentRecord = $model->getId(); $objWidget->xlabel .= $this->getXLabel($property); $event = new ManipulateWidgetEvent($environment, $model, $property, $objWidget); $dispatcher->dispatch(ManipulateWidgetEvent::NAME, $event); return $objWidget; }