├── pages ├── categories.php ├── index.php ├── settings.php ├── info.php └── content.metainfo.php ├── uninstall.php ├── .github └── workflows │ └── publish-to-redaxo.yml ├── package.yml ├── install.php ├── update.php ├── LICENSE.md ├── lib ├── base.php ├── category_splitter.php ├── hide_startarticle.php ├── pages │ ├── page_settings.php │ └── page_categories.php ├── hide_category_functions.php ├── hide_categories.php ├── move_metainfo_to_tab.php └── move_metainfo.php ├── boot.php ├── lang ├── pt_br.lang ├── en_gb.lang ├── sv_se.lang ├── de_de.lang └── es_es.lang ├── README.md └── assets ├── style.css └── script.js /pages/categories.php: -------------------------------------------------------------------------------- 1 | i18n($this->getName())); 7 | 8 | rex_be_controller::includeCurrentPageSubPath(); 9 | -------------------------------------------------------------------------------- /uninstall.php: -------------------------------------------------------------------------------- 1 | setQuery('DROP TABLE IF EXISTS `'.rex::getTable('structure_tweaks').'`;'); 8 | -------------------------------------------------------------------------------- /pages/settings.php: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 |
10 | 11 |
12 | -------------------------------------------------------------------------------- /pages/info.php: -------------------------------------------------------------------------------- 1 | getPath('README.md')); 7 | 8 | $parsedown = new Parsedown(); 9 | $content = $parsedown->text($file); 10 | 11 | $fragment = new rex_fragment(); 12 | $fragment->setVar('title', $this->i18n('page_info')); 13 | $fragment->setVar('body', $content, false); 14 | 15 | echo $fragment->parse('core/page/section.php'); 16 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-redaxo.yml: -------------------------------------------------------------------------------- 1 | name: Publish release 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | 8 | jobs: 9 | redaxo_publish: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: FriendsOfREDAXO/installer-action@v1 14 | with: 15 | myredaxo-username: ${{ secrets.MYREDAXO_USERNAME }} 16 | myredaxo-api-key: ${{ secrets.MYREDAXO_API_KEY }} 17 | description: ${{ github.event.release.body }} 18 | 19 | -------------------------------------------------------------------------------- /package.yml: -------------------------------------------------------------------------------- 1 | package: structure_tweaks 2 | version: '1.4.1' 3 | author: Friends Of REDAXO 4 | supportpage: https://github.com/FriendsOfREDAXO/structure_tweaks 5 | 6 | requires: 7 | php: '>=7.3' 8 | redaxo: '^5.2.0' 9 | packages: 10 | structure: '^2.2.0' 11 | 12 | page: 13 | title: translate:structure_tweaks 14 | perm: admin 15 | subpages: 16 | categories: { title: translate:page_categories } 17 | info: 18 | title: translate:page_info 19 | itemclass: pull-right 20 | 21 | 22 | -------------------------------------------------------------------------------- /install.php: -------------------------------------------------------------------------------- 1 | ensurePrimaryIdColumn() 9 | ->ensureColumn(new rex_sql_column('article_id', 'int(11)', false), 'id') 10 | ->ensureColumn(new rex_sql_column('type', 'varchar(100)', false), 'article_id') 11 | ->ensureColumn(new rex_sql_column('label', 'varchar(100)', false), 'type') 12 | ->ensure(); 13 | ; 14 | 15 | // Ensure that all updates are also executed on re-install 16 | include ('update.php'); 17 | -------------------------------------------------------------------------------- /update.php: -------------------------------------------------------------------------------- 1 | ensureColumn(new rex_sql_column('label', 'varchar(100)', false)) 12 | ->alter(); 13 | 14 | // New column-length in version 1.1 15 | rex_sql_table::get(rex::getTable('structure_tweaks')) 16 | ->ensureColumn(new rex_sql_column('type', 'varchar(100)', false)) 17 | ->alter(); 18 | 19 | // Update engine and character set 20 | rex_sql::factory() 21 | ->setQuery('ALTER TABLE `'.rex::getTable('structure_tweaks').'` ENGINE = InnoDB;') 22 | ->setQuery('ALTER TABLE `'.rex::getTable('structure_tweaks').'` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'); 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Friends Of REDAXO 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/base.php: -------------------------------------------------------------------------------- 1 | getName(); 14 | } 15 | 16 | /** 17 | * @return rex_addon 18 | */ 19 | protected static function addon() 20 | { 21 | return rex_addon::get('structure_tweaks'); 22 | } 23 | 24 | /** 25 | * @param $string 26 | * @return string 27 | */ 28 | protected static function msg($string) 29 | { 30 | return \rex_i18n::msg(self::name().'_'.$string); 31 | } 32 | 33 | /** 34 | * @param string $type 35 | * @return array 36 | */ 37 | protected static function getArticles($type) 38 | { 39 | $sql = rex_sql::factory(); 40 | $articles = $sql->getArray('SELECT * FROM '.rex::getTable(self::name()).' WHERE `type` = ?', [ $type ]); 41 | 42 | $return = []; 43 | foreach ($articles as $article) { 44 | $return[] = $article['article_id']; 45 | } 46 | 47 | return $return; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /boot.php: -------------------------------------------------------------------------------- 1 | isAvailable() || rex_addon::get('structure')->isAvailable()) { 8 | rex_view::addCssFile($this->getAssetsUrl('style.css')); 9 | rex_view::addJsFile($this->getAssetsUrl('script.js')); 10 | } 11 | 12 | // Hide startarticles 13 | structure_tweaks_hide_startarticle::init(); 14 | 15 | // Hide category functions 16 | structure_tweaks_hide_category_functions::init(); 17 | 18 | // Hide categories 19 | structure_tweaks_hide_categories::init(); 20 | 21 | // Split categories 22 | structure_tweaks_category_splitter::init(); 23 | 24 | // load settings page 25 | $page = $this->getProperty('page'); 26 | $page['subpages']['settings'] = ['title' => $this->i18n('structure_tweaks_page_settings')]; 27 | $this->setProperty('page', $page); 28 | 29 | // Move meta infos 30 | if (rex_string::versionCompare(rex::getVersion(), '5.10.0-dev', '<')) { 31 | if ($this->getConfig('move_meta_info_page')) { 32 | structure_tweaks_move_metainfo::init(); 33 | } 34 | } else { 35 | if ($this->getConfig('move_meta_info_to_tab')) { 36 | structure_tweaks_move_metainfo_to_tab::init(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lang/pt_br.lang: -------------------------------------------------------------------------------- 1 | structure_tweaks = Structure Tweaks 2 | 3 | structure_tweaks_page_settings = Configurações 4 | structure_tweaks_page_categories = Categorias 5 | structure_tweaks_page_info = Info 6 | structure_tweaks_description = Permite a manipulação da estrutura do output 7 | structure_tweaks_deleted = Referência foi deletada. 8 | structure_tweaks_list_rowmsg = Nenhuma referência encontrada. 9 | structure_tweaks_list_table_attr = Lista de todas as referências 10 | structure_tweaks_article_id = ID do artigo 11 | structure_tweaks_article_name = Nome do artigo 12 | structure_tweaks_functions = Funções 13 | structure_tweaks_edit = Editar 14 | structure_tweaks_delete = Deletar 15 | structure_tweaks_article_linkmap = Categoria 16 | structure_tweaks_article_exists = Já existe um ID com essa referência! 17 | structure_tweaks_select = Começar artigo 18 | structure_tweaks_article_not_found = Artigo não encontrado 19 | structure_tweaks_type = Tipo 20 | structure_tweaks_hide_startarticle = Esconder "começar artigo" 21 | structure_tweaks_split_category = Separador de categorias 22 | structure_tweaks_move_meta_info_page = Exibir artigo de banco de dados na barra lateral 23 | structure_tweaks_save = Salvar 24 | structure_tweaks_saved = Configurações salvas 25 | structure_tweaks_metadata = Banco de dados 26 | structure_tweaks_metainfo_fields = Informação de dados 27 | structure_tweaks_splitter_label = Label 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Structure Tweaks 2 | 3 | ### 1. Artikel ausblenden 4 | 5 | Da bei REDAXO Artikel-Kategorien durch besonders konfigurierte Artikel erzeugt werden, sind diese Artikel stets in der Kategorienansicht sichtbar. 6 | Solange dieser Artikel für Inhalte genutzt wird, fällt das nicht weiter auf. 7 | Falls man jedoch Kategorien ähnlich wie Dateiordner als reine Datensilos nutzen möchte, kann dieser zusätzliche Artikel die Übersicht stören. 8 | 9 | Es können Artikel bestimmt werden, die in der Übersicht nicht sichtbar sein sollen. 10 | Die Artikel werden über CSS ausgeblendet. Evtl. vorhandene Inhalte bleiben also bestehen und werden im Frontend angezeigt. 11 | 12 | ### 2. Funktionen ausblenden 13 | 14 | Es können die Funktionen zum Löschen und zur Statusänderung sowie der Funktionen-Tab ausgeblendet werden. 15 | 16 | ### 3. Breitere Trenner in der Kategorienübersicht 17 | 18 | Es können Kategorien bestimmt werden, vor denen ein breiter Trenner mit optionalem Text erscheinen soll. 19 | 20 | ### 4. Artikel-Metadaten 21 | 22 | #### bis REDAXO 5.9: in der Seitenspalte anzeigen 23 | 24 | Die Artikel-Metainfos des Metainfo-Addons können optional statt in einem Tab in der Seitenspalte angezeigt werden. Dort werden sie mit den Metadaten der Strukturansicht kombiniert. Außerdem kann die Anzeige des Artikelstatus zum On- und Offlineschalten des Artikels genutzt werden. 25 | 26 | #### ab REDAXO 5.10: in einem Tab anzeigen 27 | 28 | Ab REDAXO 5.10 werden Metadaten als Standard in der Seitenspalte angezeigt. Das Addon bietet ab dieser REDAXO-Version die Möglichkeit, die Metadaten in einen Tab zu verschieben. 29 | 30 | ### Credits 31 | 32 | Rexdude, Ingo Winter, Daniel Weitenauer 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /assets/style.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Move metainfo 3 | */ 4 | .moved-metainfo .rex-form-group:not(.rex-form-group-vertical) > dt, 5 | .moved-metainfo .rex-form-group:not(.rex-form-group-vertical) > dd, 6 | .moved-metainfo .rex-form-group:not(.rex-form-group-vertical) > dd:first-child, 7 | .moved-metainfo .dl-horizontal > dt, 8 | .moved-metainfo .dl-horizontal > dd, 9 | .moved-metainfo .dl-horizontal > dd:first-child { 10 | margin: 0; 11 | padding: 0; 12 | float: none; 13 | display: block !important; 14 | width: 100% !important; 15 | text-align: left !important; 16 | } 17 | 18 | /** 19 | * Hide Startarticle 20 | */ 21 | .rex-startarticle.is-hidden { 22 | display: none !important; 23 | } 24 | /** 25 | * Hide Categories 26 | */ 27 | .structure-tweaks-category.is-hidden { 28 | display: none !important; 29 | } 30 | 31 | /** 32 | * Hide category status 33 | */ 34 | .structure-tweak-functions-all { 35 | display: none !important; 36 | } 37 | 38 | /** 39 | * Category splitter 40 | */ 41 | .structure-tweaks-splitter, 42 | .structure-tweaks-splitter:focus, 43 | .structure-tweaks-splitter:active, 44 | .structure-tweaks-splitter:hover { 45 | color: #324050; 46 | font-weight: bold; 47 | background-color: #F3F6FB !important; 48 | border-color: #F3F6FB !important;; 49 | } 50 | @media (prefers-color-scheme: dark) { 51 | body.rex-has-theme:not(.rex-theme-light) .structure-tweaks-splitter, 52 | body.rex-has-theme:not(.rex-theme-light) .structure-tweaks-splitter:focus, 53 | body.rex-has-theme:not(.rex-theme-light) .structure-tweaks-splitter:active, 54 | body.rex-has-theme:not(.rex-theme-light) .structure-tweaks-splitter:hover { 55 | color: rgba(255, 255, 255, 0.75); 56 | font-weight: bold; 57 | background-color: #1b232c !important; 58 | border-color: #1b232c !important;; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lang/en_gb.lang: -------------------------------------------------------------------------------- 1 | structure_tweaks = Structure Tweaks 2 | 3 | structure_tweaks_page_settings = Settings 4 | structure_tweaks_page_categories = Categories 5 | structure_tweaks_page_info = Info 6 | structure_tweaks_description = Allows manipulation of the structure output 7 | structure_tweaks_deleted = Reference has been deleted. 8 | structure_tweaks_list_rowmsg = No references found 9 | structure_tweaks_list_table_attr = List of all references 10 | structure_tweaks_article_id = Article ID 11 | structure_tweaks_article_name = Article name 12 | structure_tweaks_functions = Functions 13 | structure_tweaks_edit = edit 14 | structure_tweaks_delete = delete 15 | structure_tweaks_article_linkmap = Kategorie 16 | structure_tweaks_article_exists = A reference with this ID already exists! 17 | structure_tweaks_select = Start article 18 | structure_tweaks_article_not_found = Article not found! 19 | structure_tweaks_type = Type 20 | structure_tweaks_hide_startarticle = Hide start article (for all users) 21 | structure_tweaks_hide_startarticle_non_admin = Hide start article (for non-admins) 22 | structure_tweaks_hide_category_functions = Deactivate category status (for all users) 23 | structure_tweaks_hide_category_functions_non_admin = Deactivate category status (for non-admins) 24 | structure_tweaks_hide_category_functions_all = Deactivate category functions (for all users) 25 | structure_tweaks_hide_category_functions_all_non_admin = Deactivate category functions (for non-admins) 26 | structure_tweaks_hide_categories = Hide category (for all users) 27 | structure_tweaks_hide_categories_non_admin = Hide category (for non-admins) 28 | structure_tweaks_split_category = Category separator 29 | structure_tweaks_move_meta_info_page = Show article metadata in sidebar 30 | structure_tweaks_move_meta_info_to_tab = Show article metadata in a tabbed page 31 | structure_tweaks_save = save 32 | structure_tweaks_saved = Settings saved 33 | structure_tweaks_metadata = Metadata 34 | structure_tweaks_metainfo_fields = Meta Info 35 | structure_tweaks_splitter_label = Label 36 | -------------------------------------------------------------------------------- /lang/sv_se.lang: -------------------------------------------------------------------------------- 1 | structure_tweaks = Structure Tweaks 2 | 3 | structure_tweaks_page_settings = Inställningar 4 | structure_tweaks_page_categories = Kategorier 5 | structure_tweaks_page_info = Info 6 | structure_tweaks_description = Tillåter manipulering av strukturoutput ... 7 | structure_tweaks_deleted = Referensen raderades. 8 | structure_tweaks_list_rowmsg = Inga referenser hittades! 9 | structure_tweaks_list_table_attr = Lista av alla referenser 10 | structure_tweaks_article_id = Artikel-ID 11 | structure_tweaks_article_name = Artikel-namn 12 | structure_tweaks_functions = Funktioner 13 | structure_tweaks_edit = redigera 14 | structure_tweaks_delete = radera 15 | structure_tweaks_article_linkmap = Kategori 16 | structure_tweaks_article_exists = En referens med denna ID finns redan! 17 | structure_tweaks_select = Startartikel 18 | structure_tweaks_article_not_found = Artikeln kunde inte hittas! 19 | structure_tweaks_type = Typ 20 | structure_tweaks_hide_startarticle = Dölj startartikeln 21 | structure_tweaks_hide_startarticle_non_admin = Dölj startup-objektet (för alla användare utom administratörer) 22 | structure_tweaks_hide_category_functions = Deaktivera kategori-status (för alla användare) 23 | structure_tweaks_hide_category_functions_non_admin = Deaktivera kategori-status (för alla användare utom administratörerna) 24 | structure_tweaks_hide_category_functions_all = Deaktivera kategori-funktionen (för alla användare) 25 | structure_tweaks_hide_category_functions_all_non_admin = Deaktivera kategori-funktionen (för alla användare utom administratörerna) 26 | structure_tweaks_hide_categories = Dölj kategori (för alla användare) 27 | structure_tweaks_hide_categories_non_admin = Dölj kategori (för alla användare utom administratörer) 28 | structure_tweaks_split_category = Kategori avskiljare 29 | structure_tweaks_move_meta_info_page = Visa artikel-metadata i sidospalten 30 | structure_tweaks_move_meta_info_to_tab = Visa artikel-metadata i en flik 31 | structure_tweaks_save = Dpara 32 | structure_tweaks_saved = Inställningar sparades 33 | structure_tweaks_metadata = Metadata 34 | structure_tweaks_metainfo_fields = Meta info 35 | structure_tweaks_splitter_label = Label 36 | -------------------------------------------------------------------------------- /lib/category_splitter.php: -------------------------------------------------------------------------------- 1 | isAvailable() && rex_request('page', 'string') == 'structure') { 15 | rex_extension::register('PAGE_HEADER', [__CLASS__, 'ep']); 16 | } 17 | }); 18 | } 19 | 20 | /** 21 | * @return array 22 | */ 23 | public static function getSplitterCategories() 24 | { 25 | $sql = rex_sql::factory(); 26 | $articles = $sql->getArray('SELECT * FROM '.rex::getTable(self::name()).' WHERE `type` = "split_category"'); 27 | 28 | $return = []; 29 | foreach ($articles as $article) { 30 | $item = [ 31 | 'article_id' => $article['article_id'], 32 | 'label' => rex_i18n::translate($article['label']), 33 | ]; 34 | 35 | $return[] = $item; 36 | } 37 | 38 | return $return; 39 | } 40 | 41 | /** 42 | * EP CALLBACK 43 | * @param rex_extension_point $ep 44 | * @return string 45 | */ 46 | public static function ep(rex_extension_point $ep) 47 | { 48 | $subject = $ep->getSubject(); 49 | 50 | // Pass splitting categories to JavaScript 51 | $split_categories = self::getSplitterCategories(); 52 | if (!empty($split_categories)) { 53 | $subject .= ' 54 | 61 | '; 62 | } 63 | 64 | return $subject; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lang/de_de.lang: -------------------------------------------------------------------------------- 1 | structure_tweaks = Structure Tweaks 2 | 3 | structure_tweaks_page_settings = Einstellungen 4 | structure_tweaks_page_categories = Kategorien 5 | structure_tweaks_page_info = Info 6 | structure_tweaks_description = Möglichkeiten zur Manipulation der Strukturausgabe.. 7 | structure_tweaks_deleted = Verweis wurde gelöscht. 8 | structure_tweaks_list_rowmsg = Keine Verweise vorhanden 9 | structure_tweaks_list_table_attr = Auflistung aller Verweise 10 | structure_tweaks_article_id = Artikel-ID 11 | structure_tweaks_article_name = Artikel-Name 12 | structure_tweaks_functions = Funktionen 13 | structure_tweaks_edit = bearbeiten 14 | structure_tweaks_delete = löschen 15 | structure_tweaks_article_linkmap = Kategorie 16 | structure_tweaks_article_exists = Ein Verweis mit dieser ID existiert bereits! 17 | structure_tweaks_select = Startartikel 18 | structure_tweaks_article_not_found = Artikel nicht gefunden! 19 | structure_tweaks_type = Typ 20 | structure_tweaks_hide_startarticle = Startartikel ausblenden (für alle Nutzer) 21 | structure_tweaks_hide_startarticle_non_admin = Startartikel ausblenden (für alle Nutzer außer Administratoren) 22 | structure_tweaks_hide_category_functions = Kategorie-Status deaktivieren (für alle Nutzer) 23 | structure_tweaks_hide_category_functions_non_admin = Kategorie-Status deaktivieren (für alle Nutzer außer Administratoren) 24 | structure_tweaks_hide_category_functions_all = Kategorie-Funktionen deaktivieren (für alle Nutzer) 25 | structure_tweaks_hide_category_functions_all_non_admin = Kategorie-Funktionen deaktivieren (für alle Nutzer außer Administratoren) 26 | structure_tweaks_hide_categories = Kategorie ausblenden (für alle Nutzer) 27 | structure_tweaks_hide_categories_non_admin = Kategorie ausblenden (für alle Nutzer außer Administratoren) 28 | structure_tweaks_split_category = Trenner vor Kategorie 29 | structure_tweaks_move_meta_info_page = Anzeige der Artikel-Metadaten in der Seitenspalte 30 | structure_tweaks_move_meta_info_to_tab = Anzeige der Artikel-Metadaten in einem Tab 31 | structure_tweaks_save = Speichern 32 | structure_tweaks_saved = Einstellungen gespeichert 33 | structure_tweaks_metadata = Metadaten 34 | structure_tweaks_metainfo_fields = Meta Infos 35 | structure_tweaks_splitter_label = Beschriftung 36 | -------------------------------------------------------------------------------- /lang/es_es.lang: -------------------------------------------------------------------------------- 1 | structure_tweaks = Ajustes de estructura 2 | 3 | structure_tweaks_page_settings = Ajustes 4 | structure_tweaks_page_categories = Categorias 5 | structure_tweaks_page_info = Info 6 | structure_tweaks_description = Permite la manipulación de la salida de la estructura 7 | structure_tweaks_deleted = La referencia ha sido eliminada. 8 | structure_tweaks_list_rowmsg = No se encontraron referencias 9 | structure_tweaks_list_table_attr = Lista de todas las referencias 10 | structure_tweaks_article_id = ID del artículo 11 | structure_tweaks_article_name = Nombre del artículo 12 | structure_tweaks_functions = Funciones 13 | structure_tweaks_edit = Editar 14 | structure_tweaks_delete = Borrar 15 | structure_tweaks_article_linkmap = Categoría 16 | structure_tweaks_article_exists = ¡Ya existe una referencia con esta ID! 17 | structure_tweaks_select = Comenzar artículo 18 | structure_tweaks_article_not_found = Artículo no encontrado! 19 | structure_tweaks_type = Tipo 20 | structure_tweaks_hide_startarticle = Ocultar artículo de inicio (para todos los usuarios) 21 | structure_tweaks_hide_startarticle_non_admin = Ocultar artículo de inicio (para no administradores) 22 | structure_tweaks_hide_category_functions = Desactivar estado de categoría (para todos los usuarios) 23 | structure_tweaks_hide_category_functions_non_admin = Desactivar estado de categoría (para todos los usuarios excepto los administradores 24 | structure_tweaks_hide_category_functions_all = Deshabilitar las características de la categoría (para todos los usuarios) 25 | structure_tweaks_hide_category_functions_all_non_admin = Deshabilitar las características de la categoría (para todos los usuarios excepto los administradores) 26 | structure_tweaks_hide_categories = Ocultar categoría (para todos los usuarios) 27 | structure_tweaks_hide_categories_non_admin = Ocultar categoría (para no administradores) 28 | structure_tweaks_split_category = Separador de categoría 29 | structure_tweaks_move_meta_info_page = Mostrar los metadatos del artículo en la barra lateral 30 | structure_tweaks_save = Guardar 31 | structure_tweaks_saved = Configuraciones guardadas 32 | structure_tweaks_metadata = Metadatos 33 | structure_tweaks_metainfo_fields = Meta información 34 | structure_tweaks_splitter_label = subtítulo 35 | -------------------------------------------------------------------------------- /lib/hide_startarticle.php: -------------------------------------------------------------------------------- 1 | isAvailable() && in_array($page, $pages)) { 18 | rex_extension::register('PAGE_HEADER', [__CLASS__, 'ep']); 19 | } 20 | }); 21 | } 22 | 23 | /** 24 | * @param bool $non_admin 25 | * @return array 26 | */ 27 | protected static function getHiddenArticles($non_admin = false) 28 | { 29 | if ($non_admin) { 30 | $type = 'hide_startarticle_non_admin'; 31 | } else { 32 | $type = 'hide_startarticle'; 33 | } 34 | 35 | return self::getArticles($type); 36 | } 37 | 38 | /** 39 | * EP CALLBACK 40 | * @param rex_extension_point $ep 41 | * @return string 42 | */ 43 | public static function ep(rex_extension_point $ep) 44 | { 45 | $subject = $ep->getSubject(); 46 | 47 | // Pass hidden articles to JavaScript 48 | $hidden_articles = self::getHiddenArticles(); 49 | if (!empty($hidden_articles)) { 50 | $subject .= self::getScript($hidden_articles); 51 | } 52 | 53 | // Pass hidden non-admin articles to JavaScript 54 | $hidden_articles = self::getHiddenArticles(true); 55 | if (!empty($hidden_articles) && !rex::getUser()->isAdmin()) { 56 | $subject .= self::getScript($hidden_articles); 57 | } 58 | 59 | return $subject; 60 | } 61 | 62 | /** 63 | * @param array $hidden_articles 64 | * @return string 65 | */ 66 | protected static function getScript($hidden_articles) 67 | { 68 | return ' 69 | 76 | '; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /pages/content.metainfo.php: -------------------------------------------------------------------------------- 1 | setQuery(' 9 | SELECT article.*, template.attributes as template_attributes 10 | FROM ' . rex::getTablePrefix() . 'article as article 11 | LEFT JOIN ' . rex::getTablePrefix() . 'template as template ON template.id = article.template_id 12 | WHERE article.id = ? AND clang_id = ?', [ 13 | $articleId, 14 | $clang 15 | ]); 16 | 17 | $context = new rex_context([ 18 | 'page' => rex_be_controller::getCurrentPage(), 19 | 'article_id' => $articleId, 20 | 'category_id' => $categoryId, 21 | 'clang' => $clang, 22 | 'ctype' => $ctype, 23 | ]); 24 | 25 | $content = ''; 26 | 27 | if (rex_post('savemeta', 'boolean')) { 28 | $content = rex_view::success(rex_i18n::msg('minfo_metadata_saved')); 29 | } 30 | 31 | $panel = '
32 | 33 | 34 | '; 35 | 36 | $metainfoHandler = new rex_metainfo_article_handler(); 37 | $form = $metainfoHandler->getForm([ 38 | 'id' => $articleId, 39 | 'clang' => $clang, 40 | 'article' => $article, 41 | ]); 42 | 43 | $n = []; 44 | $n['label'] = ''; 45 | $n['field'] = ''; 46 | $formElements = [$n]; 47 | 48 | $fragment = new rex_fragment(); 49 | $fragment->setVar('elements', $formElements, false); 50 | $panel .= $fragment->parse('core/form/form.php'); 51 | 52 | $panel .= $form . '
'; 53 | 54 | $formElements = []; 55 | 56 | $n = []; 57 | $n['field'] = ''; 58 | $formElements[] = $n; 59 | 60 | $fragment = new rex_fragment(); 61 | $fragment->setVar('elements', $formElements, false); 62 | $buttons = $fragment->parse('core/form/submit.php'); 63 | 64 | $fragment = new rex_fragment(); 65 | $fragment->setVar('class', 'edit', false); 66 | $fragment->setVar('title', rex_i18n::msg('general'), false); 67 | $fragment->setVar('body', $panel, false); 68 | $fragment->setVar('buttons', $buttons, false); 69 | $content .= $fragment->parse('core/page/section.php'); 70 | 71 | return ' 72 |
73 | ' . $content . ' 74 |
'; 75 | -------------------------------------------------------------------------------- /lib/pages/page_settings.php: -------------------------------------------------------------------------------- 1 | setConfig(rex_post('config', [ 20 | ['move_meta_info_page', 'bool'], 21 | ['move_meta_info_to_tab', 'bool'], 22 | ])); 23 | 24 | $message = rex_view::success($addon->i18n('saved')); 25 | } 26 | 27 | return $message; 28 | } 29 | 30 | /** 31 | * @return string 32 | */ 33 | public static function getForm() 34 | { 35 | $addon = self::addon(); 36 | 37 | // Checkboxes 38 | if (rex_string::versionCompare(rex::getVersion(), '5.10.0-dev', '<')) { 39 | $checkbox_elements = []; 40 | $checkbox_elements[] = [ 41 | 'label' => '', 42 | 'field' => 'getConfig('move_meta_info_page') ? ' checked="checked"' : '').' />', 43 | ]; 44 | } else { 45 | $checkbox_elements = []; 46 | $checkbox_elements[] = [ 47 | 'label' => '', 48 | 'field' => 'getConfig('move_meta_info_to_tab') ? ' checked="checked"' : '').' />', 49 | ]; 50 | } 51 | $fragment = new rex_fragment(); 52 | $fragment->setVar('elements', $checkbox_elements, false); 53 | $checkboxes = $fragment->parse('core/form/checkbox.php'); 54 | 55 | // Submit 56 | $submit_elements = []; 57 | $submit_elements[] = [ 58 | 'field' => '', 59 | ]; 60 | $fragment = new rex_fragment(); 61 | $fragment->setVar('flush', true); 62 | $fragment->setVar('elements', $submit_elements, false); 63 | $submit = $fragment->parse('core/form/submit.php'); 64 | 65 | // Form 66 | $fragment = new rex_fragment(); 67 | $fragment->setVar('class', 'edit'); 68 | $fragment->setVar('title', $addon->i18n('page_settings')); 69 | $fragment->setVar('body', $checkboxes, false); 70 | $fragment->setVar('buttons', $submit, false); 71 | $form = $fragment->parse('core/page/section.php'); 72 | 73 | return $form; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/hide_category_functions.php: -------------------------------------------------------------------------------- 1 | isAvailable() && rex_request('page', 'string') == 'structure') || 16 | (rex_plugin::get('structure', 'content')->isAvailable() && rex_request('page', 'string') == 'content/edit') 17 | ) { 18 | rex_extension::register('PAGE_HEADER', [__CLASS__, 'ep']); 19 | } 20 | }); 21 | } 22 | 23 | /** 24 | * @param bool $non_admin 25 | * @return array 26 | */ 27 | protected static function getHiddenCategories($non_admin = false) 28 | { 29 | if ($non_admin) { 30 | $type = 'hide_cat_functions_non_admin'; 31 | } else { 32 | $type = 'hide_cat_functions'; 33 | } 34 | 35 | return self::getArticles($type); 36 | } 37 | 38 | /** 39 | * @param bool $non_admin 40 | * @return array 41 | */ 42 | protected static function getHiddenCategoriesAll($non_admin = false) 43 | { 44 | if ($non_admin) { 45 | $type = 'hide_cat_functions_all_non_admin'; 46 | } else { 47 | $type = 'hide_cat_functions_all'; 48 | } 49 | 50 | return self::getArticles($type); 51 | } 52 | 53 | /** 54 | * EP CALLBACK 55 | * @param rex_extension_point $ep 56 | * @return string 57 | */ 58 | public static function ep(rex_extension_point $ep) 59 | { 60 | $subject = $ep->getSubject(); 61 | 62 | // Pass hidden categories to JavaScript 63 | $hidden_categories = self::getHiddenCategories(); 64 | if (!empty($hidden_categories)) { 65 | $subject .= self::getScript($hidden_categories); 66 | } 67 | 68 | // Pass hidden non-admin categories to JavaScript 69 | $hidden_categories = self::getHiddenCategories(true); 70 | if (!empty($hidden_categories) && !rex::getUser()->isAdmin()) { 71 | $subject .= self::getScript($hidden_categories); 72 | } 73 | 74 | // Pass hidden categories to JavaScript 75 | $hidden_categories = self::getHiddenCategoriesAll(); 76 | if (!empty($hidden_categories)) { 77 | $subject .= self::getScriptAll($hidden_categories); 78 | } 79 | 80 | // Pass hidden non-admin categories to JavaScript 81 | $hidden_categories = self::getHiddenCategoriesAll(true); 82 | if (!empty($hidden_categories) && !rex::getUser()->isAdmin()) { 83 | $subject .= self::getScriptAll($hidden_categories); 84 | } 85 | 86 | return $subject; 87 | } 88 | 89 | /** 90 | * @param array $hidden_categories 91 | * @return string 92 | */ 93 | protected static function getScript($hidden_categories) 94 | { 95 | $deprecated_traversing = 'false'; 96 | if (version_compare(rex::getVersion(), '5.5.0', '<')) { 97 | $deprecated_traversing = 'true'; 98 | } 99 | 100 | return ' 101 | 108 | '; 109 | } 110 | 111 | /** 112 | * @param array $hidden_categories 113 | * @return string 114 | */ 115 | protected static function getScriptAll($hidden_categories) 116 | { 117 | $deprecated_traversing = 'false'; 118 | if (version_compare(rex::getVersion(), '5.5.0', '<')) { 119 | $deprecated_traversing = 'true'; 120 | } 121 | 122 | return ' 123 | 130 | '; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /lib/hide_categories.php: -------------------------------------------------------------------------------- 1 | isAvailable() && 15 | (rex_request('page', 'string') == 'structure' || rex_request('page', 'string') == 'linkmap') 16 | ) { 17 | rex_extension::register('PAGE_HEADER', [__CLASS__, 'ep']); 18 | } 19 | }); 20 | 21 | if (rex_plugin::get('structure', 'content')->isAvailable() && rex_request('page', 'string') == 'content/functions') { 22 | rex_extension::register('OUTPUT_FILTER', [__CLASS__, 'epFunctions']); 23 | } 24 | } 25 | 26 | /** 27 | * @param bool $non_admin 28 | * @return array 29 | */ 30 | protected static function getHiddenCategories($non_admin = false) 31 | { 32 | if ($non_admin) { 33 | $type = 'hide_categories_non_admin'; 34 | } else { 35 | $type = 'hide_categories'; 36 | } 37 | 38 | return self::getArticles($type); 39 | } 40 | 41 | /** 42 | * EP CALLBACK 43 | * @param rex_extension_point $ep 44 | * @return string 45 | */ 46 | public static function ep(rex_extension_point $ep) 47 | { 48 | $subject = $ep->getSubject(); 49 | 50 | // Pass hidden categories to JavaScript 51 | $hidden_categories = self::getHiddenCategories(); 52 | if (!empty($hidden_categories)) { 53 | if (rex_request('page', 'string') == 'structure') { 54 | $subject .= self::getScript($hidden_categories); 55 | } 56 | if (rex_request('page', 'string') == 'linkmap') { 57 | $subject .= self::getScriptInLinkmap($hidden_categories); 58 | } 59 | } 60 | 61 | // Pass hidden non-admin categories to JavaScript 62 | $hidden_categories = self::getHiddenCategories(true); 63 | if (!empty($hidden_categories) && !rex::getUser()->isAdmin()) { 64 | if (rex_request('page', 'string') == 'structure') { 65 | $subject .= self::getScript($hidden_categories); 66 | } 67 | if (rex_request('page', 'string') == 'linkmap') { 68 | $subject .= self::getScriptInLinkmap($hidden_categories); 69 | } 70 | } 71 | 72 | return $subject; 73 | } 74 | 75 | /** 76 | * EP CALLBACK 77 | * @param rex_extension_point $ep 78 | * @return string 79 | */ 80 | public static function epFunctions(rex_extension_point $ep) 81 | { 82 | $subject = $ep->getSubject(); 83 | 84 | // Hidden categories 85 | $hidden_categories = self::getHiddenCategories(); 86 | if (!empty($hidden_categories)) { 87 | $subject = self::removeCategoryOptions($subject, 'category_id_new', $hidden_categories); 88 | $subject = self::removeCategoryOptions($subject, 'category_copy_id_new', $hidden_categories); 89 | } 90 | 91 | // Hidden non-admin categories 92 | $hidden_categories = self::getHiddenCategories(true); 93 | if (!empty($hidden_categories) && !rex::getUser()->isAdmin()) { 94 | $subject = self::removeCategoryOptions($subject, 'category_id_new', $hidden_categories); 95 | $subject = self::removeCategoryOptions($subject, 'category_copy_id_new', $hidden_categories); 96 | } 97 | 98 | return $subject; 99 | } 100 | 101 | /** 102 | * @param array $hidden_categories 103 | * @return string 104 | */ 105 | protected static function getScript($hidden_categories) 106 | { 107 | return ' 108 | 115 | '; 116 | } 117 | 118 | /** 119 | * @param array $hidden_categories 120 | * @return string 121 | */ 122 | protected static function getScriptInLinkmap($hidden_categories) 123 | { 124 | return ' 125 | 132 | '; 133 | } 134 | 135 | private static function removeCategoryOptions(string $subject, string $select_id, array $hidden_categories): string 136 | { 137 | libxml_use_internal_errors(true); // Disable HTML parsing warnings @see https://stackoverflow.com/questions/9149180/domdocumentloadhtml-error 138 | 139 | $dom = new DOMDocument('1.0', 'utf-8'); 140 | $dom->loadHTML($subject); 141 | 142 | $element = $dom->getElementById($select_id); 143 | if ($element) { 144 | /** @var DOMElement $option */ 145 | foreach ($element->getElementsByTagName('option') as $option) { 146 | if (in_array($option->getAttribute('value'), $hidden_categories)) { 147 | $element->removeChild($option); 148 | } 149 | } 150 | } 151 | 152 | libxml_use_internal_errors(false); // Enable HTML parsing warnings 153 | 154 | return $dom->saveHTML(); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /lib/move_metainfo_to_tab.php: -------------------------------------------------------------------------------- 1 | isAvailable() && rex_plugin::get('structure', 'content')->isAvailable()) { 14 | // Remove meta info from sidebar 15 | rex_extension::register('STRUCTURE_CONTENT_SIDEBAR', [__CLASS__, 'removeMetaPage']); 16 | 17 | rex_extension::register('PAGES_PREPARED', function () { 18 | $page = new rex_be_page('metainfo', rex_i18n::msg('metadata')); 19 | $page->setSubPath(rex_addon::get('structure_tweaks')->getPath('pages/content.metainfo.php')); 20 | $page_controller = rex_be_controller::getPageObject('content'); 21 | $page_controller->addSubpage($page); 22 | }); 23 | } 24 | } 25 | 26 | /** 27 | * EP CALLBACK 28 | * @param rex_extension_point $ep 29 | * @return string 30 | */ 31 | public static function removeMetaPage(rex_extension_point $ep) 32 | { 33 | $subject = $ep->getSubject(); 34 | 35 | libxml_use_internal_errors(true); // Disable HTML parsing warnings @see https://stackoverflow.com/questions/9149180/domdocumentloadhtml-error 36 | $dom = new DOMDocument('1.0', 'utf-8'); 37 | $dom->loadHTML(mb_convert_encoding($subject, 'HTML-ENTITIES', 'utf-8')); // Fix encoding of loadHTML https://stackoverflow.com/questions/8218230/php-domdocument-loadhtml-not-encoding-utf-8-correctly 38 | $metadata = $dom->getElementById('rex-page-sidebar-metainfo'); 39 | if ($metadata) { 40 | $metadata->parentNode->removeChild($metadata); 41 | libxml_use_internal_errors(false); // Enable HTML parsing warnings 42 | 43 | // @see https://stackoverflow.com/questions/9924261/removing-doctype-while-saving-domdocument 44 | $subject = preg_replace('~<(?:!DOCTYPE|/?(?:html|body))[^>]*>\s*~i', '', $dom->saveHTML()); 45 | } 46 | 47 | return $subject; 48 | } 49 | 50 | /** 51 | * Substituted metadata panel 52 | * @see redaxo/src/addons/structure/plugins/content/boot.php 53 | * @return string 54 | */ 55 | protected static function getStructure() 56 | { 57 | $article_id = self::getArticleId(); 58 | $clang_id = self::getClangId(); 59 | $article = rex_article::get($article_id, $clang_id); 60 | $article_status = self::getArticleStatus($article_id, $clang_id); 61 | 62 | return ' 63 |
64 |
'.rex_i18n::msg('created_by').'
'.$article->getValue('createuser').'
65 |
'.rex_i18n::msg('created_on').'
'.rex_formatter::strftime($article->getValue('createdate'), 'date').'
66 |
'.rex_i18n::msg('updated_by').'
'.$article->getValue('updateuser').'
67 |
'.rex_i18n::msg('updated_on').'
'.rex_formatter::strftime($article->getValue('updatedate'), 'date').'
68 |
'.rex_i18n::msg('status').'
'.$article_status.'
69 |
70 | '; 71 | } 72 | 73 | /** 74 | * Make article status switchable 75 | * @see redaxo/src/addons/structure/pages/index.php 76 | * @param int $article_id 77 | * @param int $clang_id 78 | * @return string 79 | */ 80 | protected static function getArticleStatus($article_id, $clang_id) 81 | { 82 | $article = rex_article::get($article_id, $clang_id); 83 | $artstart = rex_request('artstart', 'int'); 84 | $catstart = rex_request('catstart', 'int'); 85 | 86 | $perm = rex::getUser()->getComplexPerm('structure')->hasCategoryPerm($article_id); 87 | 88 | $context = new rex_context([ 89 | 'page' => 'content/edit', 90 | 'category_id' => $article->getCategoryId(), 91 | 'article_id' => $article_id, 92 | 'clang' => $clang_id, 93 | ]); 94 | 95 | $article_status_types = rex_article_service::statusTypes(); 96 | $article_status = $article_status_types[$article->getValue('status')][0]; 97 | $article_class = $article_status_types[$article->getValue('status')][1]; 98 | $article_icon = $article_status_types[$article->getValue('status')][2]; 99 | 100 | if (version_compare(rex::getVersion(), '5.5.0', '<')) { 101 | if ($article->isStartArticle()) { 102 | $article_link = $context->getUrl([ 103 | 'rex-api-call' => 'category_status', 104 | 'catstart' => $catstart, 105 | 'category-id' => $article->getCategoryId(), 106 | ]); 107 | } else { 108 | $article_link = $context->getUrl([ 109 | 'rex-api-call' => 'article_status', 110 | 'artstart' => $artstart 111 | ]); 112 | } 113 | } else { 114 | if ($article->isStartArticle()) { 115 | $article_link = $context->getUrl([ 116 | 'catstart' => $catstart, 117 | 'category-id' => $article->getCategoryId(), 118 | ] + rex_api_category_status::getUrlParams()); 119 | } else { 120 | $article_link = $context->getUrl([ 121 | 'artstart' => $artstart 122 | ] + rex_api_article_status::getUrlParams()); 123 | } 124 | } 125 | 126 | if ($perm && rex::getUser()->hasPerm('publishArticle[]')) { 127 | $return = ' '.$article_status.''; 128 | } else { 129 | $return = ' '.$article_status.''; 130 | } 131 | 132 | return $return; 133 | } 134 | 135 | /** 136 | * @return int 137 | */ 138 | protected static function getArticleId() 139 | { 140 | $article_id = rex_request('article_id', 'int'); 141 | $article_id = rex_article::get($article_id) ? $article_id : 0; 142 | 143 | return $article_id; 144 | } 145 | 146 | /** 147 | * @return int 148 | */ 149 | protected static function getClangId() 150 | { 151 | $clang_id = rex_request('clang', 'int'); 152 | $clang_id = rex_clang::exists($clang_id) ? $clang_id : rex_clang::getStartId(); 153 | 154 | return $clang_id; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /lib/pages/page_categories.php: -------------------------------------------------------------------------------- 1 | 0) { 13 | $return .= self::delete(); 14 | } 15 | 16 | $fragment = new rex_fragment(); 17 | $fragment->setVar('title', self::msg('page_settings')); 18 | if (in_array(self::getFunc(), ['add', 'edit'])) { 19 | $fragment->setVar('class', 'edit', false); 20 | $fragment->setVar('body', self::getForm(), false); 21 | } else { 22 | $fragment->setVar('content', self::getTable(), false); 23 | } 24 | $return .= $fragment->parse('core/page/section.php'); 25 | 26 | return $return; 27 | } 28 | 29 | /** 30 | * @return string 31 | */ 32 | protected static function delete() 33 | { 34 | $sql = rex_sql::factory(); 35 | #$sql->setDebug(true); 36 | $sql->setTable(rex::getTable(self::name())); 37 | $sql->setWhere('id='.self::getArticleId().' LIMIT 1'); 38 | 39 | if ($sql->delete()) { 40 | $message = rex_view::info(self::msg('deleted')); 41 | } else { 42 | $message = rex_view::warning($sql->getError()); 43 | } 44 | 45 | return $message; 46 | } 47 | 48 | /** 49 | * @return string 50 | */ 51 | protected static function getTable() 52 | { 53 | $list = rex_list::factory('SELECT * FROM '.rex::getTable(self::name()).' ORDER BY id'); 54 | 55 | $head = ''; 56 | $body = ''; 57 | 58 | $list->setNoRowsMessage(self::msg('list_rowmsg')); 59 | 60 | // Icon 61 | $list->addColumn($head, $body, 0, [ 62 | '###VALUE###', 63 | '###VALUE###' 64 | ]); 65 | $list->setColumnParams($head, ['func' => 'edit', 'article_id' => '###id###']); 66 | 67 | // Name & ID 68 | $list->addColumn(self::msg('article_name'), '', 2, array('###VALUE###','###VALUE###')); 69 | $list->setColumnFormat(self::msg('article_name'), 'custom', __CLASS__.'::getArticleName'); 70 | $list->setColumnLabel('article_id', self::msg('article_id')); 71 | 72 | // Type 73 | $list->setColumnFormat('type', 'custom', __CLASS__.'::getType'); 74 | $list->setColumnLabel('type', self::msg('type')); 75 | 76 | // Label 77 | $list->setColumnLabel('label', self::msg('splitter_label')); 78 | 79 | // Functions 80 | $list->addColumn(self::msg('functions'), self::msg('edit'), -1, [ 81 | '###VALUE###', 82 | '###VALUE###' 83 | ]); 84 | $list->setColumnParams(self::msg('functions'), ['func' => 'edit', 'article_id' => '###id###']); 85 | $list->addColumn('delete_column', self::msg('delete'), -1, [ 86 | '', 87 | '###VALUE###' 88 | ]); 89 | $list->setColumnParams('delete_column', ['func' => 'delete', 'article_id' => '###id###']); 90 | $list->addLinkAttribute('delete_column', 'onclick', 'return confirm(\''.self::msg('delete').' ?\')'); 91 | 92 | return $list->get(); 93 | } 94 | 95 | /** 96 | * @return string 97 | */ 98 | protected static function getForm() 99 | { 100 | $article_id = self::getArticleId(); 101 | 102 | $form = rex_form::factory(rex::getTable(self::name()), self::msg('select'), 'id='.$article_id); 103 | 104 | if (self::getFunc() == 'edit') { 105 | $form->addParam('article_id', $article_id); 106 | } 107 | $form->addErrorMessage(REX_FORM_ERROR_VIOLATE_UNIQUE_KEY, self::msg('article_exists')); 108 | 109 | $field = $form->addLinkmapField('article_id'); 110 | $field->setLabel(self::msg('article_linkmap')); 111 | 112 | $field = $form->addSelectField('type'); 113 | $field->setLabel(self::msg('type')); 114 | $field->setAttribute('class', 'form-control selectpicker'); 115 | $select = $field->getSelect(); 116 | $select->setSize(1); 117 | $select->addOption('---', ''); 118 | $select->addOption(self::msg('hide_startarticle'), 'hide_startarticle'); 119 | $select->addOption(self::msg('hide_startarticle_non_admin'), 'hide_startarticle_non_admin'); 120 | $select->addOption(self::msg('hide_category_functions'), 'hide_cat_functions'); 121 | $select->addOption(self::msg('hide_category_functions_non_admin'), 'hide_cat_functions_non_admin'); 122 | $select->addOption(self::msg('hide_category_functions_all'), 'hide_cat_functions_all'); 123 | $select->addOption(self::msg('hide_category_functions_all_non_admin'), 'hide_cat_functions_all_non_admin'); 124 | $select->addOption(self::msg('hide_categories'), 'hide_categories'); 125 | $select->addOption(self::msg('hide_categories_non_admin'), 'hide_categories_non_admin'); 126 | $select->addOption(self::msg('split_category'), 'split_category'); 127 | 128 | $field = $form->addTextField('label'); 129 | $field->setLabel(self::msg('splitter_label')); 130 | 131 | $form->addRawField(' 132 | 138 | '); 139 | 140 | return $form->get(); 141 | } 142 | 143 | /** 144 | * @return string 145 | */ 146 | protected static function getFunc() 147 | { 148 | return \rex_request::request('func', 'string'); 149 | } 150 | 151 | /** 152 | * @return int 153 | */ 154 | protected static function getArticleId() 155 | { 156 | return \rex_request::request('article_id', 'int'); 157 | } 158 | 159 | /** 160 | * EP CALLBACK 161 | * @param array $p 162 | * @return string 163 | */ 164 | public static function getArticleName($p) 165 | { 166 | /** @var rex_list $list */ 167 | $list = $p["list"]; 168 | 169 | $article = rex_article::get($list->getValue("article_id")); 170 | 171 | if ($article instanceof rex_article) { 172 | $return = $article->getName(); 173 | } else { 174 | $return = self::msg('article_not_found'); 175 | } 176 | 177 | return $return; 178 | } 179 | 180 | /** 181 | * EP CALLBACK 182 | * @param array $p 183 | * @return string 184 | */ 185 | public static function getType($p) 186 | { 187 | /** @var rex_list $list */ 188 | $list = $p["list"]; 189 | $type = $list->getValue("type"); 190 | 191 | $text = [ 192 | '' => '---', 193 | 'hide_startarticle' => self::msg('hide_startarticle'), 194 | 'hide_startarticle_non_admin' => self::msg('hide_startarticle_non_admin'), 195 | 'hide_cat_functions' => self::msg('hide_category_functions'), 196 | 'hide_cat_functions_non_admin' => self::msg('hide_category_functions_non_admin'), 197 | 'hide_cat_functions_all' => self::msg('hide_category_functions_all'), 198 | 'hide_cat_functions_all_non_admin' => self::msg('hide_category_functions_all_non_admin'), 199 | 'hide_categories' => self::msg('hide_categories'), 200 | 'hide_categories_non_admin' => self::msg('hide_categories_non_admin'), 201 | 'split_category' => self::msg('split_category'), 202 | ]; 203 | 204 | return $text[$type]; 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /lib/move_metainfo.php: -------------------------------------------------------------------------------- 1 | isAvailable()) { 14 | // Remove meta info tab 15 | rex_addon::get('metainfo')->removeProperty('pages'); 16 | 17 | // Metainfo js 18 | if (rex_be_controller::getCurrentPagePart(1) == 'content') { 19 | rex_view::addJsFile(rex_url::addonAssets('metainfo', 'metainfo.js')); 20 | } 21 | 22 | // Redirect meta info into sidebar 23 | rex_extension::register('STRUCTURE_CONTENT_SIDEBAR', [__CLASS__, 'getMetaPage']); 24 | } 25 | } 26 | 27 | /** 28 | * EP CALLBACK 29 | * @param rex_extension_point $ep 30 | * @return string 31 | */ 32 | public static function getMetaPage(rex_extension_point $ep) 33 | { 34 | $params = $ep->getParams(); 35 | $subject = $ep->getSubject(); 36 | 37 | $panel = self::getStructure().self::getMetaInfo(); 38 | 39 | $fragment = new rex_fragment(); 40 | $fragment->setVar('title', ' '.self::msg('metadata'), false); 41 | $fragment->setVar('body', $panel, false); 42 | $fragment->setVar('article_id', $params['article_id'], false); 43 | $fragment->setVar('clang', $params['clang'], false); 44 | $fragment->setVar('ctype', $params['ctype'], false); 45 | $fragment->setVar('collapse', true); 46 | $fragment->setVar('collapsed', false); 47 | $content = $fragment->parse('core/page/section.php'); 48 | 49 | return $subject.$content; 50 | } 51 | 52 | /** 53 | * Substituted metadata panel 54 | * @see redaxo/src/addons/structure/plugins/content/boot.php 55 | * @return string 56 | */ 57 | protected static function getStructure() 58 | { 59 | $article_id = self::getArticleId(); 60 | $clang_id = self::getClangId(); 61 | $article = rex_article::get($article_id, $clang_id); 62 | $article_status = self::getArticleStatus($article_id, $clang_id); 63 | 64 | return ' 65 |
66 |
'.rex_i18n::msg('created_by').'
'.$article->getValue('createuser').'
67 |
'.rex_i18n::msg('created_on').'
'.rex_formatter::strftime($article->getValue('createdate'), 'date').'
68 |
'.rex_i18n::msg('updated_by').'
'.$article->getValue('updateuser').'
69 |
'.rex_i18n::msg('updated_on').'
'.rex_formatter::strftime($article->getValue('updatedate'), 'date').'
70 |
'.rex_i18n::msg('status').'
'.$article_status.'
71 |
72 | '; 73 | } 74 | 75 | /** 76 | * @return string 77 | */ 78 | protected static function getMetaInfo() 79 | { 80 | $return = ''; 81 | 82 | /** 83 | * @see redaxo/src/addons/structure/plugins/content/pages/content.php 84 | */ 85 | $article_id = self::getArticleId(); 86 | $clang = self::getClangId(); 87 | 88 | $article = rex_sql::factory(); 89 | $article->setQuery(' 90 | SELECT 91 | article.*, template.attributes as template_attributes 92 | FROM 93 | '.rex::getTablePrefix().'article as article 94 | LEFT JOIN '.rex::getTablePrefix()."template as template 95 | ON template.id=article.template_id 96 | WHERE 97 | article.id='$article_id' 98 | AND clang_id=$clang" 99 | ); 100 | 101 | if ($article->getRows() == 1) { 102 | // ----- ctype holen 103 | $template_attributes = $article->getArrayValue('template_attributes'); 104 | 105 | // Für Artikel ohne Template 106 | if (!is_array($template_attributes)) { 107 | $template_attributes = []; 108 | } 109 | 110 | $ctypes = isset($template_attributes['ctype']) ? $template_attributes['ctype'] : []; // ctypes - aus dem template 111 | 112 | $ctype = rex_request('ctype', 'int', 1); 113 | if (!array_key_exists($ctype, $ctypes)) { 114 | $ctype = 1; 115 | } // default = 1 116 | 117 | $context = new rex_context([ 118 | 'page' => rex_be_controller::getCurrentPage(), 119 | 'article_id' => $article_id, 120 | 'clang' => $clang, 121 | 'ctype' => $ctype, 122 | ]); 123 | 124 | /** 125 | * @see redaxo/src/addons/metainfo/pages/content.metainfo.php 126 | */ 127 | $metainfoHandler = new rex_metainfo_article_handler(); 128 | $form = $metainfoHandler->getForm([ 129 | 'id' => $article_id, 130 | 'clang' => $clang, 131 | 'article' => $article, 132 | ]); 133 | 134 | $formElements = []; 135 | $formElements[] = [ 136 | 'label' => '', 137 | 'field' => '', 138 | ]; 139 | $fragment = new rex_fragment(); 140 | $fragment->setVar('elements', $formElements, false); 141 | $form = $fragment->parse('core/form/form.php').$form; 142 | 143 | $return = ' 144 |
145 | '.(rex_post('savemeta', 'boolean') ? rex_view::success(rex_i18n::msg('minfo_metadata_saved')) : '').' 146 |
147 | '.self::msg('metainfo_fields').' 148 | 149 | 150 | '.$form.' 151 | 152 |
153 |
154 | '; 155 | } 156 | 157 | return $return; 158 | } 159 | 160 | /** 161 | * Make article status switchable 162 | * @see redaxo/src/addons/structure/pages/index.php 163 | * @param int $article_id 164 | * @param int $clang_id 165 | * @return string 166 | */ 167 | protected static function getArticleStatus($article_id, $clang_id) 168 | { 169 | $article = rex_article::get($article_id, $clang_id); 170 | $artstart = rex_request('artstart', 'int'); 171 | $catstart = rex_request('catstart', 'int'); 172 | 173 | $perm = rex::getUser()->getComplexPerm('structure')->hasCategoryPerm($article_id); 174 | 175 | $context = new rex_context([ 176 | 'page' => 'content/edit', 177 | 'category_id' => $article->getCategoryId(), 178 | 'article_id' => $article_id, 179 | 'clang' => $clang_id, 180 | ]); 181 | 182 | $article_status_types = rex_article_service::statusTypes(); 183 | $article_status = $article_status_types[$article->getValue('status')][0]; 184 | $article_class = $article_status_types[$article->getValue('status')][1]; 185 | $article_icon = $article_status_types[$article->getValue('status')][2]; 186 | 187 | if (version_compare(rex::getVersion(), '5.5.0', '<')) { 188 | if ($article->isStartArticle()) { 189 | $article_link = $context->getUrl([ 190 | 'rex-api-call' => 'category_status', 191 | 'catstart' => $catstart, 192 | 'category-id' => $article->getCategoryId(), 193 | ]); 194 | } else { 195 | $article_link = $context->getUrl([ 196 | 'rex-api-call' => 'article_status', 197 | 'artstart' => $artstart 198 | ]); 199 | } 200 | } else { 201 | if ($article->isStartArticle()) { 202 | $article_link = $context->getUrl([ 203 | 'catstart' => $catstart, 204 | 'category-id' => $article->getCategoryId(), 205 | ] + rex_api_category_status::getUrlParams()); 206 | } else { 207 | $article_link = $context->getUrl([ 208 | 'artstart' => $artstart 209 | ] + rex_api_article_status::getUrlParams()); 210 | } 211 | } 212 | 213 | if ($perm && rex::getUser()->hasPerm('publishArticle[]')) { 214 | $return = ' '.$article_status.''; 215 | } else { 216 | $return = ' '.$article_status.''; 217 | } 218 | 219 | return $return; 220 | } 221 | 222 | /** 223 | * @return int 224 | */ 225 | protected static function getArticleId() 226 | { 227 | $article_id = rex_request('article_id', 'int'); 228 | $article_id = rex_article::get($article_id) ? $article_id : 0; 229 | 230 | return $article_id; 231 | } 232 | 233 | /** 234 | * @return int 235 | */ 236 | protected static function getClangId() 237 | { 238 | $clang_id = rex_request('clang', 'int'); 239 | $clang_id = rex_clang::exists($clang_id) ? $clang_id : rex_clang::getStartId(); 240 | 241 | return $clang_id; 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /assets/script.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Friends Of Redaxo 3 | */ 4 | var structureTweaks = function() { 5 | /** 6 | * @type {Array} 7 | */ 8 | this.hiddenArticles = []; 9 | /** 10 | * @type {Array} 11 | */ 12 | this.hiddenCategories = []; 13 | /** 14 | * @type {Array} 15 | */ 16 | this.hiddenCategoryRows = []; 17 | /** 18 | * @type {Array} 19 | */ 20 | this.splitterCategories = []; 21 | 22 | /** 23 | * @see Addon quick_navigation 24 | * @param key 25 | * @returns {*} 26 | */ 27 | this.getUrlVars = function(key) { 28 | var vars = {}; 29 | var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { 30 | vars[key] = value; 31 | }); 32 | 33 | if (key !== undefined) { 34 | return vars[key]; 35 | } 36 | 37 | return vars; 38 | }; 39 | 40 | /** 41 | * @param articles 42 | * @returns {structureTweaks} 43 | */ 44 | this.setHiddenArticles = function(articles) { 45 | this.hiddenArticles = JSON.parse(articles); 46 | 47 | return this; 48 | }; 49 | 50 | /** 51 | * @param articles 52 | * @returns {structureTweaks} 53 | */ 54 | this.setHiddenCategories = function(articles) { 55 | this.hiddenCategories = JSON.parse(articles); 56 | 57 | return this; 58 | }; 59 | 60 | /** 61 | * @param articles 62 | * @returns {structureTweaks} 63 | */ 64 | this.setHiddenCategoryRows = function(articles) { 65 | this.hiddenCategoryRows = JSON.parse(articles); 66 | 67 | return this; 68 | }; 69 | 70 | /** 71 | * @param categories 72 | * @returns {structureTweaks} 73 | */ 74 | this.setSplitterCategories = function(categories) { 75 | this.splitterCategories = JSON.parse(categories); 76 | 77 | return this; 78 | }; 79 | 80 | /** 81 | * Hide articles 82 | * @returns {structureTweaks} 83 | */ 84 | this.hideArticles = function() { 85 | var categoryId = this.getUrlVars('category_id'); 86 | 87 | /*if (this.getUrlVars('page') == 'linkmap') { 88 | jQuery(".rex-icon-startarticle").parents("li").addClass("rex-startarticle"); 89 | } */ 90 | 91 | if (categoryId && this.hiddenArticles.indexOf(parseInt(categoryId)) > -1) { 92 | jQuery(".rex-startarticle").addClass("is-hidden"); 93 | } 94 | 95 | return this; 96 | }; 97 | 98 | /** 99 | * Hide category functions 100 | * @param deprecatedTraversing 101 | * @returns {structureTweaks} 102 | */ 103 | this.hideCategoryFunctions = function(deprecatedTraversing) { 104 | var searchStart; 105 | var searchEnd; 106 | var $categoryStatus; 107 | var $categoryDelete; 108 | var $categoryMeta; 109 | var $categoryActions; 110 | var textMetaStatus; 111 | var textStatus; 112 | 113 | var clangId = this.getUrlVars('clang'); 114 | if (clangId === undefined) { 115 | clangId = 1; 116 | } 117 | 118 | var articleId = this.getUrlVars('article_id'); 119 | if (articleId === undefined) { 120 | articleId = 0; 121 | } 122 | 123 | var categoryId = this.getUrlVars('category_id'); 124 | if (categoryId === undefined) { 125 | categoryId = 0; 126 | } 127 | 128 | var catStart = this.getUrlVars('catstart'); 129 | if (catStart === undefined) { 130 | catStart = 0; 131 | } 132 | 133 | for (var i = 0; i < this.hiddenCategories.length; i++) { 134 | searchStart = 'index.php?page=structure&category_id=' + categoryId + '&article_id=' + articleId + '&clang=' + clangId; 135 | searchEnd = '&catstart=' + catStart; 136 | 137 | // Page structure 138 | if (deprecatedTraversing) { 139 | $categoryStatus = $('a[href="' + searchStart + '&category-id=' + this.hiddenCategories[i] + '&rex-api-call=category_status' + searchEnd + '"]'); 140 | if ($categoryStatus.length) { 141 | $categoryStatus.parents('td').addClass('structure-tweaks-status').parents('tr').addClass('structure-tweaks-container'); 142 | } 143 | 144 | $categoryDelete = $('a[href="' + searchStart + '&category-id=' + this.hiddenCategories[i] + '&rex-api-call=category_delete' + searchEnd + '"]'); 145 | if ($categoryDelete.length) { 146 | $categoryDelete.parents('td').addClass('structure-tweaks-delete').parents('tr').addClass('structure-tweaks-container'); 147 | } 148 | 149 | $categoryMeta = $('a[href="' + searchStart + '&edit_id=' + this.hiddenCategories[i] + '&function=edit_cat' + searchEnd + '"]'); 150 | if ($categoryMeta.length) { 151 | $categoryMeta.parents('td').addClass('structure-tweaks-meta').parents('tr').addClass('structure-tweaks-container'); 152 | } 153 | } else { 154 | $categoryMeta = $('a[href="' + searchStart + '&edit_id=' + this.hiddenCategories[i] + '&function=edit_cat' + searchEnd + '"]'); 155 | if ($categoryMeta.length) { 156 | $categoryActions = $categoryMeta.parents('tr').addClass('structure-tweaks-container').find('.rex-table-action'); 157 | 158 | $categoryActions 159 | .first().addClass('structure-tweaks-meta') 160 | .next().addClass('structure-tweaks-delete') 161 | .next().addClass('structure-tweaks-status'); 162 | } 163 | } 164 | 165 | textStatus = $('.structure-tweaks-container .structure-tweaks-status a').html(); 166 | $('.structure-tweaks-container .structure-tweaks-status a').replaceWith('' + textStatus + ''); 167 | 168 | // Page content/edit 169 | if (articleId == this.hiddenCategories[i]) { 170 | textMetaStatus = $('.structure-tweaks-metainfos .structure-tweaks-status a').html(); 171 | $('.structure-tweaks-metainfos .structure-tweaks-status a').replaceWith('' + textMetaStatus + ''); 172 | } 173 | } 174 | 175 | return this; 176 | }; 177 | 178 | /** 179 | * Hide category functions 180 | * @param deprecatedTraversing 181 | * @returns {structureTweaks} 182 | */ 183 | this.hideCategoryFunctionsAll = function(deprecatedTraversing) { 184 | var searchStart; 185 | var searchEnd; 186 | var $categoryStatus; 187 | var $categoryDelete; 188 | var $categoryMeta; 189 | var $articleFunctions; 190 | var $categoryActions; 191 | var textMetaStatus; 192 | var textDelete; 193 | var textStatus; 194 | 195 | var clangId = this.getUrlVars('clang'); 196 | if (clangId === undefined) { 197 | clangId = 1; 198 | } 199 | 200 | var articleId = this.getUrlVars('article_id'); 201 | if (articleId === undefined) { 202 | articleId = 0; 203 | } 204 | 205 | var categoryId = this.getUrlVars('category_id'); 206 | if (categoryId === undefined) { 207 | categoryId = 0; 208 | } 209 | 210 | var catStart = this.getUrlVars('catstart'); 211 | if (catStart === undefined) { 212 | catStart = 0; 213 | } 214 | 215 | for (var i = 0; i < this.hiddenCategories.length; i++) { 216 | searchStart = 'index.php?page=structure&category_id=' + categoryId + '&article_id=' + articleId + '&clang=' + clangId; 217 | searchEnd = '&catstart=' + catStart; 218 | 219 | // Page structure 220 | if (deprecatedTraversing) { 221 | $categoryStatus = $('a[href="' + searchStart + '&category-id=' + this.hiddenCategories[i] + '&rex-api-call=category_status' + searchEnd + '"]'); 222 | if ($categoryStatus.length) { 223 | $categoryStatus.parents('td').addClass('structure-tweaks-status').parents('tr').addClass('structure-tweaks-container-all'); 224 | } 225 | 226 | $categoryDelete = $('a[href="' + searchStart + '&category-id=' + this.hiddenCategories[i] + '&rex-api-call=category_delete' + searchEnd + '"]'); 227 | if ($categoryDelete.length) { 228 | $categoryDelete.parents('td').addClass('structure-tweaks-delete').parents('tr').addClass('structure-tweaks-container-all'); 229 | } 230 | 231 | $categoryMeta = $('a[href="' + searchStart + '&edit_id=' + this.hiddenCategories[i] + '&function=edit_cat' + searchEnd + '"]'); 232 | if ($categoryMeta.length) { 233 | $categoryMeta.parents('td').addClass('structure-tweaks-meta').parents('tr').addClass('structure-tweaks-container-all'); 234 | } 235 | } else { 236 | $categoryMeta = $('a[href="' + searchStart + '&edit_id=' + this.hiddenCategories[i] + '&function=edit_cat' + searchEnd + '"]'); 237 | if ($categoryMeta.length) { 238 | $categoryActions = $categoryMeta.parents('tr').addClass('structure-tweaks-container-all').find('.rex-table-action'); 239 | 240 | $categoryActions 241 | .first().addClass('structure-tweaks-meta') 242 | .next().addClass('structure-tweaks-delete') 243 | .next().addClass('structure-tweaks-status'); 244 | } 245 | } 246 | 247 | textDelete = $('.structure-tweaks-container-all .structure-tweaks-delete a').html(); 248 | $('.structure-tweaks-container-all .structure-tweaks-delete a').replaceWith('' + textDelete + ''); 249 | textStatus = $('.structure-tweaks-container-all .structure-tweaks-status a').html(); 250 | $('.structure-tweaks-container-all .structure-tweaks-status a').replaceWith('' + textStatus + ''); 251 | 252 | // Page content/edit 253 | if (articleId == this.hiddenCategories[i]) { 254 | $articleFunctions = $('#rex-js-structure-content-nav').find('li'); 255 | $articleFunctions.last().addClass('structure-tweak-functions-all'); 256 | 257 | textMetaStatus = $('.structure-tweaks-metainfos .structure-tweaks-status a').html(); 258 | $('.structure-tweaks-metainfos .structure-tweaks-status a').replaceWith('' + textMetaStatus + ''); 259 | } 260 | } 261 | 262 | return this; 263 | }; 264 | 265 | /** 266 | * Hide categories 267 | * @returns {structureTweaks} 268 | */ 269 | this.hideCategories = function() { 270 | var that = this; 271 | jQuery(".rex-page-section").first().find(".rex-table-id").each(function() { 272 | var categoryId = $(this).html(); 273 | if (that.hiddenCategoryRows.indexOf(parseInt(categoryId)) >= 0) { 274 | $(this).parents('tr').addClass('structure-tweaks-category is-hidden'); 275 | } 276 | }); 277 | 278 | return this; 279 | }; 280 | 281 | /** 282 | * Hide categories 283 | * @returns {structureTweaks} 284 | */ 285 | this.hideCategoriesInLinkmap = function() { 286 | var that = this; 287 | jQuery(".rex-linkmap-list-group").first().find(".list-group-item a").each(function() { 288 | var regex = /.*category_id=(\d*)&clang=.*/; 289 | var categoryId = regex.exec($(this).attr('href')); 290 | if (categoryId[1] !== 'undefined' && that.hiddenCategoryRows.indexOf(categoryId[1]) >= 0) { 291 | $(this).parents('li').addClass('structure-tweaks-category is-hidden'); 292 | } 293 | }); 294 | 295 | return this; 296 | }; 297 | 298 | /** 299 | * Split categories 300 | * @returns {structureTweaks} 301 | */ 302 | this.splitCategories = function() { 303 | var clangId = this.getUrlVars('clang'); 304 | if (clangId === undefined) { 305 | clangId = 1; 306 | } 307 | var articleId = this.getUrlVars('article_id'); 308 | if (articleId === undefined) { 309 | articleId = 0; 310 | } 311 | 312 | for (var i = 0; i < this.splitterCategories.length; i++) { 313 | var search = 'index.php?page=structure&category_id=' + this.splitterCategories[i]['article_id'] + '&article_id=' + articleId + '&clang=' + clangId; 314 | var $categoryRow = $('a[href="' + search + '"]'); 315 | var label = this.splitterCategories[i]['label']; 316 | if (!label) { 317 | label = ' '; 318 | } 319 | 320 | // Insert splitter 321 | if ($categoryRow.length && !$categoryRow.parents('tr').hasClass('is-hidden')) { 322 | $categoryRow 323 | .parents('tr').before('' + label + '') 324 | .parents('.panel').addClass('structure-tweaks-splitted'); 325 | } 326 | } 327 | 328 | return this; 329 | }; 330 | 331 | /** 332 | * @returns {structureTweaks} 333 | */ 334 | this.pageCategories = function() { 335 | var value = jQuery('#rex-structure-tweaks-startartikel-type option:selected').val(); 336 | if (value === undefined) { 337 | value = ""; 338 | } 339 | 340 | if (value != 'split_category') { 341 | jQuery("#rex-structure-tweaks-startartikel-label").parents('dl').slideUp(100); 342 | } 343 | 344 | jQuery('#rex-structure-tweaks-startartikel-type').change(function() { 345 | var value = jQuery(this).find('option:selected').val(); 346 | 347 | if (value == 'split_category') { 348 | jQuery("#rex-structure-tweaks-startartikel-label").parents('dl').slideDown(100); 349 | } else { 350 | jQuery("#rex-structure-tweaks-startartikel-label").parents('dl').slideUp(100); 351 | } 352 | }); 353 | 354 | return this; 355 | }; 356 | }; 357 | --------------------------------------------------------------------------------