diff --git a/src/system/modules/bootstrap/assets/css/backend.css b/src/system/modules/bootstrap/assets/css/backend.css index 440b83b..f19d066 100644 --- a/src/system/modules/bootstrap/assets/css/backend.css +++ b/src/system/modules/bootstrap/assets/css/backend.css @@ -47,4 +47,8 @@ input[readonly] { .bootstrapMultiColumnWizard.striped tr:nth-child(2n) td { background: #eee; +} + +.bootstrapMultiColumnWizard.striped .operations { + padding-right: 5px; } \ No newline at end of file diff --git a/src/system/modules/bootstrap/classes/DataContainer/Bootstrap.php b/src/system/modules/bootstrap/classes/DataContainer/Bootstrap.php new file mode 100644 index 0000000..5deaffa --- /dev/null +++ b/src/system/modules/bootstrap/classes/DataContainer/Bootstrap.php @@ -0,0 +1,178 @@ +table]['fields'][$dc->field]['eval']['columnFields']); + + $arrConfig = $dc->getDCA(); + $length = count($arrKeys); + + foreach((array)$values as $key => $value) + { + $arrRow = array + ( + $arrKeys[0] => $key, + ); + + if($arrConfig['fields'][$dc->field]['eval']['multiColumns']) + { + for($i=1; $i<$length; $i++) + { + $arrRow[$arrKeys[$i]] = isset($value[$arrKeys[$i]]) ? $value[$arrKeys[$i]] : null; + } + } + else + { + $arrRow[$arrKeys[1]] = $value; + } + + $arrNew[] = $arrRow; + } + + return $arrNew; + } + + + /** + * @param array $values + * @param DC_General $dc + * @return array + * @throws \RuntimeException + */ + public function saveAssociativeFromMcw($values, DC_General $dc) + { + $arrNew = array(); + $arrKeys = array_keys($GLOBALS['TL_DCA'][$dc->table]['fields'][$dc->field]['eval']['columnFields']); + + // support sub attributes of an array + if(strpos($dc->field, '.') !== false) + { + $parts = explode('.', $dc->field); + $target =& $GLOBALS[$dc->getDataProvider()->getRoot()][$dc->getId()]; + + $postKey = str_replace('.', '_', $dc->field) . '_' . $dc->getWidgetID(); + + // @todo do we have to take care of html attributes here? + $values = \Input::post($postKey); + + foreach((array) $values as $row ) + { + $arrNew[$row[$arrKeys[0]]] = $row[$arrKeys[1]]; + } + + foreach($parts as $part) + { + $new =& $target; + unset($target); + $target =& $new[$part]; + unset($new); + } + + $target = $arrNew; + + $dc->getEnvironment()->getCurrentModel()->setProperty($parts[0], $GLOBALS[$dc->getDataProvider()->getRoot()][$dc->getId()][$parts[0]]); + $dc->getEnvironment()->getCurrentModel()->setMeta(DCGE::MODEL_IS_CHANGED, true); + $dc->getEnvironment()->getCurrentModel()->setProperty($dc->field, null); + return; + } + + $arrConfig = $dc->getDCA(); + $length = count($arrKeys); + + foreach((array) $values as $value ) + { + $arrCombined = array(); + + if($arrConfig['fields'][$dc->field]['eval']['multiColumns']) + { + for($i=1; $i<$length; $i++) + { + if($arrConfig['fields'][$dc->field]['eval']['columnFields'][$arrKeys[$i]]['inputType'] == 'checkbox') + { + $arrCombined[$arrKeys[$i]] = (bool) $value[$arrKeys[$i]]; + } + + else { + $arrCombined[$arrKeys[$i]] = $value[$arrKeys[$i]]; + } + + } + + $arrNew[$value[$arrKeys[0]]] = $arrCombined; + } + else + { + $arrNew[$value[$arrKeys[0]]] = ($arrConfig['fields'][$dc->field]['inputType'] == 'checkbox' ? (bool) $value[$arrKeys[$i]] : $value[$arrKeys[$i]]); + } + } + + return $arrNew; + } + + public function loadSubPath($value, DC_General $dc) + { + $config = $dc->getFieldDefinition($dc->field); + + $root = $dc->getDataProvider()->getRoot(); + $value = $GLOBALS[$root][$dc->getId()]; + + foreach($config['subPath'] as $path) + { + $value = $value[$path]; + } + + return $value[$dc->field]; + } + + public function saveToSubSection($value, DC_General $dc) + { + $config = $dc->getFieldDefinition($dc->field); + + $root = $dc->getDataProvider()->getRoot(); + $point =& $GLOBALS[$root][$dc->getId()]; + + foreach($config['subPath'] as $path) + { + $target =& $point[$path]; + unset($point); + $point =& $target; + unset($target); + } + + $point[$dc->field] = $value; + + $dc->getEnvironment()->getCurrentModel()->setProperty($config['subPath'][0], $GLOBALS[$root][$dc->getId()][$config['subPath'][0]]); + $dc->getEnvironment()->getCurrentModel()->setMeta(DCGE::MODEL_IS_CHANGED, true); + $dc->getEnvironment()->getCurrentModel()->setProperty($dc->field, null); + + return; + } + +} \ No newline at end of file diff --git a/src/system/modules/bootstrap/classes/DcGeneral/Data/BootstrapConfigDriver.php b/src/system/modules/bootstrap/classes/DcGeneral/Data/BootstrapConfigDriver.php index 9872aec..b8d88b4 100644 --- a/src/system/modules/bootstrap/classes/DcGeneral/Data/BootstrapConfigDriver.php +++ b/src/system/modules/bootstrap/classes/DcGeneral/Data/BootstrapConfigDriver.php @@ -17,10 +17,14 @@ use DcGeneral\Data\DriverInterface; use DcGeneral\Data\ModelInterface; -class BootstrapDriver implements DriverInterface +class BootstrapConfigDriver implements DriverInterface { protected $strSource = null; + protected $strRoot = null; + + protected $arrIds = null; + /** * Set base config with source and other necessary parameter. @@ -33,6 +37,16 @@ class BootstrapDriver implements DriverInterface */ public function setBaseConfig(array $arrConfig) { + // check root + if(!isset($arrConfig['root'])) + { + throw new \RuntimeException('No root given'); + } + + $this->strRoot = $arrConfig['root']; + + + // set source if(!isset($arrConfig['source'])) { throw new \RuntimeException('Missing directory name'); @@ -48,6 +62,11 @@ public function setBaseConfig(array $arrConfig) $objFiles->mkdir($arrConfig['source']); } + if(isset($arrConfig['ids'])) + { + $this->arrIds = $arrConfig['ids']; + } + $this->strSource = $arrConfig['source']; } @@ -88,6 +107,17 @@ public function getEmptyCollection() } + /** + * get name of root + * + * @return string + */ + public function getRoot() + { + return $this->strRoot; + } + + /** * Fetch a single or first record by id or filter. * @@ -101,12 +131,12 @@ public function getEmptyCollection() */ public function fetch(ConfigInterface $objConfig) { - if($objConfig->getId() == null) + if($this->arrIds !== null && !in_array($objConfig->getId(), $this->arrIds)) { - $objConfig->setId('layout'); + throw new \RuntimeException(''); } - if(!isset($GLOBALS['BOOTSTRAP'][$objConfig->getId()])) + if(!isset($GLOBALS[$this->strRoot][$objConfig->getId()])) { return null; } @@ -119,7 +149,7 @@ public function fetch(ConfigInterface $objConfig) require_once $this->getFilePath($objConfig->getId()); } - foreach($GLOBALS['BOOTSTRAP'][$objConfig->getId()] as $key => $value) + foreach($GLOBALS[$this->strRoot][$objConfig->getId()] as $key => $value) { $objModel->setProperty($key, $value); } @@ -140,51 +170,31 @@ public function fetch(ConfigInterface $objConfig) */ public function fetchAll(ConfigInterface $objConfig) { - $objIterator = new \DirectoryIterator(TL_ROOT . '/' . $this->strSource); - if($objConfig->getIdOnly()) { - $arrIds = array(); - - foreach($objIterator as $file) - { - if($file->isFile()) - { - $arrIds[] = $file->getBasename(); - } - } - - return $arrIds; + return $this->arrIds !== null ? $this->arrIds : array_keys($GLOBALS[$this->strRoot]); } $objCollection = $this->getEmptyCollection(); - $arrIds = $objConfig->getIds(); + $arrIds = $this->arrIds !== null ? $this->arrIds : array_keys($GLOBALS[$this->strRoot]); - foreach($objIterator as $file) + foreach($arrIds as $id) { - $id = $file->getBasename('.php'); - - if(!empty($arrIds) && !in_array($id, $arrIds)) - { - continue; - } + $objModel = $this->getEmptyModel(); + $objModel->setID($id); - if(!file_exists($this->getFilePath($id))) + if(file_exists($this->getFilePath($id))) { - continue; + require_once $this->getFilePath($id); } - $objModel = $this->getEmptyModel(); - $objModel->setID($id); - - require_once $this->getFilePath($id); - if(!isset($GLOBALS['BOOTSTRAP'][$id])) + if(!isset($GLOBALS[$this->strRoot][$id])) { continue; } - foreach($GLOBALS['BOOTSTRAP'][$id] as $key => $value) + foreach($GLOBALS[$this->strRoot][$id] as $key => $value) { $objModel->setProperty($key, $value); } @@ -270,7 +280,6 @@ public function save(ModelInterface $objItem) $objFile = new \File($this->getFilePath($objItem->getId(), false)); - var_dump($data); $objFile->write($data); $objFile->close(); } @@ -281,28 +290,56 @@ public function save(ModelInterface $objItem) * @param array $arrTree * @return string */ - protected function prepareForSave($item, $arrTree = array('BOOTSTRAP')) + protected function prepareForSave($item, $arrTree = null) { + if($arrTree === null) + { + $arrTree = array($this->strRoot); + } + $buffer = ''; foreach($item as $key => $value) { - if($key == 'id' && count($arrTree) == 1) + if($value === null) { continue; } $arrNewTree = $arrTree; + + if($item instanceof ModelInterface) + { + $arrNewTree[] = $item->getProperty('id'); + } + $arrNewTree[] = $key; - if(is_array($value)) + if($key == 'id' && count($arrTree) == 1) { + continue; + } + if(is_array($value)) + { $buffer .= $this->prepareForSave($value, $arrNewTree); } else { - $buffer .= '$GLOBALS[\'' . implode('\'][\'', $arrNewTree) . '\'] '; + $buffer .= '$GLOBALS'; + + foreach($arrNewTree as $tree) + { + if(is_int($tree)) + { + $buffer .= '[' . $tree . ']'; + } + else + { + $buffer .= '[\'' . $tree . '\']'; + } + } + $buffer .= ' = ' . $this->prepareValueForSave($value) . ";\n"; } } @@ -331,6 +368,10 @@ protected function prepareValueForSave($value) return '\'' . addslashes($value) . '\''; } + elseif(is_null($value)) + { + return 'null'; + } else { throw new \RuntimeException('Invalid value given'); diff --git a/src/system/modules/bootstrap/config/autoload.php b/src/system/modules/bootstrap/config/autoload.php index ef7b661..db82737 100755 --- a/src/system/modules/bootstrap/config/autoload.php +++ b/src/system/modules/bootstrap/config/autoload.php @@ -49,6 +49,7 @@ 'Netzmacht\Bootstrap\Iterator\ArrayCallbackModify' => 'system/modules/bootstrap/classes/Iterator/ArrayCallbackModify.php', 'Netzmacht\Bootstrap\Iterator\ArrayOuter' => 'system/modules/bootstrap/classes/Iterator/ArrayOuter.php', 'Netzmacht\Bootstrap\Iterator\ArrayCallbackFilter' => 'system/modules/bootstrap/classes/Iterator/ArrayCallbackFilter.php', + 'Netzmacht\Bootstrap\DataContainer\Bootstrap' => 'system/modules/bootstrap/classes/DataContainer/Bootstrap.php', 'Netzmacht\Bootstrap\DataContainer\Content' => 'system/modules/bootstrap/classes/DataContainer/Content.php', 'Netzmacht\Bootstrap\DataContainer\Layout' => 'system/modules/bootstrap/classes/DataContainer/Layout.php', 'Netzmacht\Bootstrap\DataContainer\General' => 'system/modules/bootstrap/classes/DataContainer/General.php', diff --git a/src/system/modules/bootstrap/config/bootstrap/miscellaneous.php b/src/system/modules/bootstrap/config/bootstrap/miscellaneous.php index 8d0d96c..a9202de 100644 --- a/src/system/modules/bootstrap/config/bootstrap/miscellaneous.php +++ b/src/system/modules/bootstrap/config/bootstrap/miscellaneous.php @@ -26,10 +26,10 @@ ), // the array where all icons are defined - 'set' => array(), + 'set' => array(), // which tag shall be used for icons - 'template' => array(), + 'template' => array(), ); $GLOBALS['BOOTSTRAP']['dropdown'] = array @@ -50,6 +50,6 @@ 'adjustForm' => true, - 'remoteUrl' => 'SimpleAjax.php?page=%s&modal=%s', + 'remoteUrl' => 'SimpleAjax.php?page=%s&modal=%s', 'remoteDynamicUrl' => 'SimpleAjax.php?page=%s&modal=%s&dynamic=%s&id=%s', ); \ No newline at end of file diff --git a/src/system/modules/bootstrap/dca/tl_bootstrap.php b/src/system/modules/bootstrap/dca/tl_bootstrap.php index db878ac..29a2705 100644 --- a/src/system/modules/bootstrap/dca/tl_bootstrap.php +++ b/src/system/modules/bootstrap/dca/tl_bootstrap.php @@ -1,5 +1,7 @@ loadLanguageFile('tl_form_field'); + $GLOBALS['TL_DCA']['tl_bootstrap'] = array ( 'config' => array @@ -15,12 +17,12 @@ ( 'default' => array ( - 'class' => 'Netzmacht\Bootstrap\DcGeneral\Data\BootstrapConfigDriver', + 'class' => 'Netzmacht\Bootstrap\DcGeneral\Data\BootstrapConfigDriver', 'source' => 'system/config/bootstrap', - 'createSource' => true, + 'root' => 'BOOTSTRAP', + 'ids' => array('form', 'layout', 'templates'), + 'createDirectory' => true, ), - 'folder' => 'system/modules/bootstrap/config/bootstrap', - ), ), @@ -62,7 +64,22 @@ 'layout' => array ( - 'test' => array('viewport'), + 'viewport' => array('viewport'), + 'palettes' => array(':hide', 'metapalette', 'metasubselectpalettes.rows', 'metasubselectpalettes.cols'), + ), + + 'templates' => array + ( + 'templates' => array('dynamicLoad'), + 'modifiers' => array('bar'), + ), + + 'form' => array + ( + 'table' => array('tableFormat', 'defaultTableless'), + 'widgets' => array(':hide', 'widgets'), + 'styleSelect' => array(':hide', 'enabled', 'class', 'defaultStyle'), + 'dataAttributes' => array('dataAttributes'), ), ), @@ -72,6 +89,328 @@ 'viewport' => array ( 'inputType' => 'text', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['viewport'], + 'eval' => array + ( + 'decodeEntities' => true, + 'tl_class' => 'long' + ), + ), + + 'metapalette' => array + ( + 'inputType' => 'multiColumnWizard', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['metapalette'], + 'save_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'saveAssociativeFromMcw'), + ), + + 'load_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'loadAssociativeForMcw'), + ), + + 'eval' => array + ( + 'tl_class' => 'bootstrapMultiColumnWizard hideSubLabels', + 'columnFields' => array + ( + 'legend' => array + ( + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['legend'], + 'inputType' => 'text', + 'eval' => array + ( + 'valign' => 'top', + + 'style' => 'width: 120px; margin-top: 7px; vertical-align: top', + ) + ), + + 'fields' => array + ( + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['fields'], + 'inputType' => 'multiColumnWizard', + 'eval' => array + ( + 'flatArray' => true, + 'columnFields' => array + ( + 'fields' => array + ( + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['fields'], + 'inputType' => 'text', + 'eval' => array('style' => 'width: 400px',), + ), + + + ), + ), + ), + ), + + ), + ), + + + 'dynamicLoad' => array + ( + 'inputType' => 'multiColumnWizard', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['dynamicLoad'], + 'save_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'saveAssociativeFromMcw'), + ), + + 'load_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'loadAssociativeForMcw'), + ), + + 'eval' => array + ( + 'tl_class' => 'bootstrapMultiColumnWizard hideSubLabels alignOperations', + 'explanation' => true, + + + 'columnFields' => array + ( + 'path' => array + ( + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['path'], + 'inputType' => 'text', + 'explanation' => true, + 'eval' => array + ( + 'valign' => 'top', + 'columnPos' => '1', + 'style' => 'width: 600px; margin-top: 7px; margin-bottom: 7px; vertical-align: top', + ) + ), + + 'templates' => array + ( + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['templates'], + 'inputType' => 'multiColumnWizard', + 'eval' => array + ( + 'columnPos' => '1', + 'flatArray' => true, + 'columnFields' => array + ( + 'fields' => array + ( + 'label' => 'test', + 'inputType' => 'text', + 'eval' => array('style' => 'width: 200px',), + ), + + + ), + ), + ), + ), + + ), + ), + + 'widgets' => array + ( + 'inputType' => 'multiColumnWizard', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['widgets'], + 'save_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'saveAssociativeFromMcw'), + ), + + 'load_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'loadAssociativeForMcw'), + ), + 'eval' => array + ( + 'tl_class' => 'bootstrapMultiColumnWizard striped', + 'templatePrefix' => 'form_', + 'buttons' => array('up' => false, 'down' => false), + 'multiColumns' => true, + + 'columnFields' => array + ( + 'name' => array + ( + 'inputType' => 'select', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['widget'], + 'options' => array_keys($GLOBALS['TL_FFL']), + 'reference' => &$GLOBALS['TL_LANG']['FFL'], + 'eval' => array('style' => 'width: 180px', 'columnPos' => '1'), + ), + + 'noFormControl' => array + ( + 'inputType' => 'checkbox', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['noFormControl'], + 'eval' => array('style' => 'width: 80px; margin-top: 20px;', 'valign' => 'top'), + ), + + 'noLabel' => array + ( + 'inputType' => 'checkbox', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['noLabel'], + 'eval' => array('style' => 'width: 80px; margin-top: 20px;', 'valign' => 'top'), + ), + + 'allowInputGroup' => array + ( + 'inputType' => 'checkbox', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['allowInputGroup'], + 'eval' => array('style' => 'width: 80px; margin-top: 20px;', 'valign' => 'top'), + ), + + + 'modalFooter' => array + ( + 'inputType' => 'checkbox', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['modalFooter'], + 'eval' => array('style' => 'width: 80px; margin-top: 20px;', 'valign' => 'top'), + ), + + 'styleSelect' => array + ( + 'inputType' => 'checkbox', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['styleSelect'], + 'eval' => array('style' => 'width: 80px; margin-top: 20px;', 'valign' => 'top'), + ), + + 'generateTemplate' => array + ( + 'inputType' => 'select', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['generateTemplate'], + 'options_callback' => array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'getTemplates'), + 'eval' => array('style' => 'width: 180px', 'columnPos' => '1', 'includeBlankOption' => true), + ), + ), + ), + ), + + 'defaultTableless' => array + ( + 'inputType' => 'checkbox', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['defaultTableless'], + 'eval' => array + ( + 'tl_class' => 'w50' + ), + ), + + 'tableFormat' => array + ( + 'inputType' => 'multiColumnWizard', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['tableFormat'], + 'save_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'saveAssociativeFromMcw'), + ), + + 'load_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'loadAssociativeForMcw'), + ), + 'eval' => array + ( + 'tl_class' => 'bootstrapMultiColumnWizard', + + 'columnFields' => array + ( + 'type' => array + ( + 'inputType' => 'text', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['tableFormat_type'], + 'eval' => array('style' => 'width: 150px', 'readonly' => true), + ), + + 'value' => array + ( + 'inputType' => 'text', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['tableFormat_class'], + 'eval' => array('style' => 'width: 350px'), + ), + ), + + 'buttons' => array('up' => false, 'copy' => 'false', 'down' => false, 'delete' => false), + ), + ), + + 'enabled' => array + ( + 'inputType' => 'checkbox', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['styleSelect_enabled'], + 'subPath' => array('styleSelect'), + 'load_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'loadSubPath'), + ), + 'save_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'saveToSubSection'), + ), + 'eval' => array + ( + + 'tl_class' => '' + ), + ), + + 'class' => array + ( + 'inputType' => 'text', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['styleSelect_enabled'], + 'subPath' => array('styleSelect'), + 'load_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'loadSubPath'), + ), + 'save_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'saveToSubSection'), + ), + 'eval' => array + ( + + 'tl_class' => 'w50' + ), + ), + + 'defaultStyle' => array + ( + 'inputType' => 'text', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['styleSelect_enabled'], + 'subPath' => array('styleSelect'), + 'load_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'loadSubPath'), + ), + 'save_callback' => array + ( + array('Netzmacht\Bootstrap\DataContainer\Bootstrap', 'saveToSubSection'), + ), + 'eval' => array + ( + + 'tl_class' => 'w50' + ), + ), + + + 'dataAttributes' => array + ( + 'inputType' => 'listWizard', + 'label' => &$GLOBALS['TL_LANG']['tl_bootstrap']['dataAttributes'], + 'eval' => array + ( + 'multiple' => true, + 'size' => 1, + ), ), ), diff --git a/src/system/modules/bootstrap/languages/de/tl_bootstrap.php b/src/system/modules/bootstrap/languages/de/tl_bootstrap.php new file mode 100644 index 0000000..af015cb --- /dev/null +++ b/src/system/modules/bootstrap/languages/de/tl_bootstrap.php @@ -0,0 +1,79 @@ +