first commit

This commit is contained in:
2025-06-17 11:53:18 +02:00
commit 9f0f7ba12b
8804 changed files with 1369176 additions and 0 deletions

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<access component="com_mails">
<section name="component">
<action name="core.admin" title="JACTION_ADMIN" />
</section>
</access>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
<help key="Mail_Templates:_Options"/>
<inlinehelp button="show"/>
<fieldset
name="mails_options"
label="COM_MAILS_CONFIG_MAIL_OPTIONS" >
<field
name="mail_style"
type="list"
label="COM_MAILS_FIELD_MAIL_STYLE_LABEL"
default="plaintext"
validate="options"
>
<option value="plaintext">COM_MAILS_FIELD_OPTION_PLAINTEXT</option>
<option value="html">COM_MAILS_FIELD_OPTION_HTML</option>
<option value="both">COM_MAILS_FIELD_OPTION_BOTH</option>
</field>
<field
name="alternative_mailconfig"
type="radio"
label="COM_MAILS_CONFIG_FIELD_ALTERNATIVE_MAILCONFIG_LABEL"
layout="joomla.form.field.radio.switcher"
default="0"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="copy_mails"
type="radio"
label="COM_MAILS_CONFIG_FIELD_COPY_MAILS_LABEL"
layout="joomla.form.field.radio.switcher"
default="0"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="attachment_folder"
type="text"
label="COM_MAILS_CONFIG_FIELD_ATTACHMENT_FOLDER_LABEL"
description="COM_MAILS_CONFIG_FIELD_ATTACHMENT_FOLDER_DESC"
validate="folderPathExists"
exclude="administrator|api|cache|cli|components|includes|language|layouts|libraries|modules|plugins|templates|tmp"
/>
</fieldset>
<fieldset
name="permissions"
label="JCONFIG_PERMISSIONS_LABEL"
>
<field
name="rules"
type="rules"
label="JCONFIG_PERMISSIONS_LABEL"
filter="rules"
validate="rules"
component="com_mails"
section="component"
/>
</fieldset>
</config>

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fields name="filter">
<field
name="search"
type="text"
inputmode="search"
label="COM_MAILS_FILTER_SEARCH_LABEL"
description="COM_MAILS_FILTER_SEARCH_DESC"
hint="JSEARCH_FILTER"
/>
<field
name="language"
type="contentlanguage"
label="JGRID_HEADING_LANGUAGE"
class="js-select-submit-on-change"
>
<option value="">JOPTION_SELECT_LANGUAGE</option>
</field>
<field
name="extension"
type="sql"
label="COM_MAILS_HEADING_EXTENSION"
query="SELECT DISTINCT extension FROM #__mail_templates WHERE extension IN (SELECT name FROM #__extensions WHERE enabled = 1) ORDER BY extension ASC"
key_field="extension"
value_field="extension"
translate="true"
class="js-select-submit-on-change"
>
<option value="">COM_MAILS_FILTER_OPTION_SELECT_EXTENSION</option>
</field>
</fields>
<fields name="list">
<field
name="fullordering"
type="list"
label="JGLOBAL_SORT_BY"
class="js-select-submit-on-change"
default="a.template_id ASC"
validate="options"
>
<option value="">JGLOBAL_SORT_BY</option>
<option value="a.template_id ASC">JGRID_HEADING_ID_ASC</option>
<option value="a.template_id DESC">JGRID_HEADING_ID_DESC</option>
</field>
<field
name="limit"
type="limitbox"
label="JGLOBAL_LIST_LIMIT"
default="25"
class="js-select-submit-on-change"
/>
</fields>
</form>

View File

@ -0,0 +1,210 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fieldset>
<field
name="template_id"
type="hidden"
/>
<field
name="language"
type="hidden"
/>
<field
name="subject"
type="text"
label="COM_MAILS_FIELD_SUBJECT_LABEL"
/>
<field
name="body"
type="editor"
label="COM_MAILS_FIELD_BODY_LABEL"
editor="none"
buttons="false"
rows="20"
class="form-control"
filter="\Joomla\CMS\Component\ComponentHelper::filterText"
/>
<field
name="htmlbody"
type="editor"
label="COM_MAILS_FIELD_HTMLBODY_LABEL"
buttons="true"
hide="fields,pagebreak,readmore,module"
class="inputbox"
filter="\Joomla\CMS\Component\ComponentHelper::filterText"
/>
</fieldset>
<field
name="attachments"
type="subform"
label="COM_MAILS_FIELD_ATTACHMENTS_LABEL"
multiple="true"
layout="joomla.form.field.subform.repeatable-table"
>
<form>
<field
name="file"
type="filelist"
hide_default="true"
label="COM_MAILS_FIELD_FILE_LABEL"
validate="options"
/>
<field
name="name"
type="text"
label="COM_MAILS_FIELD_FILENAME_LABEL"
/>
</form>
</field>
<fields name="params" label="COM_MAILS_FIELD_BASIC_LABEL">
<fieldset name="basic">
<field
name="alternative_mailconfig"
type="radio"
label="COM_MAILS_FIELD_ALTERNATIVE_MAILCONFIG_LABEL"
layout="joomla.form.field.radio.switcher"
default="0"
filter="boolean"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="mailfrom"
type="email"
label="COM_MAILS_FIELD_MAIL_FROM_EMAIL_LABEL"
filter="string"
validate="email"
showon="alternative_mailconfig:1"
/>
<field
name="fromname"
type="text"
label="COM_MAILS_FIELD_MAIL_FROM_NAME_LABEL"
filter="string"
showon="alternative_mailconfig:1"
/>
<field
name="replyto"
type="email"
label="COM_MAILS_FIELD_MAIL_REPLY_TO_EMAIL_LABEL"
filter="string"
validate="email"
showon="alternative_mailconfig:1"
/>
<field
name="replytoname"
type="text"
label="COM_MAILS_FIELD_MAIL_REPLY_TO_NAME_LABEL"
filter="string"
showon="alternative_mailconfig:1"
/>
<field
name="mailer"
type="list"
label="COM_MAILS_FIELD_MAIL_MAILER_LABEL"
default="mail"
filter="word"
showon="alternative_mailconfig:1"
validate="options"
>
<option value="mail">COM_MAILS_FIELD_VALUE_PHP_MAIL</option>
<option value="sendmail">COM_MAILS_FIELD_VALUE_SENDMAIL</option>
<option value="smtp">COM_MAILS_FIELD_VALUE_SMTP</option>
</field>
<field
name="sendmail"
type="text"
label="COM_MAILS_FIELD_MAIL_SENDMAIL_PATH_LABEL"
default="/usr/sbin/sendmail"
showon="alternative_mailconfig:1[AND]mailer:sendmail"
filter="string"
/>
<field
name="smtphost"
type="text"
label="COM_MAILS_FIELD_MAIL_SMTP_HOST_LABEL"
default="localhost"
showon="alternative_mailconfig:1[AND]mailer:smtp"
filter="string"
/>
<field
name="smtpport"
type="number"
label="COM_MAILS_FIELD_MAIL_SMTP_PORT_LABEL"
showon="alternative_mailconfig:1[AND]mailer:smtp"
min="1"
max="65535"
default="25"
hint="25"
validate="number"
filter="integer"
/>
<field
name="smtpsecure"
type="list"
label="COM_MAILS_FIELD_MAIL_SMTP_SECURE_LABEL"
default="none"
showon="alternative_mailconfig:1[AND]mailer:smtp"
filter="word"
validate="options"
>
<option value="none">COM_MAILS_FIELD_VALUE_NONE</option>
<option value="ssl">COM_MAILS_FIELD_VALUE_SSL</option>
<option value="tls">COM_MAILS_FIELD_VALUE_TLS</option>
</field>
<field
name="smtpauth"
type="radio"
label="COM_MAILS_FIELD_MAIL_SMTP_AUTH_LABEL"
layout="joomla.form.field.radio.switcher"
default="0"
showon="alternative_mailconfig:1[AND]mailer:smtp"
filter="boolean"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="smtpuser"
type="text"
label="COM_MAILS_FIELD_MAIL_SMTP_USERNAME_LABEL"
showon="alternative_mailconfig:1[AND]mailer:smtp[AND]smtpauth:1"
filter="string"
autocomplete="off"
/>
<field
name="smtppass"
type="password"
label="COM_MAILS_FIELD_MAIL_SMTP_PASSWORD_LABEL"
showon="alternative_mailconfig:1[AND]mailer:smtp[AND]smtpauth:1"
filter="raw"
autocomplete="off"
lock="true"
/>
<field
name="copyto"
type="email"
label="COM_MAILS_FIELD_MAIL_COPY_MAIL_LABEL"
validate="email"
default=""
filter="string"
/>
</fieldset>
</fields>
</form>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="component" method="upgrade">
<name>com_mails</name>
<author>Joomla! Project</author>
<creationDate>2019-01</creationDate>
<copyright>(C) 2019 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>4.0.0</version>
<description>COM_MAILS_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Component\Mails</namespace>
<administration>
<files folder="admin">
<filename>access.xml</filename>
<filename>config.xml</filename>
<filename>mails.xml</filename>
<folder>forms</folder>
<folder>services</folder>
<folder>src</folder>
<folder>tmpl</folder>
</files>
<languages folder="admin">
<language tag="en-GB">language/en-GB/com_mails.ini</language>
<language tag="en-GB">language/en-GB/com_mails.sys.ini</language>
</languages>
</administration>
</extension>

View File

@ -0,0 +1,53 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
use Joomla\CMS\Extension\ComponentInterface;
use Joomla\CMS\Extension\MVCComponent;
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
use Joomla\CMS\Extension\Service\Provider\MVCFactory;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
/**
* The config service provider.
*
* @since 4.0.0
*/
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.0.0
*/
public function register(Container $container)
{
$container->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\Mails'));
$container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\Mails'));
$container->set(
ComponentInterface::class,
function (Container $container) {
$component = new MVCComponent($container->get(ComponentDispatcherFactoryInterface::class));
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
return $component;
}
);
}
};

View File

@ -0,0 +1,64 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Mails\Administrator\Controller;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Router\Route;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Mail templates Controller
*
* @since 4.0.0
*/
class DisplayController extends BaseController
{
/**
* The default view.
*
* @var string
* @since 4.0.0
*/
protected $default_view = 'templates';
/**
* Method to display a view.
*
* @param boolean $cachable If true, the view output will be cached
* @param array $urlparams An array of safe URL parameters and their variable types.
* @see \Joomla\CMS\Filter\InputFilter::clean() for valid values.
*
* @return BaseController|boolean This object to support chaining.
*
* @since 4.0.0
*/
public function display($cachable = false, $urlparams = [])
{
$view = $this->input->get('view', 'templates');
$layout = $this->input->get('layout', '');
$id = $this->input->getString('template_id');
// Check for edit form.
if ($view == 'template' && $layout == 'edit' && !$this->checkEditId('com_mails.edit.template', $id)) {
// Somehow the person just went to the form - we don't allow that.
$this->setMessage(Text::sprintf('COM_MAILS_ERROR_UNHELD_ID', $id), 'error');
$this->setRedirect(Route::_('index.php?option=com_mails&view=templates', false));
return false;
}
return parent::display();
}
}

View File

@ -0,0 +1,303 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Mails\Administrator\Controller;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Event\Model;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\FormController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;
use Joomla\Input\Input;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The template controller
*
* @since 4.0.0
*/
class TemplateController extends FormController
{
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
* Recognized key values include 'name', 'default_task', 'model_path', and
* 'view_path' (this list is not meant to be comprehensive).
* @param MVCFactoryInterface $factory The factory.
* @param CMSApplication $app The Application for the dispatcher
* @param Input $input Input
*
* @since 4.0.0
* @throws \Exception
*/
public function __construct($config = [], MVCFactoryInterface $factory = null, $app = null, $input = null)
{
parent::__construct($config, $factory, $app, $input);
$this->view_item = 'template';
$this->view_list = 'templates';
}
/**
* Method to check if you can add a new record.
*
* @param array $data An array of input data.
*
* @return boolean
*
* @since 4.0.0
*/
protected function allowAdd($data = [])
{
return false;
}
/**
* Method to edit an existing record.
*
* @param string $key The name of the primary key of the URL variable.
* @param string $urlVar The name of the URL variable if different from the primary key
* (sometimes required to avoid router collisions).
*
* @return boolean True if access level check and checkout passes, false otherwise.
*
* @since 4.0.0
*/
public function edit($key = null, $urlVar = null)
{
// Do not cache the response to this, its a redirect, and mod_expires and google chrome browser bugs cache it forever!
$this->app->allowCache(false);
$context = "$this->option.edit.$this->context";
// Get the previous record id (if any) and the current record id.
$template_id = $this->input->getCmd('template_id');
$language = $this->input->getCmd('language');
// Access check.
if (!$this->allowEdit(['template_id' => $template_id, 'language' => $language], $template_id)) {
$this->setMessage(Text::_('JLIB_APPLICATION_ERROR_EDIT_NOT_PERMITTED'), 'error');
$this->setRedirect(
Route::_(
'index.php?option=' . $this->option . '&view=' . $this->view_list
. $this->getRedirectToListAppend(),
false
)
);
return false;
}
// Check-out succeeded, push the new record id into the session.
$this->holdEditId($context, $template_id . '.' . $language);
$this->app->setUserState($context . '.data', null);
$this->setRedirect(
Route::_(
'index.php?option=' . $this->option . '&view=' . $this->view_item
. $this->getRedirectToItemAppend([$template_id, $language], 'template_id'),
false
)
);
return true;
}
/**
* Gets the URL arguments to append to an item redirect.
*
* @param string[] $recordId The primary key id for the item in the first element and the language of the
* mail template in the second key.
* @param string $urlVar The name of the URL variable for the id.
*
* @return string The arguments to append to the redirect URL.
*
* @since 4.0.0
*/
protected function getRedirectToItemAppend($recordId = null, $urlVar = 'id')
{
$language = array_pop($recordId);
$return = parent::getRedirectToItemAppend(array_pop($recordId), $urlVar);
$return .= '&language=' . $language;
return $return;
}
/**
* Method to save a record.
*
* @param string $key The name of the primary key of the URL variable.
* @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions).
*
* @return boolean True if successful, false otherwise.
*
* @since 4.0.0
*/
public function save($key = null, $urlVar = null)
{
// Check for request forgeries.
$this->checkToken();
/** @var \Joomla\CMS\MVC\Model\AdminModel $model */
$model = $this->getModel();
$data = $this->input->post->get('jform', [], 'array');
$context = "$this->option.edit.$this->context";
$task = $this->getTask();
$recordId = $this->input->getCmd('template_id');
$language = $this->input->getCmd('language');
// Populate the row id from the session.
$data['template_id'] = $recordId;
$data['language'] = $language;
// Access check.
if (!$this->allowSave($data, 'template_id')) {
$this->setMessage(Text::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'), 'error');
$this->setRedirect(
Route::_(
'index.php?option=' . $this->option . '&view=' . $this->view_list
. $this->getRedirectToListAppend(),
false
)
);
return false;
}
// Validate the posted data.
// Sometimes the form needs some posted data, such as for plugins and modules.
$form = $model->getForm($data, false);
if (!$form) {
$this->app->enqueueMessage($model->getError(), 'error');
return false;
}
// Send an object which can be modified through the plugin event
$objData = (object) $data;
$this->getDispatcher()->dispatch(
'onContentNormaliseRequestData',
new Model\NormaliseRequestDataEvent('onContentNormaliseRequestData', [
'context' => $this->option . '.' . $this->context,
'data' => $objData,
'subject' => $form,
])
);
$data = (array) $objData;
// Test whether the data is valid.
$validData = $model->validate($form, $data);
// Check for validation errors.
if ($validData === false) {
// Get the validation messages.
$errors = $model->getErrors();
// Push up to three validation messages out to the user.
for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof \Exception) {
$this->app->enqueueMessage($errors[$i]->getMessage(), 'warning');
} else {
$this->app->enqueueMessage($errors[$i], 'warning');
}
}
// Save the data in the session.
$this->app->setUserState($context . '.data', $data);
// Redirect back to the edit screen.
$this->setRedirect(
Route::_(
'index.php?option=' . $this->option . '&view=' . $this->view_item
. $this->getRedirectToItemAppend([$recordId, $language], 'template_id'),
false
)
);
return false;
}
// Attempt to save the data.
if (!$model->save($validData)) {
// Save the data in the session.
$this->app->setUserState($context . '.data', $validData);
// Redirect back to the edit screen.
$this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()), 'error');
$this->setRedirect(
Route::_(
'index.php?option=' . $this->option . '&view=' . $this->view_item
. $this->getRedirectToItemAppend([$recordId, $language], 'template_id'),
false
)
);
return false;
}
$langKey = $this->text_prefix . ($recordId === 0 && $this->app->isClient('site') ? '_SUBMIT' : '') . '_SAVE_SUCCESS';
$prefix = $this->app->getLanguage()->hasKey($langKey) ? $this->text_prefix : 'COM_MAILS';
$this->setMessage(Text::_($prefix . ($recordId === 0 && $this->app->isClient('site') ? '_SUBMIT' : '') . '_SAVE_SUCCESS'));
// Redirect the user and adjust session state based on the chosen task.
switch ($task) {
case 'apply':
// Set the record data in the session.
$this->holdEditId($context, $recordId);
$this->app->setUserState($context . '.data', null);
// Redirect back to the edit screen.
$this->setRedirect(
Route::_(
'index.php?option=' . $this->option . '&view=' . $this->view_item
. $this->getRedirectToItemAppend([$recordId, $language], 'template_id'),
false
)
);
break;
default:
// Clear the record id and data from the session.
$this->releaseEditId($context, $recordId);
$this->app->setUserState($context . '.data', null);
$url = 'index.php?option=' . $this->option . '&view=' . $this->view_list
. $this->getRedirectToListAppend();
// Check if there is a return value
$return = $this->input->get('return', null, 'base64');
if (!\is_null($return) && Uri::isInternal(base64_decode($return))) {
$url = base64_decode($return);
}
// Redirect to the list screen.
$this->setRedirect(Route::_($url, false));
break;
}
// Invoke the postSave method to allow for the child class to access the model.
$this->postSaveHook($model, $validData);
return true;
}
}

View File

@ -0,0 +1,109 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Mails\Administrator\Helper;
use Joomla\CMS\Factory;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Mailtags HTML helper class.
*
* @since 4.0.0
*/
abstract class MailsHelper
{
/**
* Display a clickable list of tags for a mail template
*
* @param object $mail Row of the mail template.
* @param string $fieldname Name of the target field.
*
* @return string List of tags that can be inserted into a field.
*
* @since 4.0.0
*/
public static function mailtags($mail, $fieldname)
{
Factory::getApplication()->triggerEvent('onMailBeforeTagsRendering', [$mail->template_id, &$mail]);
if (!isset($mail->params['tags']) || !\count($mail->params['tags'])) {
return '';
}
$html = '<ul class="list-group">';
foreach ($mail->params['tags'] as $tag) {
$html .= '<li class="list-group-item">'
. '<a href="#" class="edit-action-add-tag" data-tag="{' . strtoupper($tag) . '}" data-target="' . $fieldname . '"'
. ' title="' . $tag . '">' . $tag . '</a>'
. '</li>';
}
$html .= '</ul>';
return $html;
}
/**
* Load the translation files for an extension
*
* @param string $extension Extension name
*
* @return void
*
* @since 4.0.0
*/
public static function loadTranslationFiles($extension)
{
static $cache = [];
$extension = strtolower($extension);
if (isset($cache[$extension])) {
return;
}
$lang = Factory::getLanguage();
$source = '';
switch (substr($extension, 0, 3)) {
case 'com':
default:
$source = JPATH_ADMINISTRATOR . '/components/' . $extension;
break;
case 'mod':
$source = JPATH_SITE . '/modules/' . $extension;
break;
case 'plg':
$parts = explode('_', $extension, 3);
if (\count($parts) > 2) {
$source = JPATH_PLUGINS . '/' . $parts[1] . '/' . $parts[2];
}
break;
}
$lang->load($extension, JPATH_ADMINISTRATOR)
|| $lang->load($extension, $source);
if (!$lang->hasKey(strtoupper($extension))) {
$lang->load($extension . '.sys', JPATH_ADMINISTRATOR)
|| $lang->load($extension . '.sys', $source);
}
$cache[$extension] = true;
}
}

View File

@ -0,0 +1,407 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Mails\Administrator\Model;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\AdminModel;
use Joomla\CMS\Object\CMSObject;
use Joomla\CMS\Table\Table;
use Joomla\Filesystem\Path;
use Joomla\Registry\Registry;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Item Model for a Mail template.
*
* @since 4.0.0
*/
class TemplateModel extends AdminModel
{
/**
* The prefix to use with controller messages.
*
* @var string
* @since 4.0.0
*/
protected $text_prefix = 'COM_MAILS';
/**
* The type alias for this content type (for example, 'com_content.article').
*
* @var string
* @since 4.0.0
*/
public $typeAlias = 'com_mails.template';
/**
* Method to test whether a record can be deleted.
*
* @param object $record A record object.
*
* @return boolean True if allowed to delete the record. Defaults to the permission set in the component.
*
* @since 4.0.0
*/
protected function canDelete($record)
{
return false;
}
/**
* Method to get the record form.
*
* @param array $data An optional array of data for the form to interrogate.
* @param boolean $loadData True if the form is to load its own data (default case), false if not.
*
* @return \Joomla\CMS\Form\Form|bool A JForm object on success, false on failure
*
* @since 4.0.0
*/
public function getForm($data = [], $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_mails.template', 'template', ['control' => 'jform', 'load_data' => $loadData]);
if (empty($form)) {
return false;
}
$params = ComponentHelper::getParams('com_mails');
if ($params->get('mail_style', 'plaintext') == 'plaintext') {
$form->removeField('htmlbody');
}
if ($params->get('mail_style', 'plaintext') == 'html') {
$form->removeField('body');
}
if (!$params->get('alternative_mailconfig', '0')) {
$form->removeField('alternative_mailconfig', 'params');
$form->removeField('mailfrom', 'params');
$form->removeField('fromname', 'params');
$form->removeField('replyto', 'params');
$form->removeField('replytoname', 'params');
$form->removeField('mailer', 'params');
$form->removeField('sendmail', 'params');
$form->removeField('smtphost', 'params');
$form->removeField('smtpport', 'params');
$form->removeField('smtpsecure', 'params');
$form->removeField('smtpauth', 'params');
$form->removeField('smtpuser', 'params');
$form->removeField('smtppass', 'params');
}
if (!$params->get('copy_mails')) {
$form->removeField('copyto', 'params');
}
if (!trim($params->get('attachment_folder', ''))) {
$form->removeField('attachments');
return $form;
}
try {
$attachmentPath = rtrim(Path::check(JPATH_ROOT . '/' . $params->get('attachment_folder')), \DIRECTORY_SEPARATOR);
} catch (\Exception $e) {
$attachmentPath = '';
}
if (!$attachmentPath || $attachmentPath === Path::clean(JPATH_ROOT) || !is_dir($attachmentPath)) {
$form->removeField('attachments');
return $form;
}
$field = $form->getField('attachments');
$subform = new \SimpleXMLElement($field->formsource);
$files = $subform->xpath('field[@name="file"]');
$files[0]->addAttribute('directory', $attachmentPath);
$form->load('<form><field name="attachments" type="subform" '
. 'label="COM_MAILS_FIELD_ATTACHMENTS_LABEL" multiple="true" '
. 'layout="joomla.form.field.subform.repeatable-table">'
. str_replace('<?xml version="1.0"?>', '', $subform->asXML())
. '</field></form>');
return $form;
}
/**
* Method to get a single record.
*
* @param integer $pk The id of the primary key.
*
* @return CMSObject|boolean Object on success, false on failure.
*
* @since 4.0.0
*/
public function getItem($pk = null)
{
$templateId = $this->getState($this->getName() . '.template_id');
$language = $this->getState($this->getName() . '.language');
$table = $this->getTable('Template', 'Table');
if ($templateId != '' && $language != '') {
// Attempt to load the row.
$return = $table->load(['template_id' => $templateId, 'language' => $language]);
// Check for a table object error.
if ($return === false && $table->getError()) {
$this->setError($table->getError());
return false;
}
}
// Convert to the CMSObject before adding other data.
$properties = $table->getProperties(1);
$item = ArrayHelper::toObject($properties, CMSObject::class);
if (property_exists($item, 'params')) {
$registry = new Registry($item->params);
$item->params = $registry->toArray();
}
if (!$item->template_id) {
$item->template_id = $templateId;
}
if (!$item->language) {
$item->language = $language;
}
return $item;
}
/**
* Get the master data for a mail template.
*
* @param integer $pk The id of the primary key.
*
* @return CMSObject|boolean Object on success, false on failure.
*
* @since 4.0.0
*/
public function getMaster($pk = null)
{
$template_id = $this->getState($this->getName() . '.template_id');
$table = $this->getTable('Template', 'Table');
if ($template_id != '') {
// Attempt to load the row.
$return = $table->load(['template_id' => $template_id, 'language' => '']);
// Check for a table object error.
if ($return === false && $table->getError()) {
$this->setError($table->getError());
return false;
}
}
// Convert to the CMSObject before adding other data.
$properties = $table->getProperties(1);
$item = ArrayHelper::toObject($properties, CMSObject::class);
if (property_exists($item, 'params')) {
$registry = new Registry($item->params);
$item->params = $registry->toArray();
}
return $item;
}
/**
* Method to get a table object, load it if necessary.
*
* @param string $name The table name. Optional.
* @param string $prefix The class prefix. Optional.
* @param array $options Configuration array for model. Optional.
*
* @return Table A Table object
*
* @since 4.0.0
* @throws \Exception
*/
public function getTable($name = 'Template', $prefix = 'Administrator', $options = [])
{
return parent::getTable($name, $prefix, $options);
}
/**
* Method to get the data that should be injected in the form.
*
* @return mixed The data for the form.
*
* @since 4.0.0
*/
protected function loadFormData()
{
// Check the session for previously entered form data.
$app = Factory::getApplication();
$data = $app->getUserState('com_mails.edit.template.data', []);
if (empty($data)) {
$data = $this->getItem();
}
$this->preprocessData('com_mails.template', $data);
return $data;
}
/**
* Method to validate the form data.
*
* @param Form $form The form to validate against.
* @param array $data The data to validate.
* @param string $group The name of the field group to validate.
*
* @return array|boolean Array of filtered data if valid, false otherwise.
*
* @since 4.0.0
*/
public function validate($form, $data, $group = null)
{
$validLanguages = LanguageHelper::getContentLanguages([0, 1]);
if (!\array_key_exists($data['language'], $validLanguages)) {
$this->setError(Text::_('COM_MAILS_FIELD_LANGUAGE_CODE_INVALID'));
return false;
}
return parent::validate($form, $data, $group);
}
/**
* Method to save the form data.
*
* @param array $data The form data.
*
* @return boolean True on success, False on error.
*
* @since 4.0.0
*/
public function save($data)
{
$table = $this->getTable();
$context = $this->option . '.' . $this->name;
$key = $table->getKeyName();
$template_id = (!empty($data['template_id'])) ? $data['template_id'] : $this->getState($this->getName() . '.template_id');
$language = (!empty($data['language'])) ? $data['language'] : $this->getState($this->getName() . '.language');
$isNew = true;
// Include the plugins for the save events.
\Joomla\CMS\Plugin\PluginHelper::importPlugin($this->events_map['save']);
// Allow an exception to be thrown.
try {
// Load the row if saving an existing record.
$table->load(['template_id' => $template_id, 'language' => $language]);
if ($table->subject) {
$isNew = false;
}
// Load the default row
$table->load(['template_id' => $template_id, 'language' => '']);
// Bind the data.
if (!$table->bind($data)) {
$this->setError($table->getError());
return false;
}
// Prepare the row for saving
$this->prepareTable($table);
// Check the data.
if (!$table->check()) {
$this->setError($table->getError());
return false;
}
// Trigger the before save event.
$result = Factory::getApplication()->triggerEvent($this->event_before_save, [$context, $table, $isNew, $data]);
if (\in_array(false, $result, true)) {
$this->setError($table->getError());
return false;
}
// Store the data.
if (!$table->store()) {
$this->setError($table->getError());
return false;
}
// Clean the cache.
$this->cleanCache();
// Trigger the after save event.
Factory::getApplication()->triggerEvent($this->event_after_save, [$context, $table, $isNew, $data]);
} catch (\Exception $e) {
$this->setError($e->getMessage());
return false;
}
$this->setState($this->getName() . '.new', $isNew);
return true;
}
/**
* Prepare and sanitise the table data prior to saving.
*
* @param Table $table A reference to a Table object.
*
* @return void
*
* @since 4.0.0
*/
protected function prepareTable($table)
{
}
/**
* Stock method to auto-populate the model state.
*
* @return void
*
* @since 4.0.0
*/
protected function populateState()
{
parent::populateState();
$template_id = Factory::getApplication()->getInput()->getCmd('template_id');
$this->setState($this->getName() . '.template_id', $template_id);
$language = Factory::getApplication()->getInput()->getCmd('language');
$this->setState($this->getName() . '.language', $language);
}
}

View File

@ -0,0 +1,219 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Mails\Administrator\Model;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\DatabaseQuery;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Methods supporting a list of mail template records.
*
* @since 4.0.0
*/
class TemplatesModel extends ListModel
{
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
*
* @since 4.0.0
* @throws \Exception
*/
public function __construct($config = [])
{
if (empty($config['filter_fields'])) {
$config['filter_fields'] = [
'template_id', 'a.template_id',
'language', 'a.language',
'subject', 'a.subject',
'body', 'a.body',
'htmlbody', 'a.htmlbody',
'extension',
];
}
parent::__construct($config);
}
/**
* Method to auto-populate the model state.
*
* This method should only be called once per instantiation and is designed
* to be called on the first call to the getState() method unless the model
* configuration flag to ignore the request is set.
*
* Note. Calling getState in this method will result in recursion.
*
* @param string $ordering An optional ordering field.
* @param string $direction An optional direction (asc|desc).
*
* @return void
*
* @since 4.0.0
*/
protected function populateState($ordering = null, $direction = null)
{
// Load the parameters.
$params = ComponentHelper::getParams('com_mails');
$this->setState('params', $params);
// List state information.
parent::populateState('a.template_id', 'asc');
}
/**
* Get a list of mail templates
*
* @return array
*
* @since 4.0.0
*/
public function getItems()
{
$items = parent::getItems();
$id = '';
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName('language'))
->from($db->quoteName('#__mail_templates'))
->where($db->quoteName('template_id') . ' = :id')
->where($db->quoteName('language') . ' != ' . $db->quote(''))
->order($db->quoteName('language') . ' ASC')
->bind(':id', $id);
foreach ($items as $item) {
$id = $item->template_id;
$db->setQuery($query);
$item->languages = $db->loadColumn();
}
return $items;
}
/**
* Build an SQL query to load the list data.
*
* @return DatabaseQuery
*
* @since 4.0.0
*/
protected function getListQuery()
{
// Create a new query object.
$db = $this->getDatabase();
$query = $db->getQuery(true);
// Select the required fields from the table.
$query->select(
$this->getState(
'list.select',
$db->quoteName('a') . '.*'
)
);
$query->from($db->quoteName('#__mail_templates', 'a'))
->where($db->quoteName('a.language') . ' = ' . $db->quote(''));
// Filter by search in title.
if ($search = trim($this->getState('filter.search', ''))) {
if (stripos($search, 'id:') === 0) {
$search = substr($search, 3);
$query->where($db->quoteName('a.template_id') . ' = :search')
->bind(':search', $search);
} else {
$search = '%' . str_replace(' ', '%', $search) . '%';
$query->where(
'(' . $db->quoteName('a.template_id') . ' LIKE :search1'
. ' OR ' . $db->quoteName('a.subject') . ' LIKE :search2'
. ' OR ' . $db->quoteName('a.body') . ' LIKE :search3'
. ' OR ' . $db->quoteName('a.htmlbody') . ' LIKE :search4)'
)
->bind([':search1', ':search2', ':search3', ':search4'], $search);
}
}
// Filter on the extension.
if ($extension = $this->getState('filter.extension')) {
$query->where($db->quoteName('a.extension') . ' = :extension')
->bind(':extension', $extension);
} else {
// Only show mail template from enabled extensions
$subQuery = $db->getQuery(true)
->select($db->quoteName('name'))
->from($db->quoteName('#__extensions'))
->where($db->quoteName('enabled') . ' = 1');
$query->where($db->quoteName('a.extension') . ' IN(' . $subQuery . ')');
}
// Filter on the language.
if ($language = $this->getState('filter.language')) {
$query->join(
'INNER',
$db->quoteName('#__mail_templates', 'b'),
$db->quoteName('b.template_id') . ' = ' . $db->quoteName('a.template_id')
. ' AND ' . $db->quoteName('b.language') . ' = :language'
)
->bind(':language', $language);
}
// Add the list ordering clause
$listOrdering = $this->state->get('list.ordering', 'a.template_id');
$orderDirn = $this->state->get('list.direction', 'ASC');
$query->order($db->escape($listOrdering) . ' ' . $db->escape($orderDirn));
return $query;
}
/**
* Get list of extensions which are using mail templates
*
* @return array
*
* @since 4.0.0
*/
public function getExtensions()
{
$db = $this->getDatabase();
$subQuery = $db->getQuery(true)
->select($db->quoteName('name'))
->from($db->quoteName('#__extensions'))
->where($db->quoteName('enabled') . ' = 1');
$query = $db->getQuery(true)
->select('DISTINCT ' . $db->quoteName('extension'))
->from($db->quoteName('#__mail_templates'))
->where($db->quoteName('extension') . ' IN (' . $subQuery . ')');
$db->setQuery($query);
return $db->loadColumn();
}
/**
* Get a list of the current content languages
*
* @return array
*
* @since 4.0.0
*/
public function getLanguages()
{
return LanguageHelper::getContentLanguages([0, 1]);
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Mails\Administrator\Table;
use Joomla\CMS\Table\Table;
use Joomla\Database\DatabaseDriver;
use Joomla\Event\DispatcherInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Mail Table class.
*
* @since 4.0.0
*/
class TemplateTable extends Table
{
/**
* An array of key names to be json encoded in the bind function
*
* @var array
* @since 4.0.0
*/
protected $_jsonEncode = ['attachments', 'params'];
/**
* Constructor
*
* @param DatabaseDriver $db Database connector object
* @param ?DispatcherInterface $dispatcher Event dispatcher for this table
*
* @since 4.0.0
*/
public function __construct(DatabaseDriver $db, DispatcherInterface $dispatcher = null)
{
parent::__construct('#__mail_templates', ['template_id', 'language'], $db, $dispatcher);
}
}

View File

@ -0,0 +1,155 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Mails\Administrator\View\Template;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Object\CMSObject;
use Joomla\CMS\Toolbar\Toolbar;
use Joomla\CMS\Toolbar\ToolbarHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* View to edit a mail template.
*
* @since 4.0.0
*/
class HtmlView extends BaseHtmlView
{
/**
* The Form object
*
* @var \Joomla\CMS\Form\Form
*/
protected $form;
/**
* The active item
*
* @var CMSObject
*/
protected $item;
/**
* The model state
*
* @var object
*/
protected $state;
/**
* The template data
*
* @var array
*/
protected $templateData;
/**
* Master data for the mail template
*
* @var CMSObject
*/
protected $master;
/**
* Execute and display a template script.
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*
* @since 4.0.0
*/
public function display($tpl = null)
{
$this->state = $this->get('State');
$this->item = $this->get('Item');
$this->master = $this->get('Master');
$this->form = $this->get('Form');
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
list($component, $template_id) = explode('.', $this->item->template_id, 2);
$fields = ['subject', 'body', 'htmlbody'];
$this->templateData = [];
$language = $this->getLanguage();
$language->load($component, JPATH_SITE, $this->item->language, true);
$language->load($component, JPATH_SITE . '/components/' . $component, $this->item->language, true);
$language->load($component, JPATH_ADMINISTRATOR, $this->item->language, true);
$language->load($component, JPATH_ADMINISTRATOR . '/components/' . $component, $this->item->language, true);
$this->master->subject = Text::_($this->master->subject);
$this->master->body = Text::_($this->master->body);
if ($this->master->htmlbody) {
$this->master->htmlbody = Text::_($this->master->htmlbody);
} else {
$this->master->htmlbody = nl2br($this->master->body, false);
}
$this->templateData = [
'subject' => $this->master->subject,
'body' => $this->master->body,
'htmlbody' => $this->master->htmlbody,
];
foreach ($fields as $field) {
if (\is_null($this->item->$field) || $this->item->$field == '') {
$this->item->$field = $this->master->$field;
$this->form->setValue($field, null, $this->item->$field);
}
}
$this->addToolbar();
parent::display($tpl);
}
/**
* Add the page title and toolbar.
*
* @return void
*
* @since 4.0.0
*/
protected function addToolbar()
{
Factory::getApplication()->getInput()->set('hidemainmenu', true);
$toolbar = Toolbar::getInstance();
ToolbarHelper::title(
Text::_('COM_MAILS_PAGE_EDIT_MAIL'),
'pencil-2 article-add'
);
$saveGroup = $toolbar->dropdownButton('save-group');
$saveGroup->configure(
function (Toolbar $childBar) {
$childBar->apply('template.apply');
$childBar->save('template.save');
}
);
$toolbar->cancel('template.cancel', 'JTOOLBAR_CLOSE');
$toolbar->divider();
$toolbar->help('Mail_Template:_Edit');
}
}

View File

@ -0,0 +1,147 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Mails\Administrator\View\Templates;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Pagination\Pagination;
use Joomla\CMS\Toolbar\Toolbar;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\Component\Mails\Administrator\Helper\MailsHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* View for the mail templates configuration
*
* @since 4.0.0
*/
class HtmlView extends BaseHtmlView
{
/**
* An array of items
*
* @var array
*/
protected $items;
/**
* An array of installed languages
*
* @var array
*/
protected $languages;
/**
* Site default language
*
* @var \stdClass
*/
protected $defaultLanguage;
/**
* The pagination object
*
* @var Pagination
*/
protected $pagination;
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* Form object for search filters
*
* @var Form
*/
public $filterForm;
/**
* The active search filters
*
* @var array
*/
public $activeFilters;
/**
* Execute and display a template script.
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*
* @since 4.0.0
*/
public function display($tpl = null)
{
$this->items = $this->get('Items');
$this->languages = $this->get('Languages');
$this->pagination = $this->get('Pagination');
$this->state = $this->get('State');
$this->filterForm = $this->get('FilterForm');
$this->activeFilters = $this->get('ActiveFilters');
$extensions = $this->get('Extensions');
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
// Find and set site default language
$defaultLanguageTag = ComponentHelper::getParams('com_languages')->get('site');
foreach ($this->languages as $tag => $language) {
if ($tag === $defaultLanguageTag) {
$this->defaultLanguage = $language;
break;
}
}
foreach ($extensions as $extension) {
MailsHelper::loadTranslationFiles($extension);
}
$this->addToolbar();
parent::display($tpl);
}
/**
* Add the page title and toolbar.
*
* @return void
*
* @since 4.0.0
*/
protected function addToolbar()
{
// Get the toolbar object instance
$toolbar = Toolbar::getInstance('toolbar');
$user = $this->getCurrentUser();
ToolbarHelper::title(Text::_('COM_MAILS_MAILS_TITLE'), 'envelope');
if ($user->authorise('core.admin', 'com_mails') || $user->authorise('core.options', 'com_mails')) {
$toolbar->preferences('com_mails');
}
$toolbar->help('Mail_Templates');
}
}

View File

@ -0,0 +1,120 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// no direct access
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
use Joomla\Component\Mails\Administrator\Helper\MailsHelper;
$app = Factory::getApplication();
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('keepalive')
->useScript('form.validate')
->useScript('com_mails.admin-email-template-edit');
$this->useCoreUI = true;
$input = $app->getInput();
list($component, $sub_id) = explode('.', $this->master->template_id, 2);
$sub_id = str_replace('.', '_', $sub_id);
$this->document->addScriptOptions('com_mails', ['templateData' => $this->templateData]);
?>
<form action="<?php echo Route::_('index.php?option=com_mails&layout=edit&template_id=' . $this->item->template_id . '&language=' . $this->item->language); ?>" method="post" name="adminForm" id="item-form" aria-label="<?php echo Text::_('COM_MAILS_FORM_EDIT'); ?>" class="form-validate">
<div class="main-card">
<?php echo HTMLHelper::_('uitab.startTabSet', 'myTab', ['active' => 'general', 'recall' => true, 'breakpoint' => 768]); ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'general', Text::_('COM_MAILS_MAIL_CONTENT')); ?>
<div class="row">
<div class="col-md-12">
<h1><?php echo Text::_($component . '_MAIL_' . $sub_id . '_TITLE'); ?> - <?php echo $this->escape($this->item->language); ?>
</h1>
<div class="small mb-1">
<span class="badge bg-secondary"><?php echo $this->escape($this->master->template_id); ?></span>
</div>
<p><?php echo Text::_($component . '_MAIL_' . $sub_id . '_DESC'); ?></p>
</div>
</div>
<div class="row">
<div class="col-md-9">
<?php echo $this->form->renderField('subject'); ?>
</div>
<div class="col-md-3">
<button type="button" id="btnResetSubject" class="btn btn-secondary">
<?php echo Text::_('COM_MAILS_RESET_TO_DEFAULT_SUBJECT'); ?>
</button>
</div>
</div>
<?php if ($fieldBody = $this->form->getField('body')) : ?>
<div class="row">
<div class="col-md-9">
<?php echo $this->form->renderField('body'); ?>
</div>
<div class="col-md-3">
<button type="button" id="btnResetBody" class="btn btn-secondary">
<?php echo Text::_('COM_MAILS_RESET_TO_DEFAULT_BODY'); ?>
</button>
<div class="tags-container-body mt-3 <?php echo $fieldBody->disabled ? 'hidden' : ''; ?>">
<h2><?php echo Text::_('COM_MAILS_FIELDSET_TAGS_LABEL'); ?></h2>
<?php echo MailsHelper::mailtags($this->master, 'body'); ?>
</div>
</div>
</div>
<?php endif; ?>
<?php if ($fieldHtmlBody = $this->form->getField('htmlbody')) : ?>
<div class="row">
<div class="col-md-9">
<?php echo $this->form->renderField('htmlbody'); ?>
</div>
<div class="col-md-3">
<button type="button" id="btnResetHtmlBody" class="btn btn-secondary">
<?php echo Text::_('COM_MAILS_RESET_TO_DEFAULT_HTML_BODY'); ?>
</button>
<div class="tags-container-htmlbody mt-3 <?php echo $fieldHtmlBody->disabled ? 'hidden' : ''; ?>">
<h2><?php echo Text::_('COM_MAILS_FIELDSET_TAGS_LABEL'); ?></h2>
<?php echo MailsHelper::mailtags($this->master, 'htmlbody'); ?>
</div>
</div>
</div>
<?php endif; ?>
<?php if ($this->form->getField('attachments')) : ?>
<div class="row">
<div class="col-md-9">
<?php echo $this->form->renderField('attachments'); ?>
</div>
</div>
<?php endif; ?>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php if (count($this->form->getFieldset('basic'))) : ?>
<?php echo LayoutHelper::render('joomla.edit.params', $this); ?>
<?php endif; ?>
<?php echo HTMLHelper::_('uitab.endTabSet'); ?>
</div>
<?php echo $this->form->renderField('template_id'); ?>
<?php echo $this->form->renderField('language'); ?>
<input type="hidden" name="task" value="">
<input type="hidden" name="return" value="<?php echo $input->get('return', null, 'BASE64'); ?>">
<?php echo HTMLHelper::_('form.token'); ?>
</form>

View File

@ -0,0 +1,120 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_mails
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
HTMLHelper::_('bootstrap.dropdown', '.dropdown-toggle');
/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('table.columns');
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn = $this->escape($this->state->get('list.direction'));
?>
<form action="<?php echo Route::_('index.php?option=com_mails&view=templates'); ?>" method="post" name="adminForm" id="adminForm">
<div class="row">
<div class="col-md-12">
<div id="j-main-container" class="j-main-container">
<?php
// Search tools bar
echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]);
?>
<?php if (empty($this->items)) : ?>
<div class="alert alert-info">
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
<?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
</div>
<?php else : ?>
<table class="table" id="mailtemplateList">
<caption class="visually-hidden">
<?php echo Text::_('COM_MAILS_TABLE_CAPTION'); ?>,
<span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>,
<span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span>
</caption>
<thead>
<tr>
<th scope="col" class="w-20">
<?php echo Text::_('JGLOBAL_TITLE'); ?>
</th>
<th scope="col" class="w-15 d-none d-md-table-cell">
<?php echo Text::_('COM_MAILS_HEADING_EXTENSION'); ?>
</th>
<?php if (count($this->languages) > 1) : ?>
<th scope="col" class="w-10 text-center">
<?php echo Text::_('COM_MAILS_HEADING_EDIT_TEMPLATES'); ?>
</th>
<?php endif; ?>
<th scope="col" class="w-25 d-none d-md-table-cell">
<?php echo Text::_('COM_MAILS_HEADING_DESCRIPTION'); ?>
</th>
<th scope="col" class="w-20 d-none d-md-table-cell">
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.template_id', $listDirn, $listOrder); ?>
</th>
</tr>
</thead>
<tbody>
<?php foreach ($this->items as $i => $item) :
list($component, $sub_id) = explode('.', $item->template_id, 2);
$sub_id = str_replace('.', '_', $sub_id);
?>
<tr class="row<?php echo $i % 2; ?>">
<th scope="row">
<a href="<?php echo Route::_('index.php?option=com_mails&task=template.edit&template_id=' . $item->template_id . '&language=' . $this->defaultLanguage->lang_code); ?>">
<?php echo Text::_($component . '_MAIL_' . $sub_id . '_TITLE'); ?>
</a>
</th>
<td class="d-none d-md-table-cell">
<?php echo Text::_($component); ?>
</td>
<?php if (count($this->languages) > 1) : ?>
<td>
<ul class="list-unstyled d-flex justify-content-center">
<?php foreach ($this->languages as $language) : ?>
<li class="p-1">
<a href="<?php echo Route::_('index.php?option=com_mails&task=template.edit&template_id=' . $item->template_id . '&language=' . $language->lang_code); ?>">
<?php if ($language->image) : ?>
<?php echo HTMLHelper::_('image', 'mod_languages/' . $language->image . '.gif', $language->title_native, ['title' => $language->title_native], true); ?>
<?php else : ?>
<span class="badge bg-secondary" title="<?php echo $language->title_native; ?>"><?php echo $language->lang_code; ?></span>
<?php endif; ?>
</a>
</li>
<?php endforeach; ?>
</ul>
</td>
<?php endif; ?>
<td class="d-none d-md-table-cell">
<?php echo Text::_($component . '_MAIL_' . $sub_id . '_DESC'); ?>
</td>
<td class="d-none d-md-table-cell text-break">
<?php echo $item->template_id; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php // load the pagination. ?>
<?php echo $this->pagination->getListFooter(); ?>
<?php endif; ?>
<input type="hidden" name="task" value="">
<input type="hidden" name="boxchecked" value="0">
<?php echo HTMLHelper::_('form.token'); ?>
</div>
</div>
</div>
</form>