/**
* Module: Document Template Changer
*
* Purpose: Allows a new template to be applied to
* groups of documents using either a textbox for
* specifying ranges or by using a document tree.
*
* Author: Garry Nutting, MODx Testing Team
* Version: 1
* Date: 05/03/06
*/
//-- get theme
$tb_prefix = $modx->db->config['table_prefix'];
$theme = $modx->db->select('setting_value', $tb_prefix . 'system_settings', 'setting_name=\'manager_theme\'', '');
$theme = $modx->db->getRow($theme);
$theme = ($theme['setting_value'] <> '') ? $theme['setting_value'] : 'MODx';
//-- setup initial vars
$table = $modx->getFullTableName('site_content');
$temptable = $modx->getFullTableName('site_templates');
$output = '';
$error = '';
if (!isset ($_POST['opcode'])) {
//-- get templates - for use in Datagrid
$templates = $modx->db->select('id,templatename,description', $temptable);
//-- compile output
$output .= '
<html>
<head>
<link rel="stylesheet" type="text/css" href="media/style/' . $theme . '/style.css" />
<link rel="stylesheet" type="text/css" href="media/style/' . $theme . '/coolButtons2.css" />
<style type="text/css">
.topdiv {border:0;}
.subdiv {border:0;}
.tplbutton {text-align:right;}
ul, li {list-style:none;}
</style>
<script type="text/javascript" language="JavaScript" src="media/script/cb2.js"></script>
<!-- tree functions from www.dustindiaz.com -->
<script type="text/javascript">
function getElementsByClass(searchClass,node,tag) {
var classElements=\'\';
if ( node == null )
node = document;
if ( tag == null )
tag = \'*\';
var els = node.getElementsByTagName(tag);
var elsLen = els.length;
var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
for (i = 0; i < elsLen; i++) {
if ( pattern.test(els[i].className) && els[i].checked==true) {
classElements += \'id="\'+els[i].value+\'" OR \';
}
}
return classElements;
}
function getSelectedRadio(buttonGroup) {
// returns the array number of the selected radio button or -1 if no button is selected
if (buttonGroup[0]) { // if the button group is an array (one button is not an array)
for (var i=0; i<buttonGroup.length; i++) {
if (buttonGroup[i].checked) {
return i
}
}
} else {
if (buttonGroup.checked) { return 0; } // if the one button is checked, return zero
}
// if we get to this point, no radio button is selected
return -1;
} // Ends the "getSelectedRadio" function
function getSelectedRadioValue(buttonGroup) {
// returns the value of the selected radio button or "" if no button is selected
var i = getSelectedRadio(buttonGroup);
if (i == -1) {
return "";
} else {
if (buttonGroup[i]) { // Make sure the button group is an array (not just one button)
return buttonGroup[i].value;
} else { // The button group is just the one button, and it is checked
return buttonGroup.value;
}
}
} // Ends the "getSelectedRadioValue" function
function postForm(opcode,pids) {
if (opcode==\'tree\') {
document.module.opcode.value=opcode;
document.module.template.value=getSelectedRadioValue(document.template.id);
document.module.pids.value=getElementsByClass(\'pids\',document.subdiv,\'input\');
document.module.submit();
} else {
document.range.template.value=getSelectedRadioValue(document.template.id);
document.range.submit();
}
}
function switchMenu(obj) {
var el = document.getElementById(obj);
if ( el.style.display != \'none\' ) {
el.style.display = \'none\';
}
else {
el.style.display = \'\';
}
}
</script>
</head>
<body>
<div class="subTitle">
<span class="right"><img src="media/images/_tx_.gif" width="1" height="5"><br />Document Template Changer </span>
<table cellpadding="0" cellspacing="0"><tr><td class="coolButton" id="Button4" onclick="document.location.href=\'index.php?a=106\';"><img src="media/images/icons/cancel.gif" align="absmiddle"> Cancel</td></tr></table>
</div>
<div class="sectionHeader"><img src=\'media/images/misc/dot.gif\' alt="." /> Select the New Template</div>
<div class="sectionBody">
<form name="template">';
//-- render list of templates
include_once "../manager/includes/controls/datagrid.class.php";
$grd = new DataGrid('', $templates); // set page size to 0 to show all items
$grd->noRecordMsg = "No Templates Found";
$grd->cssClass = "grid";
$grd->columnHeaderClass = "gridHeader";
$grd->itemClass = "gridItem";
$grd->altItemClass = "gridAltItem";
$grd->columns = " ,ID, Name, Description";
$grd->colTypes = "template:<input type='radio' name='id' value='[+id+]' /> [+value+]";
$grd->colWidths = "5%,5%,40%,50%";
$grd->fields = "template,id,templatename,description";
$output .= $grd->render();
$output .= "<br />
<table class='grid' cellpadding='1' cellspacing='1'><tr><td class='gridItem' style=\"width:5%;\"><input type='radio' name='id' value='0' /></td><td class='gridItem' style=\"width:5%;\">0</td><td style=\"width:40%;\" class='gridItem'>Blank Template</td><td style=\"width:50%;\"></td></tr></table>
";
$output .= '</form></div>';
if (isset ($_POST['tswitch'])) {
$output .= '
<div class="sectionHeader"><img src=\'media/images/misc/dot.gif\' alt="." /> Select from the Document Tree:</div>
<div class="sectionBody">
<form name="module" method="post">
<input type="hidden" name="opcode" value="tree" />
<input type="hidden" name="pids" />
<input type="hidden" name="template" />
<input type="submit" name="submit" onclick="postForm(\'tree\');" value="Submit" />
';
$output .= getDocTree();
$output .= '
</form>
<form name="switch" method="post">
<input type="submit" style="float:right" name="rswitch" value="Switch back to setting a Document ID Range" />
</form>
<div style="clear:both;"></div>
</div>';
} else {
$output .= '
<div class="sectionHeader"><img src=\'media/images/misc/dot.gif\' alt="." /> Specify a Range of Document IDs:</div>
<div class="sectionBody">
<form name="range" method="post">
<input type="hidden" name="opcode" value="range" />
<input type="hidden" name="template" />
<input name="pids" type="text" size="100%" />
<input type="submit" name="submit" onclick="postForm(\'range\');" value="Submit" />
</form>
<p><strong>Key (where n is a document ID number):</strong><br /><br />n* - Change template for this document and immediate children<br />
n** - Change template for this document and ALL children<br />
n-n2 - Change template for this range of documents<br />
n - Change template for a single document</p>
<p>Example: 1*,4**,2-20,25 - This will change the selected template for documents 1 and its children, document 4 and all children, documents 2 through 20 and document 25.</p>
<form name="switch" method="post">
<input type="submit" style="float:right" name="tswitch" value="View and select documents using the Document Tree" />
</form>
<div style="clear:both;"></div>
</div>';
}
$output .= '
</body>
</html>
';
return $output;
// opcode is tree, run the tree data handler
}
elseif ($_POST['opcode'] == 'tree') {
$values = $_POST['pids'];
if ($_POST['pids'] <> '' && $_POST['template'] <> '') {
//-- run UPDATE query
$values = rtrim($values, ' OR ');
$fields = array (
'template' => intval($_POST['template']
));
$modx->db->update($fields, $table, $values);
} else {
$error .= 'No document or template selection was made. <br />';
}
$output .= '
<html><head>
<link rel="stylesheet" type="text/css" href="media/style/' . $theme . '/style.css" />
<link rel="stylesheet" type="text/css" href="media/style/' . $theme . '/coolButtons2.css" />
<style type="text/css">
.topdiv {border:0;}
.subdiv {border:0;}
ul, li {list-style:none;}
</style>
<script type="text/javascript" language="JavaScript" src="media/script/cb2.js"></script>
</head><body>
<div class="subTitle">
<span class="right"><img src="media/images/_tx_.gif" width="1" height="5"><br />Document Template Changer </span>
<table cellpadding="0" cellspacing="0"><tr><td class="coolButton" id="Button4" onclick="document.location.href=\'index.php?a=106\';"><img src="media/images/icons/cancel.gif" align="absmiddle"> Cancel</td></tr></table>
</div>
<div class="sectionHeader"><img src=\'media/images/misc/dot.gif\' alt="." /> Update Completed</div>
<div class="sectionBody">
';
if ($error == '') {
$output .= '<p>Update was completed successfully, with no errors.';
} else {
$output .= '<p>Update has completed but encountered errors:<br />';
$output .= $error;
}
$output .= '
</p>
<p>Use the Back button if you need make more changes. If you have finished all the template updates, please use the Refresh Site button to clear the document cache files.</p>
<form name="back" method="post"><input type="submit" name="back" value="Back" /></form><input type="submit" name="refresh" onclick="document.location.href=\'index.php?a=26\';" value="Refresh Site" />
</div></body></html>';
return $output;
}
//-- values have been passed via the range text field
elseif ($_POST['opcode'] == 'range') {
//-- set initial vars
$values = array ();
$pids = '';
$error = '';
//-- check for empty field
if (trim($_POST['pids']) <> '') {
$values = explode(',', $_POST['pids']);
} else {
$error .= 'No Values have been specified.';
}
//-- parse values, and check for invalid entries
foreach ($values as $key => $value) {
//-- value is a range
if (preg_match('/^[\d]+\-[\d]+$/', trim($value))) {
//-- explode the lower and upper limits
$match = explode('-', $value);
//-- Upper limit lower than lower limit
if (($match[1] - $match[0]) < 0) {
$error = 'Upper limit less than lower limit:' . $value . '<br />';
}
//-- loop through values and parse WHERE SQL statement
$loop = $match[1] - $match[0];
for ($i = 0; $i <= $loop; $i++) {
$pids .= 'id=\'' . ($i + $match[0]) . '\' OR ';
}
}
//-- value is a group for immediate children
elseif (preg_match('/^[\d]+\*$/', trim($value), $match)) {
//-- get ID number of folder
$match = rtrim($match[0], '*');
//-- get ALL children
$group = $modx->db->select('id', $table, 'parent=' . $match, '', '');
//-- parse WHERE SQL statement
$pids .= 'id=\'' . $match . '\' OR ';
while ($row = $modx->db->getRow($group)) {
$pids .= 'id=\'' . $row['id'] . '\' OR ';
}
}
//-- value is a group for ALL children
elseif (preg_match('/^[\d]+\*\*$/', trim($value), $match)) {
//-- get ID number of folder
$match = rtrim($match[0], '**');
$idarray[]=$match;
//-- recurse and get ALL children
for ($i = 0; $i < count($idarray); $i++) {
$where = 'parent=' . $idarray[$i];
$rs = $modx->db->select("id", $table, $where);
if ($modx->db->getRecordCount($rs) > 0) {
while ($row = $modx->db->getRow($rs)) {
$idarray[] = $row['id'];
}
}
}
//-- parse array into string
for ($i = 0; $i < count($idarray); $i++) {
$pids .= 'id=\'' . $idarray[$i] . '\' OR ';
}
}
//-- value is a single document
elseif (preg_match('/^[\d]+$/', trim($value))) {
//-- parse WHERE SQL statement
$pids .= 'id=\'' . trim($value) . '\' OR ';
//-- value is invalid
} else {
$error .= 'Invalid Value:' . $value . '<br />';
}
} //foreach end
if ($_POST['pids'] <> '' && $_POST['template'] <> '') {
//-- run UPDATE query
$values = rtrim($pids, ' OR ');
$fields = array (
'template' => intval($_POST['template']
));
$modx->db->update($fields, $table, $values);
} else {
$error .= 'No document or template selection was made. <br />';
}
$output .= '
<html><head>
<link rel="stylesheet" type="text/css" href="media/style/' . $theme . '/style.css" />
<link rel="stylesheet" type="text/css" href="media/style/' . $theme . '/coolButtons2.css" />
<style type="text/css">
.topdiv {border:0;}
.subdiv {border:0;}
ul, li {list-style:none;}
</style>
<script type="text/javascript" language="JavaScript" src="media/script/cb2.js"></script>
</head><body>
<div class="subTitle">
<span class="right"><img src="media/images/_tx_.gif" width="1" height="5"><br />Document Template Changer </span>
<table cellpadding="0" cellspacing="0"><tr><td class="coolButton" id="Button4" onclick="document.location.href=\'index.php?a=106\';"><img src="media/images/icons/cancel.gif" align="absmiddle"> Cancel</td></tr></table>
</div>
<div class="sectionHeader"><img src=\'media/images/misc/dot.gif\' alt="." /> Update Completed</div>
<div class="sectionBody">
';
if ($error == '') {
$output .= '<p>Update was completed successfully, with no errors.';
} else {
$output .= '<p>Update has completed but encountered errors:<br />';
$output .= $error;
}
$output .= '
</p>
<p>Use the Back button if you need make more changes. If you have finished all the template updates, please use the Refresh Site button to clear the document cache files.</p>
<form name="back" method="post"><input type="submit" name="back" value="Back" /></form><input type="submit" name="refresh" onclick="document.location.href=\'index.php?a=26\';" value="Refresh Site" />
</div></body></html>';
return $output;
}
function getDocTree() {
global $modx;
global $table;
$subdiv = true;
// $siteMapRoot [int]
$siteMapRoot = 0;
// $removeNewLines [ true | false ]
$removeNewLines = (!isset ($removeNewLines)) ? false : ($removeNewLines == true);
// $maxLevels [ int ]
$maxLevels = 0;
// $textOfLinks [ string ]
$textOfLinks = (!isset ($textOfLinks)) ? 'menutitle' : "$textOfLinks";
// $titleOfLinks [ string ]
$titleOfLinks = (!isset ($titleOfLinks)) ? 'description' : "$titleOfLinks";
// $pre [ string ]
$pre = (!isset ($pre)) ? '' : "$pre";
// $post [ string ]
$post = (!isset ($post)) ? '' : "$post";
// $selfAsLink [ true | false ]
$selfAsLink = (!isset ($selfAsLink)) ? false : ($selfAsLink == true);
// $hereClass [ string ]
$hereClass = (!isset ($hereClass)) ? 'here' : $hereClass;
// $topdiv [ true | false ]
// Indicates if the top level UL is wrapped by a containing DIV block
$topdiv = (!isset ($topdiv)) ? false : ($topdiv == true);
// $topdivClass [ string ]
$topdivClass = (!isset ($topdivClass)) ? 'topdiv' : "$topdivClass";
// $topnavClass [ string ]
$topnavClass = (!isset ($topnavClass)) ? 'topnav' : "$topnavClass";
// $useCategoryFolders [ true | false ]
// If you want folders without any content to render without a link to be used
// as "category" pages (defaults to true). In order to use Category Folders,
// the template must be set to (blank) or it won't work properly.
$useCategoryFolders = (!isset ($useCategoryFolders)) ? true : "$useCategoryFolders";
// $categoryClass [ string ]
// CSS Class for folders with no content (e.g., category folders)
$categoryClass = (!isset ($categoryClass)) ? 'category' : "$categoryClass";
// $subdiv [ true | false ]
$subdiv = (!isset ($subdiv)) ? false : ($subdiv == true);
// $subdivClass [ string ]
$subdivClass = (!isset ($subdivClass)) ? 'subdiv' : "$subdivClass";
// $orderBy [ string ]
$orderBy = (!isset ($orderBy)) ? 'menuindex' : "$orderBy";
// $orderDesc [true | false]
$orderDesc = (!isset ($orderDesc)) ? false : ($orderDesc == true);
// ###########################################
// End config, the rest takes care of itself #
// ###########################################
$debugMode = false;
// Initialize
$MakeMap = "";
$siteMapRoot = (isset ($startDoc)) ? $startDoc : $siteMapRoot;
$maxLevels = (isset ($levelLimit)) ? $levelLimit : $maxLevels;
$ie = ($removeNewLines) ? '' : "\n";
//Added by Remon: (undefined variables php notice)
$activeLinkIDs = array ();
$subnavClass = '';
//display expand/collapse exclusion for top level
$startRoot = $siteMapRoot;
// Overcome single use limitation on functions
global $MakeMap_Defined;
if (!isset ($MakeMap_Defined)) {
function filterHidden($var) {
return (!$var['hidemenu'] == 1);
}
function filterEmpty($var) {
return (!empty ($var));
}
function MakeMap($modx, $listParent, $listLevel, $description, $titleOfLinks, $maxLevels, $inside, $pre, $post, $selfAsLink, $ie, $activeLinkIDs, $topdiv, $topdivClass, $topnavClass, $subdiv, $subdivClass, $subnavClass, $hereClass, $useCategoryFolders, $categoryClass, $showDescription, $descriptionField, $textOfLinks, $orderBy, $orderDesc, $debugMode) {
//-- get ALL children
$table = $modx->getFullTableName('site_content');
$csql = $modx->db->select('*', $table, 'parent="' . $listParent . '"');
$children = array ();
for ($i = 0; $i < @ $modx->db->getRecordCount($csql); $i++) {
array_push($children, @ $modx->db->getRow($csql));
}
$numChildren = count($children);
if (is_array($children) && !empty ($children)) {
// determine if it's a top category or not
$toplevel = !$inside;
// build the output
$topdivcls = (!empty ($topdivClass)) ? ' class="' . $topdivClass . '"' : '';
$topdivblk = ($topdiv) ? "<div$topdivcls id=\"$listParent\">" : '';
$topnavcls = (!empty ($topnavClass)) ? ' class="' . $topnavClass . '"' : '';
$subdivcls = (!empty ($subdivClass)) ? ' class="' . $subdivClass . '"' : '';
$subdivblk = ($subdiv) ? "<div$subdivcls id=\"$listParent\">$ie" : '';
$subnavcls = (!empty ($subnavClass)) ? ' class="' . $subnavClass . '"' : '';
//-- output the div and add the expand/collapse if required
$output .= ($toplevel) ? "$topdivblk<ul$topnavcls>$ie" : "$ie" . (($listParent != $startRoot) ? '' : '') . "$subdivblk<ul$subnavcls>$ie";
//loop through and process subchildren
foreach ($children as $child) {
// get highlight colour
if ($child['deleted'] == 1) {
$color = '#000'; //black
}
elseif ($child['hidemenu'] == 1) {
$color = '#ff9933'; //orange
}
elseif ($child['published'] == 0) {
$color = '#ff6600'; //red
} else {
$color = '#339900'; //green
}
// figure out if it's a containing category folder or not
$numChildren--;
$isFolder = $child['isfolder'];
$itsEmpty = ($isFolder && ($child['template'] == '0'));
$itm = "";
// if menutitle is blank fall back to pagetitle for menu link
$textOfLinks = (empty ($child['menutitle'])) ? 'pagetitle' : "$textOfLinks";
// If at the top level
if (!$inside) {
$itm .= ((!$selfAsLink && ($child['id'] == $modx->documentIdentifier)) || ($itsEmpty && $useCategoryFolders)) ? $pre .
$child[$textOfLinks] . $post . (($debugMode) ? ' self|cat' : '') : $pre .
$child[$textOfLinks] . $post;
$itm .= ($debugMode) ? ' top' : '';
}
// it's a folder and it's below the top level
elseif ($isFolder && $inside) {
$itm .= "<img src='media/images/tree/folder.gif' alt='Folder' onclick=\"switchMenu(" .
$child['id'] . ")\" /><input type=\"checkbox\" class=\"pids\" id=\"check" . $child['id'] . "\" name=\"check\" value=\"" . $child['id'] . "\" />" . $pre . '<span style="color:' . $color . ';">' . $child[$textOfLinks] . ' ('.$child['template'].')</span>' . $post . (($debugMode) ? ' subfolder F' : '');
}
// it's a document inside a folder
else {
$itm .= ($child['alias'] > '0' && !$selfAsLink && ($child['id'] == $modx->documentIdentifier)) ? $child[$textOfLinks] : "<img src='media/images/tree/page-blank.gif' alt='Page' /><input type=\"checkbox\" class=\"pids\" id=\"check" . $child['id'] . "\" name=\"check\" value=\"" . $child['id'] . "\" />" . '<span style="color:' . $color . ';">' . $child[$textOfLinks] . ' ('.$child['template'].')</span>';
$itm .= ($debugMode) ? ' doc' : '';
}
$itm .= ($debugMode) ? "$useCategoryFolders $isFolder $itsEmpty" : '';
// loop back through if the doc is a folder and has not reached the max levels
if ($isFolder && (($maxLevels == 0) || ($maxLevels > $listLevel +1))) {
$itm .= MakeMap($modx, $child['id'], $listLevel +1, $description, $titleOfLinks, $maxLevels, true, $pre, $post, $selfAsLink, $ie, $activeLinkIDs, $topdiv, $topdivClass, $topnavClass, $subdiv, $subdivClass, $subnavClass, $hereClass, $useCategoryFolders, $categoryClass, false, '', $textOfLinks, $orderBy, $orderDesc, $debugMode);
}
if ($itm) {
$output .= "<li$class><label for=\"" . $child['id'] . "\">$itm</label></li>$ie";
$class = '';
}
}
$output .= "</ul>$ie";
$output .= ($toplevel) ? (($topdiv) ? "</div>$ie" : "") : (($subdiv) ? "</div>$ie" : "");
}
return $output;
}
$MakeMap_Defined = true;
}
// return the output
return MakeMap($modx, $siteMapRoot, 0, false, $titleOfLinks, $maxLevels, true, $pre, $post, $selfAsLink, $ie, $activeLinkIDs, $topdiv, $topdivClass, $topnavClass, $subdiv, $subdivClass, $subnavClass, $hereClass, $useCategoryFolders, $categoryClass, false, '', $textOfLinks, $orderBy, $orderDesc, $debugMode);
}
ручная работа: указать id’ишники, для кого надо скопом поменять темплейт. да и пройдись в репозиторий. да много прикольных вещичек. на одном из сайтов, ща нет времени ковыряться, стоит плагин, который автоматом для детей устанавливает родительский темплейт. ну, и способ для знающих: через запрос к мускулу, надо будет указать ручками набор id’ишников.