392 lines
7.8 KiB
PHP
392 lines
7.8 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
|
|
*/
|
|
|
|
namespace NRFramework\Widgets;
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
use Joomla\CMS\Factory;
|
|
use Joomla\Registry\Registry;
|
|
|
|
class FAQ extends Widget
|
|
{
|
|
/**
|
|
* Widget default options
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $widget_options = [
|
|
/**
|
|
* FAQ Settings
|
|
*/
|
|
|
|
/**
|
|
* The questions and answers.
|
|
*
|
|
* Format:
|
|
*
|
|
* [
|
|
* [
|
|
* 'question' => 'Question 1',
|
|
* 'answer' => 'Answer 1'
|
|
* ],
|
|
* [
|
|
* 'question' => 'Question 2',
|
|
* 'answer' => 'Answer 2'
|
|
* ],
|
|
* ]
|
|
*/
|
|
'value' => '',
|
|
|
|
/**
|
|
* Requires "show_toggle_icon" to be enabled to work.
|
|
*
|
|
* Define the initial state of the FAQ.
|
|
*
|
|
* Available values:
|
|
*
|
|
* - first-open: Open the first question
|
|
* - all-open: Opens all questions
|
|
* - all-closed: Closes all questions
|
|
*/
|
|
'initial_state' => 'first-open',
|
|
|
|
// Set whether to have one question open at a time
|
|
'keep_one_question_open' => true,
|
|
|
|
// Set the columns.
|
|
'columns' => 1,
|
|
|
|
// Set the gap between the items.
|
|
'item_gap' => 16,
|
|
|
|
// Set the gap between the columns.
|
|
'column_gap' => 16,
|
|
|
|
// Set whether to display a separator between items
|
|
'separator' => false,
|
|
|
|
// Set the separator color
|
|
'separator_color' => '',
|
|
|
|
/**
|
|
* Item Settings
|
|
*/
|
|
// Each item background color.
|
|
'item_background_color' => null,
|
|
|
|
// Each item border radius.
|
|
'item_border_radius' => null,
|
|
|
|
// Each item padding.
|
|
'item_padding' => null,
|
|
|
|
/**
|
|
* Question
|
|
*/
|
|
// Question font size
|
|
'question_font_size' => null,
|
|
|
|
// Each question text color.
|
|
'question_text_color' => null,
|
|
|
|
/**
|
|
* Answer
|
|
*/
|
|
// Answer font size
|
|
'answer_font_size' => null,
|
|
|
|
// Each answer text color.
|
|
'answer_text_color' => null,
|
|
|
|
/**
|
|
* Icon Settings
|
|
*/
|
|
/**
|
|
* Whether to show an icon that can toggle the open/close state of the answer.
|
|
*
|
|
* If disabled, all answers will appear by default.
|
|
* If enabled, all answers will be hidden by default.
|
|
*/
|
|
'show_toggle_icon' => false,
|
|
|
|
/**
|
|
* Set the icon that will be used.
|
|
*
|
|
* Available values:
|
|
* - arrow
|
|
* - plus_minus
|
|
* - circle_arrow
|
|
* - circle_plus_minus
|
|
*/
|
|
'icon' => 'arrow',
|
|
|
|
/**
|
|
* Set the icon position.
|
|
*
|
|
* Available values:
|
|
*
|
|
* - right
|
|
* - left
|
|
*/
|
|
'icon_position' => 'right',
|
|
|
|
/**
|
|
* FAQ Schema
|
|
*/
|
|
// Set whether to generate the FAQ Schema on the page.
|
|
'generate_faq' => false,
|
|
|
|
// Custom Item CSS Classes
|
|
'item_css_class' => ''
|
|
];
|
|
|
|
/**
|
|
* Class constructor
|
|
*
|
|
* @param array $options
|
|
*/
|
|
public function __construct($options = [])
|
|
{
|
|
parent::__construct($options);
|
|
|
|
$this->prepare();
|
|
}
|
|
|
|
/**
|
|
* Prepares the FAQ.
|
|
*
|
|
* @return void
|
|
*/
|
|
private function prepare()
|
|
{
|
|
if ($this->options['show_toggle_icon'])
|
|
{
|
|
$this->options['show_toggle_icon'] = true;
|
|
$this->options['css_class'] .= ' has-icons';
|
|
$this->options['css_class'] .= ' position-icon-' . $this->options['icon_position'];
|
|
$this->options['css_class'] .= ' has-icon-' . $this->options['icon'];
|
|
}
|
|
|
|
if (!empty($this->options['item_background_color']) && $this->options['item_background_color'] !== 'none')
|
|
{
|
|
$this->options['css_class'] .= ' has-item-bg-color';
|
|
}
|
|
|
|
if ($this->options['separator'])
|
|
{
|
|
$this->options['css_class'] .= ' has-separator';
|
|
}
|
|
|
|
$this->options['css_class'] .= ' ' . $this->options['initial_state'];
|
|
|
|
if ($this->options['keep_one_question_open'])
|
|
{
|
|
$this->options['css_class'] .= ' keep-one-question-open';
|
|
}
|
|
|
|
if ((int) $this->options['columns'] > 1)
|
|
{
|
|
$this->options['css_class'] .= ' has-columns';
|
|
}
|
|
|
|
$this->generateFAQ();
|
|
|
|
if ($this->options['load_css_vars'])
|
|
{
|
|
$this->options['custom_css'] = $this->getWidgetCSS();
|
|
}
|
|
}
|
|
|
|
private function generateFAQ()
|
|
{
|
|
// Ensure "generate_faq" is enabled
|
|
if (!$this->options['generate_faq'])
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Ensure we have questions and answers
|
|
if (!is_array($this->options['value']) && !count($this->options['value']))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Abort if FAQ cannot be compiled
|
|
if (!$faq = $this->getFAQ())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Hook into GSD to add the FAQ
|
|
Factory::getApplication()->registerEvent('onGSDBeforeRender', function(&$data) use ($faq)
|
|
{
|
|
try
|
|
{
|
|
// get the data
|
|
$tmpData = $data;
|
|
if (defined('nrJ4'))
|
|
{
|
|
$tmpData = $data->getArgument('0');
|
|
}
|
|
|
|
// Append the FAQ Schema
|
|
$tmpData[] = $faq;
|
|
|
|
// Ensure unique FAQ
|
|
$tmpData = array_unique($tmpData);
|
|
|
|
// Set back the new value to $data object
|
|
if (defined('nrJ4'))
|
|
{
|
|
$data->setArgument(0, $tmpData);
|
|
}
|
|
else
|
|
{
|
|
$data = $tmpData;
|
|
}
|
|
|
|
} catch (\Throwable $th)
|
|
{
|
|
$this->throwError($th->getMessage());
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Returns the FAQ JSON/LD code.
|
|
*
|
|
* @return string
|
|
*/
|
|
private function getFAQ()
|
|
{
|
|
$autoload_file = JPATH_ADMINISTRATOR . '/components/com_gsd/autoload.php';
|
|
if (!file_exists($autoload_file))
|
|
{
|
|
return;
|
|
}
|
|
|
|
require_once $autoload_file;
|
|
|
|
// Prepare the FAQ
|
|
$payload = [
|
|
'mode' => 'manual',
|
|
'faq_repeater_fields' => json_decode(json_encode($this->options['value']))
|
|
];
|
|
$payload = new Registry($payload);
|
|
$faq = new \GSD\Schemas\Schemas\FAQ($payload);
|
|
|
|
// Get the JSON/LD code of the FAQ
|
|
$json = new \GSD\Json($faq->get());
|
|
|
|
// Return the code
|
|
return $json->generate();
|
|
}
|
|
|
|
/**
|
|
* Returns the CSS for the widget.
|
|
*
|
|
* @param array $exclude_breakpoints Define breakpoints to exclude their CSS
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getWidgetCSS($exclude_breakpoints = [])
|
|
{
|
|
$controls = [
|
|
// CSS Variables
|
|
[
|
|
'property' => '--item-background-color',
|
|
'value' => $this->options['item_background_color']
|
|
],
|
|
[
|
|
'property' => '--question-text-color',
|
|
'value' => $this->options['question_text_color']
|
|
],
|
|
[
|
|
'property' => '--answer-text-color',
|
|
'value' => $this->options['answer_text_color']
|
|
],
|
|
[
|
|
'property' => '--separator-color',
|
|
'value' => $this->options['separator_color']
|
|
],
|
|
|
|
// CSS
|
|
[
|
|
'property' => '--item-padding',
|
|
'type' => 'Spacing',
|
|
'value' => $this->options['item_padding'],
|
|
'unit' => 'px'
|
|
],
|
|
[
|
|
'property' => '--item-gap',
|
|
'value' => $this->options['item_gap'],
|
|
'unit' => 'px'
|
|
],
|
|
[
|
|
'property' => '--column-gap',
|
|
'value' => $this->options['column_gap'],
|
|
'unit' => 'px'
|
|
],
|
|
[
|
|
'property' => '--item-border-radius',
|
|
'type' => 'Spacing',
|
|
'value' => $this->options['item_border_radius'],
|
|
'unit' => 'px'
|
|
],
|
|
[
|
|
'property' => '--question-font-size',
|
|
'value' => $this->options['question_font_size'],
|
|
'unit' => 'px'
|
|
],
|
|
[
|
|
'property' => '--answer-font-size',
|
|
'value' => $this->options['answer_font_size'],
|
|
'unit' => 'px'
|
|
],
|
|
];
|
|
|
|
$selector = '.tf-faq-widget.' . $this->options['id'];
|
|
|
|
$controlsInstance = new \NRFramework\Controls\Controls(null, $selector, $exclude_breakpoints);
|
|
|
|
if (!$controlsCSS = $controlsInstance->generateCSS($controls))
|
|
{
|
|
return;
|
|
}
|
|
|
|
return $controlsCSS;
|
|
}
|
|
|
|
/**
|
|
* Returns all CSS files.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function getCSS()
|
|
{
|
|
return [
|
|
'plg_system_nrframework/widgets/faq.css'
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Returns all JS files.
|
|
*
|
|
* @param string $theme
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function getJS()
|
|
{
|
|
return [
|
|
'plg_system_nrframework/widgets/faq.js'
|
|
];
|
|
}
|
|
} |