213 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?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();
 | |
| } |