This commit is contained in:
2024-12-31 11:07:09 +01:00
parent df7915205d
commit e089172b15
1916 changed files with 165422 additions and 271 deletions

View File

@ -0,0 +1,113 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\GroupedlistField;
use Joomla\CMS\HTML\HTMLHelper;
use NRFramework\Extension;
class JFormFieldAcymailing extends GroupedlistField
{
/**
* Method to get the field option groups.
*
* @return array The field option objects as a nested array in groups.
*
* @since 1.6
*/
public function getGroups()
{
$groups = [];
$lists = [];
if ($acymailing_5_is_installed = Extension::isInstalled('com_acymailing'))
{
$lists['5'] = $this->getAcym5Lists();
}
if ($acymailing_6_is_installed = Extension::isInstalled('com_acym'))
{
$lists['6'] = $this->getAcym6Lists();
}
foreach ($lists as $group_key => $group)
{
if (!is_array($group))
{
continue;
}
foreach ($group as $list)
{
$groupLabel = 'AcyMailing ' . ($group_key == '5' ? $group_key : '');
$groups[$groupLabel][] = HTMLHelper::_('select.option', $list->id, $list->name);
}
}
return $groups;
}
/**
* Get AcyMailing 6 lists
*
* @return mixed Array on success, null on failure
*/
private function getAcym6Lists()
{
if (!@include_once(JPATH_ADMINISTRATOR . '/components/com_acym/helpers/helper.php'))
{
return;
}
$lists = acym_get('class.list')->getAll();
if (!is_array($lists))
{
return;
}
// Add 6: prefix to each list id.
foreach ($lists as $key => &$list)
{
$list->id = '6:' . $list->id;
}
return $lists;
}
/**
* Get AcyMailing 5 lists
*
* @return mixed Array on success, null on failure
*/
private function getAcym5Lists()
{
if (!@include_once(JPATH_ADMINISTRATOR . '/components/com_acymailing/helpers/helper.php'))
{
return;
}
$lists = acymailing_get('class.list')->getLists();
if (!is_array($lists))
{
return;
}
// The getGroups method expects the id property
foreach ($lists as $key => $list)
{
$list->id = $list->listid;
}
return $lists;
}
}

View File

@ -0,0 +1,213 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\Language\Text;
use Joomla\Filesystem\File;
use Joomla\CMS\Session\Session;
use Joomla\Registry\Registry;
use Joomla\CMS\Uri\Uri;
use NRFramework\HTML;
/*
* Creates an AJAX-based dropdown
* https://select2.org/
*/
abstract class JFormFieldAjaxify extends ListField
{
/**
* Textbox placeholder
*
* @var string
*/
protected $placeholder = 'Select Items';
/**
* AJAX rows limit
*
* @var int
*/
protected $limit = 50;
/**
* List of options.
*
* @var Registry
*/
protected $options;
/**
* Current page
*
* @var int
*/
protected $page;
/**
* Search term
*
* @var string
*/
protected $search_term;
/**
* Method to render the input field
*
* @return string
*/
protected function getInput()
{
if ($this->value && is_string($this->value))
{
$this->value = \NRFramework\Functions::makeArray($this->value);
}
$isSingle = !isset($this->element['multiple']) || $this->element['multiple'] == 'false';
$placeholder = (string) $this->element['placeholder'];
$this->placeholder = empty($placeholder) ? $this->placeholder : $placeholder;
$searchPlaceholder = isset($this->element['searchPlaceholder']) ? (string) $this->element['searchPlaceholder'] : false;
HTML::stylesheet('plg_system_nrframework/select2.css');
HTML::script('plg_system_nrframework/vendor/select2.min.js');
HTML::script('plg_system_nrframework/ajaxify.js');
if (!defined('isJ4'))
{
$this->class .= ' input-xxlarge select2 tf-select-ajaxify';
}
return '<div class="tf-ajaxify-wrapper" data-single-value="' . var_export($isSingle, true) . '" data-search-placeholder="' . Text::_($searchPlaceholder) . '" data-placeholder="' . htmlspecialchars(Text::_($this->placeholder)) . '" data-ajax-endpoint="' . $this->getAjaxEndpoint() . '">' . parent::getInput() . '</div>';
}
protected function getAjaxEndpoint()
{
$reflector = new ReflectionClass($this);
$filename = $reflector->getFileName();
$file = File::stripExt(basename($filename));
$token = Session::getFormToken();
$field_attributes = (array) $this->element->attributes();
$data = [
'task' => 'include',
'file' => $file,
'path' => 'plugins/system/nrframework/fields/',
'class' => get_called_class(),
$token => 1,
'field_attributes' => $field_attributes['@attributes']
];
return URI::base() . '?option=com_ajax&format=raw&plugin=nrframework&' . http_build_query($data);
}
/**
* Method to get the data to be passed to the layout for rendering.
*
* @return array
*/
protected function getLayoutData()
{
$data = parent::getLayoutData();
$extraData = [
'class' => 'input-xxlarge select2 tf-select-ajaxify'
];
return array_merge($data, $extraData);
}
/**
* Returns data object used by the AJAX request
*
* @param array $options
*
* @return array
*/
public function onAjax($options)
{
$this->options = new Registry($options);
// Reinitialize Field
$this->element = (array) $this->options->get('field_attributes');
$this->init();
$this->limit = $this->options->get('limit', $this->limit);
$this->page = $this->options->get('page', 1);
$this->search_term = $this->options->get('term');
$rows = $this->getItems();
$hasMoreRecords = false;
if ($this->limit > 0)
{
$total = $this->getItemsTotal();
$hasMoreRecords = ($this->page * $this->limit) < $total;
}
$data = [
'results' => $rows,
'pagination' => ['more' => $hasMoreRecords]
];
echo json_encode($data);
}
/**
* Load selected options
*
* @return void
*/
protected function getOptions()
{
$options = $this->value;
if (empty($options))
{
return;
}
// In case the value is previously saved in a comma separated format.
if (!is_array($options))
{
$options = explode(',', $options);
}
if (!method_exists($this, 'validateOptions'))
{
return $options;
}
// Remove empty and null items
$options = array_filter($options);
try
{
return $this->validateOptions($options);
}
catch (Exception $e)
{
echo $e->getMessage();
}
}
/**
* This method is called by the onAjax method and must return an array of arrays
*
* @return void
*/
abstract protected function getItems();
abstract protected function getItemsTotal();
}

View File

@ -0,0 +1,68 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
//
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Factory;
class JFormFieldAkeebaSubs extends ListField
{
/**
* Method to get a list of options for a list input.
*
* @return array An array of options.
*/
protected function getOptions()
{
if (!NRFramework\Extension::isInstalled('akeebasubs'))
{
return;
}
$lists = $this->getLevels();
if (!count($lists))
{
return;
}
$options = array();
foreach ($lists as $option)
{
$options[] = HTMLHelper::_('select.option', $option->id, $option->name);
}
return array_merge(parent::getOptions(), $options);
}
/**
* Retrieve all Akeeba Subscription Levels
*
* @return array Subscription Levels
*/
private function getLevels()
{
// Get a db connection.
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('l.akeebasubs_level_id as id, l.title AS name, l.enabled as published')
->from('#__akeebasubs_levels AS l')
->where('l.enabled > -1')
->order('l.title, l.akeebasubs_level_id');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use NRFramework\HTML;
class JFormFieldAssignmentSelection extends ListField
{
/**
* Assignment options
*
* @var array
*/
protected $options = array(
0 => 'JDISABLED',
1 => 'NR_INCLUDE',
2 => 'NR_EXCLUDE'
);
/**
* Return options list to field
*
* @return array
*/
protected function getOptions()
{
foreach ($this->options as $key => $value)
{
$options[] = HTMLHelper::_('select.option', $key, Text::_($value));
}
return array_merge(parent::getOptions(), $options);
}
/**
* Setup field with predefined classes and load its media files
*
* @param SimpleXMLElement $element
* @param String $value
* @param String $group
*
* @return SimpleXMLElement
*/
public function setup(SimpleXMLElement $element, $value, $group = NULL)
{
$return = parent::setup($element, $value, $group);
HTMLHelper::_('jquery.framework');
HTML::script('plg_system_nrframework/assignmentselection.js');
HTML::stylesheet('plg_system_nrframework/assignmentselection.css');
$this->class = 'assignmentselection chzn-color-state';
return $return;
}
}

View File

@ -0,0 +1,90 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
require_once dirname(__DIR__) . '/helpers/field.php';
###### Note ######
# This field is deprecated. Use NR_Well instead
###### Note ######
class JFormFieldNR_Block extends NRFormField
{
/**
* The field type.
*
* @var string
*/
public $type = 'nr_block';
protected function getLabel()
{
return '';
}
/**
* Method to render the input field
*
* @return string
*/
protected function getInput()
{
HTMLHelper::stylesheet('plg_system_nrframework/fields.css', false, true);
$title = $this->get('label');
$description = $this->get('description');
$class = $this->get('class');
$showclose = $this->get('showclose', 0);
$start = $this->get('start', 0);
$end = $this->get('end', 0);
$info = $this->get("html", null);
if ($info)
{
$info = str_replace("{{", "<", $info);
$info = str_replace("}}", ">", $info);
}
$html = array();
if ($start || !$end)
{
$html[] = '</div>';
if (strpos($class, 'alert') !== false)
{
$html[] = '<div class="alert ' . $class . '">';
}
else
{
$html[] = '<div class="well nr-well' . $class . '">';
}
if ($title)
{
$html[] = '<h4>' . $this->prepareText($title) . '</h4>';
}
if ($description)
{
$html[] = '<div class="well-desc">' . $this->prepareText($description) . $info . '</div>';
}
$html[] = '<div><div>';
}
if (!$start && !$end)
{
$html[] = '</div>';
}
return '</div>' . implode('', $html);
}
}

View File

@ -0,0 +1,69 @@
<?php
/**
* @author Tassos.gr <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\Language\Text;
class JFormFieldComparator extends ListField
{
private $defaults = [
'includes' => 'NR_IS',
'not_includes' => 'NR_IS_NOT'
];
/**
* Method to get the field input markup for a generic list.
* Use the multiple attribute to enable multiselect.
*
* @return string The field input markup.
*/
protected function getInput()
{
$this->required = true;
$this->class .= ' comparator';
return parent::getInput();
}
/**
* Return the label.
*
* @return string
*/
protected function getLabel()
{
if (!isset($this->element['label']))
{
return Text::_('NR_MATCH');
}
return parent::getLabel();
}
/**
* Return the options.
*
* @return string
*/
protected function getOptions()
{
if (!$options = parent::getOptions())
{
$options = $this->defaults;
foreach ($options as $key => &$value)
{
$value = Text::_($value);
}
}
return $options;
}
}

View File

@ -0,0 +1,229 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\Registry\Registry;
require_once __DIR__ . '/ajaxify.php';
/*
* Creates an AJAX-based dropdown
* https://select2.org/
*/
class JFormFieldComponentItems extends JFormFieldAjaxify
{
/**
* Single items table name
*
* @var string
*/
protected $table = 'content';
/**
* Primary key column of the single items table
*
* @var string
*/
protected $column_id = 'id';
/**
* The title column of the single items table
*
* @var string
*/
protected $column_title = 'title';
/**
* The state column of the single items table
*
* @var string
*/
protected $column_state = 'state';
/**
* Pass extra where SQL statement
*
* @var string
*/
protected $where;
/**
* Pass extra join SQL statement
*
* @var string
*/
protected $join;
/**
* Pass extra group SQL statement
*
* @var string
*/
protected $query_group;
/**
* The Joomla database object
*
* @var object
*/
protected $db;
/**
* Method to attach a JForm object to the field.
*
* @param SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` 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]".
*
* @return boolean True on success.
*
* @since 3.2
*/
public function setup(SimpleXMLElement $element, $value, $group = null)
{
if ($return = parent::setup($element, $value, $group))
{
$this->init();
}
return $return;
}
public function init()
{
$this->table = isset($this->element['table']) ? (string) $this->element['table'] : $this->table;
$this->column_id = isset($this->element['column_id']) ? (string) $this->element['column_id'] : $this->column_id;
$this->column_id = $this->prefix($this->column_id);
$this->column_title = isset($this->element['column_title']) ? (string) $this->element['column_title'] : $this->column_title;
$this->column_title = $this->prefix($this->column_title);
$this->column_state = isset($this->element['column_state']) ? (string) $this->element['column_state'] : $this->column_state;
$this->column_state = $this->prefix($this->column_state);
$this->where = isset($this->element['where']) ? (string) $this->element['where'] : null;
$this->join = isset($this->element['join']) ? (string) $this->element['join'] : null;
$this->query_group = isset($this->element['group']) ? (string) $this->element['group'] : null;
if (!isset($this->element['placeholder']) && isset($this->element['description']))
{
$this->placeholder = (string) $this->element['description'];
}
// Initialize database Object
$this->db = Factory::getDbo();
}
private function prefix($string)
{
if (strpos($string, '.') === false)
{
$string = 'i.' . $string;
}
return $string;
}
protected function getTemplateResult()
{
return '<span class="row-text">\' + state.text + \'</span><span style="float:right; opacity:.7">\' + state.id + \'</span>';
}
protected function getItemsQuery()
{
$db = $this->db;
$query = $this->getQuery()
->order($db->quoteName($this->column_id) . ' DESC');
if ($this->limit > 0)
{
// Joomla uses offset
$page = $this->page - 1;
$query->setLimit($this->limit, $page * $this->limit);
}
return $query;
}
protected function getItems()
{
$db = $this->db;
$db->setQuery($this->getItemsQuery());
return $db->loadObjectList();
}
protected function getItemsTotal()
{
$db = $this->db;
$query = $this->getQuery()
->clear('select')
->select('count(*)');
$db->setQuery($query);
return (int) $db->loadResult();
}
protected function getQuery()
{
$db = $this->db;
$query = $db->getQuery(true)
->select([
$db->quoteName($this->column_id, 'id'),
$db->quoteName($this->column_title, 'text'),
$db->quoteName($this->column_state, 'state')
])
->from($db->quoteName('#__' . $this->table, 'i'));
if (!empty($this->search_term))
{
$query->where($db->quoteName($this->column_title) . ' LIKE ' . $db->quote('%' . $this->search_term . '%'));
}
if ($this->join)
{
$query->join('INNER', $this->join);
}
if ($this->where)
{
$query->where($this->where);
}
if ($this->query_group)
{
$query->group($this->query_group);
}
return $query;
}
protected function validateOptions($options)
{
$db = $this->db;
$query = $this->getQuery()
->where($db->quoteName($this->column_id) . ' IN (' . implode(',', $options) . ')');
$db->setQuery($query);
return $db->loadAssocList('id', 'text');
}
}

View File

@ -0,0 +1,87 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\HiddenField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
use NRFramework\Conditions\ConditionBuilder;
use NRFramework\Extension;
class JFormFieldConditionBuilder extends HiddenField
{
/**
* Method to render the input field
*
* @return string
*/
protected function getInput()
{
// Condition Builder relies on com_ajax for AJAX requests.
if (!Extension::componentIsEnabled('ajax'))
{
\Factory::getApplication()->enqueueMessage(Text::_('AJAX Component is not enabled.'), 'error');
return;
}
// This is required on views we don't control such as the Fields or the Modules view page.
HTMLHelper::_('formbehavior.chosen', '.hasChosen');
HTMLHelper::stylesheet('plg_system_nrframework/fields.css', ['relative' => true, 'version' => 'auto']);
HTMLHelper::stylesheet('plg_system_nrframework/joomla' . (defined('nrJ4') ? '4' : '3') . '.css', ['relative' => true, 'version' => 'auto']);
Text::script('NR_CB_SELECT_CONDITION_GET_STARTED');
Text::script('NR_ARE_YOU_SURE_YOU_WANT_TO_DELETE_THIS_ITEM');
// Value must be always be a JSON string.
if (is_array($this->value))
{
$this->value = json_encode($this->value);
}
$style = '';
if ($max_width = (string) $this->element['max_width'])
{
$style = ' style="max-width:' . $max_width . ';"';
}
$payload = [
'include_rules' => isset($this->getOptions()['include_rules']) ? ConditionBuilder::prepareXmlRulesList($this->getOptions()['include_rules']) : '',
'exclude_rules' => isset($this->getOptions()['exclude_rules']) ? ConditionBuilder::prepareXmlRulesList($this->getOptions()['exclude_rules']) : '',
'exclude_rules_pro' => isset($this->getOptions()['exclude_rules_pro']) && $this->getOptions()['exclude_rules_pro'] === 'true',
'geo_modal' => ConditionBuilder::getGeoModal() // Out of context
];
return '
<div class="cb-wrapper"' . $style . '>
' . parent::getInput() . ConditionBuilder::getLayout('conditionbuilder', $payload) . '
</div>
';
}
/**
* Returns the field options.
*
* @return array
*/
protected function getOptions()
{
$options = [
'include_rules' => (string) $this->element['include_rules'],
'exclude_rules' => (string) $this->element['exclude_rules'],
'exclude_rules_pro' => (string) $this->element['exclude_rules_pro']
];
return $options;
}
}

View File

@ -0,0 +1,75 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
require_once dirname(__DIR__) . '/helpers/groupfield.php';
class JFormFieldNR_Content extends NRFormGroupField
{
public $type = 'Content';
public function getCategories()
{
$extension = isset($this->element['extension']) ? (string) $this->element['extension'] : 'com_content';
$query = $this->db->getQuery(true)
->select('COUNT(c.id)')
->from('#__categories AS c')
->where('c.extension = ' . $this->db->quote($extension))
->where('c.parent_id > 0')
->where('c.published > -1');
$this->db->setQuery($query);
$total = $this->db->loadResult();
$options = array();
if ($this->get('show_ignore'))
{
if (in_array('-1', $this->value))
{
$this->value = array('-1');
}
$options[] = HTMLHelper::_('select.option', '-1', '- ' . Text::_('NR_IGNORE') . ' -', 'value', 'text', 0);
$options[] = HTMLHelper::_('select.option', '-', '&nbsp;', 'value', 'text', 1);
}
$query->clear('select')
->select('c.id, c.title as name, c.level, c.published, c.language')
->order('c.lft');
$this->db->setQuery($query);
$list = $this->db->loadObjectList();
$options = array_merge($options, $this->getOptionsByList($list, array('language'), -1));
return $options;
}
public function getItems()
{
$query = $this->db->getQuery(true)
->select('COUNT(i.id)')
->from('#__content AS i')
->where('i.access > -1');
$this->db->setQuery($query);
$total = $this->db->loadResult();
$query->clear('select')
->select('i.id, i.title as name, i.language, c.title as cat, i.access as published')
->join('LEFT', '#__categories AS c ON c.id = i.catid')
->order('i.title, i.ordering, i.id');
$this->db->setQuery($query);
$list = $this->db->loadObjectList();
return $this->getOptionsByList($list, array('language', 'cat', 'id'));
}
}

View File

@ -0,0 +1,88 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
use Joomla\CMS\Form\FormField;
use Joomla\CMS\Factory;
class JFormFieldCSSSelector extends FormField
{
/**
* Render the Opening Hours
*
* @return string
*/
protected function getInput()
{
$isNew = $this->form->getData()->get('id') == 0;
if (is_string($this->value))
{
$this->value = json_decode($this->value, true);
}
$elName = (string) $this->element['name'];
$groups = explode('.', $this->group);
$groups[] = $elName;
$xml = array_map(function($group) {
return '<fields name="' . $group . '">';
}, $groups);
$xml = implode(' ', $xml);
$fieldsetUniqueName = $this->group . $elName;
$xml .= '
<fieldset name="' . $fieldsetUniqueName . '">
<field name="selector" type="text"
hiddenLabel="true"
filter="raw"
hint="NR_CSS_SELECTOR_ENTER"
default="' . ($isNew && isset($this->value['selector']) ? $this->value['selector'] : '') .'"
/>
<field name="task" type="list"
hiddenLabel="true"
default="' . ($isNew && isset($this->value['task']) ? $this->value['task'] : 'text') .'">
<option value="text">NR_CSS_SELECTOR_TEXT</option>
<option value="html">NR_CSS_SELECTOR_HTML</option>
<option value="innerhtml">NR_CSS_SELECTOR_INNER_HTML</option>
<option value="attr">NR_CSS_SELECTOR_ATTR</option>
<option value="count">NR_CSS_SELECTOR_TOTAL</option>
</field>
<field name="attr" type="text"
showon="task:attr"
hiddenLabel="true"
hint="NR_CSS_SELECTOR_ATTR_NAME"
default="' . ($isNew && isset($this->value['attr']) ? $this->value['attr'] : '') .'"
/>
</fieldset>
';
$xml .= str_repeat('</fields>', count($groups));
$this->form->setField(new SimpleXMLElement($xml));
$html = $this->form->renderFieldSet($fieldsetUniqueName);
Factory::getDocument()->addStyleDeclaration('
.css_selector_container {
display:flex;
gap:10px;
}
.css_selector_container .control-group {
margin:0;
width:270px;
}
');
return '<div class="css_selector_container">' . $html . '</div>';
}
}

View File

@ -0,0 +1,213 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
require_once JPATH_PLUGINS . '/system/nrframework/helpers/fieldlist.php';
class JFormFieldNR_Currencies extends NRFormFieldList
{
public $currencies = [
"AED" => "United Arab Emirates Dirham",
"AFN" => "Afghan Afghani",
"ALL" => "Albanian Lek",
"AMD" => "Armenian Dram",
"ANG" => "Netherlands Antillean Guilder",
"AOA" => "Angolan Kwanza",
"ARS" => "Argentine Peso",
"AUD" => "Australian Dollar",
"AWG" => "Aruban Florin",
"AZN" => "Azerbaijani Manat",
"BAM" => "Bosnia-Herzegovina Convertible Mark",
"BBD" => "Barbadian Dollar",
"BDT" => "Bangladeshi Taka",
"BGN" => "Bulgarian Lev",
"BHD" => "Bahraini Dinar",
"BIF" => "Burundian Franc",
"BMD" => "Bermudan Dollar",
"BND" => "Brunei Dollar",
"BOB" => "Bolivian Boliviano",
"BRL" => "Brazilian Real",
"BSD" => "Bahamian Dollar",
"BTC" => "Bitcoin",
"BTN" => "Bhutanese Ngultrum",
"BWP" => "Botswanan Pula",
"BYN" => "Belarusian Ruble",
"BYR" => "Belarusian Ruble (pre-2016)",
"BZD" => "Belize Dollar",
"CAD" => "Canadian Dollar",
"CDF" => "Congolese Franc",
"CHF" => "Swiss Franc",
"CLF" => "Chilean Unit of Account (UF)",
"CLP" => "Chilean Peso",
"CNY" => "Chinese Yuan",
"COP" => "Colombian Peso",
"CRC" => "Costa Rican Colón",
"CUC" => "Cuban Convertible Peso",
"CUP" => "Cuban Peso",
"CVE" => "Cape Verdean Escudo",
"CZK" => "Czech Republic Koruna",
"DJF" => "Djiboutian Franc",
"DKK" => "Danish Krone",
"DOP" => "Dominican Peso",
"DZD" => "Algerian Dinar",
"EEK" => "Estonian Kroon",
"EGP" => "Egyptian Pound",
"ERN" => "Eritrean Nakfa",
"ETB" => "Ethiopian Birr",
"EUR" => "Euro",
"FJD" => "Fijian Dollar",
"FKP" => "Falkland Islands Pound",
"GBP" => "British Pound Sterling",
"GEL" => "Georgian Lari",
"GGP" => "Guernsey Pound",
"GHS" => "Ghanaian Cedi",
"GIP" => "Gibraltar Pound",
"GMD" => "Gambian Dalasi",
"GNF" => "Guinean Franc",
"GTQ" => "Guatemalan Quetzal",
"GYD" => "Guyanaese Dollar",
"HKD" => "Hong Kong Dollar",
"HNL" => "Honduran Lempira",
"HRK" => "Croatian Kuna",
"HTG" => "Haitian Gourde",
"HUF" => "Hungarian Forint",
"IDR" => "Indonesian Rupiah",
"ILS" => "Israeli New Sheqel",
"IMP" => "Manx pound",
"INR" => "Indian Rupee",
"IQD" => "Iraqi Dinar",
"IRR" => "Iranian Rial",
"ISK" => "Icelandic Króna",
"JEP" => "Jersey Pound",
"JMD" => "Jamaican Dollar",
"JOD" => "Jordanian Dinar",
"JPY" => "Japanese Yen",
"KES" => "Kenyan Shilling",
"KGS" => "Kyrgystani Som",
"KHR" => "Cambodian Riel",
"KMF" => "Comorian Franc",
"KPW" => "North Korean Won",
"KRW" => "South Korean Won",
"KWD" => "Kuwaiti Dinar",
"KYD" => "Cayman Islands Dollar",
"KZT" => "Kazakhstani Tenge",
"LAK" => "Laotian Kip",
"LBP" => "Lebanese Pound",
"LKR" => "Sri Lankan Rupee",
"LRD" => "Liberian Dollar",
"LSL" => "Lesotho Loti",
"LTL" => "Lithuanian Litas",
"LVL" => "Latvian Lats",
"LYD" => "Libyan Dinar",
"MAD" => "Moroccan Dirham",
"MDL" => "Moldovan Leu",
"MGA" => "Malagasy Ariary",
"MKD" => "Macedonian Denar",
"MMK" => "Myanma Kyat",
"MNT" => "Mongolian Tugrik",
"MOP" => "Macanese Pataca",
"MRO" => "Mauritanian Ouguiya",
"MTL" => "Maltese Lira",
"MUR" => "Mauritian Rupee",
"MVR" => "Maldivian Rufiyaa",
"MWK" => "Malawian Kwacha",
"MXN" => "Mexican Peso",
"MYR" => "Malaysian Ringgit",
"MZN" => "Mozambican Metical",
"NAD" => "Namibian Dollar",
"NGN" => "Nigerian Naira",
"NIO" => "Nicaraguan Córdoba",
"NOK" => "Norwegian Krone",
"NPR" => "Nepalese Rupee",
"NZD" => "New Zealand Dollar",
"OMR" => "Omani Rial",
"PAB" => "Panamanian Balboa",
"PEN" => "Peruvian Nuevo Sol",
"PGK" => "Papua New Guinean Kina",
"PHP" => "Philippine Peso",
"PKR" => "Pakistani Rupee",
"PLN" => "Polish Zloty",
"PYG" => "Paraguayan Guarani",
"QAR" => "Qatari Rial",
"RON" => "Romanian Leu",
"RSD" => "Serbian Dinar",
"RUB" => "Russian Ruble",
"RWF" => "Rwandan Franc",
"SAR" => "Saudi Riyal",
"SBD" => "Solomon Islands Dollar",
"SCR" => "Seychellois Rupee",
"SDG" => "Sudanese Pound",
"SEK" => "Swedish Krona",
"SGD" => "Singapore Dollar",
"SHP" => "Saint Helena Pound",
"SLL" => "Sierra Leonean Leone",
"SOS" => "Somali Shilling",
"SRD" => "Surinamese Dollar",
"STD" => "São Tomé and Príncipe Dobra",
"SVC" => "Salvadoran Colón",
"SYP" => "Syrian Pound",
"SZL" => "Swazi Lilangeni",
"THB" => "Thai Baht",
"TJS" => "Tajikistani Somoni",
"TMT" => "Turkmenistani Manat",
"TND" => "Tunisian Dinar",
"TOP" => "Tongan Pa?anga",
"TRY" => "Turkish Lira",
"TTD" => "Trinidad and Tobago Dollar",
"TWD" => "New Taiwan Dollar",
"TZS" => "Tanzanian Shilling",
"UAH" => "Ukrainian Hryvnia",
"UGX" => "Ugandan Shilling",
"USD" => "United States Dollar",
"UYU" => "Uruguayan Peso",
"UZS" => "Uzbekistan Som",
"VEF" => "Venezuelan Bolívar Fuerte",
"VND" => "Vietnamese Dong",
"VUV" => "Vanuatu Vatu",
"WST" => "Samoan Tala",
"XAF" => "CFA Franc BEAC",
"XAG" => "Silver Ounce",
"XAU" => "Gold Ounce",
"XCD" => "East Caribbean Dollar",
"XDR" => "Special Drawing Rights",
"XOF" => "CFA Franc BCEAO",
"XPD" => "Palladium Ounce",
"XPF" => "CFP Franc",
"XPT" => "Platinum Ounce",
"YER" => "Yemeni Rial",
"ZAR" => "South African Rand",
"ZMK" => "Zambian Kwacha (pre-2013)",
"ZMW" => "Zambian Kwacha",
"ZWL" => "Zimbabwean Dollar",
];
protected function getOptions()
{
$options = array();
if ($this->showSelect())
{
$options[] = HTMLHelper::_('select.option', "", "- " . Text::_("NR_SELECT_CURRENCY"). " -");
}
asort($this->currencies);
foreach ($this->currencies as $key => $value)
{
$options[] = HTMLHelper::_('select.option', $key, $key . " (" . $value . ")");
}
return array_merge(parent::getOptions(), $options);
}
}

View File

@ -0,0 +1,77 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\Language\Text;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNR_Freetext extends NRFormField
{
/**
* The field type.
*
* @var string
*/
public $type = 'freetext';
/**
* Method to render the input field
*
* @return string
*/
protected function getInput()
{
$file = $this->get("file", false);
$text = $this->get("text", false);
$label = $this->get("label", false);
$description = $this->get("description", false);
if (!$label)
{
$html[] = '</div><div class="freetext '.$this->get("class").'">';
}
if ($file)
{
$html[] = $this->renderContent($this->get("file"), $this->get("path"), $this);
}
if ($text)
{
$html[] = $this->prepareText($text);
if (!defined('nrJ4') && $description)
{
$html[] = '<p class="description">' . Text::_($description) . '</p>';
}
}
return implode(" ", $html);
}
/**
* Render PHP file with data
*
* @param string $file The file name
* @param string $path The pathname
* @param mixed $displayData The data object passed to template file
*
* @return string HTML rendered
*/
private function renderContent($file, $path, $displayData = null)
{
$layout = new FileLayout($file, JPATH_SITE . $path, array('debug' => 0));
return $layout->render($displayData);
}
}

View File

@ -0,0 +1,63 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
require_once JPATH_PLUGINS . '/system/nrframework/helpers/fieldlist.php';
class JFormFieldNR_Geo extends NRFormFieldList
{
private $list;
protected function getInput()
{
if ($this->get('detect_visitor_country', false) && empty($this->value) && $countryCode = \NRFramework\Helpers\Geo::getVisitorCountryCode())
{
$this->value = $countryCode;
}
return parent::getInput();
}
protected function getOptions()
{
switch ($this->get('geo'))
{
case 'continents':
$this->list = \NRFramework\Continents::getContinentsList();
$selectLabel = 'NR_SELECT_CONTINENT';
break;
default:
$this->list = \NRFramework\Countries::getCountriesList();
$selectLabel = 'NR_SELECT_COUNTRY';
break;
}
if ($this->get('use_label_as_value', false))
{
$this->list = array_combine($this->list, $this->list);
}
$options = array();
if ($this->get("showselect", 'true') === 'true')
{
$options[] = HTMLHelper::_('select.option', "", "- " . Text::_($selectLabel) . " -");
}
foreach ($this->list as $key => $value)
{
$options[] = HTMLHelper::_('select.option', $key, $value);
}
return array_merge(parent::getOptions(), $options);
}
}

View File

@ -0,0 +1,88 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\FormField;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
class JFormFieldGeoDBChecker extends FormField
{
/**
* Whether TGeoIP is disabled or not.
*
* @var boolean
*/
private $tgeoip_plugin_disabled = false;
protected function getLabel()
{
return;
}
/**
* Renders the field.
*
* @param array $options
*
* @return string
*/
public function renderField($options = [])
{
// Check if TGeoIP plugin is enabled
if (!\NRFramework\Extension::pluginIsEnabled('tgeoip'))
{
$this->tgeoip_plugin_disabled = true;
return parent::renderField($options);
}
// Do not render the field if the database is up-to-date
if (!\NRFramework\Extension::geoPluginNeedsUpdate())
{
return;
}
return parent::renderField($options);
}
/**
* Shows a warning message when the Geolocation plugin is disabled.
*
* @return string
*/
private function disabledPluginWarning()
{
return '<div class="alert alert-warning geo-db-checker" style="margin-top: 0; margin-bottom: 0;">' .
'<h3 style="margin-top:0;">' . Text::sprintf('NR_GEO_PLUGIN_DISABLED') . '</h3>' .
'<p>' . Text::sprintf('NR_GEO_PLUGIN_DISABLED_DESC', '<a href="' . Route::_('index.php?option=com_plugins&view=plugins&filter' . (defined('nrJ4') ? '[search]' : '_search') . '=System - Tassos.gr GeoIP Plugin') . '" target="_blank">', '</a>') . '</p>' .
'</div>';
}
/**
* If the geolocation database is missing or its outdated, then display a helpful message
* to the usser notifying them that they need to update.
*
* @return string
*/
protected function getInput()
{
if ($this->tgeoip_plugin_disabled)
{
return $this->disabledPluginWarning();
}
return '<div class="alert alert-info" style="margin: 0;">' .
'<h3 style="margin-top:0;">' . Text::sprintf('NR_GEO_MAINTENANCE') . '</h3>' .
'<p>' . Text::sprintf('NR_GEO_MAINTENANCE_DESC') . '</p>' .
'<a class="btn btn-success" data-toggle="modal" data-bs-toggle="modal" href="#tf-geodbchecker-modal"><span class="icon-refresh"></span> Update Database</a>' .
'</div>';
}
}

View File

@ -0,0 +1,374 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2024 Tassos Marinos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\ListField;
// Define a new class extending Joomla's ListField for Google Product Categories
class JFormFieldTassos_GoogleProductCategory extends ListField
{
/**
* Dropdown options array
*
* @var array
*/
private $options;
/**
* Static array defining 1st and 2nd level categories for Google Product Categories
*
* @reference: https://www.google.com/basepages/producttype/taxonomy-with-ids.en-US.xls
*
* @var array
*/
private static $categories = [
1 => [
'title' => 'Animals & Pet Supplies',
'subcategories' => [
3237 => 'Live Animals',
2 => 'Pet Supplies'
]
],
166 => [
'title' => 'Apparel & Accessories',
'subcategories' => [
1604 => 'Clothing',
167 => 'Clothing Accessories',
184 => 'Costumes & Accessories',
6552 => 'Handbag & Wallet Accessories',
6551 => 'Handbags, Wallets & Cases',
188 => 'Jewelry',
1933 => 'Shoe Accessories',
187 => 'Shoes'
]
],
8 => [
'title' => 'Arts & Entertainment',
'subcategories' => [
499969 => 'Event Tickets',
5710 => 'Hobbies & Creative Arts',
5709 => 'Party & Celebration'
]
],
537 => [
'title' => 'Baby & Toddler',
'subcategories' => [
4678 => 'Baby Bathing',
5859 => 'Baby Gift Sets',
5252 => 'Baby Health',
540 => 'Baby Safety',
2847 => 'Baby Toys & Activity Equipment',
2764 => 'Baby Transport',
4386 => 'Baby Transport Accessories',
548 => 'Diapering',
561 => 'Nursing & Feeding',
6952 => 'Potty Training',
6899 => 'Swaddling & Receiving Blankets'
]
],
111 => [
'title' => 'Business & Industrial',
'subcategories' => [
5863 => 'Advertising & Marketing',
112 => 'Agriculture',
7261 => 'Automation Control Components',
114 => 'Construction',
7497 => 'Dentistry',
2155 => 'Film & Television',
1813 => 'Finance & Insurance',
135 => 'Food Service',
1827 => 'Forestry & Logging',
7240 => 'Hairdressing & Cosmetology',
1795 => 'Heavy Machinery',
1475 => 'Hotel & Hospitality',
5830 => 'Industrial Storage',
8025 => 'Industrial Storage Accessories',
500086 => 'Janitorial Carts & Caddies',
1556 => 'Law Enforcement',
1470 => 'Manufacturing',
6987 => 'Material Handling',
2496 => 'Medical',
2187 => 'Mining & Quarrying',
4285 => 'Piercing & Tattooing',
138 => 'Retail',
1624 => 'Science & Laboratory',
976 => 'Signage',
2047 => 'Work Safety Protective Gear'
]
],
141 => [
'title' => 'Cameras & Optics',
'subcategories' => [
2096 => 'Camera & Optic Accessories',
142 => 'Cameras',
156 => 'Optics',
39 => 'Photography'
]
],
222 => [
'title' => 'Electronics',
'subcategories' => [
3356 => 'Arcade Equipment',
223 => 'Audio',
3702 => 'Circuit Boards & Components',
262 => 'Communications',
1801 => 'Components',
278 => 'Computers',
2082 => 'Electronics Accessories',
3895 => 'GPS Accessories',
339 => 'GPS Navigation Systems',
6544 => 'GPS Tracking Devices',
340 => 'Marine Electronics',
342 => 'Networking',
345 => 'Print, Copy, Scan & Fax',
912 => 'Radar Detectors',
500091 => 'Speed Radars',
4488 => 'Toll Collection Devices',
386 => 'Video',
1270 => 'Video Game Console Accessories',
1294 => 'Video Game Consoles'
]
],
412 => [
'title' => 'Food, Beverages & Tobacco',
'subcategories' => [
413 => 'Beverages',
422 => 'Food Items',
435 => 'Tobacco Products'
]
],
436 => [
'title' => 'Furniture',
'subcategories' => [
554 => 'Baby & Toddler Furniture',
6433 => 'Beds & Accessories',
441 => 'Benches',
6356 => 'Cabinets & Storage',
442 => 'Carts & Islands',
7248 => 'Chair Accessories',
443 => 'Chairs',
457 => 'Entertainment Centers & TV Stands',
6345 => 'Furniture Sets',
6860 => 'Futon Frames',
2786 => 'Futon Pads',
450 => 'Futons',
6362 => 'Office Furniture',
503765 => 'Office Furniture Accessories',
458 => 'Ottomans',
4299 => 'Outdoor Furniture',
6963 => 'Outdoor Furniture Accessories',
6915 => 'Room Divider Accessories',
4163 => 'Room Dividers',
464 => 'Shelving',
8023 => 'Shelving Accessories',
7212 => 'Sofa Accessories',
460 => 'Sofas',
6913 => 'Table Accessories',
6392 => 'Tables'
]
],
632 => [
'title' => 'Hardware',
'subcategories' => [
503739 => 'Building Consumables',
115 => 'Building Materials',
128 => 'Fencing & Barriers',
543575 => 'Fuel',
502975 => 'Fuel Containers & Tanks',
2878 => 'Hardware Accessories',
500096 => 'Hardware Pumps',
499873 => 'Heating, Ventilation & Air Conditioning',
1974 => 'Locks & Keys',
133 => 'Plumbing',
127 => 'Power & Electrical Supplies',
499982 => 'Small Engines',
1910 => 'Storage Tanks',
3650 => 'Tool Accessories',
1167 => 'Tools'
]
],
469 => [
'title' => 'Health & Beauty',
'subcategories' => [
491 => 'Health Care',
5573 => 'Jewelry Cleaning & Care',
2915 => 'Personal Care'
]
],
536 => [
'title' => 'Home & Garden',
'subcategories' => [
574 => 'Bathroom Accessories',
359 => 'Business & Home Security',
696 => 'Decor',
5835 => 'Emergency Preparedness',
2862 => 'Fireplace & Wood Stove Accessories',
6792 => 'Fireplaces',
1679 => 'Flood, Fire & Gas Safety',
3348 => 'Household Appliance Accessories',
604 => 'Household Appliances',
630 => 'Household Supplies',
638 => 'Kitchen & Dining',
689 => 'Lawn & Garden',
594 => 'Lighting',
2956 => 'Lighting Accessories',
4171 => 'Linens & Bedding',
4358 => 'Parasols & Rain Umbrellas',
985 => 'Plants',
729 => 'Pool & Spa',
600 => 'Smoking Accessories',
6173 => 'Umbrella Sleeves & Cases',
2639 => 'Wood Stoves'
]
],
5181 => [
'title' => 'Luggage & Bags',
'subcategories' => [
100 => 'Backpacks',
101 => 'Briefcases',
108 => 'Cosmetic & Toiletry Bags',
549 => 'Diaper Bags',
502974 => 'Dry Boxes',
103 => 'Duffel Bags',
104 => 'Fanny Packs',
105 => 'Garment Bags',
110 => 'Luggage Accessories',
106 => 'Messenger Bags',
5608 => 'Shopping Totes',
107 => 'Suitcases',
6553 => 'Train Cases'
]
],
772 => [
'title' => 'Mature',
'subcategories' => [
773 => 'Erotic',
780 => 'Weapons'
]
],
783 => [
'title' => 'Media',
'subcategories' => [
784 => 'Books',
499995 => 'Carpentry & Woodworking Project Plans',
839 => 'DVDs & Videos',
886 => 'Magazines & Newspapers',
855 => 'Music & Sound Recordings',
5037 => 'Product Manuals',
887 => 'Sheet Music'
]
],
922 => [
'title' => 'Office Supplies',
'subcategories' => [
6174 => 'Book Accessories',
8078 => 'Desk Pads & Blotters',
923 => 'Filing & Organization',
932 => 'General Office Supplies',
5829 => 'Impulse Sealers',
8499 => 'Lap Desks',
2435 => 'Name Plates',
6519 => 'Office & Chair Mats',
6373 => 'Office Carts',
950 => 'Office Equipment',
2986 => 'Office Instruments',
2014 => 'Paper Handling',
964 => 'Presentation Supplies',
2636 => 'Shipping Supplies'
]
],
5605 => [
'title' => 'Religious & Ceremonial',
'subcategories' => [
5606 => 'Memorial Ceremony Supplies',
97 => 'Religious Items',
5455 => 'Wedding Ceremony Supplies'
]
],
2092 => [
'title' => 'Software',
'subcategories' => [
313 => 'Computer Software',
5032 => 'Digital Goods & Currency',
1279 => 'Video Game Software'
]
],
988 => [
'title' => 'Sporting Goods',
'subcategories' => [
499713 => 'Athletics',
990 => 'Exercise & Fitness',
1001 => 'Indoor Games',
1011 => 'Outdoor Recreation'
]
],
1239 => [
'title' => 'Toys & Games',
'subcategories' => [
4648 => 'Game Timers',
3793 => 'Games',
1249 => 'Outdoor Play Equipment',
3867 => 'Puzzles',
1253 => 'Toys'
]
],
888 => [
'title' => 'Vehicles & Parts',
'subcategories' => [
5613 => 'Vehicle Parts & Accessories',
5614 => 'Vehicles'
]
]
];
/**
* Returns all options to dropdown field
*
* This function merges options and returns the complete list of options to be displayed in the dropdown field of the form.
*
* @return array Array of options for the dropdown
*/
protected function getOptions()
{
return array_merge(parent::getOptions(), $this->buildTree());
}
/**
* Recursive traversal of the businessTypes array tree
*
* @param Array $types The business types
* @param integer $level The array level
*
* @return array
*/
private function buildTree()
{
foreach (self::$categories as $id => $firstLevelData)
{
$this->options[] = [
'value' => $id,
'text' => $firstLevelData['title'],
];
foreach ($firstLevelData['subcategories'] as $id => $title)
{
$this->options[] = [
'value' => $id,
'text' => '- ' . $title,
];
}
}
return $this->options;
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Form\FormHelper;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNR_Inline extends NRFormField
{
public function renderField($options = [])
{
HTMLHelper::stylesheet('plg_system_nrframework/inline-control-group.css', ['relative' => true, 'version' => 'auto']);
$start = $this->get('start', 1);
$end = $this->get('end', 0);
if ($start && !$end)
{
// Apply showon on the start of the inline field
$showon = '';
if ($dataShowon = $this->get('showon'))
{
$dataShowon = FormHelper::parseShowOnConditions($dataShowon, $this->formControl, $this->group);
$showon = ' data-showon="' . htmlspecialchars(json_encode($dataShowon)) . '"';
}
$label = $this->getLabel() ? '<div class="control-label">' . $this->getLabel() . '</div>' : '';
return '<div class="control-group"' . $showon . '>' . $label . '<div class="controls"><div class="inline-control-group' . ($this->class ? ' ' . $this->class : '') . '">';
}
return '</div></div>' . ($this->getLabel() ? '</div>' : '') . '</div>';
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\Registry\Registry;
require_once __DIR__ . '/componentitems.php';
class JFormFieldJShoppingComponentItems extends JFormFieldComponentItems
{
public function init()
{
// Get default language
$this->element['column_title'] = 'name_' . $this->getLanguage();
parent::init();
}
/**
* JoomShopping is using different columns per language. Therefore, we need to use their API to get the default language code.
*
* @return string
*/
private function getLanguage($default = 'en-GB')
{
// Silent inclusion.
@include_once JPATH_SITE . '/components/com_jshopping/lib/factory.php';
// JoomShopping 5.0+ fix
@include_once JPATH_SITE . '/components/com_jshopping/bootstrap.php';
if (!class_exists('JSFactory'))
{
return $default;
}
return JSFactory::getConfig()->defaultLanguage;
}
}

View File

@ -0,0 +1,119 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
require_once JPATH_PLUGINS . '/system/nrframework/helpers/fieldlist.php';
class JFormFieldModules extends NRFormFieldList
{
/**
* Method to get a list of options for a list input.
*
* @return array An array of options.
*/
protected function getOptions()
{
$db = $this->db;
$this->layout = 'joomla.form.field.list-fancy-select';
$query = $db->getQuery(true);
$query->select('*')
->from('#__modules')
->where('published=1')
->where('access !=3')
->order('title');
$editingModuleId = $this->getEditingModuleID();
$client = isset($this->element['client']) ? (int) $this->element['client'] : false;
// If we're creating a new module, use the client_id from the browser
$input = Factory::getApplication()->input;
$url_client_id = $input->get('client_id', '');
if ($url_client_id !== '')
{
$client = $url_client_id;
}
// If we're editing a module
if ($editingModuleId)
{
// If it's an admin module
$editingBackendModuleDetails = \NRFramework\Helpers\Module::getData($editingModuleId, 'id', ['client_id' => 1]);
// Show only admin modules
if ($editingBackendModuleDetails)
{
$client = '1';
}
}
if ($client !== false)
{
$query->where('client_id = ' . $client);
}
// Exclude currently editing module
$excludeEditingModule = isset($this->element['excludeeditingmodule']) && (string) $this->element['excludeeditingmodule'] === 'true' ? true : false;
if ($excludeEditingModule && $editingModuleId)
{
$query->where('id != ' . $editingModuleId);
}
$rows = $db->setQuery($query);
$results = $db->loadObjectList();
$options = array();
if ($this->showSelect())
{
$options[] = HTMLHelper::_('select.option', "", '- ' . Text::_("NR_SELECT_MODULE") . ' -');
}
foreach ($results as $option)
{
$options[] = HTMLHelper::_('select.option', $option->id, $option->title . ' (' . $option->id . ')');
}
$options = array_merge(parent::getOptions(), $options);
return $options;
}
private function getEditingModuleID()
{
$input = Factory::getApplication()->input;
/**
* First check the keys `request_option` and `request_layout` respectively instead of `option` and `layout`
* in case an AJAX request needs to sends us these data but cannot use the `option` and `layout` as different
* values are needed for the AJAX request to function properly.
*
* i.e. ConditionBuilder's "Viewed Another Box" should not display the current box when fetching the rule fields
* via AJAX. Since its not possible to get the current box ID after the AJAX has happened, we send the `id`
* (popup ID) alongside the `request_option` (com_rstbox) and `request_layout` (edit) parameters.
*/
$option = $input->get('request_option') ? $input->get('request_option') : $input->get('option');
$layout = $input->get('request_layout') ? $input->get('request_layout') : $input->get('layout');
if (in_array($option, ['com_modules', 'com_advancedmodules']) && $layout == 'edit')
{
return (int) $input->getInt('id');
}
return false;
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
require_once JPATH_PLUGINS . '/system/nrframework/helpers/fieldlist.php';
class JFormFieldNRBrowser extends NRFormFieldList
{
/**
* Browsers List
*
* @var array
*/
public $options = array(
'chrome' => 'NR_CHROME',
'firefox' => 'NR_FIREFOX',
'edge' => 'NR_EDGE',
'ie' => 'NR_IE',
'safari' => 'NR_SAFARI',
'opera' => 'NR_OPERA'
);
protected function getOptions()
{
asort($this->options);
foreach ($this->options as $key => $option)
{
$options[] = HTMLHelper::_('select.option', $key, Text::_($option));
}
return array_merge(parent::getOptions(), $options);
}
}

View File

@ -0,0 +1,394 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Layout\FileLayout;
use Joomla\Registry\Registry;
use Joomla\CMS\Language\Text;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNRChainedFields extends NRFormField
{
/**
* All CSV choices.
*
* @var array
*/
protected $choices = [];
/**
* The separator used in the CSV file.
*
* @var string
*/
protected $separator = ',';
/**
* The data source contents.
*
* @var string
*/
protected $dataset = '';
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*/
protected function getInput()
{
$layout = new FileLayout('chainedfields', JPATH_PLUGINS . '/system/nrframework/layouts');
$data_source = $this->get('data_source', 'custom');
switch ($data_source)
{
case 'custom':
$this->dataset = $this->get('data_source_custom', '');
break;
case 'csv_file':
$csv_file = $this->get('data_source_csv', '');
if (!file_exists($csv_file))
{
return;
}
$this->dataset = $csv_file;
break;
}
$this->separator = $this->get('separator', ',');
$data = [
'csv' => $this->dataset,
'data_source' => $data_source,
'value' => $this->getValue(),
'data' => $this->getData()
];
return $layout->render($data);
}
/**
* Returns the field value.
*
* @return mixed
*/
private function getValue()
{
if (!$this->value)
{
return null;
}
if (!$this->choices = \NRFramework\Helpers\ChainedFields::loadCSV($this->dataset, $this->get('data_source', 'custom'), $this->separator, $this->id . '_', $this->name))
{
return null;
}
$choices = $this->choices['inputs'];
// Ensure the value is in correct format when used as plain field or in subform
$this->value = array_values((array) $this->value);
foreach ($this->choices['inputs'] as $key => $input)
{
$choices[$key]['choices'] = $this->getSelectedChoices($key, $this->value, $input);
}
return $choices;
}
/**
* Finds the choices of the select.
*
* @param string $key
* @param array $value
* @param array $input
*
* @return mixed
*/
private function getSelectedChoices($key, $value, $input)
{
$choices = $this->getSelectChoices($value, $input['id']);
if (!is_array($choices))
{
return null;
}
// set selected options based on value
foreach ($choices as $_key => &$choice)
{
if (!isset($value[$key]) || $choice['value'] !== $value[$key])
{
continue;
}
$choice['isSelected'] = true;
}
return $choices;
}
/**
* Handles the AJAX request.
*
* Runs when select a value from a select field.
*
* @param array $options
*
* @return array
*/
public function onAjax($options)
{
$options = new Registry($options);
if (!$select_id = $options->get('select_id'))
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
]);
jexit();
}
if (!$value = $options->get('value'))
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
]);
jexit();
}
if (!$value = json_decode($options->get('value'), true))
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
]);
jexit();
}
if (!$data_source = $options->get('data_source'))
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
]);
jexit();
}
if (!$csv = $options->get('csv'))
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
]);
jexit();
}
$csv = json_decode($csv, true);
// get field ID from select ID
$id = preg_replace('/_[0-9]+$/', '', $select_id);
if (!$id || !$select_id || !$value || !$csv)
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
]);
jexit();
}
$this->id = $id;
// get all CSV data
if (!$this->choices = \NRFramework\Helpers\ChainedFields::loadCSV($csv, $data_source, $this->separator, $this->id . '_', $this->name))
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_CANNOT_PROCESS_REQUEST')
]);
jexit();
}
// find next select options
$this->findNextOptions($id, $select_id, $value);
}
/**
* Finds the options of the next select.
*
* @param string $id
* @param string $select_id
* @param array $value
*
* @return void
*/
private function findNextOptions($id, $select_id, $value)
{
// find next ID
$next_select_id = $this->getNextSelectID($id, $select_id);
// get next choices
$choices = $next_select_id ? $this->getSelectChoices($value, $next_select_id) : [];
echo json_encode([
'error' => false,
'response' => $choices
]);
jexit();
}
/**
* Returns the select choices.
*
* @param array $field_value
* @param string $select_id
* @param integer $depth
* @param array $choices
* @param array $full_field_value
*
* @return array
*/
private function getSelectChoices($field_value = null, $select_id = null, $depth = null, $choices = null, $full_field_value = null)
{
$full_field_value = $full_field_value !== null ? $full_field_value : $field_value;
$value = array_shift($field_value);
$index = $select_id ? $this->getSelectID($select_id) : 1;
$depth = $depth ? $depth : 1;
$choices = $choices === null ? $this->choices['choices'] : (empty($choices) ? [] : $choices);
$select_choices = [];
if ($depth == $index)
{
$select_choices = $choices;
}
else
{
foreach ($choices as $choice)
{
if ($choice['value'] !== $value)
{
continue;
}
$select_choices = $this->getSelectChoices($field_value, $select_id, $depth + 1, !empty($choice['choices']) ? $choice['choices'] : [], $full_field_value);
break;
}
}
if (empty($select_choices) && $this->getPreviousSelectValue($select_id, $full_field_value))
{
$select_choices = [
[
'text' => 'No options',
'value' => '',
'isSelected' => true
]
];
}
return $select_choices;
}
/**
* Returns the previous select value
*
* @param string $select_id
* @param string $full_field_value
*
* @return string
*/
public function getPreviousSelectValue($select_id, $full_field_value)
{
$explode = explode('_', $select_id);
$input_id = $explode[count($explode) - 1];
$field_id = rtrim($select_id, '_' . $input_id);
$prev_input_id = sprintf('%s.%s', $field_id, $input_id - 1);
$prev_input_value = isset($full_field_value[$prev_input_id]) ? $full_field_value[$prev_input_id] : null;
return $prev_input_value;
}
/**
* Finds the next select ID
*
* @param string $base_id
* @param string $select_id
*
* @return mixed
*/
public function getNextSelectID($base_id, $select_id)
{
$id = $this->getSelectID($select_id);
$next_id = $id + 1;
if ($next_id % 10 == 0)
{
$next_id++;
}
$next_select_id = sprintf('%s_%d', $base_id, $next_id);
foreach ($this->choices['inputs'] as $input)
{
if ($input['id'] != $next_select_id)
{
continue;
}
return $next_select_id;
}
return false;
}
/**
* Gets the ID (index) of the select by its ID.
*
* @param string $select_id
*
* @return int
*/
public function getSelectID($select_id)
{
$explode = explode('_', $select_id);
return (int) array_pop($explode);
}
/**
* Fetches all CSV data.
*
* @return array
*/
private function getData()
{
if (!$this->dataset)
{
return [];
}
if (!$choices = \NRFramework\Helpers\ChainedFields::loadCSV($this->dataset, $this->get('data_source', 'csv_file'), $this->separator, $this->id . '_', $this->name))
{
return [];
}
return $choices;
}
}

View File

@ -0,0 +1,132 @@
<?php
/**
* @author Tassos.gr <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
class JFormFieldNRComponents extends ListField
{
protected function getOptions()
{
return array_merge(parent::getOptions(), $this->getInstalledComponents());
}
/**
* Method to get field parameters
*
* @param string $val Field parameter
* @param string $default The default value
*
* @return string
*/
public function get($val, $default = '')
{
return (isset($this->element[$val]) && (string) $this->element[$val] != '') ? (string) $this->element[$val] : $default;
}
/**
* Creates a list of installed components
*
* @return array
*/
protected function getInstalledComponents()
{
$lang = Factory::getLanguage();
$db = Factory::getDbo();
$components = $db->setQuery(
$db->getQuery(true)
->select('name, element')
->from('#__extensions')
->where('type = ' . $db->quote('component'))
->where('name != ""')
->where('element != ""')
->where('enabled = 1')
->order('element, name')
)->loadObjectList();
$comps = array();
foreach ($components as $component)
{
// Make sure we have a valid element
if (empty($component->element))
{
continue;
}
// Skip backend-based only components
if ($this->get('frontend', false))
{
$component_folder = JPATH_SITE . '/components/' . $component->element;
if (!is_dir($component_folder))
{
continue;
}
if (!is_dir($component_folder . '/views') &&
!is_dir($component_folder . '/View') &&
!is_dir($component_folder . '/view'))
{
continue;
}
}
// Try loading component's system language file in order to display a user friendly component name
// Runs only if the component's name is not translated already.
if (strpos($component->name, ' ') === false)
{
$filenames = [
$component->element . '.sys',
$component->element
];
$paths = [
JPATH_ADMINISTRATOR,
JPATH_ADMINISTRATOR . '/components/' . $component->element,
JPATH_SITE,
JPATH_SITE . '/components/' . $component->element
];
foreach ($filenames as $key => $filename)
{
foreach ($paths as $key => $path)
{
$loaded = $lang->load($filename, $path, null) || $lang->load($filename, $path, $lang->getDefault());
if ($loaded)
{
break 2;
}
}
}
// Translate component's name
$component->name = Text::_(strtoupper($component->name));
}
$comps[strtolower($component->element)] = $component->name;
}
asort($comps);
$options = array();
foreach ($comps as $key => $name)
{
$options[] = HTMLHelper::_('select.option', $key, $name);
}
return $options;
}
}

View File

@ -0,0 +1,123 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\Field\GroupedlistField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use NRFramework\Extension;
class JFormFieldNRConditions extends GroupedlistField
{
/**
* Method to get the field option groups.
*
* @return array The field option objects as a nested array in groups.
*/
protected function getGroups()
{
$include_rules = empty($this->element['include_rules']) ? [] : explode(',', $this->element['include_rules']);
$exclude_rules = empty($this->element['exclude_rules']) ? [] : explode(',', $this->element['exclude_rules']);
$exclude_rules_pro = empty($this->element['exclude_rules_pro']) ? false : $this->element['exclude_rules_pro'];
$groups[''][] = HTMLHelper::_('select.option', null, Text::_('NR_CB_SELECT_CONDITION'));
$conditionsList = \NRFramework\Conditions\ConditionsHelper::getConditionsList();
foreach ($conditionsList as $conditions)
{
foreach ($conditions['conditions'] as $conditionName => $condition)
{
$skip_condition = false;
/**
* Checks conditions that have multiple components as dependency.
* Check for multiple given components for a particular condition, i.e. acymailing can be loaded via com_acymailing or com_acym
*/
$multiple_components = explode('|', $conditionName);
if (count($multiple_components) >= 2)
{
foreach ($multiple_components as $component)
{
$skip_condition = false;
if (!$conditionName = $this->getConditionName($component))
{
$skip_condition = true;
continue;
}
}
}
// If the condition must be skipped, skip it
if ($skip_condition)
{
continue;
}
// Checks for a single condition whether its component exists and can be used.
if (!$conditionName = $this->getConditionName($conditionName))
{
continue;
}
// If its excluded, skip it
if (!$exclude_rules_pro && !empty($exclude_rules) && in_array($conditionName, $exclude_rules))
{
continue;
}
// If its not included, skip it
if (!$exclude_rules_pro && !empty($include_rules) && !in_array($conditionName, $include_rules))
{
continue;
}
$is_excluded_and_pro = ((count($exclude_rules) && in_array($conditionName, $exclude_rules)) || (count($include_rules) && !in_array($conditionName, $include_rules))) && $exclude_rules_pro;
$value = $conditionName;
$disabled = false;
if ($is_excluded_and_pro)
{
$disabled = true;
$value = '__';
}
// Add condition to the group
$groups[$conditions['title']][] = HTMLHelper::_('select.option', $value, $condition['title'], 'value', 'text', $disabled);
}
}
// Merge any additional groups in the XML definition.
return array_merge(parent::getGroups(), $groups);
}
/**
* Returns the parsed condition name.
*
* i.e. $condition: com_k2#Component\K2Item
* will return: Component\K2Item
*
* @param string $condition
*
* @return mixed
*/
private function getConditionName($condition)
{
$conditionNameParts = explode('#', $condition);
if (count($conditionNameParts) >= 2 && !Extension::isEnabled($conditionNameParts[0]))
{
return false;
}
return isset($conditionNameParts[1]) ? $conditionNameParts[1] : $conditionNameParts[0];
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
require_once JPATH_PLUGINS . '/system/nrframework/helpers/fieldlist.php';
class JFormFieldNRDevice extends NRFormFieldList
{
/**
* Browsers List
*
* @var array
*/
public $options = array(
'desktop' => 'NR_DESKTOPS',
'mobile' => 'NR_MOBILES',
'tablet' => 'NR_TABLETS'
);
protected function getOptions()
{
asort($this->options);
foreach ($this->options as $key => $option)
{
$options[] = HTMLHelper::_('select.option', $key, Text::_($option));
}
return array_merge(parent::getOptions(), $options);
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRDJCatalog2Categories extends JFormFieldNRTreeSelect
{
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = true;
/**
* Indicates whether the options array should have the levels re-calculated
*
* @var boolean
*/
protected $fixLevels = true;
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
$db = $this->db;
$query = $db->getQuery(true)
->select('id as value, name as text, parent_id as parent, IF (published=1, 0, 1) as disable')
->from('#__djc2_categories');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRDJCFCategories extends JFormFieldNRTreeSelect
{
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = true;
/**
* Indicates whether the options array should have the levels re-calculated
*
* @var boolean
*/
protected $fixLevels = true;
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('id as value, name as text, parent_id as `parent`, IF (published=1, 0, 1) as disable')
->from('#__djcf_categories');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRDJEventsCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all DJ Events Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, a.name as text, 0 AS level, 0 as parent, 0 as disable')
->from('#__djev_cats as a')
->group('a.id, a.name')
->order('a.id ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNREasyBlogCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, a.title as text, COUNT(DISTINCT b.id) AS level, a.parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__easyblog_category as a')
->join('LEFT', '#__easyblog_category AS b on a.lft > b.lft AND a.rgt < b.rgt')
->group('a.id, a.title, a.lft')
->order('a.lft ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNREShopCategories extends JFormFieldNRTreeSelect
{
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = true;
/**
* Indicates whether the options array should have the levels re-calculated
*
* @var boolean
*/
protected $fixLevels = true;
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, b.category_name as text, a.category_parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__eshop_categories as a')
->join('LEFT', '#__eshop_categorydetails AS b on a.id=b.category_id');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNREventBookingCategories extends JFormFieldNRTreeSelect
{
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = true;
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('id as value, name as text, level, parent, IF (published=1, 0, 1) as disable')
->from('#__eb_categories');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\Field\GroupedlistField;
use Joomla\CMS\HTML\HTMLHelper;
class JFormFieldNRFonts extends GroupedlistField
{
/**
* Method to get the field option groups.
*
* @return array The field option objects as a nested array in groups.
*
* @since 1.6
*/
protected function getGroups()
{
$groups = array();
foreach (NRFramework\Fonts::getFontGroups() as $name => $fontGroup)
{
// Initialize the group if necessary.
if (!isset($groups[$name]))
{
$groups[$name] = array();
}
foreach ($fontGroup as $font)
{
$groups[$name][] = HTMLHelper::_('select.option', $font, $font);
}
}
// Merge any additional groups in the XML definition.
return array_merge(parent::getGroups(), $groups);
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRGridboxCategories extends JFormFieldNRTreeSelect
{
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = true;
/**
* Indicates whether the options array should have the levels re-calculated
*
* @var boolean
*/
protected $fixLevels = true;
/**
* Get a list of all Gridbox Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('id as value, title as text, parent as parent, IF (published=1, 0, 1) as disable')
->from('#__gridbox_categories');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRGroupLevel extends JFormFieldNRTreeSelect
{
/**
* A helper to get the list of user groups.
* Logic from administrator\components\com_config\model\field\filters.php@getUserGroups
*
* @return object
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
// Get the user groups from the database.
$query = $db->getQuery(true)
->select('a.id AS value, a.title AS text, COUNT(DISTINCT b.id) AS level')
->from('#__usergroups AS a')
->join('LEFT', '#__usergroups AS b on a.lft > b.lft AND a.rgt < b.rgt')
->group('a.id, a.title, a.lft')
->order('a.lft ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRHikaShopCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.category_id as value, a.category_name as text, (a.category_depth - 1) AS level, a.category_parent_id as parent, IF (a.category_published=1, 0, 1) as disable')
->from('#__hikashop_category as a')
->join('LEFT', '#__hikashop_category AS b on a.category_left > b.category_left AND a.category_right < b.category_right')
->group('a.category_id, a.category_name, a.category_left')
->where($db->quoteName('a.category_type') . ' = ' . $db->quote('product'))
->where($db->quoteName('a.category_id') . ' > 2')
->order('a.category_left ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRICagendaCategories extends JFormFieldNRTreeSelect
{
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = true;
/**
* Get a list of all iCagenda Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('id as value, title as text, 0 as level, 0 as parent, IF (state=1, 0, 1) as disable')
->from('#__icagenda_category');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,165 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\Field\TextField;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\Registry\Registry;
use Joomla\CMS\Uri\Uri;
use NRFramework\Functions;
class JFormFieldNRImagesSelector extends TextField
{
/**
* Renders the Images Selector
*
* @return string The field input markup.
*/
protected function getInput()
{
$field_attributes = (array) $this->element->attributes();
$attributes = isset($field_attributes["@attributes"]) ? $field_attributes["@attributes"] : null;
$field_attributes = new Registry($attributes);
if (!$images = $field_attributes->get('images', ''))
{
return;
}
$pro_items = array_filter(array_map('trim', explode(',', $field_attributes->get('pro_items', ''))));
$columns = (int) $field_attributes->get('columns', 1);
$item_width = $field_attributes->get('item_width', 'auto');
$image_width = $field_attributes->get('image_width', '');
$width = $field_attributes->get('width', '100%');
$height = $field_attributes->get('height', '');
$key_type = $field_attributes->get('key_type', null);
$mode = $field_attributes->get('mode', null);
$gap = $field_attributes->get('gap', '10px');
$item_gap = $field_attributes->get('item_gap', null);
$class = [];
if (!empty($this->class))
{
$class[] = $this->class;
}
$images = $this->parseImages($images, $mode);
// load CSS
HTMLHelper::script('plg_system_nrframework/images-selector-field.js', ['relative' => true, 'version' => true]);
HTMLHelper::stylesheet('plg_system_nrframework/images-selector-field.css', ['relative' => true, 'version' => true]);
$layout = new FileLayout('imagesselector', JPATH_PLUGINS . '/system/nrframework/layouts');
$data = [
'value' => !empty($this->value) ? $this->value : $this->default,
'name' => $this->name,
'class' => implode(' ', $class),
'key_type' => $key_type,
'images' => $images,
'columns' => $columns,
'id' => $this->id,
'required' => $this->required,
'item_width' => $item_width,
'image_width' => $image_width,
'width' => $width,
'height' => $height,
'mode' => $mode,
'gap' => $gap,
'item_gap' => $item_gap,
'pro_items' => $pro_items
];
return $layout->render($data);
}
/**
* Parse images.
*
* @param array $images
* @param string $mode
*/
private function parseImages($images = [], $mode = null)
{
// Links
if ($mode === 'links')
{
$images = json_decode($images, true);
$site_url = Uri::root();
// Replace {{SITE_URL}}
foreach ($images as &$image)
{
$image['url'] = str_replace('{{SITE_URL}}', $site_url, $image['url']);
}
return $images;
}
// Paths to images
$paths = explode(',', $images);
$images = [];
foreach ($paths as $key => $path)
{
// skip empty paths
if (empty(rtrim(ltrim($path, ' '), ' ')))
{
continue;
}
if ($imgs = $this->getImagesFromPath($path))
{
// add new images to array of images
$images = array_merge($images, $imgs);
}
else
{
// check if image exist
if (file_exists(JPATH_ROOT . '/' . ltrim($path, ' /')))
{
// add new image to array of images
$images[] = ltrim($path, ' /');
}
}
}
return $images;
}
/**
* Returns all images in path
*
* @return mixed
*/
private function getImagesFromPath($path)
{
$folder = JPATH_ROOT . '/' . ltrim($path, ' /');
if (!is_dir($folder) || !$folder_files = scandir($folder))
{
return false;
}
$images = array_diff($folder_files, array('.', '..', '.DS_Store'));
$images = array_values($images);
// prepend path to image file names
array_walk($images, function(&$value, $key) use ($path) { $value = ltrim($path, ' /') . '/' . $value; } );
return $images;
}
}

View File

@ -0,0 +1,153 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Layout\FileLayout;
use Joomla\Registry\Registry;
use Joomla\CMS\Language\Text;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNRInlineFileUpload extends NRFormField
{
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*/
protected function getInput()
{
$layout = new FileLayout('inlinefileupload', JPATH_PLUGINS . '/system/nrframework/layouts');
$data = [
'value' => $this->value,
'name' => $this->name,
'accept' => $this->get('accept'),
'upload_folder' => base64_encode($this->get('upload_folder'))
];
return $layout->render($data);
}
/**
* Handles the AJAX request
*
* @param array $options
*
* @return array
*/
public function onAjax($options)
{
$options = new Registry($options);
if ($options->get('action') == 'remove')
{
$this->onRemove($options);
return;
}
$this->onUpload();
}
/**
* On file upload.
*
* @return string
*/
private function onUpload()
{
// Make sure we have a valid file passed
if (!$file = $this->app->input->files->get('file', null, 'cmd'))
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_UPLOAD_ERROR_INVALID_FILE')
]);
jexit();
}
// ensure an upload folder was given
if (!$upload_folder = $this->app->input->get('upload_folder', null, 'cmd'))
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_UPLOAD_FOLDER_MISSING')
]);
jexit();
}
// ensure we can decode its value
if (!$upload_folder = base64_decode($upload_folder))
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_UPLOAD_FOLDER_INVALID')
]);
jexit();
}
$uploaded_file = null;
$file_size = 0;
$file_name = null;
// try to upload the file.
try {
$uploaded_file = \NRFramework\File::upload($file, JPATH_ROOT . DIRECTORY_SEPARATOR . $upload_folder, ['text/plain', 'text/csv'], false, true);
$filePathInfo = NRFramework\File::pathinfo($uploaded_file);
$file_name = $filePathInfo['basename'];
$file_size = file_exists($uploaded_file) ? filesize($uploaded_file) : 0;
$file_size = $file_size ? number_format($file_size / 1024, 2) . ' KB' : $file_size;
} catch (\Throwable $th)
{
echo json_encode([
'error' => true,
'response' => $th->getMessage()
]);
jexit();
}
echo json_encode([
'error' => false,
'response' => Text::_('NR_FILE_UPLOADED_SUCCESSFULLY'),
'file_name' => base64_encode($file_name),
'file' => base64_encode($uploaded_file),
'file_size' => $file_size
]);
jexit();
}
/**
* On file removal.
*
* @return string
*/
private function onRemove($options)
{
if (!$file = $options->get('remove_file'))
{
echo json_encode([
'error' => true,
'response' => Text::_('NR_UPLOAD_ERROR_INVALID_FILE')
]);
jexit();
}
// If file exists, remove it
if (file_exists($file))
{
unlink($file);
}
echo json_encode([
'error' => false,
'response' => Text::_('NR_FILE_DELETED')
]);
jexit();
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRJBusinessDirectoryCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all J-BusinessDirectory Categories
*
* @return void
*/
protected function getOptions()
{
$filter_type = isset($this->element['filter_type']) ? (string) $this->element['filter_type'] : 1;
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, a.name as text, a.level AS level, a.parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__jbusinessdirectory_categories as a')
->join('LEFT', '#__jbusinessdirectory_categories AS b on a.lft > b.lft AND a.rgt < b.rgt')
->where($db->quoteName('a.type') . ' = ' . $db->q($filter_type))
->group('a.id, a.name, a.lft')
->order('a.lft ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRJCalProCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, a.title as text, COUNT(DISTINCT b.id) AS level, a.parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__categories as a')
->join('LEFT', '#__categories AS b on a.lft > b.lft AND a.rgt < b.rgt')
->where('a.extension = "com_jcalpro"')
->group('a.id, a.title, a.lft')
->order('a.lft ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRJEventsCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, a.title as text, COUNT(DISTINCT b.id) AS level, a.parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__categories as a')
->join('LEFT', '#__categories AS b on a.lft > b.lft AND a.rgt < b.rgt')
->where('a.extension = "com_jevents"')
->group('a.id, a.title, a.lft')
->order('a.lft ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRJReviewsCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all JReviews Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, a.title as text, COUNT(DISTINCT b.id) AS level, a.parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__jreviews_categories as jrc')
->join('LEFT', '#__categories AS a on jrc.id = a.id')
->join('LEFT', '#__categories AS b on a.lft > b.lft AND a.rgt < b.rgt')
->where('a.extension = "com_content"')
->group('a.id, a.title, a.lft')
->order('a.lft ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRJShoppingCategories extends JFormFieldNRTreeSelect
{
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = true;
/**
* Indicates whether the options array should have the levels re-calculated
*
* @var boolean
*/
protected $fixLevels = true;
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select($db->quoteName('name_' . $this->getLanguage(), 'text'))
->select('category_id as value, category_parent_id as parent, IF (category_publish=1, 0, 1) as disable')
->from('#__jshopping_categories');
$db->setQuery($query);
return $db->loadObjectList();
}
/**
* JoomShopping is using different columns per language. Therefore, we need to use their API to get the default language code.
*
* @return string
*/
private function getLanguage($default = 'en-GB')
{
// Silent inclusion.
@include_once JPATH_SITE . '/components/com_jshopping/lib/factory.php';
if (!class_exists('JSFactory'))
{
return $default;
}
return JSFactory::getConfig()->defaultLanguage;
}
}

View File

@ -0,0 +1,155 @@
<?php
/**
* @author Tassos.gr <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
require_once JPATH_PLUGINS . '/system/nrframework/helpers/groupfield.php';
class JFormFieldNRK2 extends NRFormGroupField
{
public $type = 'K2';
/**
* Pagetypes options
*
* @var array
*/
public $pagetype_options = array(
'itemlist_category' => 'NR_ASSIGN_K2_CATEGORY_OPTION',
'item_item' => 'NR_ASSIGN_K2_ITEM_OPTION',
'item_itemform' => 'NR_ASSIGN_K2_ITEM_FORM_OPTION',
'latest_latest' => 'NR_ASSIGN_K2_LATEST_OPTION',
'itemlist_tag' => 'NR_ASSIGN_K2_TAG_OPTION',
'itemlist_user' => 'NR_ASSIGN_K2_USER_PAGE_OPTION'
);
public function getItems()
{
$query = $this->db->getQuery(true);
$query
->select('i.id, i.title as name, i.language, c.name as cat, i.published')
->from('#__k2_items as i')
->join('LEFT', '#__k2_categories AS c ON c.id = i.catid')
->order('i.title, i.ordering, i.id');
$this->db->setQuery($query);
$list = $this->db->loadObjectList();
return $this->getOptionsByList($list, array('language', 'cat', 'id'));
}
public function getPagetypes()
{
asort($this->pagetype_options);
foreach ($this->pagetype_options as $key => $option)
{
$options[] = HTMLHelper::_('select.option', $key, Text::_($option));
}
return $options;
}
public function getTags()
{
$query = $this->db->getQuery(true);
$query
->select('t.id, t.name')
->from('#__k2_tags as t')
->order('t.id');
$this->db->setQuery($query);
$list = $this->db->loadObjectList();
return $this->getOptionsByList($list);
}
public function getCategories()
{
$query = $this->db->getQuery(true);
$query
->select('c.id, c.name, c.parent, c.published, c.language')
->from('#__k2_categories as c')
->where('c.trash = 0')
->where('c.id != c.parent')
->order('c.ordering');
$this->db->setQuery($query);
$cats = $this->db->loadObjectList();
$options = [];
// get category levels
foreach ($cats as $c)
{
$level = 0;
$parent_id = (int)$c->parent;
while ($parent_id)
{
$level++;
$parent_id = $this->getNextParentId($cats, $parent_id);
}
$c->level = $level;
$options[] = $c;
}
// sort options
$options = $this->sortTreeSelectOptions($options);
return $this->getOptionsByList($options, array('language'));
}
/**
* Sorts treeselect options
*
* @param array $options
* @param int $parent_id
*
* @return array
*/
protected function sortTreeSelectOptions($options, $parent_id = 0)
{
if (empty($options))
{
return [];
}
$result = [];
$sub_options = array_filter($options, function($option) use($parent_id)
{
return $option->parent == $parent_id;
});
foreach ($sub_options as $option)
{
$result[] = $option;
$result = array_merge($result, $this->sortTreeSelectOptions($options, $option->id));
}
return $result;
}
/**
* Returns the next parent id
* Helper method for getCategories
*
* @return int
*/
protected function getNextParentId($categories, $current_pid)
{
foreach($categories as $c)
{
if ((int)$c->id === $current_pid)
{
return (int)$c->parent;
}
}
}
}

View File

@ -0,0 +1,126 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
use \NRFramework\HTML;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNRMenuItems extends NRFormField
{
/**
* Output the HTML for the field
* Example of usage: <field name="field_name" type="nrmenuitems" label="NR_SELECTION" />
*/
protected function getInput()
{
$size = $this->get('size', 300);
$options = $this->getMenuItems();
return HTML::treeselect($options, $this->name, $this->value, $this->id, $size);
}
/**
* Get a list of menu links for one or all menus.
* Logic from administrator\components\com_menus\helpers\menus.php@getMenuLinks()
*/
public function getMenuItems()
{
NRFramework\Functions::loadLanguage('com_menus', JPATH_ADMINISTRATOR);
$db = $this->db;
// Prevent the "The SELECT would examine more than MAX_JOIN_SIZE rows; " MySQL error
// on websites with a big number of menu items in the db.
$db->setQuery('SET SQL_BIG_SELECTS = 1')->execute();
$query = $db->getQuery(true)
->select('a.id AS value, a.title AS text, a.alias, a.level, a.menutype, a.type, a.template_style_id, a.checked_out, a.language')
->from('#__menu AS a')
->join('LEFT', $db->quoteName('#__menu') . ' AS b ON a.lft > b.lft AND a.rgt < b.rgt')
->where('a.published != -2')
->group('a.id, a.alias, a.title, a.level, a.menutype, a.type, a.template_style_id, a.checked_out, a.lft, a.language')
->order('a.lft ASC');
// Get the options.
$db->setQuery($query);
try
{
$links = $db->loadObjectList();
}
catch (RuntimeException $e)
{
Factory::getApplication()->enqueueMessage($e->getMessage());
return false;
}
// Group the items by menutype.
$query->clear()
->select('*')
->from('#__menu_types')
->where('menutype <> ' . $db->quote(''))
->order('title, menutype');
$db->setQuery($query);
try
{
$menuTypes = $db->loadObjectList();
}
catch (RuntimeException $e)
{
Factory::getApplication()->enqueueMessage($e->getMessage());
return false;
}
// Create a reverse lookup and aggregate the links.
$rlu = array();
foreach ($menuTypes as &$type)
{
$type->value = 'type.' . $type->menutype;
$type->text = $type->title;
$type->level = 0;
$type->class = 'hidechildren';
$type->labelclass = 'nav-header';
$rlu[$type->menutype] = &$type;
$type->links = array();
}
foreach ($links as &$link)
{
if (isset($rlu[$link->menutype]))
{
if (preg_replace('#[^a-z0-9]#', '', strtolower($link->text)) !== preg_replace('#[^a-z0-9]#', '', $link->alias))
{
$link->text .= ' <small>[' . $link->alias . ']</small>';
}
if ($link->language && $link->language != '*')
{
$link->text .= ' <small>(' . $link->language . ')</small>';
}
if ($link->type == 'alias')
{
$link->text .= ' <small>(' . Text::_('COM_MENUS_TYPE_ALIAS') . ')</small>';
$link->disable = 1;
}
$rlu[$link->menutype]->links[] = &$link;
unset($link->menutype);
}
}
return $menuTypes;
}
}

View File

@ -0,0 +1,70 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
require_once JPATH_PLUGINS . '/system/nrframework/helpers/fieldlist.php';
class JFormFieldNRModulePositions extends NRFormFieldList
{
/**
* Method to get a list of options for a list input.
*
* @return array An array of options.
*/
protected function getOptions()
{
// get templates
$templates = $this->getTemplates();
require_once JPATH_ADMINISTRATOR . '/components/com_templates/helpers/templates.php';
// get all position options
$options = [];
$options[] = HTMLHelper::_('select.option', '', Text::_('NR_NONE_SELECTED'));
foreach ($templates as $template) {
$options[] = HTMLHelper::_('select.option', '<OPTGROUP>', $template->name);
// find all positions for template
$positions = TemplatesHelper::getPositions(0, $template->element);
foreach ($positions as $position) {
$options[] = HTMLHelper::_('select.option', $position, $position);
}
$options[] = HTMLHelper::_('select.option', '</OPTGROUP>');
}
return array_merge(parent::getOptions(), $options);
}
/**
* Returns all enabled templates
*
* @return object
*/
private function getTemplates()
{
$db = $this->db;
$query = $db->getQuery(true);
$query->select('element, name, enabled');
$query->from('#__extensions');
$query->where('client_id = 0');
$query->where('type = '.$db->quote('template'));
$query->where('enabled = 1');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,59 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
require_once JPATH_PLUGINS . '/system/nrframework/helpers/fieldlist.php';
class JFormFieldNRModules extends NRFormFieldList
{
/**
* Provide a list of all published modules.
*
* @return array An array of options.
*/
protected function getOptions()
{
// Get modules
$modules = $this->getModules();
// get all position options
$options = [];
$options[] = HTMLHelper::_('select.option', '', Text::_('NR_NONE_SELECTED'));
foreach ($modules as $module) {
$options[] = HTMLHelper::_('select.option', $module->id, $module->title . ' (' . $module->id . ')');
}
return array_merge(parent::getOptions(), $options);
}
/**
* Returns all enabled modules.
*
* @return object
*/
private function getModules()
{
$db = $this->db;
$query = $db->getQuery(true);
$query->select('id, title');
$query->from('#__modules');
$query->where('published = 1');
$query->where('client_id = 0');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,42 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\NumberField;
use Joomla\CMS\Language\Text;
class JFormFieldNRNumber extends NumberField
{
/**
* Method to render the input field
*
* @return string
*/
function getInput()
{
$parent = parent::getInput();
$addon = (string) $this->element['addon'];
if (empty($addon))
{
return $parent;
}
return '
<div class="input-append input-group">
' . $parent . '
<span class="add-on input-group-append">
<span class="input-group-text" style="font-size:inherit;">' . Text::_($addon) . '</span>
</span>
</div>
';
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
require_once JPATH_PLUGINS . '/system/nrframework/helpers/fieldlist.php';
class JFormFieldNROs extends NRFormFieldList
{
/**
* Browsers List
*
* @var array
*/
public $options = array(
'linux' => 'NR_LINUX',
'mac' => 'NR_MAC',
'android' => 'NR_ANDROID',
'ios' => 'NR_IOS',
'windows' => 'NR_WINDOWS',
'blackberry' => 'NR_BLACKBERRY',
'chromeos' => 'NR_CHROMEOS'
);
protected function getOptions()
{
asort($this->options);
foreach ($this->options as $key => $option)
{
$options[] = HTMLHelper::_('select.option', $key, Text::_($option));
}
return array_merge(parent::getOptions(), $options);
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNRRangeSlider extends NRFormField
{
/**
* Method to render the input field
*
* @return string
*/
protected function getInput()
{
$min = isset($this->element['min']) ? (float) $this->element['min'] : null;
$max = isset($this->element['max']) ? (float) $this->element['max'] : null;
$step = isset($this->element['step']) ? (float) $this->element['step'] : null;
$payload = [
'name' => $this->name,
'value' => (float) $this->value
];
if ($min)
{
$payload['min'] = $min;
}
if ($max)
{
$payload['max'] = $max;
}
if ($step)
{
$payload['step'] = $step;
}
if ($this->class)
{
$payload['css_class'] = $this->class;
}
$slider = \NRFramework\Widgets\Helper::render('RangeSlider', $payload);
return $slider;
}
}

View File

@ -0,0 +1,685 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\TextField;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\HTML\HTMLHelper;
class JFormFieldNRResponsiveControl extends TextField
{
protected $breakpoint = 'desktop';
protected $hide_device_selector = false;
/**
* Method to render the input field
*
* @return string
*/
function getInput()
{
return $this->getLayout();
}
/**
* Returns html for all devices
*
* @return array
*/
private function getFieldsData()
{
if ($this->hasSubform())
{
return $this->getSubformFieldsData();
}
return $this->getSubtypeFieldsData();
}
private function getSubtypeFieldsData()
{
$name = (string) $this->element['name'];
$breakpoints = \NRFramework\Helpers\Responsive::getBreakpoints();
$device = $this->breakpoint;
// Control default value
$control_default = json_decode($this->default, true);
$units = isset($this->element['subtype_units']) ? array_filter(array_unique(array_map('trim', explode(',', (string) $this->element['subtype_units'])))) : [];
// Default value of the input for breakpoint
$default = $control_default && isset($control_default[$device]) ? $control_default[$device] : ($device === 'desktop' ? $this->default : null);
$field_data = $this->getFieldInputByDevice($name, $device, $default);
// Render layout
$payload = [
'device' => $device,
'breakpoint' => $breakpoints[$device],
'breakpoints' => $breakpoints,
'html' => $field_data['html'],
'name' => $this->name . '[' . $name . '][' . $device . ']',
'hide_device_selector' => $this->hide_device_selector,
'units' => $units,
'unit' => $field_data['unit'] ? $field_data['unit'] : ($units ? $units[0] : null),
'is_linked' => $field_data['linked'],
];
$layout = new FileLayout('responsive_control_item', JPATH_PLUGINS . '/system/nrframework/layouts');
return $layout->render($payload);
}
/**
* Returns the field's title and value
*
* @param string $field_name The field name of the field.
* @param string $device The breakpoint of the field.
* @param string $default The default value of the field.
*
* @return array
*/
private function getFieldInputByDevice($field_name, $device, $default = null)
{
$data = [];
/**
* TODO: Remove this in the future.
*
* This is for compatibility purposes with versions < 6.0.3 as any previous
* value set, should now only be visible on the desktop breakpoint.
*/
$input_value = $this->form->getValue($field_name, $this->group);
$input_value = is_string($input_value) && json_decode($input_value, true) ? json_decode($input_value, true) : $input_value;
// Get input value
$value = $this->getFieldInputValue($field_name, $device);
// If no value is set, get the default value (if given)
if (is_null($value) && $default)
{
$value = $default;
}
$field_type = isset($this->element['subtype']) ? (string) $this->element['subtype'] : 'text';
/**
* TODO: Remove this in the future.
*
* This is for compatibility purposes, as any previous
* value set (i.e. 500, 250px, etc...),
* should now only be set on the desktop device and
* other devices (tablet, mobile) should inherit the value.
*/
if (!is_null($input_value) && $input_value !== '' && is_scalar($input_value))
{
$value = '';
// Explicit case for NRToggle and "auto" values. Set the same value across all breakpoints.
if (strtolower($field_type) === 'nrtoggle' || $input_value === 'auto')
{
$value = $input_value;
}
else
{
if ($device === 'desktop')
{
$is_dimension_control = in_array($field_type, ['TFBorderRadiusControl', 'TFDimensionControl']);
if ($is_dimension_control)
{
$input_type = $field_type === 'TFDimensionControl' ? 'margin_padding' : 'border_radius';
$value = \NRFramework\Helpers\Controls\Spacing::parseInputValue($input_value, $input_type);
$value['linked'] = '1';
}
else
{
$value = \NRFramework\Helpers\Controls\Control::findUnitInValue($input_value);
}
}
}
}
/**
* Units are set only to these fields:
*
* TFBorderRadiusControl
* TFDimensionControl
* TFUnitControl
*/
$unitBasedControls = ['TFBorderRadiusControl', 'TFDimensionControl', 'TFUnitControl'];
$value = in_array($field_type, $unitBasedControls) ? $value : (isset($value['value']) ? $value['value'] : $value);
$data = [
'html' => $this->getSubtypeHTML($field_name, $field_type, $device, $value),
'unit' => isset($value['unit']) ? $value['unit'] : null,
'linked' => isset($value['linked']) ? $value['linked'] : true,
];
return $data;
}
/**
* Returns the subtype HTML field.
*
* @param string $type
* @param string $type
* @param string $device
* @param mixed $value
*
* @return string
*/
protected function getSubtypeHTML($name, $type, $device, $value)
{
// Set hint
$hint = '';
$subtype_hint = isset($this->element['subtype_hint']) ? (string) $this->element['subtype_hint'] : null;
if ($subtype_hint)
{
$hint = 'hint="' . $subtype_hint . '"';
}
// Set format
$format = '';
$subtype_format = isset($this->element['subtype_format']) ? (string) $this->element['subtype_format'] : null;
if ($subtype_format)
{
$format = 'format="' . $subtype_format . '"';
}
// Set units
$units = '';
$subtype_units = isset($this->element['subtype_units']) ? (string) $this->element['subtype_units'] : null;
if ($subtype_units)
{
$units = 'units="' . $subtype_units . '"';
}
// Set checked
$checked = '';
$subtype_checked = isset($this->element['subtype_checked']) ? (string) $this->element['subtype_checked'] : null;
if ($subtype_checked)
{
$checked = 'checked="' . $subtype_checked . '"';
}
// Set keywords
$keywords = '';
$subtype_keywords = isset($this->element['subtype_keywords']) ? (string) $this->element['subtype_keywords'] : null;
if ($subtype_keywords)
{
$keywords = 'keywords="' . $subtype_keywords . '"';
}
// Set layout
$layout = '';
$subtype_layout = isset($this->element['subtype_layout']) ? (string) $this->element['subtype_layout'] : null;
if ($subtype_layout)
{
$layout = 'layout="' . $subtype_layout . '"';
}
// Set class
$class = '';
$subtype_class = isset($this->element['subtype_class']) ? (string) $this->element['subtype_class'] : null;
if ($subtype_class)
{
$class = 'class="' . $subtype_class . '"';
}
// Set min
$min = '';
$subtype_min = isset($this->element['subtype_min']) ? (string) $this->element['subtype_min'] : '';
if ($subtype_min !== '')
{
$min = 'min="' . $subtype_min . '"';
}
// Set max
$max = '';
$subtype_max = isset($this->element['subtype_max']) ? (string) $this->element['subtype_max'] : null;
if ($subtype_max)
{
$max = 'max="' . $subtype_max . '"';
}
// Set options
$options = '';
$subtype_options = isset($this->element['subtype_options']) ? (string) $this->element['subtype_options'] : null;
if ($subtype_options)
{
$subtype_options = json_decode($subtype_options, true);
if (is_array($subtype_options))
{
// Remove the "Inherit" option from the Desktop breakpoint
if ($device === 'desktop' && ($inherit_item_key = array_search('NR_INHERIT', $subtype_options)) !== false)
{
unset($subtype_options[$inherit_item_key]);
}
foreach ($subtype_options as $key => $label)
{
$options .= '<option value="' . $key . '">' . $label . '</option>';
}
}
}
/**
* It looks like the MediaField does not accept a null value.
*
* So set it to empty.
*/
if (strtolower($type) === 'media' && is_null($value))
{
$value = '';
}
$xml = new SimpleXMLElement('
<field
name="' . $name . '"
type="' . $type . '"
' . $format . '
' . $keywords . '
' . $checked . '
' . $hint . '
' . $units . '
' . $min . '
' . $max . '
' . $layout . '
' . $class . '
>
' . $options . '
</field>
');
$this->form->setField($xml);
$field = $this->form->getField($name, null, $value);
if ($this->group)
{
$field->id = $this->formControl . '_' . $this->group . '_' . $this->fieldname;
$field->name = $this->formControl . '[' . $this->group . '][' . $this->fieldname . ']';
}
$field->id .= '_' . $device;
$field->name .= '[' . $device . ']';
return $field->getInput();
}
public function renderField($options = [])
{
// Create separate controls for each breakpoint
$html = '';
$subtype = isset($this->element['subtype']) ? (string) $this->element['subtype'] : 'text';
$breakpoints = \NRFramework\Helpers\Responsive::getBreakpoints();
$origID = $this->id;
$showon = $this->showon;
foreach ($breakpoints as $breakpoint => $breakpoint_data)
{
$tmpShowon = $showon;
$this->id = $origID . '_' . $breakpoint;
if (in_array($subtype, ['TFDimensionControl', 'TFBorderRadiusControl']))
{
$this->id .= '_top';
}
$options['class'] = 'nr-responsive-control-group device-' . $breakpoint;
if ($breakpoint === 'desktop')
{
$options['class'] .= ' nr-responsive-control-group--active';
}
if ($showon)
{
// Add group
if ($this->group)
{
$tmpShowon = preg_replace('/(\[AND\]|\[OR\])/i', '$1' . $this->group . '.', $tmpShowon);
$tmpShowon = $this->group . '.' . $tmpShowon;
}
// Add breakpoint
$tmpShowon = str_replace('{breakpoint}', '.' . $breakpoint, $tmpShowon);
}
$this->showon = $tmpShowon;
$this->breakpoint = $breakpoint;
$html .= parent::renderField($options);
}
return $html;
}
/**
* Returns the field layout
*
* @return string
*/
private function getLayout()
{
HTMLHelper::stylesheet('plg_system_nrframework/controls/responsive_control.css', ['relative' => true, 'version' => 'auto']);
HTMLHelper::script('plg_system_nrframework/controls/responsive_control.js', ['relative' => true, 'version' => 'auto']);
$name = isset($this->element['name']) ? (string) $this->element['name'] : '';
$width = isset($this->element['width']) ? (string) $this->element['width'] : '';
$class = isset($this->element['class']) ? ' ' . (string) $this->element['class'] : '';
$this->hide_device_selector = isset($this->element['hide_device_selector']) && (string) $this->element['hide_device_selector'] === 'true';
if ($this->hide_device_selector)
{
$class .= ' compact';
}
if (defined('nrJ4'))
{
$class .= ' isJ4';
}
$data = [
'name' => $name,
'width' => $width,
'class' => $class,
'breakpoint' => $this->breakpoint,
'html' => $this->getFieldsData(),
];
// Render layout
$layout = new FileLayout('responsive_control', JPATH_PLUGINS . '/system/nrframework/layouts');
return $layout->render($data);
}
/**
* Finds the field input value
*
* @param string $field_name
* @param string $device
*
* @return string
*/
private function getFieldInputValue($field_name, $device)
{
if (!$values = $this->getValue())
{
return;
}
// New NRResponsiveControl stores [field_name][desktop][value]
if (isset($values[$device]))
{
return $values[$device];
}
// Subform NRResponsiveControl (deprecated) stores [field_control][field_name][device][value]
if (!isset($values[$field_name][$device]))
{
return;
}
// Return empty
if ($values[$field_name][$device] === '')
{
return '';
}
// Return actual value
return $values[$field_name][$device];
}
/**
* Returns the field value
*
* @return mixed
*/
private function getValue()
{
if (empty($this->value))
{
return;
}
return is_string($this->value) ? json_decode($this->value, true) : $this->value;
}
/**
* Checks whether the field uses subform to render its field.
*
* @return bool
*/
protected function hasSubform()
{
return $this->element->subform;
}
/**
* Used when NRResponsiveControl is used with
* a Subform field.
*
* Methods related to Subform are deprecated and
* we should migrate all usage to use the subtype format
* as it's a cleaner way.
*/
/**
* Returns all fields within the subform field.
*
* We must always use a single field as child.
*
* @deprecated
*
* @return void
*/
private function getSubformFieldsData()
{
if (!$fieldsList = $this->getSubformFieldsList())
{
return [];
}
$breakpoints = \NRFramework\Helpers\Responsive::getBreakpoints();
$base_name = (string) $fieldsList['base_name'];
// Control default value
$control_default = json_decode($this->default, true);
$group1 = !empty($this->group) ? '[' . $this->group . ']' : '';
$group2 = !empty($this->group) ? '_' . $this->group : '';
$device = $this->breakpoint;
$field_device_data = $fieldsList['fields'][0];
$name = $field_device_data['name'];
// Default value of the input for breakpoint
$default = null;
if ($control_default && isset($control_default[$name][$device]))
{
$default = $control_default[$name][$device];
}
$field_data = $this->getSubformFieldInputByDevice($name, $device, $default);
$field_html = $field_data['html'];
$field_html = str_replace(
[
$group1 . '[' . $name . ']',
$group2 . '_' . $name
],
[
$group1 . '[' . $base_name . '][' . $name . '][' . $device . ']',
$group2 . '_' . $base_name . '_' . $name . '_' . $device
], $field_html
);
$units = isset($field_device_data['units']) ? $field_device_data['units'] : [];
// Render layout
$payload = [
'device' => $device,
'breakpoint' => $breakpoints[$device],
'breakpoints' => $breakpoints,
'html' => $field_html,
'name' => $this->name . '[' . $name . '][' . $device . ']',
'units' => $units,
'unit' => $field_data['unit'] ? $field_data['unit'] : ($units ? $units[0] : null),
'is_linked' => $field_data['linked'],
'hide_device_selector' => false
];
$layout = new FileLayout('responsive_control_item', JPATH_PLUGINS . '/system/nrframework/layouts');
return $layout->render($payload);
}
/**
* Returns the field's title and value
*
* @param string $field_name The field name of the field.
* @param string $device The breakpoint of the field.
* @param string $default The default value of the field.
*
* @deprecated
*
* @return array
*/
private function getSubformFieldInputByDevice($field_name, $device, $default = null)
{
$data = [];
/**
* TODO: Remove this in the future.
*
* This is for compatibility purposes with versions < 6.0.3 as any previous
* value set, should now only be visible on the desktop breakpoint.
*/
$input_value = $this->form->getValue($field_name, $this->group);
foreach ($this->element->subform->field as $key => $field)
{
if ((string) $field->attributes()->name != $field_name)
{
continue;
}
// Get input value
$value = $this->getFieldInputValue($field_name, $device);
// If no value is set, get the default value (if given)
if (is_null($value) && $default)
{
$value = $default;
}
$field_type = (string) $field->attributes()->type;
/**
* TODO: Remove this in the future.
*
* This is for compatibility purposes, as any previous
* value set (i.e. 500, 250px, etc...),
* should now only be set on the desktop device and
* other devices (tablet, mobile) should inherit the value.
*/
if (!is_null($input_value) && $input_value !== '')
{
$value = '';
if ($device === 'desktop')
{
$is_dimension_control = in_array($field_type, ['TFBorderRadiusControl', 'TFDimensionControl']);
if ($is_dimension_control)
{
$input_type = $field_type === 'TFDimensionControl' ? 'margin_padding' : 'border_radius';
$value = \NRFramework\Helpers\Controls\Spacing::parseInputValue($input_value, $input_type);
$value['linked'] = '1';
}
else
{
$value = \NRFramework\Helpers\Controls\Control::findUnitInValue($input_value);
}
}
}
$data = [
'html' => $this->form->getInput($field_name, $this->group, $value),
'unit' => isset($value['unit']) ? $value['unit'] : null,
'linked' => isset($value['linked']) ? $value['linked'] : true
];
break;
}
return $data;
}
/**
* Returns the list of added fields
*
* @deprecated
*
* @return array
*/
private function getSubformFieldsList()
{
$data = [
'base_name' => $this->element['name'],
'fields' => []
];
$fieldset = $this->form->getFieldset();
foreach ($fieldset as $key => &$value)
{
if ($value->fieldname !== (string) $this->element['name'])
{
continue;
}
if (!$value instanceof JFormFieldNRResponsiveControl)
{
continue;
}
if (!isset($value->element->subform))
{
continue;
}
$atts = $value->element->subform->field->attributes();
$payload = [
'name' => (string) $atts['name']
];
$data['fields'][] = $payload;
break;
}
return $data;
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRRSBlogCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, a.title as text, (COUNT(DISTINCT b.id) - 1) AS level, a.parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__rsblog_categories as a')
->where('a.parent_id > 0')
->join('LEFT', '#__rsblog_categories AS b on a.lft > b.lft AND a.rgt < b.rgt')
->group('a.id, a.title, a.lft')
->order('a.lft ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRRSEventsProCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all RSEvents Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, a.title as text, (COUNT(DISTINCT b.id) - 1) AS level, a.parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__categories as a')
->join('LEFT', '#__categories AS b on a.lft > b.lft AND a.rgt < b.rgt')
->where('a.extension = "com_rseventspro"')
->group('a.id, a.title, a.lft')
->order('a.lft ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRSobiProCategories extends JFormFieldNRTreeSelect
{
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = true;
/**
* Indicates whether the options array should have the levels re-calculated
*
* @var boolean
*/
protected $fixLevels = true;
/**
* Increase the value(ID) of the category by one.
* This happens because we have a parent category "Bussiness Directory" that pushes-in the indentation
* and we reset it by decreasing the value, level and parent.
*
* @var boolean
*/
protected $increaseValue = true;
/**
* Get a list of all SobiPro Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('(a.id - 1) as value, b.sValue as text, (a.parent - 1) as level, (a.parent - 1) as parent, IF (a.state=1, 0, 1) as disable')
->from('#__sobipro_object as a')
->join('LEFT', "#__sobipro_language AS b on a.id = b.id AND b.sKey = 'name'")
->where($db->quoteName('a.oType') . ' = '. $db->quote('category'));
$db->setQuery($query);
$result = $db->loadObjectList();
return $result;
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRSPPageBuilderCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, a.title as text, (COUNT(DISTINCT b.id) - 1) AS level, a.parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__categories as a')
->join('LEFT', '#__categories AS b on a.lft > b.lft AND a.rgt < b.rgt')
->where('a.extension = "com_sppagebuilder"')
->group('a.id, a.title, a.lft')
->order('a.lft ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\TextField;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
class JFormFieldNRText extends TextField
{
/**
* Method to render the input field
*
* @return string
*/
public function getInput()
{
// This line added to help us support the K2 Items and Joomla! Articles dropdown listbox array values
$this->value = is_array($this->value) ? implode(',', $this->value) : $this->value;
// Adds an extra info label next to input
$addon = (string) $this->element['addon'];
$parent = parent::getInput();
if (!empty($addon))
{
$html[] = '
<div class="input-append input-group">
' . $parent . '
<span class="add-on input-group-append">
<span class="input-group-text" style="font-size:inherit;">' . Text::_($addon) . '</span>
</span>
</div>';
} else
{
$html[] = parent::getInput();
}
// Adds a link next to input
$url = $this->element['url'];
$text = $this->element['urltext'];
$target = $this->element['urltarget'] ? $this->element['urltarget'] : "_blank";
$class = $this->element['urlclass'] ? $this->element['urlclass'] : "";
$attributes = "";
// Popup mode
if ($this->element["urlpopup"])
{
$class .= " nrPopup";
$attributes = 'data-width="600" data-height="600"';
$this->addPopupScript();
}
if ($url && $text)
{
$style = !defined('nrJ4') ? ' style="margin-left:10px;"' : '';
$html[] = '<a ' . $attributes . ' class="' . $class . '"' . $style . ' href="' . $url . '" target="' . $target . '">' . Text::_($text) . '</a>';
}
return implode('', $html);
}
private function addPopupScript()
{
static $run;
if ($run)
{
return;
}
$run = true;
Factory::getDocument()->addScriptDeclaration('
jQuery(function($) {
$(".nrPopup").click(function() {
url = $(this).attr("href");
width = $(this).data("width");
height = $(this).data("height");
window.open(""+url+"", "nrPopup", "width=" + width + ", height=" + height + "");
return false;
})
})
');
}
}

View File

@ -0,0 +1,59 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\CheckboxField;
use NRFramework\HTML;
class JFormFieldNRToggle extends CheckboxField
{
/**
* On state value
*
* @var int
*/
protected $on_value = 1;
/**
* Off state value
*
* @var int
*/
protected $off_value = 0;
/**
* Method to get the field input markup.
*
* @return string
*/
public function getInput()
{
HTML::stylesheet('plg_system_nrframework/toggle.css');
$required = $this->required ? ' required aria-required="true"' : '';
$checked = $this->checked ? ' checked' : '';
$class = !empty($this->class) ? ' ' . $this->class : '';
// Fix bug inherited from the Checkbox field where the input remains checked even if save it unchecked.
if ($this->checked && (string) $this->value == (string) $this->off_value)
{
$checked = '';
}
return '
<span class="nrtoggle' . $class . '">
<input type="hidden" name="' . $this->name . '" id="' . $this->id . '_" value="' . $this->off_value . '">
<input type="checkbox" name="' . $this->name . '" id="' . $this->id . '" value="'
. htmlspecialchars($this->on_value, ENT_COMPAT, 'UTF-8') . '"' . $checked . $required . ' />
<label for="' . $this->id . '"></label>
</span>
';
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Factory;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNRURL extends NRFormField
{
/**
* Method to render the input field
*
* @return string
*/
function getInput()
{
$url = $this->get("url", "#");
$target = $this->get("target", "_blank");
$text = $this->get("text");
$class = $this->get("class");
$icon = $this->get("icon", null);
$url = str_replace("{{base}}", URI::base(), $url);
$url = str_replace("{{root}}", URI::root(), $url);
$html[] = '<a class="nrurl ' . $class . '" href="' . $url . '" target="' . $target . '">';
if ($icon)
{
$html[] = '<span class="icon-'.$icon.'"></span>';
}
$html[] = $this->prepareText($text);
$html[] = '</a>';
// Add CSS to the page
$run = false;
if (!$run)
{
Factory::getDocument()->addStyleDeclaration('
.nrurl.disabled {
pointer-events: none;
}
');
$run = true;
}
return implode(" ", $html);
}
}

View File

@ -0,0 +1,71 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRVirtueMartCategories extends JFormFieldNRTreeSelect
{
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = true;
/**
* Indicates whether the options array should have the levels re-calculated
*
* @var boolean
*/
protected $fixLevels = true;
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.virtuemart_category_id as value, b.category_name as text, c.category_parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__virtuemart_categories as a')
->join('LEFT', '#__virtuemart_categories_' . $this->getLanguage() . ' AS b on a.virtuemart_category_id = b.virtuemart_category_id')
->join('LEFT', '#__virtuemart_category_categories AS c on a.virtuemart_category_id = c.id')
->order('c.id desc');
$db->setQuery($query);
return $db->loadObjectList();
}
/**
* VirtueMart is using different tables per language. Therefore, we need to use their API to get the default language code
*
* @return string
*/
private function getLanguage($default = 'en_gb')
{
// Silent inclusion.
@include_once JPATH_ADMINISTRATOR . '/components/com_virtuemart/helpers/config.php';
if (!class_exists('VmConfig'))
{
return $default;
}
// Init configuration
VmConfig::loadConfig();
return VmConfig::$jDefLang;
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldNRZooCategories extends JFormFieldNRTreeSelect
{
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = true;
/**
* Indicates whether the options array should have the levels re-calculated
*
* @var boolean
*/
protected $fixLevels = true;
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('id as value, name as text, parent as `parent`, IF (published=1, 0, 1) as disable')
->from('#__zoo_category')
->order('ordering');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,71 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\PasswordField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
class JFormFieldNR_Password extends PasswordField
{
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*/
public function getInput()
{
if (defined('nrJ4'))
{
return parent::getInput();
}
$id = $this->id . '_btn';
$doc = Factory::getDocument();
HTMLHelper::stylesheet('plg_system_nrframework/fields.css', false, true);
$doc->addStyleDeclaration('
.nr-pass-btn {
display:flex;
align-items:center;
}
.nr-pass-btn > * {
margin:0 !important;
padding:0 !important;
}
.nr-pass-btn label {
margin-left:5px !important;
user-select: none;
}
');
$doc->addScriptDeclaration('
jQuery(function($) {
$("#' . $id . '").change(function() {
var type = $(this).is(":checked") ? "text" : "password";
$(this).closest(".nr-pass").find(".nr-pass-input input").attr("type", type);
})
})
');
return '
<div class="nr-pass input-flex">
<div class="input-flex-item nr-pass-input">'. parent::getInput() .'</div>
<div class="input-flex-item nr-pass-btn">
<input name="' . $id . '" id="' . $id . '" type="checkbox"/>
<label for="' . $id . '">' . Text::_("JSHOW") . '</label>
</div>
</div>
';
}
}

View File

@ -0,0 +1,59 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\FormField;
use Joomla\CMS\Language\Text;
class JFormFieldNR_PRO extends FormField
{
/**
* Method to render the input field
*
* @return string
*/
protected function getInput()
{
$label = (string) $this->element['label'];
$buttonClass = isset($this->element['buttonClass']) ? (string) $this->element['buttonClass'] : null;
$isFeatureMode = !is_null($label) && !empty($label);
// Backwards compatibility for fields with type="nr_pro" and have no buttonClass value
if (is_null($buttonClass))
{
$buttonClass = 'btn-sm';
}
$buttonText = $isFeatureMode ? 'NR_UNLOCK_PRO_FEATURE' : 'NR_UPGRADE_TO_PRO';
NRFramework\HTML::renderProOnlyModal();
$html = '<a style="float:none;" class="btn btn-danger' . (!empty($buttonClass) ? ' ' . $buttonClass : '') . '" href="#" data-pro-only="' . Text::_($label) . '">';
if (defined('nrJ4'))
{
$html .= '<span class="icon-lock mr-2 me-1"></span> ';
} else
{
if ($isFeatureMode)
{
$html .= '<span class="icon-lock mr-2 me-1" style="position:relative; top:1px;"></span> ';
} else
{
$html .= '<span class="icon-heart mr-2 me-1" style="position:relative; top:2px; left:-1px;"></span> ';
}
}
$html .= Text::_($buttonText) . '</a>';
return $html;
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNR_Rate extends NRFormField
{
/**
* The form field type.
*
* @var string
*/
public $type = 'nr_rate';
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*/
public function getInput()
{
// Setup properties
$starwidth = $this->get('starwidth', '25px');
$numstarts = $this->get('numstars', 5);
$maxvalue = $this->get('maxvalue', 5);
$halfstar = $this->get('halfstar', 0) ? "true" : "false";
$spacing = $this->get('spacing', "3px");
$ratedfill = $this->get('ratedfill', "#e7711b");
$this->value = empty($this->value) ? 0 : $this->value;
static $run;
if (!$run)
{
// Add styles and scripts to DOM
HTMLHelper::_('jquery.framework');
HTMLHelper::script('plg_system_nrframework/vendor/jquery.rateyo.min.js', ['relative' => true, 'version' => true]);
HTMLHelper::stylesheet('plg_system_nrframework/vendor/jquery.rateyo.min.css', ['relative' => true, 'version' => true]);
$this->doc->addStyleDeclaration('
.nr_rate {
display: flex;
align-items: center;
}
.nr_rate_preview {
background-color: #393939;
color: #fff;
padding: 7px;
font-size: 12px;
line-height: 1;
min-width: 20px;
text-align: center;
border-radius: 2px;
position:relative;
top:2px;
}
.nr_rate .jq-ry-container {
padding: 0 10px 0 0;
}
.nr_rate svg {
max-width: unset;
}
');
$run = true;
}
$this->doc->addScriptDeclaration('
jQuery(function($) {
$("#nr_rate_'.$this->id.'").rateYo({
rating: ' . $this->value . ',
starWidth: "'. $starwidth .'",
numStars: ' . $numstarts . ',
maxValue: ' . $maxvalue . ',
halfStar: ' . $halfstar . ',
spacing: "' . $spacing . '",
ratedFill: "' . $ratedfill . '",
onInit: function (rating) {
$(this).parent().find(".nr_rate_preview").html(rating);
},
onSet: function(rating) {
$(this).next("input").val(rating);
},
onChange: function(rating) {
$(this).parent().find(".nr_rate_preview").html(rating);
}
});
});
');
$html[] = '<div class="nr_rate">';
$html[] = '<div id="nr_rate_'.$this->id.'"></div>';
$html[] = '<input value="' . $this->value . '" name="' . $this->name . '" type="hidden"/>';
$html[] = '<span class="nr_rate_preview"></span>';
$html[] = '</div>';
return implode(" ", $html);
}
}

View File

@ -0,0 +1,34 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\FormField;
class JFormFieldRuleValueHint extends FormField
{
protected function getLabel()
{
return;
}
/**
* Method to render the input field
*
* @return string
*/
protected function getInput()
{
$ruleName = (string) $this->element['ruleName'];
$rule = \NRFramework\Factory::getCondition($ruleName);
return '<div class="ruleValueHint">' . $rule->getValueHint() . '</div>';
}
}

View File

@ -0,0 +1,195 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Language\Text;
require_once dirname(__DIR__) . "/helpers/smarttags.php";
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNR_SmartTags extends NRFormField
{
/**
* Method to render the input field
*
* @return string
*/
function getInput()
{
$smartTags = new NRSmartTags();
// Add extra tags by calling an external method
if ($tagsMethod = $this->get("tagsMethod", null))
{
$method = explode("::", $tagsMethod);
if (is_array($method))
{
$extraTags = call_user_func($method);
$smartTags->add($extraTags);
}
}
$tags = $smartTags->get();
if (!$tags || !is_array($tags))
{
return;
}
$html[] = '
<div class="nrSmartTags">
<a class="nrst-btn"
href="#"
data-show-label="' . Text::_("NR_SMARTTAGS_SHOW") . '"
data-hide-label="' . Text::_("NR_SMARTTAGS_HIDE") . '">
<span class="icon icon-tag"></span>
<span class="l">' . $this->prepareText($this->get("linklabel", "NR_SMARTTAGS_SHOW")) . '</span>
</a>
<div class="nrst-wrap">
<div class="nrst-list">';
foreach ($tags as $tag => $value)
{
$html[] = '<div><a href="#" data-clipboard="' . $tag . '">' . $tag . '</a></div>';
}
$html[] = '</div></div></div>';
$this->addScript();
return implode(" ", $html);
}
/**
* Adds field's script and CSS into the document once
*/
private function addScript()
{
static $run;
if ($run)
{
return;
}
// Add script
$this->doc->addScriptDeclaration('
jQuery(function($) {
$(".nrst-btn").click(function() {
list = $(this).next();
$(this).find(".l").html(list.is(":visible") ? $(this).data("show-label") : $(this).data("hide-label"));
list.slideToggle();
})
$(".nrst-list a").click(function() {
var tag = $(this);
copyTextToClipboard(tag.data("clipboard"), function(success) {
if (success) {
tag.addClass("copied");
}
setTimeout(function() {
tag.removeClass("copied");
}, 1000);
});
return false;
});
function copyTextToClipboard(text, callback) {
var textArea = document.createElement("textarea");
textArea.style.position = "fixed";
textArea.style.top = 0;
textArea.style.left = 0;
textArea.style.width = "2em";
textArea.style.height = "2em";
textArea.style.background = "transparent";
textArea.value = text;
document.body.appendChild(textArea);
textArea.select();
try {
var success = document.execCommand("copy");
callback(success);
} catch (err) {
callback(false);
}
document.body.removeChild(textArea);
}
})
');
// Add height
if ($height = $this->get("height", null))
{
$this->doc->addStyleDeclaration('
.nrst-wrap {
height: ' . $height . ';
overflow-x: hidden;
padding-right: 10px;
}'
);
}
// Add CSS
$this->doc->addStyleDeclaration('
.nrst-wrap {
display:none;
}
.nrst-list {
display:flex;
flex-wrap: wrap;
margin:10px -3px 0 -3px;
}
.nrst-list div {
min-width:50%;
}
.nrst-list a {
-webkit-transition: background 150ms ease;
-moz-transition: background 150ms ease;
transition: background 150ms ease;
color: inherit;
text-decoration: none;
display: block;
border: solid 1px #ddd;
padding: 7px;
line-height: 1;
margin: 3px;
font-size: 12px;
}
.nrst-list a:hover {
background-color:#eee;
}
.nrst-list a:after {
font-family: "IcoMoon";
font-style: normal;
speak: none;
float: right;
font-size: 10px;
line-height: 1;
}
.nrst-list a:hover:after {
content: "\e018";
}
.nrst-list a.copied {
background:#dff0d8;
}
.nrst-list a.copied:after {
content: "\47";
color: green;
}
');
$run = true;
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\FormField;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use NRFramework\SmartTags;
use Joomla\CMS\Factory;
class JFormFieldSmartTagsBox extends FormField
{
/**
* Undocumented variable
*
* @var string
*/
public $input_selector = '.show-smart-tags';
/**
* Disable field label
*
* @return boolean
*/
protected function getLabel()
{
return false;
}
/**
* Method to get a list of options for a list input.
*
* @return array An array of options.
*/
protected function getInput()
{
HTMLHelper::_('script', 'plg_system_nrframework/smarttagsbox.js', ['version' => 'auto', 'relative' => true]);
HTMLHelper::_('stylesheet', 'plg_system_nrframework/smarttagsbox.css', ['version' => 'auto', 'relative' => true]);
Text::script('NR_SMARTTAGS_NOTFOUND');
Text::script('NR_SMARTTAGS_SHOW');
Factory::getDocument()->addScriptOptions('SmartTagsBox', [
'selector' => $this->input_selector,
'tags' => [
'Joomla' => [
'{page.title}' => Text::_('NR_TAG_PAGETITLE'),
'{url}' => Text::_('NR_TAG_URL'),
'{url.path}' => Text::_('NR_TAG_URLPATH'),
'{page.lang}' => Text::_('NR_TAG_PAGELANG'),
'{page.langurl}' => Text::_('NR_TAG_PAGELANGURL'),
'{page.desc}' => TEXT::_('NR_TAG_PAGEDESC'),
'{site.name}' => TEXT::_('NR_TAG_SITENAME'),
'{site.url}' => Text::_('NR_TAG_SITEURL'),
'{site.email}' => Text::_('NR_TAG_SITEEMAIL'),
'{user.id}' => Text::_('NR_TAG_USERID'),
'{user.username}' => Text::_('NR_USER_USERNAME'),
'{user.email}' => Text::_('NR_TAG_USEREMAIL'),
'{user.name}' => Text::_('NR_TAG_USERNAME'),
'{user.firstname}' => Text::_('NR_TAG_USERFIRSTNAME'),
'{user.lastname}' => Text::_('NR_TAG_USERLASTNAME'),
'{user.groups}' => Text::_('NR_TAG_USERGROUPS'),
'{user.registerdate}' => Text::_('NR_USER_REGISTRATION_DATE'),
],
Text::_('NR_VISITOR') => [
'{client.device}' => Text::_('NR_TAG_CLIENTDEVICE'),
'{ip}' => Text::_('NR_TAG_IP'),
'{client.browser}' => Text::_('NR_TAG_CLIENTBROWSER'),
'{client.os}' => Text::_('NR_TAG_CLIENTOS'),
'{client.useragent}' => Text::_('NR_TAG_CLIENTUSERAGENT'),
'{client.id}' => Text::_('NR_TAG_CLIENTID'),
'{geo.country}' => Text::_('NR_TAG_GEOCOUNTRY'),
'{geo.countrycode}' => Text::_('NR_TAG_GEOCOUNTRYCODE'),
'{geo.city}' => Text::_('NR_TAG_GEOCITY'),
'{geo.location}' => Text::_('NR_TAG_GEOLOCATION'),
],
Text::_('NR_OTHER') => [
'{date}' => Text::_('NR_DATE'),
'{time}' => Text::_('NR_TIME'),
'{day}' => Text::_('NR_TAG_DAY'),
'{month}' => Text::_('NR_TAG_MONTH'),
'{year}' => Text::_('NR_TAG_YEAR'),
'{referrer}' => Text::_('NR_ASSIGN_REFERRER'),
'{randomid}' => Text::_('NR_TAG_RANDOMID'),
'{querystring.YOUR_KEY}' => Text::_('NR_QUERY_STRING'),
'{language.YOUR_KEY}' => Text::_('NR_LANGUAGE_STRING'),
'{post.YOUR_KEY}' => Text::_('NR_POST_DATA'),
'{cookie.YOUR_KEY}' => Text::_('NR_COOKIE')
]
]
]);
// Render box layout
$layout = new FileLayout('smarttagsbox', JPATH_PLUGINS . '/system/nrframework/layouts');
return $layout->render();
}
}

View File

@ -0,0 +1,45 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\FormField;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\FileLayout;
class JFormFieldTFAddressLookup extends FormField
{
public function getInput()
{
$group_class = isset($this->element['group_class']) ? (string) $this->element['group_class'] : 'stack mb-0';
$label = isset($this->element['label']) ? (string) $this->element['label'] : 'NR_ADDRESS';
$autocomplete = true;
if (isset($this->element['autocomplete']) & (string) $this->element['autocomplete'] === 'false')
{
$autocomplete = false;
}
Text::script('NR_UNTITLED_MARKER');
$payload = [
'id' => $this->id,
'label' => $label,
'name' => $this->name,
'value' => $this->value,
'visible' => true,
'autocomplete' => $autocomplete,
'group_class' => $group_class
];
$layout = new FileLayout('addresslookup', JPATH_PLUGINS . '/system/nrframework/layouts');
return $layout->render($payload);
}
}

View File

@ -0,0 +1,103 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\FormField;
use Joomla\CMS\Form\Form;
class JFormFieldTFBorderControl extends FormField
{
protected function getInput()
{
// Control Group Class
$control_group_class = (string) $this->element['control_group_class'];
// Defaults
$default_style = isset($this->element['default_style']) ? (string) $this->element['default_style'] : '';
$default_width = isset($this->element['default_width']) ? (string) $this->element['default_width'] : 0;
$default_color = isset($this->element['default_color']) ? (string) $this->element['default_color'] : '';
// Hides the inner control labels
$hide_labels = (bool) $this->element['hide_labels'];
$hiddenLabel = $hide_labels ? 'hiddenLabel="true"' : '';
// Prefix and suffix for the fieldset
$prefix = $suffix = '';
// Whether to display the fields inline
$inline = (bool) $this->element['inline'];
if ($inline)
{
$prefix = '<field name="border_control_row_start" type="nr_inline" />';
$suffix = '<field name="border_control_row_end" type="nr_inline" end="1" />';
}
$form_source = new SimpleXMLElement('
<form>
<fieldset name="border">
' . $prefix . '
<field name="style" type="list"
' . $hiddenLabel . '
label="NR_STYLE"
class="tfHasChosen"
description="NR_BORDER_CONTROL_STYLE_DESC"
default="' . $default_style . '"
required="' . $this->required . '"
disabled="' . $this->disabled . '">
<option value="none">NR_NONE</option>
<option value="solid">NR_SOLID</option>
<option value="dotted">NR_DOTTED</option>
<option value="dashed">NR_DASHED</option>
<option value="double">NR_DOUBLE</option>
<option value="groove">NR_GROOVE</option>
<option value="ridge">NR_RIDGE</option>
</field>
<field name="width" type="nrnumber"
' . $hiddenLabel . '
label="NR_WIDTH"
description="NR_BORDER_WIDTH_DESC"
class="input-small"
default="' . $default_width . '"
required="' . $this->required . '"
disabled="' . $this->disabled . '"
addon="px"
showon="style!:none"
/>
<field name="color" type="color"
' . $hiddenLabel . '
label="NR_COLOR"
description="NR_BORDER_COLOR_DESC"
keywords="transparent,none"
format="rgba"
position="bottom"
default="' . $default_color . '"
required="' . $this->required . '"
disabled="' . $this->disabled . '"
showon="style!:none"
/>
' . $suffix . '
</fieldset>
</form>
');
$control = $this->name;
$formname = 'border.' . str_replace(['jform[', '[', ']'], ['', '.', ''], $control);
$form = Form::getInstance($formname, $form_source->asXML(), ['control' => $control]);
$form->bind($this->value);
return $form->renderFieldset('border', [
'class' => $control_group_class
]);
}
}

View File

@ -0,0 +1,32 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
require_once 'tfdimensioncontrol.php';
class JFormFieldTFBorderRadiusControl extends JFormFieldTFDimensionControl
{
protected $input_type = 'border_radius';
/**
* Set the dimensions.
*
* @var array
*/
protected $dimensions = [
'top_left' => 'NR_TOP_LEFT',
'top_right' => 'NR_TOP_RIGHT',
'bottom_right' => 'NR_BOTTOM_RIGHT',
'bottom_left' => 'NR_BOTTOM_LEFT'
];
}

View File

@ -0,0 +1,158 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\Field\TextField;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\HTML\HTMLHelper;
class JFormFieldTFDimensionControl extends TextField
{
protected $input_type = 'margin_padding';
protected $default_units = ['px', '%', 'em', 'rem'];
/**
* Set the dimensions.
*
* @var array
*/
protected $dimensions = [
'top' => 'NR_TOP',
'right' => 'NR_RIGHT',
'bottom' => 'NR_BOTTOM',
'left' => 'NR_LEFT'
];
/**
* Set whether the linked button will be enabled or not.
*
* @var boolean
*/
protected $linked = true;
/**
* Method to get a list of options for a list input.
* @return array An array of options.
*/
protected function getInput()
{
if (!$this->dimensions = isset($this->element['dimensions']) ? $this->parseDimensions($this->element['dimensions']) : $this->dimensions)
{
return;
}
$value = is_scalar($this->value) ? $this->value : (array) $this->value;
$value = \NRFramework\Helpers\Controls\Spacing::parseInputValue($value, $this->input_type);
$this->assets();
$this->linked = isset($this->element['linked']) ? (boolean) $this->element['linked'] : (isset($value['linked']) ? (boolean) $value['linked'] : $this->linked);
$units = $this->getUnits();
if (count($units) > 0 && isset($value['value']))
{
/**
* If the value unit is not in the $units list,
* this means that the value most probably was a string that had a specific unit set,
* such as: 50em
*
* We add the "em" to the units list in order to use the existing value unit
* and later on allow the user to switch to the new units. The new units wont allow the
* user to use the previous unit once they change to the new one.
*/
if (!in_array($value['unit'], $units))
{
$units[] = $unit;
}
}
$payload = [
'dimensions' => $this->dimensions,
'dimension_control_locks' => isset($this->element['dimension_control_locks']) ? (bool) $this->element['dimension_control_locks'] === 'true' : true,
'linked' => $this->linked,
'units' => $units,
'name' => $this->name,
'value' => $value
];
$layout = new FileLayout('dimension', JPATH_PLUGINS . '/system/nrframework/layouts/controls');
return $layout->render($payload);
}
private function getUnits()
{
$units = isset($this->element['units']) && !empty($this->element['units']) ? (string) $this->element['units'] : $this->default_units;
if (!$units)
{
return [];
}
return is_string($units) ? array_filter(array_unique(array_map('trim', explode(',', $units)))) : $units;
}
/**
* Prepares the given dimensions.
*
* Input:
*
* - top:NR_TOP,right:NR_RIGHT,bottom:NR_BOTTOM,left:NR_LEFT
* - top_left:Top Left,top_right:Top Right,bottom_right:Bottom Right,bottom_left:Bottom Left
*
* @param array $dimensions
*
* @return array
*/
private function parseDimensions($dimensions = [])
{
$pairs = explode(',', $dimensions);
$parsed = [];
if (empty(array_filter($pairs)))
{
return [];
}
foreach ($pairs as $key => $pair)
{
if (!$value = explode(':', $pair))
{
continue;
}
// We expect 2 key,value pairs
if (count($value) !== 2)
{
continue;
}
$parsed[$value[0]] = Text::_($value[1]);
}
return $parsed;
}
/**
* Load field assets.
*
* @return void
*/
private function assets()
{
HTMLHelper::script('plg_system_nrframework/autosize-input.js', ['relative' => true, 'version' => 'auto']);
HTMLHelper::stylesheet('plg_system_nrframework/controls/dimension.css', ['relative' => true, 'version' => 'auto']);
HTMLHelper::script('plg_system_nrframework/controls/dimension.js', ['relative' => true, 'version' => true]);
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/treeselect.php';
class JFormFieldTFDPCalendarCategories extends JFormFieldNRTreeSelect
{
/**
* Get a list of all EventBooking Categories
*
* @return void
*/
protected function getOptions()
{
// Get a database object.
$db = $this->db;
$query = $db->getQuery(true)
->select('a.id as value, a.title as text, COUNT(DISTINCT b.id) AS level, a.parent_id as parent, IF (a.published=1, 0, 1) as disable')
->from('#__categories as a')
->join('LEFT', '#__categories AS b on a.lft > b.lft AND a.rgt < b.rgt')
->where('a.extension = "com_dpcalendar"')
->group('a.id, a.title, a.lft')
->order('a.lft ASC');
$db->setQuery($query);
return $db->loadObjectList();
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldTFEcommRangeField extends NRFormField
{
/**
* Method to render the input field
*
* @return string
*/
protected function getInput()
{
$prefixLabel = isset($this->element['prefixLabel']) ? (string) $this->element['prefixLabel'] : false;
$mainName = (string) $this->element['name'];
$showIsAnyOption = isset($this->element['showIsAnyOption']) ? (string) $this->element['showIsAnyOption'] === 'true' : false;
$isAnyOption = $showIsAnyOption ? '<option value="any">NR_ANY</option>' : '';
$showIsNotEqualOption = isset($this->element['showIsNotEqualOption']) ? (string) $this->element['showIsNotEqualOption'] === 'true' : false;
$isNotEqualOption = $showIsNotEqualOption ? '<option value="not_equal">NR_NOT_EQUAL_TO</option>' : '';
$xml = new SimpleXMLElement('
<fields name="' . $mainName . '">
<fieldset name="' . $mainName . '">
<field name="operator" type="comparator"
hiddenLabel="true"
class="noChosen"
default="any">
' . $isAnyOption . '
<option value="equal">NR_EQUAL_TO</option>
' . $isNotEqualOption . '
<option value="less_than">NR_FEWER_THAN</option>
<option value="less_than_or_equal_to">NR_FEWER_THAN_OR_EQUAL_TO</option>
<option value="greater_than">NR_GREATER_THAN</option>
<option value="greater_than_or_equal_to">NR_GREATER_THAN_OR_EQUAL_TO</option>
<option value="range">NR_BETWEEN</option>
</field>
<field name="value" type="number"
hiddenLabel="true"
class="input-small"
default="1"
hint="1"
min="1"
showon="operator!:any"
/>
<field name="range_note" type="note"
class="tf-note-and"
description="NR_AND_LC"
showon="operator:range"
/>
<field name="value2" type="number"
hiddenLabel="true"
class="input-small"
default="1"
hint="1"
min="1"
showon="operator:range"
/>
</fieldset>
</fields>
');
$this->form->setField($xml);
foreach ($xml->field as $key => $field)
{
$name = (string) $field->attributes()->name;
$type = (string) $field->attributes()->type;
$value = isset($this->value[$name]) ? $this->value[$name] : null;
$this->form->setValue($name, null, $value);
}
$html = $this->form->renderFieldset($mainName);
HTMLHelper::stylesheet('plg_system_nrframework/tf-ecomm-range-field.css', ['relative' => true, 'version' => 'auto']);
$prefix = $prefixLabel ? '<span>' . Text::_($prefixLabel) . '</span>' : '';
return '<div class="tf-ecomm-range-extra-settings' . (!empty($this->class) ? ' ' . $this->class : '') . '">' . $prefix . $html . '</div>';
}
}

View File

@ -0,0 +1,91 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\EditorField;
use Joomla\CMS\Form\Field\TextareaField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Factory;
class JFormFieldTFEditor extends TextareaField
{
public function getInput()
{
$this->class .= ' tf-editor';
$this->loadAssets();
return '<div class="tf-editor-wrapper"' . $this->getWrapperAttributes() . '>' . parent::getInput() . '</div>';
}
private function loadAssets()
{
$doc = Factory::getDocument();
// Get the global editor
$globalEditor = Factory::getConfig()->get('editor');
// Get the user editor
$userEditor = Factory::getUser()->getParam('editor');
$editor = $userEditor ? $userEditor : $globalEditor;
$option = Factory::getApplication()->input->get('option', '');
$layout = Factory::getApplication()->input->get('layout', '');
if (!in_array($option, ['com_content', 'com_contact']) || $layout !== 'edit' || $editor !== 'jce')
{
if (JVERSION < 4)
{
$doc->addScript(Uri::root(true) . '/media/editors/tinymce/tinymce.min.js');
}
else
{
$wa = $doc->getWebAssetManager();
if (!$wa->assetExists('script', 'tinymce'))
{
$wa->registerScript('tinymce', 'media/vendor/tinymce/tinymce.min.js', [], ['defer' => true]);
}
if (!$wa->assetExists('script', 'plg_editors_tinymce'))
{
$wa->registerScript('plg_editors_tinymce', 'plg_editors_tinymce/tinymce.min.js', [], ['defer' => true], ['core', 'tinymce']);
}
$wa->useScript('tinymce')->useScript('plg_editors_tinymce');
}
}
HTMLHelper::stylesheet('plg_system_nrframework/controls/editor.css', ['relative' => true, 'versioning' => 'auto']);
HTMLHelper::script('plg_system_nrframework/controls/editor.js', ['relative' => true, 'versioning' => 'auto'], ['defer' => true]);
}
private function getWrapperAttributes()
{
$plugins = isset($this->element['plugins']) ? array_filter(array_map('trim', explode(',', (string) $this->element['plugins']))) : false;
$toolbar = isset($this->element['toolbar']) ? array_filter(array_map('trim', explode(',', (string) $this->element['toolbar']))) : false;
$atts = [];
if ($plugins)
{
$atts[] = 'data-plugins="' . htmlspecialchars(json_encode($plugins), ENT_COMPAT, 'UTF-8') . '"';
}
if ($toolbar)
{
$atts[] = 'data-toolbar="' . htmlspecialchars(json_encode($toolbar), ENT_COMPAT, 'UTF-8') . '"';
}
return implode(' ', $atts);
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2021 Tassos Marinos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\TextField;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\HTML\HTMLHelper;
class JFormFieldTFGlobalDevicesSelector extends TextField
{
/**
* Method to render the input field
*
* @return string
*/
public function getInput()
{
$this->assets();
$payload = [
'devices' => \NRFramework\Helpers\Responsive::getBreakpoints()
];
$layout = new FileLayout('global_devices_selector', JPATH_PLUGINS . '/system/nrframework/layouts');
return $layout->render($payload);
}
/**
* Load field assets.
*
* @return void
*/
private function assets()
{
HTMLHelper::stylesheet('plg_system_nrframework/global_devices_selector.css', ['relative' => true, 'version' => 'auto']);
HTMLHelper::script('plg_system_nrframework/global_devices_selector.js', ['relative' => true, 'version' => 'auto']);
}
}

View File

@ -0,0 +1,114 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2020 Tassos Marinos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\FormField;
use Joomla\CMS\HTML\HTMLHelper;
class JFormFieldTFImageDimensionsControl extends FormField
{
/**
* Renders the input field with the video previewer.
*
* @return string The field input markup.
*/
protected function getInput()
{
$this->assets();
$isNew = $this->form->getData()->get('id') == 0;
$by = isset($this->element['by']) ? (string) $this->element['by'] : '';
$width = isset($this->element['width']) ? (string) $this->element['width'] : '';
$height = isset($this->element['height']) ? (string) $this->element['height'] : '';
$hide_disabled_option = isset($this->element['hide_disabled_option']) ? (string) $this->element['hide_disabled_option'] === 'true' : false;
$disabled_label = isset($this->element['disabled_label']) ? (string) $this->element['disabled_label'] : 'JDISABLED';
$hide_dropdown = isset($this->element['hide_dropdown']) ? (string) $this->element['hide_dropdown'] === 'true' : false;
if (is_string($this->value))
{
$this->value = json_decode($this->value, true);
}
$elName = (string) $this->element['name'];
$by_field = '';
if (!$hide_dropdown)
{
$by_field = '
<field name="by" type="list"
hiddenLabel="true"
default="' . ($isNew && isset($this->value['by']) ? $this->value['by'] : (is_null($this->value) ? $by : '')) .'"
>
' . (!$hide_disabled_option ? '<option value="disabled">' . $disabled_label . '</option>' : '') . '
<option value="width">NR_RESIZE_BY_WIDTH</option>
<option value="height">NR_RESIZE_BY_HEIGHT</option>
<option value="custom">NR_CUSTOM_SIZE</option>
</field>';
}
else
{
$by_field = '<field name="by" type="hidden" default="' . ($isNew && isset($this->value['by']) ? $this->value['by'] : $by) . '" />';
}
$xml = new SimpleXMLElement('
' . ($this->group ? '<fields name="' . $this->group . '">' : '') . '
<fields name="' . $elName . '">
' . $by_field . '
<field name="width" type="nrnumber"
hiddenLabel="true"
min="0"
filter="raw"
addon="px"
hint="NR_WIDTH"
default="' . ($isNew && isset($this->value['width']) ? $this->value['width'] : (is_null($this->value) ? $width : '')) .'"
showon="by:width[OR]by:custom"
/>
<field name="x_label" type="note"
class="separator-label"
description="NR_TIMES_UNICODE"
showon="by:custom"
/>
<field name="height" type="nrnumber"
hiddenLabel="true"
min="0"
filter="raw"
addon="px"
hint="NR_HEIGHT"
default="' . ($isNew && isset($this->value['height']) ? $this->value['height'] : (is_null($this->value) ? $height : '')) .'"
showon="by:height[OR]by:custom"
/>
</fields>
' . ($this->group ? '</fields>' : '') . '
');
$this->form->setField($xml);
$html = [];
$fields = isset($xml->fields) ? $xml->fields->field : $xml->field;
foreach ($fields as $key => $field)
{
$name = $field->attributes()->name;
$html[] = $this->form->renderField($name, ($this->group ? $this->group . '.' : '') . $elName);
}
return '<div class="tf-imagedimensions-control">' . implode('', $html) . '</div>';
}
private function assets()
{
HTMLHelper::stylesheet('plg_system_nrframework/controls/imagedimensions.css', ['relative' => true, 'version' => 'auto']);
HTMLHelper::script('plg_system_nrframework/controls/imagedimensions.js', ['relative' => true, 'version' => 'auto']);
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\Field\SubformField;
use Joomla\CMS\HTML\HTMLHelper;
class JFormFieldTFInputRepeater extends SubformField
{
/**
* Method to attach a Form object to the field.
*
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the <field /> tag for the form field object.
* @param mixed $value The form field value to validate.
* @param string $group The field name group control value.
*
* @return boolean True on success.
*
* @since 3.6
*/
public function setup(\SimpleXMLElement $element, $value, $group = null)
{
$element->addAttribute('multiple', true);
// By default initialize the field with an empty item.
if (empty($value))
{
$value = [0 => ''];
}
// In case we have provided a default value in the XML in JSON format
if ($value && is_string($value))
{
// Attempt to decode as JSON
$value_ = json_decode($value, true);
// If JSON decode fails, expect comma-separated or newline-separated values
if (is_null($value_))
{
$value = NRFramework\Functions::makeArray($value);
$new_value = [];
foreach ($value as $key => $val)
{
$new_value['value' . $key] = [
'value' => $val
];
}
$value = $new_value;
} else
{
$value = $value_;
}
}
parent::setup($element, $value, $group);
return true;
}
/**
* Method to get a list of options for a list input.
* @return array An array of options.
*/
protected function getInput()
{
$this->layout = 'joomla.form.field.subform.repeatable-table';
$this->assets();
return '<div class="tf-input-repeater ' . $this->class . '">' . parent::getInput() . '<a href="#" class="btn tf-input-repeater-add"><span class="icon-plus"></span></a></div>';
}
/**
* Load field assets.
*
* @return void
*/
private function assets()
{
HTMLHelper::stylesheet('plg_system_nrframework/tfinputrepeater.css', ['relative' => true, 'version' => 'auto']);
HTMLHelper::script('plg_system_nrframework/tfinputrepeater.js', ['relative' => true, 'version' => true]);
}
}

View File

@ -0,0 +1,70 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\HiddenField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\Registry\Registry;
use Joomla\CMS\Factory;
use NRFramework\HTML;
class JFormFieldTFLatLongMapSelector extends HiddenField
{
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*/
public function getInput()
{
$this->class = 'tf-map-editor--value';
// Setup properties
$this->readonly = $this->get('readonly', false) ? 'readonly' : '';
$this->value = $this->checkCoordinates($this->value, null) ? $this->value : $this->get('default', '36.892587, 27.287793');
$this->hint = $this->get('hint', 'NR_ENTER_COORDINATES');
HTMLHelper::script('plg_system_nrframework/controls/latlongmapselector.js', ['version' => 'auto', 'relative' => true]);
$payload = [
'readonly' => $this->readonly,
'disabled' => $this->disabled,
'name' => $this->name,
'required' => $this->required,
'css_class' => 'tf-lat-long-map-selector',
'id' => $this->id,
'value' => $this->value
];
return \NRFramework\Widgets\Helper::render('OpenStreetMap', $payload) . parent::getInput();
}
/**
* Method to get field parameters
*
* @param string $val Field parameter
* @param string $default The default value
*
* @return string
*/
public function get($val, $default = '')
{
return (isset($this->element[$val]) && (string) $this->element[$val] != '') ? (string) $this->element[$val] : $default;
}
/**
* Checks the validity of the coordinates
*/
private function checkCoordinates($coordinates)
{
return (preg_match("/^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$/", $coordinates));
}
}

View File

@ -0,0 +1,105 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\Field\TextField;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
class JFormFieldTFPhoneControl extends TextField
{
/**
* Returns control input.
*
* @return string
*/
protected function getInput()
{
$this->assets();
$aria_label = $this->element['aria_label'] ? (string) $this->element['aria_label'] : '';
$class = $this->element['class'] ? (string) $this->element['class'] : '';
$input_class = $this->element['input_class'] ? (string) $this->element['input_class'] : '';
$inputmask = $this->element['inputmask'] ? (string) $this->element['inputmask'] : '';
$value = $this->value;
if (is_object($value))
{
$value = (array) $value;
}
$decodedValue = is_string($value) ? json_decode($value, true) : false;
if (is_string($value) && is_array($decodedValue))
{
$value = $decodedValue;
}
else if (is_scalar($value))
{
$value = [
'code' => '',
'value' => $value
];
}
// Enqueue the country data as JS object
Factory::getDocument()->addScriptOptions('tf_phonecontrol_data', $this->getCountriesData($value['value']));
$payload = [
'name' => $this->name,
'id' => $this->id,
'value' => $value,
'class' => $class,
'input_class' => $input_class,
'inputmask' => $inputmask,
'required' => $this->required,
'readonly' => $this->readonly,
'placeholder' => (string) $this->element['placeholder'],
'browserautocomplete' => (string) $this->element['browserautocomplete'] !== '1',
'aria_label' => $aria_label
];
$layout = new FileLayout('phonecontrol', JPATH_PLUGINS . '/system/nrframework/layouts/controls');
return $layout->render($payload);
}
/**
* Load field assets.
*
* @return void
*/
private function assets()
{
HTMLHelper::stylesheet('plg_system_nrframework/vendor/choices.min.css', ['relative' => true, 'versioning' => 'auto']);
HTMLHelper::script('plg_system_nrframework/vendor/choices.min.js', ['relative' => true, 'versioning' => 'auto']);
HTMLHelper::stylesheet('plg_system_nrframework/controls/phone.css', ['relative' => true, 'versioning' => 'auto']);
HTMLHelper::script('plg_system_nrframework/controls/phone.js', ['relative' => true, 'versioning' => 'auto']);
}
private function getCountriesData($value = '')
{
$countries = NRFramework\Countries::getCountriesData();
$countries = array_map(function($country) {
return [
'name' => $country['name'],
'calling_code' => $country['calling_code']
];
}, $countries);
return $countries;
}
}

View File

@ -0,0 +1,68 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2024 Tassos Marinos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\Field\TagField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
class JFormFieldTFTagsControl extends TagField
{
/**
* Name of the layout being used to render the field
*
* @var string
* @since 4.0.0
*/
protected $layout = 'joomla.form.field.tag';
protected function getInput()
{
if (!defined('nrJ4'))
{
return parent::getInput();
}
$data = $this->getLayoutData();
$data['value'] = $this->value;
$data['options'] = $this->getOptions();
$data['multiple'] = true;
$data['allowCustom'] = true;
$data['remoteSearch'] = false;
$data['dataAttribute'] = ' allow-custom';
return $this->getRenderer($this->layout)->render($data);
}
/**
* Method to get a list of options for a list input.
*
* @return array
*/
protected function getOptions()
{
// Get all dropdown choices
$options = [];
if (is_array($this->value))
{
foreach ($this->value as $key => $value)
{
$options[] = HTMLHelper::_('select.option', $key, $value);
}
}
return $options;
}
}

View File

@ -0,0 +1,52 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\TextField;
use NRFramework\Countries;
class JFormFieldTFTel extends TextField
{
protected $layout = 'joomla.form.field.tel';
/**
* Method to render the input field
*
* @return string
*/
public function getInput()
{
$this->maybeParseValue();
return parent::getInput();
}
private function maybeParseValue()
{
$value = $this->value;
if (is_string($value) && json_decode($value, true))
{
$value = json_decode($value, true);
}
if (is_array($value))
{
$countryCode = isset($value['code']) ? $value['code'] : '';
$phoneNumber = isset($value['value']) ? $value['value'] : '';
$calling_code = Countries::getCallingCodeByCountryCode($countryCode);
$calling_code = $calling_code !== '' ? '+' . $calling_code : '';
$this->value = $calling_code . $phoneNumber;
}
}
}

View File

@ -0,0 +1,155 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2021 Tassos Marinos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\Form\Field\TextField;
use Joomla\CMS\Layout\FileLayout;
use Joomla\CMS\HTML\HTMLHelper;
class JFormFieldTFUnitControl extends TextField
{
private $units = ['px', '%', 'em', 'rem'];
private $default_unit = 'px';
private $min = 0;
private $max;
private $step;
/**
* Method to render the input field
*
* @return string
*/
public function getInput()
{
$wrapper_class = $dropdown_class = '';
$initial_name = $this->name;
$units = $this->getUnits();
$hint = $this->hint;
$parsedValue = \NRFramework\Helpers\Controls\Control::findUnitInValue($this->value);
$value = isset($parsedValue['value']) ? $parsedValue['value'] : $this->value;
$unit = isset($parsedValue['unit']) && $parsedValue['unit'] ? $parsedValue['unit'] : (isset($units[0]) && $units[0] ? $units[0] : $this->default_unit);
if ($value === 'auto' || $unit === 'auto')
{
$unit = 'auto';
$this->hint = '';
$this->readonly = true;
$wrapper_class .= ' has-value';
}
else if (count($units) > 0 && $unit)
{
/**
* If the value unit is not in the $units list,
* this means that the value most probably was a string that had a specific unit set,
* such as: 50em
*
* We add the "em" to the units list in order to use the existing value unit
* and later on allow the user to switch to the new units. The new units wont allow the
* user to use the previous unit once they change to the new one.
*/
if (!in_array($unit, $units))
{
$units[] = $unit;
}
}
if (count($units) > 0)
{
$this->assets();
}
if (count($units) > 1)
{
$wrapper_class .= ' has-multiple-units';
}
if ($value !== '')
{
$wrapper_class .= ' has-value';
}
// Update value
$this->value = $value;
// Append [value] to name
$this->name .= '[value]';
$this->min = isset($this->element['min']) ? (int) $this->element['min'] : $this->min;
$this->max = isset($this->element['max']) ? (int) $this->element['max'] : $this->max;
$this->step = isset($this->element['step']) ? (int) $this->element['step'] : $this->step;
$this->layout = 'joomla.form.field.number';
$this->class .= (!empty($this->class) ? ' ' : '') . 'tf-unit-control--value';
$html = parent::getInput();
$html = str_replace('form-control', '', $html);
$payload = [
// Default values
'value' => $value,
'unit' => $unit,
'wrapper_class' => $wrapper_class,
'dropdown_class' => $dropdown_class,
'name' => $initial_name,
'input' => $html,
'hint' => $hint,
'form_field_name' => $this->name,
'units' => $units
];
$layout = new FileLayout('unit', JPATH_PLUGINS . '/system/nrframework/layouts/controls');
return $layout->render($payload);
}
private function getUnits()
{
$units = isset($this->element['units']) ? (string) $this->element['units'] : $this->units;
return is_string($units) ? array_filter(array_unique(array_map('trim', explode(',', $units)))) : $units;
}
/**
* Method to get the data to be passed to the layout for rendering.
*
* @return array
*/
protected function getLayoutData()
{
$data = parent::getLayoutData();
$extraData = [
'max' => $this->max,
'min' => $this->min,
'step' => $this->step,
'value' => $this->value
];
return array_merge($data, $extraData);
}
/**
* Load field assets.
*
* @return void
*/
private function assets()
{
HTMLHelper::script('plg_system_nrframework/autosize-input.js', ['relative' => true, 'version' => 'auto']);
HTMLHelper::stylesheet('plg_system_nrframework/controls/unit.css', ['relative' => true, 'version' => 'auto']);
}
}

View File

@ -0,0 +1,117 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2020 Tassos Marinos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Form\Field\TextField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
class JFormFieldTFVideoInput extends TextField
{
/**
* Renders the input field with the video previewer.
*
* @return string The field input markup.
*/
protected function getInput()
{
$this->setHint();
$previewer_enabled = isset($this->element['previewer_enabled']) ? (string) $this->element['previewer_enabled'] : 'true';
if ($previewer_enabled !== 'true')
{
return parent::getInput();
}
$provider = (string) $this->element['provider'];
$this->class = 'tf-video-url-input-value';
if (!defined('nrJ4'))
{
$this->class .= ' input-xxlarge';
}
// Sanitize the URL
$this->value = filter_var($this->value, FILTER_SANITIZE_URL);
$this->assets();
$input = '';
if ($provider === 'SelfHostedVideo' && defined('nrJ4'))
{
$xml = '
<field name="' . $this->fieldname . '"
class="tf-video-url-input-value"
type="media"
preview="false"
types="videos"
hiddenLabel="true"
/>
';
$this->form->setField(new SimpleXMLElement($xml));
$field = $this->form->getField($this->fieldname, null, $this->value);
$field->name = $this->name;
$field->id = $this->id;
$input = $field->getInput();
}
else
{
$input = parent::getInput();
}
return $input . $this->getPreviewerHTML();
}
private function getProvider()
{
return $this->element['provider'] ? (string) $this->element['provider'] : '';
}
private function setHint()
{
switch ($this->getProvider())
{
case 'YouTube':
$this->hint = 'https://www.youtube.com/watch?v=IWVJq-4zW24';
break;
case 'Vimeo':
$this->hint = 'https://vimeo.com/146782320';
break;
case 'Dailymotion':
$this->hint = 'https://www.dailymotion.com/video/x8mvsem';
break;
case 'Facebook':
$this->hint = 'https://www.facebook.com/watch/?v=441279306439983';
break;
case 'SelfHostedVideo':
$this->hint = '/media/video.mp4';
break;
}
}
private function assets()
{
HTMLHelper::stylesheet('plg_system_nrframework/tf-video-input.css', ['relative' => true, 'version' => 'auto']);
HTMLHelper::script('plg_system_nrframework/tf-video-input.js', ['relative' => true, 'version' => 'auto']);
}
private function getPreviewerHTML()
{
return '<div class="tf-video-input-previewer-wrapper" data-provider="' . $this->getProvider() . '" data-root-url="' . Uri::root() . '" title="' . Text::_('NR_VIDEO_PREVIEW_VIDEO') . '"></div>';
}
}

View File

@ -0,0 +1,97 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNR_Time extends NRFormField
{
/**
* Sets the time value
*
* @var string $time_value
*/
private $time_value = null;
/**
* Method to get the field input markup.
*
* @return string The field input markup.
*/
public function getInput()
{
// Setup properties
$this->hint = $this->get('hint', '00:00');
$this->class = $this->get('class');
$this->default = $this->get('default', 'now');
$this->required = $this->get('required') === 'true';
$placement = $this->get('placement', 'top');
$align = $this->get('align', 'left');
$autoclose = $this->get('autoclose', 'true');
$donetext = $this->get('donetext', 'Done');
/**
* When an object is created using this class, it cannot set $this->value
* So we set $time_value and then use it's value to display the time
*/
$this->value = $this->time_value ? $this->time_value : $this->value;
$this->value = is_null($this->value) ? '' : $this->value;
// Add styles and scripts to DOM
HTMLHelper::_('jquery.framework');
HTMLHelper::script('plg_system_nrframework/vendor/jquery-clockpicker.min.js', ['relative' => true, 'version' => true]);
HTMLHelper::stylesheet('plg_system_nrframework/vendor/jquery-clockpicker.min.css', ['relative' => true, 'version' => true]);
static $run;
// Run once to initialize it
if (!$run)
{
$this->doc->addScriptDeclaration('
jQuery(function($) {
$(".clockpicker").clockpicker();
});
');
// Fix a CSS conflict caused by the template.css on Joomla 3
if (!defined('nrJ4'))
{
// Fuck you template.css
$this->doc->addStyleDeclaration('
.clockpicker-align-left.popover > .arrow {
left: 25px;
}
');
}
$run = true;
}
return '
<div class="clockpicker" data-donetext="' . $donetext . '" data-default="' . $this->default . '" data-placement="' . $placement . '" data-align="' . $align . '" data-autoclose="' . $autoclose . '">
' . parent::getInput() . '
</div>';
}
/**
* Sets the $time_value of the time when created as an object
* due to not being able to set the $this->value byitself
*
* @param string $value
*
* @return void
*/
public function setValue($value)
{
$this->time_value = $value;
}
}

View File

@ -0,0 +1,165 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
use \NRFramework\HTML;
defined('_JEXEC') or die;
use Joomla\CMS\Form\FormField;
use Joomla\CMS\Factory;
abstract class JFormFieldNRTreeSelect extends FormField
{
/**
* Database object
*
* @var object
*/
public $db;
/**
* Indicates whether the options array should be sorted before render.
*
* @var boolean
*/
protected $sortTree = false;
/**
* Indicates whether the options array should have the levels re-calculated
*
* @var boolean
*/
protected $fixLevels = false;
/**
* Increase the value(ID) of the category by one.
* This happens because we have a parent category "Bussiness Directory" that pushes-in the indentation
* and we reset it by decreasing the value, level and parent.
*
* @var boolean
*/
protected $increaseValue = false;
/**
* Output the HTML for the field
*/
protected function getInput()
{
$this->db = Factory::getDbo();
$options = $this->getOptions();
if ($this->sortTree)
{
$options = $this->sortTreeSelectOptions($options);
}
if ($this->fixLevels)
{
$options = $this->fixLevels($options);
}
if ($this->increaseValue)
{
// Increase by 1 the value(ID) of the category
foreach ($options as $key => $value)
{
$options[$key]->value+=1;
}
}
return HTML::treeselect($options, $this->name, $this->value, $this->id);
}
/**
* Sorts treeselect options
*
* @param array $options
* @param int $parent_id
*
* @return array
*/
protected function sortTreeSelectOptions($options, $parent_id = 0)
{
if (empty($options))
{
return [];
}
$result = [];
$sub_options = array_filter($options, function($option) use($parent_id)
{
return $option->parent == $parent_id;
});
foreach ($sub_options as $option)
{
$result[] = $option;
$result = array_merge($result, $this->sortTreeSelectOptions($options, $option->value));
}
return $result;
}
/**
* Fixes the levels of the categories
*
* @param array $categories
*
* @return array
*/
protected function fixLevels($cats)
{
// new categories
$categories = [];
// get category levels
foreach ($cats as $c)
{
$level = 0;
$parent_id = (int)$c->parent;
while ($parent_id)
{
$level++;
$parent_id = $this->getNextParentId($cats, $parent_id);
}
$c->level = $level;
$categories[] = $c;
}
return $categories;
}
/**
* Returns the next parent id
* Helper method for getCategories
*
* @return int
*/
protected function getNextParentId($categories, $current_pid)
{
foreach($categories as $c)
{
if ((int)$c->value === $current_pid)
{
return (int)$c->parent;
}
}
}
/**
* Get tree options as an Array of objects
* Each object should have the attributes: value, text, parent, level, disable
*
* @return object
*/
abstract protected function getOptions();
}

View File

@ -0,0 +1,53 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
use \NRFramework\HTML;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNR_Users extends NRFormField
{
public $type = 'Users';
protected function getInput()
{
$this->params = $this->element->attributes();
if (!is_array($this->value))
{
$this->value = explode(',', $this->value);
}
$options = $this->getUsers();
$size = (int) $this->get('size', 300);
return HTML::treeselectSimple($options, $this->name, $this->value, $this->id, $size);
}
public function getUsers()
{
$query = $this->db->getQuery(true)
->select('COUNT(u.id)')
->from('#__users AS u')
->where('u.block = 0');
$this->db->setQuery($query);
$total = $this->db->loadResult();
$query->clear('select')
->select('u.name, u.username, u.id')
->order('name');
$this->db->setQuery($query);
$list = $this->db->loadObjectList();
return $this->getOptionsByList($list, array('username', 'id'));
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\Registry\Registry;
require_once __DIR__ . '/componentitems.php';
class JFormFieldVirtueMartComponentItems extends JFormFieldComponentItems
{
public function init()
{
// Get default language
$this->element['table'] = 'virtuemart_products_' . $this->getLanguage();
parent::init();
}
/**
* VirtueMart is using different tables per language. Therefore, we need to use their API to get the default language code
*
* @return string
*/
private function getLanguage($default = 'en_gb')
{
// Silent inclusion.
@include_once JPATH_ADMINISTRATOR . '/components/com_virtuemart/helpers/config.php';
if (!class_exists('VmConfig'))
{
return $default;
}
// Init configuration
VmConfig::loadConfig();
return VmConfig::$jDefLang;
}
protected function getItems()
{
$items = parent::getItems();
// If text is not properly decoded, decode it
$items = array_map(function($item) {
$item->text = html_entity_decode($item->text);
return $item;
}, $items);
return $items;
}
}

View File

@ -0,0 +1,97 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
// No direct access to this file
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
require_once dirname(__DIR__) . '/helpers/field.php';
class JFormFieldNR_Well extends NRFormField
{
/**
* The field type.
*
* @var string
*/
public $type = 'nr_well';
/**
* Layout to render the form field
*
* @var string
*/
protected $renderLayout = 'well';
/**
* Override renderer include path
*
* @return array
*/
protected function getLayoutPaths()
{
return JPATH_PLUGINS . '/system/nrframework/layouts/';
}
/**
* Method to render the input field
*
* @return string
*/
protected function getInput()
{
HTMLHelper::stylesheet('plg_system_nrframework/fields.css', ['relative' => true, 'version' => 'auto']);
$title = $this->get('label');
$description = $this->get('description');
$url = $this->get('url');
$class = $this->get('class');
$start = $this->get('start', 0);
$end = $this->get('end', 0);
$info = $this->get("html", null);
if ($info)
{
$info = str_replace("{{", "<", $info);
$info = str_replace("}}", ">", $info);
}
$html = array();
if ($start || !$end)
{
if ($title)
{
$html[] = '<h4>' . $this->prepareText($title) . '</h4>';
}
if ($description)
{
$html[] = '<div class="well-desc">' . $this->prepareText($description) . $info . '</div>';
}
if ($url)
{
if (defined('nrJ4'))
{
$html[] = '<a class="btn btn-outline-secondary btn-sm wellbtn" target="_blank" href="' . $url . '"><span class="icon-info-circle"></span></a>';
} else
{
$html[] = '<a class="btn btn-secondary wellbtn" target="_blank" href="' . $url . '"><span class="icon-info"></span></a>';
}
}
}
if ($end) {
$html[] = '</div>';
}
return implode('', $html);
}
}