From 25c14b45de0c6907afc5d8e369da865f0981b45b Mon Sep 17 00:00:00 2001 From: Llewellyn van der Merwe Date: Sat, 16 Feb 2019 00:03:21 +0200 Subject: [PATCH] Added the new placeholder area for global & component level placeholders. Just like customcode you can now with the placeholders generate dynamic behaviour with placeholders all over the JCB custom areas. --- README.md | 17 +- admin/README.txt | 17 +- admin/access.xml | 43 +- admin/assets/css/component_placeholders.css | 13 + admin/assets/css/components_placeholders.css | 13 + admin/assets/css/placeholder.css | 13 + admin/assets/css/placeholders.css | 13 + admin/assets/images/icons/fieldtype_add.png | Bin 24499 -> 0 bytes admin/assets/images/icons/placeholders.png | Bin 0 -> 13515 bytes admin/controller.php | 2 + admin/controllers/component_placeholders.php | 321 +++++++ admin/controllers/components_placeholders.php | 43 + admin/controllers/placeholder.php | 321 +++++++ admin/controllers/placeholders.php | 106 +++ admin/helpers/compiler/a_Get.php | 71 +- admin/helpers/compiler/c_Fields.php | 10 +- admin/helpers/compiler/e_Interpretation.php | 28 +- admin/helpers/compiler/f_Infusion.php | 9 + admin/helpers/componentbuilder.php | 18 + .../en-GB/en-GB.com_componentbuilder.ini | 157 +++- .../en-GB/en-GB.com_componentbuilder.sys.ini | 47 +- .../component_placeholders/details_above.php | 31 + .../details_fullwidth.php | 31 + .../layouts/component_placeholders/index.html | 1 + .../component_placeholders/publishing.php | 32 + .../component_placeholders/publlshing.php | 34 + admin/layouts/placeholder/details_left.php | 29 + admin/layouts/placeholder/details_right.php | 29 + admin/layouts/placeholder/index.html | 1 + admin/layouts/placeholder/publishing.php | 32 + admin/layouts/placeholder/publlshing.php | 34 + .../server/linked_components_fullwidth.php | 5 + admin/models/component_placeholders.php | 864 +++++++++++++++++ admin/models/componentbuilder.php | 11 +- admin/models/components_placeholders.php | 237 +++++ admin/models/field.php | 10 + admin/models/forms/component_placeholders.js | 11 + admin/models/forms/component_placeholders.xml | 166 ++++ admin/models/forms/placeholder.js | 11 + admin/models/forms/placeholder.xml | 141 +++ admin/models/import_joomla_components.php | 12 +- admin/models/joomla_components.php | 6 +- admin/models/placeholder.php | 889 ++++++++++++++++++ admin/models/placeholders.php | 358 +++++++ admin/models/rules/uniqueplaceholder.php | 87 ++ admin/sql/install.mysql.utf8.sql | 52 + admin/sql/uninstall.mysql.utf8.sql | 2 + admin/sql/updates/mysql/2.9.11.sql | 25 + admin/sql/updates/mysql/2.9.12.sql | 25 + admin/tables/component_placeholders.php | 321 +++++++ admin/tables/placeholder.php | 321 +++++++ .../component_placeholders/submitbutton.js | 25 + .../component_placeholders/tmpl/edit.php | 107 +++ .../component_placeholders/tmpl/index.html | 1 + .../component_placeholders/view.html.php | 195 ++++ .../views/components_placeholders/index.html | 1 + .../components_placeholders/tmpl/default.php | 85 ++ .../tmpl/default_batch_body.php | 18 + .../tmpl/default_batch_footer.php | 23 + .../tmpl/default_body.php | 94 ++ .../tmpl/default_foot.php | 18 + .../tmpl/default_head.php | 47 + .../tmpl/default_toolbar.php | 45 + .../components_placeholders/tmpl/index.html | 1 + .../components_placeholders/view.html.php | 226 +++++ .../joomla_components/tmpl/default_body.php | 5 + admin/views/placeholder/submitbutton.js | 25 + admin/views/placeholder/tmpl/edit.php | 107 +++ admin/views/placeholder/tmpl/index.html | 1 + admin/views/placeholder/view.html.php | 208 ++++ admin/views/placeholders/index.html | 1 + admin/views/placeholders/tmpl/default.php | 85 ++ .../placeholders/tmpl/default_batch_body.php | 18 + .../tmpl/default_batch_footer.php | 23 + .../views/placeholders/tmpl/default_body.php | 97 ++ .../views/placeholders/tmpl/default_foot.php | 18 + .../views/placeholders/tmpl/default_head.php | 50 + .../placeholders/tmpl/default_toolbar.php | 45 + admin/views/placeholders/tmpl/index.html | 1 + admin/views/placeholders/view.html.php | 238 +++++ componentbuilder.xml | 7 +- componentbuilder_update_server.xml | 34 + script.php | 256 ++++- site/helpers/componentbuilder.php | 14 + 84 files changed, 7147 insertions(+), 42 deletions(-) create mode 100644 admin/assets/css/component_placeholders.css create mode 100644 admin/assets/css/components_placeholders.css create mode 100644 admin/assets/css/placeholder.css create mode 100644 admin/assets/css/placeholders.css delete mode 100644 admin/assets/images/icons/fieldtype_add.png create mode 100644 admin/assets/images/icons/placeholders.png create mode 100644 admin/controllers/component_placeholders.php create mode 100644 admin/controllers/components_placeholders.php create mode 100644 admin/controllers/placeholder.php create mode 100644 admin/controllers/placeholders.php create mode 100644 admin/layouts/component_placeholders/details_above.php create mode 100644 admin/layouts/component_placeholders/details_fullwidth.php create mode 100644 admin/layouts/component_placeholders/index.html create mode 100644 admin/layouts/component_placeholders/publishing.php create mode 100644 admin/layouts/component_placeholders/publlshing.php create mode 100644 admin/layouts/placeholder/details_left.php create mode 100644 admin/layouts/placeholder/details_right.php create mode 100644 admin/layouts/placeholder/index.html create mode 100644 admin/layouts/placeholder/publishing.php create mode 100644 admin/layouts/placeholder/publlshing.php create mode 100644 admin/models/component_placeholders.php create mode 100644 admin/models/components_placeholders.php create mode 100644 admin/models/forms/component_placeholders.js create mode 100644 admin/models/forms/component_placeholders.xml create mode 100644 admin/models/forms/placeholder.js create mode 100644 admin/models/forms/placeholder.xml create mode 100644 admin/models/placeholder.php create mode 100644 admin/models/placeholders.php create mode 100644 admin/models/rules/uniqueplaceholder.php create mode 100644 admin/sql/updates/mysql/2.9.11.sql create mode 100644 admin/sql/updates/mysql/2.9.12.sql create mode 100644 admin/tables/component_placeholders.php create mode 100644 admin/tables/placeholder.php create mode 100644 admin/views/component_placeholders/submitbutton.js create mode 100644 admin/views/component_placeholders/tmpl/edit.php create mode 100644 admin/views/component_placeholders/tmpl/index.html create mode 100644 admin/views/component_placeholders/view.html.php create mode 100644 admin/views/components_placeholders/index.html create mode 100644 admin/views/components_placeholders/tmpl/default.php create mode 100644 admin/views/components_placeholders/tmpl/default_batch_body.php create mode 100644 admin/views/components_placeholders/tmpl/default_batch_footer.php create mode 100644 admin/views/components_placeholders/tmpl/default_body.php create mode 100644 admin/views/components_placeholders/tmpl/default_foot.php create mode 100644 admin/views/components_placeholders/tmpl/default_head.php create mode 100644 admin/views/components_placeholders/tmpl/default_toolbar.php create mode 100644 admin/views/components_placeholders/tmpl/index.html create mode 100644 admin/views/components_placeholders/view.html.php create mode 100644 admin/views/placeholder/submitbutton.js create mode 100644 admin/views/placeholder/tmpl/edit.php create mode 100644 admin/views/placeholder/tmpl/index.html create mode 100644 admin/views/placeholder/view.html.php create mode 100644 admin/views/placeholders/index.html create mode 100644 admin/views/placeholders/tmpl/default.php create mode 100644 admin/views/placeholders/tmpl/default_batch_body.php create mode 100644 admin/views/placeholders/tmpl/default_batch_footer.php create mode 100644 admin/views/placeholders/tmpl/default_body.php create mode 100644 admin/views/placeholders/tmpl/default_foot.php create mode 100644 admin/views/placeholders/tmpl/default_head.php create mode 100644 admin/views/placeholders/tmpl/default_toolbar.php create mode 100644 admin/views/placeholders/tmpl/index.html create mode 100644 admin/views/placeholders/view.html.php diff --git a/README.md b/README.md index 3de97d706..c5be8b615 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ The Component Builder for [Joomla](https://extensions.joomla.org/extension/compo Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/component-builder/) developer, or have just started, Component Builder will safe you lots of time and money. A real must have! -You can install it quite easily and with no limitations. On [github](https://github.com/vdm-io/Joomla-Component-Builder/releases) is the latest release (2.9.11) with **ALL** its features and **ALL** concepts totally open-source and free! +You can install it quite easily and with no limitations. On [github](https://github.com/vdm-io/Joomla-Component-Builder/releases) is the latest release (2.9.13) with **ALL** its features and **ALL** concepts totally open-source and free! > Watch Quick Build of a Hello World component in [JCB on Youtube](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45) @@ -106,10 +106,11 @@ Where can you get support and help? + [German Basic Introduction](https://www.youtube.com/playlist?list=PLQRGFI8XZ_wu0tDFxJtZFwW7AxA4JHQV7) + [Hello World Tutorial](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45) + [The JCB! Wiki](https://github.com/vdm-io/Joomla-Component-Builder/wiki) -+ [JCB Google Group/forum](https://vdm.bz/jcb-forum) ++ [Google Group](https://vdm.bz/jcb-forum) + [Report a Security Issue](http://joomlacomponentbuilder.com/report-security-issues) + [Community Complaint](http://joomlacomponentbuilder.com/community-complaint) + [Open Issue On Github](https://github.com/vdm-io/Joomla-Component-Builder/issues) ^^ ++ [Telegram Group](https://t.me/jcb_group) + [JCB IRC Channel](https://vdm.bz/jcb-irc) Since [JCB](http://joomlacomponentbuilder.com) has [become a community](https://github.com/vdm-io/Joomla-Component-Builder/blob/staging/.github/SUPPORT.md) project [VDM.io](https://www.vdm.io/) is **no longer solely responsible** for support. @@ -145,14 +146,14 @@ TODO + *Author*: [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com) + *Name*: [Component Builder](https://github.com/vdm-io/Joomla-Component-Builder) + *First Build*: 30th April, 2015 -+ *Last Build*: 12th February, 2019 -+ *Version*: 2.9.11 ++ *Last Build*: 15th February, 2019 ++ *Version*: 2.9.13 + *Copyright*: Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + *License*: GNU General Public License version 2 or later; see LICENSE.txt -+ *Line count*: **195897** -+ *Field count*: **1089** -+ *File count*: **1277** -+ *Folder count*: **201** ++ *Line count*: **202937** ++ *Field count*: **1113** ++ *File count*: **1336** ++ *Folder count*: **209** > This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](http://joomlacomponentbuilder.com). > Developed by [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com) diff --git a/admin/README.txt b/admin/README.txt index 3de97d706..c5be8b615 100644 --- a/admin/README.txt +++ b/admin/README.txt @@ -12,7 +12,7 @@ The Component Builder for [Joomla](https://extensions.joomla.org/extension/compo Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/component-builder/) developer, or have just started, Component Builder will safe you lots of time and money. A real must have! -You can install it quite easily and with no limitations. On [github](https://github.com/vdm-io/Joomla-Component-Builder/releases) is the latest release (2.9.11) with **ALL** its features and **ALL** concepts totally open-source and free! +You can install it quite easily and with no limitations. On [github](https://github.com/vdm-io/Joomla-Component-Builder/releases) is the latest release (2.9.13) with **ALL** its features and **ALL** concepts totally open-source and free! > Watch Quick Build of a Hello World component in [JCB on Youtube](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45) @@ -106,10 +106,11 @@ Where can you get support and help? + [German Basic Introduction](https://www.youtube.com/playlist?list=PLQRGFI8XZ_wu0tDFxJtZFwW7AxA4JHQV7) + [Hello World Tutorial](https://www.youtube.com/watch?v=IQfsLYIeblk&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&index=45) + [The JCB! Wiki](https://github.com/vdm-io/Joomla-Component-Builder/wiki) -+ [JCB Google Group/forum](https://vdm.bz/jcb-forum) ++ [Google Group](https://vdm.bz/jcb-forum) + [Report a Security Issue](http://joomlacomponentbuilder.com/report-security-issues) + [Community Complaint](http://joomlacomponentbuilder.com/community-complaint) + [Open Issue On Github](https://github.com/vdm-io/Joomla-Component-Builder/issues) ^^ ++ [Telegram Group](https://t.me/jcb_group) + [JCB IRC Channel](https://vdm.bz/jcb-irc) Since [JCB](http://joomlacomponentbuilder.com) has [become a community](https://github.com/vdm-io/Joomla-Component-Builder/blob/staging/.github/SUPPORT.md) project [VDM.io](https://www.vdm.io/) is **no longer solely responsible** for support. @@ -145,14 +146,14 @@ TODO + *Author*: [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com) + *Name*: [Component Builder](https://github.com/vdm-io/Joomla-Component-Builder) + *First Build*: 30th April, 2015 -+ *Last Build*: 12th February, 2019 -+ *Version*: 2.9.11 ++ *Last Build*: 15th February, 2019 ++ *Version*: 2.9.13 + *Copyright*: Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + *License*: GNU General Public License version 2 or later; see LICENSE.txt -+ *Line count*: **195897** -+ *Field count*: **1089** -+ *File count*: **1277** -+ *Folder count*: **201** ++ *Line count*: **202937** ++ *Field count*: **1113** ++ *File count*: **1336** ++ *Folder count*: **209** > This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](http://joomlacomponentbuilder.com). > Developed by [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com) diff --git a/admin/access.xml b/admin/access.xml index 1dd2545b9..c78fd341a 100644 --- a/admin/access.xml +++ b/admin/access.xml @@ -146,6 +146,16 @@ + + + + + + + + + + @@ -221,7 +231,6 @@ - @@ -339,6 +348,18 @@ + + + + + + + + + + + + @@ -479,6 +500,15 @@ +
+ + + + + + + +
@@ -709,6 +739,17 @@
+
+ + + + + + + + + +
diff --git a/admin/assets/css/component_placeholders.css b/admin/assets/css/component_placeholders.css new file mode 100644 index 000000000..e7aab2271 --- /dev/null +++ b/admin/assets/css/component_placeholders.css @@ -0,0 +1,13 @@ +/** + * @package Joomla.Component.Builder + * + * @created 30th April, 2015 + * @author Llewellyn van der Merwe + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +/* CSS Document */ + + diff --git a/admin/assets/css/components_placeholders.css b/admin/assets/css/components_placeholders.css new file mode 100644 index 000000000..e7aab2271 --- /dev/null +++ b/admin/assets/css/components_placeholders.css @@ -0,0 +1,13 @@ +/** + * @package Joomla.Component.Builder + * + * @created 30th April, 2015 + * @author Llewellyn van der Merwe + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +/* CSS Document */ + + diff --git a/admin/assets/css/placeholder.css b/admin/assets/css/placeholder.css new file mode 100644 index 000000000..e7aab2271 --- /dev/null +++ b/admin/assets/css/placeholder.css @@ -0,0 +1,13 @@ +/** + * @package Joomla.Component.Builder + * + * @created 30th April, 2015 + * @author Llewellyn van der Merwe + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +/* CSS Document */ + + diff --git a/admin/assets/css/placeholders.css b/admin/assets/css/placeholders.css new file mode 100644 index 000000000..e7aab2271 --- /dev/null +++ b/admin/assets/css/placeholders.css @@ -0,0 +1,13 @@ +/** + * @package Joomla.Component.Builder + * + * @created 30th April, 2015 + * @author Llewellyn van der Merwe + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +/* CSS Document */ + + diff --git a/admin/assets/images/icons/fieldtype_add.png b/admin/assets/images/icons/fieldtype_add.png deleted file mode 100644 index 57e356980dc6f6cefc26862dc603b0388dcc2811..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24499 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 'layouts', 'dynamic_get' => 'dynamic_gets', 'custom_code' => 'custom_codes', + 'placeholder' => 'placeholders', 'library' => 'libraries', 'snippet' => 'snippets', 'validation_rule' => 'validation_rules', @@ -120,6 +121,7 @@ class ComponentbuilderController extends JControllerLegacy 'component_config' => 'components_config', 'component_dashboard' => 'components_dashboard', 'component_files_folders' => 'components_files_folders', + 'component_placeholders' => 'components_placeholders', 'snippet_type' => 'snippet_types', 'library_config' => 'libraries_config', 'library_files_folders_urls' => 'libraries_files_folders_urls' diff --git a/admin/controllers/component_placeholders.php b/admin/controllers/component_placeholders.php new file mode 100644 index 000000000..cb1f83dde --- /dev/null +++ b/admin/controllers/component_placeholders.php @@ -0,0 +1,321 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +/** + * Component_placeholders Controller + */ +class ComponentbuilderControllerComponent_placeholders extends JControllerForm +{ + /** + * Current or most recently performed task. + * + * @var string + * @since 12.2 + * @note Replaces _task. + */ + protected $task; + + /** + * Class constructor. + * + * @param array $config A named array of configuration variables. + * + * @since 1.6 + */ + public function __construct($config = array()) + { + $this->view_list = 'Components_placeholders'; // safeguard for setting the return view listing to the main view. + parent::__construct($config); + } + + /** + * Method override to check if you can add a new record. + * + * @param array $data An array of input data. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowAdd($data = array()) + { + // Get user object. + $user = JFactory::getUser(); + // Access check. + $access = $user->authorise('component_placeholders.access', 'com_componentbuilder'); + if (!$access) + { + return false; + } + + // In the absense of better information, revert to the component permissions. + return $user->authorise('component_placeholders.create', $this->option); + } + + /** + * Method override to check if you can edit an existing record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowEdit($data = array(), $key = 'id') + { + // get user object. + $user = JFactory::getUser(); + // get record id. + $recordId = (int) isset($data[$key]) ? $data[$key] : 0; + + + // Access check. + $access = ($user->authorise('component_placeholders.access', 'com_componentbuilder.component_placeholders.' . (int) $recordId) && $user->authorise('component_placeholders.access', 'com_componentbuilder')); + if (!$access) + { + return false; + } + + if ($recordId) + { + // The record has been set. Check the record permissions. + $permission = $user->authorise('component_placeholders.edit', 'com_componentbuilder.component_placeholders.' . (int) $recordId); + if (!$permission) + { + if ($user->authorise('component_placeholders.edit.own', 'com_componentbuilder.component_placeholders.' . $recordId)) + { + // Now test the owner is the user. + $ownerId = (int) isset($data['created_by']) ? $data['created_by'] : 0; + if (empty($ownerId)) + { + // Need to do a lookup from the model. + $record = $this->getModel()->getItem($recordId); + + if (empty($record)) + { + return false; + } + $ownerId = $record->created_by; + } + + // If the owner matches 'me' then allow. + if ($ownerId == $user->id) + { + if ($user->authorise('component_placeholders.edit.own', 'com_componentbuilder')) + { + return true; + } + } + } + return false; + } + } + // Since there is no permission, revert to the component permissions. + return $user->authorise('component_placeholders.edit', $this->option); + } + + /** + * Gets the URL arguments to append to an item redirect. + * + * @param integer $recordId The primary key id for the item. + * @param string $urlVar The name of the URL variable for the id. + * + * @return string The arguments to append to the redirect URL. + * + * @since 1.6 + */ + protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') + { + // get the referral options (old method use return instead see parent) + $ref = $this->input->get('ref', 0, 'string'); + $refid = $this->input->get('refid', 0, 'int'); + + // get redirect info. + $append = parent::getRedirectToItemAppend($recordId, $urlVar); + + // set the referral options + if ($refid && $ref) + { + $append = '&ref=' . (string)$ref . '&refid='. (int)$refid . $append; + } + elseif ($ref) + { + $append = '&ref='. (string)$ref . $append; + } + + return $append; + } + + /** + * Method to run batch operations. + * + * @param object $model The model. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 2.5 + */ + public function batch($model = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Set the model + $model = $this->getModel('Component_placeholders', '', array()); + + // Preset the redirect + $this->setRedirect(JRoute::_('index.php?option=com_componentbuilder&view=components_placeholders' . $this->getRedirectToListAppend(), false)); + + return parent::batch($model); + } + + /** + * Method to cancel an edit. + * + * @param string $key The name of the primary key of the URL variable. + * + * @return boolean True if access level checks pass, false otherwise. + * + * @since 12.2 + */ + public function cancel($key = null) + { + // get the referral options + $this->ref = $this->input->get('ref', 0, 'word'); + $this->refid = $this->input->get('refid', 0, 'int'); + + // Check if there is a return value + $return = $this->input->get('return', null, 'base64'); + + $cancel = parent::cancel($key); + + if (!is_null($return) && JUri::isInternal(base64_decode($return))) + { + $redirect = base64_decode($return); + + // Redirect to the return value. + $this->setRedirect( + JRoute::_( + $redirect, false + ) + ); + } + elseif ($this->refid && $this->ref) + { + $redirect = '&view=' . (string)$this->ref . '&layout=edit&id=' . (int)$this->refid; + + // Redirect to the item screen. + $this->setRedirect( + JRoute::_( + 'index.php?option=' . $this->option . $redirect, false + ) + ); + } + elseif ($this->ref) + { + $redirect = '&view='.(string)$this->ref; + + // Redirect to the list screen. + $this->setRedirect( + JRoute::_( + 'index.php?option=' . $this->option . $redirect, false + ) + ); + } + return $cancel; + } + + /** + * Method to save a record. + * + * @param string $key The name of the primary key of the URL variable. + * @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions). + * + * @return boolean True if successful, false otherwise. + * + * @since 12.2 + */ + public function save($key = null, $urlVar = null) + { + // get the referral options + $this->ref = $this->input->get('ref', 0, 'word'); + $this->refid = $this->input->get('refid', 0, 'int'); + + // Check if there is a return value + $return = $this->input->get('return', null, 'base64'); + $canReturn = (!is_null($return) && JUri::isInternal(base64_decode($return))); + + if ($this->ref || $this->refid || $canReturn) + { + // to make sure the item is checkedin on redirect + $this->task = 'save'; + } + + $saved = parent::save($key, $urlVar); + + // This is not needed since parent save already does this + // Due to the ref and refid implementation we need to add this + if ($canReturn) + { + $redirect = base64_decode($return); + + // Redirect to the return value. + $this->setRedirect( + JRoute::_( + $redirect, false + ) + ); + } + elseif ($this->refid && $this->ref) + { + $redirect = '&view=' . (string)$this->ref . '&layout=edit&id=' . (int)$this->refid; + + // Redirect to the item screen. + $this->setRedirect( + JRoute::_( + 'index.php?option=' . $this->option . $redirect, false + ) + ); + } + elseif ($this->ref) + { + $redirect = '&view=' . (string)$this->ref; + + // Redirect to the list screen. + $this->setRedirect( + JRoute::_( + 'index.php?option=' . $this->option . $redirect, false + ) + ); + } + return $saved; + } + + /** + * Function that allows child controller access to model data + * after the data has been saved. + * + * @param JModel &$model The data model object. + * @param array $validData The validated data. + * + * @return void + * + * @since 11.1 + */ + protected function postSaveHook(JModelLegacy $model, $validData = array()) + { + return; + } + +} diff --git a/admin/controllers/components_placeholders.php b/admin/controllers/components_placeholders.php new file mode 100644 index 000000000..2a2112f59 --- /dev/null +++ b/admin/controllers/components_placeholders.php @@ -0,0 +1,43 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +/** + * Components_placeholders Controller + */ +class ComponentbuilderControllerComponents_placeholders extends JControllerAdmin +{ + /** + * The prefix to use with controller messages. + * + * @var string + * @since 1.6 + */ + protected $text_prefix = 'COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS'; + + /** + * Method to get a model object, loading it if required. + * + * @param string $name The model name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return JModelLegacy The model. + * + * @since 1.6 + */ + public function getModel($name = 'Component_placeholders', $prefix = 'ComponentbuilderModel', $config = array('ignore_request' => true)) + { + return parent::getModel($name, $prefix, $config); + } +} diff --git a/admin/controllers/placeholder.php b/admin/controllers/placeholder.php new file mode 100644 index 000000000..f641889a4 --- /dev/null +++ b/admin/controllers/placeholder.php @@ -0,0 +1,321 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +/** + * Placeholder Controller + */ +class ComponentbuilderControllerPlaceholder extends JControllerForm +{ + /** + * Current or most recently performed task. + * + * @var string + * @since 12.2 + * @note Replaces _task. + */ + protected $task; + + /** + * Class constructor. + * + * @param array $config A named array of configuration variables. + * + * @since 1.6 + */ + public function __construct($config = array()) + { + $this->view_list = 'Placeholders'; // safeguard for setting the return view listing to the main view. + parent::__construct($config); + } + + /** + * Method override to check if you can add a new record. + * + * @param array $data An array of input data. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowAdd($data = array()) + { + // Get user object. + $user = JFactory::getUser(); + // Access check. + $access = $user->authorise('placeholder.access', 'com_componentbuilder'); + if (!$access) + { + return false; + } + + // In the absense of better information, revert to the component permissions. + return $user->authorise('placeholder.create', $this->option); + } + + /** + * Method override to check if you can edit an existing record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * + * @since 1.6 + */ + protected function allowEdit($data = array(), $key = 'id') + { + // get user object. + $user = JFactory::getUser(); + // get record id. + $recordId = (int) isset($data[$key]) ? $data[$key] : 0; + + + // Access check. + $access = ($user->authorise('placeholder.access', 'com_componentbuilder.placeholder.' . (int) $recordId) && $user->authorise('placeholder.access', 'com_componentbuilder')); + if (!$access) + { + return false; + } + + if ($recordId) + { + // The record has been set. Check the record permissions. + $permission = $user->authorise('placeholder.edit', 'com_componentbuilder.placeholder.' . (int) $recordId); + if (!$permission) + { + if ($user->authorise('placeholder.edit.own', 'com_componentbuilder.placeholder.' . $recordId)) + { + // Now test the owner is the user. + $ownerId = (int) isset($data['created_by']) ? $data['created_by'] : 0; + if (empty($ownerId)) + { + // Need to do a lookup from the model. + $record = $this->getModel()->getItem($recordId); + + if (empty($record)) + { + return false; + } + $ownerId = $record->created_by; + } + + // If the owner matches 'me' then allow. + if ($ownerId == $user->id) + { + if ($user->authorise('placeholder.edit.own', 'com_componentbuilder')) + { + return true; + } + } + } + return false; + } + } + // Since there is no permission, revert to the component permissions. + return $user->authorise('placeholder.edit', $this->option); + } + + /** + * Gets the URL arguments to append to an item redirect. + * + * @param integer $recordId The primary key id for the item. + * @param string $urlVar The name of the URL variable for the id. + * + * @return string The arguments to append to the redirect URL. + * + * @since 1.6 + */ + protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id') + { + // get the referral options (old method use return instead see parent) + $ref = $this->input->get('ref', 0, 'string'); + $refid = $this->input->get('refid', 0, 'int'); + + // get redirect info. + $append = parent::getRedirectToItemAppend($recordId, $urlVar); + + // set the referral options + if ($refid && $ref) + { + $append = '&ref=' . (string)$ref . '&refid='. (int)$refid . $append; + } + elseif ($ref) + { + $append = '&ref='. (string)$ref . $append; + } + + return $append; + } + + /** + * Method to run batch operations. + * + * @param object $model The model. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 2.5 + */ + public function batch($model = null) + { + JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN')); + + // Set the model + $model = $this->getModel('Placeholder', '', array()); + + // Preset the redirect + $this->setRedirect(JRoute::_('index.php?option=com_componentbuilder&view=placeholders' . $this->getRedirectToListAppend(), false)); + + return parent::batch($model); + } + + /** + * Method to cancel an edit. + * + * @param string $key The name of the primary key of the URL variable. + * + * @return boolean True if access level checks pass, false otherwise. + * + * @since 12.2 + */ + public function cancel($key = null) + { + // get the referral options + $this->ref = $this->input->get('ref', 0, 'word'); + $this->refid = $this->input->get('refid', 0, 'int'); + + // Check if there is a return value + $return = $this->input->get('return', null, 'base64'); + + $cancel = parent::cancel($key); + + if (!is_null($return) && JUri::isInternal(base64_decode($return))) + { + $redirect = base64_decode($return); + + // Redirect to the return value. + $this->setRedirect( + JRoute::_( + $redirect, false + ) + ); + } + elseif ($this->refid && $this->ref) + { + $redirect = '&view=' . (string)$this->ref . '&layout=edit&id=' . (int)$this->refid; + + // Redirect to the item screen. + $this->setRedirect( + JRoute::_( + 'index.php?option=' . $this->option . $redirect, false + ) + ); + } + elseif ($this->ref) + { + $redirect = '&view='.(string)$this->ref; + + // Redirect to the list screen. + $this->setRedirect( + JRoute::_( + 'index.php?option=' . $this->option . $redirect, false + ) + ); + } + return $cancel; + } + + /** + * Method to save a record. + * + * @param string $key The name of the primary key of the URL variable. + * @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions). + * + * @return boolean True if successful, false otherwise. + * + * @since 12.2 + */ + public function save($key = null, $urlVar = null) + { + // get the referral options + $this->ref = $this->input->get('ref', 0, 'word'); + $this->refid = $this->input->get('refid', 0, 'int'); + + // Check if there is a return value + $return = $this->input->get('return', null, 'base64'); + $canReturn = (!is_null($return) && JUri::isInternal(base64_decode($return))); + + if ($this->ref || $this->refid || $canReturn) + { + // to make sure the item is checkedin on redirect + $this->task = 'save'; + } + + $saved = parent::save($key, $urlVar); + + // This is not needed since parent save already does this + // Due to the ref and refid implementation we need to add this + if ($canReturn) + { + $redirect = base64_decode($return); + + // Redirect to the return value. + $this->setRedirect( + JRoute::_( + $redirect, false + ) + ); + } + elseif ($this->refid && $this->ref) + { + $redirect = '&view=' . (string)$this->ref . '&layout=edit&id=' . (int)$this->refid; + + // Redirect to the item screen. + $this->setRedirect( + JRoute::_( + 'index.php?option=' . $this->option . $redirect, false + ) + ); + } + elseif ($this->ref) + { + $redirect = '&view=' . (string)$this->ref; + + // Redirect to the list screen. + $this->setRedirect( + JRoute::_( + 'index.php?option=' . $this->option . $redirect, false + ) + ); + } + return $saved; + } + + /** + * Function that allows child controller access to model data + * after the data has been saved. + * + * @param JModel &$model The data model object. + * @param array $validData The validated data. + * + * @return void + * + * @since 11.1 + */ + protected function postSaveHook(JModelLegacy $model, $validData = array()) + { + return; + } + +} diff --git a/admin/controllers/placeholders.php b/admin/controllers/placeholders.php new file mode 100644 index 000000000..3492372b8 --- /dev/null +++ b/admin/controllers/placeholders.php @@ -0,0 +1,106 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +/** + * Placeholders Controller + */ +class ComponentbuilderControllerPlaceholders extends JControllerAdmin +{ + /** + * The prefix to use with controller messages. + * + * @var string + * @since 1.6 + */ + protected $text_prefix = 'COM_COMPONENTBUILDER_PLACEHOLDERS'; + + /** + * Method to get a model object, loading it if required. + * + * @param string $name The model name. Optional. + * @param string $prefix The class prefix. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return JModelLegacy The model. + * + * @since 1.6 + */ + public function getModel($name = 'Placeholder', $prefix = 'ComponentbuilderModel', $config = array('ignore_request' => true)) + { + return parent::getModel($name, $prefix, $config); + } + + public function exportData() + { + // Check for request forgeries + JSession::checkToken() or die(JText::_('JINVALID_TOKEN')); + // check if export is allowed for this user. + $user = JFactory::getUser(); + if ($user->authorise('placeholder.export', 'com_componentbuilder') && $user->authorise('core.export', 'com_componentbuilder')) + { + // Get the input + $input = JFactory::getApplication()->input; + $pks = $input->post->get('cid', array(), 'array'); + // Sanitize the input + JArrayHelper::toInteger($pks); + // Get the model + $model = $this->getModel('Placeholders'); + // get the data to export + $data = $model->getExportData($pks); + if (ComponentbuilderHelper::checkArray($data)) + { + // now set the data to the spreadsheet + $date = JFactory::getDate(); + ComponentbuilderHelper::xls($data,'Placeholders_'.$date->format('jS_F_Y'),'Placeholders exported ('.$date->format('jS F, Y').')','placeholders'); + } + } + // Redirect to the list screen with error. + $message = JText::_('COM_COMPONENTBUILDER_EXPORT_FAILED'); + $this->setRedirect(JRoute::_('index.php?option=com_componentbuilder&view=placeholders', false), $message, 'error'); + return; + } + + + public function importData() + { + // Check for request forgeries + JSession::checkToken() or die(JText::_('JINVALID_TOKEN')); + // check if import is allowed for this user. + $user = JFactory::getUser(); + if ($user->authorise('placeholder.import', 'com_componentbuilder') && $user->authorise('core.import', 'com_componentbuilder')) + { + // Get the import model + $model = $this->getModel('Placeholders'); + // get the headers to import + $headers = $model->getExImPortHeaders(); + if (ComponentbuilderHelper::checkObject($headers)) + { + // Load headers to session. + $session = JFactory::getSession(); + $headers = json_encode($headers); + $session->set('placeholder_VDM_IMPORTHEADERS', $headers); + $session->set('backto_VDM_IMPORT', 'placeholders'); + $session->set('dataType_VDM_IMPORTINTO', 'placeholder'); + // Redirect to import view. + $message = JText::_('COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_PLACEHOLDERS'); + $this->setRedirect(JRoute::_('index.php?option=com_componentbuilder&view=import', false), $message); + return; + } + } + // Redirect to the list screen with error. + $message = JText::_('COM_COMPONENTBUILDER_IMPORT_FAILED'); + $this->setRedirect(JRoute::_('index.php?option=com_componentbuilder&view=placeholders', false), $message, 'error'); + return; + } +} diff --git a/admin/helpers/compiler/a_Get.php b/admin/helpers/compiler/a_Get.php index 43ef444b7..c48ea2cf1 100644 --- a/admin/helpers/compiler/a_Get.php +++ b/admin/helpers/compiler/a_Get.php @@ -53,6 +53,13 @@ class Get */ public $params; + /** + * The global placeholders + * + * @var array + */ + public $globalPlaceholders = array(); + /** * The placeholders * @@ -781,6 +788,8 @@ class Get $this->user = JFactory::getUser(); // Get a db connection. $this->db = JFactory::getDbo(); + // get global placeholders + $this->globalPlaceholders = $this->getGlobalPlaceholders(); // check if this component is install on the current website if ($paths = $this->getLocalInstallPaths()) { @@ -857,6 +866,36 @@ class Get return ''; } + /** + * get all System Placeholders + * + * @return array The global placeholders + * + */ + public function getGlobalPlaceholders() + { + // reset bucket + $bucket = array(); + // Create a new query object. + $query = $this->db->getQuery(true); + $query->select($this->db->quoteName(array('a.target','a.value'))); + // from these tables + $query->from('#__componentbuilder_placeholder AS a'); + // Reset the query using our newly populated query object. + $this->db->setQuery($query); + // Load the items + $this->db->execute(); + if ($this->db->getNumRows()) + { + $bucket = $this->db->loadAssocList('target', 'value'); + foreach ($bucket as $key => &$code) + { + $code = base64_decode($code); + } + } + return $bucket; + } + /** * get all Component Data * @@ -888,7 +927,8 @@ class Get 'i.php_dashboard_methods', 'f.sql_tweak', 'e.version_update', - 'e.id' + 'e.id', + 'k.addplaceholders' ), array( 'addadmin_views', 'addadmin_views_id', @@ -904,7 +944,8 @@ class Get 'php_dashboard_methods', 'sql_tweak', 'version_update', - 'version_update_id' + 'version_update_id', + '_placeholders' ) ) ); @@ -919,6 +960,7 @@ class Get $query->join('LEFT', $this->db->quoteName('#__componentbuilder_component_config', 'h') . ' ON (' . $this->db->quoteName('a.id') . ' = ' . $this->db->quoteName('h.joomla_component') . ')'); $query->join('LEFT', $this->db->quoteName('#__componentbuilder_component_dashboard', 'i') . ' ON (' . $this->db->quoteName('a.id') . ' = ' . $this->db->quoteName('i.joomla_component') . ')'); $query->join('LEFT', $this->db->quoteName('#__componentbuilder_component_files_folders', 'j') . ' ON (' . $this->db->quoteName('a.id') . ' = ' . $this->db->quoteName('j.joomla_component') . ')'); + $query->join('LEFT', $this->db->quoteName('#__componentbuilder_component_placeholders', 'k') . ' ON (' . $this->db->quoteName('a.id') . ' = ' . $this->db->quoteName('k.joomla_component') . ')'); $query->where($this->db->quoteName('a.id') . ' = ' . (int) $this->componentID); // Reset the query using our newly populated query object. @@ -971,6 +1013,26 @@ class Get $this->placeholders[$this->bbb . 'Component' . $this->ddd] = $this->placeholders[$this->hhh . 'Component' . $this->hhh]; $this->placeholders[$this->bbb . 'COMPONENT' . $this->ddd] = $this->placeholders[$this->hhh . 'COMPONENT' . $this->hhh]; + // set the addcustommenus data + $component->_placeholders = (isset($component->_placeholders) && ComponentbuilderHelper::checkJson($component->_placeholders)) ? json_decode($component->_placeholders, true) : null; + if (ComponentbuilderHelper::checkArray($component->_placeholders)) + { + foreach($component->_placeholders as $row) + { + $this->globalPlaceholders[$row['target']] = $row['value']; + } + } + unset($component->_placeholders); + + // load the global placeholders + if (ComponentbuilderHelper::checkArray($this->globalPlaceholders)) + { + foreach ($this->globalPlaceholders as $globalPlaceholder => $gloabalValue) + { + $this->placeholders[$globalPlaceholder] = $gloabalValue; + } + } + // set component sales name $component->sales_name = ComponentbuilderHelper::safeString($component->system_name); @@ -2810,7 +2872,7 @@ class Get if (strpos($requeSt_id, '_request_id') !== false || strpos($requeSt_id, '_request_catid') !== false) { // keep it then, don't change - $name = $requeSt_id; + $name = $this->setPlaceholders($requeSt_id, $this->placeholders); } else { @@ -2846,7 +2908,7 @@ class Get else { // get value from xml - $xml = ComponentbuilderHelper::safeString(ComponentbuilderHelper::getBetween($field['settings']->xml, 'name="', '"')); + $xml = ComponentbuilderHelper::safeString($this->setPlaceholders(ComponentbuilderHelper::getBetween($field['settings']->xml, 'name="', '"'), $this->placeholders)); // check if a value was found if (ComponentbuilderHelper::checkString($xml)) { @@ -5662,6 +5724,7 @@ class Get $placeholders[ComponentbuilderHelper::safeString($this->componentCodeName, 'F') . 'Helper::'] = $this->bbb . 'Component' . $this->ddd . 'Helper::'; $placeholders['COM_' . ComponentbuilderHelper::safeString($this->componentCodeName, 'U')] = 'COM_' . $this->bbb . 'COMPONENT' . $this->ddd; $placeholders['com_' . $this->componentCodeName] = 'com_' . $this->bbb . 'component' . $this->ddd; + foreach ($paths as $target => $path) { // we are changing the working directory to the componet path diff --git a/admin/helpers/compiler/c_Fields.php b/admin/helpers/compiler/c_Fields.php index 34f689c2d..9e0f836a2 100644 --- a/admin/helpers/compiler/c_Fields.php +++ b/admin/helpers/compiler/c_Fields.php @@ -2295,7 +2295,7 @@ class Fields extends Structure else { // set the rest of the fields - $xmlValue = (string) ComponentbuilderHelper::getBetween($field['settings']->xml, $property['name'] . '="', '"'); + $xmlValue = (string) $this->setPlaceholders(ComponentbuilderHelper::getBetween($field['settings']->xml, $property['name'] . '="', '"'), $placeholders); } // check if translatable @@ -2872,6 +2872,14 @@ class Fields extends Structure // now set the value $replace[$replacekey] = $replacevalue; } + // load the global placeholders + if (ComponentbuilderHelper::checkArray($this->globalPlaceholders)) + { + foreach ($this->globalPlaceholders as $globalPlaceholder => $gloabalValue) + { + $replace[$globalPlaceholder] = $gloabalValue; + } + } // start loading the field type $this->fileContentDynamic['customfield_' . $data['type']] = array(); // Type <<>> diff --git a/admin/helpers/compiler/e_Interpretation.php b/admin/helpers/compiler/e_Interpretation.php index 9ec391f36..6ae77e63b 100644 --- a/admin/helpers/compiler/e_Interpretation.php +++ b/admin/helpers/compiler/e_Interpretation.php @@ -13645,10 +13645,26 @@ class Interpretation extends Fields $component = ComponentbuilderHelper::safeString($this->componentData->name_code); $viewName = 'config'; $listViewName = 'configs'; - $placeholders = array( - $this->hhh . 'component' . $this->hhh => $component, - $this->hhh . 'view' . $this->hhh => $viewName, - $this->hhh . 'views' . $this->hhh => $listViewName); + // set place holders + $placeholders = array(); + $placeholders[$this->hhh . 'component' . $this->hhh] = ComponentbuilderHelper::safeString($this->componentData->name_code); + $placeholders[$this->hhh . 'Component' . $this->hhh] = ComponentbuilderHelper::safeString($this->componentData->name_code, 'F'); + $placeholders[$this->hhh . 'COMPONENT' . $this->hhh] = ComponentbuilderHelper::safeString($this->componentData->name_code, 'U'); + $placeholders[$this->hhh . 'view' . $this->hhh] = $viewName; + $placeholders[$this->hhh . 'views' . $this->hhh] = $listViewName; + $placeholders[$this->bbb . 'component' . $this->ddd] = $placeholders[$this->hhh . 'component' . $this->hhh]; + $placeholders[$this->bbb . 'Component' . $this->ddd] = $placeholders[$this->hhh . 'Component' . $this->hhh]; + $placeholders[$this->bbb . 'COMPONENT' . $this->ddd] = $placeholders[$this->hhh . 'COMPONENT' . $this->hhh]; + $placeholders[$this->bbb . 'view' . $this->ddd] = $viewName; + $placeholders[$this->bbb . 'views' . $this->ddd] = $listViewName; + // load the global placeholders + if (ComponentbuilderHelper::checkArray($this->globalPlaceholders)) + { + foreach ($this->globalPlaceholders as $globalPlaceholder => $gloabalValue) + { + $placeholders[$globalPlaceholder] = $gloabalValue; + } + } $view = ''; $viewType = 0; // set the custom table key @@ -13676,8 +13692,8 @@ class Interpretation extends Fields { $this->configFieldSetsCustomField[$field['tabname']][] = $xmlField; // set global params to db on install - $fieldName = ComponentbuilderHelper::safeString(ComponentbuilderHelper::getBetween($xmlField, 'name="', '"')); - $fieldDefault = ComponentbuilderHelper::getBetween($xmlField, 'default="', '"'); + $fieldName = ComponentbuilderHelper::safeString($this->setPlaceholders(ComponentbuilderHelper::getBetween($xmlField, 'name="', '"'), $placeholders)); + $fieldDefault = $this->setPlaceholders(ComponentbuilderHelper::getBetween($xmlField, 'default="', '"'), $placeholders); if (isset($field['custom_value']) && ComponentbuilderHelper::checkString($field['custom_value'])) { // add array if found diff --git a/admin/helpers/compiler/f_Infusion.php b/admin/helpers/compiler/f_Infusion.php index e5a1d0663..61062975d 100644 --- a/admin/helpers/compiler/f_Infusion.php +++ b/admin/helpers/compiler/f_Infusion.php @@ -213,6 +213,15 @@ class Infusion extends Interpretation // add the helper emailer if set $this->fileContentStatic[$this->hhh . 'HELPER_EMAIL' . $this->hhh] = $this->addEmailHelper(); + // load the global placeholders + if (ComponentbuilderHelper::checkArray($this->globalPlaceholders)) + { + foreach ($this->globalPlaceholders as $globalPlaceholder => $gloabalValue) + { + $this->fileContentStatic[$globalPlaceholder] = $gloabalValue; + } + } + // reset view array $viewarray = array(); $site_edit_view_array = array(); diff --git a/admin/helpers/componentbuilder.php b/admin/helpers/componentbuilder.php index 35d3dbfbb..12ff6336c 100644 --- a/admin/helpers/componentbuilder.php +++ b/admin/helpers/componentbuilder.php @@ -1179,6 +1179,20 @@ abstract class ComponentbuilderHelper return false; } + /** + * validate that a placeholder is unique + **/ + public static function validateUniquePlaceholder($string) + { + $string = self::safeString($string); + // this list may grow as we find more cases that break the compiler (just open an issue on github) + if (in_array($string, array('component', 'view', 'views'))) + { + return false; + } + return true; + } + /** * The array of dynamic content * @@ -4476,6 +4490,10 @@ abstract class ComponentbuilderHelper { JHtmlSidebar::addEntry(JText::_('COM_COMPONENTBUILDER_SUBMENU_CUSTOM_CODES'), 'index.php?option=com_componentbuilder&view=custom_codes', $submenu === 'custom_codes'); } + if ($user->authorise('placeholder.access', 'com_componentbuilder') && $user->authorise('placeholder.submenu', 'com_componentbuilder')) + { + JHtmlSidebar::addEntry(JText::_('COM_COMPONENTBUILDER_SUBMENU_PLACEHOLDERS'), 'index.php?option=com_componentbuilder&view=placeholders', $submenu === 'placeholders'); + } if ($user->authorise('library.access', 'com_componentbuilder') && $user->authorise('library.submenu', 'com_componentbuilder')) { JHtmlSidebar::addEntry(JText::_('COM_COMPONENTBUILDER_SUBMENU_LIBRARIES'), 'index.php?option=com_componentbuilder&view=libraries', $submenu === 'libraries'); diff --git a/admin/language/en-GB/en-GB.com_componentbuilder.ini b/admin/language/en-GB/en-GB.com_componentbuilder.ini index 8a5c5cd38..6dbf5bc61 100644 --- a/admin/language/en-GB/en-GB.com_componentbuilder.ini +++ b/admin/language/en-GB/en-GB.com_componentbuilder.ini @@ -1723,6 +1723,46 @@ COM_COMPONENTBUILDER_COMPONENTS_MYSQL_TWEAKS_N_ITEMS_UNFEATURED="%s Components m COM_COMPONENTBUILDER_COMPONENTS_MYSQL_TWEAKS_N_ITEMS_UNFEATURED_1="%s Component mysql Tweaks unfeatured." COM_COMPONENTBUILDER_COMPONENTS_MYSQL_TWEAKS_N_ITEMS_UNPUBLISHED="%s Components mysql Tweaks unpublished." COM_COMPONENTBUILDER_COMPONENTS_MYSQL_TWEAKS_N_ITEMS_UNPUBLISHED_1="%s Component mysql Tweaks unpublished." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS="Components Placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_ACCESS="Components Placeholders Access" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_ACCESS_DESC="Allows the users in this group to access access components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_BATCH_OPTIONS="Batch process the selected Components Placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_BATCH_TIP="All changes will be applied to all selected Components Placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_BATCH_USE="Components Placeholders Batch Use" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_BATCH_USE_DESC="Allows users in this group to use batch copy/update method of batch components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_CREATE="Components Placeholders Create" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_CREATE_DESC="Allows the users in this group to create create components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_DELETE="Components Placeholders Delete" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_DELETE_DESC="Allows the users in this group to delete delete components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT="Components Placeholders Edit" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_CREATED_BY="Components Placeholders Edit Created By" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_CREATED_BY_DESC="Allows the users in this group to update the created by of the edit created by components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_CREATED_DATE="Components Placeholders Edit Created Date" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_CREATED_DATE_DESC="Allows the users in this group to update the created date of the edit created components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_DESC="Allows the users in this group to edit the component placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_OWN="Components Placeholders Edit Own" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_OWN_DESC="Allows the users in this group to edit edit own components placeholders created by them" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_STATE="Components Placeholders Edit State" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_STATE_DESC="Allows the users in this group to update the state of the component placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_VERSION="Components Placeholders Edit Version" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_VERSION_DESC="Allows users in this group to edit versions of version components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_ARCHIVED="%s Components Placeholders archived." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_ARCHIVED_1="%s Component Placeholders archived." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_CHECKED_IN_0="No Component Placeholders successfully checked in." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_CHECKED_IN_1="%d Component Placeholders successfully checked in." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_CHECKED_IN_MORE="%d Components Placeholders successfully checked in." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_DELETED="%s Components Placeholders deleted." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_DELETED_1="%s Component Placeholders deleted." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_FEATURED="%s Components Placeholders featured." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_FEATURED_1="%s Component Placeholders featured." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_PUBLISHED="%s Components Placeholders published." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_PUBLISHED_1="%s Component Placeholders published." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_TRASHED="%s Components Placeholders trashed." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_TRASHED_1="%s Component Placeholders trashed." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_UNFEATURED="%s Components Placeholders unfeatured." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_UNFEATURED_1="%s Component Placeholders unfeatured." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_UNPUBLISHED="%s Components Placeholders unpublished." +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_N_ITEMS_UNPUBLISHED_1="%s Component Placeholders unpublished." COM_COMPONENTBUILDER_COMPONENTS_SITE_VIEWS="Components Site Views" COM_COMPONENTBUILDER_COMPONENTS_SITE_VIEWS_ACCESS="Components Site Views Access" COM_COMPONENTBUILDER_COMPONENTS_SITE_VIEWS_ACCESS_DESC="Allows the users in this group to access access components site views" @@ -2602,6 +2642,41 @@ COM_COMPONENTBUILDER_COMPONENT_MYSQL_TWEAKS_TWEAKS="Tweaks" COM_COMPONENTBUILDER_COMPONENT_MYSQL_TWEAKS_VERSION_DESC="A count of the number of times this Component mysql Tweaks has been revised." COM_COMPONENTBUILDER_COMPONENT_MYSQL_TWEAKS_VERSION_LABEL="Revision" COM_COMPONENTBUILDER_COMPONENT_MYSQL_TWEAKS_YES_INCLUDE_BASED_ON_OPTIONS="Yes include based on options" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS="Component Placeholders" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_ADDPLACEHOLDERS="Addplaceholders" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_ADDPLACEHOLDERS_DESCRIPTION="Set dnamic placeholders for this component." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_ADDPLACEHOLDERS_LABEL="Placeholders" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_CREATED_BY_DESC="The user that created this Component Placeholders." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_CREATED_BY_LABEL="Created By" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_CREATED_DATE_DESC="The date this Component Placeholders was created." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_CREATED_DATE_LABEL="Created Date" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_DETAILS="Details" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_EDIT="Editing the Component Placeholders" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_ERROR_UNIQUE_ALIAS="Another Component Placeholders has the same alias." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_ID="Id" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_JOOMLA_COMPONENT="Joomla Component" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_JOOMLA_COMPONENT_DESCRIPTION="Select a Joomla Component" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_JOOMLA_COMPONENT_LABEL="Component" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_MODIFIED_BY_DESC="The last user that modified this Component Placeholders." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_MODIFIED_BY_LABEL="Modified By" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_MODIFIED_DATE_DESC="The date this Component Placeholders was modified." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_MODIFIED_DATE_LABEL="Modified Date" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_NEW="A New Component Placeholders" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_ORDERING_LABEL="Ordering" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_PERMISSION="Permissions" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_PUBLISHING="Publishing" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_SAVE_WARNING="Alias already existed so a number was added at the end. You can re-edit the Component Placeholders to customise the alias." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_STATUS="Status" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_TARGET_DESCRIPTION="Set the text you would like to target as a placeholder" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_TARGET_HINT="[[[core]]]" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_TARGET_LABEL="Target String Placeholder" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_TARGET_MESSAGE="Error! That target placeholder text already exist. Please add an unique placeholder target." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_VALUE_DESCRIPTION="Set the text you would like to set as the replacement value for the targeted placeholder." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_VALUE_HINT="membersmanager" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_VALUE_LABEL="Set String Value" +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_VALUE_MESSAGE="Error! Please add some set target value here." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_VERSION_DESC="A count of the number of times this Component Placeholders has been revised." +COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_VERSION_LABEL="Revision" COM_COMPONENTBUILDER_COMPONENT_SITE_VIEWS="Component Site Views" COM_COMPONENTBUILDER_COMPONENT_SITE_VIEWS_ACCESS_DESCRIPTION="Select if this view
should use access." COM_COMPONENTBUILDER_COMPONENT_SITE_VIEWS_ACCESS_LABEL="Add Access" @@ -3776,7 +3851,6 @@ COM_COMPONENTBUILDER_DASHBOARD_FIELDS="Fields

" COM_COMPONENTBUILDER_DASHBOARD_FIELDS_CATID="Category  For
Fields" COM_COMPONENTBUILDER_DASHBOARD_FIELDTYPES="Fieldtypes

" COM_COMPONENTBUILDER_DASHBOARD_FIELDTYPES_CATID="Category  For
Fieldtypes" -COM_COMPONENTBUILDER_DASHBOARD_FIELDTYPE_ADD="Add Fieldtype

" COM_COMPONENTBUILDER_DASHBOARD_FIELD_ADD="Add Field

" COM_COMPONENTBUILDER_DASHBOARD_GET_SNIPPETS="Get Snippets

" COM_COMPONENTBUILDER_DASHBOARD_HELP_DOCUMENTS="Help Documents

" @@ -3788,6 +3862,7 @@ COM_COMPONENTBUILDER_DASHBOARD_LAYOUTS="Layouts

" COM_COMPONENTBUILDER_DASHBOARD_LAYOUT_ADD="Add Layout

" COM_COMPONENTBUILDER_DASHBOARD_LIBRARIES="Libraries

" COM_COMPONENTBUILDER_DASHBOARD_LIST_OF_RECORDS="Dashboard (list of records)" +COM_COMPONENTBUILDER_DASHBOARD_PLACEHOLDERS="Placeholders

" COM_COMPONENTBUILDER_DASHBOARD_SERVERS="Servers

" COM_COMPONENTBUILDER_DASHBOARD_SITE_VIEWS="Site Views

" COM_COMPONENTBUILDER_DASHBOARD_SITE_VIEW_ADD="Add Site View

" @@ -4226,8 +4301,6 @@ COM_COMPONENTBUILDER_FIELDTYPES_BATCH_USE="Fieldtypes Batch Use" COM_COMPONENTBUILDER_FIELDTYPES_BATCH_USE_DESC="Allows users in this group to use batch copy/update method of batch fieldtypes" COM_COMPONENTBUILDER_FIELDTYPES_CREATE="Fieldtypes Create" COM_COMPONENTBUILDER_FIELDTYPES_CREATE_DESC="Allows the users in this group to create create fieldtypes" -COM_COMPONENTBUILDER_FIELDTYPES_DASHBOARD_ADD="Fieldtypes Dashboard Add" -COM_COMPONENTBUILDER_FIELDTYPES_DASHBOARD_ADD_DESC="Allows the users in this group to dashboard add of fieldtype" COM_COMPONENTBUILDER_FIELDTYPES_DASHBOARD_LIST="Fieldtypes Dashboard List" COM_COMPONENTBUILDER_FIELDTYPES_DASHBOARD_LIST_DESC="Allows the users in this group to dashboard list of fieldtype" COM_COMPONENTBUILDER_FIELDTYPES_DELETE="Fieldtypes Delete" @@ -4764,6 +4837,7 @@ COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_JOOMLA_COMPONENTS="Select the file t COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_LANGUAGES="Select the file to import data to languages." COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_LANGUAGE_TRANSLATIONS="Select the file to import data to language_translations." COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_LAYOUTS="Select the file to import data to layouts." +COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_PLACEHOLDERS="Select the file to import data to placeholders." COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_SERVERS="Select the file to import data to servers." COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_SITE_VIEWS="Select the file to import data to site_views." COM_COMPONENTBUILDER_IMPORT_SELECT_FILE_FOR_SNIPPETS="Select the file to import data to snippets." @@ -6011,8 +6085,83 @@ COM_COMPONENTBUILDER_PAIDLOCKED="Paid/Locked" COM_COMPONENTBUILDER_PATH_CODESCODE="Path: %s" COM_COMPONENTBUILDER_PATH_TO_THE_ZIPPED_PACKAGE_IS_CODESCODE_BR_S_S="Path to the zipped package is: %s
%s %s" COM_COMPONENTBUILDER_PERMISSIONS="Permissions" +COM_COMPONENTBUILDER_PLACEHOLDER="Placeholder" +COM_COMPONENTBUILDER_PLACEHOLDERS="Placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_ACCESS="Placeholders Access" +COM_COMPONENTBUILDER_PLACEHOLDERS_ACCESS_DESC="Allows the users in this group to access access placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_BATCH_OPTIONS="Batch process the selected Placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_BATCH_TIP="All changes will be applied to all selected Placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_BATCH_USE="Placeholders Batch Use" +COM_COMPONENTBUILDER_PLACEHOLDERS_BATCH_USE_DESC="Allows users in this group to use batch copy/update method of batch placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_CREATE="Placeholders Create" +COM_COMPONENTBUILDER_PLACEHOLDERS_CREATE_DESC="Allows the users in this group to create create placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_DASHBOARD_LIST="Placeholders Dashboard List" +COM_COMPONENTBUILDER_PLACEHOLDERS_DASHBOARD_LIST_DESC="Allows the users in this group to dashboard list of placeholder" +COM_COMPONENTBUILDER_PLACEHOLDERS_DELETE="Placeholders Delete" +COM_COMPONENTBUILDER_PLACEHOLDERS_DELETE_DESC="Allows the users in this group to delete delete placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT="Placeholders Edit" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_DESC="Allows the users in this group to edit the placeholder" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_OWN="Placeholders Edit Own" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_OWN_DESC="Allows the users in this group to edit edit own placeholders created by them" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_STATE="Placeholders Edit State" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_STATE_DESC="Allows the users in this group to update the state of the placeholder" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_VERSION="Placeholders Edit Version" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_VERSION_DESC="Allows users in this group to edit versions of version placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_EXPORT="Placeholders Export" +COM_COMPONENTBUILDER_PLACEHOLDERS_EXPORT_DESC="Allows the users in this group to export export placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_IMPORT="Placeholders Import" +COM_COMPONENTBUILDER_PLACEHOLDERS_IMPORT_DESC="Allows the users in this group to import import placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_ARCHIVED="%s Placeholders archived." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_ARCHIVED_1="%s Placeholder archived." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_CHECKED_IN_0="No Placeholder successfully checked in." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_CHECKED_IN_1="%d Placeholder successfully checked in." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_CHECKED_IN_MORE="%d Placeholders successfully checked in." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_DELETED="%s Placeholders deleted." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_DELETED_1="%s Placeholder deleted." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_FEATURED="%s Placeholders featured." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_FEATURED_1="%s Placeholder featured." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_PUBLISHED="%s Placeholders published." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_PUBLISHED_1="%s Placeholder published." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_TRASHED="%s Placeholders trashed." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_TRASHED_1="%s Placeholder trashed." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_UNFEATURED="%s Placeholders unfeatured." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_UNFEATURED_1="%s Placeholder unfeatured." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_UNPUBLISHED="%s Placeholders unpublished." +COM_COMPONENTBUILDER_PLACEHOLDERS_N_ITEMS_UNPUBLISHED_1="%s Placeholder unpublished." COM_COMPONENTBUILDER_PLACEHOLDERS_REMOVED="Placeholders Removed!" +COM_COMPONENTBUILDER_PLACEHOLDERS_SUBMENU="Placeholders Submenu" +COM_COMPONENTBUILDER_PLACEHOLDERS_SUBMENU_DESC="Allows the users in this group to submenu of placeholder" +COM_COMPONENTBUILDER_PLACEHOLDER_CREATED_BY_DESC="The user that created this Placeholder." +COM_COMPONENTBUILDER_PLACEHOLDER_CREATED_BY_LABEL="Created By" +COM_COMPONENTBUILDER_PLACEHOLDER_CREATED_DATE_DESC="The date this Placeholder was created." +COM_COMPONENTBUILDER_PLACEHOLDER_CREATED_DATE_LABEL="Created Date" +COM_COMPONENTBUILDER_PLACEHOLDER_DETAILS="Details" +COM_COMPONENTBUILDER_PLACEHOLDER_EDIT="Editing the Placeholder" +COM_COMPONENTBUILDER_PLACEHOLDER_ERROR_UNIQUE_ALIAS="Another Placeholder has the same alias." +COM_COMPONENTBUILDER_PLACEHOLDER_ID="Id" +COM_COMPONENTBUILDER_PLACEHOLDER_MODIFIED_BY_DESC="The last user that modified this Placeholder." +COM_COMPONENTBUILDER_PLACEHOLDER_MODIFIED_BY_LABEL="Modified By" +COM_COMPONENTBUILDER_PLACEHOLDER_MODIFIED_DATE_DESC="The date this Placeholder was modified." +COM_COMPONENTBUILDER_PLACEHOLDER_MODIFIED_DATE_LABEL="Modified Date" +COM_COMPONENTBUILDER_PLACEHOLDER_NEW="A New Placeholder" +COM_COMPONENTBUILDER_PLACEHOLDER_ORDERING_LABEL="Ordering" +COM_COMPONENTBUILDER_PLACEHOLDER_PERMISSION="Permissions" +COM_COMPONENTBUILDER_PLACEHOLDER_PUBLISHING="Publishing" COM_COMPONENTBUILDER_PLACEHOLDER_REMOVED="Placeholder Removed!" +COM_COMPONENTBUILDER_PLACEHOLDER_SAVE_WARNING="Alias already existed so a number was added at the end. You can re-edit the Placeholder to customise the alias." +COM_COMPONENTBUILDER_PLACEHOLDER_STATUS="Status" +COM_COMPONENTBUILDER_PLACEHOLDER_TARGET="Target" +COM_COMPONENTBUILDER_PLACEHOLDER_TARGET_DESCRIPTION="Set the text you would like to target as a placeholder" +COM_COMPONENTBUILDER_PLACEHOLDER_TARGET_HINT="[[[core]]]" +COM_COMPONENTBUILDER_PLACEHOLDER_TARGET_LABEL="Target String Placeholder" +COM_COMPONENTBUILDER_PLACEHOLDER_TARGET_MESSAGE="Error! That target placeholder text already exist. Please add an unique placeholder target." +COM_COMPONENTBUILDER_PLACEHOLDER_VALUE="Value" +COM_COMPONENTBUILDER_PLACEHOLDER_VALUE_DESCRIPTION="Set the text you would like to set as the replacement value for the targeted placeholder." +COM_COMPONENTBUILDER_PLACEHOLDER_VALUE_HINT="membersmanager" +COM_COMPONENTBUILDER_PLACEHOLDER_VALUE_LABEL="Set String Value" +COM_COMPONENTBUILDER_PLACEHOLDER_VALUE_MESSAGE="Error! Please add some set target value here." +COM_COMPONENTBUILDER_PLACEHOLDER_VERSION_DESC="A count of the number of times this Placeholder has been revised." +COM_COMPONENTBUILDER_PLACEHOLDER_VERSION_LABEL="Revision" COM_COMPONENTBUILDER_PLACES_ACROSS_JCB_WHERE_THIS_S_IS_LINKED="Places across JCB where this %s is linked." COM_COMPONENTBUILDER_PLEASE_ADD_FILES_TO_S="Please add files to (%s)" COM_COMPONENTBUILDER_PLEASE_ADD_FOLDERS_TO_S="Please add folders to (%s)" @@ -6890,6 +7039,7 @@ COM_COMPONENTBUILDER_SUBMENU_LANGUAGES="Languages" COM_COMPONENTBUILDER_SUBMENU_LANGUAGE_TRANSLATIONS="Language Translations" COM_COMPONENTBUILDER_SUBMENU_LAYOUTS="Layouts" COM_COMPONENTBUILDER_SUBMENU_LIBRARIES="Libraries" +COM_COMPONENTBUILDER_SUBMENU_PLACEHOLDERS="Placeholders" COM_COMPONENTBUILDER_SUBMENU_SERVERS="Servers" COM_COMPONENTBUILDER_SUBMENU_SITE_VIEWS="Site Views" COM_COMPONENTBUILDER_SUBMENU_SNIPPETS="Snippets" @@ -7058,6 +7208,7 @@ COM_COMPONENTBUILDER_THE_COMPONENT_CUSTOM_ADMIN_VIEWS="The component custom admi COM_COMPONENTBUILDER_THE_COMPONENT_DASHBOARD="The component dashboard" COM_COMPONENTBUILDER_THE_COMPONENT_FILES_FOLDERS="The component files & folders" COM_COMPONENTBUILDER_THE_COMPONENT_MYSQL_TWEAKS="The component mysql tweaks" +COM_COMPONENTBUILDER_THE_COMPONENT_PLACEHOLDERS="The component placeholders" COM_COMPONENTBUILDER_THE_COMPONENT_SITE_VIEWS="The component site views" COM_COMPONENTBUILDER_THE_COMPONENT_UPDATES="The component updates" COM_COMPONENTBUILDER_THE_COMPONENT_WITH_ALL_LINKED_ADMIN_VIEWS_FIELDS_LINKED_TO_ADMIN_VIEWS_CUSTOM_ADMIN_VIEWS_SITE_VIEWS_TEMPLATES_AND_LAYOUTS_WERE_CLONED_SUCCESSFUL="The Component with all linked admin views, fields linked to admin views, custom admin views, site views, templates and layouts were cloned successful!" diff --git a/admin/language/en-GB/en-GB.com_componentbuilder.sys.ini b/admin/language/en-GB/en-GB.com_componentbuilder.sys.ini index 8cf3736f7..8a2e9fd9f 100644 --- a/admin/language/en-GB/en-GB.com_componentbuilder.sys.ini +++ b/admin/language/en-GB/en-GB.com_componentbuilder.sys.ini @@ -261,6 +261,26 @@ COM_COMPONENTBUILDER_COMPONENTS_MYSQL_TWEAKS_EDIT_STATE="Components Mysql Tweaks COM_COMPONENTBUILDER_COMPONENTS_MYSQL_TWEAKS_EDIT_STATE_DESC="Allows the users in this group to update the state of the component mysql tweaks" COM_COMPONENTBUILDER_COMPONENTS_MYSQL_TWEAKS_EDIT_VERSION="Components Mysql Tweaks Edit Version" COM_COMPONENTBUILDER_COMPONENTS_MYSQL_TWEAKS_EDIT_VERSION_DESC="Allows users in this group to edit versions of version components mysql tweaks" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_ACCESS="Components Placeholders Access" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_ACCESS_DESC="Allows the users in this group to access access components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_BATCH_USE="Components Placeholders Batch Use" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_BATCH_USE_DESC="Allows users in this group to use batch copy/update method of batch components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_CREATE="Components Placeholders Create" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_CREATE_DESC="Allows the users in this group to create create components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_DELETE="Components Placeholders Delete" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_DELETE_DESC="Allows the users in this group to delete delete components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT="Components Placeholders Edit" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_CREATED_BY="Components Placeholders Edit Created By" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_CREATED_BY_DESC="Allows the users in this group to update the created by of the edit created by components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_CREATED_DATE="Components Placeholders Edit Created Date" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_CREATED_DATE_DESC="Allows the users in this group to update the created date of the edit created components placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_DESC="Allows the users in this group to edit the component placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_OWN="Components Placeholders Edit Own" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_OWN_DESC="Allows the users in this group to edit edit own components placeholders created by them" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_STATE="Components Placeholders Edit State" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_STATE_DESC="Allows the users in this group to update the state of the component placeholders" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_VERSION="Components Placeholders Edit Version" +COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_EDIT_VERSION_DESC="Allows users in this group to edit versions of version components placeholders" COM_COMPONENTBUILDER_COMPONENTS_SITE_VIEWS_ACCESS="Components Site Views Access" COM_COMPONENTBUILDER_COMPONENTS_SITE_VIEWS_ACCESS_DESC="Allows the users in this group to access access components site views" COM_COMPONENTBUILDER_COMPONENTS_SITE_VIEWS_BATCH_USE="Components Site Views Batch Use" @@ -428,8 +448,6 @@ COM_COMPONENTBUILDER_FIELDTYPES_BATCH_USE="Fieldtypes Batch Use" COM_COMPONENTBUILDER_FIELDTYPES_BATCH_USE_DESC="Allows users in this group to use batch copy/update method of batch fieldtypes" COM_COMPONENTBUILDER_FIELDTYPES_CREATE="Fieldtypes Create" COM_COMPONENTBUILDER_FIELDTYPES_CREATE_DESC="Allows the users in this group to create create fieldtypes" -COM_COMPONENTBUILDER_FIELDTYPES_DASHBOARD_ADD="Fieldtypes Dashboard Add" -COM_COMPONENTBUILDER_FIELDTYPES_DASHBOARD_ADD_DESC="Allows the users in this group to dashboard add of fieldtype" COM_COMPONENTBUILDER_FIELDTYPES_DASHBOARD_LIST="Fieldtypes Dashboard List" COM_COMPONENTBUILDER_FIELDTYPES_DASHBOARD_LIST_DESC="Allows the users in this group to dashboard list of fieldtype" COM_COMPONENTBUILDER_FIELDTYPES_DELETE="Fieldtypes Delete" @@ -691,10 +709,35 @@ COM_COMPONENTBUILDER_MENU_JOOMLA_COMPONENTS="Joomla Components" COM_COMPONENTBUILDER_MENU_LANGUAGE_TRANSLATIONS="Language Translations" COM_COMPONENTBUILDER_MENU_LAYOUTS="Layouts" COM_COMPONENTBUILDER_MENU_LIBRARIES="Libraries" +COM_COMPONENTBUILDER_MENU_PLACEHOLDERS="Placeholders" COM_COMPONENTBUILDER_MENU_SITE_VIEWS="Site Views" COM_COMPONENTBUILDER_MENU_SNIPPETS="Snippets" COM_COMPONENTBUILDER_MENU_TEMPLATES="Templates" COM_COMPONENTBUILDER_MENU_VALIDATION_RULES="Validation Rules" +COM_COMPONENTBUILDER_PLACEHOLDERS_ACCESS="Placeholders Access" +COM_COMPONENTBUILDER_PLACEHOLDERS_ACCESS_DESC="Allows the users in this group to access access placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_BATCH_USE="Placeholders Batch Use" +COM_COMPONENTBUILDER_PLACEHOLDERS_BATCH_USE_DESC="Allows users in this group to use batch copy/update method of batch placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_CREATE="Placeholders Create" +COM_COMPONENTBUILDER_PLACEHOLDERS_CREATE_DESC="Allows the users in this group to create create placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_DASHBOARD_LIST="Placeholders Dashboard List" +COM_COMPONENTBUILDER_PLACEHOLDERS_DASHBOARD_LIST_DESC="Allows the users in this group to dashboard list of placeholder" +COM_COMPONENTBUILDER_PLACEHOLDERS_DELETE="Placeholders Delete" +COM_COMPONENTBUILDER_PLACEHOLDERS_DELETE_DESC="Allows the users in this group to delete delete placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT="Placeholders Edit" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_DESC="Allows the users in this group to edit the placeholder" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_OWN="Placeholders Edit Own" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_OWN_DESC="Allows the users in this group to edit edit own placeholders created by them" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_STATE="Placeholders Edit State" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_STATE_DESC="Allows the users in this group to update the state of the placeholder" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_VERSION="Placeholders Edit Version" +COM_COMPONENTBUILDER_PLACEHOLDERS_EDIT_VERSION_DESC="Allows users in this group to edit versions of version placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_EXPORT="Placeholders Export" +COM_COMPONENTBUILDER_PLACEHOLDERS_EXPORT_DESC="Allows the users in this group to export export placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_IMPORT="Placeholders Import" +COM_COMPONENTBUILDER_PLACEHOLDERS_IMPORT_DESC="Allows the users in this group to import import placeholders" +COM_COMPONENTBUILDER_PLACEHOLDERS_SUBMENU="Placeholders Submenu" +COM_COMPONENTBUILDER_PLACEHOLDERS_SUBMENU_DESC="Allows the users in this group to submenu of placeholder" COM_COMPONENTBUILDER_SERVERS_ACCESS="Servers Access" COM_COMPONENTBUILDER_SERVERS_ACCESS_DESC="Allows the users in this group to access access servers" COM_COMPONENTBUILDER_SERVERS_BATCH_USE="Servers Batch Use" diff --git a/admin/layouts/component_placeholders/details_above.php b/admin/layouts/component_placeholders/details_above.php new file mode 100644 index 000000000..da98e936b --- /dev/null +++ b/admin/layouts/component_placeholders/details_above.php @@ -0,0 +1,31 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +$form = $displayData->getForm(); + +$fields = $displayData->get('fields') ?: array( + 'joomla_component' +); + +$hiddenFields = $displayData->get('hidden_fields') ?: array(); + +?> +
+ + + setFieldAttribute($field, 'type', 'hidden'); ?> + + renderField($field, null, null, array('class' => 'control-wrapper-' . $field)); ?> + +
diff --git a/admin/layouts/component_placeholders/details_fullwidth.php b/admin/layouts/component_placeholders/details_fullwidth.php new file mode 100644 index 000000000..c38954481 --- /dev/null +++ b/admin/layouts/component_placeholders/details_fullwidth.php @@ -0,0 +1,31 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +$form = $displayData->getForm(); + +$fields = $displayData->get('fields') ?: array( + 'addplaceholders' +); + +$hiddenFields = $displayData->get('hidden_fields') ?: array(); + +?> +
+ + + setFieldAttribute($field, 'type', 'hidden'); ?> + + renderField($field, null, null, array('class' => 'control-wrapper-' . $field)); ?> + +
diff --git a/admin/layouts/component_placeholders/index.html b/admin/layouts/component_placeholders/index.html new file mode 100644 index 000000000..fa6d84e80 --- /dev/null +++ b/admin/layouts/component_placeholders/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin/layouts/component_placeholders/publishing.php b/admin/layouts/component_placeholders/publishing.php new file mode 100644 index 000000000..3ff2d0f98 --- /dev/null +++ b/admin/layouts/component_placeholders/publishing.php @@ -0,0 +1,32 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +$form = $displayData->getForm(); + +$fields = $displayData->get('fields') ?: array( + 'created', + 'created_by', + 'modified', + 'modified_by' +); + +$hiddenFields = $displayData->get('hidden_fields') ?: array(); + +?> + + + setFieldAttribute($field, 'type', 'hidden'); ?> + + renderField($field, null, null, array('class' => 'control-wrapper-' . $field)); ?> + diff --git a/admin/layouts/component_placeholders/publlshing.php b/admin/layouts/component_placeholders/publlshing.php new file mode 100644 index 000000000..db19414f3 --- /dev/null +++ b/admin/layouts/component_placeholders/publlshing.php @@ -0,0 +1,34 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +$form = $displayData->getForm(); + +$fields = $displayData->get('fields') ?: array( + 'published', + 'ordering', + 'access', + 'version', + 'hits', + 'id' +); + +$hiddenFields = $displayData->get('hidden_fields') ?: array(); + +?> + + + setFieldAttribute($field, 'type', 'hidden'); ?> + + renderField($field, null, null, array('class' => 'control-wrapper-' . $field)); ?> + diff --git a/admin/layouts/placeholder/details_left.php b/admin/layouts/placeholder/details_left.php new file mode 100644 index 000000000..a7af9fa84 --- /dev/null +++ b/admin/layouts/placeholder/details_left.php @@ -0,0 +1,29 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +$form = $displayData->getForm(); + +$fields = $displayData->get('fields') ?: array( + 'target' +); + +$hiddenFields = $displayData->get('hidden_fields') ?: array(); + +?> + + + setFieldAttribute($field, 'type', 'hidden'); ?> + + renderField($field, null, null, array('class' => 'control-wrapper-' . $field)); ?> + diff --git a/admin/layouts/placeholder/details_right.php b/admin/layouts/placeholder/details_right.php new file mode 100644 index 000000000..810273690 --- /dev/null +++ b/admin/layouts/placeholder/details_right.php @@ -0,0 +1,29 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +$form = $displayData->getForm(); + +$fields = $displayData->get('fields') ?: array( + 'value' +); + +$hiddenFields = $displayData->get('hidden_fields') ?: array(); + +?> + + + setFieldAttribute($field, 'type', 'hidden'); ?> + + renderField($field, null, null, array('class' => 'control-wrapper-' . $field)); ?> + diff --git a/admin/layouts/placeholder/index.html b/admin/layouts/placeholder/index.html new file mode 100644 index 000000000..fa6d84e80 --- /dev/null +++ b/admin/layouts/placeholder/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin/layouts/placeholder/publishing.php b/admin/layouts/placeholder/publishing.php new file mode 100644 index 000000000..3ff2d0f98 --- /dev/null +++ b/admin/layouts/placeholder/publishing.php @@ -0,0 +1,32 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +$form = $displayData->getForm(); + +$fields = $displayData->get('fields') ?: array( + 'created', + 'created_by', + 'modified', + 'modified_by' +); + +$hiddenFields = $displayData->get('hidden_fields') ?: array(); + +?> + + + setFieldAttribute($field, 'type', 'hidden'); ?> + + renderField($field, null, null, array('class' => 'control-wrapper-' . $field)); ?> + diff --git a/admin/layouts/placeholder/publlshing.php b/admin/layouts/placeholder/publlshing.php new file mode 100644 index 000000000..db19414f3 --- /dev/null +++ b/admin/layouts/placeholder/publlshing.php @@ -0,0 +1,34 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +$form = $displayData->getForm(); + +$fields = $displayData->get('fields') ?: array( + 'published', + 'ordering', + 'access', + 'version', + 'hits', + 'id' +); + +$hiddenFields = $displayData->get('hidden_fields') ?: array(); + +?> + + + setFieldAttribute($field, 'type', 'hidden'); ?> + + renderField($field, null, null, array('class' => 'control-wrapper-' . $field)); ?> + diff --git a/admin/layouts/server/linked_components_fullwidth.php b/admin/layouts/server/linked_components_fullwidth.php index c69fd2f6d..72ceb0921 100644 --- a/admin/layouts/server/linked_components_fullwidth.php +++ b/admin/layouts/server/linked_components_fullwidth.php @@ -107,6 +107,11 @@ $ref = ($id) ? "&ref=server&refid=" . $id . "&return=" . urlencode(base64_encode 'icon' => 'options') ); $_buttons[1] = array( + array( + 'view' => 'component_placeholders', + 'views' => 'components_placeholders', + 'title' => JText::_('COM_COMPONENTBUILDER_THE_COMPONENT_PLACEHOLDERS'), + 'icon' => 'search'), array( 'view' => 'component_updates', 'views' => 'components_updates', diff --git a/admin/models/component_placeholders.php b/admin/models/component_placeholders.php new file mode 100644 index 000000000..2bf049f0f --- /dev/null +++ b/admin/models/component_placeholders.php @@ -0,0 +1,864 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +use Joomla\Registry\Registry; + +/** + * Componentbuilder Component_placeholders Model + */ +class ComponentbuilderModelComponent_placeholders extends JModelAdmin +{ + /** + * @var string The prefix to use with controller messages. + * @since 1.6 + */ + protected $text_prefix = 'COM_COMPONENTBUILDER'; + + /** + * The type alias for this content type. + * + * @var string + * @since 3.2 + */ + public $typeAlias = 'com_componentbuilder.component_placeholders'; + + /** + * Returns a Table object, always creating it + * + * @param type $type The table type to instantiate + * @param string $prefix A prefix for the table class name. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return JTable A database object + * + * @since 1.6 + */ + public function getTable($type = 'component_placeholders', $prefix = 'ComponentbuilderTable', $config = array()) + { + // add table path for when model gets used from other component + $this->addTablePath(JPATH_ADMINISTRATOR . '/components/com_componentbuilder/tables'); + // get instance of the table + return JTable::getInstance($type, $prefix, $config); + } + + /** + * Method to get a single record. + * + * @param integer $pk The id of the primary key. + * + * @return mixed Object on success, false on failure. + * + * @since 1.6 + */ + public function getItem($pk = null) + { + if ($item = parent::getItem($pk)) + { + if (!empty($item->params) && !is_array($item->params)) + { + // Convert the params field to an array. + $registry = new Registry; + $registry->loadString($item->params); + $item->params = $registry->toArray(); + } + + if (!empty($item->metadata)) + { + // Convert the metadata field to an array. + $registry = new Registry; + $registry->loadString($item->metadata); + $item->metadata = $registry->toArray(); + } + + if (!empty($item->addplaceholders)) + { + // Convert the addplaceholders field to an array. + $addplaceholders = new Registry; + $addplaceholders->loadString($item->addplaceholders); + $item->addplaceholders = $addplaceholders->toArray(); + } + + if (!empty($item->id)) + { + $item->tags = new JHelperTags; + $item->tags->getTagIds($item->id, 'com_componentbuilder.component_placeholders'); + } + } + + return $item; + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * @param array $options Optional array of options for the form creation. + * + * @return mixed A JForm object on success, false on failure + * + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true, $options = array('control' => 'jform')) + { + // set load data option + $options['load_data'] = $loadData; + // Get the form. + $form = $this->loadForm('com_componentbuilder.component_placeholders', 'component_placeholders', $options); + + if (empty($form)) + { + return false; + } + + $jinput = JFactory::getApplication()->input; + + // The front end calls this model and uses a_id to avoid id clashes so we need to check for that first. + if ($jinput->get('a_id')) + { + $id = $jinput->get('a_id', 0, 'INT'); + } + // The back end uses id so we use that the rest of the time and set it to 0 by default. + else + { + $id = $jinput->get('id', 0, 'INT'); + } + + $user = JFactory::getUser(); + + // Check for existing item. + // Modify the form based on Edit State access controls. + if ($id != 0 && (!$user->authorise('component_placeholders.edit.state', 'com_componentbuilder.component_placeholders.' . (int) $id)) + || ($id == 0 && !$user->authorise('component_placeholders.edit.state', 'com_componentbuilder'))) + { + // Disable fields for display. + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('published', 'disabled', 'true'); + // Disable fields while saving. + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('published', 'filter', 'unset'); + } + // If this is a new item insure the greated by is set. + if (0 == $id) + { + // Set the created_by to this user + $form->setValue('created_by', null, $user->id); + } + // Modify the form based on Edit Creaded By access controls. + if ($id != 0 && (!$user->authorise('component_placeholders.edit.created_by', 'com_componentbuilder.component_placeholders.' . (int) $id)) + || ($id == 0 && !$user->authorise('component_placeholders.edit.created_by', 'com_componentbuilder'))) + { + // Disable fields for display. + $form->setFieldAttribute('created_by', 'disabled', 'true'); + // Disable fields for display. + $form->setFieldAttribute('created_by', 'readonly', 'true'); + // Disable fields while saving. + $form->setFieldAttribute('created_by', 'filter', 'unset'); + } + // Modify the form based on Edit Creaded Date access controls. + if ($id != 0 && (!$user->authorise('component_placeholders.edit.created', 'com_componentbuilder.component_placeholders.' . (int) $id)) + || ($id == 0 && !$user->authorise('component_placeholders.edit.created', 'com_componentbuilder'))) + { + // Disable fields for display. + $form->setFieldAttribute('created', 'disabled', 'true'); + // Disable fields while saving. + $form->setFieldAttribute('created', 'filter', 'unset'); + } + // Only load these values if no id is found + if (0 == $id) + { + // Set redirected view name + $redirectedView = $jinput->get('ref', null, 'STRING'); + // Set field name (or fall back to view name) + $redirectedField = $jinput->get('field', $redirectedView, 'STRING'); + // Set redirected view id + $redirectedId = $jinput->get('refid', 0, 'INT'); + // Set field id (or fall back to redirected view id) + $redirectedValue = $jinput->get('field_id', $redirectedId, 'INT'); + if (0 != $redirectedValue && $redirectedField) + { + // Now set the local-redirected field default value + $form->setValue($redirectedField, null, $redirectedValue); + } + } + return $form; + } + + /** + * Method to get the script that have to be included on the form + * + * @return string script files + */ + public function getScript() + { + return 'administrator/components/com_componentbuilder/models/forms/component_placeholders.js'; + } + + /** + * Method to test whether a record can be deleted. + * + * @param object $record A record object. + * + * @return boolean True if allowed to delete the record. Defaults to the permission set in the component. + * + * @since 1.6 + */ + protected function canDelete($record) + { + if (!empty($record->id)) + { + if ($record->published != -2) + { + return; + } + + $user = JFactory::getUser(); + // The record has been set. Check the record permissions. + return $user->authorise('component_placeholders.delete', 'com_componentbuilder.component_placeholders.' . (int) $record->id); + } + return false; + } + + /** + * Method to test whether a record can have its state edited. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + $recordId = (!empty($record->id)) ? $record->id : 0; + + if ($recordId) + { + // The record has been set. Check the record permissions. + $permission = $user->authorise('component_placeholders.edit.state', 'com_componentbuilder.component_placeholders.' . (int) $recordId); + if (!$permission && !is_null($permission)) + { + return false; + } + } + // In the absense of better information, revert to the component permissions. + return $user->authorise('component_placeholders.edit.state', 'com_componentbuilder'); + } + + /** + * Method override to check if you can edit an existing record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * @since 2.5 + */ + protected function allowEdit($data = array(), $key = 'id') + { + // Check specific edit permission then general edit permission. + $user = JFactory::getUser(); + + return $user->authorise('component_placeholders.edit', 'com_componentbuilder.component_placeholders.'. ((int) isset($data[$key]) ? $data[$key] : 0)) or $user->authorise('component_placeholders.edit', 'com_componentbuilder'); + } + + /** + * Prepare and sanitise the table data prior to saving. + * + * @param JTable $table A JTable object. + * + * @return void + * + * @since 1.6 + */ + protected function prepareTable($table) + { + $date = JFactory::getDate(); + $user = JFactory::getUser(); + + if (isset($table->name)) + { + $table->name = htmlspecialchars_decode($table->name, ENT_QUOTES); + } + + if (isset($table->alias) && empty($table->alias)) + { + $table->generateAlias(); + } + + if (empty($table->id)) + { + $table->created = $date->toSql(); + // set the user + if ($table->created_by == 0 || empty($table->created_by)) + { + $table->created_by = $user->id; + } + // Set ordering to the last item if not set + if (empty($table->ordering)) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('MAX(ordering)') + ->from($db->quoteName('#__componentbuilder_component_placeholders')); + $db->setQuery($query); + $max = $db->loadResult(); + + $table->ordering = $max + 1; + } + } + else + { + $table->modified = $date->toSql(); + $table->modified_by = $user->id; + } + + if (!empty($table->id)) + { + // Increment the items version number. + $table->version++; + } + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_componentbuilder.edit.component_placeholders.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + return $data; + } + + /** + * Method to get the unique fields of this table. + * + * @return mixed An array of field names, boolean false if none is set. + * + * @since 3.0 + */ + protected function getUniqeFields() + { + return false; + } + + /** + * Method to delete one or more records. + * + * @param array &$pks An array of record primary keys. + * + * @return boolean True if successful, false if an error occurs. + * + * @since 12.2 + */ + public function delete(&$pks) + { + if (!parent::delete($pks)) + { + return false; + } + + return true; + } + + /** + * Method to change the published state of one or more records. + * + * @param array &$pks A list of the primary keys to change. + * @param integer $value The value of the published state. + * + * @return boolean True on success. + * + * @since 12.2 + */ + public function publish(&$pks, $value = 1) + { + if (!parent::publish($pks, $value)) + { + return false; + } + + return true; + } + + /** + * Method to perform batch operations on an item or a set of items. + * + * @param array $commands An array of commands to perform. + * @param array $pks An array of item ids. + * @param array $contexts An array of item contexts. + * + * @return boolean Returns true on success, false on failure. + * + * @since 12.2 + */ + public function batch($commands, $pks, $contexts) + { + // Sanitize ids. + $pks = array_unique($pks); + JArrayHelper::toInteger($pks); + + // Remove any values of zero. + if (array_search(0, $pks, true)) + { + unset($pks[array_search(0, $pks, true)]); + } + + if (empty($pks)) + { + $this->setError(JText::_('JGLOBAL_NO_ITEM_SELECTED')); + return false; + } + + $done = false; + + // Set some needed variables. + $this->user = JFactory::getUser(); + $this->table = $this->getTable(); + $this->tableClassName = get_class($this->table); + $this->contentType = new JUcmType; + $this->type = $this->contentType->getTypeByTable($this->tableClassName); + $this->canDo = ComponentbuilderHelper::getActions('component_placeholders'); + $this->batchSet = true; + + if (!$this->canDo->get('core.batch')) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION')); + return false; + } + + if ($this->type == false) + { + $type = new JUcmType; + $this->type = $type->getTypeByAlias($this->typeAlias); + } + + $this->tagsObserver = $this->table->getObserverOfClass('JTableObserverTags'); + + if (!empty($commands['move_copy'])) + { + $cmd = JArrayHelper::getValue($commands, 'move_copy', 'c'); + + if ($cmd == 'c') + { + $result = $this->batchCopy($commands, $pks, $contexts); + + if (is_array($result)) + { + foreach ($result as $old => $new) + { + $contexts[$new] = $contexts[$old]; + } + $pks = array_values($result); + } + else + { + return false; + } + } + elseif ($cmd == 'm' && !$this->batchMove($commands, $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!$done) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION')); + + return false; + } + + // Clear the cache + $this->cleanCache(); + + return true; + } + + /** + * Batch copy items to a new category or current. + * + * @param integer $values The new values. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return mixed An array of new IDs on success, boolean false on failure. + * + * @since 12.2 + */ + protected function batchCopy($values, $pks, $contexts) + { + if (empty($this->batchSet)) + { + // Set some needed variables. + $this->user = JFactory::getUser(); + $this->table = $this->getTable(); + $this->tableClassName = get_class($this->table); + $this->canDo = ComponentbuilderHelper::getActions('component_placeholders'); + } + + if (!$this->canDo->get('component_placeholders.create') && !$this->canDo->get('component_placeholders.batch')) + { + return false; + } + + // get list of uniqe fields + $uniqeFields = $this->getUniqeFields(); + // remove move_copy from array + unset($values['move_copy']); + + // make sure published is set + if (!isset($values['published'])) + { + $values['published'] = 0; + } + elseif (isset($values['published']) && !$this->canDo->get('component_placeholders.edit.state')) + { + $values['published'] = 0; + } + + $newIds = array(); + // Parent exists so let's proceed + while (!empty($pks)) + { + // Pop the first ID off the stack + $pk = array_shift($pks); + + $this->table->reset(); + + // only allow copy if user may edit this item. + if (!$this->user->authorise('component_placeholders.edit', $contexts[$pk])) + { + // Not fatal error + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + + // Check that the row actually exists + if (!$this->table->load($pk)) + { + if ($error = $this->table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // Only for strings + if (ComponentbuilderHelper::checkString($this->table->joomla_component) && !is_numeric($this->table->joomla_component)) + { + $this->table->joomla_component = $this->generateUniqe('joomla_component',$this->table->joomla_component); + } + + // insert all set values + if (ComponentbuilderHelper::checkArray($values)) + { + foreach ($values as $key => $value) + { + if (strlen($value) > 0 && isset($this->table->$key)) + { + $this->table->$key = $value; + } + } + } + + // update all uniqe fields + if (ComponentbuilderHelper::checkArray($uniqeFields)) + { + foreach ($uniqeFields as $uniqeField) + { + $this->table->$uniqeField = $this->generateUniqe($uniqeField,$this->table->$uniqeField); + } + } + + // Reset the ID because we are making a copy + $this->table->id = 0; + + // TODO: Deal with ordering? + // $this->table->ordering = 1; + + // Check the row. + if (!$this->table->check()) + { + $this->setError($this->table->getError()); + + return false; + } + + if (!empty($this->type)) + { + $this->createTagsHelper($this->tagsObserver, $this->type, $pk, $this->typeAlias, $this->table); + } + + // Store the row. + if (!$this->table->store()) + { + $this->setError($this->table->getError()); + + return false; + } + + // Get the new item ID + $newId = $this->table->get('id'); + + // Add the new ID to the array + $newIds[$pk] = $newId; + } + + // Clean the cache + $this->cleanCache(); + + return $newIds; + } + + /** + * Batch move items to a new category + * + * @param integer $value The new category ID. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 12.2 + */ + protected function batchMove($values, $pks, $contexts) + { + if (empty($this->batchSet)) + { + // Set some needed variables. + $this->user = JFactory::getUser(); + $this->table = $this->getTable(); + $this->tableClassName = get_class($this->table); + $this->canDo = ComponentbuilderHelper::getActions('component_placeholders'); + } + + if (!$this->canDo->get('component_placeholders.edit') && !$this->canDo->get('component_placeholders.batch')) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); + return false; + } + + // make sure published only updates if user has the permission. + if (isset($values['published']) && !$this->canDo->get('component_placeholders.edit.state')) + { + unset($values['published']); + } + // remove move_copy from array + unset($values['move_copy']); + + // Parent exists so we proceed + foreach ($pks as $pk) + { + if (!$this->user->authorise('component_placeholders.edit', $contexts[$pk])) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); + return false; + } + + // Check that the row actually exists + if (!$this->table->load($pk)) + { + if ($error = $this->table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // insert all set values. + if (ComponentbuilderHelper::checkArray($values)) + { + foreach ($values as $key => $value) + { + // Do special action for access. + if ('access' === $key && strlen($value) > 0) + { + $this->table->$key = $value; + } + elseif (strlen($value) > 0 && isset($this->table->$key)) + { + $this->table->$key = $value; + } + } + } + + + // Check the row. + if (!$this->table->check()) + { + $this->setError($this->table->getError()); + + return false; + } + + if (!empty($this->type)) + { + $this->createTagsHelper($this->tagsObserver, $this->type, $pk, $this->typeAlias, $this->table); + } + + // Store the row. + if (!$this->table->store()) + { + $this->setError($this->table->getError()); + + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to save the form data. + * + * @param array $data The form data. + * + * @return boolean True on success. + * + * @since 1.6 + */ + public function save($data) + { + $input = JFactory::getApplication()->input; + $filter = JFilterInput::getInstance(); + + // set the metadata to the Item Data + if (isset($data['metadata']) && isset($data['metadata']['author'])) + { + $data['metadata']['author'] = $filter->clean($data['metadata']['author'], 'TRIM'); + + $metadata = new JRegistry; + $metadata->loadArray($data['metadata']); + $data['metadata'] = (string) $metadata; + } + + // Set the addplaceholders items to data. + if (isset($data['addplaceholders']) && is_array($data['addplaceholders'])) + { + $addplaceholders = new JRegistry; + $addplaceholders->loadArray($data['addplaceholders']); + $data['addplaceholders'] = (string) $addplaceholders; + } + elseif (!isset($data['addplaceholders'])) + { + // Set the empty addplaceholders to data + $data['addplaceholders'] = ''; + } + + // Set the Params Items to data + if (isset($data['params']) && is_array($data['params'])) + { + $params = new JRegistry; + $params->loadArray($data['params']); + $data['params'] = (string) $params; + } + + // Alter the uniqe field for save as copy + if ($input->get('task') === 'save2copy') + { + // Automatic handling of other uniqe fields + $uniqeFields = $this->getUniqeFields(); + if (ComponentbuilderHelper::checkArray($uniqeFields)) + { + foreach ($uniqeFields as $uniqeField) + { + $data[$uniqeField] = $this->generateUniqe($uniqeField,$data[$uniqeField]); + } + } + } + + if (parent::save($data)) + { + return true; + } + return false; + } + + /** + * Method to generate a uniqe value. + * + * @param string $field name. + * @param string $value data. + * + * @return string New value. + * + * @since 3.0 + */ + protected function generateUniqe($field,$value) + { + + // set field value uniqe + $table = $this->getTable(); + + while ($table->load(array($field => $value))) + { + $value = JString::increment($value); + } + + return $value; + } + + /** + * Method to change the title + * + * @param string $title The title. + * + * @return array Contains the modified title and alias. + * + */ + protected function _generateNewTitle($title) + { + + // Alter the title + $table = $this->getTable(); + + while ($table->load(array('title' => $title))) + { + $title = JString::increment($title); + } + + return $title; + } +} diff --git a/admin/models/componentbuilder.php b/admin/models/componentbuilder.php index 10e7b1aa2..52b4cc211 100644 --- a/admin/models/componentbuilder.php +++ b/admin/models/componentbuilder.php @@ -25,7 +25,7 @@ class ComponentbuilderModelComponentbuilder extends JModelList $icons = array(); // view groups array $viewGroups = array( - 'main' => array('png.compiler', 'png.joomla_component.add', 'png.joomla_components', 'png.admin_view.add', 'png.admin_views', 'png||importjcbpackages||index.php?option=com_componentbuilder&view=joomla_components&task=joomla_components.smartImport', 'png.custom_admin_view.add', 'png.custom_admin_views', 'png.site_view.add', 'png.site_views', 'png.template.add', 'png.templates', 'png.layout.add', 'png.layouts', 'png.dynamic_get.add', 'png.dynamic_gets', 'png.custom_codes', 'png.libraries', 'png.snippets', 'png.get_snippets', 'png.validation_rules', 'png.field.add', 'png.fields', 'png.fields.catid', 'png.fieldtype.add', 'png.fieldtypes', 'png.fieldtypes.catid', 'png.language_translations', 'png.servers', 'png.help_documents') + 'main' => array('png.compiler', 'png.joomla_component.add', 'png.joomla_components', 'png.admin_view.add', 'png.admin_views', 'png||importjcbpackages||index.php?option=com_componentbuilder&view=joomla_components&task=joomla_components.smartImport', 'png.custom_admin_view.add', 'png.custom_admin_views', 'png.site_view.add', 'png.site_views', 'png.template.add', 'png.templates', 'png.layout.add', 'png.layouts', 'png.dynamic_get.add', 'png.dynamic_gets', 'png.custom_codes', 'png.placeholders', 'png.libraries', 'png.snippets', 'png.get_snippets', 'png.validation_rules', 'png.field.add', 'png.fields', 'png.fields.catid', 'png.fieldtypes', 'png.fieldtypes.catid', 'png.language_translations', 'png.servers', 'png.help_documents') ); // view access array $viewAccess = array( @@ -76,6 +76,11 @@ class ComponentbuilderModelComponentbuilder extends JModelList 'custom_code.access' => 'custom_code.access', 'custom_codes.submenu' => 'custom_code.submenu', 'custom_codes.dashboard_list' => 'custom_code.dashboard_list', + 'placeholder.create' => 'placeholder.create', + 'placeholders.access' => 'placeholder.access', + 'placeholder.access' => 'placeholder.access', + 'placeholders.submenu' => 'placeholder.submenu', + 'placeholders.dashboard_list' => 'placeholder.dashboard_list', 'library.create' => 'library.create', 'libraries.access' => 'library.access', 'library.access' => 'library.access', @@ -101,7 +106,6 @@ class ComponentbuilderModelComponentbuilder extends JModelList 'fieldtype.access' => 'fieldtype.access', 'fieldtypes.submenu' => 'fieldtype.submenu', 'fieldtypes.dashboard_list' => 'fieldtype.dashboard_list', - 'fieldtype.dashboard_add' => 'fieldtype.dashboard_add', 'language_translation.create' => 'language_translation.create', 'language_translations.access' => 'language_translation.access', 'language_translation.access' => 'language_translation.access', @@ -160,6 +164,9 @@ class ComponentbuilderModelComponentbuilder extends JModelList 'component_files_folders.create' => 'component_files_folders.create', 'components_files_folders.access' => 'component_files_folders.access', 'component_files_folders.access' => 'component_files_folders.access', + 'component_placeholders.create' => 'component_placeholders.create', + 'components_placeholders.access' => 'component_placeholders.access', + 'component_placeholders.access' => 'component_placeholders.access', 'snippet_type.create' => 'snippet_type.create', 'snippet_types.access' => 'snippet_type.access', 'snippet_type.access' => 'snippet_type.access', diff --git a/admin/models/components_placeholders.php b/admin/models/components_placeholders.php new file mode 100644 index 000000000..1267253b4 --- /dev/null +++ b/admin/models/components_placeholders.php @@ -0,0 +1,237 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +/** + * Components_placeholders Model + */ +class ComponentbuilderModelComponents_placeholders extends JModelList +{ + public function __construct($config = array()) + { + if (empty($config['filter_fields'])) + { + $config['filter_fields'] = array( + 'a.id','id', + 'a.published','published', + 'a.ordering','ordering', + 'a.created_by','created_by', + 'a.modified_by','modified_by' + ); + } + + parent::__construct($config); + } + + /** + * Method to auto-populate the model state. + * + * @return void + */ + protected function populateState($ordering = null, $direction = null) + { + $app = JFactory::getApplication(); + + // Adjust the context to support modal layouts. + if ($layout = $app->input->get('layout')) + { + $this->context .= '.' . $layout; + } + + + $sorting = $this->getUserStateFromRequest($this->context . '.filter.sorting', 'filter_sorting', 0, 'int'); + $this->setState('filter.sorting', $sorting); + + $access = $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', 0, 'int'); + $this->setState('filter.access', $access); + + $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $published = $this->getUserStateFromRequest($this->context . '.filter.published', 'filter_published', ''); + $this->setState('filter.published', $published); + + $created_by = $this->getUserStateFromRequest($this->context . '.filter.created_by', 'filter_created_by', ''); + $this->setState('filter.created_by', $created_by); + + $created = $this->getUserStateFromRequest($this->context . '.filter.created', 'filter_created'); + $this->setState('filter.created', $created); + + // List state information. + parent::populateState($ordering, $direction); + } + + /** + * Method to get an array of data items. + * + * @return mixed An array of data items on success, false on failure. + */ + public function getItems() + { + // check in items + $this->checkInNow(); + + // load parent items + $items = parent::getItems(); + + // set values to display correctly. + if (ComponentbuilderHelper::checkArray($items)) + { + foreach ($items as $nr => &$item) + { + $access = (JFactory::getUser()->authorise('component_placeholders.access', 'com_componentbuilder.component_placeholders.' . (int) $item->id) && JFactory::getUser()->authorise('component_placeholders.access', 'com_componentbuilder')); + if (!$access) + { + unset($items[$nr]); + continue; + } + + } + } + + // return items + return $items; + } + + /** + * Method to build an SQL query to load the list data. + * + * @return string An SQL query + */ + protected function getListQuery() + { + // Get the user object. + $user = JFactory::getUser(); + // Create a new query object. + $db = JFactory::getDBO(); + $query = $db->getQuery(true); + + // Select some fields + $query->select('a.*'); + + // From the componentbuilder_item table + $query->from($db->quoteName('#__componentbuilder_component_placeholders', 'a')); + + // From the componentbuilder_joomla_component table. + $query->select($db->quoteName('g.system_name','joomla_component_system_name')); + $query->join('LEFT', $db->quoteName('#__componentbuilder_joomla_component', 'g') . ' ON (' . $db->quoteName('a.joomla_component') . ' = ' . $db->quoteName('g.id') . ')'); + + // Filter by published state + $published = $this->getState('filter.published'); + if (is_numeric($published)) + { + $query->where('a.published = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.published = 0 OR a.published = 1)'); + } + + // Join over the asset groups. + $query->select('ag.title AS access_level'); + $query->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + // Implement View Level Access + if (!$user->authorise('core.options', 'com_componentbuilder')) + { + $groups = implode(',', $user->getAuthorisedViewLevels()); + $query->where('a.access IN (' . $groups . ')'); + } + + // Add the list ordering clause. + $orderCol = $this->state->get('list.ordering', 'a.id'); + $orderDirn = $this->state->get('list.direction', 'asc'); + if ($orderCol != '') + { + $query->order($db->escape($orderCol . ' ' . $orderDirn)); + } + + return $query; + } + + /** + * Method to get a store id based on model configuration state. + * + * @return string A store id. + * + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.id'); + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . $this->getState('filter.ordering'); + $id .= ':' . $this->getState('filter.created_by'); + $id .= ':' . $this->getState('filter.modified_by'); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to checkin all items left checked out longer then a set time. + * + * @return a bool + * + */ + protected function checkInNow() + { + // Get set check in time + $time = JComponentHelper::getParams('com_componentbuilder')->get('check_in'); + + if ($time) + { + + // Get a db connection. + $db = JFactory::getDbo(); + // reset query + $query = $db->getQuery(true); + $query->select('*'); + $query->from($db->quoteName('#__componentbuilder_component_placeholders')); + $db->setQuery($query); + $db->execute(); + if ($db->getNumRows()) + { + // Get Yesterdays date + $date = JFactory::getDate()->modify($time)->toSql(); + // reset query + $query = $db->getQuery(true); + + // Fields to update. + $fields = array( + $db->quoteName('checked_out_time') . '=\'0000-00-00 00:00:00\'', + $db->quoteName('checked_out') . '=0' + ); + + // Conditions for which records should be updated. + $conditions = array( + $db->quoteName('checked_out') . '!=0', + $db->quoteName('checked_out_time') . '<\''.$date.'\'' + ); + + // Check table + $query->update($db->quoteName('#__componentbuilder_component_placeholders'))->set($fields)->where($conditions); + + $db->setQuery($query); + + $db->execute(); + } + } + + return false; + } +} diff --git a/admin/models/field.php b/admin/models/field.php index 3c25a6ab3..f1d7c6ec2 100644 --- a/admin/models/field.php +++ b/admin/models/field.php @@ -930,6 +930,16 @@ class ComponentbuilderModelField extends JModelAdmin { // fix the values case 'name': + // check if we have placeholder in name + if (strpos($property['value'], '[[[') !== false || strpos($property['value'], '###') !== false) + { + $property['value'] = trim($property['value']); + } + else + { + $property['value'] = ComponentbuilderHelper::safeString($property['value']); + } + break; case 'type': $property['value'] = ComponentbuilderHelper::safeString($property['value']); break; diff --git a/admin/models/forms/component_placeholders.js b/admin/models/forms/component_placeholders.js new file mode 100644 index 000000000..4bb347a82 --- /dev/null +++ b/admin/models/forms/component_placeholders.js @@ -0,0 +1,11 @@ +/** + * @package Joomla.Component.Builder + * + * @created 30th April, 2015 + * @author Llewellyn van der Merwe + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + + diff --git a/admin/models/forms/component_placeholders.xml b/admin/models/forms/component_placeholders.xml new file mode 100644 index 000000000..d861e5090 --- /dev/null +++ b/admin/models/forms/component_placeholders.xml @@ -0,0 +1,166 @@ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+ \ No newline at end of file diff --git a/admin/models/forms/placeholder.js b/admin/models/forms/placeholder.js new file mode 100644 index 000000000..4bb347a82 --- /dev/null +++ b/admin/models/forms/placeholder.js @@ -0,0 +1,11 @@ +/** + * @package Joomla.Component.Builder + * + * @created 30th April, 2015 + * @author Llewellyn van der Merwe + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + + diff --git a/admin/models/forms/placeholder.xml b/admin/models/forms/placeholder.xml new file mode 100644 index 000000000..83376f8fa --- /dev/null +++ b/admin/models/forms/placeholder.xml @@ -0,0 +1,141 @@ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + +
+
\ No newline at end of file diff --git a/admin/models/import_joomla_components.php b/admin/models/import_joomla_components.php index f0458d32a..90eedcb33 100644 --- a/admin/models/import_joomla_components.php +++ b/admin/models/import_joomla_components.php @@ -702,7 +702,8 @@ class ComponentbuilderModelImport_joomla_components extends JModelLegacy 'template', 'layout', 'joomla_component', 'language', 'language_translation', 'custom_code', 'admin_fields', 'admin_fields_conditions', 'admin_fields_relations', 'admin_custom_tabs', 'component_admin_views', 'component_site_views', 'component_custom_admin_views', 'component_updates', 'component_mysql_tweaks', - 'component_custom_admin_menus', 'component_config', 'component_dashboard', 'component_files_folders' + 'component_custom_admin_menus', 'component_config', 'component_dashboard', 'component_files_folders', + 'component_placeholders' ); // get prefix $prefix = $this->_db->getPrefix(); @@ -2056,6 +2057,14 @@ class ComponentbuilderModelImport_joomla_components extends JModelLegacy // update the repeatable fields $item = ComponentbuilderHelper::convertRepeatableFields($item, $updaterR); break; + case 'component_placeholders': + // diverged id already updated + if (!$diverged) + { + // update the joomla_component ID where needed + $item = $this->setNewID($item, 'joomla_component', 'joomla_component', $type); + } + break; case 'component_files_folders': // diverged id already updated if (!$diverged) @@ -2845,6 +2854,7 @@ class ComponentbuilderModelImport_joomla_components extends JModelLegacy case 'component_custom_admin_menus': case 'component_config': case 'component_dashboard': + case 'component_placeholders': case 'component_files_folders': // get by joomla_component (since there should only be one of each component) $getter = array('joomla_component'); diff --git a/admin/models/joomla_components.php b/admin/models/joomla_components.php index a46edc767..436eb41c0 100644 --- a/admin/models/joomla_components.php +++ b/admin/models/joomla_components.php @@ -298,7 +298,8 @@ class ComponentbuilderModelJoomla_components extends JModelList 'component_updates' => 'joomla_component', 'component_mysql_tweaks' => 'joomla_component', 'component_custom_admin_menus' => 'joomla_component', - 'component_dashboard' => 'joomla_component' ); + 'component_dashboard' => 'joomla_component', + 'component_placeholders' => 'joomla_component' ); // load all tables linked to joomla_component foreach($linkedTables as $table => $field) { @@ -868,7 +869,8 @@ class ComponentbuilderModelJoomla_components extends JModelList 'template', 'layout', 'joomla_component', 'language', 'language_translation', 'custom_code', 'admin_fields', 'admin_fields_conditions', 'admin_fields_relations', 'admin_custom_tabs', 'component_admin_views', 'component_site_views', 'component_custom_admin_views', 'component_updates', 'component_mysql_tweaks', - 'component_custom_admin_menus', 'component_config', 'component_dashboard', 'component_files_folders' + 'component_custom_admin_menus', 'component_config', 'component_dashboard', 'component_files_folders', + 'component_placeholders' ); // smart table loop foreach ($tables as $table) diff --git a/admin/models/placeholder.php b/admin/models/placeholder.php new file mode 100644 index 000000000..06ac6eb57 --- /dev/null +++ b/admin/models/placeholder.php @@ -0,0 +1,889 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +use Joomla\Registry\Registry; + +/** + * Componentbuilder Placeholder Model + */ +class ComponentbuilderModelPlaceholder extends JModelAdmin +{ + /** + * @var string The prefix to use with controller messages. + * @since 1.6 + */ + protected $text_prefix = 'COM_COMPONENTBUILDER'; + + /** + * The type alias for this content type. + * + * @var string + * @since 3.2 + */ + public $typeAlias = 'com_componentbuilder.placeholder'; + + /** + * Returns a Table object, always creating it + * + * @param type $type The table type to instantiate + * @param string $prefix A prefix for the table class name. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return JTable A database object + * + * @since 1.6 + */ + public function getTable($type = 'placeholder', $prefix = 'ComponentbuilderTable', $config = array()) + { + // add table path for when model gets used from other component + $this->addTablePath(JPATH_ADMINISTRATOR . '/components/com_componentbuilder/tables'); + // get instance of the table + return JTable::getInstance($type, $prefix, $config); + } + + public function getVDM() + { + return $this->vastDevMod; + } + + /** + * Method to get a single record. + * + * @param integer $pk The id of the primary key. + * + * @return mixed Object on success, false on failure. + * + * @since 1.6 + */ + public function getItem($pk = null) + { + if ($item = parent::getItem($pk)) + { + if (!empty($item->params) && !is_array($item->params)) + { + // Convert the params field to an array. + $registry = new Registry; + $registry->loadString($item->params); + $item->params = $registry->toArray(); + } + + if (!empty($item->metadata)) + { + // Convert the metadata field to an array. + $registry = new Registry; + $registry->loadString($item->metadata); + $item->metadata = $registry->toArray(); + } + + if (!empty($item->value)) + { + // base64 Decode value. + $item->value = base64_decode($item->value); + } + + + if (empty($item->id)) + { + $id = 0; + } + else + { + $id = $item->id; + } + // set the id and view name to session + if ($vdm = ComponentbuilderHelper::get('placeholder__'.$id)) + { + $this->vastDevMod = $vdm; + } + else + { + // set the vast development method key + $this->vastDevMod = ComponentbuilderHelper::randomkey(50); + ComponentbuilderHelper::set($this->vastDevMod, 'placeholder__'.$id); + ComponentbuilderHelper::set('placeholder__'.$id, $this->vastDevMod); + // set a return value if found + $jinput = JFactory::getApplication()->input; + $return = $jinput->get('return', null, 'base64'); + ComponentbuilderHelper::set($this->vastDevMod . '__return', $return); + } + + if (!empty($item->id)) + { + $item->tags = new JHelperTags; + $item->tags->getTagIds($item->id, 'com_componentbuilder.placeholder'); + } + } + + return $item; + } + + /** + * Method to get the record form. + * + * @param array $data Data for the form. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * @param array $options Optional array of options for the form creation. + * + * @return mixed A JForm object on success, false on failure + * + * @since 1.6 + */ + public function getForm($data = array(), $loadData = true, $options = array('control' => 'jform')) + { + // set load data option + $options['load_data'] = $loadData; + // Get the form. + $form = $this->loadForm('com_componentbuilder.placeholder', 'placeholder', $options); + + if (empty($form)) + { + return false; + } + + $jinput = JFactory::getApplication()->input; + + // The front end calls this model and uses a_id to avoid id clashes so we need to check for that first. + if ($jinput->get('a_id')) + { + $id = $jinput->get('a_id', 0, 'INT'); + } + // The back end uses id so we use that the rest of the time and set it to 0 by default. + else + { + $id = $jinput->get('id', 0, 'INT'); + } + + $user = JFactory::getUser(); + + // Check for existing item. + // Modify the form based on Edit State access controls. + if ($id != 0 && (!$user->authorise('placeholder.edit.state', 'com_componentbuilder.placeholder.' . (int) $id)) + || ($id == 0 && !$user->authorise('placeholder.edit.state', 'com_componentbuilder'))) + { + // Disable fields for display. + $form->setFieldAttribute('ordering', 'disabled', 'true'); + $form->setFieldAttribute('published', 'disabled', 'true'); + // Disable fields while saving. + $form->setFieldAttribute('ordering', 'filter', 'unset'); + $form->setFieldAttribute('published', 'filter', 'unset'); + } + // If this is a new item insure the greated by is set. + if (0 == $id) + { + // Set the created_by to this user + $form->setValue('created_by', null, $user->id); + } + // Modify the form based on Edit Creaded By access controls. + if (!$user->authorise('core.edit.created_by', 'com_componentbuilder')) + { + // Disable fields for display. + $form->setFieldAttribute('created_by', 'disabled', 'true'); + // Disable fields for display. + $form->setFieldAttribute('created_by', 'readonly', 'true'); + // Disable fields while saving. + $form->setFieldAttribute('created_by', 'filter', 'unset'); + } + // Modify the form based on Edit Creaded Date access controls. + if (!$user->authorise('core.edit.created', 'com_componentbuilder')) + { + // Disable fields for display. + $form->setFieldAttribute('created', 'disabled', 'true'); + // Disable fields while saving. + $form->setFieldAttribute('created', 'filter', 'unset'); + } + // Only load these values if no id is found + if (0 == $id) + { + // Set redirected view name + $redirectedView = $jinput->get('ref', null, 'STRING'); + // Set field name (or fall back to view name) + $redirectedField = $jinput->get('field', $redirectedView, 'STRING'); + // Set redirected view id + $redirectedId = $jinput->get('refid', 0, 'INT'); + // Set field id (or fall back to redirected view id) + $redirectedValue = $jinput->get('field_id', $redirectedId, 'INT'); + if (0 != $redirectedValue && $redirectedField) + { + // Now set the local-redirected field default value + $form->setValue($redirectedField, null, $redirectedValue); + } + } + return $form; + } + + /** + * Method to get the script that have to be included on the form + * + * @return string script files + */ + public function getScript() + { + return 'administrator/components/com_componentbuilder/models/forms/placeholder.js'; + } + + /** + * Method to test whether a record can be deleted. + * + * @param object $record A record object. + * + * @return boolean True if allowed to delete the record. Defaults to the permission set in the component. + * + * @since 1.6 + */ + protected function canDelete($record) + { + if (!empty($record->id)) + { + if ($record->published != -2) + { + return; + } + + $user = JFactory::getUser(); + // The record has been set. Check the record permissions. + return $user->authorise('placeholder.delete', 'com_componentbuilder.placeholder.' . (int) $record->id); + } + return false; + } + + /** + * Method to test whether a record can have its state edited. + * + * @param object $record A record object. + * + * @return boolean True if allowed to change the state of the record. Defaults to the permission set in the component. + * + * @since 1.6 + */ + protected function canEditState($record) + { + $user = JFactory::getUser(); + $recordId = (!empty($record->id)) ? $record->id : 0; + + if ($recordId) + { + // The record has been set. Check the record permissions. + $permission = $user->authorise('placeholder.edit.state', 'com_componentbuilder.placeholder.' . (int) $recordId); + if (!$permission && !is_null($permission)) + { + return false; + } + } + // In the absense of better information, revert to the component permissions. + return $user->authorise('placeholder.edit.state', 'com_componentbuilder'); + } + + /** + * Method override to check if you can edit an existing record. + * + * @param array $data An array of input data. + * @param string $key The name of the key for the primary key. + * + * @return boolean + * @since 2.5 + */ + protected function allowEdit($data = array(), $key = 'id') + { + // Check specific edit permission then general edit permission. + $user = JFactory::getUser(); + + return $user->authorise('placeholder.edit', 'com_componentbuilder.placeholder.'. ((int) isset($data[$key]) ? $data[$key] : 0)) or $user->authorise('placeholder.edit', 'com_componentbuilder'); + } + + /** + * Prepare and sanitise the table data prior to saving. + * + * @param JTable $table A JTable object. + * + * @return void + * + * @since 1.6 + */ + protected function prepareTable($table) + { + $date = JFactory::getDate(); + $user = JFactory::getUser(); + + if (isset($table->name)) + { + $table->name = htmlspecialchars_decode($table->name, ENT_QUOTES); + } + + if (isset($table->alias) && empty($table->alias)) + { + $table->generateAlias(); + } + + if (empty($table->id)) + { + $table->created = $date->toSql(); + // set the user + if ($table->created_by == 0 || empty($table->created_by)) + { + $table->created_by = $user->id; + } + // Set ordering to the last item if not set + if (empty($table->ordering)) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select('MAX(ordering)') + ->from($db->quoteName('#__componentbuilder_placeholder')); + $db->setQuery($query); + $max = $db->loadResult(); + + $table->ordering = $max + 1; + } + } + else + { + $table->modified = $date->toSql(); + $table->modified_by = $user->id; + } + + if (!empty($table->id)) + { + // Increment the items version number. + $table->version++; + } + } + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 1.6 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = JFactory::getApplication()->getUserState('com_componentbuilder.edit.placeholder.data', array()); + + if (empty($data)) + { + $data = $this->getItem(); + } + + return $data; + } + + /** + * Method to get the unique fields of this table. + * + * @return mixed An array of field names, boolean false if none is set. + * + * @since 3.0 + */ + protected function getUniqeFields() + { + return false; + } + + /** + * Method to delete one or more records. + * + * @param array &$pks An array of record primary keys. + * + * @return boolean True if successful, false if an error occurs. + * + * @since 12.2 + */ + public function delete(&$pks) + { + if (!parent::delete($pks)) + { + return false; + } + + return true; + } + + /** + * Method to change the published state of one or more records. + * + * @param array &$pks A list of the primary keys to change. + * @param integer $value The value of the published state. + * + * @return boolean True on success. + * + * @since 12.2 + */ + public function publish(&$pks, $value = 1) + { + if (!parent::publish($pks, $value)) + { + return false; + } + + return true; + } + + /** + * Method to perform batch operations on an item or a set of items. + * + * @param array $commands An array of commands to perform. + * @param array $pks An array of item ids. + * @param array $contexts An array of item contexts. + * + * @return boolean Returns true on success, false on failure. + * + * @since 12.2 + */ + public function batch($commands, $pks, $contexts) + { + // Sanitize ids. + $pks = array_unique($pks); + JArrayHelper::toInteger($pks); + + // Remove any values of zero. + if (array_search(0, $pks, true)) + { + unset($pks[array_search(0, $pks, true)]); + } + + if (empty($pks)) + { + $this->setError(JText::_('JGLOBAL_NO_ITEM_SELECTED')); + return false; + } + + $done = false; + + // Set some needed variables. + $this->user = JFactory::getUser(); + $this->table = $this->getTable(); + $this->tableClassName = get_class($this->table); + $this->contentType = new JUcmType; + $this->type = $this->contentType->getTypeByTable($this->tableClassName); + $this->canDo = ComponentbuilderHelper::getActions('placeholder'); + $this->batchSet = true; + + if (!$this->canDo->get('core.batch')) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION')); + return false; + } + + if ($this->type == false) + { + $type = new JUcmType; + $this->type = $type->getTypeByAlias($this->typeAlias); + } + + $this->tagsObserver = $this->table->getObserverOfClass('JTableObserverTags'); + + if (!empty($commands['move_copy'])) + { + $cmd = JArrayHelper::getValue($commands, 'move_copy', 'c'); + + if ($cmd == 'c') + { + $result = $this->batchCopy($commands, $pks, $contexts); + + if (is_array($result)) + { + foreach ($result as $old => $new) + { + $contexts[$new] = $contexts[$old]; + } + $pks = array_values($result); + } + else + { + return false; + } + } + elseif ($cmd == 'm' && !$this->batchMove($commands, $pks, $contexts)) + { + return false; + } + + $done = true; + } + + if (!$done) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION')); + + return false; + } + + // Clear the cache + $this->cleanCache(); + + return true; + } + + /** + * Batch copy items to a new category or current. + * + * @param integer $values The new values. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return mixed An array of new IDs on success, boolean false on failure. + * + * @since 12.2 + */ + protected function batchCopy($values, $pks, $contexts) + { + if (empty($this->batchSet)) + { + // Set some needed variables. + $this->user = JFactory::getUser(); + $this->table = $this->getTable(); + $this->tableClassName = get_class($this->table); + $this->canDo = ComponentbuilderHelper::getActions('placeholder'); + } + + if (!$this->canDo->get('placeholder.create') && !$this->canDo->get('placeholder.batch')) + { + return false; + } + + // get list of uniqe fields + $uniqeFields = $this->getUniqeFields(); + // remove move_copy from array + unset($values['move_copy']); + + // make sure published is set + if (!isset($values['published'])) + { + $values['published'] = 0; + } + elseif (isset($values['published']) && !$this->canDo->get('placeholder.edit.state')) + { + $values['published'] = 0; + } + + $newIds = array(); + // Parent exists so let's proceed + while (!empty($pks)) + { + // Pop the first ID off the stack + $pk = array_shift($pks); + + $this->table->reset(); + + // only allow copy if user may edit this item. + if (!$this->user->authorise('placeholder.edit', $contexts[$pk])) + { + // Not fatal error + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + + // Check that the row actually exists + if (!$this->table->load($pk)) + { + if ($error = $this->table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // Only for strings + if (ComponentbuilderHelper::checkString($this->table->target) && !is_numeric($this->table->target)) + { + $this->table->target = $this->generateUniqe('target',$this->table->target); + } + + // insert all set values + if (ComponentbuilderHelper::checkArray($values)) + { + foreach ($values as $key => $value) + { + if (strlen($value) > 0 && isset($this->table->$key)) + { + $this->table->$key = $value; + } + } + } + + // update all uniqe fields + if (ComponentbuilderHelper::checkArray($uniqeFields)) + { + foreach ($uniqeFields as $uniqeField) + { + $this->table->$uniqeField = $this->generateUniqe($uniqeField,$this->table->$uniqeField); + } + } + + // Reset the ID because we are making a copy + $this->table->id = 0; + + // TODO: Deal with ordering? + // $this->table->ordering = 1; + + // Check the row. + if (!$this->table->check()) + { + $this->setError($this->table->getError()); + + return false; + } + + if (!empty($this->type)) + { + $this->createTagsHelper($this->tagsObserver, $this->type, $pk, $this->typeAlias, $this->table); + } + + // Store the row. + if (!$this->table->store()) + { + $this->setError($this->table->getError()); + + return false; + } + + // Get the new item ID + $newId = $this->table->get('id'); + + // Add the new ID to the array + $newIds[$pk] = $newId; + } + + // Clean the cache + $this->cleanCache(); + + return $newIds; + } + + /** + * Batch move items to a new category + * + * @param integer $value The new category ID. + * @param array $pks An array of row IDs. + * @param array $contexts An array of item contexts. + * + * @return boolean True if successful, false otherwise and internal error is set. + * + * @since 12.2 + */ + protected function batchMove($values, $pks, $contexts) + { + if (empty($this->batchSet)) + { + // Set some needed variables. + $this->user = JFactory::getUser(); + $this->table = $this->getTable(); + $this->tableClassName = get_class($this->table); + $this->canDo = ComponentbuilderHelper::getActions('placeholder'); + } + + if (!$this->canDo->get('placeholder.edit') && !$this->canDo->get('placeholder.batch')) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); + return false; + } + + // make sure published only updates if user has the permission. + if (isset($values['published']) && !$this->canDo->get('placeholder.edit.state')) + { + unset($values['published']); + } + // remove move_copy from array + unset($values['move_copy']); + + // Parent exists so we proceed + foreach ($pks as $pk) + { + if (!$this->user->authorise('placeholder.edit', $contexts[$pk])) + { + $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT')); + return false; + } + + // Check that the row actually exists + if (!$this->table->load($pk)) + { + if ($error = $this->table->getError()) + { + // Fatal error + $this->setError($error); + return false; + } + else + { + // Not fatal error + $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk)); + continue; + } + } + + // insert all set values. + if (ComponentbuilderHelper::checkArray($values)) + { + foreach ($values as $key => $value) + { + // Do special action for access. + if ('access' === $key && strlen($value) > 0) + { + $this->table->$key = $value; + } + elseif (strlen($value) > 0 && isset($this->table->$key)) + { + $this->table->$key = $value; + } + } + } + + + // Check the row. + if (!$this->table->check()) + { + $this->setError($this->table->getError()); + + return false; + } + + if (!empty($this->type)) + { + $this->createTagsHelper($this->tagsObserver, $this->type, $pk, $this->typeAlias, $this->table); + } + + // Store the row. + if (!$this->table->store()) + { + $this->setError($this->table->getError()); + + return false; + } + } + + // Clean the cache + $this->cleanCache(); + + return true; + } + + /** + * Method to save the form data. + * + * @param array $data The form data. + * + * @return boolean True on success. + * + * @since 1.6 + */ + public function save($data) + { + $input = JFactory::getApplication()->input; + $filter = JFilterInput::getInstance(); + + // set the metadata to the Item Data + if (isset($data['metadata']) && isset($data['metadata']['author'])) + { + $data['metadata']['author'] = $filter->clean($data['metadata']['author'], 'TRIM'); + + $metadata = new JRegistry; + $metadata->loadArray($data['metadata']); + $data['metadata'] = (string) $metadata; + } + + // make sure no padding is set + $data['target'] = str_replace(array('[', ']', '#'), '', $data['target']); + // add the padding (needed) + $data['target'] = '[[[' . trim($data['target']) . ']]]'; + + // Set the value string to base64 string. + if (isset($data['value'])) + { + $data['value'] = base64_encode($data['value']); + } + + // Set the Params Items to data + if (isset($data['params']) && is_array($data['params'])) + { + $params = new JRegistry; + $params->loadArray($data['params']); + $data['params'] = (string) $params; + } + + // Alter the uniqe field for save as copy + if ($input->get('task') === 'save2copy') + { + // Automatic handling of other uniqe fields + $uniqeFields = $this->getUniqeFields(); + if (ComponentbuilderHelper::checkArray($uniqeFields)) + { + foreach ($uniqeFields as $uniqeField) + { + $data[$uniqeField] = $this->generateUniqe($uniqeField,$data[$uniqeField]); + } + } + } + + if (parent::save($data)) + { + return true; + } + return false; + } + + /** + * Method to generate a uniqe value. + * + * @param string $field name. + * @param string $value data. + * + * @return string New value. + * + * @since 3.0 + */ + protected function generateUniqe($field,$value) + { + + // set field value uniqe + $table = $this->getTable(); + + while ($table->load(array($field => $value))) + { + $value = JString::increment($value); + } + + return $value; + } + + /** + * Method to change the title + * + * @param string $title The title. + * + * @return array Contains the modified title and alias. + * + */ + protected function _generateNewTitle($title) + { + + // Alter the title + $table = $this->getTable(); + + while ($table->load(array('title' => $title))) + { + $title = JString::increment($title); + } + + return $title; + } +} diff --git a/admin/models/placeholders.php b/admin/models/placeholders.php new file mode 100644 index 000000000..8deb3cb00 --- /dev/null +++ b/admin/models/placeholders.php @@ -0,0 +1,358 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +/** + * Placeholders Model + */ +class ComponentbuilderModelPlaceholders extends JModelList +{ + public function __construct($config = array()) + { + if (empty($config['filter_fields'])) + { + $config['filter_fields'] = array( + 'a.id','id', + 'a.published','published', + 'a.ordering','ordering', + 'a.created_by','created_by', + 'a.modified_by','modified_by', + 'a.target','target', + 'a.value','value' + ); + } + + parent::__construct($config); + } + + /** + * Method to auto-populate the model state. + * + * @return void + */ + protected function populateState($ordering = null, $direction = null) + { + $app = JFactory::getApplication(); + + // Adjust the context to support modal layouts. + if ($layout = $app->input->get('layout')) + { + $this->context .= '.' . $layout; + } + $target = $this->getUserStateFromRequest($this->context . '.filter.target', 'filter_target'); + $this->setState('filter.target', $target); + + $value = $this->getUserStateFromRequest($this->context . '.filter.value', 'filter_value'); + $this->setState('filter.value', $value); + + $sorting = $this->getUserStateFromRequest($this->context . '.filter.sorting', 'filter_sorting', 0, 'int'); + $this->setState('filter.sorting', $sorting); + + $access = $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', 0, 'int'); + $this->setState('filter.access', $access); + + $search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search'); + $this->setState('filter.search', $search); + + $published = $this->getUserStateFromRequest($this->context . '.filter.published', 'filter_published', ''); + $this->setState('filter.published', $published); + + $created_by = $this->getUserStateFromRequest($this->context . '.filter.created_by', 'filter_created_by', ''); + $this->setState('filter.created_by', $created_by); + + $created = $this->getUserStateFromRequest($this->context . '.filter.created', 'filter_created'); + $this->setState('filter.created', $created); + + // List state information. + parent::populateState($ordering, $direction); + } + + /** + * Method to get an array of data items. + * + * @return mixed An array of data items on success, false on failure. + */ + public function getItems() + { + // check in items + $this->checkInNow(); + + // load parent items + $items = parent::getItems(); + + // set values to display correctly. + if (ComponentbuilderHelper::checkArray($items)) + { + foreach ($items as $nr => &$item) + { + $access = (JFactory::getUser()->authorise('placeholder.access', 'com_componentbuilder.placeholder.' . (int) $item->id) && JFactory::getUser()->authorise('placeholder.access', 'com_componentbuilder')); + if (!$access) + { + unset($items[$nr]); + continue; + } + + // decode value + $item->value = base64_decode($item->value); + } + } + + // return items + return $items; + } + + /** + * Method to build an SQL query to load the list data. + * + * @return string An SQL query + */ + protected function getListQuery() + { + // Get the user object. + $user = JFactory::getUser(); + // Create a new query object. + $db = JFactory::getDBO(); + $query = $db->getQuery(true); + + // Select some fields + $query->select('a.*'); + + // From the componentbuilder_item table + $query->from($db->quoteName('#__componentbuilder_placeholder', 'a')); + + // Filter by published state + $published = $this->getState('filter.published'); + if (is_numeric($published)) + { + $query->where('a.published = ' . (int) $published); + } + elseif ($published === '') + { + $query->where('(a.published = 0 OR a.published = 1)'); + } + + // Join over the asset groups. + $query->select('ag.title AS access_level'); + $query->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access'); + // Filter by access level. + if ($access = $this->getState('filter.access')) + { + $query->where('a.access = ' . (int) $access); + } + // Implement View Level Access + if (!$user->authorise('core.options', 'com_componentbuilder')) + { + $groups = implode(',', $user->getAuthorisedViewLevels()); + $query->where('a.access IN (' . $groups . ')'); + } + // Filter by search. + $search = $this->getState('filter.search'); + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + else + { + $search = $db->quote('%' . $db->escape($search) . '%'); + $query->where('(a.target LIKE '.$search.' OR a.value LIKE '.$search.')'); + } + } + + + // Add the list ordering clause. + $orderCol = $this->state->get('list.ordering', 'a.id'); + $orderDirn = $this->state->get('list.direction', 'asc'); + if ($orderCol != '') + { + $query->order($db->escape($orderCol . ' ' . $orderDirn)); + } + + return $query; + } + + /** + * Method to get list export data. + * + * @return mixed An array of data items on success, false on failure. + */ + public function getExportData($pks) + { + // setup the query + if (ComponentbuilderHelper::checkArray($pks)) + { + // Set a value to know this is exporting method. + $_export = true; + // Get the user object. + $user = JFactory::getUser(); + // Create a new query object. + $db = JFactory::getDBO(); + $query = $db->getQuery(true); + + // Select some fields + $query->select('a.*'); + + // From the componentbuilder_placeholder table + $query->from($db->quoteName('#__componentbuilder_placeholder', 'a')); + $query->where('a.id IN (' . implode(',',$pks) . ')'); + // Implement View Level Access + if (!$user->authorise('core.options', 'com_componentbuilder')) + { + $groups = implode(',', $user->getAuthorisedViewLevels()); + $query->where('a.access IN (' . $groups . ')'); + } + + // Order the results by ordering + $query->order('a.ordering ASC'); + + // Load the items + $db->setQuery($query); + $db->execute(); + if ($db->getNumRows()) + { + $items = $db->loadObjectList(); + + // set values to display correctly. + if (ComponentbuilderHelper::checkArray($items)) + { + foreach ($items as $nr => &$item) + { + $access = (JFactory::getUser()->authorise('placeholder.access', 'com_componentbuilder.placeholder.' . (int) $item->id) && JFactory::getUser()->authorise('placeholder.access', 'com_componentbuilder')); + if (!$access) + { + unset($items[$nr]); + continue; + } + + // decode value + $item->value = base64_decode($item->value); + // unset the values we don't want exported. + unset($item->asset_id); + unset($item->checked_out); + unset($item->checked_out_time); + } + } + // Add headers to items array. + $headers = $this->getExImPortHeaders(); + if (ComponentbuilderHelper::checkObject($headers)) + { + array_unshift($items,$headers); + } + return $items; + } + } + return false; + } + + /** + * Method to get header. + * + * @return mixed An array of data items on success, false on failure. + */ + public function getExImPortHeaders() + { + // Get a db connection. + $db = JFactory::getDbo(); + // get the columns + $columns = $db->getTableColumns("#__componentbuilder_placeholder"); + if (ComponentbuilderHelper::checkArray($columns)) + { + // remove the headers you don't import/export. + unset($columns['asset_id']); + unset($columns['checked_out']); + unset($columns['checked_out_time']); + $headers = new stdClass(); + foreach ($columns as $column => $type) + { + $headers->{$column} = $column; + } + return $headers; + } + return false; + } + + /** + * Method to get a store id based on model configuration state. + * + * @return string A store id. + * + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.id'); + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.published'); + $id .= ':' . $this->getState('filter.ordering'); + $id .= ':' . $this->getState('filter.created_by'); + $id .= ':' . $this->getState('filter.modified_by'); + $id .= ':' . $this->getState('filter.target'); + $id .= ':' . $this->getState('filter.value'); + + return parent::getStoreId($id); + } + + /** + * Build an SQL query to checkin all items left checked out longer then a set time. + * + * @return a bool + * + */ + protected function checkInNow() + { + // Get set check in time + $time = JComponentHelper::getParams('com_componentbuilder')->get('check_in'); + + if ($time) + { + + // Get a db connection. + $db = JFactory::getDbo(); + // reset query + $query = $db->getQuery(true); + $query->select('*'); + $query->from($db->quoteName('#__componentbuilder_placeholder')); + $db->setQuery($query); + $db->execute(); + if ($db->getNumRows()) + { + // Get Yesterdays date + $date = JFactory::getDate()->modify($time)->toSql(); + // reset query + $query = $db->getQuery(true); + + // Fields to update. + $fields = array( + $db->quoteName('checked_out_time') . '=\'0000-00-00 00:00:00\'', + $db->quoteName('checked_out') . '=0' + ); + + // Conditions for which records should be updated. + $conditions = array( + $db->quoteName('checked_out') . '!=0', + $db->quoteName('checked_out_time') . '<\''.$date.'\'' + ); + + // Check table + $query->update($db->quoteName('#__componentbuilder_placeholder'))->set($fields)->where($conditions); + + $db->setQuery($query); + + $db->execute(); + } + } + + return false; + } +} diff --git a/admin/models/rules/uniqueplaceholder.php b/admin/models/rules/uniqueplaceholder.php new file mode 100644 index 000000000..9b478f680 --- /dev/null +++ b/admin/models/rules/uniqueplaceholder.php @@ -0,0 +1,87 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('JPATH_PLATFORM') or die; + +use Joomla\CMS\Form\Form; +use Joomla\CMS\Form\FormRule; +use Joomla\Registry\Registry; + +/** + * Form Rule (Uniqueplaceholder) class for the Joomla Platform. + */ +class JFormRuleUniqueplaceholder extends FormRule +{ + /** + * Method to test the field value for uniqueness. + * + * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `` tag for the form field object. + * @param mixed $value The form field value to validate. + * @param string $group The field name group control value. This acts as an array container for the field. + * For example if the field has name="foo" and the group value is set to "bar" then the + * full field name would end up being "bar[foo]". + * @param Registry $input An optional Registry object with the entire data set to validate against the entire form. + * @param Form $form The form object for which the field is being tested. + * + * @return boolean True if the value is valid, false otherwise. + * + * @since 11.1 + */ + public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) + { + // Get the database object and a new query object. + $db = \JFactory::getDbo(); + $query = $db->getQuery(true); + + // Get the extra field check attribute. + $id = ($input instanceof Registry) ? $input->get('id', null) : null; + + // get the component & table name + $table = ($form instanceof Form) ? $form->getName() : ''; + + // get the column name + $name = (array) $element->attributes()->{'name'}; + $column = (string) trim($name[0]); + + // check that we have a value + if (strlen($table) > 3 && strpos($table, 'componentbuilder.') !== false) + { + // now get the table name + $tableArray = explode('.', $table); + // do we have two values + if (count( (array) $tableArray) == 2) + { + // Build the query. + $query->select('COUNT(*)') + ->from('#__componentbuilder_' . (string) $tableArray[1]) + ->where($db->quoteName($column) . ' = ' . $db->quote($value)); + + // remove this item from the list + if ($id > 0) + { + $query->where($db->quoteName('id') . ' <> ' . (int) $id); + } + + // Set and query the database. + $db->setQuery($query); + $duplicate = (bool) $db->loadResult(); + + if ($duplicate) + { + return false; + } + } + } + // now test against all the placeholders in the compiler + return ComponentbuilderHelper::validateUniquePlaceholder($value); + } +} diff --git a/admin/sql/install.mysql.utf8.sql b/admin/sql/install.mysql.utf8.sql index 4841f15ba..aa4ee5f93 100644 --- a/admin/sql/install.mysql.utf8.sql +++ b/admin/sql/install.mysql.utf8.sql @@ -611,6 +611,32 @@ CREATE TABLE IF NOT EXISTS `#__componentbuilder_custom_code` ( KEY `idx_from_line` (`from_line`) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; +CREATE TABLE IF NOT EXISTS `#__componentbuilder_placeholder` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.', + `target` VARCHAR(255) NOT NULL DEFAULT '', + `value` TEXT NOT NULL, + `params` text NOT NULL DEFAULT '', + `published` TINYINT(3) NOT NULL DEFAULT 1, + `created_by` INT(10) unsigned NOT NULL DEFAULT 0, + `modified_by` INT(10) unsigned NOT NULL DEFAULT 0, + `created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `checked_out` int(11) unsigned NOT NULL DEFAULT 0, + `checked_out_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `version` INT(10) unsigned NOT NULL DEFAULT 1, + `hits` INT(10) unsigned NOT NULL DEFAULT 0, + `access` INT(10) unsigned NOT NULL DEFAULT 0, + `ordering` INT(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + KEY `idx_access` (`access`), + KEY `idx_checkout` (`checked_out`), + KEY `idx_createdby` (`created_by`), + KEY `idx_modifiedby` (`modified_by`), + KEY `idx_state` (`published`), + KEY `idx_target` (`target`) +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; + CREATE TABLE IF NOT EXISTS `#__componentbuilder_library` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.', @@ -1268,6 +1294,32 @@ CREATE TABLE IF NOT EXISTS `#__componentbuilder_component_files_folders` ( KEY `idx_joomla_component` (`joomla_component`) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; +CREATE TABLE IF NOT EXISTS `#__componentbuilder_component_placeholders` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.', + `addplaceholders` TEXT NOT NULL, + `joomla_component` INT(11) NOT NULL DEFAULT 0, + `params` text NOT NULL DEFAULT '', + `published` TINYINT(3) NOT NULL DEFAULT 1, + `created_by` INT(10) unsigned NOT NULL DEFAULT 0, + `modified_by` INT(10) unsigned NOT NULL DEFAULT 0, + `created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `checked_out` int(11) unsigned NOT NULL DEFAULT 0, + `checked_out_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `version` INT(10) unsigned NOT NULL DEFAULT 1, + `hits` INT(10) unsigned NOT NULL DEFAULT 0, + `access` INT(10) unsigned NOT NULL DEFAULT 0, + `ordering` INT(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + KEY `idx_access` (`access`), + KEY `idx_checkout` (`checked_out`), + KEY `idx_createdby` (`created_by`), + KEY `idx_modifiedby` (`modified_by`), + KEY `idx_state` (`published`), + KEY `idx_joomla_component` (`joomla_component`) +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; + CREATE TABLE IF NOT EXISTS `#__componentbuilder_snippet_type` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.', diff --git a/admin/sql/uninstall.mysql.utf8.sql b/admin/sql/uninstall.mysql.utf8.sql index d69e8c43d..6dbe36b9e 100644 --- a/admin/sql/uninstall.mysql.utf8.sql +++ b/admin/sql/uninstall.mysql.utf8.sql @@ -6,6 +6,7 @@ DROP TABLE IF EXISTS `#__componentbuilder_template`; DROP TABLE IF EXISTS `#__componentbuilder_layout`; DROP TABLE IF EXISTS `#__componentbuilder_dynamic_get`; DROP TABLE IF EXISTS `#__componentbuilder_custom_code`; +DROP TABLE IF EXISTS `#__componentbuilder_placeholder`; DROP TABLE IF EXISTS `#__componentbuilder_library`; DROP TABLE IF EXISTS `#__componentbuilder_snippet`; DROP TABLE IF EXISTS `#__componentbuilder_validation_rule`; @@ -28,6 +29,7 @@ DROP TABLE IF EXISTS `#__componentbuilder_component_custom_admin_menus`; DROP TABLE IF EXISTS `#__componentbuilder_component_config`; DROP TABLE IF EXISTS `#__componentbuilder_component_dashboard`; DROP TABLE IF EXISTS `#__componentbuilder_component_files_folders`; +DROP TABLE IF EXISTS `#__componentbuilder_component_placeholders`; DROP TABLE IF EXISTS `#__componentbuilder_snippet_type`; DROP TABLE IF EXISTS `#__componentbuilder_library_config`; DROP TABLE IF EXISTS `#__componentbuilder_library_files_folders_urls`; diff --git a/admin/sql/updates/mysql/2.9.11.sql b/admin/sql/updates/mysql/2.9.11.sql new file mode 100644 index 000000000..05b838cc6 --- /dev/null +++ b/admin/sql/updates/mysql/2.9.11.sql @@ -0,0 +1,25 @@ +CREATE TABLE IF NOT EXISTS `#__componentbuilder_component_placeholders` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.', + `addplaceholders` TEXT NOT NULL, + `joomla_component` INT(11) NOT NULL DEFAULT 0, + `params` text NOT NULL DEFAULT '', + `published` TINYINT(3) NOT NULL DEFAULT 1, + `created_by` INT(10) unsigned NOT NULL DEFAULT 0, + `modified_by` INT(10) unsigned NOT NULL DEFAULT 0, + `created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `checked_out` int(11) unsigned NOT NULL DEFAULT 0, + `checked_out_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `version` INT(10) unsigned NOT NULL DEFAULT 1, + `hits` INT(10) unsigned NOT NULL DEFAULT 0, + `access` INT(10) unsigned NOT NULL DEFAULT 0, + `ordering` INT(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + KEY `idx_access` (`access`), + KEY `idx_checkout` (`checked_out`), + KEY `idx_createdby` (`created_by`), + KEY `idx_modifiedby` (`modified_by`), + KEY `idx_state` (`published`), + KEY `idx_joomla_component` (`joomla_component`) +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; diff --git a/admin/sql/updates/mysql/2.9.12.sql b/admin/sql/updates/mysql/2.9.12.sql new file mode 100644 index 000000000..1f1683461 --- /dev/null +++ b/admin/sql/updates/mysql/2.9.12.sql @@ -0,0 +1,25 @@ +CREATE TABLE IF NOT EXISTS `#__componentbuilder_placeholder` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `asset_id` INT(10) unsigned NOT NULL DEFAULT 0 COMMENT 'FK to the #__assets table.', + `target` VARCHAR(255) NOT NULL DEFAULT '', + `value` TEXT NOT NULL, + `params` text NOT NULL DEFAULT '', + `published` TINYINT(3) NOT NULL DEFAULT 1, + `created_by` INT(10) unsigned NOT NULL DEFAULT 0, + `modified_by` INT(10) unsigned NOT NULL DEFAULT 0, + `created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `checked_out` int(11) unsigned NOT NULL DEFAULT 0, + `checked_out_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `version` INT(10) unsigned NOT NULL DEFAULT 1, + `hits` INT(10) unsigned NOT NULL DEFAULT 0, + `access` INT(10) unsigned NOT NULL DEFAULT 0, + `ordering` INT(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + KEY `idx_access` (`access`), + KEY `idx_checkout` (`checked_out`), + KEY `idx_createdby` (`created_by`), + KEY `idx_modifiedby` (`modified_by`), + KEY `idx_state` (`published`), + KEY `idx_target` (`target`) +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; diff --git a/admin/tables/component_placeholders.php b/admin/tables/component_placeholders.php new file mode 100644 index 000000000..88a89a9c4 --- /dev/null +++ b/admin/tables/component_placeholders.php @@ -0,0 +1,321 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +use Joomla\Registry\Registry; + +/** + * Components_placeholders Table class + */ +class ComponentbuilderTableComponent_placeholders extends JTable +{ + /** + * Ensure the params and metadata in json encoded in the bind method + * + * @var array + * @since 3.3 + */ + protected $_jsonEncode = array('params', 'metadata'); + + /** + * Constructor + * + * @param object Database connector object + */ + function __construct(&$db) + { + parent::__construct('#__componentbuilder_component_placeholders', 'id', $db); + + // Adding History Options + JTableObserverContenthistory::createObserver($this, array('typeAlias' => 'com_componentbuilder.component_placeholders')); + } + + public function bind($array, $ignore = '') + { + + if (isset($array['params']) && is_array($array['params'])) + { + $registry = new JRegistry; + $registry->loadArray($array['params']); + $array['params'] = (string) $registry; + } + + if (isset($array['metadata']) && is_array($array['metadata'])) + { + $registry = new JRegistry; + $registry->loadArray($array['metadata']); + $array['metadata'] = (string) $registry; + } + + // Bind the rules. + if (isset($array['rules']) && is_array($array['rules'])) + { + $rules = new JAccessRules($array['rules']); + $this->setRules($rules); + } + return parent::bind($array, $ignore); + } + + /** + * Overload the store method for the Component_placeholders table. + * + * @param boolean Toggle whether null values should be updated. + * @return boolean True on success, false on failure. + * @since 1.6 + */ + public function store($updateNulls = false) + { + $date = JFactory::getDate(); + $user = JFactory::getUser(); + + if ($this->id) + { + // Existing item + $this->modified = $date->toSql(); + $this->modified_by = $user->get('id'); + } + else + { + // New component_placeholders. A component_placeholders created and created_by field can be set by the user, + // so we don't touch either of these if they are set. + if (!(int) $this->created) + { + $this->created = $date->toSql(); + } + if (empty($this->created_by)) + { + $this->created_by = $user->get('id'); + } + } + + if (isset($this->alias)) + { + // Verify that the alias is unique + $table = JTable::getInstance('component_placeholders', 'ComponentbuilderTable'); + + if ($table->load(array('alias' => $this->alias)) && ($table->id != $this->id || $this->id == 0)) + { + $this->setError(JText::_('COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_ERROR_UNIQUE_ALIAS')); + return false; + } + } + + if (isset($this->url)) + { + // Convert IDN urls to punycode + $this->url = JStringPunycode::urlToPunycode($this->url); + } + if (isset($this->website)) + { + // Convert IDN urls to punycode + $this->website = JStringPunycode::urlToPunycode($this->website); + } + + return parent::store($updateNulls); + } + + /** + * Overloaded check method to ensure data integrity. + * + * @return boolean True on success. + */ + public function check() + { + if (isset($this->alias)) + { + // Generate a valid alias + $this->generateAlias(); + + $table = JTable::getInstance('component_placeholders', 'componentbuilderTable'); + + while ($table->load(array('alias' => $this->alias)) && ($table->id != $this->id || $this->id == 0)) + { + $this->alias = JString::increment($this->alias, 'dash'); + } + } + + /* + * Clean up keywords -- eliminate extra spaces between phrases + * and cr (\r) and lf (\n) characters from string. + * Only process if not empty. + */ + if (!empty($this->metakey)) + { + // Array of characters to remove. + $bad_characters = array("\n", "\r", "\"", "<", ">"); + + // Remove bad characters. + $after_clean = JString::str_ireplace($bad_characters, "", $this->metakey); + + // Create array using commas as delimiter. + $keys = explode(',', $after_clean); + $clean_keys = array(); + + foreach ($keys as $key) + { + // Ignore blank keywords. + if (trim($key)) + { + $clean_keys[] = trim($key); + } + } + + // Put array back together delimited by ", " + $this->metakey = implode(", ", $clean_keys); + } + + // Clean up description -- eliminate quotes and <> brackets + if (!empty($this->metadesc)) + { + // Only process if not empty + $bad_characters = array("\"", "<", ">"); + $this->metadesc = JString::str_ireplace($bad_characters, "", $this->metadesc); + } + + // If we don't have any access rules set at this point just use an empty JAccessRules class + if (!$this->getRules()) + { + $rules = $this->getDefaultAssetValues('com_componentbuilder.component_placeholders.'.$this->id); + $this->setRules($rules); + } + + // Set ordering + if ($this->published < 0) + { + // Set ordering to 0 if state is archived or trashed + $this->ordering = 0; + } + + return true; + } + + /** + * Gets the default asset values for a component. + * + * @param $string $component The component asset name to search for + * + * @return JAccessRules The JAccessRules object for the asset + */ + protected function getDefaultAssetValues($component, $try = true) + { + // Need to find the asset id by the name of the component. + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName('#__assets')) + ->where($db->quoteName('name') . ' = ' . $db->quote($component)); + $db->setQuery($query); + $db->execute(); + if ($db->loadRowList()) + { + // asset alread set so use saved rules + $assetId = (int) $db->loadResult(); + return JAccess::getAssetRules($assetId); // (TODO) instead of keeping inherited Allowed it becomes Allowed. + } + // try again + elseif ($try) + { + $try = explode('.',$component); + $result = $this->getDefaultAssetValues($try[0], false); + if ($result instanceof JAccessRules) + { + if (isset($try[1])) + { + $_result = (string) $result; + $_result = json_decode($_result); + foreach ($_result as $name => &$rule) + { + $v = explode('.', $name); + if ($try[1] !== $v[0]) + { + // remove since it is not part of this view + unset($_result->$name); + } + else + { + // clear the value since we inherit + $rule = array(); + } + } + // check if there are any view values remaining + if (count( (array) $_result)) + { + $_result = json_encode($_result); + $_result = array($_result); + // Instantiate and return the JAccessRules object for the asset rules. + $rules = new JAccessRules; + $rules->mergeCollection($_result); + + return $rules; + } + } + return $result; + } + } + return JAccess::getAssetRules(0); + } + + /** + * Method to compute the default name of the asset. + * The default name is in the form 'table_name.id' + * where id is the value of the primary key of the table. + * + * @return string + * @since 2.5 + */ + protected function _getAssetName() + { + $k = $this->_tbl_key; + return 'com_componentbuilder.component_placeholders.'.(int) $this->$k; + } + + /** + * Method to return the title to use for the asset table. + * + * @return string + * @since 2.5 + */ + protected function _getAssetTitle() + { + if (isset($this->title)) + { + return $this->title; + } + return ''; + } + + /** + * Get the parent asset id for the record + * + * @return int + * @since 2.5 + */ + protected function _getAssetParentId(JTable $table = NULL, $id = NULL) + { + $asset = JTable::getInstance('Asset'); + $asset->loadByName('com_componentbuilder'); + + return $asset->id; + } + + /** + * This view does not actually have an alias + * + * @return bool + */ + public function generateAlias() + { + return false; + } + +} diff --git a/admin/tables/placeholder.php b/admin/tables/placeholder.php new file mode 100644 index 000000000..af2d955f1 --- /dev/null +++ b/admin/tables/placeholder.php @@ -0,0 +1,321 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +use Joomla\Registry\Registry; + +/** + * Placeholders Table class + */ +class ComponentbuilderTablePlaceholder extends JTable +{ + /** + * Ensure the params and metadata in json encoded in the bind method + * + * @var array + * @since 3.3 + */ + protected $_jsonEncode = array('params', 'metadata'); + + /** + * Constructor + * + * @param object Database connector object + */ + function __construct(&$db) + { + parent::__construct('#__componentbuilder_placeholder', 'id', $db); + + // Adding History Options + JTableObserverContenthistory::createObserver($this, array('typeAlias' => 'com_componentbuilder.placeholder')); + } + + public function bind($array, $ignore = '') + { + + if (isset($array['params']) && is_array($array['params'])) + { + $registry = new JRegistry; + $registry->loadArray($array['params']); + $array['params'] = (string) $registry; + } + + if (isset($array['metadata']) && is_array($array['metadata'])) + { + $registry = new JRegistry; + $registry->loadArray($array['metadata']); + $array['metadata'] = (string) $registry; + } + + // Bind the rules. + if (isset($array['rules']) && is_array($array['rules'])) + { + $rules = new JAccessRules($array['rules']); + $this->setRules($rules); + } + return parent::bind($array, $ignore); + } + + /** + * Overload the store method for the Placeholder table. + * + * @param boolean Toggle whether null values should be updated. + * @return boolean True on success, false on failure. + * @since 1.6 + */ + public function store($updateNulls = false) + { + $date = JFactory::getDate(); + $user = JFactory::getUser(); + + if ($this->id) + { + // Existing item + $this->modified = $date->toSql(); + $this->modified_by = $user->get('id'); + } + else + { + // New placeholder. A placeholder created and created_by field can be set by the user, + // so we don't touch either of these if they are set. + if (!(int) $this->created) + { + $this->created = $date->toSql(); + } + if (empty($this->created_by)) + { + $this->created_by = $user->get('id'); + } + } + + if (isset($this->alias)) + { + // Verify that the alias is unique + $table = JTable::getInstance('placeholder', 'ComponentbuilderTable'); + + if ($table->load(array('alias' => $this->alias)) && ($table->id != $this->id || $this->id == 0)) + { + $this->setError(JText::_('COM_COMPONENTBUILDER_PLACEHOLDER_ERROR_UNIQUE_ALIAS')); + return false; + } + } + + if (isset($this->url)) + { + // Convert IDN urls to punycode + $this->url = JStringPunycode::urlToPunycode($this->url); + } + if (isset($this->website)) + { + // Convert IDN urls to punycode + $this->website = JStringPunycode::urlToPunycode($this->website); + } + + return parent::store($updateNulls); + } + + /** + * Overloaded check method to ensure data integrity. + * + * @return boolean True on success. + */ + public function check() + { + if (isset($this->alias)) + { + // Generate a valid alias + $this->generateAlias(); + + $table = JTable::getInstance('placeholder', 'componentbuilderTable'); + + while ($table->load(array('alias' => $this->alias)) && ($table->id != $this->id || $this->id == 0)) + { + $this->alias = JString::increment($this->alias, 'dash'); + } + } + + /* + * Clean up keywords -- eliminate extra spaces between phrases + * and cr (\r) and lf (\n) characters from string. + * Only process if not empty. + */ + if (!empty($this->metakey)) + { + // Array of characters to remove. + $bad_characters = array("\n", "\r", "\"", "<", ">"); + + // Remove bad characters. + $after_clean = JString::str_ireplace($bad_characters, "", $this->metakey); + + // Create array using commas as delimiter. + $keys = explode(',', $after_clean); + $clean_keys = array(); + + foreach ($keys as $key) + { + // Ignore blank keywords. + if (trim($key)) + { + $clean_keys[] = trim($key); + } + } + + // Put array back together delimited by ", " + $this->metakey = implode(", ", $clean_keys); + } + + // Clean up description -- eliminate quotes and <> brackets + if (!empty($this->metadesc)) + { + // Only process if not empty + $bad_characters = array("\"", "<", ">"); + $this->metadesc = JString::str_ireplace($bad_characters, "", $this->metadesc); + } + + // If we don't have any access rules set at this point just use an empty JAccessRules class + if (!$this->getRules()) + { + $rules = $this->getDefaultAssetValues('com_componentbuilder.placeholder.'.$this->id); + $this->setRules($rules); + } + + // Set ordering + if ($this->published < 0) + { + // Set ordering to 0 if state is archived or trashed + $this->ordering = 0; + } + + return true; + } + + /** + * Gets the default asset values for a component. + * + * @param $string $component The component asset name to search for + * + * @return JAccessRules The JAccessRules object for the asset + */ + protected function getDefaultAssetValues($component, $try = true) + { + // Need to find the asset id by the name of the component. + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName('#__assets')) + ->where($db->quoteName('name') . ' = ' . $db->quote($component)); + $db->setQuery($query); + $db->execute(); + if ($db->loadRowList()) + { + // asset alread set so use saved rules + $assetId = (int) $db->loadResult(); + return JAccess::getAssetRules($assetId); // (TODO) instead of keeping inherited Allowed it becomes Allowed. + } + // try again + elseif ($try) + { + $try = explode('.',$component); + $result = $this->getDefaultAssetValues($try[0], false); + if ($result instanceof JAccessRules) + { + if (isset($try[1])) + { + $_result = (string) $result; + $_result = json_decode($_result); + foreach ($_result as $name => &$rule) + { + $v = explode('.', $name); + if ($try[1] !== $v[0]) + { + // remove since it is not part of this view + unset($_result->$name); + } + else + { + // clear the value since we inherit + $rule = array(); + } + } + // check if there are any view values remaining + if (count( (array) $_result)) + { + $_result = json_encode($_result); + $_result = array($_result); + // Instantiate and return the JAccessRules object for the asset rules. + $rules = new JAccessRules; + $rules->mergeCollection($_result); + + return $rules; + } + } + return $result; + } + } + return JAccess::getAssetRules(0); + } + + /** + * Method to compute the default name of the asset. + * The default name is in the form 'table_name.id' + * where id is the value of the primary key of the table. + * + * @return string + * @since 2.5 + */ + protected function _getAssetName() + { + $k = $this->_tbl_key; + return 'com_componentbuilder.placeholder.'.(int) $this->$k; + } + + /** + * Method to return the title to use for the asset table. + * + * @return string + * @since 2.5 + */ + protected function _getAssetTitle() + { + if (isset($this->title)) + { + return $this->title; + } + return ''; + } + + /** + * Get the parent asset id for the record + * + * @return int + * @since 2.5 + */ + protected function _getAssetParentId(JTable $table = NULL, $id = NULL) + { + $asset = JTable::getInstance('Asset'); + $asset->loadByName('com_componentbuilder'); + + return $asset->id; + } + + /** + * This view does not actually have an alias + * + * @return bool + */ + public function generateAlias() + { + return false; + } + +} diff --git a/admin/views/component_placeholders/submitbutton.js b/admin/views/component_placeholders/submitbutton.js new file mode 100644 index 000000000..f7e80b88f --- /dev/null +++ b/admin/views/component_placeholders/submitbutton.js @@ -0,0 +1,25 @@ +/** + * @package Joomla.Component.Builder + * + * @created 30th April, 2015 + * @author Llewellyn van der Merwe + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +Joomla.submitbutton = function(task) +{ + if (task == ''){ + return false; + } else { + var action = task.split('.'); + if (action[1] == 'cancel' || action[1] == 'close' || document.formvalidator.isValid(document.getElementById("adminForm"))){ + Joomla.submitform(task, document.getElementById("adminForm")); + return true; + } else { + alert(Joomla.JText._('component_placeholders, some values are not acceptable.','Some values are unacceptable')); + return false; + } + } +} \ No newline at end of file diff --git a/admin/views/component_placeholders/tmpl/edit.php b/admin/views/component_placeholders/tmpl/edit.php new file mode 100644 index 000000000..fec03bfd1 --- /dev/null +++ b/admin/views/component_placeholders/tmpl/edit.php @@ -0,0 +1,107 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +JHtml::addIncludePath(JPATH_COMPONENT.'/helpers/html'); +JHtml::_('behavior.tooltip'); +JHtml::_('behavior.formvalidation'); +JHtml::_('formbehavior.chosen', 'select'); +JHtml::_('behavior.keepalive'); +$componentParams = $this->params; // will be removed just use $this->params instead +?> + + + + diff --git a/admin/views/component_placeholders/tmpl/index.html b/admin/views/component_placeholders/tmpl/index.html new file mode 100644 index 000000000..fa6d84e80 --- /dev/null +++ b/admin/views/component_placeholders/tmpl/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin/views/component_placeholders/view.html.php b/admin/views/component_placeholders/view.html.php new file mode 100644 index 000000000..5eef5d1c9 --- /dev/null +++ b/admin/views/component_placeholders/view.html.php @@ -0,0 +1,195 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +/** + * Component_placeholders View class + */ +class ComponentbuilderViewComponent_placeholders extends JViewLegacy +{ + /** + * display method of View + * @return void + */ + public function display($tpl = null) + { + // set params + $this->params = JComponentHelper::getParams('com_componentbuilder'); + // Assign the variables + $this->form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->script = $this->get('Script'); + $this->state = $this->get('State'); + // get action permissions + $this->canDo = ComponentbuilderHelper::getActions('component_placeholders', $this->item); + // get input + $jinput = JFactory::getApplication()->input; + $this->ref = $jinput->get('ref', 0, 'word'); + $this->refid = $jinput->get('refid', 0, 'int'); + $return = $jinput->get('return', null, 'base64'); + // set the referral string + $this->referral = ''; + if ($this->refid && $this->ref) + { + // return to the item that referred to this item + $this->referral = '&ref=' . (string)$this->ref . '&refid=' . (int)$this->refid; + } + elseif($this->ref) + { + // return to the list view that referred to this item + $this->referral = '&ref=' . (string)$this->ref; + } + // check return value + if (!is_null($return)) + { + // add the return value + $this->referral .= '&return=' . (string)$return; + } + + // Set the toolbar + $this->addToolBar(); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + throw new Exception(implode("\n", $errors), 500); + } + + // Display the template + parent::display($tpl); + + // Set the document + $this->setDocument(); + } + + + /** + * Setting the toolbar + */ + protected function addToolBar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + $user = JFactory::getUser(); + $userId = $user->id; + $isNew = $this->item->id == 0; + + JToolbarHelper::title( JText::_($isNew ? 'COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_NEW' : 'COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_EDIT'), 'pencil-2 article-add'); + // Built the actions for new and existing records. + if (ComponentbuilderHelper::checkString($this->referral)) + { + if ($this->canDo->get('component_placeholders.create') && $isNew) + { + // We can create the record. + JToolBarHelper::save('component_placeholders.save', 'JTOOLBAR_SAVE'); + } + elseif ($this->canDo->get('component_placeholders.edit')) + { + // We can save the record. + JToolBarHelper::save('component_placeholders.save', 'JTOOLBAR_SAVE'); + } + if ($isNew) + { + // Do not creat but cancel. + JToolBarHelper::cancel('component_placeholders.cancel', 'JTOOLBAR_CANCEL'); + } + else + { + // We can close it. + JToolBarHelper::cancel('component_placeholders.cancel', 'JTOOLBAR_CLOSE'); + } + } + else + { + if ($isNew) + { + // For new records, check the create permission. + if ($this->canDo->get('component_placeholders.create')) + { + JToolBarHelper::apply('component_placeholders.apply', 'JTOOLBAR_APPLY'); + JToolBarHelper::save('component_placeholders.save', 'JTOOLBAR_SAVE'); + JToolBarHelper::custom('component_placeholders.save2new', 'save-new.png', 'save-new_f2.png', 'JTOOLBAR_SAVE_AND_NEW', false); + }; + JToolBarHelper::cancel('component_placeholders.cancel', 'JTOOLBAR_CANCEL'); + } + else + { + if ($this->canDo->get('component_placeholders.edit')) + { + // We can save the new record + JToolBarHelper::apply('component_placeholders.apply', 'JTOOLBAR_APPLY'); + JToolBarHelper::save('component_placeholders.save', 'JTOOLBAR_SAVE'); + // We can save this record, but check the create permission to see + // if we can return to make a new one. + if ($this->canDo->get('component_placeholders.create')) + { + JToolBarHelper::custom('component_placeholders.save2new', 'save-new.png', 'save-new_f2.png', 'JTOOLBAR_SAVE_AND_NEW', false); + } + } + $canVersion = ($this->canDo->get('core.version') && $this->canDo->get('component_placeholders.version')); + if ($this->state->params->get('save_history', 1) && $this->canDo->get('component_placeholders.edit') && $canVersion) + { + JToolbarHelper::versions('com_componentbuilder.component_placeholders', $this->item->id); + } + if ($this->canDo->get('component_placeholders.create')) + { + JToolBarHelper::custom('component_placeholders.save2copy', 'save-copy.png', 'save-copy_f2.png', 'JTOOLBAR_SAVE_AS_COPY', false); + } + JToolBarHelper::cancel('component_placeholders.cancel', 'JTOOLBAR_CLOSE'); + } + } + JToolbarHelper::divider(); + // set help url for this view if found + $help_url = ComponentbuilderHelper::getHelpUrl('component_placeholders'); + if (ComponentbuilderHelper::checkString($help_url)) + { + JToolbarHelper::help('COM_COMPONENTBUILDER_HELP_MANAGER', false, $help_url); + } + } + + /** + * Escapes a value for output in a view script. + * + * @param mixed $var The output to escape. + * + * @return mixed The escaped value. + */ + public function escape($var) + { + if(strlen($var) > 30) + { + // use the helper htmlEscape method instead and shorten the string + return ComponentbuilderHelper::htmlEscape($var, $this->_charset, true, 30); + } + // use the helper htmlEscape method instead. + return ComponentbuilderHelper::htmlEscape($var, $this->_charset); + } + + /** + * Method to set up the document properties + * + * @return void + */ + protected function setDocument() + { + $isNew = ($this->item->id < 1); + if (!isset($this->document)) + { + $this->document = JFactory::getDocument(); + } + $this->document->setTitle(JText::_($isNew ? 'COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_NEW' : 'COM_COMPONENTBUILDER_COMPONENT_PLACEHOLDERS_EDIT')); + $this->document->addStyleSheet(JURI::root() . "administrator/components/com_componentbuilder/assets/css/component_placeholders.css", (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/css'); + $this->document->addScript(JURI::root() . $this->script, (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/javascript'); + $this->document->addScript(JURI::root() . "administrator/components/com_componentbuilder/views/component_placeholders/submitbutton.js", (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/javascript'); + JText::script('view not acceptable. Error'); + } +} diff --git a/admin/views/components_placeholders/index.html b/admin/views/components_placeholders/index.html new file mode 100644 index 000000000..fa6d84e80 --- /dev/null +++ b/admin/views/components_placeholders/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin/views/components_placeholders/tmpl/default.php b/admin/views/components_placeholders/tmpl/default.php new file mode 100644 index 000000000..fbf511bf4 --- /dev/null +++ b/admin/views/components_placeholders/tmpl/default.php @@ -0,0 +1,85 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +// load tooltip behavior +JHtml::_('behavior.tooltip'); +JHtml::_('behavior.multiselect'); +JHtml::_('dropdown.init'); +JHtml::_('formbehavior.chosen', 'select'); + +if ($this->saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_componentbuilder&task=components_placeholders.saveOrderAjax&tmpl=component'; + JHtml::_('sortablelist.sortable', 'component_placeholdersList', 'adminForm', strtolower($this->listDirn), $saveOrderingUrl); +} + +?> + +
+sidebar)): ?> +
+ sidebar; ?> +
+
+ +
+ +items)): ?> + loadTemplate('toolbar');?> +
+ +
+ + loadTemplate('toolbar');?> + + loadTemplate('head');?> + loadTemplate('foot');?> + loadTemplate('body');?> +
+ + canCreate && $this->canEdit) : ?> + JText::_('COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS_BATCH_OPTIONS'), + 'footer' => $this->loadTemplate('batch_footer') + ), + $this->loadTemplate('batch_body') + ); ?> + + + + +
+ + + + \ No newline at end of file diff --git a/admin/views/components_placeholders/tmpl/default_batch_body.php b/admin/views/components_placeholders/tmpl/default_batch_body.php new file mode 100644 index 000000000..cd9ecb2e4 --- /dev/null +++ b/admin/views/components_placeholders/tmpl/default_batch_body.php @@ -0,0 +1,18 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +?> + +

+batchDisplay; ?> \ No newline at end of file diff --git a/admin/views/components_placeholders/tmpl/default_batch_footer.php b/admin/views/components_placeholders/tmpl/default_batch_footer.php new file mode 100644 index 000000000..4c9d880be --- /dev/null +++ b/admin/views/components_placeholders/tmpl/default_batch_footer.php @@ -0,0 +1,23 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +?> + + + + \ No newline at end of file diff --git a/admin/views/components_placeholders/tmpl/default_body.php b/admin/views/components_placeholders/tmpl/default_body.php new file mode 100644 index 000000000..f83164b68 --- /dev/null +++ b/admin/views/components_placeholders/tmpl/default_body.php @@ -0,0 +1,94 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +$edit = "index.php?option=com_componentbuilder&view=components_placeholders&task=component_placeholders.edit"; + +?> +items as $i => $item): ?> + user->authorise('core.manage', 'com_checkin') || $item->checked_out == $this->user->id || $item->checked_out == 0; + $userChkOut = JFactory::getUser($item->checked_out); + $canDo = ComponentbuilderHelper::getActions('component_placeholders',$item,'components_placeholders'); + ?> + + + get('component_placeholders.edit.state')): ?> + saveOrder) + { + $iconClass = ' inactive'; + } + else + { + $iconClass = ' inactive tip-top" hasTooltip" title="' . JHtml::tooltipText('JORDERINGDISABLED'); + } + ?> + + + + saveOrder) : ?> + + + + ⋮ + + + + get('component_placeholders.edit')): ?> + checked_out) : ?> + + id); ?> + + □ + + + id); ?> + + + □ + + + +
+ get('component_placeholders.edit')): ?> + escape($item->joomla_component_system_name); ?> + checked_out): ?> + name, $item->checked_out_time, 'components_placeholders.', $canCheckin); ?> + + + escape($item->joomla_component_system_name); ?> + +
+ + + get('component_placeholders.edit.state')) : ?> + checked_out) : ?> + + published, $i, 'components_placeholders.', true, 'cb'); ?> + + published, $i, 'components_placeholders.', false, 'cb'); ?> + + + published, $i, 'components_placeholders.', true, 'cb'); ?> + + + published, $i, 'components_placeholders.', false, 'cb'); ?> + + + + id; ?> + + + \ No newline at end of file diff --git a/admin/views/components_placeholders/tmpl/default_foot.php b/admin/views/components_placeholders/tmpl/default_foot.php new file mode 100644 index 000000000..297242b41 --- /dev/null +++ b/admin/views/components_placeholders/tmpl/default_foot.php @@ -0,0 +1,18 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +?> + + pagination->getListFooter(); ?> + \ No newline at end of file diff --git a/admin/views/components_placeholders/tmpl/default_head.php b/admin/views/components_placeholders/tmpl/default_head.php new file mode 100644 index 000000000..96dfd9341 --- /dev/null +++ b/admin/views/components_placeholders/tmpl/default_head.php @@ -0,0 +1,47 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +?> + + canEdit&& $this->canState): ?> + + ', 'ordering', $this->listDirn, $this->listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + ▾ + + + ■ + + + + + + canState): ?> + + listDirn, $this->listOrder); ?> + + + + + + + + listDirn, $this->listOrder); ?> + + \ No newline at end of file diff --git a/admin/views/components_placeholders/tmpl/default_toolbar.php b/admin/views/components_placeholders/tmpl/default_toolbar.php new file mode 100644 index 000000000..0090ad08c --- /dev/null +++ b/admin/views/components_placeholders/tmpl/default_toolbar.php @@ -0,0 +1,45 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +?> +
+ +
+ + +
+
+ + pagination->getLimitBox(); ?> +
+
+ + +
+
+ + +
+
+
\ No newline at end of file diff --git a/admin/views/components_placeholders/tmpl/index.html b/admin/views/components_placeholders/tmpl/index.html new file mode 100644 index 000000000..fa6d84e80 --- /dev/null +++ b/admin/views/components_placeholders/tmpl/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin/views/components_placeholders/view.html.php b/admin/views/components_placeholders/view.html.php new file mode 100644 index 000000000..f0f076420 --- /dev/null +++ b/admin/views/components_placeholders/view.html.php @@ -0,0 +1,226 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +/** + * Componentbuilder View class for the Components_placeholders + */ +class ComponentbuilderViewComponents_placeholders extends JViewLegacy +{ + /** + * Components_placeholders view display method + * @return void + */ + function display($tpl = null) + { + if ($this->getLayout() !== 'modal') + { + // Include helper submenu + ComponentbuilderHelper::addSubmenu('components_placeholders'); + } + + // Assign data to the view + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + $this->user = JFactory::getUser(); + $this->listOrder = $this->escape($this->state->get('list.ordering')); + $this->listDirn = $this->escape($this->state->get('list.direction')); + $this->saveOrder = $this->listOrder == 'ordering'; + // set the return here value + $this->return_here = urlencode(base64_encode((string) JUri::getInstance())); + // get global action permissions + $this->canDo = ComponentbuilderHelper::getActions('component_placeholders'); + $this->canEdit = $this->canDo->get('component_placeholders.edit'); + $this->canState = $this->canDo->get('component_placeholders.edit.state'); + $this->canCreate = $this->canDo->get('component_placeholders.create'); + $this->canDelete = $this->canDo->get('component_placeholders.delete'); + $this->canBatch = $this->canDo->get('core.batch'); + + // We don't need toolbar in the modal window. + if ($this->getLayout() !== 'modal') + { + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + // load the batch html + if ($this->canCreate && $this->canEdit && $this->canState) + { + $this->batchDisplay = JHtmlBatch_::render(); + } + } + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + throw new Exception(implode("\n", $errors), 500); + } + + // Display the template + parent::display($tpl); + + // Set the document + $this->setDocument(); + } + + /** + * Setting the toolbar + */ + protected function addToolBar() + { + JToolBarHelper::title(JText::_('COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS'), 'joomla'); + JHtmlSidebar::setAction('index.php?option=com_componentbuilder&view=components_placeholders'); + JFormHelper::addFieldPath(JPATH_COMPONENT . '/models/fields'); + + if ($this->canCreate) + { + JToolBarHelper::addNew('component_placeholders.add'); + } + + // Only load if there are items + if (ComponentbuilderHelper::checkArray($this->items)) + { + if ($this->canEdit) + { + JToolBarHelper::editList('component_placeholders.edit'); + } + + if ($this->canState) + { + JToolBarHelper::publishList('components_placeholders.publish'); + JToolBarHelper::unpublishList('components_placeholders.unpublish'); + JToolBarHelper::archiveList('components_placeholders.archive'); + + if ($this->canDo->get('core.admin')) + { + JToolBarHelper::checkin('components_placeholders.checkin'); + } + } + + // Add a batch button + if ($this->canBatch && $this->canCreate && $this->canEdit && $this->canState) + { + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + // set the batch button name + $title = JText::_('JTOOLBAR_BATCH'); + // Instantiate a new JLayoutFile instance and render the batch button + $layout = new JLayoutFile('joomla.toolbar.batch'); + // add the button to the page + $dhtml = $layout->render(array('title' => $title)); + $bar->appendButton('Custom', $dhtml, 'batch'); + } + + if ($this->state->get('filter.published') == -2 && ($this->canState && $this->canDelete)) + { + JToolbarHelper::deleteList('', 'components_placeholders.delete', 'JTOOLBAR_EMPTY_TRASH'); + } + elseif ($this->canState && $this->canDelete) + { + JToolbarHelper::trash('components_placeholders.trash'); + } + } + + // set help url for this view if found + $help_url = ComponentbuilderHelper::getHelpUrl('components_placeholders'); + if (ComponentbuilderHelper::checkString($help_url)) + { + JToolbarHelper::help('COM_COMPONENTBUILDER_HELP_MANAGER', false, $help_url); + } + + // add the options comp button + if ($this->canDo->get('core.admin') || $this->canDo->get('core.options')) + { + JToolBarHelper::preferences('com_componentbuilder'); + } + + if ($this->canState) + { + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_published', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions'), 'value', 'text', $this->state->get('filter.published'), true) + ); + // only load if batch allowed + if ($this->canBatch) + { + JHtmlBatch_::addListSelection( + JText::_('COM_COMPONENTBUILDER_KEEP_ORIGINAL_STATE'), + 'batch[published]', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions', array('all' => false)), 'value', 'text', '', true) + ); + } + } + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + + if ($this->canBatch && $this->canCreate && $this->canEdit) + { + JHtmlBatch_::addListSelection( + JText::_('COM_COMPONENTBUILDER_KEEP_ORIGINAL_ACCESS'), + 'batch[access]', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text') + ); + } + } + + /** + * Method to set up the document properties + * + * @return void + */ + protected function setDocument() + { + if (!isset($this->document)) + { + $this->document = JFactory::getDocument(); + } + $this->document->setTitle(JText::_('COM_COMPONENTBUILDER_COMPONENTS_PLACEHOLDERS')); + $this->document->addStyleSheet(JURI::root() . "administrator/components/com_componentbuilder/assets/css/components_placeholders.css", (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/css'); + } + + /** + * Escapes a value for output in a view script. + * + * @param mixed $var The output to escape. + * + * @return mixed The escaped value. + */ + public function escape($var) + { + if(strlen($var) > 50) + { + // use the helper htmlEscape method instead and shorten the string + return ComponentbuilderHelper::htmlEscape($var, $this->_charset, true); + } + // use the helper htmlEscape method instead. + return ComponentbuilderHelper::htmlEscape($var, $this->_charset); + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + */ + protected function getSortFields() + { + return array( + 'a.sorting' => JText::_('JGRID_HEADING_ORDERING'), + 'a.published' => JText::_('JSTATUS'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/admin/views/joomla_components/tmpl/default_body.php b/admin/views/joomla_components/tmpl/default_body.php index 95607e7a7..ab944a8d6 100644 --- a/admin/views/joomla_components/tmpl/default_body.php +++ b/admin/views/joomla_components/tmpl/default_body.php @@ -104,6 +104,11 @@ $edit = "index.php?option=com_componentbuilder&view=joomla_components&task=jooml 'icon' => 'options') ); $_buttons[1] = array( + array( + 'view' => 'component_placeholders', + 'views' => 'components_placeholders', + 'title' => JText::_('COM_COMPONENTBUILDER_THE_COMPONENT_PLACEHOLDERS'), + 'icon' => 'search'), array( 'view' => 'component_updates', 'views' => 'components_updates', diff --git a/admin/views/placeholder/submitbutton.js b/admin/views/placeholder/submitbutton.js new file mode 100644 index 000000000..c5286068e --- /dev/null +++ b/admin/views/placeholder/submitbutton.js @@ -0,0 +1,25 @@ +/** + * @package Joomla.Component.Builder + * + * @created 30th April, 2015 + * @author Llewellyn van der Merwe + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +Joomla.submitbutton = function(task) +{ + if (task == ''){ + return false; + } else { + var action = task.split('.'); + if (action[1] == 'cancel' || action[1] == 'close' || document.formvalidator.isValid(document.getElementById("adminForm"))){ + Joomla.submitform(task, document.getElementById("adminForm")); + return true; + } else { + alert(Joomla.JText._('placeholder, some values are not acceptable.','Some values are unacceptable')); + return false; + } + } +} \ No newline at end of file diff --git a/admin/views/placeholder/tmpl/edit.php b/admin/views/placeholder/tmpl/edit.php new file mode 100644 index 000000000..973df6709 --- /dev/null +++ b/admin/views/placeholder/tmpl/edit.php @@ -0,0 +1,107 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +JHtml::addIncludePath(JPATH_COMPONENT.'/helpers/html'); +JHtml::_('behavior.tooltip'); +JHtml::_('behavior.formvalidation'); +JHtml::_('formbehavior.chosen', 'select'); +JHtml::_('behavior.keepalive'); +$componentParams = $this->params; // will be removed just use $this->params instead +?> + + + +
diff --git a/admin/views/placeholder/tmpl/index.html b/admin/views/placeholder/tmpl/index.html new file mode 100644 index 000000000..fa6d84e80 --- /dev/null +++ b/admin/views/placeholder/tmpl/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin/views/placeholder/view.html.php b/admin/views/placeholder/view.html.php new file mode 100644 index 000000000..6cf5b2664 --- /dev/null +++ b/admin/views/placeholder/view.html.php @@ -0,0 +1,208 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +/** + * Placeholder View class + */ +class ComponentbuilderViewPlaceholder extends JViewLegacy +{ + /** + * display method of View + * @return void + */ + public function display($tpl = null) + { + // set params + $this->params = JComponentHelper::getParams('com_componentbuilder'); + // Assign the variables + $this->form = $this->get('Form'); + $this->item = $this->get('Item'); + $this->script = $this->get('Script'); + $this->state = $this->get('State'); + // get action permissions + $this->canDo = ComponentbuilderHelper::getActions('placeholder', $this->item); + // get input + $jinput = JFactory::getApplication()->input; + $this->ref = $jinput->get('ref', 0, 'word'); + $this->refid = $jinput->get('refid', 0, 'int'); + $return = $jinput->get('return', null, 'base64'); + // set the referral string + $this->referral = ''; + if ($this->refid && $this->ref) + { + // return to the item that referred to this item + $this->referral = '&ref=' . (string)$this->ref . '&refid=' . (int)$this->refid; + } + elseif($this->ref) + { + // return to the list view that referred to this item + $this->referral = '&ref=' . (string)$this->ref; + } + // check return value + if (!is_null($return)) + { + // add the return value + $this->referral .= '&return=' . (string)$return; + } + + // Set the toolbar + $this->addToolBar(); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + throw new Exception(implode("\n", $errors), 500); + } + + // Display the template + parent::display($tpl); + + // Set the document + $this->setDocument(); + } + + + /** + * Setting the toolbar + */ + protected function addToolBar() + { + JFactory::getApplication()->input->set('hidemainmenu', true); + $user = JFactory::getUser(); + $userId = $user->id; + $isNew = $this->item->id == 0; + + JToolbarHelper::title( JText::_($isNew ? 'COM_COMPONENTBUILDER_PLACEHOLDER_NEW' : 'COM_COMPONENTBUILDER_PLACEHOLDER_EDIT'), 'pencil-2 article-add'); + // Built the actions for new and existing records. + if (ComponentbuilderHelper::checkString($this->referral)) + { + if ($this->canDo->get('placeholder.create') && $isNew) + { + // We can create the record. + JToolBarHelper::save('placeholder.save', 'JTOOLBAR_SAVE'); + } + elseif ($this->canDo->get('placeholder.edit')) + { + // We can save the record. + JToolBarHelper::save('placeholder.save', 'JTOOLBAR_SAVE'); + } + if ($isNew) + { + // Do not creat but cancel. + JToolBarHelper::cancel('placeholder.cancel', 'JTOOLBAR_CANCEL'); + } + else + { + // We can close it. + JToolBarHelper::cancel('placeholder.cancel', 'JTOOLBAR_CLOSE'); + } + } + else + { + if ($isNew) + { + // For new records, check the create permission. + if ($this->canDo->get('placeholder.create')) + { + JToolBarHelper::apply('placeholder.apply', 'JTOOLBAR_APPLY'); + JToolBarHelper::save('placeholder.save', 'JTOOLBAR_SAVE'); + JToolBarHelper::custom('placeholder.save2new', 'save-new.png', 'save-new_f2.png', 'JTOOLBAR_SAVE_AND_NEW', false); + }; + JToolBarHelper::cancel('placeholder.cancel', 'JTOOLBAR_CANCEL'); + } + else + { + if ($this->canDo->get('placeholder.edit')) + { + // We can save the new record + JToolBarHelper::apply('placeholder.apply', 'JTOOLBAR_APPLY'); + JToolBarHelper::save('placeholder.save', 'JTOOLBAR_SAVE'); + // We can save this record, but check the create permission to see + // if we can return to make a new one. + if ($this->canDo->get('placeholder.create')) + { + JToolBarHelper::custom('placeholder.save2new', 'save-new.png', 'save-new_f2.png', 'JTOOLBAR_SAVE_AND_NEW', false); + } + } + $canVersion = ($this->canDo->get('core.version') && $this->canDo->get('placeholder.version')); + if ($this->state->params->get('save_history', 1) && $this->canDo->get('placeholder.edit') && $canVersion) + { + JToolbarHelper::versions('com_componentbuilder.placeholder', $this->item->id); + } + if ($this->canDo->get('placeholder.create')) + { + JToolBarHelper::custom('placeholder.save2copy', 'save-copy.png', 'save-copy_f2.png', 'JTOOLBAR_SAVE_AS_COPY', false); + } + JToolBarHelper::cancel('placeholder.cancel', 'JTOOLBAR_CLOSE'); + } + } + JToolbarHelper::divider(); + // set help url for this view if found + $help_url = ComponentbuilderHelper::getHelpUrl('placeholder'); + if (ComponentbuilderHelper::checkString($help_url)) + { + JToolbarHelper::help('COM_COMPONENTBUILDER_HELP_MANAGER', false, $help_url); + } + } + + /** + * Escapes a value for output in a view script. + * + * @param mixed $var The output to escape. + * + * @return mixed The escaped value. + */ + public function escape($var) + { + if(strlen($var) > 30) + { + // use the helper htmlEscape method instead and shorten the string + return ComponentbuilderHelper::htmlEscape($var, $this->_charset, true, 30); + } + // use the helper htmlEscape method instead. + return ComponentbuilderHelper::htmlEscape($var, $this->_charset); + } + + /** + * Method to set up the document properties + * + * @return void + */ + protected function setDocument() + { + $isNew = ($this->item->id < 1); + if (!isset($this->document)) + { + $this->document = JFactory::getDocument(); + } + $this->document->setTitle(JText::_($isNew ? 'COM_COMPONENTBUILDER_PLACEHOLDER_NEW' : 'COM_COMPONENTBUILDER_PLACEHOLDER_EDIT')); + $this->document->addStyleSheet(JURI::root() . "administrator/components/com_componentbuilder/assets/css/placeholder.css", (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/css'); + $this->document->addScript(JURI::root() . $this->script, (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/javascript'); + $this->document->addScript(JURI::root() . "administrator/components/com_componentbuilder/views/placeholder/submitbutton.js", (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/javascript'); + + // add the Uikit v2 style sheets + $this->document->addStyleSheet( JURI::root(true) .'/media/com_componentbuilder/uikit-v2/css/uikit.gradient.min.css' , (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/css'); + $this->document->addStyleSheet( JURI::root(true) .'/media/com_componentbuilder/uikit-v2/css/components/notify.gradient.min.css' , (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/css'); + + // add Uikit v2 JavaScripts + $this->document->addScript( JURI::root(true) .'/media/com_componentbuilder/uikit-v2/js/uikit.min.js' , (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/javascript'); + $this->document->addScript( JURI::root(true) .'/media/com_componentbuilder/uikit-v2/js/components/lightbox.min.js', (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/javascript', (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('type' => 'text/javascript', 'async' => 'async') : true); + $this->document->addScript( JURI::root(true) .'/media/com_componentbuilder/uikit-v2/js/components/notify.min.js', (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/javascript', (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('type' => 'text/javascript', 'async' => 'async') : true); + // add var key + $this->document->addScriptDeclaration("var vastDevMod = '" . $this->get('VDM') . "';"); + // add return_here + $this->document->addScriptDeclaration("var return_here = '" . urlencode(base64_encode((string) JUri::getInstance())) . "';"); + JText::script('view not acceptable. Error'); + } +} diff --git a/admin/views/placeholders/index.html b/admin/views/placeholders/index.html new file mode 100644 index 000000000..fa6d84e80 --- /dev/null +++ b/admin/views/placeholders/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin/views/placeholders/tmpl/default.php b/admin/views/placeholders/tmpl/default.php new file mode 100644 index 000000000..302bc91b0 --- /dev/null +++ b/admin/views/placeholders/tmpl/default.php @@ -0,0 +1,85 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +// load tooltip behavior +JHtml::_('behavior.tooltip'); +JHtml::_('behavior.multiselect'); +JHtml::_('dropdown.init'); +JHtml::_('formbehavior.chosen', 'select'); + +if ($this->saveOrder) +{ + $saveOrderingUrl = 'index.php?option=com_componentbuilder&task=placeholders.saveOrderAjax&tmpl=component'; + JHtml::_('sortablelist.sortable', 'placeholderList', 'adminForm', strtolower($this->listDirn), $saveOrderingUrl); +} + +?> + +
+sidebar)): ?> +
+ sidebar; ?> +
+
+ +
+ +items)): ?> + loadTemplate('toolbar');?> +
+ +
+ + loadTemplate('toolbar');?> + + loadTemplate('head');?> + loadTemplate('foot');?> + loadTemplate('body');?> +
+ + canCreate && $this->canEdit) : ?> + JText::_('COM_COMPONENTBUILDER_PLACEHOLDERS_BATCH_OPTIONS'), + 'footer' => $this->loadTemplate('batch_footer') + ), + $this->loadTemplate('batch_body') + ); ?> + + + + +
+ + + + \ No newline at end of file diff --git a/admin/views/placeholders/tmpl/default_batch_body.php b/admin/views/placeholders/tmpl/default_batch_body.php new file mode 100644 index 000000000..c99931aaa --- /dev/null +++ b/admin/views/placeholders/tmpl/default_batch_body.php @@ -0,0 +1,18 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +?> + +

+batchDisplay; ?> \ No newline at end of file diff --git a/admin/views/placeholders/tmpl/default_batch_footer.php b/admin/views/placeholders/tmpl/default_batch_footer.php new file mode 100644 index 000000000..43d4ffea1 --- /dev/null +++ b/admin/views/placeholders/tmpl/default_batch_footer.php @@ -0,0 +1,23 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +?> + + + + \ No newline at end of file diff --git a/admin/views/placeholders/tmpl/default_body.php b/admin/views/placeholders/tmpl/default_body.php new file mode 100644 index 000000000..cb71e094c --- /dev/null +++ b/admin/views/placeholders/tmpl/default_body.php @@ -0,0 +1,97 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +$edit = "index.php?option=com_componentbuilder&view=placeholders&task=placeholder.edit"; + +?> +items as $i => $item): ?> + user->authorise('core.manage', 'com_checkin') || $item->checked_out == $this->user->id || $item->checked_out == 0; + $userChkOut = JFactory::getUser($item->checked_out); + $canDo = ComponentbuilderHelper::getActions('placeholder',$item,'placeholders'); + ?> + + + get('placeholder.edit.state')): ?> + saveOrder) + { + $iconClass = ' inactive'; + } + else + { + $iconClass = ' inactive tip-top" hasTooltip" title="' . JHtml::tooltipText('JORDERINGDISABLED'); + } + ?> + + + + saveOrder) : ?> + + + + ⋮ + + + + get('placeholder.edit')): ?> + checked_out) : ?> + + id); ?> + + □ + + + id); ?> + + + □ + + + +
+ get('placeholder.edit')): ?> + escape($item->target); ?> + checked_out): ?> + name, $item->checked_out_time, 'placeholders.', $canCheckin); ?> + + + escape($item->target); ?> + +
+ + + escape($item->value); ?> + + + get('placeholder.edit.state')) : ?> + checked_out) : ?> + + published, $i, 'placeholders.', true, 'cb'); ?> + + published, $i, 'placeholders.', false, 'cb'); ?> + + + published, $i, 'placeholders.', true, 'cb'); ?> + + + published, $i, 'placeholders.', false, 'cb'); ?> + + + + id; ?> + + + \ No newline at end of file diff --git a/admin/views/placeholders/tmpl/default_foot.php b/admin/views/placeholders/tmpl/default_foot.php new file mode 100644 index 000000000..db893039b --- /dev/null +++ b/admin/views/placeholders/tmpl/default_foot.php @@ -0,0 +1,18 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +?> + + pagination->getListFooter(); ?> + \ No newline at end of file diff --git a/admin/views/placeholders/tmpl/default_head.php b/admin/views/placeholders/tmpl/default_head.php new file mode 100644 index 000000000..854979239 --- /dev/null +++ b/admin/views/placeholders/tmpl/default_head.php @@ -0,0 +1,50 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +?> + + canEdit&& $this->canState): ?> + + ', 'ordering', $this->listDirn, $this->listOrder, null, 'asc', 'JGRID_HEADING_ORDERING'); ?> + + + + + + + ▾ + + + ■ + + + + listDirn, $this->listOrder); ?> + + + listDirn, $this->listOrder); ?> + + canState): ?> + + listDirn, $this->listOrder); ?> + + + + + + + + listDirn, $this->listOrder); ?> + + \ No newline at end of file diff --git a/admin/views/placeholders/tmpl/default_toolbar.php b/admin/views/placeholders/tmpl/default_toolbar.php new file mode 100644 index 000000000..6e9b61a9b --- /dev/null +++ b/admin/views/placeholders/tmpl/default_toolbar.php @@ -0,0 +1,45 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +?> +
+ +
+ + +
+
+ + pagination->getLimitBox(); ?> +
+
+ + +
+
+ + +
+
+
\ No newline at end of file diff --git a/admin/views/placeholders/tmpl/index.html b/admin/views/placeholders/tmpl/index.html new file mode 100644 index 000000000..fa6d84e80 --- /dev/null +++ b/admin/views/placeholders/tmpl/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin/views/placeholders/view.html.php b/admin/views/placeholders/view.html.php new file mode 100644 index 000000000..72b6f85a0 --- /dev/null +++ b/admin/views/placeholders/view.html.php @@ -0,0 +1,238 @@ + + * @github Joomla Component Builder + * @copyright Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access to this file +defined('_JEXEC') or die('Restricted access'); + +/** + * Componentbuilder View class for the Placeholders + */ +class ComponentbuilderViewPlaceholders extends JViewLegacy +{ + /** + * Placeholders view display method + * @return void + */ + function display($tpl = null) + { + if ($this->getLayout() !== 'modal') + { + // Include helper submenu + ComponentbuilderHelper::addSubmenu('placeholders'); + } + + // Assign data to the view + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->state = $this->get('State'); + $this->user = JFactory::getUser(); + $this->listOrder = $this->escape($this->state->get('list.ordering')); + $this->listDirn = $this->escape($this->state->get('list.direction')); + $this->saveOrder = $this->listOrder == 'ordering'; + // set the return here value + $this->return_here = urlencode(base64_encode((string) JUri::getInstance())); + // get global action permissions + $this->canDo = ComponentbuilderHelper::getActions('placeholder'); + $this->canEdit = $this->canDo->get('placeholder.edit'); + $this->canState = $this->canDo->get('placeholder.edit.state'); + $this->canCreate = $this->canDo->get('placeholder.create'); + $this->canDelete = $this->canDo->get('placeholder.delete'); + $this->canBatch = $this->canDo->get('core.batch'); + + // We don't need toolbar in the modal window. + if ($this->getLayout() !== 'modal') + { + $this->addToolbar(); + $this->sidebar = JHtmlSidebar::render(); + // load the batch html + if ($this->canCreate && $this->canEdit && $this->canState) + { + $this->batchDisplay = JHtmlBatch_::render(); + } + } + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + throw new Exception(implode("\n", $errors), 500); + } + + // Display the template + parent::display($tpl); + + // Set the document + $this->setDocument(); + } + + /** + * Setting the toolbar + */ + protected function addToolBar() + { + JToolBarHelper::title(JText::_('COM_COMPONENTBUILDER_PLACEHOLDERS'), 'search'); + JHtmlSidebar::setAction('index.php?option=com_componentbuilder&view=placeholders'); + JFormHelper::addFieldPath(JPATH_COMPONENT . '/models/fields'); + + if ($this->canCreate) + { + JToolBarHelper::addNew('placeholder.add'); + } + + // Only load if there are items + if (ComponentbuilderHelper::checkArray($this->items)) + { + if ($this->canEdit) + { + JToolBarHelper::editList('placeholder.edit'); + } + + if ($this->canState) + { + JToolBarHelper::publishList('placeholders.publish'); + JToolBarHelper::unpublishList('placeholders.unpublish'); + JToolBarHelper::archiveList('placeholders.archive'); + + if ($this->canDo->get('core.admin')) + { + JToolBarHelper::checkin('placeholders.checkin'); + } + } + + // Add a batch button + if ($this->canBatch && $this->canCreate && $this->canEdit && $this->canState) + { + // Get the toolbar object instance + $bar = JToolBar::getInstance('toolbar'); + // set the batch button name + $title = JText::_('JTOOLBAR_BATCH'); + // Instantiate a new JLayoutFile instance and render the batch button + $layout = new JLayoutFile('joomla.toolbar.batch'); + // add the button to the page + $dhtml = $layout->render(array('title' => $title)); + $bar->appendButton('Custom', $dhtml, 'batch'); + } + + if ($this->state->get('filter.published') == -2 && ($this->canState && $this->canDelete)) + { + JToolbarHelper::deleteList('', 'placeholders.delete', 'JTOOLBAR_EMPTY_TRASH'); + } + elseif ($this->canState && $this->canDelete) + { + JToolbarHelper::trash('placeholders.trash'); + } + + if ($this->canDo->get('core.export') && $this->canDo->get('placeholder.export')) + { + JToolBarHelper::custom('placeholders.exportData', 'download', '', 'COM_COMPONENTBUILDER_EXPORT_DATA', true); + } + } + + if ($this->canDo->get('core.import') && $this->canDo->get('placeholder.import')) + { + JToolBarHelper::custom('placeholders.importData', 'upload', '', 'COM_COMPONENTBUILDER_IMPORT_DATA', false); + } + + // set help url for this view if found + $help_url = ComponentbuilderHelper::getHelpUrl('placeholders'); + if (ComponentbuilderHelper::checkString($help_url)) + { + JToolbarHelper::help('COM_COMPONENTBUILDER_HELP_MANAGER', false, $help_url); + } + + // add the options comp button + if ($this->canDo->get('core.admin') || $this->canDo->get('core.options')) + { + JToolBarHelper::preferences('com_componentbuilder'); + } + + if ($this->canState) + { + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_PUBLISHED'), + 'filter_published', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions'), 'value', 'text', $this->state->get('filter.published'), true) + ); + // only load if batch allowed + if ($this->canBatch) + { + JHtmlBatch_::addListSelection( + JText::_('COM_COMPONENTBUILDER_KEEP_ORIGINAL_STATE'), + 'batch[published]', + JHtml::_('select.options', JHtml::_('jgrid.publishedOptions', array('all' => false)), 'value', 'text', '', true) + ); + } + } + + JHtmlSidebar::addFilter( + JText::_('JOPTION_SELECT_ACCESS'), + 'filter_access', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text', $this->state->get('filter.access')) + ); + + if ($this->canBatch && $this->canCreate && $this->canEdit) + { + JHtmlBatch_::addListSelection( + JText::_('COM_COMPONENTBUILDER_KEEP_ORIGINAL_ACCESS'), + 'batch[access]', + JHtml::_('select.options', JHtml::_('access.assetgroups'), 'value', 'text') + ); + } + } + + /** + * Method to set up the document properties + * + * @return void + */ + protected function setDocument() + { + if (!isset($this->document)) + { + $this->document = JFactory::getDocument(); + } + $this->document->setTitle(JText::_('COM_COMPONENTBUILDER_PLACEHOLDERS')); + $this->document->addStyleSheet(JURI::root() . "administrator/components/com_componentbuilder/assets/css/placeholders.css", (ComponentbuilderHelper::jVersion()->isCompatible('3.8.0')) ? array('version' => 'auto') : 'text/css'); + } + + /** + * Escapes a value for output in a view script. + * + * @param mixed $var The output to escape. + * + * @return mixed The escaped value. + */ + public function escape($var) + { + if(strlen($var) > 50) + { + // use the helper htmlEscape method instead and shorten the string + return ComponentbuilderHelper::htmlEscape($var, $this->_charset, true); + } + // use the helper htmlEscape method instead. + return ComponentbuilderHelper::htmlEscape($var, $this->_charset); + } + + /** + * Returns an array of fields the table can be sorted by + * + * @return array Array containing the field name to sort by as the key and display text as value + */ + protected function getSortFields() + { + return array( + 'a.sorting' => JText::_('JGRID_HEADING_ORDERING'), + 'a.published' => JText::_('JSTATUS'), + 'a.target' => JText::_('COM_COMPONENTBUILDER_PLACEHOLDER_TARGET_LABEL'), + 'a.value' => JText::_('COM_COMPONENTBUILDER_PLACEHOLDER_VALUE_LABEL'), + 'a.id' => JText::_('JGRID_HEADING_ID') + ); + } +} diff --git a/componentbuilder.xml b/componentbuilder.xml index 7c1c0cbea..367da45e0 100644 --- a/componentbuilder.xml +++ b/componentbuilder.xml @@ -1,15 +1,15 @@ COM_COMPONENTBUILDER - 12th February, 2019 + 15th February, 2019 Llewellyn van der Merwe llewellyn@joomlacomponentbuilder.com http://www.joomlacomponentbuilder.com Copyright (C) 2015 - 2018 Vast Development Method. All rights reserved. GNU General Public License version 2 or later; see LICENSE.txt - 2.9.11 + 2.9.13 Component Builder (v.2.9.11) +

Component Builder (v.2.9.13)

The Component Builder for [Joomla](https://extensions.joomla.org/extension/component-builder/) is highly advanced tool that is truly able to build extremely complex components in a fraction of the time. @@ -84,6 +84,7 @@ Whether you're a seasoned [Joomla](https://extensions.joomla.org/extension/compo

COM_COMPONENTBUILDER_MENU_LAYOUTS COM_COMPONENTBUILDER_MENU_DYNAMIC_GETS COM_COMPONENTBUILDER_MENU_CUSTOM_CODES + COM_COMPONENTBUILDER_MENU_PLACEHOLDERS COM_COMPONENTBUILDER_MENU_LIBRARIES COM_COMPONENTBUILDER_MENU_SNIPPETS COM_COMPONENTBUILDER_MENU_VALIDATION_RULES diff --git a/componentbuilder_update_server.xml b/componentbuilder_update_server.xml index 872042f9b..e92d17657 100644 --- a/componentbuilder_update_server.xml +++ b/componentbuilder_update_server.xml @@ -594,4 +594,38 @@ http://www.joomlacomponentbuilder.com + + Component Builder + Builds Complex Joomla Components + com_componentbuilder + component + 2.9.12 + http://www.joomlacomponentbuilder.com + + https://github.com/vdm-io/Joomla-Component-Builder/releases/download/v2.9.12/JCB_v2.9.12.zip + + + stable + + Llewellyn van der Merwe + http://www.joomlacomponentbuilder.com + + + + Component Builder + Builds Complex Joomla Components + com_componentbuilder + component + 2.9.13 + http://www.joomlacomponentbuilder.com + + http://domain.com/demo.zip + + + stable + + Llewellyn van der Merwe + http://www.joomlacomponentbuilder.com + + \ No newline at end of file diff --git a/script.php b/script.php index bbc0e6e4a..7dcaa6b61 100644 --- a/script.php +++ b/script.php @@ -730,6 +730,92 @@ class com_componentbuilderInstallerScript } } + // Create a new query object. + $query = $db->getQuery(true); + // Select id from content type table + $query->select($db->quoteName('type_id')); + $query->from($db->quoteName('#__content_types')); + // Where Placeholder alias is found + $query->where( $db->quoteName('type_alias') . ' = '. $db->quote('com_componentbuilder.placeholder') ); + $db->setQuery($query); + // Execute query to see if alias is found + $db->execute(); + $placeholder_found = $db->getNumRows(); + // Now check if there were any rows + if ($placeholder_found) + { + // Since there are load the needed placeholder type ids + $placeholder_ids = $db->loadColumn(); + // Remove Placeholder from the content type table + $placeholder_condition = array( $db->quoteName('type_alias') . ' = '. $db->quote('com_componentbuilder.placeholder') ); + // Create a new query object. + $query = $db->getQuery(true); + $query->delete($db->quoteName('#__content_types')); + $query->where($placeholder_condition); + $db->setQuery($query); + // Execute the query to remove Placeholder items + $placeholder_done = $db->execute(); + if ($placeholder_done) + { + // If succesfully remove Placeholder add queued success message. + $app->enqueueMessage(JText::_('The (com_componentbuilder.placeholder) type alias was removed from the #__content_type table')); + } + + // Remove Placeholder items from the contentitem tag map table + $placeholder_condition = array( $db->quoteName('type_alias') . ' = '. $db->quote('com_componentbuilder.placeholder') ); + // Create a new query object. + $query = $db->getQuery(true); + $query->delete($db->quoteName('#__contentitem_tag_map')); + $query->where($placeholder_condition); + $db->setQuery($query); + // Execute the query to remove Placeholder items + $placeholder_done = $db->execute(); + if ($placeholder_done) + { + // If succesfully remove Placeholder add queued success message. + $app->enqueueMessage(JText::_('The (com_componentbuilder.placeholder) type alias was removed from the #__contentitem_tag_map table')); + } + + // Remove Placeholder items from the ucm content table + $placeholder_condition = array( $db->quoteName('core_type_alias') . ' = ' . $db->quote('com_componentbuilder.placeholder') ); + // Create a new query object. + $query = $db->getQuery(true); + $query->delete($db->quoteName('#__ucm_content')); + $query->where($placeholder_condition); + $db->setQuery($query); + // Execute the query to remove Placeholder items + $placeholder_done = $db->execute(); + if ($placeholder_done) + { + // If succesfully remove Placeholder add queued success message. + $app->enqueueMessage(JText::_('The (com_componentbuilder.placeholder) type alias was removed from the #__ucm_content table')); + } + + // Make sure that all the Placeholder items are cleared from DB + foreach ($placeholder_ids as $placeholder_id) + { + // Remove Placeholder items from the ucm base table + $placeholder_condition = array( $db->quoteName('ucm_type_id') . ' = ' . $placeholder_id); + // Create a new query object. + $query = $db->getQuery(true); + $query->delete($db->quoteName('#__ucm_base')); + $query->where($placeholder_condition); + $db->setQuery($query); + // Execute the query to remove Placeholder items + $db->execute(); + + // Remove Placeholder items from the ucm history table + $placeholder_condition = array( $db->quoteName('ucm_type_id') . ' = ' . $placeholder_id); + // Create a new query object. + $query = $db->getQuery(true); + $query->delete($db->quoteName('#__ucm_history')); + $query->where($placeholder_condition); + $db->setQuery($query); + // Execute the query to remove Placeholder items + $db->execute(); + } + } + // Create a new query object. $query = $db->getQuery(true); // Select id from content type table @@ -2794,6 +2880,92 @@ class com_componentbuilderInstallerScript } } + // Create a new query object. + $query = $db->getQuery(true); + // Select id from content type table + $query->select($db->quoteName('type_id')); + $query->from($db->quoteName('#__content_types')); + // Where Component_placeholders alias is found + $query->where( $db->quoteName('type_alias') . ' = '. $db->quote('com_componentbuilder.component_placeholders') ); + $db->setQuery($query); + // Execute query to see if alias is found + $db->execute(); + $component_placeholders_found = $db->getNumRows(); + // Now check if there were any rows + if ($component_placeholders_found) + { + // Since there are load the needed component_placeholders type ids + $component_placeholders_ids = $db->loadColumn(); + // Remove Component_placeholders from the content type table + $component_placeholders_condition = array( $db->quoteName('type_alias') . ' = '. $db->quote('com_componentbuilder.component_placeholders') ); + // Create a new query object. + $query = $db->getQuery(true); + $query->delete($db->quoteName('#__content_types')); + $query->where($component_placeholders_condition); + $db->setQuery($query); + // Execute the query to remove Component_placeholders items + $component_placeholders_done = $db->execute(); + if ($component_placeholders_done) + { + // If succesfully remove Component_placeholders add queued success message. + $app->enqueueMessage(JText::_('The (com_componentbuilder.component_placeholders) type alias was removed from the #__content_type table')); + } + + // Remove Component_placeholders items from the contentitem tag map table + $component_placeholders_condition = array( $db->quoteName('type_alias') . ' = '. $db->quote('com_componentbuilder.component_placeholders') ); + // Create a new query object. + $query = $db->getQuery(true); + $query->delete($db->quoteName('#__contentitem_tag_map')); + $query->where($component_placeholders_condition); + $db->setQuery($query); + // Execute the query to remove Component_placeholders items + $component_placeholders_done = $db->execute(); + if ($component_placeholders_done) + { + // If succesfully remove Component_placeholders add queued success message. + $app->enqueueMessage(JText::_('The (com_componentbuilder.component_placeholders) type alias was removed from the #__contentitem_tag_map table')); + } + + // Remove Component_placeholders items from the ucm content table + $component_placeholders_condition = array( $db->quoteName('core_type_alias') . ' = ' . $db->quote('com_componentbuilder.component_placeholders') ); + // Create a new query object. + $query = $db->getQuery(true); + $query->delete($db->quoteName('#__ucm_content')); + $query->where($component_placeholders_condition); + $db->setQuery($query); + // Execute the query to remove Component_placeholders items + $component_placeholders_done = $db->execute(); + if ($component_placeholders_done) + { + // If succesfully remove Component_placeholders add queued success message. + $app->enqueueMessage(JText::_('The (com_componentbuilder.component_placeholders) type alias was removed from the #__ucm_content table')); + } + + // Make sure that all the Component_placeholders items are cleared from DB + foreach ($component_placeholders_ids as $component_placeholders_id) + { + // Remove Component_placeholders items from the ucm base table + $component_placeholders_condition = array( $db->quoteName('ucm_type_id') . ' = ' . $component_placeholders_id); + // Create a new query object. + $query = $db->getQuery(true); + $query->delete($db->quoteName('#__ucm_base')); + $query->where($component_placeholders_condition); + $db->setQuery($query); + // Execute the query to remove Component_placeholders items + $db->execute(); + + // Remove Component_placeholders items from the ucm history table + $component_placeholders_condition = array( $db->quoteName('ucm_type_id') . ' = ' . $component_placeholders_id); + // Create a new query object. + $query = $db->getQuery(true); + $query->delete($db->quoteName('#__ucm_history')); + $query->where($component_placeholders_condition); + $db->setQuery($query); + // Execute the query to remove Component_placeholders items + $db->execute(); + } + } + // Create a new query object. $query = $db->getQuery(true); // Select id from content type table @@ -3599,6 +3771,18 @@ class com_componentbuilderInstallerScript // Set the object into the content types table. $custom_code_Inserted = $db->insertObject('#__content_types', $custom_code); + // Create the placeholder content type object. + $placeholder = new stdClass(); + $placeholder->type_title = 'Componentbuilder Placeholder'; + $placeholder->type_alias = 'com_componentbuilder.placeholder'; + $placeholder->table = '{"special": {"dbtable": "#__componentbuilder_placeholder","key": "id","type": "Placeholder","prefix": "componentbuilderTable","config": "array()"},"common": {"dbtable": "#__ucm_content","key": "ucm_id","type": "Corecontent","prefix": "JTable","config": "array()"}}'; + $placeholder->field_mappings = '{"common": {"core_content_item_id": "id","core_title": "target","core_state": "published","core_alias": "null","core_created_time": "created","core_modified_time": "modified","core_body": "null","core_hits": "hits","core_publish_up": "null","core_publish_down": "null","core_access": "access","core_params": "params","core_featured": "null","core_metadata": "null","core_language": "null","core_images": "null","core_urls": "null","core_version": "version","core_ordering": "ordering","core_metakey": "null","core_metadesc": "null","core_catid": "null","core_xreference": "null","asset_id": "asset_id"},"special": {"target":"target","value":"value"}}'; + $placeholder->router = 'ComponentbuilderHelperRoute::getPlaceholderRoute'; + $placeholder->content_history_options = '{"formFile": "administrator/components/com_componentbuilder/models/forms/placeholder.xml","hideFields": ["asset_id","checked_out","checked_out_time","version"],"ignoreChanges": ["modified_by","modified","checked_out","checked_out_time","version","hits"],"convertToInt": ["published","ordering"],"displayLookup": [{"sourceColumn": "created_by","targetTable": "#__users","targetColumn": "id","displayColumn": "name"},{"sourceColumn": "access","targetTable": "#__viewlevels","targetColumn": "id","displayColumn": "title"},{"sourceColumn": "modified_by","targetTable": "#__users","targetColumn": "id","displayColumn": "name"}]}'; + + // Set the object into the content types table. + $placeholder_Inserted = $db->insertObject('#__content_types', $placeholder); + // Create the library content type object. $library = new stdClass(); $library->type_title = 'Componentbuilder Library'; @@ -3887,6 +4071,18 @@ class com_componentbuilderInstallerScript // Set the object into the content types table. $component_files_folders_Inserted = $db->insertObject('#__content_types', $component_files_folders); + // Create the component_placeholders content type object. + $component_placeholders = new stdClass(); + $component_placeholders->type_title = 'Componentbuilder Component_placeholders'; + $component_placeholders->type_alias = 'com_componentbuilder.component_placeholders'; + $component_placeholders->table = '{"special": {"dbtable": "#__componentbuilder_component_placeholders","key": "id","type": "Component_placeholders","prefix": "componentbuilderTable","config": "array()"},"common": {"dbtable": "#__ucm_content","key": "ucm_id","type": "Corecontent","prefix": "JTable","config": "array()"}}'; + $component_placeholders->field_mappings = '{"common": {"core_content_item_id": "id","core_title": "joomla_component","core_state": "published","core_alias": "null","core_created_time": "created","core_modified_time": "modified","core_body": "null","core_hits": "hits","core_publish_up": "null","core_publish_down": "null","core_access": "access","core_params": "params","core_featured": "null","core_metadata": "null","core_language": "null","core_images": "null","core_urls": "null","core_version": "version","core_ordering": "ordering","core_metakey": "null","core_metadesc": "null","core_catid": "null","core_xreference": "null","asset_id": "asset_id"},"special": {"joomla_component":"joomla_component"}}'; + $component_placeholders->router = 'ComponentbuilderHelperRoute::getComponent_placeholdersRoute'; + $component_placeholders->content_history_options = '{"formFile": "administrator/components/com_componentbuilder/models/forms/component_placeholders.xml","hideFields": ["asset_id","checked_out","checked_out_time","version"],"ignoreChanges": ["modified_by","modified","checked_out","checked_out_time","version","hits"],"convertToInt": ["published","ordering","joomla_component"],"displayLookup": [{"sourceColumn": "created_by","targetTable": "#__users","targetColumn": "id","displayColumn": "name"},{"sourceColumn": "access","targetTable": "#__viewlevels","targetColumn": "id","displayColumn": "title"},{"sourceColumn": "modified_by","targetTable": "#__users","targetColumn": "id","displayColumn": "name"},{"sourceColumn": "joomla_component","targetTable": "#__componentbuilder_joomla_component","targetColumn": "id","displayColumn": "system_name"}]}'; + + // Set the object into the content types table. + $component_placeholders_Inserted = $db->insertObject('#__content_types', $component_placeholders); + // Create the snippet_type content type object. $snippet_type = new stdClass(); $snippet_type->type_title = 'Componentbuilder Snippet_type'; @@ -4181,6 +4377,35 @@ class com_componentbuilderInstallerScript $custom_code_Inserted = $db->insertObject('#__content_types', $custom_code); } + // Create the placeholder content type object. + $placeholder = new stdClass(); + $placeholder->type_title = 'Componentbuilder Placeholder'; + $placeholder->type_alias = 'com_componentbuilder.placeholder'; + $placeholder->table = '{"special": {"dbtable": "#__componentbuilder_placeholder","key": "id","type": "Placeholder","prefix": "componentbuilderTable","config": "array()"},"common": {"dbtable": "#__ucm_content","key": "ucm_id","type": "Corecontent","prefix": "JTable","config": "array()"}}'; + $placeholder->field_mappings = '{"common": {"core_content_item_id": "id","core_title": "target","core_state": "published","core_alias": "null","core_created_time": "created","core_modified_time": "modified","core_body": "null","core_hits": "hits","core_publish_up": "null","core_publish_down": "null","core_access": "access","core_params": "params","core_featured": "null","core_metadata": "null","core_language": "null","core_images": "null","core_urls": "null","core_version": "version","core_ordering": "ordering","core_metakey": "null","core_metadesc": "null","core_catid": "null","core_xreference": "null","asset_id": "asset_id"},"special": {"target":"target","value":"value"}}'; + $placeholder->router = 'ComponentbuilderHelperRoute::getPlaceholderRoute'; + $placeholder->content_history_options = '{"formFile": "administrator/components/com_componentbuilder/models/forms/placeholder.xml","hideFields": ["asset_id","checked_out","checked_out_time","version"],"ignoreChanges": ["modified_by","modified","checked_out","checked_out_time","version","hits"],"convertToInt": ["published","ordering"],"displayLookup": [{"sourceColumn": "created_by","targetTable": "#__users","targetColumn": "id","displayColumn": "name"},{"sourceColumn": "access","targetTable": "#__viewlevels","targetColumn": "id","displayColumn": "title"},{"sourceColumn": "modified_by","targetTable": "#__users","targetColumn": "id","displayColumn": "name"}]}'; + + // Check if placeholder type is already in content_type DB. + $placeholder_id = null; + $query = $db->getQuery(true); + $query->select($db->quoteName(array('type_id'))); + $query->from($db->quoteName('#__content_types')); + $query->where($db->quoteName('type_alias') . ' LIKE '. $db->quote($placeholder->type_alias)); + $db->setQuery($query); + $db->execute(); + + // Set the object into the content types table. + if ($db->getNumRows()) + { + $placeholder->type_id = $db->loadResult(); + $placeholder_Updated = $db->updateObject('#__content_types', $placeholder, 'type_id'); + } + else + { + $placeholder_Inserted = $db->insertObject('#__content_types', $placeholder); + } + // Create the library content type object. $library = new stdClass(); $library->type_title = 'Componentbuilder Library'; @@ -4877,6 +5102,35 @@ class com_componentbuilderInstallerScript $component_files_folders_Inserted = $db->insertObject('#__content_types', $component_files_folders); } + // Create the component_placeholders content type object. + $component_placeholders = new stdClass(); + $component_placeholders->type_title = 'Componentbuilder Component_placeholders'; + $component_placeholders->type_alias = 'com_componentbuilder.component_placeholders'; + $component_placeholders->table = '{"special": {"dbtable": "#__componentbuilder_component_placeholders","key": "id","type": "Component_placeholders","prefix": "componentbuilderTable","config": "array()"},"common": {"dbtable": "#__ucm_content","key": "ucm_id","type": "Corecontent","prefix": "JTable","config": "array()"}}'; + $component_placeholders->field_mappings = '{"common": {"core_content_item_id": "id","core_title": "joomla_component","core_state": "published","core_alias": "null","core_created_time": "created","core_modified_time": "modified","core_body": "null","core_hits": "hits","core_publish_up": "null","core_publish_down": "null","core_access": "access","core_params": "params","core_featured": "null","core_metadata": "null","core_language": "null","core_images": "null","core_urls": "null","core_version": "version","core_ordering": "ordering","core_metakey": "null","core_metadesc": "null","core_catid": "null","core_xreference": "null","asset_id": "asset_id"},"special": {"joomla_component":"joomla_component"}}'; + $component_placeholders->router = 'ComponentbuilderHelperRoute::getComponent_placeholdersRoute'; + $component_placeholders->content_history_options = '{"formFile": "administrator/components/com_componentbuilder/models/forms/component_placeholders.xml","hideFields": ["asset_id","checked_out","checked_out_time","version"],"ignoreChanges": ["modified_by","modified","checked_out","checked_out_time","version","hits"],"convertToInt": ["published","ordering","joomla_component"],"displayLookup": [{"sourceColumn": "created_by","targetTable": "#__users","targetColumn": "id","displayColumn": "name"},{"sourceColumn": "access","targetTable": "#__viewlevels","targetColumn": "id","displayColumn": "title"},{"sourceColumn": "modified_by","targetTable": "#__users","targetColumn": "id","displayColumn": "name"},{"sourceColumn": "joomla_component","targetTable": "#__componentbuilder_joomla_component","targetColumn": "id","displayColumn": "system_name"}]}'; + + // Check if component_placeholders type is already in content_type DB. + $component_placeholders_id = null; + $query = $db->getQuery(true); + $query->select($db->quoteName(array('type_id'))); + $query->from($db->quoteName('#__content_types')); + $query->where($db->quoteName('type_alias') . ' LIKE '. $db->quote($component_placeholders->type_alias)); + $db->setQuery($query); + $db->execute(); + + // Set the object into the content types table. + if ($db->getNumRows()) + { + $component_placeholders->type_id = $db->loadResult(); + $component_placeholders_Updated = $db->updateObject('#__content_types', $component_placeholders, 'type_id'); + } + else + { + $component_placeholders_Inserted = $db->insertObject('#__content_types', $component_placeholders); + } + // Create the snippet_type content type object. $snippet_type = new stdClass(); $snippet_type->type_title = 'Componentbuilder Snippet_type'; @@ -5172,7 +5426,7 @@ class com_componentbuilderInstallerScript echo ' -

Upgrade to Version 2.9.11 Was Successful! Let us know if anything is not working as expected.

'; +

Upgrade to Version 2.9.13 Was Successful! Let us know if anything is not working as expected.

'; } } diff --git a/site/helpers/componentbuilder.php b/site/helpers/componentbuilder.php index a2ba3a50c..51bd47f03 100644 --- a/site/helpers/componentbuilder.php +++ b/site/helpers/componentbuilder.php @@ -1179,6 +1179,20 @@ abstract class ComponentbuilderHelper return false; } + /** + * validate that a placeholder is unique + **/ + public static function validateUniquePlaceholder($string) + { + $string = self::safeString($string); + // this list may grow as we find more cases that break the compiler (just open an issue on github) + if (in_array($string, array('component', 'view', 'views'))) + { + return false; + } + return true; + } + /** * The array of dynamic content *