feat(deployed): add sh404SEF 4.4.4.1791 (no-source, vetted live)
sh404SEF SEF/URL component (Weeblr), vetted clean from live; upstream gated and discontinued for Joomla 3 -> deployed files. Signed-off-by: LÁZÁR Imre <imre@illusion.hu> Assisted-by: claude-code@claude-opus-4-8
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- $Id$ -->
|
||||||
|
<access component="com_sh404sef">
|
||||||
|
<section name="component">
|
||||||
|
<action name="core.manage" title="JACTION_MANAGE" description="JACTION_MANAGE_COMPONENT_DESC" />
|
||||||
|
</section>
|
||||||
|
</access>
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement Joomsef installer
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterAcesefinstaller extends Sh404sefClassBaseinstalladapter {
|
||||||
|
|
||||||
|
protected $_group = 'sh404sefextacesef';
|
||||||
|
protected $_installType = 'acesef_ext';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix Acesef manifest files, so that their
|
||||||
|
* parameters can be displayed in a regular
|
||||||
|
* plugin screen
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function _fixManifest() {
|
||||||
|
|
||||||
|
jimport( 'joomla.filesystem.file');
|
||||||
|
|
||||||
|
// fix original files
|
||||||
|
$source = $this->parent->getPath( 'source');
|
||||||
|
$path = $source . '/' . $this->_getElement() . '.xml';
|
||||||
|
$fileContent = JFile::read( $path);
|
||||||
|
if(!empty( $fileContent)) {
|
||||||
|
$fileContent = str_replace( 'group="sef"', '', $fileContent);
|
||||||
|
$fileContent = str_replace( 'group="url"', '', $fileContent);
|
||||||
|
// group="seo" is of no use for us, so leave it behind
|
||||||
|
$written = JFile::write( $path, $fileContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $source . '/' . $this->_getElement() . '.php';
|
||||||
|
$fileContent = JFile::read( $path);
|
||||||
|
if(!empty( $fileContent)) {
|
||||||
|
$defaults = array( '_check', '_sh_is_clever', '_viva_acesef', '_i_love_acesef', '_sh_loves_acesef', '_need_acesef', '_a_b_c_acesef');
|
||||||
|
$remoteConfig = Sh404sefHelperUpdates::getRemoteConfig( $forced = false);
|
||||||
|
$remotes = empty($remoteConfig->config['ace_prefixes']) ? array() : $remoteConfig->config['ace_prefixes'];
|
||||||
|
$prefixes = array_unique( array_merge( $defaults, $remotes));
|
||||||
|
foreach( $prefixes as $prefix) {
|
||||||
|
$fileContent = preg_replace( '/function\s*' . preg_quote( $prefix) . '\s*\(\s*\)\s*\{/isU', 'function ' . $prefix . '() { return;', $fileContent);
|
||||||
|
}
|
||||||
|
// generic replace
|
||||||
|
$defaultReplaces = array( array( 'source' => 'die;', 'target' => ''));
|
||||||
|
$remoteReplaces = empty($remoteConfig->config['ace_replaces']) ? array() : $remoteConfig->config['ace_replaces'];
|
||||||
|
$replaces = array_unique( array_merge( $defaultReplaces, $remoteReplaces));
|
||||||
|
foreach( $replaces as $replace) {
|
||||||
|
$fileContent = preg_replace( '/' . $replace['source'] . '/sU', $replace['target'], $fileContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write back manifest file
|
||||||
|
$written = JFile::write( $path, $fileContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix in memory object, by killing it, thus prompting recreation
|
||||||
|
$manifest =& $this->parent->getManifest();
|
||||||
|
$manifest = null;
|
||||||
|
$manifest =& $this->parent->getManifest();
|
||||||
|
$this->manifest =& $manifest->document;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,371 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC'))
|
||||||
|
die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
jimport('joomla.application.application');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement Google analytics handling
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterAnalyticsga extends Sh404sefClassBaseanalytics
|
||||||
|
{
|
||||||
|
protected $_endPoint = 'https://www.googleapis.com/analytics/v2.4/';
|
||||||
|
protected $_authPoint = 'https://www.google.com/accounts/ClientLogin';
|
||||||
|
protected $_appKeys = array('AIzaSyCW0BXHyqBdvk_pjjrQzUVn9TGGuSCOo8s', 'AIzaSyAA43aNDAI-G_hLc8ZuDboKcF63lFgBIOE',
|
||||||
|
'AIzaSyBPE9Vv4RMn7j6lxY2ddp-Tz7M9ldALmgk');
|
||||||
|
|
||||||
|
// specific data
|
||||||
|
protected $_SID = '';
|
||||||
|
protected $_LSID = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get tracking snippet
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getSnippet()
|
||||||
|
{
|
||||||
|
// should we insert tracking code snippet ?
|
||||||
|
if (!$this->_shouldInsertSnippet())
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
//$config->analyticsType = 'uga';
|
||||||
|
switch (Sh404sefFactory::getConfig()->analyticsEdition)
|
||||||
|
{
|
||||||
|
case 'ga':
|
||||||
|
$snippet = $this->_getSnippetGa();
|
||||||
|
break;
|
||||||
|
case 'uga':
|
||||||
|
$snippet = $this->_getSnippetUga();
|
||||||
|
break;
|
||||||
|
case 'ga_and_uga':
|
||||||
|
$snippet = $this->_getSnippetGa() . "\n" . $this->_getSnippetUga();
|
||||||
|
break;
|
||||||
|
case 'gtm':
|
||||||
|
$snippet = $this->_getSnippetGtm();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$snippet = '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $snippet . "\n";
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get Classic Ananlytics tracking snippet
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function _getSnippetGa()
|
||||||
|
{
|
||||||
|
// get config
|
||||||
|
$config = Sh404sefFactory::getConfig();
|
||||||
|
$pageInfo = Sh404sefFactory::getPageInfo();
|
||||||
|
|
||||||
|
// fire event so that plugin(s) attach custom vars
|
||||||
|
$customVars = array();
|
||||||
|
$dispatcher = ShlSystem_factory::dispatcher();
|
||||||
|
$dispatcher->trigger('onShInsertAnalyticsSnippet', array(&$customVars, $config));
|
||||||
|
|
||||||
|
// in case of 404, we use a custom page url so that 404s can also be tracked in GA
|
||||||
|
$customUrl = !empty($pageInfo->httpStatus) && $pageInfo->httpStatus == 404 ? "/__404__" : '';
|
||||||
|
|
||||||
|
$displayData = array();
|
||||||
|
$displayData['tracking_code'] = trim($config->analyticsId);
|
||||||
|
$displayData['custom_vars'] = $customVars;
|
||||||
|
$displayData['custom_url'] = $customUrl;
|
||||||
|
$displayData['anonymize'] = !empty($config->analyticsEnableAnonymization);
|
||||||
|
|
||||||
|
$snippet = ShlMvcLayout_Helper::render('com_sh404sef.analytics.snippet_ga', $displayData);
|
||||||
|
|
||||||
|
return $snippet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Universal Analytics tracking snippet
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function _getSnippetUga()
|
||||||
|
{
|
||||||
|
// get config
|
||||||
|
$config = Sh404sefFactory::getConfig();
|
||||||
|
$pageInfo = Sh404sefFactory::getPageInfo();
|
||||||
|
|
||||||
|
// in case of 404, we use a custom page url so that 404s can also be tracked in GA
|
||||||
|
$customUrl =!empty($pageInfo->httpStatus) && $pageInfo->httpStatus == 404 ? '/__404__' : '';
|
||||||
|
|
||||||
|
$displayData = array();
|
||||||
|
$displayData['tracking_code'] = trim($config->analyticsUgaId);
|
||||||
|
$displayData['custom_domain'] = 'auto';
|
||||||
|
$displayData['custom_url'] = $customUrl;
|
||||||
|
$displayData['anonymize'] = !empty($config->analyticsEnableAnonymization);
|
||||||
|
|
||||||
|
$snippet = ShlMvcLayout_Helper::render('com_sh404sef.analytics.snippet_uga', $displayData);
|
||||||
|
|
||||||
|
return $snippet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Google Tags manager snippet
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function _getSnippetGtm()
|
||||||
|
{
|
||||||
|
// get config
|
||||||
|
$config = Sh404sefFactory::getConfig();
|
||||||
|
$pageInfo = Sh404sefFactory::getPageInfo();
|
||||||
|
|
||||||
|
$displayData = array();
|
||||||
|
$displayData['tracking_code'] = trim($config->analyticsGtmId);
|
||||||
|
|
||||||
|
// finalize snippet : add user tracking code
|
||||||
|
$snippet = ShlMvcLayout_Helper::render('com_sh404sef.analytics.snippet_gtm', $displayData);
|
||||||
|
|
||||||
|
return $snippet;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set client object to perform request
|
||||||
|
* for connection to analytics service
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function _prepareConnectRequest()
|
||||||
|
{
|
||||||
|
|
||||||
|
$hClient = Sh404sefHelperAnalytics::getHttpClient();
|
||||||
|
|
||||||
|
// set params
|
||||||
|
$hClient->setUri($this->_authPoint);
|
||||||
|
$hClient->setConfig(array('maxredirects' => 0, 'timeout' => 10));
|
||||||
|
|
||||||
|
// request details
|
||||||
|
$hClient->setMethod(Zendshl_Http_Client::POST);
|
||||||
|
$hClient->setEncType('application/x-www-form-urlencoded');
|
||||||
|
|
||||||
|
// request data
|
||||||
|
$postData = array('accountType' => 'GOOGLE', 'Email' => $this->_config->analyticsUser, 'Passwd' => $this->_config->analyticsPassword,
|
||||||
|
'service' => 'analytics', 'source' => JFactory::getApplication()->getCfg('sitename') . '-sh404sef-' . $this->_config->version);
|
||||||
|
|
||||||
|
$hClient->setParameterPost($postData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Handle response from connect request
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function _handleConnectResponse($response)
|
||||||
|
{
|
||||||
|
|
||||||
|
// check if authentified
|
||||||
|
Sh404sefHelperAnalytics::verifyAuthResponse($response);
|
||||||
|
|
||||||
|
// we are authorized, collect Auth token from body
|
||||||
|
$this->_extractAuthToken($response->getBody());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _fetchAccountsList()
|
||||||
|
{
|
||||||
|
|
||||||
|
$hClient = Sh404sefHelperAnalytics::getHttpClient();
|
||||||
|
$hClient->resetParameters($clearAll = true);
|
||||||
|
|
||||||
|
// build the request
|
||||||
|
$sefConfig = Sh404sefFactory::getConfig();
|
||||||
|
$accountIdBits = explode('-', trim($sefConfig->analyticsId));
|
||||||
|
if (empty($accountIdBits) || count($accountIdBits) < 3)
|
||||||
|
{
|
||||||
|
throw new Sh404sefExceptionDefault(JText::sprintf('COM_SH404SEF_ERROR_CHECKING_ANALYTICS', 'Invalid account Id'));
|
||||||
|
}
|
||||||
|
$accoundId = $accountIdBits[1];
|
||||||
|
|
||||||
|
// set target API url
|
||||||
|
$hClient
|
||||||
|
->setUri(
|
||||||
|
$this->_endPoint . 'management/accounts/' . $accoundId . '/webproperties/' . trim($sefConfig->analyticsId) . '/profiles?key='
|
||||||
|
. $this->_getAppKey());
|
||||||
|
|
||||||
|
// make sure we use GET
|
||||||
|
$hClient->setMethod(Zendshl_Http_Client::GET);
|
||||||
|
|
||||||
|
// set headers required by Google Analytics
|
||||||
|
$headers = array('GData-Version' => 2, 'Authorization' => 'GoogleLogin auth=' . $this->_Auth);
|
||||||
|
|
||||||
|
$hClient->setHeaders($headers);
|
||||||
|
|
||||||
|
//perform request
|
||||||
|
// establish connection with available methods
|
||||||
|
$adapters = array('Zendshl_Http_Client_Adapter_Curl', 'Zendshl_Http_Client_Adapter_Socket');
|
||||||
|
$rawResponse = null;
|
||||||
|
|
||||||
|
// perform connect request
|
||||||
|
foreach ($adapters as $adapter)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$hClient->setAdapter($adapter);
|
||||||
|
$response = $hClient->request();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception $e)
|
||||||
|
{
|
||||||
|
// we failed, let's try another method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return if error
|
||||||
|
if (empty($response))
|
||||||
|
{
|
||||||
|
$msg = 'unknown code';
|
||||||
|
throw new Sh404sefExceptionDefault(JText::sprintf('COM_SH404SEF_ERROR_CHECKING_ANALYTICS', $msg));
|
||||||
|
}
|
||||||
|
if (empty($response) || !is_object($response) || $response->isError())
|
||||||
|
{
|
||||||
|
$msg = method_exists($response, 'getStatus') ? $response->getStatus() : 'unknown code';
|
||||||
|
throw new Sh404sefExceptionDefault(JText::sprintf('COM_SH404SEF_ERROR_CHECKING_ANALYTICS', $msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
// analyze response
|
||||||
|
// check if authentified
|
||||||
|
Sh404sefHelperAnalytics::verifyAuthResponse($response);
|
||||||
|
$xml = simplexml_load_string($response->getBody());
|
||||||
|
|
||||||
|
if (!empty($xml->entry))
|
||||||
|
{
|
||||||
|
foreach ($xml->entry as $entry)
|
||||||
|
{
|
||||||
|
$account = new StdClass();
|
||||||
|
$bits = explode('/', (string) $entry->id);
|
||||||
|
$account->id = array_pop($bits);
|
||||||
|
$account->title = str_replace('Google Analytics Profile ', '', (string) $entry->title);
|
||||||
|
$account->title = str_replace('Google Analytics View (Profile) ', '', $account->title);
|
||||||
|
$this->_accounts[] = clone ($account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepare html filters to allow user to select the way she likes
|
||||||
|
* to view reports
|
||||||
|
*/
|
||||||
|
protected function _prepareFilters()
|
||||||
|
{
|
||||||
|
// array to hold various filters
|
||||||
|
$filters = array();
|
||||||
|
|
||||||
|
// find if we must display all filters. On dashboard, only a reduced set
|
||||||
|
$allFilters = $this->_options['showFilters'] == 'yes';
|
||||||
|
|
||||||
|
// select account to retrieve data for (or rather, profile
|
||||||
|
$customSubmit = ' onchange="shSetupAnalytics({' . ($allFilters ? '' : 'showFilters:\'no\'') . '});"';
|
||||||
|
|
||||||
|
if (version_compare(JVERSION, '3.0', 'ge'))
|
||||||
|
{
|
||||||
|
$select = '<div class="btn-group">';
|
||||||
|
$select .= Sh404sefHelperHtml::buildSelectList($this->_accounts, $this->_options['accountId'], 'accountId', $autoSubmit = false,
|
||||||
|
$addSelectAll = false, $selectAllTitle = '', $customSubmit);
|
||||||
|
$select .= '</div>';
|
||||||
|
$filters[] = $select;
|
||||||
|
|
||||||
|
// dashboard only has account selection, no room for anything else
|
||||||
|
// only shows main selection drop downs on analytics view
|
||||||
|
if ($allFilters)
|
||||||
|
{
|
||||||
|
$select = '<div class="btn-group">';
|
||||||
|
$select .= '<label for="startDate">' . JText::_('COM_SH404SEF_ANALYTICS_START_DATE') . '</label>';
|
||||||
|
$select .= JHTML::_('calendar', $this->_options['startDate'], 'startDate', 'startDate', '%Y-%m-%d', array('class' => 'class="textinput"'));
|
||||||
|
$select .= '</div>';
|
||||||
|
$filters[] = $select;
|
||||||
|
|
||||||
|
$select = '<div class="btn-group">';
|
||||||
|
$select .= '<label for="endDate">' . JText::_('COM_SH404SEF_ANALYTICS_END_DATE') . '</label>';
|
||||||
|
$select .= JHTML::_('calendar', $this->_options['endDate'], 'endDate', 'endDate', '%Y-%m-%d', array('class' => 'class="textinput"'));
|
||||||
|
$select .= '</div>';
|
||||||
|
$filters[] = $select;
|
||||||
|
|
||||||
|
// select groupBy (day, week, month)
|
||||||
|
$select = '<div class="btn-group">';
|
||||||
|
$select .= '<label for="groupBy">' . JText::_('COM_SH404SEF_ANALYTICS_GROUP_BY') . '</label>';
|
||||||
|
$select .= Sh404sefHelperAnalytics::buildAnalyticsGroupBySelectList($this->_options['groupBy'], 'groupBy', $autoSubmit = false,
|
||||||
|
$addSelectAll = false, $selectAllTitle = '', $customSubmit);
|
||||||
|
$select .= '</div>';
|
||||||
|
$filters[] = $select;
|
||||||
|
|
||||||
|
// add a click to update link
|
||||||
|
$filters[] = '<a class="btn btn-link" href="javascript: void(0);" onclick="javascript: shSetupAnalytics({forced:1'
|
||||||
|
. ($allFilters ? '' : ',showFilters:\'no\'') . '});" > [' . JText::_('COM_SH404SEF_CHECK_ANALYTICS') . ']</a>';
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// on dashboard, there is no date select, so we must display the date range
|
||||||
|
$filters[] = ' ' . JText::_('COM_SH404SEF_ANALYTICS_DATE_RANGE') . ' <div class="largertext">'
|
||||||
|
. $this->_options['startDate'] . ' >> ' . $this->_options['endDate'] . '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$select = Sh404sefHelperHtml::buildSelectList($this->_accounts, $this->_options['accountId'], 'accountId', $autoSubmit = false,
|
||||||
|
$addSelectAll = false, $selectAllTitle = '', $customSubmit);
|
||||||
|
$filters[] = JText::_('COM_SH404SEF_ANALYTICS_ACCOUNT') . ': ' . $select;
|
||||||
|
|
||||||
|
// dashboard only has account selection, no room for anything else
|
||||||
|
// only shows main selection drop downs on analytics view
|
||||||
|
if ($allFilters)
|
||||||
|
{
|
||||||
|
// select start date
|
||||||
|
$select = JHTML::_('calendar', $this->_options['startDate'], 'startDate', 'startDate', '%Y-%m-%d', array('class' => 'class="textinput"'));
|
||||||
|
$filters[] = ' ' . JText::_('COM_SH404SEF_ANALYTICS_START_DATE') . ': ' . $select;
|
||||||
|
|
||||||
|
// select end date
|
||||||
|
$select = JHTML::_('calendar', $this->_options['endDate'], 'endDate', 'endDate', '%Y-%m-%d', array('class' => 'class="textinput"'));
|
||||||
|
$filters[] = ' ' . JText::_('COM_SH404SEF_ANALYTICS_END_DATE') . ': ' . $select;
|
||||||
|
|
||||||
|
// select groupBy (day, week, month)
|
||||||
|
$select = Sh404sefHelperAnalytics::buildAnalyticsGroupBySelectList($this->_options['groupBy'], 'groupBy', $autoSubmit = false,
|
||||||
|
$addSelectAll = false, $selectAllTitle = '', $customSubmit);
|
||||||
|
$filters[] = ' ' . JText::_('COM_SH404SEF_ANALYTICS_GROUP_BY') . ': ' . $select;
|
||||||
|
|
||||||
|
// add a click to update link
|
||||||
|
$filters[] = ' <a href="javascript: void(0);" onclick="javascript: shSetupAnalytics({forced:1'
|
||||||
|
. ($allFilters ? '' : ',showFilters:\'no\'') . '});" > [' . JText::_('COM_SH404SEF_CHECK_ANALYTICS') . ']</a>';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// on dashboard, there is no date select, so we must display the date range
|
||||||
|
$filters[] = ' ' . JText::_('COM_SH404SEF_ANALYTICS_DATE_RANGE') . ' <div class="largertext">'
|
||||||
|
. $this->_options['startDate'] . ' >> ' . $this->_options['endDate'] . '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// use layout to render
|
||||||
|
return $filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _extractAuthToken($body)
|
||||||
|
{
|
||||||
|
$SID = explode('LSID=', $body);
|
||||||
|
$this->_SID = trim($SID[0]);
|
||||||
|
$this->_SID = ltrim($this->_SID, 'SID=');
|
||||||
|
|
||||||
|
$LSID = explode('Auth=', $SID[1]);
|
||||||
|
$this->_LSID = trim($LSID[0]);
|
||||||
|
|
||||||
|
$this->_Auth = trim($LSID[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,311 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of pageids data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterExportaliases extends JObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array holding each step details
|
||||||
|
* A step is defined as a task, a view and a layout
|
||||||
|
* By default, task can be 'display', but still need
|
||||||
|
* to be defined in array
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $_stepsMap = array(
|
||||||
|
|
||||||
|
-2 => array( 'task' => 'doTerminate', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
,-1 => array( 'task' => 'doCancel', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 0 => array( 'task' => 'doStart', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 1 => array( 'task' => 'doExport', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 2 => array( 'task' => 'doDownload', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
public $_stepsCount = 0;
|
||||||
|
public $_steps = array( 'next' => 0, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
public $_button = '';
|
||||||
|
public $_buttonsList = array ('next', 'previous', 'terminate', 'cancel');
|
||||||
|
// visible buttons are displayed as toolbar pressbutton
|
||||||
|
// buttons not on that list are passed as 'hidden' post data
|
||||||
|
public $_visibleButtonsList = array ( 'previous', 'next', 'terminate', 'cancel');
|
||||||
|
|
||||||
|
protected $_context = 'aliases';
|
||||||
|
protected $_total = 0;
|
||||||
|
protected $_parentController = null;
|
||||||
|
protected $_filename = '';
|
||||||
|
|
||||||
|
const MAX_PAGEIDS_PER_STEP = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, keep reference to controller
|
||||||
|
* which called the adapter
|
||||||
|
* @param unknown_type $parentController
|
||||||
|
*/
|
||||||
|
public function __construct( $parentController) {
|
||||||
|
|
||||||
|
$this->_parentController = $parentController;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
$this->_stepsCount = count( $this->_stepsMap);
|
||||||
|
|
||||||
|
// prepare data for controller
|
||||||
|
$properties = array();
|
||||||
|
|
||||||
|
$properties['_defaultController'] = 'wizard';
|
||||||
|
$properties['_defaultTask'] = '';
|
||||||
|
$properties['_defaultModel'] = '';
|
||||||
|
$properties['_defaultView'] = 'wizard';
|
||||||
|
$properties['_defaultLayout'] = 'default';
|
||||||
|
|
||||||
|
$properties['_returnController'] = 'aliases';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'aliases';
|
||||||
|
$properties['_returnLayout'] = 'default';
|
||||||
|
$properties['_pageTitle'] = JText::_('COM_SH404SEF_EXPORTING_TITLE');
|
||||||
|
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First step, by default a message
|
||||||
|
* and a Terminate button
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doStart() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('next', 'cancel');
|
||||||
|
|
||||||
|
// next steps definition
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
$result['mainText'] = JText::_('COM_SH404SEF_EXPORT_ALIASES_START');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Second step, export data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doExport() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ();
|
||||||
|
|
||||||
|
// A customiser :
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
// exporting a limited set of pageids at a time
|
||||||
|
$nextStart = JRequest::getInt( 'nextstart', 0);
|
||||||
|
|
||||||
|
// are we adding to an existing data file ?
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// calculate number of items to export
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'aliases', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'aliases.default');
|
||||||
|
$options = (object) array('layout' => 'default', 'includeHomeData' => true);
|
||||||
|
$this->_total = $model->getTotal( $options);
|
||||||
|
|
||||||
|
// do we have anything to export ?
|
||||||
|
if (empty( $this->_total)) {
|
||||||
|
$result['mainText'] = JText::_('COM_SH404SEF_NOTHING_TO_EXPORT');
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('terminate');
|
||||||
|
// next step so to trigger download, as file is ready now
|
||||||
|
$this->_steps = array( 'next' => -2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get new start item
|
||||||
|
if (empty( $nextStart)) {
|
||||||
|
// this is first pass, starting from 0
|
||||||
|
$start = 0;
|
||||||
|
$nextStart = $start + self::MAX_PAGEIDS_PER_STEP;
|
||||||
|
if ($nextStart >= $this->_total) {
|
||||||
|
// reached the end
|
||||||
|
$nextStart = $this->_total;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$start = $nextStart;
|
||||||
|
$nextStart = $start + self::MAX_PAGEIDS_PER_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// are we done ? if so, move to next step
|
||||||
|
$result['hiddenText'] = '';
|
||||||
|
|
||||||
|
if ($start >= $this->_total) {
|
||||||
|
$result['mainText'] = JText::sprintf('COM_SH404SEF_EXPORT_DONE', $this->_total);
|
||||||
|
$result['mainText'] .= $this->_getTerminateOptions();
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('terminate');
|
||||||
|
// next step so to trigger download, as file is ready now
|
||||||
|
$this->_steps = array( 'next' => 2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// actually export items
|
||||||
|
$this->_export( $start);
|
||||||
|
|
||||||
|
// continuing for another round
|
||||||
|
$result['mainText'] = JText::sprintf('COM_SH404SEF_EXPORT_EXPORTING', $start + 1, $this->_total);
|
||||||
|
$result['hiddenText'] = '<input type="hidden" name="nextstart" value="'.$nextStart.'" />';
|
||||||
|
$result['nextStart'] = $nextStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result['continue'] = array( 'task' => 'next', 'nextstart' => $nextStart, 'filename' => base64_encode($this->_filename));
|
||||||
|
$result['continue'] = array_merge( $result['continue'], $this->_steps);
|
||||||
|
$result['hiddenText'] .= '<input type="hidden" name="filename" value="'.$this->_filename.'" />';
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last step, send results as download
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doDownload() {
|
||||||
|
|
||||||
|
|
||||||
|
// fake content
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
// get the current filename with path
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// get a more readable filename
|
||||||
|
$displayName = date('Y-m-d') . '_' . $this->_context . '_export.txt';
|
||||||
|
|
||||||
|
Sh404sefHelperFiles::triggerDownload( $this->_filename, $displayName);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doTerminate() {
|
||||||
|
|
||||||
|
// are we set to purge temporary files ?
|
||||||
|
$purgeTempFiles = JRequest::getInt( 'purge_temp_files', 0);
|
||||||
|
if (!empty($purgeTempFiles)) {
|
||||||
|
Sh404sefHelperFiles::purgeTempFiles( 'sh404sef_export_' . $this->_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now go back to main page
|
||||||
|
$result = array( 'redirectTo' => true);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doCancel() {
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
$result['redirectTo'] = true;
|
||||||
|
$result['redirectOptions'] = array( 'sh404sefMsg' => 'COM_SH404SEF_WIZARD_CANCELLED');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _export( $start) {
|
||||||
|
|
||||||
|
// do we have a valid filename
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// put some data in the file
|
||||||
|
$end = $start + self::MAX_PAGEIDS_PER_STEP + 1;
|
||||||
|
$end = $end > $this->_total ? $this->_total : $end;
|
||||||
|
|
||||||
|
// fetch pageIds record from model
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'aliases', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'aliases.default');
|
||||||
|
$options = (object) array('layout' => 'default', 'includeHomeData' => true);
|
||||||
|
$records = $model->getList( $options, $returnZeroElement = false, $start, $forcedLimit = self::MAX_PAGEIDS_PER_STEP);
|
||||||
|
|
||||||
|
// do we need a header written to the file, for first record
|
||||||
|
$header = $start == 0 ? Sh404sefHelperGeneral::getExportHeaders( $this->_context) . "\n" : '';
|
||||||
|
|
||||||
|
// format them for text file output
|
||||||
|
$data = '';
|
||||||
|
$counter = $start;
|
||||||
|
$glue = Sh404sefHelperFiles::$stringDelimiter . Sh404sefHelperFiles::$fieldDelimiter . Sh404sefHelperFiles::$stringDelimiter;
|
||||||
|
if (!empty( $records)) {
|
||||||
|
foreach( $records as $record) {
|
||||||
|
$counter++;
|
||||||
|
if ($record->newurl == sh404SEF_HOMEPAGE_CODE) {
|
||||||
|
$record->newurl = '__ Homepage __';
|
||||||
|
}
|
||||||
|
$textRecord = $record->alias . $glue . $record->oldurl . $glue . $record->newurl
|
||||||
|
. $glue . $record->type
|
||||||
|
. $glue . $record->hits . Sh404sefHelperFiles::$stringDelimiter
|
||||||
|
;
|
||||||
|
$line = Sh404sefHelperFiles::$stringDelimiter . $counter . $glue . $textRecord;
|
||||||
|
$data .= $line . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare data for storage
|
||||||
|
if (!empty( $header)) {
|
||||||
|
// first record written to file, prepend header
|
||||||
|
$data = $header . $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store in file
|
||||||
|
$status = Sh404sefHelperFiles::appendToFile( $this->_filename, $data);
|
||||||
|
|
||||||
|
// return any error
|
||||||
|
return $status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getTerminateOptions() {
|
||||||
|
|
||||||
|
$options = '<br /><br />';
|
||||||
|
$options .= '<input type="checkbox" name="purge_temp_files" value="1" checked="checked" >';
|
||||||
|
$options .= JText::_('COM_SH404SEF_PURGE_TEMP_FILES');
|
||||||
|
$options .= '<br />';
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,364 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of page title and metas data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterExportmetas extends JObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array holding each step details
|
||||||
|
* A step is defined as a task, a view and a layout
|
||||||
|
* By default, task can be 'display', but still need
|
||||||
|
* to be defined in array
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $_stepsMap = array(
|
||||||
|
|
||||||
|
-2 => array( 'task' => 'doTerminate', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
,-1 => array( 'task' => 'doCancel', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 0 => array( 'task' => 'doStart', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 1 => array( 'task' => 'doExport', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 2 => array( 'task' => 'doDownload', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
public $_stepsCount = 0;
|
||||||
|
public $_steps = array( 'next' => 0, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
public $_button = '';
|
||||||
|
public $_buttonsList = array ('next', 'previous', 'terminate', 'cancel');
|
||||||
|
// visible buttons are displayed as toolbar pressbutton
|
||||||
|
// buttons not on that list are passed as 'hidden' post data
|
||||||
|
public $_visibleButtonsList = array ( 'previous', 'next', 'terminate', 'cancel');
|
||||||
|
|
||||||
|
|
||||||
|
protected $_context = 'metas';
|
||||||
|
protected $_total = 0;
|
||||||
|
protected $_parentController = null;
|
||||||
|
protected $_filename = '';
|
||||||
|
|
||||||
|
const MAX_PAGEIDS_PER_STEP = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, keep reference to controller
|
||||||
|
* which called the adapter
|
||||||
|
* @param unknown_type $parentController
|
||||||
|
*/
|
||||||
|
public function __construct( $parentController) {
|
||||||
|
|
||||||
|
$this->_parentController = $parentController;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
$this->_stepsCount = count( $this->_stepsMap);
|
||||||
|
|
||||||
|
// prepare data for controller
|
||||||
|
$properties = array();
|
||||||
|
|
||||||
|
$properties['_defaultController'] = 'wizard';
|
||||||
|
$properties['_defaultTask'] = '';
|
||||||
|
$properties['_defaultModel'] = '';
|
||||||
|
$properties['_defaultView'] = 'wizard';
|
||||||
|
$properties['_defaultLayout'] = 'default';
|
||||||
|
|
||||||
|
$properties['_returnController'] = 'metas';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'metas';
|
||||||
|
$properties['_returnLayout'] = 'default';
|
||||||
|
$properties['_pageTitle'] = JText::_('COM_SH404SEF_EXPORTING_TITLE');
|
||||||
|
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First step, by default a message
|
||||||
|
* and a Terminate button
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doStart() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('next', 'cancel');
|
||||||
|
|
||||||
|
// A customiser :
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
$result['mainText'] = JText::_('COM_SH404SEF_EXPORT_METAS_START');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Second step, export data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doExport() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ();
|
||||||
|
|
||||||
|
// next steps definition
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
// exporting a limited set of pageids at a time
|
||||||
|
$nextStart = JRequest::getInt( 'nextstart', 0);
|
||||||
|
|
||||||
|
// are we adding to an existing data file ?
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// calculate number of items to export
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'urls', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'metas.default');
|
||||||
|
$options = (object) array('layout' => 'export', 'getMetaData' => true, 'onlyWithMetaData' => true, 'simpleUrlList' => true);
|
||||||
|
$this->_total = $model->getTotal( $options);
|
||||||
|
|
||||||
|
// do we have anything to export ?
|
||||||
|
if (empty( $this->_total)) {
|
||||||
|
$result['mainText'] = JText::_('COM_SH404SEF_NOTHING_TO_EXPORT');
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('terminate');
|
||||||
|
// next step so to trigger download, as file is ready now
|
||||||
|
$this->_steps = array( 'next' => -2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get new start item
|
||||||
|
if (empty( $nextStart)) {
|
||||||
|
// this is first pass, starting from 0
|
||||||
|
$start = 0;
|
||||||
|
$nextStart = $start + self::MAX_PAGEIDS_PER_STEP;
|
||||||
|
if ($nextStart >= $this->_total) {
|
||||||
|
// reached the end
|
||||||
|
$nextStart = $this->_total;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$start = $nextStart;
|
||||||
|
$nextStart = $start + self::MAX_PAGEIDS_PER_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// are we done ? if so, move to next step
|
||||||
|
$result['hiddenText'] = '';
|
||||||
|
|
||||||
|
if ($start >= $this->_total) {
|
||||||
|
// append homepage data. Hard to put them at the beginning, that'd make the whole counting logic more complex
|
||||||
|
$this->_exportHomePageData( $this->_total);
|
||||||
|
|
||||||
|
// keep going to terminate page
|
||||||
|
$result['mainText'] = JText::sprintf('COM_SH404SEF_EXPORT_DONE', $this->_total);
|
||||||
|
$result['mainText'] .= $this->_getTerminateOptions();
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('terminate');
|
||||||
|
// next step so to trigger download, as file is ready now
|
||||||
|
$this->_steps = array( 'next' => 2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// actually export items
|
||||||
|
$this->_export( $start);
|
||||||
|
|
||||||
|
// continuing for another round
|
||||||
|
$result['mainText'] = JText::sprintf('COM_SH404SEF_EXPORT_EXPORTING', $start + 1, $this->_total);
|
||||||
|
$result['hiddenText'] = '<input type="hidden" name="nextstart" value="'.$nextStart.'" />';
|
||||||
|
$result['nextStart'] = $nextStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result['continue'] = array( 'task' => 'next', 'nextstart' => $nextStart, 'filename' => base64_encode($this->_filename));
|
||||||
|
$result['continue'] = array_merge( $result['continue'], $this->_steps);
|
||||||
|
$result['hiddenText'] .= '<input type="hidden" name="filename" value="'.$this->_filename.'" />';
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last step, send results as download
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doDownload() {
|
||||||
|
|
||||||
|
|
||||||
|
// fake content
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
// get the current filename with path
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// get a more readable filename
|
||||||
|
$displayName = date('Y-m-d') . '_' . $this->_context . '_export.txt';
|
||||||
|
|
||||||
|
Sh404sefHelperFiles::triggerDownload( $this->_filename, $displayName);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doTerminate() {
|
||||||
|
|
||||||
|
// are we set to purge temporary files ?
|
||||||
|
$purgeTempFiles = JRequest::getInt( 'purge_temp_files', 0);
|
||||||
|
if (!empty($purgeTempFiles)) {
|
||||||
|
Sh404sefHelperFiles::purgeTempFiles( 'sh404sef_export_' . $this->_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now go back to main page
|
||||||
|
$result = array( 'redirectTo' => true);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doCancel() {
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
$result['redirectTo'] = true;
|
||||||
|
$result['redirectOptions'] = array( 'sh404sefMsg' => 'COM_SH404SEF_WIZARD_CANCELLED');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _export( $start) {
|
||||||
|
|
||||||
|
// do we have a valid filename
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// put some data in the file
|
||||||
|
$end = $start + self::MAX_PAGEIDS_PER_STEP + 1;
|
||||||
|
$end = $end > $this->_total ? $this->_total : $end;
|
||||||
|
|
||||||
|
// fetch pageIds record from model
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'urls', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'metas.default');
|
||||||
|
$options = (object) array('layout' => 'export', 'getMetaData' => true, 'onlyWithMetaData' => true, 'simpleUrlList' => true);
|
||||||
|
$records = $model->getList( $options, $returnZeroElement = false, $start, $forcedLimit = self::MAX_PAGEIDS_PER_STEP);
|
||||||
|
|
||||||
|
// do we need a header written to the file, for first record
|
||||||
|
$header = $start == 0 ? Sh404sefHelperGeneral::getExportHeaders( $this->_context) . "\n" : '';
|
||||||
|
|
||||||
|
// format them for text file output
|
||||||
|
$data = '';
|
||||||
|
$counter = $start;
|
||||||
|
$glue = Sh404sefHelperFiles::$stringDelimiter . Sh404sefHelperFiles::$fieldDelimiter . Sh404sefHelperFiles::$stringDelimiter;
|
||||||
|
if (!empty( $records)) {
|
||||||
|
foreach( $records as $record) {
|
||||||
|
$counter++;
|
||||||
|
$data .= $this->_createLine( $record, $counter, $glue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare data for storage
|
||||||
|
if (!empty( $header)) {
|
||||||
|
// first record written to file, prepend header
|
||||||
|
$data = $header . $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store in file
|
||||||
|
$status = Sh404sefHelperFiles::appendToFile( $this->_filename, $data);
|
||||||
|
|
||||||
|
// return any error
|
||||||
|
return $status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _exportHomePageData( $start) {
|
||||||
|
|
||||||
|
// get data from model
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'metas', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'metas.default');
|
||||||
|
$options = (object) array('layout' => 'default', 'newurl' => sh404SEF_HOMEPAGE_CODE);
|
||||||
|
$this->_total += 1;
|
||||||
|
$homePageMetaData = $model->getList( $options);
|
||||||
|
|
||||||
|
// format them for text file output
|
||||||
|
$data = '';
|
||||||
|
$counter = $start;
|
||||||
|
$glue = Sh404sefHelperFiles::$stringDelimiter . Sh404sefHelperFiles::$fieldDelimiter . Sh404sefHelperFiles::$stringDelimiter;
|
||||||
|
if (!empty( $homePageMetaData)) {
|
||||||
|
foreach( $homePageMetaData as $record) {
|
||||||
|
$counter++;
|
||||||
|
$record->oldurl = '';
|
||||||
|
$record->newurl = '__ Homepage __';
|
||||||
|
$data .= $this->_createLine( $record, $counter, $glue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare data for storage
|
||||||
|
if (!empty( $header)) {
|
||||||
|
// first record written to file, prepend header
|
||||||
|
$data = $header . $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store in file
|
||||||
|
$status = Sh404sefHelperFiles::appendToFile( $this->_filename, $data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an export file line, based on db record
|
||||||
|
*
|
||||||
|
* @param $record the data coming from DB
|
||||||
|
* @param $counter, running counter
|
||||||
|
* @param $glue , glue string between elements of records
|
||||||
|
*/
|
||||||
|
protected function _createLine( $record, $counter, $glue) {
|
||||||
|
|
||||||
|
$textRecord = $record->oldurl . $glue . $record->newurl
|
||||||
|
. $glue . (empty( $record->cpt) ? 0 : $record->cpt)
|
||||||
|
. $glue . (empty( $record->rank) ? 0 : $record->rank)
|
||||||
|
. $glue . (!isset( $record->dateadd) ? '0000-00-00' : $record->dateadd)
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->metatitle)
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->metadesc)
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->metakey)
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->metalang)
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->metarobots) . Sh404sefHelperFiles::$stringDelimiter;
|
||||||
|
$line = Sh404sefHelperFiles::$stringDelimiter . $counter . $glue . $textRecord . "\n";
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getTerminateOptions() {
|
||||||
|
|
||||||
|
$options = '<br /><br />';
|
||||||
|
$options .= '<input type="checkbox" name="purge_temp_files" value="1" checked="checked" >';
|
||||||
|
$options .= JText::_('COM_SH404SEF_PURGE_TEMP_FILES');
|
||||||
|
$options .= '<br />';
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,308 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of pageids data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterExportpageids extends JObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array holding each step details
|
||||||
|
* A step is defined as a task, a view and a layout
|
||||||
|
* By default, task can be 'display', but still need
|
||||||
|
* to be defined in array
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $_stepsMap = array(
|
||||||
|
|
||||||
|
-2 => array( 'task' => 'doTerminate', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
,-1 => array( 'task' => 'doCancel', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 0 => array( 'task' => 'doStart', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 1 => array( 'task' => 'doExport', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 2 => array( 'task' => 'doDownload', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
public $_stepsCount = 0;
|
||||||
|
public $_steps = array( 'next' => 0, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
public $_button = '';
|
||||||
|
public $_buttonsList = array ('next', 'previous', 'terminate', 'cancel');
|
||||||
|
// visible buttons are displayed as toolbar pressbutton
|
||||||
|
// buttons not on that list are passed as 'hidden' post data
|
||||||
|
public $_visibleButtonsList = array ( 'previous', 'next', 'terminate', 'cancel');
|
||||||
|
|
||||||
|
protected $_context = 'pageids';
|
||||||
|
protected $_total = 0;
|
||||||
|
protected $_parentController = null;
|
||||||
|
protected $_filename = '';
|
||||||
|
|
||||||
|
const MAX_PAGEIDS_PER_STEP = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, keep reference to controller
|
||||||
|
* which called the adapter
|
||||||
|
* @param unknown_type $parentController
|
||||||
|
*/
|
||||||
|
public function __construct( $parentController) {
|
||||||
|
|
||||||
|
$this->_parentController = $parentController;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
$this->_stepsCount = count( $this->_stepsMap);
|
||||||
|
|
||||||
|
// prepare data for controller
|
||||||
|
$properties = array();
|
||||||
|
|
||||||
|
$properties['_defaultController'] = 'wizard';
|
||||||
|
$properties['_defaultTask'] = '';
|
||||||
|
$properties['_defaultModel'] = '';
|
||||||
|
$properties['_defaultView'] = 'wizard';
|
||||||
|
$properties['_defaultLayout'] = 'default';
|
||||||
|
|
||||||
|
$properties['_returnController'] = 'pageids';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'pageids';
|
||||||
|
$properties['_returnLayout'] = 'default';
|
||||||
|
$properties['_pageTitle'] = JText::_('COM_SH404SEF_EXPORTING_TITLE');
|
||||||
|
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First step, by default a message
|
||||||
|
* and a Terminate button
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doStart() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('next', 'cancel');
|
||||||
|
|
||||||
|
// next steps definition
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
$result['mainText'] = JText::_('COM_SH404SEF_EXPORT_PAGEIDS_START');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Second step, export data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doExport() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ();
|
||||||
|
|
||||||
|
// next steps definition
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
// exporting a limited set of pageids at a time
|
||||||
|
$nextStart = JRequest::getInt( 'nextstart', 0);
|
||||||
|
|
||||||
|
// are we adding to an existing data file ?
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// calculate number of items to export
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'urls', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'pageids.default');
|
||||||
|
$options = (object) array('layout' => 'default', 'getPageId' => true, 'simpleUrlList' => true,);
|
||||||
|
$this->_total = $model->getTotal( $options);
|
||||||
|
|
||||||
|
// do we have anything to export ?
|
||||||
|
if (empty( $this->_total)) {
|
||||||
|
$result['mainText'] = JText::_('COM_SH404SEF_NOTHING_TO_EXPORT');
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('terminate');
|
||||||
|
// next step so to trigger download, as file is ready now
|
||||||
|
$this->_steps = array( 'next' => -2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get new start item
|
||||||
|
if (empty( $nextStart)) {
|
||||||
|
// this is first pass, starting from 0
|
||||||
|
$start = 0;
|
||||||
|
$nextStart = $start + self::MAX_PAGEIDS_PER_STEP;
|
||||||
|
if ($nextStart >= $this->_total) {
|
||||||
|
// reached the end
|
||||||
|
$nextStart = $this->_total;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$start = $nextStart;
|
||||||
|
$nextStart = $start + self::MAX_PAGEIDS_PER_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// are we done ? if so, move to next step
|
||||||
|
$result['hiddenText'] = '';
|
||||||
|
|
||||||
|
if ($start >= $this->_total) {
|
||||||
|
$result['mainText'] = JText::sprintf('COM_SH404SEF_EXPORT_DONE', $this->_total);
|
||||||
|
$result['mainText'] .= $this->_getTerminateOptions();
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('terminate');
|
||||||
|
// next step so to trigger download, as file is ready now
|
||||||
|
$this->_steps = array( 'next' => 2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// actually export items
|
||||||
|
$this->_export( $start);
|
||||||
|
|
||||||
|
// continuing for another round
|
||||||
|
$result['mainText'] = JText::sprintf('COM_SH404SEF_EXPORT_EXPORTING', $start + 1, $this->_total);
|
||||||
|
$result['hiddenText'] = '<input type="hidden" name="nextstart" value="'.$nextStart.'" />';
|
||||||
|
$result['nextStart'] = $nextStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result['continue'] = array( 'task' => 'next', 'nextstart' => $nextStart, 'filename' => base64_encode($this->_filename));
|
||||||
|
$result['continue'] = array_merge( $result['continue'], $this->_steps);
|
||||||
|
$result['hiddenText'] .= '<input type="hidden" name="filename" value="'.$this->_filename.'" />';
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last step, send results as download
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doDownload() {
|
||||||
|
|
||||||
|
|
||||||
|
// fake content
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
// get the current filename with path
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// get a more readable filename
|
||||||
|
$displayName = date('Y-m-d') . '_' . $this->_context . '_export.txt';
|
||||||
|
|
||||||
|
Sh404sefHelperFiles::triggerDownload( $this->_filename, $displayName);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doTerminate() {
|
||||||
|
|
||||||
|
// are we set to purge temporary files ?
|
||||||
|
$purgeTempFiles = JRequest::getInt( 'purge_temp_files', 0);
|
||||||
|
if (!empty($purgeTempFiles)) {
|
||||||
|
Sh404sefHelperFiles::purgeTempFiles( 'sh404sef_export_' . $this->_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now go back to main page
|
||||||
|
$result = array( 'redirectTo' => true);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doCancel() {
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
$result['redirectTo'] = true;
|
||||||
|
$result['redirectOptions'] = array( 'sh404sefMsg' => 'COM_SH404SEF_WIZARD_CANCELLED');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _export( $start) {
|
||||||
|
|
||||||
|
// do we have a valid filename
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// put some data in the file
|
||||||
|
$end = $start + self::MAX_PAGEIDS_PER_STEP + 1;
|
||||||
|
$end = $end > $this->_total ? $this->_total : $end;
|
||||||
|
|
||||||
|
// fetch pageIds record from model
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'urls', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'pageids.default');
|
||||||
|
$options = (object) array('layout' => 'default', 'getPageId' => true, 'simpleUrlList' => true);
|
||||||
|
$records = $model->getList( $options, $returnZeroElement = false, $start, $forcedLimit = self::MAX_PAGEIDS_PER_STEP);
|
||||||
|
|
||||||
|
// do we need a header written to the file, for first record
|
||||||
|
$header = $start == 0 ? Sh404sefHelperGeneral::getExportHeaders( $this->_context) . "\n" : '';
|
||||||
|
|
||||||
|
// format them for text file output
|
||||||
|
$data = '';
|
||||||
|
$counter = $start;
|
||||||
|
$glue = Sh404sefHelperFiles::$stringDelimiter . Sh404sefHelperFiles::$fieldDelimiter . Sh404sefHelperFiles::$stringDelimiter;
|
||||||
|
if (!empty( $records)) {
|
||||||
|
foreach( $records as $record) {
|
||||||
|
$counter++;
|
||||||
|
$textRecord = $record->pageid . $glue . $record->oldurl . $glue . $record->nonsefurl
|
||||||
|
. $glue . $record->pageidtype
|
||||||
|
. $glue . $record->pageidhits . Sh404sefHelperFiles::$stringDelimiter
|
||||||
|
;
|
||||||
|
$line = Sh404sefHelperFiles::$stringDelimiter . $counter . $glue . $textRecord;
|
||||||
|
$data .= $line . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare data for storage
|
||||||
|
if (!empty( $header)) {
|
||||||
|
// first record written to file, prepend header
|
||||||
|
$data = $header . $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store in file
|
||||||
|
$status = Sh404sefHelperFiles::appendToFile( $this->_filename, $data);
|
||||||
|
|
||||||
|
// return any error
|
||||||
|
return $status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getTerminateOptions() {
|
||||||
|
|
||||||
|
$options = '<br /><br />';
|
||||||
|
$options .= '<input type="checkbox" name="purge_temp_files" value="1" checked="checked" >';
|
||||||
|
$options .= JText::_('COM_SH404SEF_PURGE_TEMP_FILES');
|
||||||
|
$options .= '<br />';
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,317 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of page title and metas data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterExporturls extends JObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array holding each step details
|
||||||
|
* A step is defined as a task, a view and a layout
|
||||||
|
* By default, task can be 'display', but still need
|
||||||
|
* to be defined in array
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $_stepsMap = array(
|
||||||
|
|
||||||
|
-2 => array( 'task' => 'doTerminate', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
,-1 => array( 'task' => 'doCancel', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 0 => array( 'task' => 'doStart', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 1 => array( 'task' => 'doExport', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 2 => array( 'task' => 'doDownload', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
public $_stepsCount = 0;
|
||||||
|
public $_steps = array( 'next' => 0, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
public $_button = '';
|
||||||
|
public $_buttonsList = array ('next', 'previous', 'terminate', 'cancel');
|
||||||
|
// visible buttons are displayed as toolbar pressbutton
|
||||||
|
// buttons not on that list are passed as 'hidden' post data
|
||||||
|
public $_visibleButtonsList = array ( 'previous', 'next', 'terminate', 'cancel');
|
||||||
|
|
||||||
|
|
||||||
|
protected $_context = 'urls';
|
||||||
|
protected $_total = 0;
|
||||||
|
protected $_parentController = null;
|
||||||
|
protected $_filename = '';
|
||||||
|
|
||||||
|
const MAX_PAGEIDS_PER_STEP = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, keep reference to controller
|
||||||
|
* which called the adapter
|
||||||
|
* @param unknown_type $parentController
|
||||||
|
*/
|
||||||
|
public function __construct( $parentController) {
|
||||||
|
|
||||||
|
$this->_parentController = $parentController;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
$this->_stepsCount = count( $this->_stepsMap);
|
||||||
|
|
||||||
|
// prepare data for controller
|
||||||
|
$properties = array();
|
||||||
|
|
||||||
|
$properties['_defaultController'] = 'wizard';
|
||||||
|
$properties['_defaultTask'] = '';
|
||||||
|
$properties['_defaultModel'] = '';
|
||||||
|
$properties['_defaultView'] = 'wizard';
|
||||||
|
$properties['_defaultLayout'] = 'default';
|
||||||
|
|
||||||
|
$properties['_returnController'] = 'urls';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'urls';
|
||||||
|
$properties['_returnLayout'] = 'default';
|
||||||
|
$properties['_pageTitle'] = JText::_('COM_SH404SEF_EXPORTING_TITLE');
|
||||||
|
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First step, by default a message
|
||||||
|
* and a Terminate button
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doStart() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('next', 'cancel');
|
||||||
|
|
||||||
|
// A customiser :
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
$result['mainText'] = JText::_('COM_SH404SEF_EXPORT_URLS_START');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Second step, export data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doExport() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ();
|
||||||
|
|
||||||
|
// next steps definition
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
// exporting a limited set of pageids at a time
|
||||||
|
$nextStart = JRequest::getInt( 'nextstart', 0);
|
||||||
|
|
||||||
|
// are we adding to an existing data file ?
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// calculate number of items to export
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'urls', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'urls.default');
|
||||||
|
$options = (object) array('layout' => 'export', 'getMetaData' => true, 'simpleUrlList' => true);
|
||||||
|
$this->_total = $model->getTotal( $options);
|
||||||
|
|
||||||
|
// do we have anything to export ?
|
||||||
|
if (empty( $this->_total)) {
|
||||||
|
$result['mainText'] = JText::_('COM_SH404SEF_NOTHING_TO_EXPORT');
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('terminate');
|
||||||
|
// next step so to trigger download, as file is ready now
|
||||||
|
$this->_steps = array( 'next' => -2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get new start item
|
||||||
|
if (empty( $nextStart)) {
|
||||||
|
// this is first pass, starting from 0
|
||||||
|
$start = 0;
|
||||||
|
$nextStart = $start + self::MAX_PAGEIDS_PER_STEP;
|
||||||
|
if ($nextStart >= $this->_total) {
|
||||||
|
// reached the end
|
||||||
|
$nextStart = $this->_total;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$start = $nextStart;
|
||||||
|
$nextStart = $start + self::MAX_PAGEIDS_PER_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// are we done ? if so, move to next step
|
||||||
|
$result['hiddenText'] = '';
|
||||||
|
|
||||||
|
if ($start >= $this->_total) {
|
||||||
|
$result['mainText'] = JText::sprintf('COM_SH404SEF_EXPORT_DONE', $this->_total);
|
||||||
|
$result['mainText'] .= $this->_getTerminateOptions();
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('terminate');
|
||||||
|
// next step so to trigger download, as file is ready now
|
||||||
|
$this->_steps = array( 'next' => 2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// actually export items
|
||||||
|
$this->_export( $start);
|
||||||
|
|
||||||
|
// continuing for another round
|
||||||
|
$result['mainText'] = JText::sprintf('COM_SH404SEF_EXPORT_EXPORTING', $start + 1, $this->_total);
|
||||||
|
$result['hiddenText'] = '<input type="hidden" name="nextstart" value="'.$nextStart.'" />';
|
||||||
|
$result['nextStart'] = $nextStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result['continue'] = array( 'task' => 'next', 'nextstart' => $nextStart, 'filename' => base64_encode($this->_filename));
|
||||||
|
$result['continue'] = array_merge( $result['continue'], $this->_steps);
|
||||||
|
$result['hiddenText'] .= '<input type="hidden" name="filename" value="'.$this->_filename.'" />';
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last step, send results as download
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doDownload() {
|
||||||
|
|
||||||
|
|
||||||
|
// fake content
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
// get the current filename with path
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// get a more readable filename
|
||||||
|
$displayName = date('Y-m-d') . '_' . $this->_context . '_export.txt';
|
||||||
|
|
||||||
|
Sh404sefHelperFiles::triggerDownload( $this->_filename, $displayName);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doTerminate() {
|
||||||
|
|
||||||
|
// are we set to purge temporary files ?
|
||||||
|
$purgeTempFiles = JRequest::getInt( 'purge_temp_files', 0);
|
||||||
|
if (!empty($purgeTempFiles)) {
|
||||||
|
Sh404sefHelperFiles::purgeTempFiles( 'sh404sef_export_' . $this->_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now go back to main page
|
||||||
|
$result = array( 'redirectTo' => true);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doCancel() {
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
$result['redirectTo'] = true;
|
||||||
|
$result['redirectOptions'] = array( 'sh404sefMsg' => 'COM_SH404SEF_WIZARD_CANCELLED');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _export( $start) {
|
||||||
|
|
||||||
|
// do we have a valid filename
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// put some data in the file
|
||||||
|
$end = $start + self::MAX_PAGEIDS_PER_STEP + 1;
|
||||||
|
$end = $end > $this->_total ? $this->_total : $end;
|
||||||
|
|
||||||
|
// fetch pageIds record from model
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'urls', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'urls.default');
|
||||||
|
$options = (object) array('layout' => 'export', 'getMetaData' => true, 'getPageId' => false, 'simpleUrlList' => true);
|
||||||
|
$records = $model->getList( $options, $returnZeroElement = false, $start, $forcedLimit = self::MAX_PAGEIDS_PER_STEP);
|
||||||
|
|
||||||
|
// do we need a header written to the file, for first record
|
||||||
|
$header = $start == 0 ? Sh404sefHelperGeneral::getExportHeaders( $this->_context) . "\n" : '';
|
||||||
|
|
||||||
|
// format them for text file output
|
||||||
|
$data = '';
|
||||||
|
$counter = $start;
|
||||||
|
$glue = Sh404sefHelperFiles::$stringDelimiter . Sh404sefHelperFiles::$fieldDelimiter . Sh404sefHelperFiles::$stringDelimiter;
|
||||||
|
if (!empty( $records)) {
|
||||||
|
foreach( $records as $record) {
|
||||||
|
$counter++;
|
||||||
|
$textRecord = $record->oldurl . $glue . $record->newurl
|
||||||
|
. $glue . $record->cpt
|
||||||
|
. $glue . $record->rank
|
||||||
|
. $glue . $record->dateadd
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->metatitle)
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->metadesc)
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->metakey)
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->metalang)
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->metarobots)
|
||||||
|
. $glue . Sh404sefHelperFiles::csvQuote( $record->canonical)
|
||||||
|
;
|
||||||
|
$line = Sh404sefHelperFiles::$stringDelimiter . $counter . $glue . $textRecord . Sh404sefHelperFiles::$stringDelimiter;
|
||||||
|
$data .= $line . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare data for storage
|
||||||
|
if (!empty( $header)) {
|
||||||
|
// first record written to file, prepend header
|
||||||
|
$data = $header . $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store in file
|
||||||
|
$status = Sh404sefHelperFiles::appendToFile( $this->_filename, $data);
|
||||||
|
|
||||||
|
// return any error
|
||||||
|
return $status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getTerminateOptions() {
|
||||||
|
|
||||||
|
$options = '<br /><br />';
|
||||||
|
$options .= '<input type="checkbox" name="purge_temp_files" value="1" checked="checked" >';
|
||||||
|
$options .= JText::_('COM_SH404SEF_PURGE_TEMP_FILES');
|
||||||
|
$options .= '<br />';
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,315 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of page title and metas data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterExportview404 extends JObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array holding each step details
|
||||||
|
* A step is defined as a task, a view and a layout
|
||||||
|
* By default, task can be 'display', but still need
|
||||||
|
* to be defined in array
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $_stepsMap = array(
|
||||||
|
|
||||||
|
-2 => array( 'task' => 'doTerminate', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
,-1 => array( 'task' => 'doCancel', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 0 => array( 'task' => 'doStart', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 1 => array( 'task' => 'doExport', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 2 => array( 'task' => 'doDownload', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
public $_stepsCount = 0;
|
||||||
|
public $_steps = array( 'next' => 0, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
public $_button = '';
|
||||||
|
public $_buttonsList = array ('next', 'previous', 'terminate', 'cancel');
|
||||||
|
// visible buttons are displayed as toolbar pressbutton
|
||||||
|
// buttons not on that list are passed as 'hidden' post data
|
||||||
|
public $_visibleButtonsList = array ( 'previous', 'next', 'terminate', 'cancel');
|
||||||
|
|
||||||
|
|
||||||
|
protected $_context = 'view404';
|
||||||
|
protected $_total = 0;
|
||||||
|
protected $_parentController = null;
|
||||||
|
protected $_filename = '';
|
||||||
|
|
||||||
|
const MAX_PAGEIDS_PER_STEP = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, keep reference to controller
|
||||||
|
* which called the adapter
|
||||||
|
* @param unknown_type $parentController
|
||||||
|
*/
|
||||||
|
public function __construct( $parentController) {
|
||||||
|
|
||||||
|
$this->_parentController = $parentController;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
$this->_stepsCount = count( $this->_stepsMap);
|
||||||
|
|
||||||
|
// prepare data for controller
|
||||||
|
$properties = array();
|
||||||
|
|
||||||
|
$properties['_defaultController'] = 'wizard';
|
||||||
|
$properties['_defaultTask'] = '';
|
||||||
|
$properties['_defaultModel'] = '';
|
||||||
|
$properties['_defaultView'] = 'wizard';
|
||||||
|
$properties['_defaultLayout'] = 'default';
|
||||||
|
|
||||||
|
$properties['_returnController'] = 'urls';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'urls';
|
||||||
|
$properties['_returnLayout'] = 'view404';
|
||||||
|
$properties['_pageTitle'] = JText::_('COM_SH404SEF_EXPORTING_TITLE');
|
||||||
|
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First step, by default a message
|
||||||
|
* and a Terminate button
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doStart() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('next', 'cancel');
|
||||||
|
|
||||||
|
// A customiser :
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
$result['mainText'] = JText::_('COM_SH404SEF_EXPORT_VIEW404_START');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Second step, export data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doExport() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ();
|
||||||
|
|
||||||
|
// next steps definition
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
// exporting a limited set of pageids at a time
|
||||||
|
$nextStart = JRequest::getInt( 'nextstart', 0);
|
||||||
|
|
||||||
|
// are we adding to an existing data file ?
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// calculate number of items to export
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'urls', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'urls.view404');
|
||||||
|
$options = (object) array('layout' => 'view404');
|
||||||
|
$this->_total = $model->getTotal( $options);
|
||||||
|
|
||||||
|
// do we have anything to export ?
|
||||||
|
if (empty( $this->_total)) {
|
||||||
|
$result['mainText'] = JText::_('COM_SH404SEF_NOTHING_TO_EXPORT');
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('terminate');
|
||||||
|
// next step so to trigger download, as file is ready now
|
||||||
|
$this->_steps = array( 'next' => -2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get new start item
|
||||||
|
if (empty( $nextStart)) {
|
||||||
|
// this is first pass, starting from 0
|
||||||
|
$start = 0;
|
||||||
|
$nextStart = $start + self::MAX_PAGEIDS_PER_STEP;
|
||||||
|
if ($nextStart >= $this->_total) {
|
||||||
|
// reached the end
|
||||||
|
$nextStart = $this->_total;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$start = $nextStart;
|
||||||
|
$nextStart = $start + self::MAX_PAGEIDS_PER_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// are we done ? if so, move to next step
|
||||||
|
$result['hiddenText'] = '';
|
||||||
|
|
||||||
|
if ($start >= $this->_total) {
|
||||||
|
$result['mainText'] = JText::sprintf('COM_SH404SEF_EXPORT_DONE', $this->_total);
|
||||||
|
$result['mainText'] .= $this->_getTerminateOptions();
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('terminate');
|
||||||
|
// next step so to trigger download, as file is ready now
|
||||||
|
$this->_steps = array( 'next' => 2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// actually export items
|
||||||
|
$this->_export( $start);
|
||||||
|
|
||||||
|
// continuing for another round
|
||||||
|
$result['mainText'] = JText::sprintf('COM_SH404SEF_EXPORT_EXPORTING', $start + 1, $this->_total);
|
||||||
|
$result['hiddenText'] = '<input type="hidden" name="nextstart" value="'.$nextStart.'" />';
|
||||||
|
$result['nextStart'] = $nextStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result['continue'] = array( 'task' => 'next', 'nextstart' => $nextStart, 'filename' => base64_encode($this->_filename));
|
||||||
|
$result['continue'] = array_merge( $result['continue'], $this->_steps);
|
||||||
|
$result['hiddenText'] .= '<input type="hidden" name="filename" value="'.$this->_filename.'" />';
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last step, send results as download
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doDownload() {
|
||||||
|
|
||||||
|
|
||||||
|
// fake content
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
// get the current filename with path
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// get a more readable filename
|
||||||
|
$displayName = date('Y-m-d') . '_' . $this->_context . '_export.txt';
|
||||||
|
|
||||||
|
Sh404sefHelperFiles::triggerDownload( $this->_filename, $displayName);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doTerminate() {
|
||||||
|
|
||||||
|
// are we set to purge temporary files ?
|
||||||
|
$purgeTempFiles = JRequest::getInt( 'purge_temp_files', 0);
|
||||||
|
if (!empty($purgeTempFiles)) {
|
||||||
|
Sh404sefHelperFiles::purgeTempFiles( 'sh404sef_export_' . $this->_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now go back to main page
|
||||||
|
$result = array( 'redirectTo' => true);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doCancel() {
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
$result['redirectTo'] = true;
|
||||||
|
$result['redirectOptions'] = array( 'sh404sefMsg' => 'COM_SH404SEF_WIZARD_CANCELLED');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _export( $start) {
|
||||||
|
|
||||||
|
// do we have a valid filename
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_export_' . $this->_context);
|
||||||
|
|
||||||
|
// put some data in the file
|
||||||
|
$end = $start + self::MAX_PAGEIDS_PER_STEP + 1;
|
||||||
|
$end = $end > $this->_total ? $this->_total : $end;
|
||||||
|
|
||||||
|
// fetch pageIds record from model
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'urls', 'Sh404sefModel');
|
||||||
|
$model->setContext( 'urls.view404');
|
||||||
|
$options = (object) array('layout' => 'view404');
|
||||||
|
$records = $model->getList( $options, $returnZeroElement = false, $start, $forcedLimit = self::MAX_PAGEIDS_PER_STEP);
|
||||||
|
|
||||||
|
// do we need a header written to the file, for first record
|
||||||
|
$header = $start == 0 ? Sh404sefHelperGeneral::getExportHeaders( $this->_context) . "\n" : '';
|
||||||
|
|
||||||
|
// format them for text file output
|
||||||
|
$data = '';
|
||||||
|
$counter = $start;
|
||||||
|
$glue = Sh404sefHelperFiles::$stringDelimiter . Sh404sefHelperFiles::$fieldDelimiter . Sh404sefHelperFiles::$stringDelimiter;
|
||||||
|
if (!empty( $records)) {
|
||||||
|
foreach( $records as $record) {
|
||||||
|
$counter++;
|
||||||
|
$textRecord = $record->oldurl . $glue . $record->newurl
|
||||||
|
. $glue . $record->cpt
|
||||||
|
. $glue . $record->rank
|
||||||
|
. $glue . $record->dateadd
|
||||||
|
. $glue . ''//Sh404sefHelperFiles::csvQuote( $record->metatitle)
|
||||||
|
. $glue . ''//Sh404sefHelperFiles::csvQuote( $record->metadesc)
|
||||||
|
. $glue . ''//Sh404sefHelperFiles::csvQuote( $record->metakey)
|
||||||
|
. $glue . ''//Sh404sefHelperFiles::csvQuote( $record->metalang)
|
||||||
|
. $glue . ''//Sh404sefHelperFiles::csvQuote( $record->metarobots)
|
||||||
|
. Sh404sefHelperFiles::$stringDelimiter;
|
||||||
|
$line = Sh404sefHelperFiles::$stringDelimiter . $counter . $glue . $textRecord;
|
||||||
|
$data .= $line . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare data for storage
|
||||||
|
if (!empty( $header)) {
|
||||||
|
// first record written to file, prepend header
|
||||||
|
$data = $header . $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store in file
|
||||||
|
$status = Sh404sefHelperFiles::appendToFile( $this->_filename, $data);
|
||||||
|
|
||||||
|
// return any error
|
||||||
|
return $status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getTerminateOptions() {
|
||||||
|
|
||||||
|
$options = '<br /><br />';
|
||||||
|
$options .= '<input type="checkbox" name="purge_temp_files" value="1" checked="checked" >';
|
||||||
|
$options .= JText::_('COM_SH404SEF_PURGE_TEMP_FILES');
|
||||||
|
$options .= '<br />';
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of pageids data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterImportaliases extends Sh404sefClassImportgeneric {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
// let parent do their job
|
||||||
|
$properties = parent::setup();
|
||||||
|
|
||||||
|
// set context record
|
||||||
|
$this->_context = 'aliases';
|
||||||
|
|
||||||
|
// setup a few custom properties
|
||||||
|
$properties['_returnController'] = 'aliases';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'aliases';
|
||||||
|
$properties['_returnLayout'] = 'default';
|
||||||
|
|
||||||
|
// and return the whole thing
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a record in the database, based
|
||||||
|
* on data read from import file
|
||||||
|
*
|
||||||
|
* @param array $header an array of fields, as built from the header line
|
||||||
|
* @param string $line raw record obtained from import file
|
||||||
|
*/
|
||||||
|
protected function _createRecord( $header, $line) {
|
||||||
|
|
||||||
|
// extract the record
|
||||||
|
$line = $this->_lineToArray( $line);
|
||||||
|
|
||||||
|
// get table object to store record
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'aliases', 'Sh404sefModel');
|
||||||
|
|
||||||
|
// bind table to current record
|
||||||
|
$record = array();
|
||||||
|
$record['newurl'] = $line[3];
|
||||||
|
if ($record['newurl'] == '__ Homepage __') {
|
||||||
|
$record['newurl'] = sh404SEF_HOMEPAGE_CODE;
|
||||||
|
}
|
||||||
|
$record['alias'] = $line[1];
|
||||||
|
$record['type'] = $line[4];
|
||||||
|
|
||||||
|
|
||||||
|
// find if there is already same alias record for this non-sef url. If so
|
||||||
|
// we want the imported record to overwrite the existing one.
|
||||||
|
$existingRecords = $model->getByAttr( array( 'newurl' => $record['newurl'], 'alias' => $record['alias']));
|
||||||
|
if( !empty( $existingRecords)) {
|
||||||
|
$existingRecord = $existingRecords[0]; // getByAttr always returns an array
|
||||||
|
|
||||||
|
// use the existing id, this will be enought to override existing record when saving
|
||||||
|
$record['id'] = $existingRecord->id;
|
||||||
|
|
||||||
|
// ensure consistency : delete the remaining records, though there is no reason
|
||||||
|
// there can be more than one record with same alias AND same SEF
|
||||||
|
array_shift( $existingRecords);
|
||||||
|
if (!empty( $existingRecords)) {
|
||||||
|
ShlDbHelper::deleteIn( '#__sh404sef_aliases', 'id', $existingRecords, ShlDbHelper::INTEGER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save record : returns the record id, so failure is when 0 is returned
|
||||||
|
$saveId = $model->save( $record);
|
||||||
|
if(empty( $saveId)) {
|
||||||
|
// rethrow a more appropriate error message
|
||||||
|
throw new Sh404sefExceptionDefault( JText::sprintf( 'COM_SH404SEF_IMPORT_ERROR_INSERTING_INTO_DB', $line[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of pageids data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterImportpageids extends Sh404sefClassImportgeneric {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
// let parent do their job
|
||||||
|
$properties = parent::setup();
|
||||||
|
|
||||||
|
// set context record
|
||||||
|
$this->_context = 'pageids';
|
||||||
|
|
||||||
|
// setup a few custom properties
|
||||||
|
$properties['_returnController'] = 'pageids';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'pageids';
|
||||||
|
$properties['_returnLayout'] = 'default';
|
||||||
|
|
||||||
|
// and return the whole thing
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a record in the database, based
|
||||||
|
* on data read from import file
|
||||||
|
*
|
||||||
|
* @param array $header an array of fields, as built from the header line
|
||||||
|
* @param string $line raw record obtained from import file
|
||||||
|
*/
|
||||||
|
protected function _createRecord( $header, $line) {
|
||||||
|
|
||||||
|
// extract the record
|
||||||
|
$line = $this->_lineToArray( $line);
|
||||||
|
|
||||||
|
// get table object to store record
|
||||||
|
jimport( 'joomla.database.table');
|
||||||
|
$table = JTable::getInstance( 'pageids', 'Sh404sefTable');
|
||||||
|
|
||||||
|
// bind table to current record
|
||||||
|
$record = array();
|
||||||
|
$record['newurl'] = $line[3];
|
||||||
|
if ($record['newurl'] == '__ Homepage __') {
|
||||||
|
$record['newurl'] = sh404SEF_HOMEPAGE_CODE;
|
||||||
|
}
|
||||||
|
$record['pageid'] = $line[1];
|
||||||
|
$record['type'] = $line[4];
|
||||||
|
|
||||||
|
// save record
|
||||||
|
if (!$table->save( $record)) {
|
||||||
|
throw new Sh404sefExceptionDefault( JText::sprintf( 'COM_SH404SEF_IMPORT_ERROR_INSERTING_INTO_DB', $line[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,123 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of pageids data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterImportsh404sefmetas extends Sh404sefClassImportgeneric {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
// let parent do their job
|
||||||
|
$properties = parent::setup();
|
||||||
|
|
||||||
|
// set context record
|
||||||
|
$this->_context = 'sh404sefmetas';
|
||||||
|
|
||||||
|
// setup a few custom properties
|
||||||
|
$properties['_returnController'] = 'urls';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'urls';
|
||||||
|
$properties['_returnLayout'] = 'default';
|
||||||
|
|
||||||
|
// and return the whole thing
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a record in the database, based
|
||||||
|
* on data read from import file
|
||||||
|
*
|
||||||
|
* @param array $header an array of fields, as built from the header line
|
||||||
|
* @param string $line raw record obtained from import file
|
||||||
|
*/
|
||||||
|
protected function _createRecord( $header, $line) {
|
||||||
|
|
||||||
|
// extract the record
|
||||||
|
$line = $this->_lineToArray( trim( $line));
|
||||||
|
|
||||||
|
// get table object to store record
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'metas', 'Sh404sefModel');
|
||||||
|
|
||||||
|
// bind table to current record
|
||||||
|
$record = array();
|
||||||
|
$record['newurl'] = $line[1];
|
||||||
|
$record['metatitle'] = $line[4];
|
||||||
|
$record['metadesc'] = $line[2];
|
||||||
|
$record['metakey'] = $line[3];
|
||||||
|
$record['metalang'] = $line[5];
|
||||||
|
$record['metarobots'] = $line[6];
|
||||||
|
|
||||||
|
// clean up records
|
||||||
|
foreach( $record as $key => $value) {
|
||||||
|
if ($value == ' ') {
|
||||||
|
$record[$key] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find if there is already an url record for this non-sef url. If so
|
||||||
|
// we want the imported record to overwrite the existing one.
|
||||||
|
// while makinf sure we're doing that with the main url, not one of the duplicates
|
||||||
|
$existingRecords = $model->getByAttr( array( 'newurl' => $record['newurl']));
|
||||||
|
if( !empty( $existingRecords)) {
|
||||||
|
$existingRecord = $existingRecords[0]; // getByAttr always returns an array
|
||||||
|
|
||||||
|
// use the existing id, this will be enought to override existing record when saving
|
||||||
|
$record['id'] = $existingRecord->id;
|
||||||
|
|
||||||
|
// ensure consistency : delete the remaining records, though there is no reason
|
||||||
|
// there can be more than one record with same SEF AND same SEF
|
||||||
|
array_shift( $existingRecords);
|
||||||
|
if (!empty( $existingRecords)) {
|
||||||
|
ShlDbHelper::deleteIn( '#__sh404sef_metas', 'id', $existingRecords, ShlDbHelper::INTEGER);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$record['id'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save record : returns the record id, so failure is when 0 is returned
|
||||||
|
$status = $model->save( $record);
|
||||||
|
if (!$status) {
|
||||||
|
// rethrow a more appropriate error message
|
||||||
|
throw new Sh404sefExceptionDefault( JText::sprintf( 'COM_SH404SEF_IMPORT_ERROR_INSERTING_INTO_DB', $line[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return html for any option that could
|
||||||
|
* be presented to the user on the last
|
||||||
|
* page of the wizard (like clean temp files)
|
||||||
|
* for instance. This will be displayed just after
|
||||||
|
* the mainText text, as prepared by the main
|
||||||
|
* part of this controller
|
||||||
|
*/
|
||||||
|
protected function _getTerminateOptions() {
|
||||||
|
|
||||||
|
$options = JText::_( 'COM_SH404SEF_IMPORT_URLS_WARNING');
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,148 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of pageids data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterImportsh404sefurls extends Sh404sefClassImportgeneric {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
// let parent do their job
|
||||||
|
$properties = parent::setup();
|
||||||
|
|
||||||
|
// set context record
|
||||||
|
$this->_context = 'sh404sefurls';
|
||||||
|
|
||||||
|
// setup a few custom properties
|
||||||
|
$properties['_returnController'] = 'urls';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'urls';
|
||||||
|
$properties['_returnLayout'] = 'default';
|
||||||
|
|
||||||
|
// and return the whole thing
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a record in the database, based
|
||||||
|
* on data read from import file
|
||||||
|
*
|
||||||
|
* @param array $header an array of fields, as built from the header line
|
||||||
|
* @param string $line raw record obtained from import file
|
||||||
|
*/
|
||||||
|
protected function _createRecord( $header, $line) {
|
||||||
|
|
||||||
|
// extract the record
|
||||||
|
$line = $this->_lineToArray( trim($line));
|
||||||
|
|
||||||
|
// get table object to store record
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'editurl', 'Sh404sefModel');
|
||||||
|
|
||||||
|
// bind table to current record
|
||||||
|
$record = array();
|
||||||
|
$record['oldurl'] = $line[3];
|
||||||
|
$record['newurl'] = $line[4];
|
||||||
|
if ($record['newurl'] == '__ Homepage __') {
|
||||||
|
$record['newurl'] = sh404SEF_HOMEPAGE_CODE;
|
||||||
|
}
|
||||||
|
$record['cpt'] = $line[1];
|
||||||
|
$record['rank'] = $line[2];
|
||||||
|
$record['dateadd'] = $line[5];
|
||||||
|
$record['metatitle'] = '';
|
||||||
|
$record['metadesc'] = '';
|
||||||
|
$record['metakey'] = '';
|
||||||
|
$record['metalang'] = '';
|
||||||
|
$record['metarobots'] = '';
|
||||||
|
|
||||||
|
// find if there is already an url record for this non-sef url. If so
|
||||||
|
// we want the imported record to overwrite the existing one.
|
||||||
|
// while makinf sure we're doing that with the main url, not one of the duplicates
|
||||||
|
$existingRecords = $model->getByAttr( array( 'newurl' => $record['newurl'], 'oldurl' => $record['oldurl']));
|
||||||
|
if( !empty( $existingRecords)) {
|
||||||
|
$existingRecord = $existingRecords[0]; // getByAttr always returns an array
|
||||||
|
|
||||||
|
// use the existing id, this will be enought to override existing record when saving
|
||||||
|
$record['id'] = $existingRecord->id;
|
||||||
|
|
||||||
|
// ensure consistency : delete the remaining records, though there is no reason
|
||||||
|
// there can be more than one record with same SEF AND same SEF
|
||||||
|
array_shift( $existingRecords);
|
||||||
|
if (!empty( $existingRecords)) {
|
||||||
|
ShlDbHelper::deleteIn( '#__sh404sef_urls', 'id', $existingRecords, ShlDbHelper::INTEGER);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$record['id'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find if we already have a meta data record for this non-sef url
|
||||||
|
// as we want to update it if so, instead of creating a new record
|
||||||
|
$metasModel = ShlMvcModel_Base::getInstance( 'metas', 'Sh404sefModel');
|
||||||
|
$existingMetas = $metasModel->getByAttr( array( 'newurl' => $record['newurl']));
|
||||||
|
if( !empty( $existingMetas)) {
|
||||||
|
$existingMeta = $existingMetas[0]; // getByAttr always returns an array
|
||||||
|
|
||||||
|
// use the existing id, this will be enought to override existing record when saving
|
||||||
|
$record['meta_id'] = $existingMeta->id;
|
||||||
|
} else {
|
||||||
|
$record['meta_id'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for aliases, we don't import them here, but we need to create a dummy
|
||||||
|
// record so as to preserve possible pre-existing aliases for the same non-sef url
|
||||||
|
$aliasesModel = ShlMvcModel_Base::getInstance( 'editalias', 'Sh404sefModel');
|
||||||
|
$existingAliases = $aliasesModel->getByAttr( array( 'newurl' => $record['newurl']));
|
||||||
|
$record['shAliasList'] = '';
|
||||||
|
if( !empty( $existingAliases)) {
|
||||||
|
foreach( $existingAliases as $existingAlias) {
|
||||||
|
// build up a text list, just as if we were to edit aliases
|
||||||
|
// as this is what the model expect to receive
|
||||||
|
$record['shAliasList'] .= $existingAlias->alias . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save record : returns the record id, so failure is when 0 is returned
|
||||||
|
$savedId = $model->save( $record, sh404SEF_URLTYPE_AUTO);
|
||||||
|
if (empty( $savedId)) {
|
||||||
|
// rethrow a more appropriate error message
|
||||||
|
throw new Sh404sefExceptionDefault( JText::sprintf( 'COM_SH404SEF_IMPORT_ERROR_INSERTING_INTO_DB', $line[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return html for any option that could
|
||||||
|
* be presented to the user on the last
|
||||||
|
* page of the wizard (like clean temp files)
|
||||||
|
* for instance. This will be displayed just after
|
||||||
|
* the mainText text, as prepared by the main
|
||||||
|
* part of this controller
|
||||||
|
*/
|
||||||
|
protected function _getTerminateOptions() {
|
||||||
|
|
||||||
|
$options = JText::_( 'COM_SH404SEF_IMPORT_URLS_WARNING');
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of pageids data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterImporturls extends Sh404sefClassImportgeneric {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
// let parent do their job
|
||||||
|
$properties = parent::setup();
|
||||||
|
|
||||||
|
// set context record
|
||||||
|
$this->_context = 'urls';
|
||||||
|
|
||||||
|
// setup a few custom properties
|
||||||
|
$properties['_returnController'] = 'urls';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'urls';
|
||||||
|
$properties['_returnLayout'] = 'default';
|
||||||
|
|
||||||
|
// and return the whole thing
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a record in the database, based
|
||||||
|
* on data read from import file
|
||||||
|
*
|
||||||
|
* @param array $header an array of fields, as built from the header line
|
||||||
|
* @param string $line raw record obtained from import file
|
||||||
|
*/
|
||||||
|
protected function _createRecord( $header, $line) {
|
||||||
|
|
||||||
|
// extract the record
|
||||||
|
$line = $this->_lineToArray( $line);
|
||||||
|
|
||||||
|
// get table object to store record
|
||||||
|
$model = ShlMvcModel_Base::getInstance( 'editurl', 'Sh404sefModel');
|
||||||
|
|
||||||
|
// bind table to current record
|
||||||
|
$record = array();
|
||||||
|
$record['oldurl'] = $line[1];
|
||||||
|
$record['newurl'] = $line[2];
|
||||||
|
if ($record['newurl'] == '__ Homepage __') {
|
||||||
|
$record['newurl'] = sh404SEF_HOMEPAGE_CODE;
|
||||||
|
}
|
||||||
|
$record['cpt'] = $line[3];
|
||||||
|
$record['rank'] = $line[4];
|
||||||
|
$record['dateadd'] = $line[5];
|
||||||
|
$record['metatitle'] = $line[6];
|
||||||
|
$record['metadesc'] = $line[7];
|
||||||
|
$record['metakey'] = $line[8];
|
||||||
|
$record['metalang'] = $line[9];
|
||||||
|
$record['metarobots'] = $line[10];
|
||||||
|
$record['canonical'] = $line[11];
|
||||||
|
|
||||||
|
// find if there is already an url record for this non-sef url. If so
|
||||||
|
// we want the imported record to overwrite the existing one.
|
||||||
|
// while makinf sure we're doing that with the main url, not one of the duplicates
|
||||||
|
$existingRecords = $model->getByAttr( array( 'newurl' => $record['newurl'], 'oldurl' => $record['oldurl']));
|
||||||
|
if( !empty( $existingRecords)) {
|
||||||
|
$existingRecord = $existingRecords[0]; // getByAttr always returns an array
|
||||||
|
|
||||||
|
// use the existing id, this will be enought to override existing record when saving
|
||||||
|
$record['id'] = $existingRecord->id;
|
||||||
|
|
||||||
|
// ensure consistency : delete the remaining records, though there is no reason
|
||||||
|
// there can be more than one record with same SEF AND same SEF
|
||||||
|
array_shift( $existingRecords);
|
||||||
|
if (!empty( $existingRecords)) {
|
||||||
|
ShlDbHelper::deleteIn( '#__sh404sef_urls', 'id', $existingRecords, ShlDbHelper::INTEGER);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$record['id'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find if we already have a meta data record for this non-sef url
|
||||||
|
// as we want to update it if so, instead of creating a new record
|
||||||
|
$metasModel = ShlMvcModel_Base::getInstance( 'metas', 'Sh404sefModel');
|
||||||
|
$existingMetas = $metasModel->getByAttr( array( 'newurl' => $record['newurl']));
|
||||||
|
if( !empty( $existingMetas)) {
|
||||||
|
$existingMeta = $existingMetas[0]; // getByAttr always returns an array
|
||||||
|
|
||||||
|
// use the existing id, this will be enought to override existing record when saving
|
||||||
|
$record['meta_id'] = $existingMeta->id;
|
||||||
|
} else {
|
||||||
|
$record['meta_id'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for aliases, we don't import them here, but we need to create a dummy
|
||||||
|
// record so as to preserve possible pre-existing aliases for the same non-sef url
|
||||||
|
$aliasesModel = ShlMvcModel_Base::getInstance( 'editalias', 'Sh404sefModel');
|
||||||
|
$existingAliases = $aliasesModel->getByAttr( array( 'newurl' => $record['newurl']));
|
||||||
|
$record['shAliasList'] = '';
|
||||||
|
if( !empty( $existingAliases)) {
|
||||||
|
foreach( $existingAliases as $existingAlias) {
|
||||||
|
// build up a text list, just as if we were to edit aliases
|
||||||
|
// as this is what the model expect to receive
|
||||||
|
$record['shAliasList'] .= $existingAlias->alias . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save record : returns the record id, so failure is when 0 is returned
|
||||||
|
$savedId = $model->save( $record, sh404SEF_URLTYPE_AUTO);
|
||||||
|
if (empty( $savedId)) {
|
||||||
|
// rethrow a more appropriate error message
|
||||||
|
throw new Sh404sefExceptionDefault( JText::sprintf( 'COM_SH404SEF_IMPORT_ERROR_INSERTING_INTO_DB', $line[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return html for any option that could
|
||||||
|
* be presented to the user on the last
|
||||||
|
* page of the wizard (like clean temp files)
|
||||||
|
* for instance. This will be displayed just after
|
||||||
|
* the mainText text, as prepared by the main
|
||||||
|
* part of this controller
|
||||||
|
*/
|
||||||
|
protected function _getTerminateOptions() {
|
||||||
|
|
||||||
|
$options = JText::_( 'COM_SH404SEF_IMPORT_URLS_WARNING');
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<html><body bgcolor="#FFFFFF"></body></html>
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement Joomsef installer
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefAdapterJoomsefinstaller extends Sh404sefClassBaseinstalladapter {
|
||||||
|
|
||||||
|
protected $_group = 'sh404sefextjoomsef';
|
||||||
|
protected $_installType = 'sef_ext';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix Joomsef manifest files, to force upgrade method
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function _fixManifest() {
|
||||||
|
|
||||||
|
jimport( 'joomla.filesystem.file');
|
||||||
|
|
||||||
|
// fix original file
|
||||||
|
$source = $this->parent->getPath( 'source');
|
||||||
|
$path = $source . '/' . $this->_getElement() . '.xml';
|
||||||
|
$fileContent = JFile::read( $path);
|
||||||
|
if(!empty( $fileContent)) {
|
||||||
|
$fileContent = str_replace( 'type="sef_ext"', 'type="sef_ext" method="upgrade"', $fileContent);
|
||||||
|
|
||||||
|
$defaults = array();
|
||||||
|
$remoteConfig = Sh404sefHelperUpdates::getRemoteConfig( $forced = false);
|
||||||
|
$remotes = empty($remoteConfig->config['joomsef_prefixes']) ? array() : $remoteConfig->config['joomsef_prefixes'];
|
||||||
|
$prefixes = array_unique( array_merge( $defaults, $remotes));
|
||||||
|
foreach( $prefixes as $prefix) {
|
||||||
|
$fileContent = preg_replace( '/function\s*' . preg_quote( $prefix) . '\s*\(\s*\)\s*\{/isU', 'function ' . $prefix . '() { return;', $fileContent);
|
||||||
|
}
|
||||||
|
// generic replace
|
||||||
|
$defaultReplaces = array();
|
||||||
|
$remoteReplaces = empty($remoteConfig->config['joomsef_prefixes']) ? array() : $remoteConfig->config['joomsef_prefixes'];
|
||||||
|
$replaces = array_unique( array_merge( $defaultReplaces, $remoteReplaces));
|
||||||
|
foreach( $replaces as $replace) {
|
||||||
|
$fileContent = preg_replace( '/' . $replace['source'] . '/sU', $replace['target'], $fileContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// group="seo" is of no use for us, so leave it behind
|
||||||
|
$written = JFile::write( $path, $fileContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix in memory object, by killing it, thus prompting recreation
|
||||||
|
$manifest = $this->parent->getManifest();
|
||||||
|
$manifest = null;
|
||||||
|
$manifest = $this->parent->getManifest();
|
||||||
|
$this->manifest = & $manifest->document;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get unique element id for the plugin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function _getElement($xml) {
|
||||||
|
|
||||||
|
$element = parent::_getElement( $xml);
|
||||||
|
|
||||||
|
return 'com_' . $element;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC'))
|
||||||
|
die('Direct Access to this location is not allowed.');
|
||||||
|
if (is_readable(JPATH_ADMINISTRATOR . '/components/com_sh404sef/sh404sef.php'))
|
||||||
|
{
|
||||||
|
require_once 'sh404sef.php';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo 'Missing main sh404SEF file: probably corrupted installation.';
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
#sbox-btn-close {display: none;}
|
||||||
|
|
||||||
|
#sbox-window.sh404sef-popup {
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sbox-overlay.sh404sef-popup {
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh404sef-popup #content-box {
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-48-sh404sef { background-image: url(../images/icon-48-sh404sef-logo.png); }
|
||||||
|
|
||||||
|
.icon-32-purge { background-image: url(../images/icon-32-purge.png); }
|
||||||
|
.icon-32-purgeselected { background-image: url(../images/icon-32-purgeselected.png); }
|
||||||
|
|
||||||
|
div.sh404sef-toolbar-title {
|
||||||
|
font-size: 22px; font-weight: bold; color: #0B55C4; line-height: 48px;
|
||||||
|
padding-left: 135px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.adminlist input.inputbox,
|
||||||
|
table.adminlist textarea.inputbox,
|
||||||
|
table.adminlist select.inputbox,
|
||||||
|
table.adminlist img.inputbox,
|
||||||
|
table.adminlist button.inputbox {
|
||||||
|
float: left;
|
||||||
|
clear: none;
|
||||||
|
min-width: 0px;
|
||||||
|
margin: 5px 5px 5px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.adminlist label.radiobtn,
|
||||||
|
table.adminlist label.radiobtn {
|
||||||
|
float: left;
|
||||||
|
clear: none;
|
||||||
|
min-width: 0px;
|
||||||
|
margin: 5px 10px 5px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-message-box ul{
|
||||||
|
color: #0055BB;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #C3D2E5;
|
||||||
|
background-image: url(../images/notice-info.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-error-box ul{
|
||||||
|
color: #c00;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #E6C0C0;
|
||||||
|
background-image: url(../images/notice-alert.png);
|
||||||
|
border-color: #DE7A7B;
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
/*start list by component */
|
||||||
|
div.current ul.listBycomponent li {
|
||||||
|
width: 25%;
|
||||||
|
float: left;
|
||||||
|
display: table-cell;
|
||||||
|
height: 30px;
|
||||||
|
padding-top: 3px !important;
|
||||||
|
}
|
||||||
@ -0,0 +1,198 @@
|
|||||||
|
.big {
|
||||||
|
height: 25px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 25px;
|
||||||
|
pading-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hasTip img {
|
||||||
|
vertical-align: baseline;
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current label,div.current span.faux-label {
|
||||||
|
clear: none !important;
|
||||||
|
float: left !important;
|
||||||
|
min-width: 200px !important;
|
||||||
|
margin-top: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current fieldset.radio label {
|
||||||
|
min-width: 45px !important;
|
||||||
|
margin-top: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current span.hasTip {
|
||||||
|
clear: left;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current li {
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current li:nth-child(odd) {
|
||||||
|
background-color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current li:nth-child(even) {
|
||||||
|
background-color: #EFEFEF;
|
||||||
|
}
|
||||||
|
/*div.current li:hover {
|
||||||
|
background-color:#FAFAFA;
|
||||||
|
}*/
|
||||||
|
div.current li span.spacer {
|
||||||
|
float: left;
|
||||||
|
clear: both;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px dotted lightGrey;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
/*start list by component */
|
||||||
|
div.current ul.listBycomponent li {
|
||||||
|
width: 22%;
|
||||||
|
float: left;
|
||||||
|
display: table-cell;
|
||||||
|
height: 30px;
|
||||||
|
padding-top: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul.listBycomponent li.listsroweven {
|
||||||
|
background-color: #EFEFEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul.listBycomponent li.listsrowodd {
|
||||||
|
background-color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul.listBycomponent li.listsrowodd:hover {
|
||||||
|
background-color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul.listBycomponent li.listsroweven:hover {
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul.listBycomponent li.listsrow0 {
|
||||||
|
height: 15px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current li.listBycomponent span.spacer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul.listBycomponent li.listsrow0 span.hasTip {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul.listBycomponent li input,div.current ul.listBycomponent li select
|
||||||
|
{
|
||||||
|
width: 95%;
|
||||||
|
float: left;
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul.listBycomponent li label {
|
||||||
|
min-height: 12px;
|
||||||
|
width: 95%;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #006699;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start list error document */
|
||||||
|
div.current ul li.errorpage {
|
||||||
|
width: 30%;
|
||||||
|
float: left;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul li.errorpage ul li {
|
||||||
|
list-style-type: disc;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul li.errorpage0 {
|
||||||
|
float: left;
|
||||||
|
min-width: 820px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current ul li.errorpage1 {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.config-option-list,ul.config-option-list li {
|
||||||
|
padding: 7px 2px 7px 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current input,div.current textarea,div.current select {
|
||||||
|
margin: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current fieldset.radio {
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.current fieldset.radio input {
|
||||||
|
margin-top: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.sh404sef-textinput {
|
||||||
|
font-size: 1.091em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.sh404sef-additionaltext {
|
||||||
|
font-size: 1.091em;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-sliders ul#rules li {
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-horizontal .shlegend-label .control-label {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.form-horizontal .shlegend-label .control-label legend {
|
||||||
|
margin-bottom: 0.3em;
|
||||||
|
}
|
||||||
|
.form-horizontal .shrules .controls {
|
||||||
|
margin-left:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shinfo-icon-wrapper {
|
||||||
|
width: 14px;
|
||||||
|
height: 25px;
|
||||||
|
line-height: 18px;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.tooltip-inner {
|
||||||
|
max-width: 300px;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.tooltip-inner h4 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.tip-wrap {
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.tip-text {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
.sh404sef-popup #content-box {
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-48-sh404sef { background-image: url(../images/icon-48-sh404sef-logo.png); }
|
||||||
|
.icon-48-warning { background-image: url(../images/icon-48-warning.png); }
|
||||||
|
.icon-32-confirmeddeletepageids { background-image: url(../images/icon-32-delete.png); }
|
||||||
|
.icon-32-confirmedpurgepageids { background-image: url(../images/icon-32-delete.png); }
|
||||||
|
.icon-32-confirmeddeldup { background-image: url(../images/icon-32-delete.png); }
|
||||||
|
|
||||||
|
div.sh404sef-toolbar-title {
|
||||||
|
font-size: 22px; font-weight: bold; color: #0B55C4; line-height: 48px;
|
||||||
|
padding-left: 135px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.headerconfirm {
|
||||||
|
font-size: 22px; font-weight: bold; color: #0B55C4; line-height: 48px;
|
||||||
|
padding-left: 10px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh404sef-popup td.key {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh-ajax-loading {
|
||||||
|
background-image: url(../images/sh-ajax-loader-wide.gif);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-message-box ul{
|
||||||
|
color: #0055BB;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #C3D2E5;
|
||||||
|
background-image: url(../images/notice-info.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-error-box ul{
|
||||||
|
color: #c00;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #E6C0C0;
|
||||||
|
background-image: url(../images/notice-alert.png);
|
||||||
|
border-color: #DE7A7B;
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<html><body bgcolor="#FFFFFF"></body></html>
|
||||||
@ -0,0 +1,329 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
#sbox-btn-close {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sbox-window.sh404sef-popup {
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sbox-overlay.sh404sef-popup {
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-48-sh404sef {
|
||||||
|
background-image: url(../images/icon-48-sh404sef-logo.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-48-save {
|
||||||
|
background-image: url(../images/icon-48-save.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
dt#config span {
|
||||||
|
color: #0B55C4;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt#management span {
|
||||||
|
color: #0B55C4;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt#analytics span {
|
||||||
|
color: #0B55C4;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt#qcontrol span {
|
||||||
|
color: #0B55C4;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt#security span {
|
||||||
|
color: #0B55C4;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt#infos span {
|
||||||
|
color: #0B55C4;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt#stats span {
|
||||||
|
color: #0B55C4;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.largertext {
|
||||||
|
display: inline;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shlargerkey {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol {
|
||||||
|
border-collapse: collapse;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol td {
|
||||||
|
padding: 1px 1px 1px 1px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol table.adminlist tbody tr td {
|
||||||
|
background: #f4f4f4;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol thead td {
|
||||||
|
background: #ffffff;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol td.spacer {
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol td.divider {
|
||||||
|
border-right: 1px solid #e0e0e0;
|
||||||
|
width: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol span {
|
||||||
|
float: none;
|
||||||
|
width: 80px;
|
||||||
|
height: 32px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: block;
|
||||||
|
background-position: center top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol td.qbutton {
|
||||||
|
text-align: center;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol td.qbutton span {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol a {
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 1px solid #fbfbfb;
|
||||||
|
padding: 1px 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol a:hover {
|
||||||
|
border-left: 1px solid #e0e0e0;
|
||||||
|
border-top: 1px solid #e0e0e0;
|
||||||
|
border-right: 1px solid #ccc;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #0B55C4;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol input.inputbox,table.qcontrol textarea.inputbox,table.qcontrol select.inputbox,table.qcontrol img.inputbox,table.qcontrol button.inputbox
|
||||||
|
{
|
||||||
|
float: left;
|
||||||
|
clear: none;
|
||||||
|
min-width: 0px;
|
||||||
|
margin: 5px 5px 5px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.qcontrol table.adminlist label {
|
||||||
|
float: left;
|
||||||
|
clear: none;
|
||||||
|
min-width: 0px;
|
||||||
|
margin: 5px 10px 5px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sh404sef-toolbar-title {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #0B55C4;
|
||||||
|
line-height: 48px;
|
||||||
|
padding-left: 135px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh-ajax-loading {
|
||||||
|
background-image: url(../images/sh-ajax-loader-wide.gif);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-block {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#left.cp-block {
|
||||||
|
width: 55%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#right.cp-block {
|
||||||
|
float: right;
|
||||||
|
width: 44%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#right-top {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.cp-icons-config {
|
||||||
|
float: left;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.cp-icons-others {
|
||||||
|
float: left;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpanel div.iconconfig {
|
||||||
|
text-align: center;
|
||||||
|
margin-right: 5px;
|
||||||
|
float: left;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpanel div.iconconfig a {
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
height: 97px;
|
||||||
|
width: 108px;
|
||||||
|
color: green;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpanel div.iconconfig a:hover {
|
||||||
|
border-left: 1px solid #eee;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
border-right: 1px solid #ccc;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
background: #f9f9f9;
|
||||||
|
color: #0B55C4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpanel div.iconothers {
|
||||||
|
text-align: center;
|
||||||
|
margin-right: 5px;
|
||||||
|
float: left;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpanel div.iconothers img,#cpanel div.iconconfig img {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpanel div.iconothers a {
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
height: 97px;
|
||||||
|
width: 108px;
|
||||||
|
/*color: #666; */
|
||||||
|
color: blue;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpanel div.iconothers a:hover {
|
||||||
|
border-left: 1px solid #eee;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
border-right: 1px solid #ccc;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
background: #f9f9f9;
|
||||||
|
color: #0B55C4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh404sef-analytics-wrapper {
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analytics-report-image img {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.hasAnalyticsTip {
|
||||||
|
display: inline;
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*div.current input, div.current textarea, div.current select*/
|
||||||
|
div.sh404sef-analytics select#accountId, div.sh404sef-analytics input#accountId, div.sh404sef-analytics textarea#accountId {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-message-box ul{
|
||||||
|
color: #0055BB;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #C3D2E5;
|
||||||
|
background-image: url(../images/notice-info.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-error-box ul{
|
||||||
|
color: #c00;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #E6C0C0;
|
||||||
|
background-image: url(../images/notice-alert.png);
|
||||||
|
border-color: #DE7A7B;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sh404sef-footer-container {
|
||||||
|
clear: both;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px #DDDDDD solid;
|
||||||
|
background: none repeat scroll 0 0 #EDEDED;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
font-style: italic;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
margin-top: 1.5em;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
.sh404sef-popup #content-box {
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-48-sh404sef { background-image: url(../images/icon-48-sh404sef-logo.png); }
|
||||||
|
.icon-32-cpanel { background-image: url(../images/icon-32-cpanel.png); }
|
||||||
|
|
||||||
|
div.sh404sef-toolbar-title {
|
||||||
|
font-size: 22px; font-weight: bold; color: #0B55C4; line-height: 48px;
|
||||||
|
padding-left: 135px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh404sef-popup td.key {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh-ajax-loading {
|
||||||
|
background-image: url(../images/sh-ajax-loader-wide.gif);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mainurl {
|
||||||
|
|
||||||
|
font-size: 22px; font-weight: bold; color: #0B55C4; line-height: 48px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-message-box ul{
|
||||||
|
color: #0055BB;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #C3D2E5;
|
||||||
|
background-image: url(../images/notice-info.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-error-box ul{
|
||||||
|
color: #c00;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #E6C0C0;
|
||||||
|
background-image: url(../images/notice-alert.png);
|
||||||
|
border-color: #DE7A7B;
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
.icon-48-sh404sef {
|
||||||
|
background-image: url(../images/icon-48-sh404sef-logo.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-48-save {
|
||||||
|
background-image: url(../images/icon-48-save.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.largertext {
|
||||||
|
display: inline;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shlargerkey {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sh404sef-toolbar-title {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #0B55C4;
|
||||||
|
line-height: 48px;
|
||||||
|
padding-left: 135px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toolbar-sh-progress-button-cpprogress {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh-ajax-loading {
|
||||||
|
background-image: url(../images/sh-ajax-loader-wide.gif);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh404sef-analytics-wrapper {
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analytics-report-image img {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.hasAnalyticsTip {
|
||||||
|
display: inline;
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*div.current input, div.current textarea, div.current select*/
|
||||||
|
div.sh404sef-analytics select#accountId,div.sh404sef-analytics input#accountId,div.sh404sef-analytics textarea#accountId
|
||||||
|
{
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.hero-unit {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.tooltip-inner {
|
||||||
|
max-width: 300px;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.tooltip-inner h4 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-center, td.shl-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.analytics-report-image {
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Fix for toolbar
|
||||||
|
*/
|
||||||
|
@media ( min-width : 480px) {
|
||||||
|
.shl-secondary-toolbar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media ( max-width : 480px) {
|
||||||
|
.shl-secondary-toolbar {
|
||||||
|
display: inherit !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
#editurl-container textarea {
|
||||||
|
width:90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#editurl-container input {
|
||||||
|
width:90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.tooltip-inner {
|
||||||
|
max-width: 300px;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.tooltip-inner h4 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.tip-wrap {
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.tip-text {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
@ -0,0 +1,571 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
.table td.shl-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-left button.btn {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-centered {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-middle {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-centered {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-id {
|
||||||
|
width: 4%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-id {
|
||||||
|
text-align: right;
|
||||||
|
padding-top: 12px;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-check {
|
||||||
|
width: 2%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-check {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-shurl {
|
||||||
|
width: 6%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-shurl {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-rank {
|
||||||
|
width: 6%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-rank {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-sef {
|
||||||
|
max-width: 250px !important;
|
||||||
|
width: 35%;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-sef {
|
||||||
|
text-align: left;
|
||||||
|
max-width: 250px !important;
|
||||||
|
width: 35%;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-sef span {
|
||||||
|
max-width: 250px !important;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-sef button {
|
||||||
|
text-align: left;
|
||||||
|
max-width: 250px !important;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-nonsef {
|
||||||
|
width: 25%;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-nonsef {
|
||||||
|
text-align: left;
|
||||||
|
max-width: 250px !important;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-icon {
|
||||||
|
width: 7%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-icon {
|
||||||
|
padding-top: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-hits {
|
||||||
|
width: 5%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-hits {
|
||||||
|
text-align: right;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-metatitle {
|
||||||
|
width: 25%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-metatitle {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-metadesc {
|
||||||
|
width: 25%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td.shl-list-metadesc {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th.shl-list-large-buttons {
|
||||||
|
width: 27%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.shl-line-wrap350 {
|
||||||
|
max-width: 350px !important;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.shl-line-wrap350 {
|
||||||
|
max-width: 350px !important;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shmodal-header h3 {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh-ajax-loading {
|
||||||
|
background-image: url(../images/sh-ajax-loader-wide.gif);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#sh-progress-cpprogress {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** z-index fixes **/
|
||||||
|
.shl-z-m-100 {
|
||||||
|
z-index: -100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-z-m-200 {
|
||||||
|
z-index: -200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-z-100 {
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-z-200 {
|
||||||
|
z-index: 200;
|
||||||
|
}
|
||||||
|
/** main content **/
|
||||||
|
.shl-main-content {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-isis-white-top {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
height: 78px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** modals **/
|
||||||
|
.shmodal-content {
|
||||||
|
padding-top: 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shmodal-toolbar {
|
||||||
|
position: fixed;
|
||||||
|
background-color: #fff;
|
||||||
|
height: 54px;
|
||||||
|
z-index: 3000;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shmodal-toolbar-wrapper {
|
||||||
|
height: 30px;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shmodal-toolbar div.alert {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shmodal-toolbar-text {
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 6px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shmodal-toolbar-buttons {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#shl-modal-searchbar-right-block,div#shl-main-searchbar-right-block {
|
||||||
|
margin-left: 0;
|
||||||
|
padding-left: 8px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#shl-main-searchbar-right-block {
|
||||||
|
/* box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-main-searchbar-wrapper {
|
||||||
|
z-index: 1010;
|
||||||
|
background-color: #fff;
|
||||||
|
height: 48px;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
padding-left: 2%;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-modal-searchbar-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
height: 34px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-bottom-box-shadow {
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-main-list-wrapper div.alert {
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-main-list-wrapper-padding {
|
||||||
|
padding-top: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-modal-list-wrapper {
|
||||||
|
padding-top: 34px;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Generic **/
|
||||||
|
.shl-left-separator {
|
||||||
|
padding-left: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-right-separator {
|
||||||
|
padding-right: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-fixed {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-modal-searchbar-wrapper div.pagination-toolbar {
|
||||||
|
float: right;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.shl-no-margin,div.shl-no-margin {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#shl-sidebar-container {
|
||||||
|
padding-top: 10px;
|
||||||
|
margin: 0;
|
||||||
|
z-index: 1020;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-no-margin-left,div.shl-no-margin-left {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#COM_SH404SEF_DEF_404_PAGE .controls {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.shl-fixed-header {
|
||||||
|
background-color: #184A7D;
|
||||||
|
background-image: linear-gradient(to bottom, #17568C, #1A3867);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
padding: 5px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 30;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1020;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-fixed-subheader {
|
||||||
|
background: -moz-linear-gradient(center top, #FFFFFF 0%, #EDEDED 100%)
|
||||||
|
repeat scroll 0 0 transparent;
|
||||||
|
border-bottom: 1px solid #D3D3D3;
|
||||||
|
color: #0C192E;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
text-shadow: 0 1px 0 #FFFFFF;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 77px;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.shl-fixed-top-hidden {
|
||||||
|
height: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** collapsible main menu **/
|
||||||
|
.shl-navbar {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-navbar-fixed-top .shl-navbar-inner,.shl-navbar-fixed-top .shl-navbar-inner .container-fluid
|
||||||
|
{
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-navbar .brand {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-navbar .btn-navbar {
|
||||||
|
margin-top: 3px;
|
||||||
|
margin-right: 3px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-navbar .btn-navbar {
|
||||||
|
background-color: #5BB75B;
|
||||||
|
background-image: linear-gradient(to bottom, #62C462, #51A351);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||||
|
margin-bottom: 2px;
|
||||||
|
display: block;
|
||||||
|
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||||
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.1) inset, 0 1px 0
|
||||||
|
rgba(255, 255, 255, 0.075);
|
||||||
|
float: left;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
padding: 7px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-navbar .btn-navbar.btn:hover {
|
||||||
|
background-color: #5BB75B;
|
||||||
|
background-position: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-navbar .btn-navbar .icon-bar {
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
border-radius: 1px 1px 1px 1px;
|
||||||
|
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
|
||||||
|
display: block;
|
||||||
|
height: 2px;
|
||||||
|
width: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-nav-collapse .nav .nav-header {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-nav-collapse.collapse.in {
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-nav-collapse .nav,.shl-navbar .shl-nav-collapse .nav.pull-right {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-nav-collapse .dropdown-menu {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-nav-collapse .nav>li>a.dropdown-toggle {
|
||||||
|
background-color: rgba(255, 255, 255, 0.07);
|
||||||
|
background-image: -moz-linear-gradient(top, rgba(255, 255, 255, 0.15),
|
||||||
|
rgba(255, 255, 255, 0.05) );
|
||||||
|
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(255, 255, 255, 0.15)
|
||||||
|
), to(rgba(255, 255, 255, 0.05) ) );
|
||||||
|
background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.15),
|
||||||
|
rgba(255, 255, 255, 0.05) );
|
||||||
|
background-image: -o-linear-gradient(top, rgba(255, 255, 255, 0.15),
|
||||||
|
rgba(255, 255, 255, 0.05) );
|
||||||
|
background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.15),
|
||||||
|
rgba(255, 255, 255, 0.05) );
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#26ffffff',
|
||||||
|
endColorstr='#0cffffff', GradientType=0 );
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #eee;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-nav-collapse .nav li a {
|
||||||
|
margin-bottom: 0;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.25);
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-nav-collapse .nav>li>a,.shl-nav-collapse .dropdown-menu a {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #fff;
|
||||||
|
-webkit-border-radius: 0;
|
||||||
|
-moz-border-radius: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shl-nav-collapse .dropdown-menu li+li a {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** at low width, remove stickiness of side and top bars **/
|
||||||
|
@media ( max-width : 768px) {
|
||||||
|
div.shl-fixed,header.shl-fixed-header,div.shl-fixed-subheader {
|
||||||
|
position: inherit !important;
|
||||||
|
}
|
||||||
|
div.shl-fixed-top-hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
header.shl-fixed-header {
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: inherit;
|
||||||
|
}
|
||||||
|
div.shl-fixed-subheader {
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: inherit;
|
||||||
|
}
|
||||||
|
div.shl-fixed-top-hidden {
|
||||||
|
height: 90px;
|
||||||
|
}
|
||||||
|
.shl-hidden-low-width,div.shl-hidden-low-width {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
#shl-main-menu-coll-container .btn {
|
||||||
|
text-align: left ! important;
|
||||||
|
}
|
||||||
|
div.shl-main-list-wrapper-padding {
|
||||||
|
padding-top: 0 ! important;
|
||||||
|
}
|
||||||
|
div.shmodal-toolbar {
|
||||||
|
position: inherit !important;
|
||||||
|
}
|
||||||
|
div.shl-modal-list-wrapper {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
.shmodal-content {
|
||||||
|
padding-top: 5px !important;
|
||||||
|
}
|
||||||
|
div.shmodal-toolbar-buttons {
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
div.shmodal-toolbar-wrapper {
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
div.shmodal-toolbar div.alert {
|
||||||
|
padding: 3px; ! important;
|
||||||
|
margin-bottom: 3px !important;
|
||||||
|
}
|
||||||
|
div.shl-main-searchbar-wrapper {
|
||||||
|
padding: 0 ! important;
|
||||||
|
height: auto !important;
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
div.shl-modal-searchbar-wrapper {
|
||||||
|
padding: 0 ! important;
|
||||||
|
margin-top: 5px ! important;
|
||||||
|
margin-bottom: 5px ! important;
|
||||||
|
height: auto !important;
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
div#shl-main-searchbar-right-block,div#shl-modal-searchbar-right-block {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
div.shmodal-toolbar-buttons {
|
||||||
|
clear: left !important;
|
||||||
|
}
|
||||||
|
div#j-sidebar-container {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sh404sef-footer-container {
|
||||||
|
clear: both;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px #DDDDDD solid;
|
||||||
|
background: none repeat scroll 0 0 #EDEDED;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
font-style: italic;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1030;
|
||||||
|
bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** at low height, fold main menu into a button **/
|
||||||
|
@media ( min-height : 768px) {
|
||||||
|
#shl-main-menu-coll-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media ( max-height : 768px) {
|
||||||
|
#shl-main-menu-full {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
#sbox-btn-close {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sbox-window.sh404sef-popup {
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sbox-overlay.sh404sef-popup {
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh404sef-popup #content-box {
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-32-main {
|
||||||
|
background-image: url(../images/icon-32-default.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-48-sh404sef {
|
||||||
|
background-image: url(../images/icon-48-sh404sef-logo.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-48-warning {
|
||||||
|
background-image: url(../images/icon-48-warning.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-32-purge {
|
||||||
|
background-image: url(../images/icon-32-purge.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-32-purgeselected {
|
||||||
|
background-image: url(../images/icon-32-purgeselected.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-32-home {
|
||||||
|
background-image: url(../images/icon-32-frontpage.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-32-cpanel {
|
||||||
|
background-image: url(../images/icon-32-cpanel.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-32-import {
|
||||||
|
background-image: url(../images/icon-32-import.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-32-export {
|
||||||
|
background-image: url(../images/icon-32-export.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-32-selectnfredirect {
|
||||||
|
background-image: url(../images/icon-32-default.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-32-deletedeldup {
|
||||||
|
background-image: url(../images/icon-32-delete.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sh404sef-toolbar-title {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #0B55C4;
|
||||||
|
line-height: 48px;
|
||||||
|
padding-left: 135px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh-ajax-loading {
|
||||||
|
background-image: url(../images/sh-ajax-loader-wide.gif);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mainurl {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #0B55C4;
|
||||||
|
line-height: 48px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sh404sef-red {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sh404sef-red-center {
|
||||||
|
color: red;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-message-box ul {
|
||||||
|
color: #0055BB;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #C3D2E5;
|
||||||
|
background-image: url(../images/notice-info.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-error-box ul {
|
||||||
|
color: #c00;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #E6C0C0;
|
||||||
|
background-image: url(../images/notice-alert.png);
|
||||||
|
border-color: #DE7A7B;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sh404sef-footer-container {
|
||||||
|
clear: both;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px #DDDDDD solid;
|
||||||
|
background: none repeat scroll 0 0 #EDEDED;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
font-style: italic;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
margin-top: 1.5em;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
.sh404sef-popup #content-box {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
-webkit-border-top-right-radius: 10px;
|
||||||
|
-webkit-border-top-left-radius: 10px;
|
||||||
|
-moz-border-radius-topleft: 10px;
|
||||||
|
-moz-border-radius-topright: 10px;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh404sef-popup #toolbar-box {
|
||||||
|
padding: 0;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-48-sh404sef { background-image: url(../images/icon-48-sh404sef-logo.png); }
|
||||||
|
.icon-32-next { background-image: url(../images/icon-32-next.png); }
|
||||||
|
.icon-32-previous { background-image: url(../images/icon-32-previous.png); }
|
||||||
|
.icon-32-cancel { background-image: url(../images/icon-32-cancel-wizard.png); }
|
||||||
|
.icon-32-terminate { background-image: url(../images/icon-32-terminate.png); }
|
||||||
|
|
||||||
|
|
||||||
|
div.sh404sef-toolbar-title {
|
||||||
|
font-size: 22px; font-weight: bold; color: #0B55C4; line-height: 48px;
|
||||||
|
padding-left: 135px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.headerconfirm {
|
||||||
|
font-size: 22px; font-weight: bold; color: #0B55C4; line-height: 48px;
|
||||||
|
padding-left: 10px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh404sef-popup td.key {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sh-ajax-loading {
|
||||||
|
background-image: url(../images/sh-ajax-loader-wide.gif);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-message-box ul{
|
||||||
|
color: #0055BB;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #C3D2E5;
|
||||||
|
background-image: url(../images/notice-info.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#sh-error-box ul{
|
||||||
|
color: #c00;
|
||||||
|
background-position: 4px top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 3px solid #84A7DB;
|
||||||
|
border-bottom: 3px solid #84A7DB;
|
||||||
|
background-color: #E6C0C0;
|
||||||
|
background-image: url(../images/notice-alert.png);
|
||||||
|
border-color: #DE7A7B;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 574 B |
|
After Width: | Height: | Size: 683 B |
|
After Width: | Height: | Size: 582 B |
|
After Width: | Height: | Size: 336 B |
|
After Width: | Height: | Size: 567 B |
|
After Width: | Height: | Size: 650 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 977 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
@ -0,0 +1 @@
|
|||||||
|
<html><body bgcolor="#FFFFFF"></body></html>
|
||||||
|
After Width: | Height: | Size: 692 B |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 404 B |
@ -0,0 +1 @@
|
|||||||
|
<html><body bgcolor="#FFFFFF"></body></html>
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
function shAjaxHandler(task, options, closewindow) {
|
||||||
|
|
||||||
|
var form = document.id('adminForm');
|
||||||
|
form.task.value = task;
|
||||||
|
|
||||||
|
// Create a progress indicator
|
||||||
|
var update = document.id("sh-message-box").empty();
|
||||||
|
update.set("html", "<div class='sh-ajax-loading'> </div>");
|
||||||
|
document.id("sh-error-box").empty();
|
||||||
|
|
||||||
|
// Set the options of the form"s Request handler.
|
||||||
|
var onSuccessFn = function(response, responseXML) {
|
||||||
|
//alert(response);
|
||||||
|
var root, status, message;
|
||||||
|
try {
|
||||||
|
root = responseXML.documentElement;
|
||||||
|
status = root.getElementsByTagName("status").item(0).firstChild.nodeValue;
|
||||||
|
message = root.getElementsByTagName("message").item(0).firstChild.nodeValue;
|
||||||
|
} catch (err) {
|
||||||
|
status = 'failure';
|
||||||
|
message = "<div id='error-box-content'><ul><li>Sorry, something went wrong on the server while performing this action. Please retry or cancel</li></ul></div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove progress indicator
|
||||||
|
var update = document.id("sh-message-box").empty();
|
||||||
|
|
||||||
|
// insert results
|
||||||
|
if (status == "success") {
|
||||||
|
update.set("html", message);
|
||||||
|
if (closewindow) {
|
||||||
|
setTimeout("window.parent.SqueezeBox.close()", 1500);
|
||||||
|
} else {
|
||||||
|
setTimeout("document.id('sh-message-box').empty()", 3000);
|
||||||
|
}
|
||||||
|
} else if (status == 'redirect') {
|
||||||
|
setTimeout("parent.window.location='" + message + "';", 100);
|
||||||
|
window.parent.shReloadModal = false;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
} else {
|
||||||
|
document.id('sh-error-box').set("html", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the form.
|
||||||
|
form.set( 'send', {url: 'index.php', method: 'post', onSuccess: onSuccessFn});
|
||||||
|
form.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
Joomla.submitbutton = function(pressbutton) {
|
||||||
|
if (pressbutton == "cancel") {
|
||||||
|
window.parent.shReloadModal = false;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
}
|
||||||
|
if (pressbutton == "back") {
|
||||||
|
window.parent.shReloadModal = true;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<html><body bgcolor="#FFFFFF"></body></html>
|
||||||
@ -0,0 +1,376 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
var shQuickControlNeedsUpdate = false;
|
||||||
|
var shAnalyticsCompletedRequestsList = {};
|
||||||
|
var shAnalyticsProgress = null;
|
||||||
|
var shAnalyticsOptions = null;
|
||||||
|
|
||||||
|
function shSetupQuickControl() {
|
||||||
|
var url = "index.php?option=com_sh404sef&c=configuration&view=configuration&layout=qcontrol&format=raw&tmpl=component&noMsg=1";
|
||||||
|
new Request.HTML({
|
||||||
|
url : url,
|
||||||
|
method : 'get',
|
||||||
|
onSuccess : function(responseTree, responseElements, responseHTML,
|
||||||
|
responseJavaScript) {
|
||||||
|
shUpdateQuickControl(responseHTML);
|
||||||
|
},
|
||||||
|
onFailure : function(xhr) {
|
||||||
|
shUpdateQuickControl('Server not responding for Quick control');
|
||||||
|
}
|
||||||
|
}).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
function shUpdateQuickControl(response) {
|
||||||
|
|
||||||
|
document.id('qcontrolcontent').set("html", response);
|
||||||
|
|
||||||
|
shUpdateTooltips();
|
||||||
|
|
||||||
|
setTimeout("document.id('sh-message-box').empty()", 3000);
|
||||||
|
setTimeout("document.id('sh-error-box').empty()", 5000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shUpdateTooltips() {
|
||||||
|
|
||||||
|
$$('.hasTip').each(function(el) {
|
||||||
|
var title = el.get('title');
|
||||||
|
if (title) {
|
||||||
|
var parts = title.split('::', 2);
|
||||||
|
el.store('tip:title', parts[0]);
|
||||||
|
el.store('tip:text', parts[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var AnalyticsTooltips = new Tips($$('.hasTip'), {
|
||||||
|
maxTitleChars : 50,
|
||||||
|
fixed : false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function shSetupSecStats(task) {
|
||||||
|
task = task ? task : 'showsecstats';
|
||||||
|
var url = "index.php?option=com_sh404sef&task=" + task
|
||||||
|
+ "&layout=secstats&format=raw&tmpl=component&noMsg=1";
|
||||||
|
var update = document.id("sh-progress-cpprogress").empty();
|
||||||
|
update.set("html", "<div class='sh-ajax-loading'> </div>");
|
||||||
|
new Request.HTML({
|
||||||
|
url : url,
|
||||||
|
method : 'get',
|
||||||
|
onSuccess : function(responseTree, responseElements, responseHTML,
|
||||||
|
responseJavaScript) {
|
||||||
|
update.empty();
|
||||||
|
shUpdateSecStats(responseHTML);
|
||||||
|
},
|
||||||
|
onFailure : function(xhr) {
|
||||||
|
update.empty();
|
||||||
|
shUpdateSecStats('Server not responding for security stats');
|
||||||
|
}
|
||||||
|
}).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
function shUpdateSecStats(response) {
|
||||||
|
|
||||||
|
document.id('secstatscontent').set("html", response);
|
||||||
|
setTimeout("document.id('sh-message-box').empty()", 3000);
|
||||||
|
setTimeout("document.id('sh-error-box').empty()", 5000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shSetupUpdates(forced) {
|
||||||
|
forced = forced ? "forced=1" : 'forced=0';
|
||||||
|
var url = "index.php?option=com_sh404sef&task=showupdates&layout=updates&format=raw&tmpl=component&noMsg=1&"
|
||||||
|
+ forced;
|
||||||
|
var update = document.id("sh-progress-cpprogress").empty();
|
||||||
|
update.set("html", "<div class='sh-ajax-loading'> </div>");
|
||||||
|
new Request.HTML({
|
||||||
|
url : url,
|
||||||
|
method : 'get',
|
||||||
|
onSuccess : function(responseTree, responseElements, responseHTML,
|
||||||
|
responseJavaScript) {
|
||||||
|
update.empty();
|
||||||
|
shUpdateUpdates(responseHTML);
|
||||||
|
},
|
||||||
|
onFailure : function(xhr) {
|
||||||
|
update.empty();
|
||||||
|
shUpdateUpdates('Server not responding for Updates check');
|
||||||
|
}
|
||||||
|
}).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
function shUpdateButtonClick() {
|
||||||
|
document.id("sh-update-button").empty();
|
||||||
|
var update = document.id("sh-progress-cpprogress").empty();
|
||||||
|
update.set("html", "<div class='sh-ajax-loading'> </div>");
|
||||||
|
}
|
||||||
|
|
||||||
|
function shUpdateUpdates(response) {
|
||||||
|
|
||||||
|
document.id('updatescontent').set("html", response);
|
||||||
|
setTimeout("document.id('sh-message-box').empty()", 3000);
|
||||||
|
setTimeout("document.id('sh-error-box').empty()", 5000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shAnalyticsRequestCompleted(req) {
|
||||||
|
|
||||||
|
shAnalyticsCompletedRequestsList.set(req, true);
|
||||||
|
completed = true;
|
||||||
|
shAnalyticsCompletedRequestsList.each(function(value, key) {
|
||||||
|
completed = completed && value;
|
||||||
|
});
|
||||||
|
if (completed) {
|
||||||
|
shAnalyticsProgress.empty();
|
||||||
|
setTimeout('shRefreshTooltips();', 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shRefreshTooltips() {
|
||||||
|
|
||||||
|
$$('.hasAnalyticsTip').each(function(el) {
|
||||||
|
var title = el.get('title');
|
||||||
|
if (title) {
|
||||||
|
var parts = title.split('::', 2);
|
||||||
|
el.store('tip:title', parts[0]);
|
||||||
|
el.store('tip:text', parts[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var AnalyticsTooltips = new Tips($$('.hasAnalyticsTip'), {
|
||||||
|
maxTitleChars : 50,
|
||||||
|
fixed : false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function shSetupAnalytics(options) {
|
||||||
|
|
||||||
|
shAnalyticsOptions = options || {};
|
||||||
|
|
||||||
|
shAnalyticsProgress = document.id("sh-progress-analyticsprogress");
|
||||||
|
shAnalyticsProgress
|
||||||
|
.set("html", "<div class='sh-ajax-loading'> </div>");
|
||||||
|
|
||||||
|
var defaultOptions = {
|
||||||
|
forced : 0,
|
||||||
|
showFilters : 'yes',
|
||||||
|
accountId : '',
|
||||||
|
groupBy : '',
|
||||||
|
startDate : '',
|
||||||
|
endDate : '',
|
||||||
|
cpWidth : 0,
|
||||||
|
report : 'dashboard',
|
||||||
|
subrequest : 'visits'
|
||||||
|
};
|
||||||
|
|
||||||
|
forced = "forced="
|
||||||
|
+ (shAnalyticsOptions.forced ? shAnalyticsOptions.forced
|
||||||
|
: defaultOptions.forced);
|
||||||
|
|
||||||
|
shAnalyticsOptions.showFilters = shAnalyticsOptions.showFilters ? shAnalyticsOptions.showFilters : defaultOptions.showFilters;
|
||||||
|
showFilters = "&showFilters="
|
||||||
|
+ (shAnalyticsOptions.showFilters ? shAnalyticsOptions.showFilters
|
||||||
|
: defaultOptions.showFilters);
|
||||||
|
|
||||||
|
// is account Id selected by user ?
|
||||||
|
var accountIdEl = document.id('accountId');
|
||||||
|
accountId = accountIdEl ? "&accountId=" + accountIdEl.value
|
||||||
|
: defaultOptions.accountId;
|
||||||
|
var startDateEl = document.id('startDate');
|
||||||
|
startDate = startDateEl ? "&startDate=" + startDateEl.value
|
||||||
|
: defaultOptions.startDate;
|
||||||
|
var endDateEl = document.id('endDate');
|
||||||
|
endDate = endDateEl ? "&endDate=" + endDateEl.value
|
||||||
|
: defaultOptions.endDate;
|
||||||
|
var reportEl = document.id('report');
|
||||||
|
report = "&report=" + (reportEl ? reportEl.value : defaultOptions.report);
|
||||||
|
var groupByEl = document.id('groupBy');
|
||||||
|
groupBy = "&groupBy="
|
||||||
|
+ (groupByEl ? groupByEl.value : defaultOptions.groupBy);
|
||||||
|
var cpEl = document.id('sh404sef-analytics-wrapper');
|
||||||
|
cpWidth = "&cpWidth=" + (cpEl ? cpEl.offsetWidth : defaultOptions.cpWidth);
|
||||||
|
shAnalyticsOptions.url = "index.php?option=com_sh404sef&view=analytics&format=raw&tmpl=component&noMsg=1&"
|
||||||
|
+ forced
|
||||||
|
+ showFilters
|
||||||
|
+ report
|
||||||
|
+ accountId
|
||||||
|
+ groupBy
|
||||||
|
+ cpWidth
|
||||||
|
+ startDate + endDate;
|
||||||
|
|
||||||
|
if (shAnalyticsOptions.showFilters == 'yes') {
|
||||||
|
shAnalyticsCompletedRequestsList = new Hash({
|
||||||
|
'headers' : false,
|
||||||
|
'visits' : false,
|
||||||
|
'sources' : false,
|
||||||
|
'global' : false,
|
||||||
|
'perf' : false,
|
||||||
|
'topsocialfb': false,
|
||||||
|
'topsocialtweeter': false,
|
||||||
|
'topsocialpinterest': false,
|
||||||
|
'topsocialplusone': false,
|
||||||
|
'topsocialplusonepage': false,
|
||||||
|
'top5urls' : false,
|
||||||
|
'top5referrers' : false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
shAnalyticsCompletedRequestsList = new Hash({
|
||||||
|
'headers' : false,
|
||||||
|
'visits' : false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't empty headers!
|
||||||
|
shAnalyticsCompletedRequestsList.each(function(value, key) {
|
||||||
|
if (key != "headers") {
|
||||||
|
try{
|
||||||
|
document.id("analyticscontent_" + key).empty();
|
||||||
|
} catch (e) {
|
||||||
|
//alert(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('headers');
|
||||||
|
_shPerformAnalyticsSubRequest('visits');
|
||||||
|
|
||||||
|
if (shAnalyticsOptions.showFilters == 'yes') {
|
||||||
|
for ( var i = 1; i < 11; i++) {
|
||||||
|
setTimeout('shContinueAnalytics' + i + '();', 600 * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics1() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('sources');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics2() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('global');
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics3() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('perf');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics4() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('top5urls');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics5() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('top5referrers');
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics6() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('topsocialfb');
|
||||||
|
}
|
||||||
|
function shContinueAnalytics7() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('topsocialtweeter');
|
||||||
|
}
|
||||||
|
function shContinueAnalytics8() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('topsocialpinterest');
|
||||||
|
}
|
||||||
|
function shContinueAnalytics9() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('topsocialplusone');
|
||||||
|
}
|
||||||
|
function shContinueAnalytics10() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('topsocialplusonepage');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _shPerformAnalyticsSubRequest(subrequestname) {
|
||||||
|
|
||||||
|
new Request.HTML({
|
||||||
|
url : shAnalyticsOptions.url + '&subrequest=' + subrequestname,
|
||||||
|
method : 'get',
|
||||||
|
onSuccess : function(responseTree, responseElements, responseHTML,
|
||||||
|
responseJavaScript) {
|
||||||
|
shAnalyticsRequestCompleted(subrequestname);
|
||||||
|
shUpdateAnalytics(responseHTML, subrequestname);
|
||||||
|
},
|
||||||
|
onFailure : function(xhr) {
|
||||||
|
shAnalyticsRequestCompleted(subrequestname);
|
||||||
|
shUpdateAnalytics('Server not responding for ' + subrequestname, subrequestname);
|
||||||
|
}
|
||||||
|
}).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
function shUpdateAnalytics(response, subrequest) {
|
||||||
|
|
||||||
|
document.id('analyticscontent_' + subrequest).set("html", response);
|
||||||
|
id = document.id('startDate');
|
||||||
|
if (id) {
|
||||||
|
Calendar.setup({
|
||||||
|
inputField : "startDate", // id of the input field
|
||||||
|
ifFormat : "%Y-%m-%d", // format of the input field
|
||||||
|
button : "startDate_img", // trigger for the calendar (button ID)
|
||||||
|
align : "Bl", // alignment (defaults to "Bl")
|
||||||
|
singleClick : true
|
||||||
|
});
|
||||||
|
Calendar.setup({
|
||||||
|
inputField : "endDate", // id of the input field
|
||||||
|
ifFormat : "%Y-%m-%d", // format of the input field
|
||||||
|
button : "endDate_img", // trigger for the calendar (button ID)
|
||||||
|
align : "Tl", // alignment (defaults to "Bl")
|
||||||
|
singleClick : true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setTimeout("document.id('sh-message-box').empty()", 3000);
|
||||||
|
setTimeout("document.id('sh-error-box').empty()", 5000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shSubmitQuickControl() {
|
||||||
|
|
||||||
|
var form = document.id('adminForm');
|
||||||
|
|
||||||
|
// Create a progress indicator
|
||||||
|
var update = document.id("sh-progress-cpprogress").empty();
|
||||||
|
update.set("html", "<div class='sh-ajax-loading'> </div>");
|
||||||
|
document.id("sh-error-box").empty();
|
||||||
|
|
||||||
|
// Set the options of the form"s Request handler.
|
||||||
|
var onSuccessFn = function(response) {
|
||||||
|
var message;
|
||||||
|
//alert(response);
|
||||||
|
message = "<div id='error-box-content'><ul><li>Sorry, something went wrong on the server while performing this action. Please try again or contact administrator</li></ul></div>";
|
||||||
|
|
||||||
|
// remove progress indicator
|
||||||
|
var update = document.id("sh-progress-cpprogress").empty();
|
||||||
|
|
||||||
|
// insert results
|
||||||
|
shUpdateQuickControl(response);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
form.set('send', {
|
||||||
|
url : 'index.php',
|
||||||
|
method : 'post',
|
||||||
|
onSuccess : onSuccessFn
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send the form.
|
||||||
|
form.send();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
function shAjaxHandler(task, options, closewindow) {
|
||||||
|
|
||||||
|
var form = document.id('adminForm');
|
||||||
|
form.task.value = task;
|
||||||
|
|
||||||
|
// Create a progress indicator
|
||||||
|
var update = document.id("sh-message-box").empty();
|
||||||
|
update.set("html", "<div class='sh-ajax-loading'> </div>");
|
||||||
|
document.id("sh-error-box").empty();
|
||||||
|
|
||||||
|
// Set the options of the form"s Request handler.
|
||||||
|
var onSuccessFn = function(response, responseXML) {
|
||||||
|
//alert(response);
|
||||||
|
var root, status, message;
|
||||||
|
try {
|
||||||
|
root = responseXML.documentElement;
|
||||||
|
status = root.getElementsByTagName("status").item(0).firstChild.nodeValue;
|
||||||
|
message = root.getElementsByTagName("message").item(0).firstChild.nodeValue;
|
||||||
|
} catch (err) {
|
||||||
|
status = 'failure';
|
||||||
|
message = "<div id='error-box-content'><ul><li>Sorry, something went wrong on the server while performing this action. Please retry or cancel</li>" +
|
||||||
|
"<li>" + response + "</li>"
|
||||||
|
"</ul></div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove progress indicator
|
||||||
|
var update = document.id("sh-message-box").empty();
|
||||||
|
|
||||||
|
// insert results
|
||||||
|
if (status == "success") {
|
||||||
|
update.set("html", message);
|
||||||
|
if (closewindow) {
|
||||||
|
setTimeout("window.parent.SqueezeBox.close()", 1500);
|
||||||
|
} else {
|
||||||
|
setTimeout("document.id('sh-message-box').empty()", 3000);
|
||||||
|
}
|
||||||
|
} else if (status == 'redirect') {
|
||||||
|
setTimeout("parent.window.location='" + message + "';", 100);
|
||||||
|
window.parent.shReloadModal = false;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
} else {
|
||||||
|
document.id('sh-error-box').set("html", message);
|
||||||
|
setTimeout("document.id('sh-error-box').empty();", 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the form.
|
||||||
|
form.set( 'send', {url: 'index.php', method: 'post', onSuccess: onSuccessFn});
|
||||||
|
form.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
Joomla.submitbutton = function(pressbutton) {
|
||||||
|
if (pressbutton == "cancel") {
|
||||||
|
window.parent.shReloadModal = false;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
}
|
||||||
|
if (pressbutton == "back") {
|
||||||
|
window.parent.shReloadModal = true;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
var __sh404sefJs = (function($) {
|
||||||
|
var tmp = {
|
||||||
|
|
||||||
|
// function to call on document ready
|
||||||
|
onReady : function() {
|
||||||
|
jQuery(window).resize(__sh404sefJs.stickyPagination);
|
||||||
|
__sh404sefJs.stickyPagination();
|
||||||
|
},
|
||||||
|
|
||||||
|
// display the pagination bar at the top, fixed, or let it
|
||||||
|
// at bottom, scrolling
|
||||||
|
stickyPagination : function() {
|
||||||
|
var needed = $("#shl-bottom-pagination-container ul.pagination-list").width();
|
||||||
|
var avail = $("#shl-main-searchbar-right-block").width();
|
||||||
|
var used = 0;
|
||||||
|
$("#shl-main-searchbar-right-block div.btn-group").each(function() {
|
||||||
|
var w = jQuery(this).width();
|
||||||
|
used += w;
|
||||||
|
});
|
||||||
|
if ((avail - used - 20) > needed) {
|
||||||
|
var c = jQuery("#shl-bottom-pagination-container").html();
|
||||||
|
if(c) {
|
||||||
|
$("#shl-bottom-pagination-container").html("");
|
||||||
|
$("#shl-top-pagination-container").html(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var t = jQuery("#shl-top-pagination-container").html();
|
||||||
|
if(t) {
|
||||||
|
$("#shl-bottom-pagination-container").html(t);
|
||||||
|
$("#shl-top-pagination-container").html("");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// init
|
||||||
|
jQuery(document).ready(tmp.onReady);
|
||||||
|
return tmp;
|
||||||
|
})(jQuery);
|
||||||
@ -0,0 +1,290 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
var shQuickControlNeedsUpdate = false;
|
||||||
|
var shAnalyticsCompletedRequestsList = {};
|
||||||
|
var shAnalyticsProgress = null;
|
||||||
|
var shAnalyticsOptions = null;
|
||||||
|
|
||||||
|
function shSetupQuickControl() {
|
||||||
|
var url = "index.php?option=com_sh404sef&c=configuration&view=configuration&layout=qcontrol&format=raw&tmpl=component&noMsg=1";
|
||||||
|
|
||||||
|
var onSuccess = function(response) {
|
||||||
|
progress.empty();
|
||||||
|
jQuery('#qcontrolcontent').html(response);
|
||||||
|
shlBootstrap.updateBootstrap();
|
||||||
|
};
|
||||||
|
// request quick control panel
|
||||||
|
var onFailure = function() {
|
||||||
|
shUpdateQuickControl('<div class="alert alert-error">Server not responding for Quick control</div>');
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery.get(url, shUpdateQuickControl).fail(onFailure);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shUpdateQuickControl(response) {
|
||||||
|
|
||||||
|
jQuery('#qcontrolcontent').html(response);
|
||||||
|
shlBootstrap.updateBootstrap();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shSetupSecStats(task) {
|
||||||
|
task = task || 'showsecstats';
|
||||||
|
var url = "index.php?option=com_sh404sef&task=" + task + "&layout=secstats&format=raw&tmpl=component&noMsg=1";
|
||||||
|
var progress = jQuery("#sh-progress-cpprogress").empty();
|
||||||
|
progress.html("<div class='sh-ajax-loading'> </div>");
|
||||||
|
|
||||||
|
// request quick control panel
|
||||||
|
var onSuccess = function(response) {
|
||||||
|
progress.empty();
|
||||||
|
jQuery('#secstatscontent').html(response);
|
||||||
|
};
|
||||||
|
var onFailure = function() {
|
||||||
|
progress.empty();
|
||||||
|
jQuery('#secstatscontent').html('<div class="alert alert-error">Server not responding for security stats</div>');
|
||||||
|
};
|
||||||
|
|
||||||
|
jQuery.get(url, onSuccess).fail(onFailure);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shSetupUpdates(forced) {
|
||||||
|
forced = forced ? "forced=1" : 'forced=0';
|
||||||
|
var url = "index.php?option=com_sh404sef&task=showupdates&layout=updates&format=raw&tmpl=component&noMsg=1&" + forced;
|
||||||
|
var progress = jQuery("#sh-progress-cpprogress").empty();
|
||||||
|
progress.html("<div class='sh-ajax-loading'> </div>");
|
||||||
|
var onSuccess = function(response) {
|
||||||
|
progress.empty();
|
||||||
|
jQuery('#updatescontent').html(response);
|
||||||
|
};
|
||||||
|
var onFailure = function() {
|
||||||
|
progress.empty();
|
||||||
|
jQuery('#updatescontent').html('<div class="alert alert-error">Server not responding for Updates check</div>');
|
||||||
|
};
|
||||||
|
|
||||||
|
jQuery.get(url, onSuccess).fail(onFailure);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shUpdateButtonClick() {
|
||||||
|
jQuery("#sh-update-button").empty();
|
||||||
|
var progress = jQuery("#sh-progress-cpprogress").empty();
|
||||||
|
progress.html("<div class='sh-ajax-loading'> </div>");
|
||||||
|
}
|
||||||
|
|
||||||
|
function shAnalyticsRequestCompleted(req) {
|
||||||
|
|
||||||
|
shAnalyticsCompletedRequestsList[req] = true;
|
||||||
|
completed = true;
|
||||||
|
jQuery.each(shAnalyticsCompletedRequestsList, function(key, value) {
|
||||||
|
completed = completed && value;
|
||||||
|
});
|
||||||
|
if (completed) {
|
||||||
|
shAnalyticsProgress.empty();
|
||||||
|
setTimeout('shlBootstrap.updateBootstrap();', 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shSetupAnalytics(options) {
|
||||||
|
|
||||||
|
shAnalyticsOptions = options || {};
|
||||||
|
|
||||||
|
shAnalyticsProgress = jQuery("#sh-progress-analyticsprogress");
|
||||||
|
shAnalyticsProgress.html("<div class='sh-ajax-loading'> </div>");
|
||||||
|
|
||||||
|
var defaultOptions = {
|
||||||
|
forced : 0,
|
||||||
|
showFilters : 'yes',
|
||||||
|
accountId : '',
|
||||||
|
groupBy : '',
|
||||||
|
startDate : '',
|
||||||
|
endDate : '',
|
||||||
|
cpWidth : 0,
|
||||||
|
report : 'dashboard',
|
||||||
|
subrequest : 'visits'
|
||||||
|
};
|
||||||
|
shAnalyticsOptions.showFilters = shAnalyticsOptions.showFilters ? shAnalyticsOptions.showFilters : defaultOptions.showFilters;
|
||||||
|
forced = "forced=" + (shAnalyticsOptions.forced ? shAnalyticsOptions.forced : defaultOptions.forced);
|
||||||
|
showFilters = "&showFilters=" + shAnalyticsOptions.showFilters;
|
||||||
|
|
||||||
|
accountId = defaultOptions.accountId;
|
||||||
|
var startDateEl = jQuery('#startDate');
|
||||||
|
startDate = startDateEl && startDateEl.val() ? "&startDate=" + startDateEl.val() : defaultOptions.startDate;
|
||||||
|
var endDateEl = jQuery('#endDate');
|
||||||
|
endDate = endDateEl && endDateEl.val() ? "&endDate=" + endDateEl.val() : defaultOptions.endDate;
|
||||||
|
var reportEl = jQuery('#report');
|
||||||
|
report = "&report=" + (reportEl && reportEl.val() ? reportEl.val() : defaultOptions.report);
|
||||||
|
var groupByEl = jQuery('#groupBy');
|
||||||
|
groupBy = "&groupBy=" + (groupByEl && groupByEl.val() ? groupByEl.val() : defaultOptions.groupBy);
|
||||||
|
var cpEl = jQuery('#sh404sef-analytics-wrapper');
|
||||||
|
cpWidth = "&cpWidth=" + (cpEl ? cpEl.width() : defaultOptions.cpWidth);
|
||||||
|
shAnalyticsOptions.url = "index.php?option=com_sh404sef&view=analytics&format=raw&tmpl=component&noMsg=1&" + forced
|
||||||
|
+ showFilters + report + accountId + groupBy + cpWidth + startDate + endDate;
|
||||||
|
|
||||||
|
if (shAnalyticsOptions.showFilters == 'yes') {
|
||||||
|
shAnalyticsCompletedRequestsList = {
|
||||||
|
headers : false,
|
||||||
|
visits : false,
|
||||||
|
sources : false,
|
||||||
|
global : false,
|
||||||
|
perf : false,
|
||||||
|
topsocialfb : false,
|
||||||
|
topsocialtweeter : false,
|
||||||
|
topsocialpinterest : false,
|
||||||
|
topsocialplusone : false,
|
||||||
|
topsocialplusonepage : false,
|
||||||
|
top5urls : false,
|
||||||
|
top5referrers : false
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
shAnalyticsCompletedRequestsList = {
|
||||||
|
headers : false,
|
||||||
|
visits : false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't empty headers!
|
||||||
|
jQuery.each(shAnalyticsCompletedRequestsList, function(key, value) {
|
||||||
|
if (key != "headers") {
|
||||||
|
try {
|
||||||
|
jQuery("#analyticscontent_" + key).empty();
|
||||||
|
} catch (e) {
|
||||||
|
// alert(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('headers');
|
||||||
|
_shPerformAnalyticsSubRequest('visits');
|
||||||
|
|
||||||
|
if (shAnalyticsOptions.showFilters == 'yes') {
|
||||||
|
for ( var i = 1; i < 11; i++) {
|
||||||
|
setTimeout('shContinueAnalytics' + i + '();', 600 * i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics1() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('sources');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics2() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('global');
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics3() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('perf');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics4() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('top5urls');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics5() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('top5referrers');
|
||||||
|
}
|
||||||
|
|
||||||
|
function shContinueAnalytics6() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('topsocialfb');
|
||||||
|
}
|
||||||
|
function shContinueAnalytics7() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('topsocialtweeter');
|
||||||
|
}
|
||||||
|
function shContinueAnalytics8() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('topsocialpinterest');
|
||||||
|
}
|
||||||
|
function shContinueAnalytics9() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('topsocialplusone');
|
||||||
|
}
|
||||||
|
function shContinueAnalytics10() {
|
||||||
|
|
||||||
|
_shPerformAnalyticsSubRequest('topsocialplusonepage');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _shPerformAnalyticsSubRequest(subrequestname) {
|
||||||
|
|
||||||
|
var onSuccess = function(response) {
|
||||||
|
shAnalyticsRequestCompleted(subrequestname);
|
||||||
|
shUpdateAnalytics(response, subrequestname);
|
||||||
|
};
|
||||||
|
var onFailure = function() {
|
||||||
|
shAnalyticsRequestCompleted(subrequestname);
|
||||||
|
shUpdateAnalytics('<div class="alert alert-error">Server not responding for ' + subrequestname, subrequestname + '</div>');
|
||||||
|
};
|
||||||
|
|
||||||
|
jQuery.get(shAnalyticsOptions.url + '&subrequest=' + subrequestname, onSuccess).fail(onFailure);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shUpdateAnalytics(response, subrequest) {
|
||||||
|
|
||||||
|
jQuery('#analyticscontent_' + subrequest).html(response);
|
||||||
|
id = jQuery('#startDate');
|
||||||
|
|
||||||
|
if (id.length) {
|
||||||
|
Calendar.setup({
|
||||||
|
inputField : "startDate", // id of the input field
|
||||||
|
ifFormat : "%Y-%m-%d", // format of the input field
|
||||||
|
button : "startDate_img", // trigger for the calendar (button ID)
|
||||||
|
align : "Bl", // alignment (defaults to "Bl")
|
||||||
|
singleClick : true
|
||||||
|
});
|
||||||
|
Calendar.setup({
|
||||||
|
inputField : "endDate", // id of the input field
|
||||||
|
ifFormat : "%Y-%m-%d", // format of the input field
|
||||||
|
button : "endDate_img", // trigger for the calendar (button ID)
|
||||||
|
align : "Tl", // alignment (defaults to "Bl")
|
||||||
|
singleClick : true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setTimeout("jQuery('#sh-message-box').empty()", 3000);
|
||||||
|
setTimeout("jQuery('#sh-error-box').empty()", 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shSubmitQuickControl() {
|
||||||
|
|
||||||
|
var form = jQuery('#adminForm');
|
||||||
|
|
||||||
|
// Create a progress indicator
|
||||||
|
var update = jQuery("#sh-progress-cpprogress").empty();
|
||||||
|
update.html("<div class='sh-ajax-loading'> </div>");
|
||||||
|
|
||||||
|
// Set the options of the form"s Request handler.
|
||||||
|
var onSuccessFn = function(response) {
|
||||||
|
// alert(response);
|
||||||
|
// remove progress indicator
|
||||||
|
var update = jQuery("#sh-progress-cpprogress").empty();
|
||||||
|
|
||||||
|
// insert results
|
||||||
|
shUpdateQuickControl(response);
|
||||||
|
|
||||||
|
};
|
||||||
|
// request quick control panel
|
||||||
|
var onFailure = function() {
|
||||||
|
shUpdateQuickControl('<div class="alert alert-error">Server not responding for Quick control</div>');
|
||||||
|
}
|
||||||
|
jQuery('#sh404sef-qcontrol .alert').remove();
|
||||||
|
jQuery.post('index.php', form.serialize(), onSuccessFn).fail(onFailure);
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
function shStopEvent(event) {
|
||||||
|
|
||||||
|
// cancel the event
|
||||||
|
new DOMEvent(event).stop();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shProcessToolbarClick(id, pressbutton) {
|
||||||
|
|
||||||
|
if (pressbutton != 'cancel') {
|
||||||
|
var el = document.getElementById(id);
|
||||||
|
var options = el.rel;
|
||||||
|
if (typeof this.baseurl == 'undefined') {
|
||||||
|
this.baseurl = [];
|
||||||
|
}
|
||||||
|
if (typeof this.baseurl[pressbutton] == 'undefined') {
|
||||||
|
this.baseurl[pressbutton] = el.href;
|
||||||
|
}
|
||||||
|
var url = baseurl[pressbutton];
|
||||||
|
var cid = document.getElementsByName('cid[]');
|
||||||
|
var list = '';
|
||||||
|
if (cid) {
|
||||||
|
var length = cid.length;
|
||||||
|
for ( var i = 0; i < length; i++) {
|
||||||
|
if (cid[i].checked) {
|
||||||
|
list += '&cid[]=' + cid[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
url += list;
|
||||||
|
el.href = url;
|
||||||
|
window.parent.SqueezeBox.fromElement(el, {parse:'rel'});
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shHideMainMenu() {
|
||||||
|
if (document.adminForm.hidemainmenu) {
|
||||||
|
document.adminForm.hidemainmenu.value=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Joomla.submitbutton = function (pressbutton) {
|
||||||
|
if (pressbutton == "cancelPopup") {
|
||||||
|
window.parent.shReloadModal = false;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
} else if (pressbutton == "backPopup") {
|
||||||
|
window.parent.shReloadModal = true;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
} else {
|
||||||
|
if (pressbutton == "selectnfredirect") {
|
||||||
|
window.parent.shReloadModal = true;
|
||||||
|
}
|
||||||
|
if (pressbutton) {
|
||||||
|
document.adminForm.task.value = pressbutton;
|
||||||
|
}
|
||||||
|
if (typeof document.adminForm.onsubmit == "function") {
|
||||||
|
document.adminForm.onsubmit();
|
||||||
|
}
|
||||||
|
document.adminForm.submit();
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
function shMetasClearFields() {
|
||||||
|
|
||||||
|
var form = document.id('adminForm');
|
||||||
|
form.task.value = '';
|
||||||
|
form.format.value = 'html';
|
||||||
|
form.shajax.value = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shAjaxHandler(task, options, closewindow) {
|
||||||
|
|
||||||
|
var form = document.id('adminForm');
|
||||||
|
form.task.value = task;
|
||||||
|
form.format.value = "raw";
|
||||||
|
form.shajax.value = 1;
|
||||||
|
|
||||||
|
// Create a progress indicator
|
||||||
|
var update = document.id("sh-message-box").empty();
|
||||||
|
update.set("html", "<div class='sh-ajax-loading'> </div>");
|
||||||
|
document.id("sh-error-box").empty();
|
||||||
|
|
||||||
|
// Set the options of the form"s Request handler.
|
||||||
|
var onSuccessFn = function(response, responseXML) {
|
||||||
|
//alert(response);
|
||||||
|
var root, status, message;
|
||||||
|
try {
|
||||||
|
root = responseXML.documentElement;
|
||||||
|
status = root.getElementsByTagName("status").item(0).firstChild.nodeValue;
|
||||||
|
message = root.getElementsByTagName("message").item(0).firstChild.nodeValue;
|
||||||
|
} catch (err) {
|
||||||
|
status = 'failure';
|
||||||
|
message = "<div id='error-box-content'><ul><li>Sorry, something went wrong on the server while performing this action. Please retry or cancel</li></ul></div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove progress indicator
|
||||||
|
var update = document.id("sh-message-box").empty();
|
||||||
|
|
||||||
|
// reset task and format
|
||||||
|
shMetasClearFields();
|
||||||
|
|
||||||
|
// insert results
|
||||||
|
if (status == "success") {
|
||||||
|
update.set("html", message);
|
||||||
|
if (closewindow) {
|
||||||
|
setTimeout("window.parent.SqueezeBox.close()", 1500);
|
||||||
|
} else {
|
||||||
|
setTimeout("document.id('sh-message-box').empty()", 3000);
|
||||||
|
}
|
||||||
|
} else if (status == 'redirect') {
|
||||||
|
setTimeout("parent.window.location='" + message + "';", 100);
|
||||||
|
window.parent.shReloadModal = false;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
} else {
|
||||||
|
document.id('sh-error-box').set("html", message);
|
||||||
|
setTimeout("document.id('sh-error-box').empty();", 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the form.
|
||||||
|
form.set( 'send', {url: 'index.php', method: 'post', onSuccess: onSuccessFn});
|
||||||
|
form.send();
|
||||||
|
}
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
function shAjaxHandler(task, options, closewindow) {
|
||||||
|
|
||||||
|
var form = document.id('adminForm');
|
||||||
|
form.task.value = task;
|
||||||
|
form.format.value = "raw";
|
||||||
|
|
||||||
|
// Create a progress indicator
|
||||||
|
var update = document.id("sh-message-box").empty();
|
||||||
|
update.set("html","<div class='sh-ajax-loading'> </div>");
|
||||||
|
document.id("sh-error-box").empty();
|
||||||
|
|
||||||
|
// Set the options of the form"s Request handler.
|
||||||
|
var onSuccessFn = function(response, responseXML) {
|
||||||
|
var root, status, message;
|
||||||
|
try {
|
||||||
|
root = responseXML.documentElement;
|
||||||
|
status = root.getElementsByTagName("status").item(0).firstChild.nodeValue;
|
||||||
|
message = root.getElementsByTagName("message").item(0).firstChild.nodeValue;
|
||||||
|
} catch (err) {
|
||||||
|
status = 'failure';
|
||||||
|
message = "<div id='error-box-content'><ul><li>Sorry, something went wrong on the server while performing this action. Please retry or cancel</li></ul></div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove progress indicator
|
||||||
|
var update = document.id("sh-message-box").empty();
|
||||||
|
|
||||||
|
// insert results
|
||||||
|
if (status == "success") {
|
||||||
|
update.set("html",message);
|
||||||
|
if (closewindow) {
|
||||||
|
setTimeout("window.parent.SqueezeBox.close()", 1500);
|
||||||
|
} else {
|
||||||
|
setTimeout("document.id('sh-message-box').empty()", 3000);
|
||||||
|
}
|
||||||
|
} else if (status == 'redirect') {
|
||||||
|
setTimeout("parent.window.location='" + message + "';", 100);
|
||||||
|
window.parent.shReloadModal = false;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
} else {
|
||||||
|
document.id('sh-error-box').set("html",message);
|
||||||
|
setTimeout("document.id('sh-error-box').empty();", 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the form.
|
||||||
|
form.set( 'send', {url: 'index.php', method: 'post', onSuccess: onSuccessFn});
|
||||||
|
form.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function shStopEvent(event) {
|
||||||
|
|
||||||
|
// cancel the event
|
||||||
|
new DOMEvent(event).stop();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Joomla.submitbutton = function (pressbutton) {
|
||||||
|
if (pressbutton == "cancelPopup") {
|
||||||
|
window.parent.shReloadModal = false;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
} else if (pressbutton == "backPopup") {
|
||||||
|
window.parent.shReloadModal = true;
|
||||||
|
window.parent.SqueezeBox.close();
|
||||||
|
} else {
|
||||||
|
if (pressbutton == "selectnfredirect") {
|
||||||
|
window.parent.shReloadModal = true;
|
||||||
|
}
|
||||||
|
if (pressbutton) {
|
||||||
|
document.adminForm.task.value = pressbutton;
|
||||||
|
}
|
||||||
|
if (typeof document.adminForm.onsubmit == "function") {
|
||||||
|
document.adminForm.onsubmit();
|
||||||
|
}
|
||||||
|
document.adminForm.submit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function shListItemAjaxTask(id, task, options, closewindow) {
|
||||||
|
var f = document.adminForm;
|
||||||
|
cb = eval('f.' + id);
|
||||||
|
if (cb) {
|
||||||
|
for (i = 0; true; i++) {
|
||||||
|
cbx = eval('f.cb' + i);
|
||||||
|
if (!cbx)
|
||||||
|
break;
|
||||||
|
cbx.checked = false;
|
||||||
|
} // for
|
||||||
|
cb.checked = true;
|
||||||
|
f.boxchecked.value = 1;
|
||||||
|
shAjaxHandler(task, options, closewindow);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
function shAjaxHandler(task, options, closewindow) {
|
||||||
|
|
||||||
|
var form = jQuery('#adminForm');
|
||||||
|
jQuery('#adminForm input[name=task]').val(task);
|
||||||
|
jQuery('#adminForm input[name=format]').val('raw');
|
||||||
|
jQuery('#adminForm input[name=shajax]').val('1');
|
||||||
|
|
||||||
|
// Create a progress indicator
|
||||||
|
var update = jQuery("#sh-progress-cpprogress")
|
||||||
|
update.empty();
|
||||||
|
update.html("<div class='sh-ajax-loading'> </div>");
|
||||||
|
|
||||||
|
// Set the options of the form"s Request handler.
|
||||||
|
var onSuccessFn = function(response) {
|
||||||
|
|
||||||
|
// restore form
|
||||||
|
jQuery('#adminForm input[name=task]').val('');
|
||||||
|
jQuery('#adminForm input[name=format]').val('html');
|
||||||
|
jQuery('#adminForm input[name=shajax]').val('0');
|
||||||
|
|
||||||
|
//alert(response);
|
||||||
|
var root, status, message;
|
||||||
|
try {
|
||||||
|
root = response.documentElement;
|
||||||
|
status = root.getElementsByTagName("status").item(0).firstChild.nodeValue;
|
||||||
|
message = "<div class='alert alert-success'>" + root.getElementsByTagName("message").item(0).firstChild.nodeValue + '</div>';
|
||||||
|
} catch (err) {
|
||||||
|
status = 'failure';
|
||||||
|
message = "<div class='alert alert-error'>Sorry, something went wrong on the server while performing this action. Please retry or cancel.</div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove progress indicator
|
||||||
|
var update = jQuery("#sh-progress-cpprogress").empty();
|
||||||
|
var update = jQuery("#sh-message-box2").empty();
|
||||||
|
|
||||||
|
// insert results
|
||||||
|
if (status == "success") {
|
||||||
|
update.html(message);
|
||||||
|
if (closewindow) {
|
||||||
|
setTimeout("shlBootstrap.closeModal()", 1500);
|
||||||
|
} else {
|
||||||
|
setTimeout("jQuery('#sh-message-box2').empty()", 3000);
|
||||||
|
}
|
||||||
|
} else if (status == 'redirect') {
|
||||||
|
setTimeout("parent.window.location='" + message + "';", 100);
|
||||||
|
shlBootstrap.closeModal();
|
||||||
|
} else {
|
||||||
|
jQuery('#sh-message-box').html(message);
|
||||||
|
setTimeout("jQuery('#sh-message-box2').empty();", 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the form.
|
||||||
|
jQuery.post('index.php', form.serialize())
|
||||||
|
.always(onSuccessFn);
|
||||||
|
};
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
function shStopEvent(event) {
|
||||||
|
|
||||||
|
// cancel the event
|
||||||
|
new DOMEvent(event).stop();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function shProcessToolbarClick(id, pressbutton) {
|
||||||
|
|
||||||
|
if (pressbutton != 'cancel') {
|
||||||
|
var el = document.getElementById(id);
|
||||||
|
if (typeof this.baseurl == 'undefined') {
|
||||||
|
this.baseurl = [];
|
||||||
|
}
|
||||||
|
if (typeof this.baseurl[pressbutton] == 'undefined') {
|
||||||
|
this.baseurl[pressbutton] = el.href;
|
||||||
|
}
|
||||||
|
var url = baseurl[pressbutton];
|
||||||
|
var cid = document.getElementsByName('cid[]');
|
||||||
|
var list = '';
|
||||||
|
if (cid) {
|
||||||
|
var length = cid.length;
|
||||||
|
for ( var i = 0; i < length; i++) {
|
||||||
|
if (cid[i].checked) {
|
||||||
|
list += '&cid[]=' + cid[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
url += list;
|
||||||
|
el.href = url;
|
||||||
|
window.parent.SqueezeBox.fromElement(el, {parse:'rel'});
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@ -0,0 +1,925 @@
|
|||||||
|
sh404sef 4 changelog
|
||||||
|
|
||||||
|
(2014-07-01 17:04 - build #1791)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2014-07-01 ] Version 4.4.4.1791
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[chg] Added back configuration saving betwen uninstall/install Fixes
|
||||||
|
#327
|
||||||
|
[chg] Canonical tag now includes leading scheme and host See #342
|
||||||
|
|
||||||
|
[bug] Memcache cache driver may eat up all available memcache memory
|
||||||
|
and slow down
|
||||||
|
[bug] Social buttons plugin gets published back on update (if user
|
||||||
|
manually disabled it)
|
||||||
|
[bug] Medium-level security issue for logged-in administrators only, on
|
||||||
|
Joomla! 2.x only, input not sufficiently sanitized
|
||||||
|
[bug] Configuration for type of cache handler is not saved
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2014-06-06 ] Version 4.4.3.1770
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[bug] Fatal error on php versions less than 5.3, on multilingual sites
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2014-06-05 ] Version 4.4.2.1767
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[bug] Some Virtuemart product details url may be blank under some
|
||||||
|
combinations of menu items linking to categories and products
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2014-06-04 ] Version 4.4.1.1762
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Per url Google publisher tag, in addition to the pre-existing
|
||||||
|
global publisher tag
|
||||||
|
[new] Google Analytics IP anonymization
|
||||||
|
|
||||||
|
[chg] More css for Facebook buttons, handling more templates
|
||||||
|
[chg] Clean internal caches upon installation, to avoid wrong new
|
||||||
|
versions display when switching between editions
|
||||||
|
[chg] Added a workaround for bug in Community Builder, not using Joomla
|
||||||
|
API to fetch some request variables
|
||||||
|
[chg] Hack to workaround Kunena custom routing method for some urls,
|
||||||
|
including pagination links, in Kunena 3.0.3+
|
||||||
|
[chg] Added canonical url when exporting urls to file
|
||||||
|
[chg] Moved router encodesegments() method to a helper, avoid issues
|
||||||
|
for some extensions running onAfterInitialise event several times
|
||||||
|
[chg] Added small bottom margin to social buttons, in case they wrap at
|
||||||
|
low width
|
||||||
|
|
||||||
|
[bug] Virtuemart product links can be wrong on multilingual sites under
|
||||||
|
some combinations of menu items direct links Fixes #325
|
||||||
|
[bug] Links to items in Joomla! fake "Uncategorised" category do not
|
||||||
|
comply with "insert menu item title" config setting
|
||||||
|
[bug] Social buttons could be displayed on featured articles view even
|
||||||
|
for articles which category was excluded
|
||||||
|
[bug] Sometimes Itemid-only links may have wrong language code in SEF
|
||||||
|
urls Fixes #323
|
||||||
|
[bug] Cannot switch language when using /index.php/ and Joomla config
|
||||||
|
does not match sh404SEF config Fixes #315
|
||||||
|
[bug] Joomla! language detection doesn't work anymore Fixes #324
|
||||||
|
[bug] Aliases for home page are saved and works, but are not displayed
|
||||||
|
on the edit url popup
|
||||||
|
[bug] Inserted tags for social buttons are not replaced when 'Only on
|
||||||
|
canonical page' param is on Fixes weeblr-dev/sh404sef-issues#319
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2014-04-09 ] Version 4.4.0.1725
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Added Linkedin share button to social buttons list
|
||||||
|
[new] Added warning messages on multilingual sites that Joomla!
|
||||||
|
languagefilter system plugin should now be enabled
|
||||||
|
[new] Analytics snippets now in JLayout, can be overriden in site
|
||||||
|
templates
|
||||||
|
[new] Adjust to changes in Joomla! routing API in J! 3.3
|
||||||
|
[new] Now checking Joomla! redirects table before declaring a 404, in
|
||||||
|
case some redirects existed prior to sh404sef usage
|
||||||
|
[new] Support for Google+ authorship information
|
||||||
|
[new] Added Twitter Cards support, global and per page
|
||||||
|
[new] Added optional Facebook Share button to social buttons Fixes 294
|
||||||
|
|
||||||
|
[chg] Simplified social buttons markup and css, better styling
|
||||||
|
[chg] Moved social buttons to JLayout, so that they can be overriden
|
||||||
|
from templates. Works in both J2.x and J3.x
|
||||||
|
[chg] Performance: check if shurl exists only once
|
||||||
|
[chg] Pagination doesn't work any more with Kunena 3.0.4 Fixes #310
|
||||||
|
[chg] Better detection of content urls when displaying social buttons
|
||||||
|
(Twitter, Facebook, G+)
|
||||||
|
[chg] Added toolbar access to configuration on all views
|
||||||
|
[chg] List of components to always leave as non-sef is now in remote
|
||||||
|
configuration
|
||||||
|
[chg] Better 3rd-party extensions compatiblity when "using Joomla!
|
||||||
|
router" or "leaving as non-sef"
|
||||||
|
[chg] Better multilingual compatiblity
|
||||||
|
[chg] Updated German language files - Thanks Alex H.
|
||||||
|
[chg] Updated Russian language files - Thanks Alex
|
||||||
|
[chg] Updated Swedish language files - Thanks Kristian
|
||||||
|
[chg] Updated language files (French, German)
|
||||||
|
[chg] Updated French translation
|
||||||
|
[chg] Increased tweet via account field in social plugin settings
|
||||||
|
[chg] CSS tweaking of social buttons
|
||||||
|
[chg] Warnings in Analytics manager, new in PHP 5.4
|
||||||
|
|
||||||
|
[bug] May display PHP warnings rendering pagination on multilingual
|
||||||
|
sites
|
||||||
|
[bug] Don't display \ in OpenGraph tag when page title has a $n
|
||||||
|
characters
|
||||||
|
[bug] Duplicate urls may disappear from url manager display when
|
||||||
|
customizing main url
|
||||||
|
[bug] Missing files and folders are not displayed as errors on control
|
||||||
|
panel
|
||||||
|
[bug] Showing error message upon url deletion, even though all went
|
||||||
|
fine
|
||||||
|
[bug] Wrong redirect from non-sef to sef on site using /index.php/
|
||||||
|
rewriting mode
|
||||||
|
[bug] Fatal error when exporting meta data Fixes #308
|
||||||
|
[bug] Warning displayed on some purge operations when file cache has
|
||||||
|
not been enabled yet
|
||||||
|
[bug] Wrong path to javascript file in Analytics manager, result in
|
||||||
|
analytics not loading
|
||||||
|
[bug] Remote configuration not read anymore, wrong url
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2014-01-23 ] Version 4.3.0.1671
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Addes support for Google Tags Manager
|
||||||
|
[new] One click update either through Joomla! updater or built-in
|
||||||
|
auto-updater
|
||||||
|
[new] Added Google Analytics Universal snippet handling
|
||||||
|
|
||||||
|
[chg] Account for upcoming Googlebot mobile user agent change
|
||||||
|
[chg] Updated Dutch translation - Thanks JoomlaDownloads
|
||||||
|
[chg] Updated Russian translation - Thanks Alex Smirnov
|
||||||
|
[chg] Make sure default ACL record is written to database upon
|
||||||
|
installation
|
||||||
|
[chg] Make sure default ACL record is written to database upon
|
||||||
|
installation
|
||||||
|
[chg] Added back remote configuration option to configuration page
|
||||||
|
[chg] Removed deprecated view code
|
||||||
|
[chg] More explicit error messages when saving config, urls, duplicates
|
||||||
|
|
||||||
|
[bug] Error message not displayed when server is not responding at all
|
||||||
|
to new version or security stats requests
|
||||||
|
[bug] Select a redirect for 404 button is not working Fixe #305
|
||||||
|
[bug] 404 records may not be purged when using the purge button
|
||||||
|
[bug] Urls may not be purged when using the purge button
|
||||||
|
[bug] Customizing url does not add old url to aliases list
|
||||||
|
[bug] Version number of newly installed version is not always displayed
|
||||||
|
on main control panel
|
||||||
|
[bug] Redirect from /index.php/something to /something even if set to
|
||||||
|
NOT use mod_rewrite Fixes #299
|
||||||
|
[bug] Logged in users are not allowed to view sites in offline mode
|
||||||
|
Fixes #240, fixes #297
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2013-11-02 ] Version 4.2.1.1586
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[bug] Introduced fatal bug in Joomla! versions pre-3.2 when preparing
|
||||||
|
release for Joomla! 3.2
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2013-11-01 ] Version 4.2.0.1582
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Automatic 301 redirect when trying to access an existing url with
|
||||||
|
/index.php/ while url rewriting is enabled
|
||||||
|
|
||||||
|
[chg] J! 3.2 backward compatibility break: ConfigModelComponent
|
||||||
|
refactoring, moving around, now requires to load a different file
|
||||||
|
[chg] Added workaround for J!3.2 API backward compat break
|
||||||
|
[chg] Add language information on urls created using "simple" mode, in
|
||||||
|
case it's missing and we're on a multilingual site Fixes #216
|
||||||
|
[chg] Let Akeeba go through offline mode. Not as secure as could be.
|
||||||
|
[chg] Added a workaround for bug in Virtuemart, creating fake request
|
||||||
|
variables, would prevent custom meta data to be inserted normally
|
||||||
|
Fixes #264
|
||||||
|
[chg] Skip versionning component to allow front end editing in J! 3.2+
|
||||||
|
[chg] Strict standards compliance, don't use JFilterInput statically
|
||||||
|
[chg] Added version check to prevent method name conflict due to change
|
||||||
|
in J! 3.2 router
|
||||||
|
[chg] Adjustments to changes in Joomla! 3.2 API (JTable interface)
|
||||||
|
[chg] Joomla! 3.2 change in API
|
||||||
|
[chg] Updated Pagination class to latest J! 3.1.x code
|
||||||
|
[chg] Pagination not displayed in Joomla! 3 on some pages. Added back
|
||||||
|
HTML prev and next tags onto pagination links Fixes #255
|
||||||
|
[chg] Now using consistently remote_addr. Fixes #198
|
||||||
|
[chg] Adjust to Kunena deprecating kimport function, would cause fatal
|
||||||
|
error
|
||||||
|
[chg] Joomla! does not update cached values in JRequest, resulting in
|
||||||
|
incorrect input if JRequest is used to read the "task" input
|
||||||
|
before a component is rendered, if the controller.task syntax is
|
||||||
|
used
|
||||||
|
[chg] J3.1 changed name of items associations parameter fixes #251
|
||||||
|
|
||||||
|
[bug] Incoming non-sef linking to a non-existing article is redirected
|
||||||
|
to home instead of letting Joomla! return a 404 Fixes #285
|
||||||
|
[bug] Article submitted from frontend may not be stored in the proper
|
||||||
|
category Fixes #291
|
||||||
|
[bug] Manual custom url is not displayed in url manager if there is a
|
||||||
|
404 by the same name and the custom url already has duplicates
|
||||||
|
Fixes #273
|
||||||
|
[bug] Notice error display under some circumstances upon creation of
|
||||||
|
some Virtuemart urls
|
||||||
|
[bug] Wrong default language read from Joomla! config, may result in
|
||||||
|
wrong language used to build sef urls, on multilingual sites
|
||||||
|
[bug] Wrong default language detected with Joomfish on multilingual
|
||||||
|
sites Fixes #267
|
||||||
|
[bug] Not reading cookie path and domain to set language cookie on
|
||||||
|
multilingual sites
|
||||||
|
[bug] Specifying a blacklisted IP with wildcards (*) blocks too many
|
||||||
|
users Fixes #204
|
||||||
|
[bug] Not redirecting anymore from /index.php to / Fixes #188
|
||||||
|
[bug] Only partial analytics reports displayed in analytics manager on
|
||||||
|
Joomla! 2.5.x Fixes #269
|
||||||
|
[bug] Does not comply with LanguageFilter plugin setting "Use default
|
||||||
|
langauge" on multilingual sites fixes #261
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2013-04-25 ] Version 4.1.0.1559
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[chg] Workaround for PHP bytecode cache systems that fail on valid PHP
|
||||||
|
code
|
||||||
|
[chg] Workaround for backward compatiblity issue in installer
|
||||||
|
introduced in Joomla! 3.1
|
||||||
|
|
||||||
|
[bug] On multilingual sites (J! 3.0+), hreflang tags are missing
|
||||||
|
[bug] Added check to avoid error if sh404SEF system plugin has been
|
||||||
|
disabled by user
|
||||||
|
[bug] Enforcing www option does not work when site is in a subfolder
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2013-03-07 ] Version 4.0.3.1552
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Characters counters are now also added to Joomla! backend pages
|
||||||
|
where page title and page description can be edited by users
|
||||||
|
[new] Added characters counters on page title and page description
|
||||||
|
fields of all sh404SEF admin pages; will display recommended
|
||||||
|
characters count ranges and show remaining characters count.
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2013-02-26 ] Version 4.0.2-rc.1544
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[chg] Updated Bulgarian, German, Spanish, French, Hungarian, Italian,
|
||||||
|
Dutch, Romanian, Russian and Swedish translations
|
||||||
|
[chg] Improved canonical tag handling, to manage multiple tags that can
|
||||||
|
be inserted by Joomla! 3+ and other extensions. Added a
|
||||||
|
configuration setting to enable/disable this feature
|
||||||
|
[chg] Program configuration is now overridable from remote
|
||||||
|
configuration
|
||||||
|
|
||||||
|
[bug] Fixed security issue in Open Graph implementation
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2013-02-18 ] Version 4.0.1 - Joomla! 3 compatible release candidate
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[chg] Main control panel now only loads global visits graphic, other
|
||||||
|
infos are only in Analytics manager
|
||||||
|
[chg] Added a check to similar urls plugin to prevent warnings
|
||||||
|
appearing under specific but undefined circumstances Fixes #215
|
||||||
|
[chg] Removed useless markup on control panel, under Access stats, when
|
||||||
|
Debug to log file is not activated
|
||||||
|
[chg] Allow aliases with % characters Fixes #217
|
||||||
|
[chg] A canonical tag is now always included in com_content article
|
||||||
|
pages (removes tracking vars, print flag)
|
||||||
|
[chg] Removed unused shSimpleLogger class
|
||||||
|
|
||||||
|
[bug] Error message is not displayed when one tries to save a new SEF
|
||||||
|
identical to an existing one
|
||||||
|
[bug] Security stats are not updated correctly on main control panel
|
||||||
|
[bug] Installable extension plugins are not loaded automatically Fixes
|
||||||
|
#208
|
||||||
|
[bug] Error page document is not saved inside the proper content
|
||||||
|
category
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2012-11-26 ] Version 3.7.0.1485
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[bug] Analytics exclude IP list is cleared when saving sh404SEF general
|
||||||
|
configuration fixes #190
|
||||||
|
[bug] Not cleaning up properly requests for Facebook channel urls
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2012-11-01 ] Version 3.6.4.1481
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[bug] Analytics snippet not inserted for non-logged in users Fixes #186
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2012-10-24 ] Version 3.6.3.1478
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[chg] Updated Swedish translation
|
||||||
|
[chg] Updated Russian translation
|
||||||
|
[chg] Updated French translation
|
||||||
|
[chg] Updated Hungarian translation
|
||||||
|
|
||||||
|
[bug] Adjusted to removal by Joomla of usertype. Would cause analytics
|
||||||
|
snippet to be inserted even if if it was disabled for some user
|
||||||
|
groups. Added a better selector, now showing a direct list of
|
||||||
|
user groups, allowing simple selection. Fixes 174
|
||||||
|
[bug] URLs may not be removed from disk cache when deleted one at a
|
||||||
|
time from backend Url manager
|
||||||
|
[bug] 404 page category created with wrong parent_id, may not be
|
||||||
|
available
|
||||||
|
[bug] Incorrect version check
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2012-10-12 ] Version 3.6.2.1465
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Added check and message in case user has disabled either shLib
|
||||||
|
system plugin or sh404sef system plugin
|
||||||
|
|
||||||
|
[chg] Added a protection against invalid Virtuemart non-sef urls,
|
||||||
|
missing product_id
|
||||||
|
[chg] Added protection against pages with invalid UTF-8 characters,
|
||||||
|
that were breaking SEO features
|
||||||
|
|
||||||
|
[bug] Leave URL as non-sef doesn't work (regression)
|
||||||
|
[bug] Posisble PHP fatal error when shLib plugin is not installed
|
||||||
|
before sh404SEF plugin (due to older installations, possibly by
|
||||||
|
other extensions using shLib)
|
||||||
|
[bug] Incorrect date tag in plugins manifest files, release date was
|
||||||
|
not written to manifest when building the release
|
||||||
|
[bug] Automatic redirects from non-sef to sef don't work
|
||||||
|
[bug] Virtuemart router.php file does not create sef links for category
|
||||||
|
pages, when they are linked to a menu item. Instead it returns an
|
||||||
|
Itemid. We now create the SEF link in such cases
|
||||||
|
[bug] Release date is not inserted in manifest file
|
||||||
|
[bug] Insert news site unique id in urls only inserts article id, not
|
||||||
|
full unique if (introduced in 3.6.0)
|
||||||
|
[bug] Possible display of warning when performing security log files
|
||||||
|
garbage collection if security log files folder has not been
|
||||||
|
created yet
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2012-09-18 ] Version 3.6.0.1422
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Added Joomla! version check before installing new version
|
||||||
|
[new] Added a resource manager to handle shared programming libraries
|
||||||
|
amongst several extensions
|
||||||
|
[new] Added shared memory caching (memcache, APC, etc) for sef/non-sef
|
||||||
|
url storage, and for database queries
|
||||||
|
[new] Pin it button nows also handle K2 independant images in items
|
||||||
|
Tracker #155
|
||||||
|
[new] Added global Joomla! ACL permissions option
|
||||||
|
[new] Added Virtuemart 2+ plugin Tracker #144
|
||||||
|
[new] Added "gclid" (from Google AdWords) to list of tracking vars that
|
||||||
|
are stripped before doing checks for custom page title,
|
||||||
|
descriptions, etc Added also to remote configuration file, so all
|
||||||
|
users with "Enable remote configuration" set to Yes will benefit
|
||||||
|
immediately, without having to upgrade
|
||||||
|
[new] Open graph url tag is now cleaned from possible Google analytics
|
||||||
|
tracking vars Tracker #146
|
||||||
|
[new] Implemented "Vary" http headers when automatic template switching
|
||||||
|
is enabled for mobile devices Tracker #136
|
||||||
|
[new] Mobile template is now presented to Googlebot-Mobile crawler, if
|
||||||
|
mobile device detection is enabled Tracker #131
|
||||||
|
[new] Added detection of a query var for automatic mobile template
|
||||||
|
switcher. Now webmaster can add
|
||||||
|
"sh404SEF_override_mobile_detection=force_mobile" or
|
||||||
|
"sh404SEF_override_mobile_detection=force_desktop" to a link on a
|
||||||
|
page, allowing user to override mobile device detection by
|
||||||
|
sh404SEF. This is maintained by a cookie for subsequent clicks on
|
||||||
|
the same page, and a rel="canonical" link is added to avoid
|
||||||
|
duplicate content
|
||||||
|
[new] Added method for 3rd-party developers to obtain SEF urls from
|
||||||
|
inside the backend of a Joomla! site:
|
||||||
|
Sh404sefHelperGeneral::getSefFromNonSef( $nonSefUrl,
|
||||||
|
$fullyQualified = true, $xhtml = false, $ssl = null) - Method is
|
||||||
|
autoloaded, no need to include file Tracker #60
|
||||||
|
|
||||||
|
[chg] Removed useless Kunena parameters
|
||||||
|
[chg] Installer now checks version compatibility with any previously
|
||||||
|
installed shared resource (such as shlib)
|
||||||
|
[chg] Updated Russian, Swedish, Italian, Romanian, French, Spanish,
|
||||||
|
Dutch, German and Spanish language files
|
||||||
|
[chg] Updated Open Graph data implementation according to latest
|
||||||
|
Facebook specs Tracker #154
|
||||||
|
[chg] Export urls wizard now uses "slow server" settings, to make sure
|
||||||
|
any number of urls can be exported w/o exceeding server resources
|
||||||
|
Tracker #119
|
||||||
|
[chg] Cleaned new urls storage process (getSefLocation()), use only db
|
||||||
|
helper, exceptions and removed redundant code (should also
|
||||||
|
improve perf in some edge cases)
|
||||||
|
[chg] Moved analytics display temp files to /media dir
|
||||||
|
[chg] Simplified 404 error page edit page, now using consistently the
|
||||||
|
same article category ('sh404sef custom content') Tracker #151
|
||||||
|
[chg] Removed uneeded css
|
||||||
|
[chg] Moved all log files to Joomla! standard log directory Tracker #50
|
||||||
|
[chg] Now using shLib shared programming library
|
||||||
|
[chg] Moved database error handling entirely to either exceptions, or
|
||||||
|
dual exception/errornum handling
|
||||||
|
[chg] sef_404::getCategories() now deprecated, write call to log file.
|
||||||
|
Use Sh404sefModelSlugs model instead
|
||||||
|
[chg] Dropped remaining uses of Joomla! DS constant
|
||||||
|
[chg] Updated plugin to handle Kunena 2.x Tracker #145
|
||||||
|
[chg] Removed uneeded Docman configuration options Tracker #152
|
||||||
|
[chg] Parsing incoming requests with Joomla! router (when user asked
|
||||||
|
so) is now done last, as Joomla! router jumps to 404 page if it
|
||||||
|
does not recognize a request, preventing us from doing shUrl and
|
||||||
|
custom redirects checks
|
||||||
|
[chg] Now disabling Joomla! caching when displaying 404 page, to be
|
||||||
|
able insert our custom text (current url, and similar urls
|
||||||
|
suggestions) Also: language detection may not work when full page
|
||||||
|
caching is on.
|
||||||
|
[chg] Added default value to default language function, in case default
|
||||||
|
language has not been saved in configuration
|
||||||
|
[chg] Comply with PHP Strict standards
|
||||||
|
[chg] Added a workaround for Joomla! loading its platform language
|
||||||
|
strings before the SEF url has been decoded. As pagination
|
||||||
|
strings are stored inside platform language files, this may
|
||||||
|
result under some circumstances in pagination strings (Start,
|
||||||
|
end, ...) not being translated Tracker #143
|
||||||
|
|
||||||
|
[bug] Some regular expressions were not UTF-8 compatible - Thks
|
||||||
|
G.Papadakis
|
||||||
|
[bug] Sef and non-sef urls are not displayed when editing a shurl or
|
||||||
|
meta data
|
||||||
|
[bug] Offline display template lacks css when site is in a
|
||||||
|
sub-directory of server
|
||||||
|
[bug] On multilingual sites, nowonly try to redirect user to her
|
||||||
|
language on homepage, as otherwise we wouldn't know what the
|
||||||
|
correct destination would be
|
||||||
|
[bug] Pagination may not work on some components (those leaving page
|
||||||
|
number out of the SEF url, or not using standard Joomla!
|
||||||
|
JPagination object) when user has not set SEF urls on in global
|
||||||
|
configuration Tracker #142
|
||||||
|
[bug] Possible infinite redirect loop when some custom query vars are
|
||||||
|
added to a homepage request
|
||||||
|
[bug] Wrong page number in page title when a blog view is used as front
|
||||||
|
page Tracker #141
|
||||||
|
[bug] Prevent notice error when displaying social buttons on a totally
|
||||||
|
empty article (!)
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2012-06-27 ] Version 3.5.1.1299
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[chg] Updated Bulgarian, French, Hungarian, Russian and Swedish
|
||||||
|
translations
|
||||||
|
|
||||||
|
[bug] Homepage custom meta data is not displayed anymore Tracker #132
|
||||||
|
[bug] Featured articles view does not get proper url on second or more
|
||||||
|
languages, on multilingual sites (reported by Simon Gendrin)
|
||||||
|
Tracker #134
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2012-06-14 ] Version 3.5.0.1295
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Reworked rel="prev" and rel="next" head tags, comply now with
|
||||||
|
Google guidelines and improves paginated content handling by
|
||||||
|
search engines
|
||||||
|
[new] Added Pinterest support to social buttons AND Analytics reports.
|
||||||
|
Pinning actions are tracked inside Google Analytics and your site
|
||||||
|
control panel like other social buttons Tracker #102
|
||||||
|
[new] Google Anlytics backend integration now using version 2.4 of API
|
||||||
|
- as version 2.3 will be shut down in july 2012
|
||||||
|
|
||||||
|
[chg] Updated Bulgarian, German, Spanish, French, Hungarian, Italian,
|
||||||
|
Dutch, Romanian, Russian and Swedish translations
|
||||||
|
[chg] Removed uneeded language parameter Tracker #125
|
||||||
|
[chg] Added check to prevent some notice error display when there is no
|
||||||
|
default language version of an article or category, on
|
||||||
|
multilingual sites
|
||||||
|
[chg] Added check to prevent some notice error display when there is no
|
||||||
|
default language version of an article or category, on
|
||||||
|
multilingual sites
|
||||||
|
[chg] Added check to prevent notice error display if user completely
|
||||||
|
delete the "Page" text from configuration Tracker #113
|
||||||
|
[chg] Added workaround for bug in Joomla! front end com_media image
|
||||||
|
browser, probably using relative urls Tracker #120
|
||||||
|
[chg] Adjust 404 errors logging in case server is running IPV6
|
||||||
|
[chg] Some changes for Falang compatibility
|
||||||
|
[chg] CSS tweaking to the wizards display
|
||||||
|
[chg] Updated Russian translation (Alex Smirnov)
|
||||||
|
|
||||||
|
[bug] SEF url is saved to database when doing a 301 automatic redirect
|
||||||
|
from non-sef to sef, when set to use Joomla! router, which should
|
||||||
|
not save sef url to db Tracker #114
|
||||||
|
[bug] Under some circumstances, cache file lock file may not be deleted
|
||||||
|
and cache not used anymore Tracker #115
|
||||||
|
[bug] Incorrect paginated urls on home page of some multilingual sites
|
||||||
|
[bug] Social buttons link is not correct when using "no .htaccess"
|
||||||
|
rewrite mode Tracker #121
|
||||||
|
[bug] QRCode creator does not add /index.php/ prefix when not using a
|
||||||
|
.htaccess file Tracker #116
|
||||||
|
[bug] Under some circumstances, social buttons can be displayed on
|
||||||
|
category pages, even of set to display only on canonical page
|
||||||
|
Tracker #108
|
||||||
|
[bug] Incorrect call to framework getMenu() method. No visible effect
|
||||||
|
though
|
||||||
|
[bug] Collect memory & time would not work, need update to J! 2.5
|
||||||
|
format Tracker #107
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2012-02-13 ] Version 3.4.6.1269
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Added 301 auto-redirect to protect against pages of your site
|
||||||
|
which have been Facebook-liked using old method, that can
|
||||||
|
generate fb_xd_fragment and fb_xd_bust duplicate content issue
|
||||||
|
Tracker #95
|
||||||
|
[new] Implemented channelUrl for Facebook like/send button, to protect
|
||||||
|
against fb_xd_fragment and fb_xd_bust SEO issues Tracker #95
|
||||||
|
[new] You can now select exactly which social button to display on a a
|
||||||
|
tag by tag basis, using 'type' attribute in
|
||||||
|
{sh404sef_social_buttons} tags
|
||||||
|
[new] Added canonical tag handling for J! 2.5 new com_finder "Smart
|
||||||
|
search"
|
||||||
|
[new] Workaround for issue in J! 2.5: cannot use categories model from
|
||||||
|
outside of com_content
|
||||||
|
|
||||||
|
[chg] Updated Spanish translation by Hertak
|
||||||
|
[chg] Simple title and better robots meta on 404 page
|
||||||
|
[chg] Don't show Open graph data on 404 pages
|
||||||
|
[chg] Removed Virtuemart 1.x plugin
|
||||||
|
[chg] Better detection of item category, when displaying social
|
||||||
|
buttons, will work also when article is displayed inside a module
|
||||||
|
Tracker #103
|
||||||
|
[chg] Replaced deprecated function in Mosets Tree plugin Tracker #97
|
||||||
|
[chg] Updated Russian translation (Alex Smirnov)
|
||||||
|
[chg] Updated Romanian translation (Valentin Barbu)
|
||||||
|
[chg] Updated Italian translation (Andrea Castrovilli)
|
||||||
|
[chg] Updated German translation (Jürgen Hörmann)
|
||||||
|
[chg] Updated Bulgarian translation (Kiril Yoviev)
|
||||||
|
[chg] Cleaned up all language files, key deduplication, ready to upload
|
||||||
|
to translation server
|
||||||
|
[chg] Moved some of the social buttons javascript links to end of body
|
||||||
|
instead of end of document head Tracker #385
|
||||||
|
[chg] Added a check to handle name conflict between Mighty Touch and
|
||||||
|
JomSocial, avoiding fatal errors Tracker #393
|
||||||
|
[chg] Changed default layout for Twitter and G+, to use shURls and hide
|
||||||
|
clicks count Tracker #81
|
||||||
|
[chg] Can now modify URLs in a case-sensitive manner Tracker #379
|
||||||
|
[chg] Updated Dutch translation by Gerard van Enschut Tracker #88
|
||||||
|
[chg] Update to Swedish translation, by JokrSolutions
|
||||||
|
[chg] Added a check in case user enters a space as an alias to an URL
|
||||||
|
Tracker #87
|
||||||
|
|
||||||
|
[bug] Prevent creating useless links to 404 page, when site is crawled
|
||||||
|
[bug] Outbound links images are not inserted into page if site is in
|
||||||
|
root dir Tracker #96
|
||||||
|
[bug] file cache TTL is multiplied by 86400 seconds (a day) instead of
|
||||||
|
3600 (an hour) Tracker #98
|
||||||
|
[bug] A shurl is created for homepage on multilingual sites Tracker
|
||||||
|
#105
|
||||||
|
[bug] Infinite redirect loop when site is accessed by crawlers on
|
||||||
|
multilingual sites when autoredirect from non-sef to sef is on
|
||||||
|
Tracker #104
|
||||||
|
[bug] May generate loop redirects when adding aliases identical to
|
||||||
|
original url, except for the letter case
|
||||||
|
[bug] Custom canonical URL is not saved if it is the only custom meta
|
||||||
|
data for an url Tracker #94
|
||||||
|
[bug] Kunena plugin: new post from category doesn't have a distinct URL
|
||||||
|
Tracker #93
|
||||||
|
[bug] Rewriting prefix is lost when redirecting incoming url to the
|
||||||
|
same with correct case Tracker #91
|
||||||
|
[bug] Open graph fb:admins tag should use "property" field, not "name"
|
||||||
|
[bug] When "Use default" is selected as Object type option for specific
|
||||||
|
urls, the Opengraph data object type is not inserted Tracker #395
|
||||||
|
[bug] Batch-modifying page title or description would erase other meta
|
||||||
|
data previously set, if any Tracker #86
|
||||||
|
[bug] Added test to avoid duplicating records when Apply and Save
|
||||||
|
button are pressed in sequence when adding custom meta data to a
|
||||||
|
URL Tracker #85
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-12-13 ] Version 3.4.4.1226
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Added option to use shURL instead of full SEF url in social
|
||||||
|
buttons. Especially useful for Tweeting, to better use those 140
|
||||||
|
characters Tracker #67
|
||||||
|
[new] Can now restrict display of social buttons to only some content
|
||||||
|
categories Tracker #76
|
||||||
|
|
||||||
|
[chg] Removed display of unused hit counter Tracker #80
|
||||||
|
[chg] Updated French translation
|
||||||
|
[chg] Removed autoredirect from Joomla SEF to SEF Tracker #78
|
||||||
|
[chg] When saving data from Title and metas manager, if one url is
|
||||||
|
incorrect, we now attempt to save remaining data, in case some of
|
||||||
|
it is correct and can be saved
|
||||||
|
[chg] We now delete a meta data record if user happens to clear all
|
||||||
|
meta data fields, save space and avoid having a meta data icon
|
||||||
|
show in url manager when meta data have been cleared Tracker #75
|
||||||
|
[chg] Social buttons should not be displayed when printing Joomla!
|
||||||
|
articles Tracker #74
|
||||||
|
[chg] Added some styles to social buttons background
|
||||||
|
[chg] Added a check to prevent recording empty urls in 404 list Tracker
|
||||||
|
#390
|
||||||
|
|
||||||
|
[bug] Display mysql error when using slow server mode and sorting urls
|
||||||
|
by duplicates, meta or alias Tracker #389
|
||||||
|
[bug] Popup window too small when editing some urls, poor display
|
||||||
|
[bug] If Joomla! full page cache is activated, social buttons may
|
||||||
|
sometimes not be inserted, or may not work
|
||||||
|
[bug] Disable social buttons insertion if global "Activate SEO
|
||||||
|
management" is disabled by user
|
||||||
|
[bug] In case of incoming requests for a non-sef url, variables from
|
||||||
|
the home page link could be added to this non-sef
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-11-22 ] Version 3.4.3.1212
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Updated Romanian translation
|
||||||
|
|
||||||
|
[chg] Updated Swedish translation by BR Kristian
|
||||||
|
[chg] Added workaround for JDispatcher::...handler not recognized when
|
||||||
|
running an opcache system
|
||||||
|
|
||||||
|
[bug] Notices can be displayed if site runs with sh404sef disabled and
|
||||||
|
meta data management is activated
|
||||||
|
[bug] Could display a notice error trying to redirect a 404 url, when
|
||||||
|
there is no suggested sef url found
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-11-19 ] Version 3.4.2.1210
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[chg] Added protections so that social features are not triggered on
|
||||||
|
404 pages
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-11-19 ] Version 3.4.1.1207
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[bug] Database error when upgrading from a previous version (site would
|
||||||
|
work fine). Immediately installing a second time fixes the error.
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-11-18 ] Version 3.4.0.1205
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Analytics reports now includes social engagement information:
|
||||||
|
Facebook likes, Tweet, 1+ actions
|
||||||
|
[new] Social buttons can be inserted automatically in Joomla! articles,
|
||||||
|
below title or at end of article
|
||||||
|
[new] Added creation of social networking buttons, handling for
|
||||||
|
Facebook Like and Send, Tweeter, Google +1 and the new Google
|
||||||
|
Page badge. Will place social buttons anywhere in content, other
|
||||||
|
extensions, modules or even templates
|
||||||
|
[new] Added automatic creation and management of Open Graph meta data,
|
||||||
|
to allow better indexing by Facebook, Google+ and other social
|
||||||
|
networks
|
||||||
|
[new] Added more protection against fatal error if user accidentally
|
||||||
|
disable sh404SEF system plugin Tracker #375
|
||||||
|
[new] Added tracking of 404 pages on Google Analytics - you'll get 404s
|
||||||
|
count on sh404SEF Analytics report, as well as on Google
|
||||||
|
Analytics panel
|
||||||
|
[new] Added "All categories" options to insert article id setting
|
||||||
|
Tracker #53
|
||||||
|
[new] 404 error page mechanism now compatible with Joomla! multilingual
|
||||||
|
feature. Can have 404 error page per language
|
||||||
|
|
||||||
|
[chg] Re-enabled automatic language redirect upon visitor first visit,
|
||||||
|
as workaround to counter bug in Firefox and IE9 was found for
|
||||||
|
this to work properly Tracker #59
|
||||||
|
[chg] Group meta tag insertion when possible, better performance on
|
||||||
|
very large pages
|
||||||
|
[chg] Added support for multilingual menu item associations, and a new
|
||||||
|
option to Enable/disable multilingual support in sh404SEF. Use
|
||||||
|
instead of Enabling/Disabling Joomla! Language filter plugin
|
||||||
|
Tracker #57
|
||||||
|
[chg] Simplified similar urls plugin database query, to reduce overhead
|
||||||
|
Tracker #55
|
||||||
|
[chg] Moved sh404SEF 404 error page content from the "Uncategorised"
|
||||||
|
category to our own, as localized versions of Joomla! would call
|
||||||
|
the "Uncategorise" category differently, making it impossible to
|
||||||
|
save or retrieve our error page. The change is done by install
|
||||||
|
script, and existing error pages will be moved over to new
|
||||||
|
category automatically
|
||||||
|
[chg] Start and end pagination links now also use html5 rel and next
|
||||||
|
tags as needed Tracker #372
|
||||||
|
[chg] Updated css on site main control panel sh404SEFmodule
|
||||||
|
[chg] Clarified one Swedish language tooltip
|
||||||
|
[chg] Moved some options (itemid management) to core instead of plugin,
|
||||||
|
so that they can be activated even if extension-specific plugin
|
||||||
|
does not implement them
|
||||||
|
|
||||||
|
[bug] Whitelisting user agent doesn't prevent anti-flooding to operate
|
||||||
|
[bug] Notice errors could be displayed if no similar urls found when
|
||||||
|
trying to redirect a 404
|
||||||
|
[bug] On multipage articles, when not displaying the table of content,
|
||||||
|
first page has 2 different urls created Tracker #56
|
||||||
|
[bug] under some circumstances, custom page title and meta data may not
|
||||||
|
be inserted in the page Tracker #47
|
||||||
|
[bug] getCategories function called statically, but not declared so,
|
||||||
|
could cause some notices errors on some servers
|
||||||
|
[bug] When auto-redirecting non-sef to SEF url, some get variables may
|
||||||
|
not be passed along on some occasions
|
||||||
|
[bug] Itemid is lost on "Edit article" icons for Joomla content Tracker
|
||||||
|
#49
|
||||||
|
[bug] Kunena plugin: wrong url for editing profile when "Short url to
|
||||||
|
profile" option is enabled Tracker #369
|
||||||
|
[bug] On 404 error pages, if user removes the "similar urls" text from
|
||||||
|
the template, the marker for the faulty requested urls is not
|
||||||
|
replaced either Tracker #370
|
||||||
|
[bug] Regression: custom meta_ext plugin not used anymore
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-09-05 ] Version 3.3.0.1122
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Now providing a QRCode for each SEF url, in URL manager Tracker
|
||||||
|
#319
|
||||||
|
[new] Integrated Swedish translation, by BR Kristian Tracker #39
|
||||||
|
[new] Improved SEO for paginated content: now use HTML5 prev and next
|
||||||
|
tags on all paginated links Tracker #36
|
||||||
|
[new] Added option to completely exclude category name from page title
|
||||||
|
(on Joomla! content) Tracker #38
|
||||||
|
|
||||||
|
[chg] Added max url lenght on custom urls input fields
|
||||||
|
[chg] Replaced a hardcoded text on control panel with language file
|
||||||
|
string
|
||||||
|
[chg] Removed ability to not translate urls (on multilingual sites), as
|
||||||
|
this would cause errors, and we'll have to wait for Joomfish to
|
||||||
|
build a general solution Tracker #42
|
||||||
|
[chg] Updated com_banners plugin Tracker #43
|
||||||
|
|
||||||
|
[bug] Sometimes a warning could be displayed when redirecting an alias
|
||||||
|
with an added query string
|
||||||
|
[bug] Aliases that are non-sef urls are not taken into account
|
||||||
|
[bug] Always append Itemid to SEF url would not work, moved language
|
||||||
|
string to another file to fix Tracker #44
|
||||||
|
[bug] Exact error message not displayed when saving data in Title and
|
||||||
|
metas manager, displays generic message instead 'Something went
|
||||||
|
wrong on the server' Tracker #41
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-07-19 ] Version 3.2.0.1108
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Joomla 1.7 compat: load mootols in backend
|
||||||
|
|
||||||
|
[chg] Compat with 1.7: adjusted to modified JDatabase class
|
||||||
|
replacePrefix() method, would prevent shUrls to be created
|
||||||
|
[chg] Added protection against sites with no default menu items, or
|
||||||
|
default menu items set to not be publicly visible. Would cause a
|
||||||
|
fatal error Tracker #33
|
||||||
|
[chg] Reduced url max length, very long urls could cause 404 Tracker
|
||||||
|
#32
|
||||||
|
[chg] Added compatibility layer for shRouter::shGetPageInfo()
|
||||||
|
|
||||||
|
[bug] Installation of 404 page article was commented out!
|
||||||
|
[bug] Aliases with a trailing / are not taken into a account
|
||||||
|
[bug] Preview links in backend does not use /index.php/ if in 'no
|
||||||
|
htaccess' mode
|
||||||
|
[bug] Error doc configuration page would only list sh404SEF default
|
||||||
|
error doc, would miss other Uncategorised articles in select list
|
||||||
|
Tracker #35
|
||||||
|
[bug] Missing shIncludeMetaPlugin() function in page content rewriting
|
||||||
|
feature Tracker #31
|
||||||
|
[bug] When auto-redirect from non-sef to sef is activated, it is not
|
||||||
|
possible to edit articles or weblinks on the front end Tracker
|
||||||
|
#30
|
||||||
|
[bug] Still using old #__redirection table when checking new shurl
|
||||||
|
creation, could prevent creation of shurl in some cases
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-06-30 ] Version 3.1.5.1098
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Properly handling multilanguage, the SEO way. Warning: Joomla!
|
||||||
|
LanguageFilter system plugin must be DISABLED!! Tracker #26
|
||||||
|
[new] Updated 3rd-party SEF url plugins installer to J! 1.6 format
|
||||||
|
[new] Handling of Joomla! multi-lingual features, still need some
|
||||||
|
tweaking for home page links Tracker #26
|
||||||
|
[new] Automatic handling of canonical urls for print version of joomla
|
||||||
|
articles
|
||||||
|
[new] Added backward compatiblity class 'shRouter' for using J! 1.5
|
||||||
|
plugins in J! 1.6 Tracker #24
|
||||||
|
|
||||||
|
[chg] Kunena plugin largely updated with help from Matias Griese,
|
||||||
|
increased performance and compatibility with all Kunena versions
|
||||||
|
Tracker #355
|
||||||
|
[chg] Some SEF links may no be rewritten when Joomla SEF setting is
|
||||||
|
off, as the SEF plugin checks directly Joomla config instead of
|
||||||
|
asking router for current SEF mode Tracker #27
|
||||||
|
[chg] Updated 'Home page URL' parameter tooltip
|
||||||
|
[chg] Updated links to new support site url
|
||||||
|
|
||||||
|
[bug] Bad query on uninstalling sh404SEF while removing database tables
|
||||||
|
[bug] May generate fatal error on page 2 or more of Blog view, when no
|
||||||
|
specific number of items per page has been set at menu item level
|
||||||
|
(ie using only global params)
|
||||||
|
[bug] Using old $database global in com_newsfeeds and mosets tree
|
||||||
|
plugin, would cause fatal error Tracker #28
|
||||||
|
[bug] Sometimes urls consisting only of an Itemid were not properly
|
||||||
|
handled
|
||||||
|
[bug] Jomsocial frontpage and profile page have same url when user not
|
||||||
|
logged in
|
||||||
|
[bug] SEF url not created when a category is included in url
|
||||||
|
[bug] Missing category for the * language when using more than one
|
||||||
|
language can result in empty sef url
|
||||||
|
[bug] On url list, first attempt to reach page 2 or more after logging
|
||||||
|
in stays on page one Tracker #359
|
||||||
|
[bug] Fatal error creating sef urls for Community Builder Tracker #23
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-06-07 ] Version 3.1.4.1078
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[chg] Changed SEF url to user edit profile Tracker #22
|
||||||
|
|
||||||
|
[bug] "view" parameter not revoved from SEF urls for Search component
|
||||||
|
Tracker #21
|
||||||
|
[bug] Id not removed from sef url when showing "All categories" Tracker
|
||||||
|
#19
|
||||||
|
[bug] Fatal error in com_contact plugin Tracker #18
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-06-03 ] Version 3.1.3.1073
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] For Uncategorized items, user can now select to either use only
|
||||||
|
item title in url (recommended) or insert menu item title Tracker
|
||||||
|
#12
|
||||||
|
[new] Registration link was not SEF
|
||||||
|
|
||||||
|
[bug] Sometimes Meta description is not inserted by sh404sef Tracker
|
||||||
|
#17
|
||||||
|
[bug] Insert id in article url does not work when "All categories" is
|
||||||
|
selected Tracker #14
|
||||||
|
[bug] Create an account link cause fatal error Tracker #13
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
[ 2011-05-31 ] Version 3.1.2.1071
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[new] Reworked short urls system, now called shURL, faster and shorter.
|
||||||
|
Can be created without having to purge existing SEF urls. Prevent
|
||||||
|
collisions with existing SEF or aliases, bad words filtering
|
||||||
|
[new] Added shortlinks tag configuration page
|
||||||
|
[new] Component, module and plugins install/uninstall, complying with
|
||||||
|
preverve configuration settings
|
||||||
|
|
||||||
|
[chg] Separated forced update flag between version check and remote
|
||||||
|
config check
|
||||||
|
[chg] Converted old languages files to Joomla! language file format
|
||||||
|
(ini)
|
||||||
|
[chg] Version checker can now handle multiple version file servers
|
||||||
|
|
||||||
|
[bug] Error in database class, would cause purging urls to fail
|
||||||
|
[bug] Can't use pagination links or other actions on meta manager after
|
||||||
|
using the save button Tracker #336
|
||||||
|
[bug] Issue with arrays in urls, when using only non-sef urls
|
||||||
@ -0,0 +1,306 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC'))
|
||||||
|
die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement analytics handling
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefClassBaseanalytics
|
||||||
|
{
|
||||||
|
// default end point for the analytics service
|
||||||
|
protected $_endPoint = '';
|
||||||
|
|
||||||
|
// default authorization url
|
||||||
|
protected $_authPoint = '';
|
||||||
|
|
||||||
|
// application key
|
||||||
|
protected $_appKeys = array();
|
||||||
|
|
||||||
|
// account list
|
||||||
|
protected $_accounts = array();
|
||||||
|
|
||||||
|
// SEF configuration
|
||||||
|
protected $_config = null;
|
||||||
|
|
||||||
|
// options for current request (ie account id, format
|
||||||
|
protected $_options = null;
|
||||||
|
|
||||||
|
// authorization token, to be cached
|
||||||
|
protected $_Auth = '';
|
||||||
|
|
||||||
|
public function fetchAnalytics($config, $options)
|
||||||
|
{
|
||||||
|
|
||||||
|
// store parameters
|
||||||
|
$this->_config = $config;
|
||||||
|
$this->_options = $options;
|
||||||
|
|
||||||
|
// prepare a default response object
|
||||||
|
$response = new stdClass();
|
||||||
|
$response->status = true;
|
||||||
|
$response->statusMessage = JText::_('COM_SH404SEF_CLICK_TO_CHECK_ANALYTICS');
|
||||||
|
$response->note = '';
|
||||||
|
|
||||||
|
// connect to server and fetch data
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$rawResponse = $this->_fetchData();
|
||||||
|
}
|
||||||
|
catch (Exception $e)
|
||||||
|
{
|
||||||
|
$response->status = false;
|
||||||
|
$response->statusMessage = $e->getMessage();
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return response
|
||||||
|
$response->analyticsData = $rawResponse;
|
||||||
|
|
||||||
|
// attach html select list or input boxes to response, to allow user to filter the data viewed
|
||||||
|
$response->filters = $this->_prepareFilters();
|
||||||
|
|
||||||
|
// update date/time display
|
||||||
|
$response->statusMessage = JText::sprintf('COM_SH404SEF_UPDATED_ON', strftime('%c'));
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _fetchData()
|
||||||
|
{
|
||||||
|
|
||||||
|
// first try to connect, if we don't already have a token
|
||||||
|
$this->_getAuthToken();
|
||||||
|
|
||||||
|
// get the http client
|
||||||
|
$hClient = Sh404sefHelperAnalytics::getHttpClient();
|
||||||
|
|
||||||
|
// fetch account list from supplier
|
||||||
|
$this->_fetchAccountsList();
|
||||||
|
|
||||||
|
// and find about which one to use (use first one is none selected from a previous request
|
||||||
|
//if (empty($this->_options['accountId']))
|
||||||
|
//{
|
||||||
|
$this->_options['accountId'] = Sh404sefHelperAnalytics::getDefaultAccountId($this->_accounts);
|
||||||
|
//}
|
||||||
|
|
||||||
|
// check in case we don' have valid account ID
|
||||||
|
if (empty($this->_options['accountId']))
|
||||||
|
{
|
||||||
|
throw new Sh404sefExceptionDefault('Empty account ID to query analytics API. Contact admin.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a report object
|
||||||
|
$className = 'Sh404sefAdapterAnalytics' . strtolower($this->_config->analyticsType) . 'report' . strtolower($this->_options['report']);
|
||||||
|
$report = new $className();
|
||||||
|
|
||||||
|
// ask it to perform API requests as needed,
|
||||||
|
$dataResponse = $report->fetchData($this->_config, $this->_options, $this->_Auth, $this->_endPoint, $this->_getAppKey());
|
||||||
|
|
||||||
|
// return data response for further processing
|
||||||
|
return $dataResponse;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch list of accounts, to be overloaded
|
||||||
|
*/
|
||||||
|
protected function _fetchAccountsList()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache authorization token
|
||||||
|
*/
|
||||||
|
protected function _getAuthToken()
|
||||||
|
{
|
||||||
|
|
||||||
|
// create cache Id and get cache object
|
||||||
|
$cacheId = md5($this->_config->analyticsPassword . $this->_config->analyticsUser . 'sdfhk546548-(}=])))');
|
||||||
|
|
||||||
|
$cache = JFactory::getCache('sh404sef_analytics_auth');
|
||||||
|
$cache->setLifetime(10080); // cache result for 7 days
|
||||||
|
$cache->setCaching(1); // force caching on
|
||||||
|
|
||||||
|
$this->_Auth = $cache->get(array($this, 'doGetAuthToken'), $args = array(), $cacheId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* performs actuall request to get token
|
||||||
|
*/
|
||||||
|
public function doGetAuthToken()
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->_prepareConnectRequest();
|
||||||
|
$connectReponse = $this->_connect();
|
||||||
|
$this->_handleConnectResponse($connectReponse);
|
||||||
|
|
||||||
|
return $this->_Auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to analytics supplier
|
||||||
|
*
|
||||||
|
* Meant to be overloaded by adapter
|
||||||
|
*
|
||||||
|
* @param $config , sef config object, holding connecton parameters
|
||||||
|
*/
|
||||||
|
protected function _connect()
|
||||||
|
{
|
||||||
|
|
||||||
|
// get the http client
|
||||||
|
$hClient = Sh404sefHelperAnalytics::getHttpClient();
|
||||||
|
|
||||||
|
// establish connection with available methods
|
||||||
|
$adapters = array('Zendshl_Http_Client_Adapter_Curl', 'Zendshl_Http_Client_Adapter_Socket');
|
||||||
|
$rawResponse = null;
|
||||||
|
|
||||||
|
// perform connect request
|
||||||
|
foreach ($adapters as $adapter)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$hClient->setAdapter($adapter);
|
||||||
|
$rawResponse = $hClient->request();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception $e)
|
||||||
|
{
|
||||||
|
// we failed, let's try another method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return if error
|
||||||
|
if (empty($rawResponse))
|
||||||
|
{
|
||||||
|
$msg = 'unknown code';
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, JText::sprintf('COM_SH404SEF_ERROR_CHECKING_ANALYTICS', $msg));
|
||||||
|
throw new Sh404sefExceptionDefault(JText::sprintf('COM_SH404SEF_ERROR_CHECKING_ANALYTICS', $msg));
|
||||||
|
}
|
||||||
|
if (!is_object($rawResponse) || $rawResponse->isError())
|
||||||
|
{
|
||||||
|
$msg = method_exists($rawResponse, 'getStatus') ? $rawResponse->getStatus() : 'unknown code';
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, JText::sprintf('COM_SH404SEF_ERROR_CHECKING_ANALYTICS', $msg));
|
||||||
|
throw new Sh404sefExceptionDefault(JText::sprintf('COM_SH404SEF_ERROR_CHECKING_ANALYTICS', $msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
// success, return response
|
||||||
|
return $rawResponse;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set client object to perform request
|
||||||
|
* for connection to analytics service
|
||||||
|
*
|
||||||
|
* To be oveloaded
|
||||||
|
*/
|
||||||
|
protected function _prepareConnectRequest()
|
||||||
|
{
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle response from connect request
|
||||||
|
*
|
||||||
|
* To be overloaded
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function _handleConnectResponse($response)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user set parameters and request
|
||||||
|
* data allow inserting tracking snippet
|
||||||
|
*/
|
||||||
|
protected function _shouldInsertSnippet()
|
||||||
|
{
|
||||||
|
// get config
|
||||||
|
$config = &Sh404sefFactory::getConfig();
|
||||||
|
|
||||||
|
// check if we have a tracking code, no need to insert snippet if no tracking code
|
||||||
|
if (empty($config->analyticsId) && ($config->analyticsEdition == 'ga' || $config->analyticsEdition == 'ga_and_uga'))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($config->analyticsUgaId) && ($config->analyticsEdition == 'uga' || $config->analyticsEdition == 'ga_and_uga'))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($config->analyticsGtmId) && $config->analyticsEdition == 'gtm')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we are set to include tracking code for current user
|
||||||
|
if (!sh404sefHelperGeneral::isInGroupList(JAccess::getGroupsByUser(JFactory::getUser()->id, $recursive = true), $config->analyticsUserGroups))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// check if current IP is on exclusion list
|
||||||
|
if (!empty($config->analyticsExcludeIP))
|
||||||
|
{
|
||||||
|
$ip = empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR'];
|
||||||
|
$exclude = Sh404sefHelperGeneral::checkIPList($ip, $config->analyticsExcludeIP);
|
||||||
|
if ($exclude)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _prepareCommonHeaders()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepare html filters to allow user to select the way she likes
|
||||||
|
* to view reports
|
||||||
|
*/
|
||||||
|
protected function _prepareFilters()
|
||||||
|
{
|
||||||
|
// array to hold various filters
|
||||||
|
$filters = array();
|
||||||
|
|
||||||
|
return $filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getAppKey()
|
||||||
|
{
|
||||||
|
static $_key = null;
|
||||||
|
|
||||||
|
if (is_null($_key))
|
||||||
|
{
|
||||||
|
$remoteConfig = Sh404sefHelperUpdates::getRemoteConfig($forced = false);
|
||||||
|
$keys = empty($remoteConfig->config['google_analytics_api_keys']) ? $this->_appKeys : $remoteConfig->config['google_analytics_api_keys'];
|
||||||
|
$_key = $keys[mt_rand(0, count($keys) - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $_key;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
// load a few constants
|
||||||
|
require_once JPATH_ROOT . '/administrator/components/com_sh404sef/defines.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL caching
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefClassBasecache {
|
||||||
|
|
||||||
|
protected static $_instance = null;
|
||||||
|
|
||||||
|
// general configuration
|
||||||
|
protected $_config = null;
|
||||||
|
|
||||||
|
// cache content
|
||||||
|
protected $_urlCache = array();
|
||||||
|
protected $_urlCacheCount = 0;
|
||||||
|
protected $_urlCacheCreationDate = null;
|
||||||
|
|
||||||
|
// cache stats
|
||||||
|
protected $_urlCacheMisses = 0;
|
||||||
|
protected $_urlCacheHits = 0;
|
||||||
|
protected $_urlCacheMissesList = array();
|
||||||
|
|
||||||
|
public function __construct( $config) {
|
||||||
|
|
||||||
|
// store sef config
|
||||||
|
$this->_config = $config;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch an URL from cache, return null if not found
|
||||||
|
public function getSefUrlFromCache( $nonSefUrl, & $sefUrl) {
|
||||||
|
|
||||||
|
return sh404SEF_URLTYPE_NONE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch an URL from cache, return null if not found
|
||||||
|
public function getNonSefUrlFromCache( $sefUrl, & $nonSefUrl) {
|
||||||
|
|
||||||
|
return sh404SEF_URLTYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addSefUrlToCache( $nonSefUrl, $sefUrl, $UrlType) {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeUrlFromCache( $nonSefUrlList) {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function purge() {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getCacheStats() {
|
||||||
|
|
||||||
|
$cacheTotal = $this->_urlCacheMisses+$this->_urlCacheHits;
|
||||||
|
$out = 'Cache hits : '. $this->_urlCacheHits . " [".( !empty( $cacheTotal) ? (int)(100*$this->_urlCacheHits/$cacheTotal) . '%' : 'N/A') .']<br />';
|
||||||
|
$out .= 'Cache misses : '. $this->_urlCacheMisses . " [".( !empty( $cacheTotal) ? (int)(100*$this->_urlCacheMisses/$cacheTotal) . '%' : 'N/A'). ']<br />';
|
||||||
|
$out .= 'Cache total : '. $cacheTotal . '<br />';
|
||||||
|
$out .= 'Url added to cache : '. $this->_urlCacheCount . '<br />';
|
||||||
|
$out .= '<br /><br /><br />Misses list';
|
||||||
|
foreach($this->_urlCacheMissesList as $url) {
|
||||||
|
$out .= '<pre>'.$url.'</pre><br />';
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _varExport( $cache, $start) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
jimport( 'joomla.application.component.controller' );
|
||||||
|
|
||||||
|
Class Sh404sefClassBasecontroller extends ShlMvcController_Base {
|
||||||
|
|
||||||
|
protected $_context = 'com_sh404sef';
|
||||||
|
|
||||||
|
protected $_defaultController = '';
|
||||||
|
protected $_defaultTask = '';
|
||||||
|
protected $_defaultModel = '';
|
||||||
|
protected $_defaultView = 'default';
|
||||||
|
protected $_defaultLayout = 'default';
|
||||||
|
|
||||||
|
protected $_returnController = '';
|
||||||
|
protected $_returnTask = '';
|
||||||
|
protected $_returnView = 'default';
|
||||||
|
protected $_returnLayout = 'default';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the view
|
||||||
|
*/
|
||||||
|
public function display($cachable = false, $urlparams = false) {
|
||||||
|
|
||||||
|
// catch up any result message coming from an
|
||||||
|
// ajax save for instance, and push that into
|
||||||
|
// the application message queue
|
||||||
|
$messageCode = JRequest::getCmd( 'sh404sefMsg');
|
||||||
|
if (!empty($messageCode)) {
|
||||||
|
$msg = JText::_( $messageCode);
|
||||||
|
if ($msg != $messageCode) {
|
||||||
|
// if no language string exists, JText will
|
||||||
|
// return the input string, so only display if
|
||||||
|
// we have something to display
|
||||||
|
$app = JFactory::getApplication();
|
||||||
|
$app->enqueuemessage( $msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set the default view name in case it's missing
|
||||||
|
$viewName = JRequest::getWord('view');
|
||||||
|
if (empty( $viewName)) {
|
||||||
|
JRequest::setVar( 'view', $this->_defaultView);
|
||||||
|
}
|
||||||
|
|
||||||
|
$document =JFactory::getDocument();
|
||||||
|
|
||||||
|
$viewType = $document->getType();
|
||||||
|
$viewName = JRequest::getCmd( 'view', $this->_defaultView);
|
||||||
|
$viewLayout = JRequest::getCmd( 'layout', $this->_defaultLayout );
|
||||||
|
|
||||||
|
$view = $this->getView( $viewName, $viewType, '', array( 'base_path'=>$this->basePath));
|
||||||
|
|
||||||
|
// Get/Create the model
|
||||||
|
if ($model = $this->getModel($viewName)) {
|
||||||
|
// store initial context in model
|
||||||
|
$model->setContext( $this->_context);
|
||||||
|
|
||||||
|
// Push the model into the view (as default)
|
||||||
|
$view->setModel($model, true);
|
||||||
|
|
||||||
|
// and push also the default redirect
|
||||||
|
$view->defaultRedirectUrl = $this->_getDefaultRedirect( array( 'layout' => $viewLayout));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the layout
|
||||||
|
$view->setLayout($viewLayout);
|
||||||
|
|
||||||
|
// push controller errors in the view
|
||||||
|
$error = $this->getError();
|
||||||
|
if (!empty( $error)) {
|
||||||
|
$view->setError( $error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the view
|
||||||
|
$view->display();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method implementing cancelling the list view
|
||||||
|
* Go back to dashboard
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function dashboard() {
|
||||||
|
|
||||||
|
// define where we want to go : dashboard ie all default values
|
||||||
|
$bits = array( 'c' => '', 'task' => '', 'view' => '');
|
||||||
|
|
||||||
|
// get there
|
||||||
|
$this->setRedirect( $this->_getDefaultRedirect( $bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue a series of messages in the application message
|
||||||
|
* queue, while JApplication::enqueuemessage will do it
|
||||||
|
* one at a time
|
||||||
|
* @param array of strings $msgs the messages
|
||||||
|
* @param string $msgType the message type (same for all messages in $msgs)
|
||||||
|
*/
|
||||||
|
public function enqueuemessages( $msgs, $msgType = null) {
|
||||||
|
|
||||||
|
// nothing to do if no messages
|
||||||
|
if (empty( $msgs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get application
|
||||||
|
$app = JFactory::getApplication();
|
||||||
|
|
||||||
|
// loop messages and enqueue
|
||||||
|
foreach( $msgs as $msg) {
|
||||||
|
$app->enqueuemessage( $msg, $msgType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a (non routed) Joomla url according to default values
|
||||||
|
* of controller, task, view and layout
|
||||||
|
*
|
||||||
|
* @param array $userVars optional set of variables to override default vars, or add more to url
|
||||||
|
* @return string the target url, not routed
|
||||||
|
*/
|
||||||
|
protected function _getDefaultRedirect( $userVars = array()) {
|
||||||
|
|
||||||
|
// get default values of the controller
|
||||||
|
$defaultVars = array( 'c' => $this->_returnController, 'layout' => $this->_returnLayout, 'view' => $this->_returnView, 'task' => $this->_returnTask);
|
||||||
|
|
||||||
|
// override default vars with user defined vars
|
||||||
|
$vars = array_merge( $defaultVars, $userVars);
|
||||||
|
|
||||||
|
// strip empty vars
|
||||||
|
foreach( $vars as $key => $value) {
|
||||||
|
if ($value == '') {
|
||||||
|
unset( $vars[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sh404sefHelperUrl::buildUrl( $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,213 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
class Sh404sefClassBaseEditController extends Sh404sefClassBasecontroller {
|
||||||
|
|
||||||
|
protected $_context = 'com_sh404sef.edit';
|
||||||
|
|
||||||
|
protected $_editController = '';
|
||||||
|
protected $_editTask = 'edit';
|
||||||
|
protected $_editLayout = '';
|
||||||
|
|
||||||
|
protected $_returnController = '';
|
||||||
|
protected $_returnTask = '';
|
||||||
|
protected $_returnView = 'default';
|
||||||
|
protected $_returnLayout = 'default';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Id of the currently edited item
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $_id = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST data saved in case of need to edit again
|
||||||
|
* same data (if error detected)
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
protected $_editData = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the view
|
||||||
|
*/
|
||||||
|
public function display($cachable = false, $urlparams = false) {
|
||||||
|
|
||||||
|
// Set the default view name in case it's missing
|
||||||
|
$viewName = JRequest::getWord('view');
|
||||||
|
if (empty( $viewName)) {
|
||||||
|
JRequest::setVar( 'view', $this->_defaultView);
|
||||||
|
}
|
||||||
|
|
||||||
|
$document =JFactory::getDocument();
|
||||||
|
|
||||||
|
$viewType = $document->getType();
|
||||||
|
$viewName = JRequest::getCmd( 'view');
|
||||||
|
$this->_editView = $viewName;
|
||||||
|
$viewLayout = JRequest::getCmd( 'layout', $this->_defaultLayout );
|
||||||
|
|
||||||
|
$view = $this->getView( $viewName, $viewType, '', array( 'base_path'=>$this->basePath));
|
||||||
|
|
||||||
|
// Get/Create the model
|
||||||
|
if ($model = $this->getModel($viewName)) {
|
||||||
|
// store initial context in model
|
||||||
|
$model->setContext( $this->_context);
|
||||||
|
|
||||||
|
// if we have some stored data from a previous attempt at editing
|
||||||
|
// that failed because of validation, then push saved data into
|
||||||
|
// the model, to redisplay it for user to fix or cancel
|
||||||
|
if (!is_null($this->_editData)) {
|
||||||
|
$model->setData( $this->_editData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push the model into the view (as default)
|
||||||
|
$view->setModel($model, true);
|
||||||
|
|
||||||
|
// and push also the default redirect
|
||||||
|
$view->defaultRedirectUrl = $this->_getDefaultRedirect();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the layout
|
||||||
|
$view->setLayout($viewLayout);
|
||||||
|
|
||||||
|
// push controller errors in the view
|
||||||
|
$error = $this->getError();
|
||||||
|
if (!empty( $error)) {
|
||||||
|
$view->setError( $error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the view
|
||||||
|
$view->display();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit() {
|
||||||
|
|
||||||
|
// hide the main menu
|
||||||
|
JRequest::setVar('hidemainmenu', 1);
|
||||||
|
|
||||||
|
// find and store edited item id
|
||||||
|
$cid = JRequest::getVar('cid', array(0), 'default', 'array');
|
||||||
|
$this->_id = $cid[0];
|
||||||
|
|
||||||
|
// let the base controller do the rest
|
||||||
|
$this->display();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save() {
|
||||||
|
|
||||||
|
// Check for request forgeries
|
||||||
|
JRequest::checkToken() or jexit( 'Invalid Token' );
|
||||||
|
|
||||||
|
// save incoming data
|
||||||
|
$this->_editData = JRequest::get('post');
|
||||||
|
|
||||||
|
// find and store edited item id
|
||||||
|
$this->_id = JRequest::getInt('id');
|
||||||
|
|
||||||
|
// perform saving of incoming data
|
||||||
|
$savedId = $this->_doSave( $this->_editData);
|
||||||
|
|
||||||
|
// error ?
|
||||||
|
if (empty( $savedId)) {
|
||||||
|
// edit again with same data
|
||||||
|
$errorMsg = $this->getError();
|
||||||
|
$errorMsg = empty( $errorMsg) ? $this->_getMessage( 'failure') : $errorMsg;
|
||||||
|
$this->setError( $errorMsg);
|
||||||
|
JRequest::setVar( 'c', $this->_editController);
|
||||||
|
JRequest::setVar( 'task', $this->_editTask);
|
||||||
|
JRequest::setVar( 'cid', array($this->_id));
|
||||||
|
// in case of error, if this is an ajax call,
|
||||||
|
// we simply return the error to the caller
|
||||||
|
$isAjax = JRequest::getInt( 'shajax') == 1;
|
||||||
|
if(!$isAjax) {
|
||||||
|
// if not ajax, we edit again the same page
|
||||||
|
$this->edit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// saved, no need to keep them
|
||||||
|
$this->_editData = null;
|
||||||
|
|
||||||
|
// display response
|
||||||
|
$this->display();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apply() {
|
||||||
|
|
||||||
|
// Check for request forgeries
|
||||||
|
JRequest::checkToken() or jexit( 'Invalid Token' );
|
||||||
|
|
||||||
|
// just an alias for save
|
||||||
|
$this->save();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancel() {
|
||||||
|
|
||||||
|
// Check for request forgeries
|
||||||
|
JRequest::checkToken() or jexit( 'Invalid Token' );
|
||||||
|
|
||||||
|
$this->setRedirect( $this->_getDefaultRedirect(), $this->_getMessage( 'cancel'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setId( $id) {
|
||||||
|
|
||||||
|
$this->_id = $id;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getMessage( $type) {
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'success':
|
||||||
|
$msg = JText::_('COM_SH404SEF_ELEMENT_SAVED');
|
||||||
|
break;
|
||||||
|
case 'failure':
|
||||||
|
$msg = JText::_('COM_SH404SEF_ELEMENT_NOT_SAVED');
|
||||||
|
break;
|
||||||
|
case 'cancel':
|
||||||
|
$msg = JText::_('COM_SH404SEF_CANCELLED');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$msg = '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $msg;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _doSave( $dataArray, $urlType = sh404SEF_URLTYPE_CUSTOM) {
|
||||||
|
|
||||||
|
// get model
|
||||||
|
$model = $this->getModel( $this->_defaultView);
|
||||||
|
|
||||||
|
// perform save operation
|
||||||
|
$savedId = $model->save( $dataArray, $urlType);
|
||||||
|
|
||||||
|
// store error message
|
||||||
|
if (empty( $savedId)) {
|
||||||
|
$this->setError( $model->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// return result
|
||||||
|
return $savedId;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
abstract class Sh404sefClassBaseeditmodel extends Sh404sefClassBaseModel {
|
||||||
|
|
||||||
|
protected $_context = 'sh404sef.edit';
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
jimport( 'joomla.plugin.plugin' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base extension handler plugin
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
*/
|
||||||
|
class Sh404sefClassBaseextplugin extends JPlugin {
|
||||||
|
|
||||||
|
|
||||||
|
const TYPE_DEFAULT = 0;
|
||||||
|
const TYPE_SKIP = 1;
|
||||||
|
const TYPE_SIMPLE = 2;
|
||||||
|
|
||||||
|
const TYPE_SH404SEF_ROUTER = 0; // do not change, must be 0 for compat reason
|
||||||
|
const TYPE_JOOMLA_ROUTER = 1; // do not change, must be 1 for compat reason
|
||||||
|
|
||||||
|
const TYPE_JOOMSEF_ROUTER = 30;
|
||||||
|
const TYPE_ACESEF_ROUTER = 40;
|
||||||
|
const TYPE_NO_ROUTER = 100;
|
||||||
|
const TYPE_OPENSEF_ROUTER = 101;
|
||||||
|
|
||||||
|
protected $_componentType = null;
|
||||||
|
protected $_pluginType = null;
|
||||||
|
|
||||||
|
protected $_option = '';
|
||||||
|
protected $_optionNoCom = '';
|
||||||
|
protected $_extName = '';
|
||||||
|
protected $_config = null;
|
||||||
|
protected $_sefPluginPath = null;
|
||||||
|
protected $_metaPluginPath = null;
|
||||||
|
|
||||||
|
protected $_version = '';
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct( $option, $config) {
|
||||||
|
|
||||||
|
$this->_option = $option;
|
||||||
|
$this->_optionNoCom = str_replace('com_', '', $this->_option);
|
||||||
|
$this->_config = $config;
|
||||||
|
$this->_pluginType = self::TYPE_NO_ROUTER;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComponentType() {
|
||||||
|
|
||||||
|
if(is_null( $this->_componentType)) {
|
||||||
|
switch ($this->_optionNoCom) {
|
||||||
|
// leave urls non-sef
|
||||||
|
case (in_array($this->_optionNoCom, $this->_config->skip)):
|
||||||
|
$this->_componentType = self::TYPE_SKIP;
|
||||||
|
break;
|
||||||
|
// use simple encoding
|
||||||
|
case (in_array($this->_optionNoCom, $this->_config->nocache)):
|
||||||
|
$this->_componentType = self::TYPE_SIMPLE;
|
||||||
|
break;
|
||||||
|
// default handler, full sef
|
||||||
|
default:
|
||||||
|
$this->_componentType = self::TYPE_DEFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now validate that type: if required plugin is not available,
|
||||||
|
// we'll need to switch back to "simple
|
||||||
|
if($this->_componentType == self::TYPE_DEFAULT) {
|
||||||
|
$path = $this->getSefPluginPath();
|
||||||
|
if(empty( $path)) {
|
||||||
|
$this->_componentType = self::TYPE_SIMPLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->_componentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPluginType() {
|
||||||
|
|
||||||
|
return $this->_pluginType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
|
||||||
|
return $this->_extName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVersion() {
|
||||||
|
|
||||||
|
return $this->_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSefPluginPath( $nonSefVars = array()) {
|
||||||
|
|
||||||
|
if(is_null( $this->_sefPluginPath)) {
|
||||||
|
$this->_findSefPluginPath( $nonSefVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_sefPluginPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetaPluginPath( $nonSefUrl = '') {
|
||||||
|
|
||||||
|
if(is_null( $this->_metaPluginPath)) {
|
||||||
|
$this->_findMetaPluginPath( $nonSefUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_metaPluginPath;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function _findSefPluginPath( $nonSefVars = array()) {
|
||||||
|
|
||||||
|
$this->_sefPluginPath = '';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _findMetaPluginPath( $nonSefUrl = '') {
|
||||||
|
|
||||||
|
$this->_metaPluginPath = '';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,450 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapted for SEF module for Joomla!
|
||||||
|
*
|
||||||
|
* @author $Author: shumisha $
|
||||||
|
* @copyright Yannick Gaultier - 2007-2011
|
||||||
|
* @package sh404SEF-16
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
// No direct access
|
||||||
|
defined('JPATH_BASE') or die;
|
||||||
|
|
||||||
|
require_once JPATH_LIBRARIES . '/joomla/installer/adapters/plugin.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin installer
|
||||||
|
*
|
||||||
|
* @package Joomla.Framework
|
||||||
|
* @subpackage Installer
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
class Sh404sefClassBaseinstalladapter extends JInstallerPlugin
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $_basePath = '';
|
||||||
|
|
||||||
|
protected $_group = 'sh404sefextplugins';
|
||||||
|
protected $_installType = 'plugin';
|
||||||
|
|
||||||
|
/** @var string install function routing */
|
||||||
|
var $route = 'install';
|
||||||
|
|
||||||
|
protected $manifest = null;
|
||||||
|
protected $manifest_script = null;
|
||||||
|
protected $name = null;
|
||||||
|
protected $scriptElement = null;
|
||||||
|
protected $oldFiles = null;
|
||||||
|
|
||||||
|
public function __construct(&$parent, &$db, $options = Array()) {
|
||||||
|
|
||||||
|
parent::__construct($parent, $db, $options);
|
||||||
|
$this->_basePath = JPATH_ROOT . '/' . 'plugins';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom install method
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return boolean True on success
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public function install()
|
||||||
|
{
|
||||||
|
|
||||||
|
// set our target path
|
||||||
|
$this->parent->setPath( 'extension_root', $this->_getPath());
|
||||||
|
|
||||||
|
// Get a database connector object
|
||||||
|
$db = $this->parent->getDbo();
|
||||||
|
|
||||||
|
// Get the extension manifest object
|
||||||
|
$this->manifest = $this->parent->getManifest();
|
||||||
|
|
||||||
|
$xml = $this->manifest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ---------------------------------------------------------------------------------------------
|
||||||
|
* Manifest Document Setup Section
|
||||||
|
* ---------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Set the extensions name
|
||||||
|
$name = (string)$xml->name;
|
||||||
|
$name = JFilterInput::getInstance()->clean($name, 'string');
|
||||||
|
$this->set('name', $name);
|
||||||
|
|
||||||
|
// Get the component description
|
||||||
|
$description = (string)$xml->description;
|
||||||
|
if ($description) {
|
||||||
|
$this->parent->set('message', JText::_($description));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->parent->set('message', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Backward Compatability
|
||||||
|
* @todo Deprecate in future version
|
||||||
|
*/
|
||||||
|
$type = (string)$xml->attributes()->type;
|
||||||
|
$pname = $this->_getElement($xml);
|
||||||
|
|
||||||
|
$group = $this->_group;
|
||||||
|
if ($type == $this->_installType && !empty( $pname)) {
|
||||||
|
$this->parent->setPath('extension_root', JPATH_PLUGINS. '/' .$group. '/' .$element);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_NO_FILE', JText::_('JLIB_INSTALLER_'.$this->route)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we should enable overwrite settings
|
||||||
|
*/
|
||||||
|
// Check to see if a plugin by the same name is already installed
|
||||||
|
$query = 'SELECT `extension_id`' .
|
||||||
|
' FROM `#__extensions`' .
|
||||||
|
' WHERE folder = '.$db->Quote($group) .
|
||||||
|
' AND element = '.$db->Quote($element);
|
||||||
|
$db->setQuery($query);
|
||||||
|
try {
|
||||||
|
$db->execute();
|
||||||
|
}
|
||||||
|
catch(JException $e)
|
||||||
|
{
|
||||||
|
// Install failed, roll back changes
|
||||||
|
$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_ROLLBACK', JText::_('JLIB_INSTALLER_'.$this->route), $db->stderr(true)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$id = $db->loadResult();
|
||||||
|
|
||||||
|
// if its on the fs...
|
||||||
|
if (file_exists($this->parent->getPath('extension_root')) && (!$this->parent->isOverwrite() || $this->parent->isUpgrade()))
|
||||||
|
{
|
||||||
|
$updateElement = $xml->update;
|
||||||
|
// upgrade manually set
|
||||||
|
// update function available
|
||||||
|
// update tag detected
|
||||||
|
if ($this->parent->isUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'update')) || is_a($updateElement, 'JXMLElement'))
|
||||||
|
{
|
||||||
|
// force these one
|
||||||
|
$this->parent->setOverwrite(true);
|
||||||
|
$this->parent->setUpgrade(true);
|
||||||
|
if ($id) { // if there is a matching extension mark this as an update; semantics really
|
||||||
|
$this->route = 'update';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!$this->parent->isOverwrite())
|
||||||
|
{
|
||||||
|
// overwrite is set
|
||||||
|
// we didn't have overwrite set, find an udpate function or find an update tag so lets call it safe
|
||||||
|
$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_DIRECTORY', JText::_('JLIB_INSTALLER_'.$this->route), $this->parent->getPath('extension_root')));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ---------------------------------------------------------------------------------------------
|
||||||
|
* Installer Trigger Loading
|
||||||
|
* ---------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
// If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet)
|
||||||
|
if ((string)$xml->scriptfile)
|
||||||
|
{
|
||||||
|
$manifestScript = (string)$xml->scriptfile;
|
||||||
|
$manifestScriptFile = $this->parent->getPath('source'). '/' .$manifestScript;
|
||||||
|
if (is_file($manifestScriptFile))
|
||||||
|
{
|
||||||
|
// load the file
|
||||||
|
include_once $manifestScriptFile;
|
||||||
|
}
|
||||||
|
// Set the class name
|
||||||
|
$classname = 'plg'.$group.$element.'InstallerScript';
|
||||||
|
if (class_exists($classname))
|
||||||
|
{
|
||||||
|
// create a new instance
|
||||||
|
$this->parent->manifestClass = new $classname($this);
|
||||||
|
// and set this so we can copy it later
|
||||||
|
$this->set('manifest_script', $manifestScript);
|
||||||
|
// Note: if we don't find the class, don't bother to copy the file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// run preflight if possible (since we know we're not an update)
|
||||||
|
ob_start();
|
||||||
|
ob_implicit_flush(false);
|
||||||
|
if ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'preflight'))
|
||||||
|
{
|
||||||
|
if($this->parent->manifestClass->preflight($this->route, $this) === false)
|
||||||
|
{
|
||||||
|
// Install failed, rollback changes
|
||||||
|
$this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_PLG_INSTALL_CUSTOM_INSTALL_FAILURE'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$msg = ob_get_contents(); // create msg object; first use here
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ---------------------------------------------------------------------------------------------
|
||||||
|
* Filesystem Processing Section
|
||||||
|
* ---------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
// If the plugin directory does not exist, lets create it
|
||||||
|
$created = false;
|
||||||
|
if (!file_exists($this->parent->getPath('extension_root')))
|
||||||
|
{
|
||||||
|
if (!$created = JFolder::create($this->parent->getPath('extension_root')))
|
||||||
|
{
|
||||||
|
$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_CREATE_DIRECTORY', JText::_('JLIB_INSTALLER_'.$this->route), $this->parent->getPath('extension_root')));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're updating at this point when there is always going to be an extension_root find the old xml files
|
||||||
|
if($this->route == 'update')
|
||||||
|
{
|
||||||
|
// Hunt for the original XML file
|
||||||
|
$old_manifest = null;
|
||||||
|
$tmpInstaller = new JInstaller(); // create a new installer because findManifest sets stuff; side effects!
|
||||||
|
// look in the extension root
|
||||||
|
$tmpInstaller->setPath('source', $this->parent->getPath('extension_root'));
|
||||||
|
if ($tmpInstaller->findManifest())
|
||||||
|
{
|
||||||
|
$old_manifest = $tmpInstaller->getManifest();
|
||||||
|
$this->oldFiles = $old_manifest->files;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we created the plugin directory and will want to remove it if we
|
||||||
|
* have to roll back the installation, lets add it to the installation
|
||||||
|
* step stack
|
||||||
|
*/
|
||||||
|
if ($created) {
|
||||||
|
$this->parent->pushStep(array ('type' => 'folder', 'path' => $this->parent->getPath('extension_root')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all necessary files
|
||||||
|
if ($this->parent->parseFiles($xml->files, -1, $this->oldFiles) === false)
|
||||||
|
{
|
||||||
|
// Install failed, roll back changes
|
||||||
|
$this->parent->abort();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse optional tags -- media and language files for plugins go in admin app
|
||||||
|
$this->parent->parseMedia($xml->media, 1);
|
||||||
|
$this->parent->parseLanguages($xml->languages, 1);
|
||||||
|
|
||||||
|
// If there is a manifest script, lets copy it.
|
||||||
|
if ($this->get('manifest_script'))
|
||||||
|
{
|
||||||
|
$path['src'] = $this->parent->getPath('source'). '/' .$this->get('manifest_script');
|
||||||
|
$path['dest'] = $this->parent->getPath('extension_root'). '/' .$this->get('manifest_script');
|
||||||
|
|
||||||
|
if (!file_exists($path['dest']))
|
||||||
|
{
|
||||||
|
if (!$this->parent->copyFiles(array ($path)))
|
||||||
|
{
|
||||||
|
// Install failed, rollback changes
|
||||||
|
$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_MANIFEST', JText::_('JLIB_INSTALLER_'.$this->route)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ---------------------------------------------------------------------------------------------
|
||||||
|
* Database Processing Section
|
||||||
|
* ---------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
$row = JTable::getInstance('extension');
|
||||||
|
// Was there a plugin already installed with the same name?
|
||||||
|
if ($id)
|
||||||
|
{
|
||||||
|
if (!$this->parent->isOverwrite())
|
||||||
|
{
|
||||||
|
// Install failed, roll back changes
|
||||||
|
$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_ALLREADY_EXISTS', JText::_('JLIB_INSTALLER_'.$this->route), $this->get('name')));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$row->load($id);
|
||||||
|
$row->name = $this->get('name');
|
||||||
|
$row->manifest_cache = $this->parent->generateManifestCache();
|
||||||
|
$row->store(); // update the manifest cache and name
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Store in the extensions table (1.6)
|
||||||
|
$row->name = $this->get('name');
|
||||||
|
$row->type = 'plugin';
|
||||||
|
$row->ordering = 0;
|
||||||
|
$row->element = $element;
|
||||||
|
$row->folder = $group;
|
||||||
|
$row->enabled = 1;
|
||||||
|
$row->protected = 0;
|
||||||
|
$row->access = 1;
|
||||||
|
$row->client_id = 0;
|
||||||
|
$row->params = $this->parent->getParams();
|
||||||
|
$row->custom_data = ''; // custom data
|
||||||
|
$row->system_data = ''; // system data
|
||||||
|
$row->manifest_cache = $this->parent->generateManifestCache();
|
||||||
|
|
||||||
|
// Editor plugins are published by default
|
||||||
|
if ($group == 'editors') {
|
||||||
|
$row->enabled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$row->store())
|
||||||
|
{
|
||||||
|
// Install failed, roll back changes
|
||||||
|
$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_ROLLBACK', JText::_('JLIB_INSTALLER_'.$this->route), $db->stderr(true)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we have created a plugin item, we add it to the installation step stack
|
||||||
|
// so that if we have to rollback the changes we can undo it.
|
||||||
|
$this->parent->pushStep(array ('type' => 'extension', 'id' => $row->extension_id));
|
||||||
|
$id = $row->extension_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Let's run the queries for the module
|
||||||
|
* If Joomla 1.5 compatible, with discreet sql files - execute appropriate
|
||||||
|
* file for utf-8 support or non-utf-8 support
|
||||||
|
*/
|
||||||
|
// try for Joomla 1.5 type queries
|
||||||
|
// second argument is the utf compatible version attribute
|
||||||
|
if(strtolower($this->route) == 'install') {
|
||||||
|
$utfresult = $this->parent->parseSQLFiles($this->manifest->install->sql);
|
||||||
|
if ($utfresult === false)
|
||||||
|
{
|
||||||
|
// Install failed, rollback changes
|
||||||
|
$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_SQL_ERROR', JText::_('JLIB_INSTALLER_'.$this->route), $db->stderr(true)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the schema version to be the latest update version
|
||||||
|
if($this->manifest->update) {
|
||||||
|
$this->parent->setSchemaVersion($this->manifest->update->schemas, $row->extension_id);
|
||||||
|
}
|
||||||
|
} else if(strtolower($this->route) == 'update') {
|
||||||
|
if($this->manifest->update)
|
||||||
|
{
|
||||||
|
$result = $this->parent->parseSchemaUpdates($this->manifest->update->schemas, $row->extension_id);
|
||||||
|
if ($result === false)
|
||||||
|
{
|
||||||
|
// Install failed, rollback changes
|
||||||
|
$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_UPDATE_SQL_ERROR', $db->stderr(true)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start Joomla! 1.6
|
||||||
|
ob_start();
|
||||||
|
ob_implicit_flush(false);
|
||||||
|
if ($this->parent->manifestClass && method_exists($this->parent->manifestClass,$this->route))
|
||||||
|
{
|
||||||
|
if($this->parent->manifestClass->{$this->route}($this) === false)
|
||||||
|
{
|
||||||
|
// Install failed, rollback changes
|
||||||
|
$this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_PLG_INSTALL_CUSTOM_INSTALL_FAILURE'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$msg .= ob_get_contents(); // append messages
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ---------------------------------------------------------------------------------------------
|
||||||
|
* Finalization and Cleanup Section
|
||||||
|
* ---------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Lastly, we will copy the manifest file to its appropriate place.
|
||||||
|
if (!$this->parent->copyManifest(-1))
|
||||||
|
{
|
||||||
|
// Install failed, rollback changes
|
||||||
|
$this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PLG_INSTALL_COPY_SETUP', JText::_('JLIB_INSTALLER_'.$this->route)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// And now we run the postflight
|
||||||
|
ob_start();
|
||||||
|
ob_implicit_flush(false);
|
||||||
|
if ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'postflight'))
|
||||||
|
{
|
||||||
|
$this->parent->manifestClass->postflight($this->route, $this);
|
||||||
|
}
|
||||||
|
$msg .= ob_get_contents(); // append messages
|
||||||
|
ob_end_clean();
|
||||||
|
if ($msg != '') {
|
||||||
|
$this->parent->set('extension_message', $msg);
|
||||||
|
}
|
||||||
|
return $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get unique element id for the plugin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function _getElement( $xml) {
|
||||||
|
|
||||||
|
static $_element = null;
|
||||||
|
|
||||||
|
if( is_null( $_element)) {
|
||||||
|
// get name, should work for Joomsef, not sure for Aces, as
|
||||||
|
// I have seen some plugin with wrong filename attribute
|
||||||
|
// should use the "extension" field with acesef
|
||||||
|
if (count($xml->files->children()))
|
||||||
|
{
|
||||||
|
foreach ($xml->files->children() as $file)
|
||||||
|
{
|
||||||
|
$type = $this->_installType;
|
||||||
|
if ((string)$file->attributes()->$type)
|
||||||
|
{
|
||||||
|
$_element = (string)$file->attributes()->$type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return $_element;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get sub dir of given plugin, usually based on name
|
||||||
|
* of extension. Obtaining that name will vary based
|
||||||
|
* on the type of plugin
|
||||||
|
*/
|
||||||
|
protected function _getPath() {
|
||||||
|
|
||||||
|
return $this->_basePath . '/' . $this->_group;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _fixManifest() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,444 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
|
||||||
|
class Sh404sefClassBaselistmodel extends Sh404sefClassBasemodel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data array
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $_data = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data total
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $_total = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pagination object
|
||||||
|
*
|
||||||
|
* @var object
|
||||||
|
*/
|
||||||
|
protected $_pagination = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds current context, ie : controller/model/view/layout hierarchy
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $_context = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get lists item data
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param object holding options
|
||||||
|
* @param boolea $returnZeroElement . If true, and the list returned is empty, a null object will be returned (as an array)
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getList( $options = null, $returnZeroElement = false, $forcedLimitstart = null, $forcedLimit = null) {
|
||||||
|
|
||||||
|
// make sure we use latest user state
|
||||||
|
$this->_updateContextData();
|
||||||
|
|
||||||
|
// Lets load the content if it doesn't already exist
|
||||||
|
if (is_null($this->_data)) {
|
||||||
|
|
||||||
|
// get pagination values, and check them
|
||||||
|
$total = $this->getTotal($options);
|
||||||
|
$limitstart = is_null( $forcedLimitstart) ? $this->_getState( 'limitstart') : $forcedLimitstart;
|
||||||
|
if( !is_null( $forcedLimitstart) && $limitstart >= $total) {
|
||||||
|
$limitstart = 0;
|
||||||
|
$this->_setState( 'limitstart', 0);
|
||||||
|
}
|
||||||
|
$limit = is_null( $forcedLimit) ? $this->_getState( 'limit') : $forcedLimit;
|
||||||
|
|
||||||
|
// don't allow display 'all' ie $limit = 0, and do sanity check
|
||||||
|
if (empty( $limit) || intval( $limit) > 500) {
|
||||||
|
$limit = 20;
|
||||||
|
$this->_setState( 'limit', $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the actual query
|
||||||
|
$query = $this->_buildListQuery( $options, $forcedLimitstart, $forcedLimit);
|
||||||
|
$this->_data = $this->_getList( $query);
|
||||||
|
//echo '<br >----------------------<br />data query:<br />' . $query . '<br >----------- '. count( $this->_data).' -----------<br />';
|
||||||
|
if ($returnZeroElement && empty( $this->_data)) {
|
||||||
|
// create an empty record and return it
|
||||||
|
$zeroObject = JTable::getInstance( $this->_defaultTable, 'Sh404sefTable');
|
||||||
|
return array( $zeroObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get the total number of categories
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getTotal( $options = null) {
|
||||||
|
|
||||||
|
// make sure we use latest user state
|
||||||
|
$this->_updateContextData();
|
||||||
|
|
||||||
|
$options = is_null($options) ? new stdClass() : $options;
|
||||||
|
// Lets load the content if it doesn't already exist
|
||||||
|
if (is_null($this->_total)) {
|
||||||
|
$options->onlyCount = true;
|
||||||
|
$query = $this->_buildListQuery( $options);
|
||||||
|
$this->_total = $this->_getListCount( $query);
|
||||||
|
$options->onlyCount = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get a pagination object for the lists
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getPagination( $options = null) {
|
||||||
|
|
||||||
|
// make sure we use latest user state
|
||||||
|
$this->_updateContextData();
|
||||||
|
|
||||||
|
// Lets load the content if it doesn't already exist
|
||||||
|
if (empty($this->_pagination)) {
|
||||||
|
// get pagination values, and check them
|
||||||
|
$total = $this->getTotal($options);
|
||||||
|
$limitstart = $this->_getState( 'limitstart');
|
||||||
|
$limit = $this->_getState( 'limit');
|
||||||
|
|
||||||
|
// create a pagination object
|
||||||
|
jimport('joomla.html.pagination');
|
||||||
|
$this->_pagination = new JPagination( $total, $limitstart, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_pagination;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets alist of current filters and sort options which have
|
||||||
|
* been applied when building up the data
|
||||||
|
*
|
||||||
|
* @return object the list ov values as object properties
|
||||||
|
*/
|
||||||
|
public function getDisplayOptions() {
|
||||||
|
|
||||||
|
$options = new stdClass();
|
||||||
|
|
||||||
|
// search string applied to either sef or non sef
|
||||||
|
$options->search_all = $this->_getState( 'search_all');
|
||||||
|
// ordering column
|
||||||
|
$options->filter_order = $this->_getState( 'filter_order');
|
||||||
|
// show all/only custom/only automatic
|
||||||
|
$options->filter_order_Dir = $this->_getState( 'filter_order_Dir');
|
||||||
|
|
||||||
|
// return cached instance
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a display option for the current context
|
||||||
|
*
|
||||||
|
* @return mixed previous value of the property
|
||||||
|
*/
|
||||||
|
public function setDisplayOptions( $key, $value) {
|
||||||
|
|
||||||
|
// read previous
|
||||||
|
$previous = $this->_getState( $key);
|
||||||
|
|
||||||
|
// set new
|
||||||
|
$this->_setState( $key, $value);
|
||||||
|
|
||||||
|
// return previous
|
||||||
|
return $previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _buildListQuery( $options, $forcedLimitstart = null, $forcedLimit = null) {
|
||||||
|
|
||||||
|
// Collect the various parts of the query
|
||||||
|
$select = $this->_buildListSelect( $options);
|
||||||
|
$join = $this->_buildListJoin( $options);
|
||||||
|
$where = $this->_buildListWhere( $options);
|
||||||
|
$limit = $this->_buildListLimit( $options, $forcedLimitstart, $forcedLimit);
|
||||||
|
$orderBy = $this->_buildListOrderBy( $options);
|
||||||
|
$groupBy = $this->_buildListGroupBy( $options);
|
||||||
|
|
||||||
|
// complete query
|
||||||
|
$query = $select . $join . $where . $groupBy;
|
||||||
|
|
||||||
|
// wrap if combined queries
|
||||||
|
$query = $this->_buildListCombinedQuery( $query, $options);
|
||||||
|
|
||||||
|
// add sorting
|
||||||
|
$query .= $orderBy;
|
||||||
|
|
||||||
|
// limit number of items
|
||||||
|
$query .= $limit;
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function _buildListSelect( $options) {
|
||||||
|
|
||||||
|
// array to hold select clause parts
|
||||||
|
$select = array();
|
||||||
|
|
||||||
|
// get options
|
||||||
|
$select[] = ' select *';
|
||||||
|
|
||||||
|
// add from clause
|
||||||
|
$select[] = 'from ' . $this->_getTableName();
|
||||||
|
|
||||||
|
// aggregate clauses
|
||||||
|
$select = ( count( $select ) ? implode( ' ', $select ) : '' );
|
||||||
|
|
||||||
|
return $select;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _buildListJoin( $options) {
|
||||||
|
|
||||||
|
// array to hold join clause parts
|
||||||
|
$join = array();
|
||||||
|
|
||||||
|
// aggregate clauses
|
||||||
|
$join = ( count( $join ) ? ' ' . implode( ' ', $join ) : '' );
|
||||||
|
|
||||||
|
return $join;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _buildListWhere( $options) {
|
||||||
|
|
||||||
|
// array to hold where clause parts
|
||||||
|
$where = array();
|
||||||
|
|
||||||
|
// aggregate clauses
|
||||||
|
$where = ( count( $where ) ? ' WHERE '. implode( ' AND ', $where ) : '' );
|
||||||
|
|
||||||
|
return $where;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _buildListLimit( $options, $forcedLimitstart = null, $forcedLimit = null) {
|
||||||
|
|
||||||
|
// build query fragment
|
||||||
|
$limitString = '';
|
||||||
|
|
||||||
|
// get the layout options from param
|
||||||
|
$layout = $this->_getOption( 'layout', $options);
|
||||||
|
|
||||||
|
// in some case, we only need a simple list of urls, with no
|
||||||
|
// additionnal date, pageids, aliases, etc
|
||||||
|
$simpleUrlList = $this->_getOption( 'simpleUrlList', $options, false);
|
||||||
|
|
||||||
|
// various cases of layouts
|
||||||
|
switch ($layout) {
|
||||||
|
case 'view404':
|
||||||
|
default:
|
||||||
|
// build query fragment
|
||||||
|
$onlyCount = $this->_getOption( 'onlyCount', $options, false);
|
||||||
|
if (!$onlyCount) {
|
||||||
|
$limitstart = is_null( $forcedLimitstart) ? ( $this->_getState( 'limitstart')) : intval($forcedLimitstart);
|
||||||
|
$limit = is_null( $forcedLimit) ? intval( $this->_getState( 'limit')) : intval( $forcedLimit);
|
||||||
|
if(empty($limit) && empty( $limitstart)) {
|
||||||
|
$limitstring = '';
|
||||||
|
} else {
|
||||||
|
$limitString = ' limit ' . $limitstart . ',' . $limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $limitString;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _buildListGroupBy( $options) {
|
||||||
|
|
||||||
|
// build query fragment
|
||||||
|
$groupBy = '';
|
||||||
|
|
||||||
|
return $groupBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _buildListOrderBy( $options) {
|
||||||
|
|
||||||
|
// get set of filters applied to the current view
|
||||||
|
$filters = $this->getDisplayOptions();
|
||||||
|
|
||||||
|
// build query fragment
|
||||||
|
if(!empty($filters->filter_order)) {
|
||||||
|
$orderBy = ' order by ' . $this->_db->quoteName( $filters->filter_order);
|
||||||
|
$orderBy .= ' ' . $filters->filter_order_Dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $orderBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _buildListCombinedQuery( $query, $options) {
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides context data definition, to be used by context handler
|
||||||
|
* Should be overriden by descendant
|
||||||
|
*/
|
||||||
|
protected function _getContextDataDef() {
|
||||||
|
|
||||||
|
$application = JFactory::getApplication();
|
||||||
|
|
||||||
|
// define context data to be retrieved. Cannot be done at class level,
|
||||||
|
// as some default values are dynamic
|
||||||
|
$contextData = array(
|
||||||
|
|
||||||
|
array( 'name' => 'limit', 'html_name' => 'limit', 'default' => $application->getCfg('list_limit'), 'type' => 'int')
|
||||||
|
, array( 'name' => 'limitstart', 'html_name' => 'limitstart', 'default' => 0, 'type' => 'int')
|
||||||
|
// search string applied to either sef or non sef
|
||||||
|
, array( 'name' => 'search_all', 'html_name' => 'search_all', 'default' => '', 'type' => 'string')
|
||||||
|
// ordering column
|
||||||
|
, array( 'name' => 'filter_order', 'html_name' => 'filter_order', 'default' => 'oldurl', 'type' => 'string')
|
||||||
|
// ordering direction
|
||||||
|
, array( 'name' => 'filter_order_Dir', 'html_name' => 'filter_order_Dir', 'default' => 'ASC', 'type' => 'string')
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
return $contextData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset model internal cached data
|
||||||
|
* used after changing context for instance
|
||||||
|
*/
|
||||||
|
protected function _resetData() {
|
||||||
|
|
||||||
|
// clean data, total and pagination, as we need them rebuilt
|
||||||
|
$this->_data = null;
|
||||||
|
$this->_total = null;
|
||||||
|
$this->_pagination = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read application user state stored by
|
||||||
|
* Joomla application object for the current context
|
||||||
|
* context represents current controller/model/view hierarchy
|
||||||
|
* and has been set by each of those elements
|
||||||
|
*/
|
||||||
|
protected function _updateContextData() {
|
||||||
|
|
||||||
|
// if not been there before, or context has changed since last visit
|
||||||
|
if (is_null($this->_context) || $this->_context != $this->getState( 'context')) {
|
||||||
|
|
||||||
|
// read context name and store inclass variabel, easier to access later on
|
||||||
|
$this->_context = $this->getState( 'context', $this->_context);
|
||||||
|
|
||||||
|
// get an application instance
|
||||||
|
$application = JFactory::getApplication();
|
||||||
|
|
||||||
|
// define context data to be retrieved. Cannot be done at class level,
|
||||||
|
// as some default values are dynamic
|
||||||
|
$contextData = $this->_getContextDataDef();
|
||||||
|
|
||||||
|
// must reset limistart if limit is changed
|
||||||
|
$mustResetLimitstart = false;
|
||||||
|
|
||||||
|
// get the values from session and store them for future reuse
|
||||||
|
foreach( $contextData as $contextDataItem) {
|
||||||
|
|
||||||
|
// must reset limistart if limit is changed, so store previous value of limit
|
||||||
|
if ($contextDataItem['name'] == 'limit') {
|
||||||
|
// search for previous value
|
||||||
|
$previousLimit = $application->getUserState( $this->_context . '.limit');
|
||||||
|
$previousLimitstart = $application->getUserState( $this->_context . '.limitstart');
|
||||||
|
}
|
||||||
|
|
||||||
|
// get value
|
||||||
|
$value = $application->getUserStateFromRequest( $this->_context . '.' . $contextDataItem['name'], $contextDataItem['html_name'], $contextDataItem['default'], $contextDataItem['type'] );
|
||||||
|
|
||||||
|
if ($contextDataItem['name'] == 'limit' && isset($previousLimit) && $value != $previousLimit) {
|
||||||
|
$mustResetLimitstart = true;
|
||||||
|
$newLimit = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and store it into this model
|
||||||
|
$this->setState( $this->_context . '.' . $contextDataItem['name'], $value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// now check if we should reset limitstart
|
||||||
|
if ($mustResetLimitstart) {
|
||||||
|
|
||||||
|
$newLimitstart = empty( $newLimit) ? 0 : $newLimit * floor( $previousLimitstart / $newLimit);
|
||||||
|
// store it into the session and the model
|
||||||
|
$application->setUserState( $this->_context . '.limitstart', $newLimitstart);
|
||||||
|
$this->setState( $this->_context . '.limitstart', $newLimitstart);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getOption( $name, $options, $default = null) {
|
||||||
|
|
||||||
|
if (empty( $options) || !is_object( $options)) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = isset( $options->$name) ? $options->$name : $default;
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Short cut to get current state of value
|
||||||
|
* @param string $key
|
||||||
|
*/
|
||||||
|
protected function _getState( $key) {
|
||||||
|
|
||||||
|
return $this->getState( $this->_context . '.' . $key);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* short cut to set the state of a value
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param mixed $value
|
||||||
|
*/
|
||||||
|
protected function _setState( $key, $value) {
|
||||||
|
|
||||||
|
return $this->setState( $this->_context . '.' . $key, $value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function _cleanForQuery( $string) {
|
||||||
|
|
||||||
|
return $this->_db->escape( JString::trim( JString::strtolower( $string )));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,315 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
jimport('joomla.application.component.model');
|
||||||
|
|
||||||
|
abstract class Sh404sefClassBasemodel extends ShlMvcModel_Base {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data object
|
||||||
|
*
|
||||||
|
* @var object
|
||||||
|
*/
|
||||||
|
protected $_data = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds current context, ie : controller/model/view/layout hierarchy
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $_context = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds default table name
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $_defaultTable = '';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an item as an object
|
||||||
|
* identified by its db id
|
||||||
|
*
|
||||||
|
* @param integer $id
|
||||||
|
*/
|
||||||
|
public function getById( $id) {
|
||||||
|
|
||||||
|
// if no cached data, fetch from DB or create
|
||||||
|
if (is_null( $this->_data) || $this->_data->id != $id) {
|
||||||
|
|
||||||
|
jimport('joomla.database.table');
|
||||||
|
|
||||||
|
// get a table instance
|
||||||
|
$this->_data = JTable::getInstance( $this->_defaultTable, 'Sh404sefTable');
|
||||||
|
|
||||||
|
// load from table
|
||||||
|
try {
|
||||||
|
$this->_data->load( $id);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
ShlSystem_Log::error( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage());
|
||||||
|
$this->_data->setError( $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// set error
|
||||||
|
$error = $this->_data->getError();
|
||||||
|
if (!empty($error)) {
|
||||||
|
$this->setError( $error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of items as objects
|
||||||
|
* as selected in the db based on passed
|
||||||
|
* options (ie $options = array( 'id' => 12);)
|
||||||
|
*
|
||||||
|
* Data is not cached!
|
||||||
|
*
|
||||||
|
* @param array $options an array of key/ value pairs representing select params
|
||||||
|
* @param boolean if true, method will only count matching records
|
||||||
|
*
|
||||||
|
* @return array of objects
|
||||||
|
*/
|
||||||
|
public function getByAttr( $options, $countOnly = false) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
if($countOnly) {
|
||||||
|
$list = ShlDbHelper::count( $this->_getTableName(), '*', $options);
|
||||||
|
} else {
|
||||||
|
$list = ShlDbHelper::selectObjectList( $this->_getTableName(), '*', $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$list = $countOnly ? 0 : array();
|
||||||
|
ShlSystem_Log::error( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setData( $data) {
|
||||||
|
|
||||||
|
// get a table instance
|
||||||
|
$this->_data = JTable::getInstance( $this->_defaultTable, 'Sh404sefTable');
|
||||||
|
|
||||||
|
// bind data
|
||||||
|
try {
|
||||||
|
$this->_data->bind( $data);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
ShlSystem_Log::error( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage());
|
||||||
|
$this->_data->setError( $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// set error
|
||||||
|
$error = $this->_data->getError();
|
||||||
|
if (!empty($error)) {
|
||||||
|
$this->setError( $error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create or update a record to
|
||||||
|
* DB from POST data or input array of data
|
||||||
|
*
|
||||||
|
* @param array $dataArray an array holding data to save. If empty, $_POST is used
|
||||||
|
* @return integer id of created or updated record
|
||||||
|
*/
|
||||||
|
public function save( $dataArray = null) {
|
||||||
|
|
||||||
|
// get required tools
|
||||||
|
jimport( 'joomla.database.table');
|
||||||
|
$this->_data = JTable::getInstance( $this->_defaultTable, 'Sh404sefTable');
|
||||||
|
$post = is_null( $dataArray) ? JRequest::get('post') : $dataArray;
|
||||||
|
|
||||||
|
// use table save method
|
||||||
|
try {
|
||||||
|
$status = $this->_data->save( $post);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
ShlSystem_Log::error( 'sh404sef', '%s::%s::%d: %s', __CLASS__, __METHOD__, __LINE__, $e->getMessage());
|
||||||
|
$this->_data->setError( $e->getMessage());
|
||||||
|
$status = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// report error
|
||||||
|
if (!$status) {
|
||||||
|
JFactory::getApplication()->enqueuemessage( $this->_data->getError());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if success, fetch last insert id and return that
|
||||||
|
$tableDb = $this->_data->getDBO();
|
||||||
|
$keyName = $this->_data->getKeyName();
|
||||||
|
$id = empty($post[$keyName]) ? 0 : intval($post[$keyName]);
|
||||||
|
$savedId = empty( $id) ? $tableDb->insertid() : $id;
|
||||||
|
|
||||||
|
return $savedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set current context string, replacing existing one
|
||||||
|
*
|
||||||
|
* @param string $newContext
|
||||||
|
* @return string updated context
|
||||||
|
*/
|
||||||
|
public function setContext( $newContext = '') {
|
||||||
|
|
||||||
|
if (!empty( $newContext)) {
|
||||||
|
$this->setState( 'context', $newContext);
|
||||||
|
|
||||||
|
// reset object data as context has changed
|
||||||
|
$this->_resetData();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getState( 'context');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update current context string, appending
|
||||||
|
* new context to existing one, separated by '.'
|
||||||
|
*
|
||||||
|
* @param string $newContextPart
|
||||||
|
* @return string updated context
|
||||||
|
*/
|
||||||
|
public function updateContext( $newContextPart = '') {
|
||||||
|
|
||||||
|
$currentContext = $this->getState('context');
|
||||||
|
|
||||||
|
if (!empty( $newContextPart)) {
|
||||||
|
$this->setState( 'context', $currentContext . '.' . $newContextPart);
|
||||||
|
|
||||||
|
// reset object data as context has changed
|
||||||
|
$this->_resetData();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getState( 'context');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getTableName() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an object list
|
||||||
|
* Overriden to check on respective values
|
||||||
|
* of limit and limit start
|
||||||
|
* If limit is 0, limitstart should be reset to 0 as well
|
||||||
|
*
|
||||||
|
* @param string The query
|
||||||
|
* @param int Offset
|
||||||
|
* @param int The number of records
|
||||||
|
* @return array
|
||||||
|
* @access protected
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
protected function _getList( $query, $limitstart=0, $limit=0 )
|
||||||
|
{
|
||||||
|
|
||||||
|
// check limit and lim
|
||||||
|
$limitstart = $limit === 0 ? 0 : $limitstart;
|
||||||
|
|
||||||
|
// do the job
|
||||||
|
$result = parent::_getList( $query, $limitstart, $limit);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides context data definition, to be used by context handler
|
||||||
|
* Should be overriden by descendant
|
||||||
|
*/
|
||||||
|
protected function _getContextDataDef() {
|
||||||
|
|
||||||
|
$application = JFactory::getApplication();
|
||||||
|
|
||||||
|
// define context data to be retrieved. Cannot be done at class level,
|
||||||
|
// as some default values are dynamic
|
||||||
|
$contextData = array();
|
||||||
|
|
||||||
|
return $contextData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset model internal cached data
|
||||||
|
* used after changing context for instance
|
||||||
|
*/
|
||||||
|
protected function _resetData() {
|
||||||
|
|
||||||
|
// clean data, total and pagination, as we need them rebuilt
|
||||||
|
$this->_data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read application user state stored by
|
||||||
|
* Joomla application object for the current context
|
||||||
|
* context represents current controller/model/view hierarchy
|
||||||
|
* and has been set by each of those elements
|
||||||
|
*/
|
||||||
|
protected function _updateContextData() {
|
||||||
|
|
||||||
|
// if not been there before, or context has changed since last visit
|
||||||
|
if (is_null($this->_context) || $this->_context != $this->getState( 'context')) {
|
||||||
|
|
||||||
|
// read context name and store inclass variabel, easier to access later on
|
||||||
|
$this->_context = $this->getState( 'context');
|
||||||
|
|
||||||
|
// get an application instance
|
||||||
|
$application = JFactory::getApplication();
|
||||||
|
|
||||||
|
// define context data to be retrieved. Cannot be done at class level,
|
||||||
|
// as some default values are dynamic
|
||||||
|
$contextData = $this->_getContextDataDef();
|
||||||
|
|
||||||
|
// get the values from session and store them for future reuse
|
||||||
|
if (!empty( $contextData)) {
|
||||||
|
foreach( $contextData as $contextDataItem) {
|
||||||
|
// get value
|
||||||
|
$value = $application->getUserStateFromRequest( $this->_context . '.' . $contextDataItem['name'], $contextDataItem['html_name'], $contextDataItem['default'], $contextDataItem['type'] );
|
||||||
|
|
||||||
|
// and store
|
||||||
|
$this->setState( $this->_context . '.' . $contextDataItem['name'], $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getOption( $name, $options, $default = null) {
|
||||||
|
|
||||||
|
$value = isset( $options->$name) ? $options->$name : $default;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Short cut to get current state of value
|
||||||
|
* @param string $key
|
||||||
|
*/
|
||||||
|
protected function _getState( $key) {
|
||||||
|
|
||||||
|
return $this->getState( $this->_context . '.' . $key);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _cleanForQuery( $string) {
|
||||||
|
|
||||||
|
return $this->_db->escape( JString::trim( JString::strtolower( $string )));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,296 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
Class Sh404sefClassBasewizcontroller extends Sh404sefClassBasecontroller {
|
||||||
|
|
||||||
|
protected $_context = 'com_sh404sef.wiz';
|
||||||
|
|
||||||
|
protected $_defaultController = '';
|
||||||
|
protected $_defaultTask = '';
|
||||||
|
protected $_defaultModel = '';
|
||||||
|
protected $_defaultView = 'wizard';
|
||||||
|
protected $_defaultLayout = 'default';
|
||||||
|
|
||||||
|
protected $_returnController = '';
|
||||||
|
protected $_returnTask = '';
|
||||||
|
protected $_returnView = 'default';
|
||||||
|
protected $_returnLayout = 'default';
|
||||||
|
|
||||||
|
protected $_opType = '';
|
||||||
|
protected $_opSubject = '';
|
||||||
|
|
||||||
|
protected $_mainText = '';
|
||||||
|
protected $_hiddenText = '';
|
||||||
|
protected $_stepTitle = '';
|
||||||
|
protected $_setFormEncType = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @param array 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).
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public function __construct( $config = array() ) {
|
||||||
|
|
||||||
|
// call parent, doing main construct job
|
||||||
|
parent::__construct( $config);
|
||||||
|
|
||||||
|
// attach appropriate adapter
|
||||||
|
$this->_opType = strtolower( JRequest::getCmd( 'optype')); //ex : 'import'
|
||||||
|
$this->_opSubject = strtolower( JRequest::getCmd( 'opsubject')); // ex: pageids
|
||||||
|
|
||||||
|
// update context
|
||||||
|
$this->_context .= '.' . $this->_opType . '.' . $this->_opSubject;
|
||||||
|
|
||||||
|
// create adapter object
|
||||||
|
$adapterName = 'Sh404sefAdapter' . ucfirst( $this->_opType) . $this->_opSubject;
|
||||||
|
|
||||||
|
if (!class_exists( $adapterName)) {
|
||||||
|
$this->_fail( 'COM_SH404SEF_INVALID_WIZARD_ADAPTER');
|
||||||
|
} else {
|
||||||
|
$this->_adapter = new $adapterName( $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect properties from adapter
|
||||||
|
$properties = $this->_adapter->setup();
|
||||||
|
|
||||||
|
// and store them
|
||||||
|
foreach($properties as $key => $value) {
|
||||||
|
$this->$key = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the view
|
||||||
|
*/
|
||||||
|
public function display( $cachable = false, $urlparams = false) {
|
||||||
|
|
||||||
|
// catch up any result message coming from an
|
||||||
|
// ajax save for instance, and push that into
|
||||||
|
// the application message queue
|
||||||
|
$messageCode = JRequest::getCmd( 'sh404sefMsg');
|
||||||
|
if (!empty($messageCode)) {
|
||||||
|
$msg = JText::_( $messageCode);
|
||||||
|
if ($msg != $messageCode) {
|
||||||
|
// if no language string exists, JText will
|
||||||
|
// return the input string, so only display if
|
||||||
|
// we have something to display
|
||||||
|
$app = JFactory::getApplication();
|
||||||
|
$app->enqueuemessage( $msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get/create the view
|
||||||
|
$document =JFactory::getDocument();
|
||||||
|
$viewType = $document->getType();
|
||||||
|
$view = $this->getView( $this->_adapter->_stepsMap[$this->_adapter->_step]['view'], $viewType, '', array( 'base_path'=>$this->basePath));
|
||||||
|
|
||||||
|
// Set the layout
|
||||||
|
$view->setLayout( $this->_adapter->_stepsMap[$this->_adapter->_step]['layout']);
|
||||||
|
|
||||||
|
// push button list into the view
|
||||||
|
$view->buttonsList = $this->_adapter->_buttonsList;
|
||||||
|
$view->visibleButtonsList = $this->_adapter->_visibleButtonsList;
|
||||||
|
|
||||||
|
// push list of steps in to the view
|
||||||
|
foreach( $this->_adapter->_buttonsList as $button) {
|
||||||
|
$view->$button = $this->_adapter->_steps[$button];
|
||||||
|
}
|
||||||
|
|
||||||
|
// push controller name into view
|
||||||
|
$view->actionController = $this->_defaultController;
|
||||||
|
|
||||||
|
// push operation type and subject into the view
|
||||||
|
$view->opType = $this->_opType;
|
||||||
|
$view->opSubject = $this->_opSubject;
|
||||||
|
|
||||||
|
// push title, main and hidden text
|
||||||
|
$view->pageTitle = $this->_pageTitle;
|
||||||
|
$view->mainText = $this->_mainText;
|
||||||
|
$view->hiddenText = $this->_hiddenText;
|
||||||
|
$view->setFormEncType = $this->_setFormEncType;
|
||||||
|
|
||||||
|
// check if we are done, and need to set a redirect
|
||||||
|
if (!empty( $this->_redirectTo)) {
|
||||||
|
$view->redirectTo = $this->_redirectTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we are continuein to another step, and need to set a redirect
|
||||||
|
if (!empty( $this->_continue)) {
|
||||||
|
$view->continue = $this->_continue;
|
||||||
|
}
|
||||||
|
if (!empty( $this->_nextStart)) {
|
||||||
|
$view->nextstart = $this->_nextStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// push controller errors in the view
|
||||||
|
$error = $this->getError();
|
||||||
|
if (!empty( $error)) {
|
||||||
|
$view->setError( $error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the view
|
||||||
|
$view->display();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry point for first screen of wizard
|
||||||
|
* without token check
|
||||||
|
*/
|
||||||
|
public function start() {
|
||||||
|
|
||||||
|
$this->_adapter->_button = 'next';
|
||||||
|
$this->_dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function next() {
|
||||||
|
|
||||||
|
// Check for request forgeries
|
||||||
|
//JRequest::checkToken() or jexit( 'Invalid Token' );
|
||||||
|
|
||||||
|
// if not form submit, just display current step
|
||||||
|
$this->_adapter->_button = 'next';
|
||||||
|
$this->_dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function previous() {
|
||||||
|
|
||||||
|
// Check for request forgeries
|
||||||
|
JRequest::checkToken() or jexit( 'Invalid Token' );
|
||||||
|
|
||||||
|
$this->_adapter->_button = 'previous';
|
||||||
|
$this->_dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function terminate() {
|
||||||
|
|
||||||
|
// Check for request forgeries
|
||||||
|
JRequest::checkToken() or jexit( 'Invalid Token' );
|
||||||
|
|
||||||
|
$this->_adapter->_button = 'terminate';
|
||||||
|
$this->_dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and display an error message
|
||||||
|
* in the parent window
|
||||||
|
*/
|
||||||
|
public function cancel() {
|
||||||
|
|
||||||
|
// Check for request forgeries
|
||||||
|
JRequest::checkToken() or jexit( 'Invalid Token' );
|
||||||
|
|
||||||
|
$this->_adapter->_button = 'cancel';
|
||||||
|
$this->_dispatch();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main entry point
|
||||||
|
*/
|
||||||
|
protected function _dispatch() {
|
||||||
|
|
||||||
|
// collect and store request params
|
||||||
|
// what is the step id to run depending on what button was pressed
|
||||||
|
// ie : next = 3, previous = 1, terminate = 6
|
||||||
|
foreach( $this->_adapter->_buttonsList as $button) {
|
||||||
|
$this->_adapter->_steps[$button] = JRequest::getInt( $button, $this->_adapter->_steps[$button]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check request params
|
||||||
|
if(!in_array( $this->_adapter->_button, $this->_adapter->_buttonsList)) {
|
||||||
|
$this->_fail( 'COM_SH404SEF_INVALID_WIZARD_STEP');
|
||||||
|
}
|
||||||
|
|
||||||
|
// _dispatch request to appropriate method
|
||||||
|
|
||||||
|
// _step contains numerical id of _stepsMap record to use
|
||||||
|
$this->_adapter->_step = $this->_adapter->_steps[$this->_adapter->_button];
|
||||||
|
|
||||||
|
// call the 'task' method listed in the _stepsMap array item
|
||||||
|
if (empty( $this->_adapter->_stepsMap[$this->_adapter->_step])) {
|
||||||
|
$this->_fail( 'COM_SH404SEF_INVALID_WIZARD_STEP');
|
||||||
|
} else {
|
||||||
|
$methodName = $this->_adapter->_stepsMap[$this->_adapter->_step]['task'];
|
||||||
|
if (is_callable (array( $this->_adapter, $methodName))) {
|
||||||
|
$result = $this->_adapter->$methodName();
|
||||||
|
$this->_useAdapterResult( $result);
|
||||||
|
$this->display();
|
||||||
|
} else {
|
||||||
|
$this->_fail( 'COM_SH404SEF_INVALID_WIZARD_STEP');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid internal parameters, errors in parameters
|
||||||
|
*/
|
||||||
|
protected function _fail( $msg) {
|
||||||
|
|
||||||
|
$app = JFactory::getApplication();
|
||||||
|
$app->enqueuemessage( $msg, 'error');
|
||||||
|
$this->display();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _useAdapterResult( $result) {
|
||||||
|
|
||||||
|
// use results : the adapter may have change the suject
|
||||||
|
// of this operation, after analyzing incoming data in an import
|
||||||
|
// for instance
|
||||||
|
if( !empty( $result['opSubject'])) {
|
||||||
|
$this->_opSubject = $result['opSubject'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// redirections results
|
||||||
|
$redirectOptions = empty( $result['redirectOptions']) ? array() : $result['redirectOptions'];
|
||||||
|
|
||||||
|
if (!empty( $result['redirectTo'])) {
|
||||||
|
$this->_redirectTo = $this->_getDefaultRedirect( $redirectOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// display results
|
||||||
|
if( !empty( $result['mainText'])) {
|
||||||
|
$this->_mainText = $result['mainText'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !empty( $result['hiddenText'])) {
|
||||||
|
$this->_hiddenText = $result['hiddenText'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty( $result['setFormEncType'])) {
|
||||||
|
$this->_setFormEncType = $result['setFormEncType'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !empty( $result['continue'])) {
|
||||||
|
// calculate redirect url to next step
|
||||||
|
$vars = array( 'option' => 'com_sh404sef', 'c' => $this->_defaultController, 'tmpl' => 'component', 'optype' => $this->_opType, 'opsubject' => $this->_opSubject);
|
||||||
|
$vars = array_merge( $vars, $result['continue']);
|
||||||
|
$this->_continue = Sh404sefHelperUrl::buildUrl( $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !empty( $result['nextStart'])) {
|
||||||
|
$this->_nextStart = $result['nextStart'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC'))
|
||||||
|
die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
@ -0,0 +1,443 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
// load a few constants
|
||||||
|
require_once JPATH_ROOT . '/administrator/components/com_sh404sef/defines.php';
|
||||||
|
|
||||||
|
//define('SH_SHOW_CACHE_STATS', 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL caching
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefClassFilecache extends Sh404sefClassBasecache {
|
||||||
|
|
||||||
|
protected $_newUrlsCache = array();
|
||||||
|
protected $_newUrlsCacheCount = 0;
|
||||||
|
protected $_cacheFilename = '';
|
||||||
|
protected $_cacheFilefullpath = '';
|
||||||
|
protected $_lockFilefullpath = '';
|
||||||
|
protected $_cacheFileLocked = false;
|
||||||
|
protected $_urlCacheRam = 0;
|
||||||
|
protected $_lockTtl = 35; // usual exec time is 30sec
|
||||||
|
|
||||||
|
protected $_fileHeader = '<?php // shCache : URL cache file for sh404SEF
|
||||||
|
// version %s
|
||||||
|
if (!defined(\'_JEXEC\')) die(\'Direct Access to this location is not allowed.\');
|
||||||
|
$shURLCacheCreationDate = %s;
|
||||||
|
';
|
||||||
|
|
||||||
|
public function __construct( $config) {
|
||||||
|
|
||||||
|
parent::__construct( $config);
|
||||||
|
|
||||||
|
// init cache filename, must be unique per live site, in case of multisite
|
||||||
|
$liveSite = str_replace( 'administrator/', '', JURI::base());
|
||||||
|
$this->_cacheFilename = 'shCacheContent.' . md5( $liveSite);
|
||||||
|
$this->_cacheFilefullpath = sh404SEF_FRONT_ABS_PATH . 'cache' . '/' . $this->_cacheFilename . '.php';
|
||||||
|
$this->_lockFilefullpath = sh404SEF_FRONT_ABS_PATH . 'cache' . '/' . $this->_cacheFilename . '.shlock';
|
||||||
|
|
||||||
|
// every now and then we clear the cache to let it refill with more recent data
|
||||||
|
$this->_itsTimeToCheckTTL = mt_rand(1, SH404SEF_URL_CACHE_WRITES_TO_CHECK_TTL) == 1;
|
||||||
|
|
||||||
|
// register method that will store urls created during
|
||||||
|
// current page request into cache file
|
||||||
|
if (!empty($this->_config->shUseURLCache)) {
|
||||||
|
register_shutdown_function( array( $this, 'writeURLCacheToDisk'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSefUrlFromCache( $nonSefUrl, & $sefUrl) {
|
||||||
|
|
||||||
|
if (!$this->_config->shUseURLCache) {
|
||||||
|
$sefUrl = null;
|
||||||
|
$this->_urlCacheMisses += 1;
|
||||||
|
return sh404SEF_URLTYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure cache is loaded, in case this method is called first
|
||||||
|
$this->_loadURLCache();
|
||||||
|
|
||||||
|
// no urls in cache, no need to go further
|
||||||
|
if (empty($this->_urlCacheCount) && empty($this->_newUrlsCacheCount)) {
|
||||||
|
$sefUrl = null;
|
||||||
|
$this->_urlCacheMisses += 1;
|
||||||
|
return sh404SEF_URLTYPE_NONE;
|
||||||
|
}
|
||||||
|
$key = md5( $nonSefUrl);
|
||||||
|
if(!empty( $this->_urlCache[$key])) {
|
||||||
|
$tmp = explode('#', $this->_urlCache[$key]); // cache format : non-sef#sef#type
|
||||||
|
$sefUrl = $tmp[1];
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', 'Retrieved SEF from disk cache : '.$sefUrl.' => '.html_entity_decode( $tmp[0], ENT_QUOTES).'('.$tmp[2].')');
|
||||||
|
$this->_urlCacheHits += 1;
|
||||||
|
return $tmp[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!empty( $this->_newUrlsCache[$key])) {
|
||||||
|
$tmp = explode('#', $this->_newUrlsCache[$key]); // cache format : non-sef#sef#type
|
||||||
|
$sefUrl = $tmp[1];
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', 'Retrieved SEF from disk cache : '.$sefUrl.' => '.html_entity_decode( $tmp[0], ENT_QUOTES).'('.$tmp[2].')');
|
||||||
|
$this->_urlCacheHits += 1;
|
||||||
|
return $tmp[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_urlCacheMisses += 1;
|
||||||
|
$this->_urlCacheMissesList[] = $nonSefUrl;
|
||||||
|
return sh404SEF_URLTYPE_NONE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch an URL from cache, return null if not found
|
||||||
|
public function getNonSefUrlFromCache( $sefUrl, & $nonSefUrl) {
|
||||||
|
|
||||||
|
if (!$this->_config->shUseURLCache) {
|
||||||
|
$nonSefUrl = null;
|
||||||
|
return sh404SEF_URLTYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure cache is loaded, in case this method is called first
|
||||||
|
$this->_loadURLCache();
|
||||||
|
|
||||||
|
// no urls in cache, no need to go further
|
||||||
|
if (empty($this->_urlCacheCount) && empty($this->_newUrlsCacheCount)) {
|
||||||
|
$nonSefUrl = null;
|
||||||
|
return sh404SEF_URLTYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// search for requested sef url in disk stored cache
|
||||||
|
foreach( $this->_urlCache as $key => $value) {
|
||||||
|
if (strpos( $value, $sefUrl) !== false) {
|
||||||
|
$tmp = explode('#', $value); // cache format : non-sef#sef#type
|
||||||
|
$nonSef = html_entity_decode( $tmp[0], ENT_QUOTES);
|
||||||
|
if ($sefUrl == $tmp[1]) {
|
||||||
|
$nonSefUrl = $nonSef;
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', 'Retrieved Non SEF from disk cache : '.$nonSefUrl.' => '.$tmp[1].'('.$tmp[2].')');
|
||||||
|
return $tmp[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// search also in urls waiting to be stored to disk
|
||||||
|
foreach( $this->_newUrlsCache as $key => $value) {
|
||||||
|
if (strpos( $value, $sefUrl) !== false) {
|
||||||
|
$tmp = explode('#', $value); // cache format : non-sef#sef#type
|
||||||
|
$nonSef = html_entity_decode( $tmp[0], ENT_QUOTES);
|
||||||
|
if ($sefUrl == $tmp[1]) {
|
||||||
|
$nonSefUrl = $nonSef;
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', 'Retrieved Non SEF from mem cache : '.$nonSefUrl.' => '.$tmp[1].'('.$tmp[2].')');
|
||||||
|
return $tmp[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sh404SEF_URLTYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addSefUrlToCache( $nonSefUrl, $sefUrl, $UrlType) {
|
||||||
|
|
||||||
|
if (!$this->_config->shUseURLCache) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure cache is loaded, in case this method is called first
|
||||||
|
$this->_loadURLCache();
|
||||||
|
|
||||||
|
// insertion key
|
||||||
|
$key = md5( $nonSefUrl);
|
||||||
|
|
||||||
|
// already there?
|
||||||
|
if(!empty($this->_urlCache[$key]) || !empty( $this->_newUrlsCache[$key])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($this->_urlCacheCount + $this->_newUrlsCacheCount) >= $this->_config->shMaxURLInCache) {
|
||||||
|
return null; // v 1.2.4.c added total cache size control
|
||||||
|
}
|
||||||
|
// Filter out non sef url which include &mosmsg, as I don't want to have a cache entry for every single msg
|
||||||
|
// that can be thrown at me, including every 404 error
|
||||||
|
if (strpos(strtolower($nonSefUrl), '&mosmsg')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// new cache format : non-sef#sef#type
|
||||||
|
$this->_newUrlsCache[md5($nonSefUrl)] = htmlentities( $nonSefUrl, ENT_QUOTES).'#'.$sefUrl.'#'.$UrlType;
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', 'Adding to URL cache : '.$sefUrl.' <= '.$nonSefUrl);
|
||||||
|
$this->_newUrlsCacheCount++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeUrlFromCache( $nonSefUrlList) {
|
||||||
|
|
||||||
|
if (!$this->_config->shUseURLCache || empty($nonSefUrlList)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure cache is loaded, in case this method is called first
|
||||||
|
$this->_loadURLCache();
|
||||||
|
|
||||||
|
$foundInDiskCache = false;
|
||||||
|
$foundInMemCache = false;
|
||||||
|
foreach ($nonSefUrlList as $nonSefURL) {
|
||||||
|
if (!empty($this->_newUrlsCache)) {
|
||||||
|
foreach ($this->_newUrlsCache as $key => $cacheItem) { // look up in memory cache
|
||||||
|
$tmp = explode('#', $cacheItem);
|
||||||
|
$cacheNonSef = html_entity_decode( $tmp[0], ENT_QUOTES);
|
||||||
|
if ($cacheNonSef == $nonSefURL) {
|
||||||
|
unset($this->_newUrlsCache[$key]);
|
||||||
|
$this->_newUrlsCacheCount--;
|
||||||
|
$foundInMemCache = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: rewrite using md5 key
|
||||||
|
if (!empty($this->_urlCache)) {
|
||||||
|
foreach ($this->_urlCache as $key => $cacheItem) { // look up disk cache
|
||||||
|
$tmp = explode('#', $cacheItem);
|
||||||
|
$cacheNonSef = html_entity_decode( $tmp[0], ENT_QUOTES);
|
||||||
|
if ($cacheNonSef == $nonSefURL) {
|
||||||
|
unset($this->_urlCache[$key]);
|
||||||
|
$this->_urlCacheCount--;
|
||||||
|
$foundInDiskCache = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($foundInMemCache) {
|
||||||
|
$this->_newUrlsCache = array_values($this->_newUrlsCache); // simply reindex mem cache
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($foundInDiskCache) { // we need to remove these url from the disk cache file
|
||||||
|
// to make it simpler, I simply rewrite the complete file
|
||||||
|
$this->_newUrlsCache = (empty($this->_newUrlsCache) ?
|
||||||
|
array_values($this->_urlCache)
|
||||||
|
:array_merge($this->_urlCache, $this->_newUrlsCache));
|
||||||
|
$this->_urlCache = array(); // don't need disk cache anymore, as all URL are in mem cache
|
||||||
|
// so we remove both on disk cache and in memory copy of on disk cache
|
||||||
|
$this->purge();
|
||||||
|
// no need to write new URL list in disk file, as this will be done automatically at shutdown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function writeURLCacheToDisk() {
|
||||||
|
|
||||||
|
// If we acquired lock at page load, we can write
|
||||||
|
if (count($this->_newUrlsCache) && $this->_cacheFileLocked) {
|
||||||
|
$cache = '';
|
||||||
|
$now = time();
|
||||||
|
if (!file_exists($this->_cacheFilefullpath)) {
|
||||||
|
$cache = sprintf( $this->_fileHeader, $this->_config->version, $now);
|
||||||
|
$this->_urlCacheCreationDate = $now;
|
||||||
|
} else {
|
||||||
|
// check cache TTL
|
||||||
|
if (empty($this->_urlCacheCreationDate)){ // file exists, but creation date is missing : we are upgrading from a previous version
|
||||||
|
$status = stat($this->_cacheFilefullpath); // lets's read from file status : use last change date as creation date
|
||||||
|
if (!empty($status)) {
|
||||||
|
$this->_urlCacheCreationDate = $status[9];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SH404SEF_URL_CACHE_TTL && $this->_itsTimeToCheckTTL) { // probability = 1/SH404SEF_WRITES_TO_CLEAN_LOGS
|
||||||
|
if (!empty($this->_urlCacheCreationDate)){ // if we have a valid creation date, check TTL
|
||||||
|
if (($now-$this->_urlCacheCreationDate) > SH404SEF_URL_CACHE_TTL*3600) { // cache must be cleared
|
||||||
|
$this->_urlCache = array();
|
||||||
|
unlink($this->_cacheFilefullpath);
|
||||||
|
$this->_urlCacheCreationDate = $now;
|
||||||
|
$cache = sprintf( $this->_fileHeader, $this->_config->version, $now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$count = count( $this->_urlCache);
|
||||||
|
$cache .= $this->_varExport( $this->_newUrlsCache, $count); // only need to write memory cache, ie: those URL added since last read of cache from disk
|
||||||
|
$cache .= "\n".'$shURLCacheCreationDate='.$now.';';
|
||||||
|
$cacheFile = fopen( $this->_cacheFilefullpath,'ab');
|
||||||
|
if ($cacheFile) {
|
||||||
|
fwrite( $cacheFile, $cache);
|
||||||
|
fclose( $cacheFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// in any case, release lock to file
|
||||||
|
$this->_releaseLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function purge( $allCaches = true) {
|
||||||
|
|
||||||
|
jimport( 'joomla.filesystem.file');
|
||||||
|
jimport( 'joomla.filesystem.folder');
|
||||||
|
if(!JFolder::exists(sh404SEF_FRONT_ABS_PATH . 'cache'))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if($allCaches) {
|
||||||
|
// delete all sh404SEF cache files in the dir
|
||||||
|
// so as to clear also potential https, or alternate domains caches
|
||||||
|
jimport( 'joomla.filesystem.folder');
|
||||||
|
$files = JFolder::files( sh404SEF_FRONT_ABS_PATH . 'cache', 'shCacheContent\.', $recurse = false, $fullpath = true);
|
||||||
|
if(!empty( $files)) {
|
||||||
|
foreach( $files as $file) {
|
||||||
|
if (JFile::exists( $file)) {
|
||||||
|
JFile::delete( $file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// only delete cache for current live site url
|
||||||
|
if (JFile::exists( $this->_cacheFilefullpath)) {
|
||||||
|
JFile::delete( $this->_cacheFilefullpath);
|
||||||
|
}
|
||||||
|
if (JFile::exists( $this->_lockFilefullpath)) {
|
||||||
|
JFile::delete( $this->_lockFilefullpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCacheStats() {
|
||||||
|
|
||||||
|
// collect basic data
|
||||||
|
$out = parent::getCacheStats();
|
||||||
|
|
||||||
|
// add urls waiting to be written
|
||||||
|
$out .= 'In memory, waiting to be written : '. $this->_newUrlsCacheCount . '<br />';
|
||||||
|
|
||||||
|
// add ram usage of cached urls read from disk file
|
||||||
|
// and stored in ram
|
||||||
|
$out .= 'Ram used : '. $this->_urlCacheRam . '<br />';
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load cached URL from disk into an array in memory
|
||||||
|
protected function _loadURLCache() {
|
||||||
|
|
||||||
|
static $shDiskCacheLoaded = false;
|
||||||
|
|
||||||
|
if (!$shDiskCacheLoaded) {
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', 'Cache not loaded - trying to load '.$this->_cacheFilefullpath);
|
||||||
|
if (file_exists( $this->_cacheFilefullpath)) {
|
||||||
|
$startMem = function_exists('memory_get_usage')? memory_get_usage():'unavailable';
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', 'Including cache file (mem = '.$startMem.')');
|
||||||
|
$this->_urlCache = array();
|
||||||
|
// we try lock the cache file until the end of the request
|
||||||
|
// so as to avoid other concurrent requests writing to it
|
||||||
|
// while we have some pending data
|
||||||
|
$this->_acquireLock();
|
||||||
|
|
||||||
|
// read cache file content
|
||||||
|
include($this->_cacheFilefullpath);
|
||||||
|
$this->_urlCacheCreationDate = $shURLCacheCreationDate;
|
||||||
|
|
||||||
|
$endMem = function_exists('memory_get_usage')? memory_get_usage():'unavailable';
|
||||||
|
$this->_urlCacheRam = $startMem == 'unavailable' ? $startMem: $endMem - $startMem;
|
||||||
|
$shDiskCacheLoaded = !empty($this->_urlCache);
|
||||||
|
$this->_urlCacheCount = !empty($this->_urlCache) ? count($this->_urlCache) : 0;
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', 'Cache file included : '.($startMem == 'unavailable' ? $startMem: $endMem-$startMem).' bytes used, '.$this->_urlCacheCount.' URLs');
|
||||||
|
} else {
|
||||||
|
// cache file not there, create it
|
||||||
|
$now = time();
|
||||||
|
$cache = sprintf( $this->_fileHeader, $this->_config->version, $now);
|
||||||
|
|
||||||
|
// lock cache file before using it
|
||||||
|
if ( $this->_acquireLock()) {
|
||||||
|
$cacheFile = fopen( $this->_cacheFilefullpath,'ab');
|
||||||
|
if ($cacheFile) {
|
||||||
|
fwrite( $cacheFile, $cache);
|
||||||
|
fclose( $cacheFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->_urlCache = array();
|
||||||
|
$this->_urlCacheCount = 0;
|
||||||
|
$shDiskCacheLoaded = true; // we don't want to try again if it failed first time
|
||||||
|
$this->_urlCacheCreationDate = $now;
|
||||||
|
ShlSystem_Log::debug( 'sh404sef', 'Cache file does not exists');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _acquireLock() {
|
||||||
|
|
||||||
|
$attempts = 0;
|
||||||
|
$tryAgain = false;
|
||||||
|
$now = time();
|
||||||
|
do {
|
||||||
|
// directly attempts to create the lock. If it fails, then element is already locked
|
||||||
|
$handle = @fopen( $this->_lockFilefullpath, 'x');
|
||||||
|
if ($handle) {
|
||||||
|
// we could create file for writing, element is not locked.
|
||||||
|
// store time, close and return
|
||||||
|
$written = fwrite( $handle, $now);
|
||||||
|
$closed = fclose($handle);
|
||||||
|
// return true if we could write the time stamp
|
||||||
|
$this->_cacheFileLocked = !empty($written) && $closed;
|
||||||
|
// we don't try again, even if we failed writing -> something is not working anyway
|
||||||
|
} else {
|
||||||
|
// we could not create lock file, element is already locked
|
||||||
|
// by another process. Check for timeout
|
||||||
|
// read lock file, and check TTL
|
||||||
|
if ($this->_itsTimeToCheckTTL) {
|
||||||
|
$lockTime = JFile::exists($this->_lockFilefullpath) ? file_get_contents( $this->_lockFilefullpath) : 0;
|
||||||
|
$lockTime = (int) trim( $lockTime);
|
||||||
|
if (($now - $lockTime) > $this->_lockTtl) {
|
||||||
|
// existing lock has timed out, we can release it
|
||||||
|
$this->_cacheFileLocked = $this->_releaseLock( true);
|
||||||
|
// we have released the lock file, we can try again grabbing it
|
||||||
|
// as we test also for _cacheFileLocked, this will happen only if the release was successful
|
||||||
|
$tryAgain = true;
|
||||||
|
} else {
|
||||||
|
$tryAgain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!$this->_cacheFileLocked && $tryAgain);
|
||||||
|
|
||||||
|
return $this->_cacheFileLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _releaseLock( $forced = false) {
|
||||||
|
|
||||||
|
if ($this->_cacheFileLocked || $forced) {
|
||||||
|
jimport( 'joomla.filesystem.file');
|
||||||
|
if (JFile::exists( $this->_lockFilefullpath)) {
|
||||||
|
$this->_cacheFileLocked = !JFile::delete( $this->_lockFilefullpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_cacheFileLocked;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _varExport( $cache, $start) {
|
||||||
|
|
||||||
|
// export content of array $cache, inserting a numeric key starting at $start
|
||||||
|
$size = count( $cache);
|
||||||
|
if (empty($size)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$ret = '';
|
||||||
|
|
||||||
|
foreach($cache as $key => $value) { // use for instead of foreach to reduce memory usage
|
||||||
|
$tmp = explode('#', $value); // cache format : non-sef#sef#type
|
||||||
|
$nonSef = html_entity_decode( $tmp[0], ENT_QUOTES);
|
||||||
|
$ret .= "\n".'$this->_urlCache[\''.md5($nonSef).'\']=\''.$value.'\';';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,411 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* sh404SEF - SEO extension for Joomla!
|
||||||
|
*
|
||||||
|
* @author Yannick Gaultier
|
||||||
|
* @copyright (c) Yannick Gaultier 2014
|
||||||
|
* @package sh404SEF
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
|
||||||
|
* @version 4.4.4.1791
|
||||||
|
* @date 2014-07-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Security check to ensure this file is being included by a parent file.
|
||||||
|
if (!defined('_JEXEC')) die('Direct Access to this location is not allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement wizard based exportation of generic data
|
||||||
|
*
|
||||||
|
* @author shumisha
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Sh404sefClassImportgeneric extends JObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array holding each step details
|
||||||
|
* A step is defined as a task, a view and a layout
|
||||||
|
* By default, task can be 'display', but still need
|
||||||
|
* to be defined in array
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $_stepsMap = array(
|
||||||
|
|
||||||
|
-2 => array( 'task' => 'doTerminate', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
,-1 => array( 'task' => 'doCancel', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 0 => array( 'task' => 'doStart', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 1 => array( 'task' => 'doUpload', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 2 => array( 'task' => 'doValidate', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
, 3 => array( 'task' => 'doImport', 'view' => 'wizard', 'layout' => 'default')
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
public $_stepsCount = 0;
|
||||||
|
public $_steps = array( 'next' => 0, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
public $_button = '';
|
||||||
|
public $_buttonsList = array ('next', 'previous', 'terminate', 'cancel');
|
||||||
|
// visible buttons are displayed as toolbar pressbutton
|
||||||
|
// buttons not on that list are passed as 'hidden' post data
|
||||||
|
public $_visibleButtonsList = array ( 'previous', 'next', 'terminate', 'cancel');
|
||||||
|
|
||||||
|
protected $_context = '';
|
||||||
|
protected $_total = 0;
|
||||||
|
protected $_parentController = null;
|
||||||
|
protected $_filename = '';
|
||||||
|
protected $_result = array();
|
||||||
|
|
||||||
|
const MAX_PAGEIDS_PER_STEP = 20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor, keep reference to controller
|
||||||
|
* which called the adapter
|
||||||
|
* @param unknown_type $parentController
|
||||||
|
*/
|
||||||
|
public function __construct( $parentController) {
|
||||||
|
|
||||||
|
$this->_parentController = $parentController;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for current adapter, to be used by parent controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setup() {
|
||||||
|
|
||||||
|
$this->_stepsCount = count( $this->_stepsMap);
|
||||||
|
|
||||||
|
// prepare data for controller
|
||||||
|
$properties = array();
|
||||||
|
|
||||||
|
$properties['_defaultController'] = 'wizard';
|
||||||
|
$properties['_defaultTask'] = '';
|
||||||
|
$properties['_defaultModel'] = '';
|
||||||
|
$properties['_defaultView'] = 'wizard';
|
||||||
|
$properties['_defaultLayout'] = 'default';
|
||||||
|
|
||||||
|
$properties['_returnController'] = 'default';
|
||||||
|
$properties['_returnTask'] = '';
|
||||||
|
$properties['_returnView'] = 'default';
|
||||||
|
$properties['_returnLayout'] = 'default';
|
||||||
|
$properties['_pageTitle'] = JText::_('COM_SH404SEF_IMPORTING_TITLE');
|
||||||
|
|
||||||
|
return $properties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First step, by default a message
|
||||||
|
* and a Terminate button
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doStart() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ('next', 'cancel');
|
||||||
|
|
||||||
|
// next steps definition
|
||||||
|
$this->_steps = array( 'next' => 1, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
$this->_result['mainText'] = JText::_('COM_SH404SEF_IMPORT_' . strtoupper( $this->_context). '_START');
|
||||||
|
|
||||||
|
return $this->_result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Second step, let user upload file
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doUpload() {
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ( 'next', 'cancel');
|
||||||
|
|
||||||
|
// next steps definition
|
||||||
|
$this->_steps = array( 'next' => 2, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// return results
|
||||||
|
|
||||||
|
// make sure we can upload, ie set the correct encoding type for the form
|
||||||
|
$this->_result['setFormEncType'] = 'multipart/form-data';
|
||||||
|
|
||||||
|
// prepare display
|
||||||
|
$this->_result['mainText'] = JText::sprintf('COM_SH404SEF_IMPORT_UPLOAD_FILE', Sh404sefHelperFiles::getMaxUploadSize());
|
||||||
|
|
||||||
|
// add a file browse button
|
||||||
|
$this->_result['mainText'] .= '<div style="text-align:center;width:100%;" ><input type="file" name="wizardfile" size="70" /></div>';
|
||||||
|
|
||||||
|
return $this->_result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Second step, read file content, validate and display for user go ahead
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doValidate() {
|
||||||
|
|
||||||
|
// get file name
|
||||||
|
$fileRecord = JRequest::getVar( 'wizardfile', null, 'files');
|
||||||
|
|
||||||
|
// move uploaded file, to get access to it
|
||||||
|
$this->_filename = Sh404sefHelperFiles::createFileName( $this->_filename, 'sh404sef_import_' . $this->_context);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!move_uploaded_file($fileRecord['tmp_name'], $this->_filename)) {
|
||||||
|
// could not write to web space temp dir
|
||||||
|
throw new Sh404sefExceptionDefault( JText::_('COM_SH404SEF_WRITE_FAILED'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ( 'previous', 'next', 'cancel');
|
||||||
|
|
||||||
|
// next steps definition
|
||||||
|
$this->_steps = array( 'next' => 3, 'previous' => 1, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// analyse file content, returning itemsCount
|
||||||
|
$importType = $this->_analyzeImportFileContent( $this->_filename);
|
||||||
|
|
||||||
|
// we may have to change the opSubject and related data. If user asked for instance to import
|
||||||
|
// aliases, from the aliases page, but actually loaded an import file
|
||||||
|
// containing urls or pageids
|
||||||
|
if ($this->_context != $importType) {
|
||||||
|
$this->_result['opSubject'] = $importType;
|
||||||
|
// update filename
|
||||||
|
$oldFileName = $this->_filename;
|
||||||
|
$this->_filename = str_replace( $this->_context, $importType, $this->_filename);
|
||||||
|
// and rename the temp file
|
||||||
|
JFile::move( $oldFileName, $this->_filename);
|
||||||
|
// tell parent controller that we should go to new target afer this import
|
||||||
|
$this->_parentController->set( '_returnController', $importType);
|
||||||
|
$this->_parentController->set( '_returnView', $importType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save current file for next steps
|
||||||
|
$this->_result['mainText'] = JText::sprintf( 'COM_SH404SEF_IMPORT_VALIDATE_IMPORT', $importType, $this->_total);
|
||||||
|
$this->_result['hiddenText'] = '<input type="hidden" name="filename" value="' . $this->_filename . '" />';
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->_handleException( $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last step, actually perform importation
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doImport() {
|
||||||
|
|
||||||
|
// collect file and import type information
|
||||||
|
$this->_filename = JRequest::getString( 'filename');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// read file content in an array
|
||||||
|
$lines = file( $this->_filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
|
|
||||||
|
// start analysing
|
||||||
|
if (empty( $lines)) {
|
||||||
|
throw new Sh404sefExceptionDefault( 'COM_SH404SEF_ERROR_IMPORT');
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract header line
|
||||||
|
$header = array_shift( $lines);
|
||||||
|
if (empty( $header)) {
|
||||||
|
throw new Sh404sefExceptionDefault( 'COM_SH404SEF_ERROR_IMPORT');
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn header into an array
|
||||||
|
$header = $this->_lineToArray( $header);
|
||||||
|
|
||||||
|
// count items
|
||||||
|
$this->_total = count( $lines);
|
||||||
|
|
||||||
|
// iterate through file content and create each record
|
||||||
|
foreach( $lines as $line) {
|
||||||
|
$this->_createRecord( $header, $line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get back memory
|
||||||
|
unset( $lines);
|
||||||
|
|
||||||
|
// delete temporary uploaded file
|
||||||
|
JFile::delete( $this->_filename);
|
||||||
|
|
||||||
|
// which button should be displayed ?
|
||||||
|
$this->_visibleButtonsList = array ( 'terminate');
|
||||||
|
|
||||||
|
// next steps definition
|
||||||
|
$this->_steps = array( 'next' => 3, 'previous' => 0, 'cancel' => -1, 'terminate' => -2);
|
||||||
|
|
||||||
|
// setup display of wizard last page
|
||||||
|
$this->_result['hiddenText'] = '';
|
||||||
|
$this->_result['mainText'] = JText::sprintf('COM_SH404SEF_IMPORT_DONE', $this->_total, $this->_context);
|
||||||
|
$this->_result['mainText'] .= $this->_getTerminateOptions();
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
|
||||||
|
$this->_handleException( $e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doTerminate() {
|
||||||
|
|
||||||
|
// now go back to main page
|
||||||
|
$this->_result = array( 'redirectTo' => true);
|
||||||
|
|
||||||
|
return $this->_result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the wizard window and redirect to default page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function doCancel() {
|
||||||
|
|
||||||
|
$this->_result['redirectTo'] = true;
|
||||||
|
$this->_result['redirectOptions'] = array();
|
||||||
|
|
||||||
|
return $this->_result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyze the content of a potential import file
|
||||||
|
* to try recognize its content. Also find the
|
||||||
|
* number of records in the file
|
||||||
|
* @param string $filename fully pathed file name
|
||||||
|
*/
|
||||||
|
protected function _analyzeImportFileContent( $filename) {
|
||||||
|
|
||||||
|
// read file content in an array
|
||||||
|
$lines = file( $filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
|
|
||||||
|
// start analysing
|
||||||
|
if (empty( $lines)) {
|
||||||
|
throw new Sh404sefExceptionDefault( JText::_('COM_SH404SEF_IMPORT_UNRECOGNIZED_CONTENT'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract header line
|
||||||
|
jimport( 'joomla.utilities.string');
|
||||||
|
$header = JString::trim(array_shift( $lines));
|
||||||
|
if (empty( $header)) {
|
||||||
|
throw new Sh404sefExceptionDefault( JText::_('COM_SH404SEF_IMPORT_UNRECOGNIZED_CONTENT'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check against known headers
|
||||||
|
$headers = Sh404sefHelperGeneral::getExportHeaders();
|
||||||
|
foreach( $headers as $key => $value) {
|
||||||
|
if( $header == $value) {
|
||||||
|
$importType = $key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// have we found something ?
|
||||||
|
if (empty( $importType)) {
|
||||||
|
throw new Sh404sefExceptionDefault( JText::_('COM_SH404SEF_IMPORT_UNRECOGNIZED_CONTENT'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// count items
|
||||||
|
$this->_total = count( $lines);
|
||||||
|
|
||||||
|
// clear memory
|
||||||
|
unset( $lines);
|
||||||
|
|
||||||
|
// return record
|
||||||
|
return $importType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return html for any option that could
|
||||||
|
* be presented to the user on the last
|
||||||
|
* page of the wizard (like clean temp files)
|
||||||
|
* for instance. This will be displayed just after
|
||||||
|
* the mainText text, as prepared by the main
|
||||||
|
* part of this controller
|
||||||
|
*/
|
||||||
|
protected function _getTerminateOptions() {
|
||||||
|
|
||||||
|
$options = '';
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an exception by returning to step 2, where
|
||||||
|
* user can select a file
|
||||||
|
*
|
||||||
|
* @param Sh404sefExceptionDefault $e
|
||||||
|
*/
|
||||||
|
protected function _handleException( Exception $e) {
|
||||||
|
|
||||||
|
// unable to get the file, display error and go back to step 2, "doUpload"
|
||||||
|
$this->_parentController->setError( $e->getMessage());
|
||||||
|
|
||||||
|
// try delete the uploaded file
|
||||||
|
if (JFile::exists( $this->_filename)) {
|
||||||
|
JFile::delete( $this->_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// go back to previous step
|
||||||
|
$this->doUpload();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a record in the database, based
|
||||||
|
* on data read from import file
|
||||||
|
*
|
||||||
|
* @param array $header an array of fields, as built from the header line
|
||||||
|
* @param string $line raw record obtained from import file
|
||||||
|
*/
|
||||||
|
protected function _createRecord( $header, $line) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function _lineToArray( $line, $glue = null) {
|
||||||
|
|
||||||
|
$glue = is_null( $glue) ? Sh404sefHelperFiles::$stringDelimiter . Sh404sefHelperFiles::$fieldDelimiter . Sh404sefHelperFiles::$stringDelimiter : $glue;
|
||||||
|
|
||||||
|
// remove opening and closing quotes - can't use trim or ltrim, as this would remove several occurences
|
||||||
|
if (substr( $line, 0, 1) == Sh404sefHelperFiles::$stringDelimiter) {
|
||||||
|
$line = substr( $line, 1);
|
||||||
|
}
|
||||||
|
if (substr( $line, -1, 1) == Sh404sefHelperFiles::$stringDelimiter) {
|
||||||
|
$line = substr( $line, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// break up the line
|
||||||
|
$records = explode( $glue, $line);
|
||||||
|
if (empty( $records)) {
|
||||||
|
return $records;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now clean up a bit
|
||||||
|
foreach( $records as $i => $value) {
|
||||||
|
|
||||||
|
// remove double quotes, and store back in array
|
||||||
|
$records[$i] = Sh404sefHelperFiles::csvUnquote( $value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $records;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<html><body bgcolor="#FFFFFF"></body></html>
|
||||||