diff --git a/administrator/components/com_contact/helpers/contact.php b/administrator/components/com_contact/helpers/contact.php
index 5982f7bfc5c45..4b67589870e43 100644
--- a/administrator/components/com_contact/helpers/contact.php
+++ b/administrator/components/com_contact/helpers/contact.php
@@ -120,7 +120,7 @@ public static function validateSection($section, $item)
$section = 'mail';
}
- if (JFactory::getApplication()->isClient('site') && $section == 'category')
+ if (JFactory::getApplication()->isClient('site') && ($section == 'category' || $section == 'form'))
{
// The contact form needs to be the mail section
$section = 'contact';
diff --git a/administrator/components/com_contact/models/contact.php b/administrator/components/com_contact/models/contact.php
index c6e1393768866..405047adc1fce 100644
--- a/administrator/components/com_contact/models/contact.php
+++ b/administrator/components/com_contact/models/contact.php
@@ -57,6 +57,14 @@ class ContactModelContact extends JModelAdmin
'user_id' => 'batchUser',
);
+ /**
+ * Name of the form
+ *
+ * @var string
+ * @since __DEPLOY_VERSION__
+ */
+ protected $formName = 'contact';
+
/**
* Batch change a linked user.
*
@@ -175,7 +183,7 @@ public function getForm($data = array(), $loadData = true)
JForm::addFieldPath(JPATH_ADMINISTRATOR . '/components/com_users/models/fields');
// Get the form.
- $form = $this->loadForm('com_contact.contact', 'contact', array('control' => 'jform', 'load_data' => $loadData));
+ $form = $this->loadForm('com_contact.' . $this->formName, $this->formName, array('control' => 'jform', 'load_data' => $loadData));
if (empty($form))
{
@@ -341,7 +349,7 @@ public function save($data)
foreach ($links as $link)
{
- if ($data['params'][$link])
+ if (!empty($data['params'][$link]))
{
$data['params'][$link] = JStringPunycode::urlToPunycode($data['params'][$link]);
}
diff --git a/administrator/language/en-GB/en-GB.com_contact.sys.ini b/administrator/language/en-GB/en-GB.com_contact.sys.ini
index fa859f0244b21..d41ce9b13f52f 100644
--- a/administrator/language/en-GB/en-GB.com_contact.sys.ini
+++ b/administrator/language/en-GB/en-GB.com_contact.sys.ini
@@ -21,6 +21,8 @@ COM_CONTACT_CONTENT_TYPE_CATEGORY="Contact Category"
COM_CONTACT_FEATURED_VIEW_DEFAULT_DESC="This view lists the featured contacts."
COM_CONTACT_FEATURED_VIEW_DEFAULT_OPTION="Default"
COM_CONTACT_FEATURED_VIEW_DEFAULT_TITLE="Featured Contacts"
+COM_CONTACT_FORM_VIEW_DEFAULT_DESC="Create a new contact."
+COM_CONTACT_FORM_VIEW_DEFAULT_TITLE="Create Contact"
COM_CONTACT_CONTACTS="Contacts"
COM_CONTACT_TAGS_CONTACT="Contact"
COM_CONTACT_TAGS_CATEGORY="Contact Category"
diff --git a/administrator/language/en-GB/en-GB.ini b/administrator/language/en-GB/en-GB.ini
index 94b803958a5a8..7037599ad6e5a 100644
--- a/administrator/language/en-GB/en-GB.ini
+++ b/administrator/language/en-GB/en-GB.ini
@@ -823,6 +823,7 @@ JHELP_MENUS_MENU_ITEM_ARTICLE_FEATURED="Menus_Menu_Item_Article_Featured"
JHELP_MENUS_MENU_ITEM_ARTICLE_SINGLE_ARTICLE="Menus_Menu_Item_Article_Single_Article"
JHELP_MENUS_MENU_ITEM_CONTACT_CATEGORIES="Menus_Menu_Item_Contact_Categories"
JHELP_MENUS_MENU_ITEM_CONTACT_CATEGORY="Menus_Menu_Item_Contact_Category"
+JHELP_MENUS_MENU_ITEM_CONTACT_CREATE="Menus_Menu_Item_Contact_Create"
JHELP_MENUS_MENU_ITEM_CONTACT_FEATURED="Menus_Menu_Item_Contact_Featured"
JHELP_MENUS_MENU_ITEM_CONTACT_SINGLE_CONTACT="Menus_Menu_Item_Contact_Single_Contact"
JHELP_MENUS_MENU_ITEM_DISPLAY_SITE_CONFIGURATION="Menus_Menu_Item_Display_Site_Configuration"
diff --git a/components/com_contact/controllers/contact.php b/components/com_contact/controllers/contact.php
index 82180e6233f0b..ca35aed7a0c7f 100644
--- a/components/com_contact/controllers/contact.php
+++ b/components/com_contact/controllers/contact.php
@@ -9,6 +9,10 @@
defined('_JEXEC') or die;
+use Joomla\CMS\Factory;
+use Joomla\CMS\Uri\Uri;
+use Joomla\Utilities\ArrayHelper;
+
/**
* Controller for single contact view
*
@@ -16,6 +20,22 @@
*/
class ContactControllerContact extends JControllerForm
{
+ /**
+ * The URL view item variable.
+ *
+ * @var string
+ * @since __DEPLOY_VERSION__
+ */
+ protected $view_item = 'form';
+
+ /**
+ * The URL view list variable.
+ *
+ * @var string
+ * @since __DEPLOY_VERSION__
+ */
+ protected $view_list = 'categories';
+
/**
* Method to get a model object, loading it if required.
*
@@ -27,7 +47,7 @@ class ContactControllerContact extends JControllerForm
*
* @since 1.6.4
*/
- public function getModel($name = '', $prefix = '', $config = array('ignore_request' => true))
+ public function getModel($name = 'form', $prefix = '', $config = array('ignore_request' => true))
{
return parent::getModel($name, $prefix, array('ignore_request' => false));
}
@@ -58,7 +78,7 @@ public function submit()
$contact = $model->getItem($id);
// Get item params, take menu parameters into account if necessary
- $active = $app->getMenu()->getActive();
+ $active = $app->getMenu()->getActive();
$stateParams = clone $model->getState()->get('params');
// If the current view is the active item and a contact view for this contact, then the menu item params take priority
@@ -266,4 +286,143 @@ private function _sendEmail($data, $contact, $copy_email_activated)
return $sent;
}
+
+ /**
+ * Method override to check if you can add a new record.
+ *
+ * @param array $data An array of input data.
+ *
+ * @return boolean
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ protected function allowAdd($data = array())
+ {
+ if ($categoryId = ArrayHelper::getValue($data, 'catid', $this->input->getInt('catid'), 'int'))
+ {
+ $user = Factory::getUser();
+
+ // If the category has been passed in the data or URL check it.
+ return $user->authorise('core.create', 'com_contact.category.' . $categoryId);
+ }
+
+ // In the absence of better information, revert to the component permissions.
+ return parent::allowAdd();
+ }
+
+ /**
+ * Method override to check if you can edit an existing record.
+ *
+ * @param array $data An array of input data.
+ * @param string $key The name of the key for the primary key; default is id.
+ *
+ * @return boolean
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ protected function allowEdit($data = array(), $key = 'id')
+ {
+ $recordId = (int) isset($data[$key]) ? $data[$key] : 0;
+
+ if (!$recordId)
+ {
+ return false;
+ }
+
+ // Need to do a lookup from the model.
+ $record = $this->getModel()->getItem($recordId);
+ $categoryId = (int) $record->catid;
+
+ if ($categoryId)
+ {
+ $user = Factory::getUser();
+
+ // The category has been set. Check the category permissions.
+ if ($user->authorise('core.edit', $this->option . '.category.' . $categoryId))
+ {
+ return true;
+ }
+
+ // Fallback on edit.own.
+ if ($user->authorise('core.edit.own', $this->option . '.category.' . $categoryId))
+ {
+ return ($record->created_by == $user->id);
+ }
+
+ return false;
+ }
+
+ // Since there is no asset tracking, revert to the component permissions.
+ return parent::allowEdit($data, $key);
+ }
+
+ /**
+ * Gets the URL arguments to append to an item redirect.
+ *
+ * @param integer $recordId The primary key id for the item.
+ * @param string $urlVar The name of the URL variable for the id.
+ *
+ * @return string The arguments to append to the redirect URL.
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ protected function getRedirectToItemAppend($recordId = 0, $urlVar = 'id')
+ {
+ // Need to override the parent method completely.
+ $tmpl = $this->input->get('tmpl');
+
+ $append = '';
+
+ // Setup redirect info.
+ if ($tmpl)
+ {
+ $append .= '&tmpl=' . $tmpl;
+ }
+
+ $append .= '&layout=edit';
+
+ $append .= '&' . $urlVar . '=' . (int) $recordId;
+
+ $itemId = $this->input->getInt('Itemid');
+ $return = $this->getReturnPage();
+ $catId = $this->input->getInt('catid');
+
+ if ($itemId)
+ {
+ $append .= '&Itemid=' . $itemId;
+ }
+
+ if ($catId)
+ {
+ $append .= '&catid=' . $catId;
+ }
+
+ if ($return)
+ {
+ $append .= '&return=' . base64_encode($return);
+ }
+
+ return $append;
+ }
+
+ /**
+ * Get the return URL.
+ *
+ * If a "return" variable has been passed in the request
+ *
+ * @return string The return URL.
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ protected function getReturnPage()
+ {
+ $return = $this->input->get('return', null, 'base64');
+
+ if (empty($return) || !Uri::isInternal(base64_decode($return)))
+ {
+ return Uri::base();
+ }
+
+ return base64_decode($return);
+ }
}
diff --git a/components/com_contact/helpers/icon.php b/components/com_contact/helpers/icon.php
new file mode 100644
index 0000000000000..cc6ff8f9a7fc5
--- /dev/null
+++ b/components/com_contact/helpers/icon.php
@@ -0,0 +1,150 @@
+id;
+
+ $text = LayoutHelper::render('joomla.content.icons.create', array('params' => $params, 'legacy' => false));
+
+ // Add the button classes to the attribs array
+ if (isset($attribs['class']))
+ {
+ $attribs['class'] .= ' btn btn-primary';
+ }
+ else
+ {
+ $attribs['class'] = 'btn btn-primary';
+ }
+
+ $button = HTMLHelper::_('link', Route::_($url), $text, $attribs);
+
+ $output = '' . $button . '';
+
+ return $output;
+ }
+
+ /**
+ * Display an edit icon for the contact.
+ *
+ * This icon will not display in a popup window, nor if the contact is trashed.
+ * Edit access checks must be performed in the calling code.
+ *
+ * @param object $contact The contact information
+ * @param Registry $params The item parameters
+ * @param array $attribs Optional attributes for the link
+ * @param boolean $legacy True to use legacy images, false to use icomoon based graphic
+ *
+ * @return string The HTML for the contact edit icon.
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public static function edit($contact, $params, $attribs = array(), $legacy = false)
+ {
+ $user = Factory::getUser();
+ $uri = Uri::getInstance();
+
+ // Ignore if in a popup window.
+ if ($params && $params->get('popup'))
+ {
+ return '';
+ }
+
+ // Ignore if the state is negative (trashed).
+ if ($contact->published < 0)
+ {
+ return '';
+ }
+
+ // Show checked_out icon if the contact is checked out by a different user
+ if (property_exists($contact, 'checked_out')
+ && property_exists($contact, 'checked_out_time')
+ && $contact->checked_out > 0
+ && $contact->checked_out != $user->get('id'))
+ {
+ $checkoutUser = Factory::getUser($contact->checked_out);
+ $date = HTMLHelper::_('date', $contact->checked_out_time);
+ $tooltip = Text::_('JLIB_HTML_CHECKED_OUT') . ' :: ' . Text::sprintf('COM_CONTACT_CHECKED_OUT_BY', $checkoutUser->name)
+ . '
' . $date;
+
+ $text = LayoutHelper::render('joomla.content.icons.edit_lock', array('tooltip' => $tooltip, 'legacy' => $legacy));
+
+ $output = HTMLHelper::_('link', '#', $text, $attribs);
+
+ return $output;
+ }
+
+ $contactUrl = ContactHelperRoute::getContactRoute($contact->slug, $contact->catid, $contact->language);
+ $url = $contactUrl . '&task=contact.edit&id=' . $contact->id . '&return=' . base64_encode($uri);
+
+ if ($contact->published == 0)
+ {
+ $overlib = Text::_('JUNPUBLISHED');
+ }
+ else
+ {
+ $overlib = Text::_('JPUBLISHED');
+ }
+
+ $date = HTMLHelper::_('date', $contact->created);
+ $author = $contact->created_by_alias ?: Factory::getUser($contact->created_by)->name;
+
+ $overlib .= '<br />';
+ $overlib .= $date;
+ $overlib .= '<br />';
+ $overlib .= Text::sprintf('COM_CONTACT_WRITTEN_BY', htmlspecialchars($author, ENT_COMPAT, 'UTF-8'));
+
+ $icon = $contact->published ? 'edit' : 'eye-close';
+
+ if (strtotime($contact->publish_up) > strtotime(Factory::getDate())
+ || ((strtotime($contact->publish_down) < strtotime(Factory::getDate())) && $contact->publish_down != Factory::getDbo()->getNullDate()))
+ {
+ $icon = 'eye-close';
+ }
+
+ $text = '';
+ $text .= Text::_('JGLOBAL_EDIT');
+
+ $attribs['title'] = Text::_('COM_CONTACT_EDIT_CONTACT');
+ $output = HTMLHelper::_('link', Route::_($url), $text, $attribs);
+
+ return $output;
+ }
+}
diff --git a/components/com_contact/helpers/legacyrouter.php b/components/com_contact/helpers/legacyrouter.php
index bef342523af08..1c1657e0a6cf4 100644
--- a/components/com_contact/helpers/legacyrouter.php
+++ b/components/com_contact/helpers/legacyrouter.php
@@ -73,7 +73,7 @@ public function build(&$query, &$segments)
$mView = empty($menuItem->query['view']) ? null : $menuItem->query['view'];
$mId = empty($menuItem->query['id']) ? null : $menuItem->query['id'];
- if (isset($query['view']))
+ if (isset($query['view']) && $query['view'] != 'form')
{
$view = $query['view'];
diff --git a/components/com_contact/models/form.php b/components/com_contact/models/form.php
new file mode 100644
index 0000000000000..3f9faa395bed8
--- /dev/null
+++ b/components/com_contact/models/form.php
@@ -0,0 +1,165 @@
+getState('contact.id');
+
+ // Get a row instance.
+ $table = $this->getTable();
+
+ // Attempt to load the row.
+ try
+ {
+ if (!$table->load($itemId))
+ {
+ return false;
+ }
+ }
+ catch (Exception $e)
+ {
+ Factory::getApplication()->enqueueMessage($e->getMessage());
+
+ return false;
+ }
+
+ $properties = $table->getProperties();
+ $value = ArrayHelper::toObject($properties, 'JObject');
+
+ // Convert field to Registry.
+ $value->params = new Registry($value->params);
+
+ // Convert the metadata field to an array.
+ $registry = new Registry($value->metadata);
+ $value->metadata = $registry->toArray();
+
+ if ($itemId)
+ {
+ $value->tags = new Joomla\CMS\Helper\TagsHelper;
+ $value->tags->getTagIds($value->id, 'com_contact.contact');
+ $value->metadata['tags'] = $value->tags;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Get the return URL.
+ *
+ * @return string The return URL.
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function getReturnPage()
+ {
+ return base64_encode($this->getState('return_page'));
+ }
+
+ /**
+ * Method to save the form data.
+ *
+ * @param array $data The form data.
+ *
+ * @return boolean True on success.
+ *
+ * @throws Exception
+ * @since __DEPLOY_VERSION__
+ */
+ public function save($data)
+ {
+ // Associations are not edited in frontend ATM so we have to inherit them
+ if (Associations::isEnabled() && !empty($data['id'])
+ && $associations = Associations::getAssociations('com_contact', '#__contact_details', 'com_contact.item', $data['id']))
+ {
+ foreach ($associations as $tag => $associated)
+ {
+ $associations[$tag] = (int) $associated->id;
+ }
+
+ $data['associations'] = $associations;
+ }
+
+ return parent::save($data);
+ }
+
+ /**
+ * Method to auto-populate the model state.
+ *
+ * Note. Calling getState in this method will result in recursion.
+ *
+ * @return void
+ *
+ * @throws Exception
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ protected function populateState()
+ {
+ $app = Factory::getApplication();
+
+ // Load state from the request.
+ $pk = $app->input->getInt('id');
+ $this->setState('contact.id', $pk);
+
+ $this->setState('contact.catid', $app->input->getInt('catid'));
+
+ $return = $app->input->get('return', null, 'base64');
+ $this->setState('return_page', base64_decode($return));
+
+ // Load the parameters.
+ $params = $app->getParams();
+ $this->setState('params', $params);
+
+ $this->setState('layout', $app->input->getString('layout'));
+ }
+}
diff --git a/components/com_contact/models/forms/form.xml b/components/com_contact/models/forms/form.xml
index 3bd4fdbec77e3..51b9efaa91094 100644
--- a/components/com_contact/models/forms/form.xml
+++ b/components/com_contact/models/forms/form.xml
@@ -1,772 +1,378 @@
-