1
0
mirror of https://github.com/phpbb/phpbb.git synced 2025-06-04 13:35:13 +02:00

Theme editor replaced with something more basic, it was not robust and was more error prone

git-svn-id: file:///svn/phpbb/trunk@7562 89ea8834-ac86-4346-8a33-228a782c2dd0
This commit is contained in:
David M 2007-05-13 20:35:34 +00:00
parent 36cb62292f
commit 66d5070564
4 changed files with 194 additions and 585 deletions

View File

@ -141,249 +141,90 @@
//-->
</script>
<!-- IF S_EDIT_TEMPLATE -->
<a href="{U_BACK}" style="float: right">&laquo; {L_BACK}</a>
<a href="{U_BACK}" style="float: right">&laquo; {L_BACK}</a>
<h1>{L_EDIT}</h1>
<h1>{L_EDIT_TEMPLATE}</h1>
<p>{L_EDIT_EXPLAIN}</p>
<p>{L_EDIT_TEMPLATE_EXPLAIN}</p>
<p>{L_SELECTED}: <strong>{SELECTED_TEMPLATE}</strong></p>
<p>{L_SELECTED_TEMPLATE}: <strong>{SELECTED_TEMPLATE}</strong></p>
<form id="acp_styles" method="post" action="{U_ACTION}">
<form id="acp_styles" method="post" action="{U_ACTION}">
<!-- IF S_EDIT_TEMPLATE or (S_EDIT_THEME and not S_THEME_IN_DB) -->
<fieldset>
<legend>{L_SELECT}</legend>
<dl>
<dt><label for="template_file">{L_FILE}:</label></dt>
<dd><select id="template_file" name="template_file" onchange="if (this.options[this.selectedIndex].value != '') this.form.submit();">{S_TEMPLATES}</select> <input class="button2" type="submit" value="{L_SELECT}" /></dd>
</dl>
</fieldset>
<!-- ENDIF -->
<fieldset>
<legend>{L_SELECT_TEMPLATE}</legend>
<dl>
<dt><label for="template_file">{L_TEMPLATE_FILE}:</label></dt>
<dd><select id="template_file" name="template_file" onchange="if (this.options[this.selectedIndex].value != '') this.form.submit();">{S_TEMPLATES}</select> <input class="button2" type="submit" value="{L_SELECT}" /></dd>
</dl>
</fieldset>
</form>
</form>
<!-- IF TEMPLATE_FILE -->
<script type="text/javascript" defer="defer">
<!--
function change_editor_height(height)
{
editor = document.getElementById('template_data');
editor.rows = Math.max(5, Math.min(height, 999));
append_text_rows('acp_styles', height);
append_text_rows('acp_template', height);
}
function append_text_rows(form_name, value)
{
url = document.getElementById(form_name).action;
var_start = url.indexOf('&text_rows=');
if (var_start == -1)
{
document.getElementById(form_name).action = url + "&text_rows=" + value;
}
else
{
url_start = url.substring(0, var_start + 1);
var_end = url.substring(var_start + 1).indexOf('&');
if (var_end == -1)
{
document.getElementById(form_name).action = url_start + "text_rows=" + value;
}
else
{
document.getElementById(form_name).action = url_start + url.substring(var_end + var_start + 2) + "&text_rows=" + value;
}
}
}
//-->
</script>
<form id="acp_template" method="post" action="{U_ACTION}">
<fieldset>
<legend>{L_TEMPLATE_EDITOR}</legend>
<dl>
<dt><label>{L_SELECTED_TEMPLATE_FILE}:</label></dt>
<dd>{TEMPLATE_FILE}</dd>
</dl>
<dl>
<dt><label for="text_rows">{L_TEMPLATE_EDITOR_HEIGHT}:</label></dt>
<dd><input id="text_rows" type="text" maxlength="3" value="{TEXT_ROWS}" /> <input class="button2" type="button" name="update" onclick="change_editor_height(this.form.text_rows.value);" value="{L_UPDATE}" /></dd>
</dl>
<textarea id="template_data" name="template_data" style="font-family:'Courier New', monospace;font-size:9pt;line-height:125%;width:100%;" cols="80" rows="{TEXT_ROWS}">{TEMPLATE_DATA}</textarea>
</fieldset>
<fieldset class="submit-buttons">
<legend>{L_SUBMIT}</legend>
{S_HIDDEN_FIELDS}
<input class="button1" id="save" type="submit" name="save" value="{L_SUBMIT}" />
</fieldset>
</form>
<!-- ENDIF -->
<!-- ELSEIF S_EDIT_THEME -->
<script type="text/javascript">
<!-- IF TEMPLATE_FILE or (S_EDIT_THEME and S_THEME_IN_DB) -->
<script type="text/javascript" defer="defer">
<!--
function change_editor_height(height)
{
editor = document.getElementById('css_data');
editor = document.getElementById('template_data');
editor.rows = Math.max(5, Math.min(height, 999));
append_text_rows('acp_styles', height);
append_text_rows('acp_theme', height);
append_text_rows('acp_custom_class', height);
append_text_rows('acp_template', height);
}
function append_text_rows(form_name, value)
{
url = document.getElementById(form_name).action;
var_start = url.indexOf('&text_rows=');
if (var_start == -1)
{
document.getElementById(form_name).action = url + "&text_rows=" + value;
}
else
{
url_start = url.substring(0, var_start + 1);
var_end = url.substring(var_start + 1).indexOf('&');
if (var_end == -1)
{
document.getElementById(form_name).action = url_start + "text_rows=" + value;
}
else
{
document.getElementById(form_name).action = url_start + url.substring(var_end + var_start + 2) + "&text_rows=" + value;
}
}
}
//-->
</script>
<a href="{U_BACK}" style="float: right">&laquo; {L_BACK}</a>
<h1>{L_EDIT_THEME}</h1>
<p>{L_EDIT_THEME_EXPLAIN}</p>
<p>{L_SELECTED_THEME}: <strong>{SELECTED_THEME}</strong></p>
<!-- IF S_SHOWCSS -->
<h3>{L_SHOW_CSS_NOTE}</h3>
<p>{L_SHOW_CSS_EXPLAIN}</p>
<!-- ENDIF -->
<form id="acp_styles" method="post" action="{U_ACTION}">
<form id="acp_template" method="post" action="{U_ACTION}">
<fieldset>
<legend>{L_SELECT_CLASS}</legend>
<legend>{L_EDITOR}</legend>
<!-- IF S_EDIT_TEMPLATE or (S_EDIT_THEME and not S_THEME_IN_DB) -->
<dl>
<dt><label for="css_class">{L_SELECT_CLASS}:</label></dt>
<dd><select id="css_class" name="css_class" onchange="if (this.options[this.selectedIndex].value != '') this.form.submit();">{S_CLASSES}</select></dd>
<dd><input class="button1" type="submit" id="select_class" name="select_class" value="{L_SELECT}" /></dd>
<dt><label>{L_SELECTED_FILE}:</label></dt>
<dd>{TEMPLATE_FILE}</dd>
</dl>
<!-- IF S_CLASS -->
<dl>
<dt><label>{L_SELECTED_CLASS}:</label></dt>
<dd>{S_CLASS}</dd>
</dl>
<!-- ENDIF -->
<dl>
<dt><label for="text_rows">{L_EDITOR_HEIGHT}:</label></dt>
<dd><input id="text_rows" type="text" maxlength="3" value="{TEXT_ROWS}" /> <input class="button2" type="button" name="update" onclick="change_editor_height(this.form.text_rows.value);" value="{L_UPDATE}" /></dd>
</dl>
<textarea id="template_data" name="template_data" style="font-family:'Courier New', monospace;font-size:9pt;line-height:125%;width:100%;" cols="80" rows="{TEXT_ROWS}">{TEMPLATE_DATA}</textarea>
</fieldset>
</form>
<!-- IF S_CLASS -->
<form id="acp_theme" method="post" action="{U_ACTION}">
<!-- IF S_SHOWCSS -->
<fieldset>
<legend>{L_THEME_EDITOR}</legend>
<dl>
<dt><label for="text_rows">{L_THEME_EDITOR_HEIGHT}:</label></dt>
<dd><input id="text_rows" type="text" maxlength="3" value="{TEXT_ROWS}" /> <input class="button1" type="button" name="update" onclick="change_editor_height(this.form.text_rows.value);" value="{L_UPDATE}" /></dd>
</dl>
<textarea id="css_data" name="css_data" style="font-family:'Courier New', monospace;font-size:9pt;line-height:125%;width:100%;" cols="80" rows="{TEXT_ROWS}">{CSS_DATA}</textarea>
</fieldset>
<!-- ELSE -->
<fieldset>
<legend>{L_BACKGROUND}</legend>
<dl>
<dt><label for="background_color">{L_BACKGROUND_COLOUR}:</label><br /><span>{L_CSS_COLOUR_EXPLAIN}</span></dt>
<dd><input id="background_color" name="background_color" type="text" value="{BACKGROUND_COLOR}" size="6" />&nbsp;&nbsp;<span>[ <a href="#" onclick="swatch('background_color'); return false">{L_COLOUR_SWATCH}</a> ]</span></dd>
</dl>
<dl>
<dt><label for="backround_image">{L_BACKGROUND_IMAGE}:</label></dt>
<dd><select id="background_image" name="background_image">{S_BACKGROUND_IMAGE}</select></dd>
</dl>
<dl>
<dt><label for="background_repeat">{L_BACKGROUND_REPEAT}:</label></dt>
<dd><select id="background_repeat" name="background_repeat">{S_BACKGROUND_REPEAT}</select></dd>
</dl>
</fieldset>
<fieldset>
<legend>{L_FOREGROUND}</legend>
<dl>
<dt><label for="color">{L_FONT_COLOUR}:</label><br /><span>{L_CSS_COLOUR_EXPLAIN}</span></dt>
<dd><input id="color" name="color" type="text" value="{COLOR}" size="6" />&nbsp;&nbsp;<span>[ <a href="#" onclick="swatch('color'); return false">{L_COLOUR_SWATCH}</a> ]</span></dd>
</dl>
<dl>
<dt><label for="font_family">{L_FONT_FACE}:</label><br /><span>{L_FONT_FACE_EXPLAIN}</span></dt>
<dd><input id="font_family" name="font_family" type="text" value="{FONT_FAMILY}" size="40" maxlength="255" /></dd>
</dl>
<dl>
<dt><label for="font_size">{L_FONT_SIZE}:</label></dt>
<dd><input id="font_size" name="font_size" type="text" value="{FONT_SIZE}" size="5" maxlength="5" /> <select id="font_size_unit" name="font_size_unit">{S_FONT_SIZE_UNITS}</select></dd>
</dl>
<dl>
<dt><label for="font_weight">{L_BOLD}:</label></dt>
<dd><label><input id="font_weight" type="radio" class="radio" name="font_weight" value="bold"<!-- IF FONT_WEIGHT eq "bold" --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label><input type="radio" class="radio" name="font_weight" value="none"<!-- IF FONT_WEIGHT eq "none" --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
<label><input type="radio" class="radio" name="font_weight" value=""<!-- IF not FONT_WEIGHT --> checked="checked"<!-- ENDIF --> /> {L_UNSET}</label></dd>
</dl>
<dl>
<dt><label for="font_style">{L_ITALIC}:</label></dt>
<dd><label><input id="font_style" type="radio" class="radio" name="font_style" value="italic"<!-- IF FONT_STYLE eq "italic" --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label><input type="radio" class="radio" name="font_style" value="none"<!-- IF FONT_STYLE eq "none" --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
<label><input type="radio" class="radio" name="font_style" value=""<!-- IF not FONT_STYLE --> checked="checked"<!-- ENDIF --> /> {L_UNSET}</label></dd>
</dl>
<dl>
<dt><label for="text_decoration">{L_UNDERLINE}:</label></dt>
<dd><label><input id="text_decoration" type="radio" class="radio" name="text_decoration" value="underline"<!-- IF TEXT_DECORATION eq "underline" --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label><input type="radio" class="radio" name="text_decoration" value="none"<!-- IF TEXT_DECORATION eq "none" --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
<label><input type="radio" class="radio" name="text_decoration" value=""<!-- IF not TEXT_DECORATION --> checked="checked"<!-- ENDIF --> /> {L_UNSET}</label></dd>
</dl>
<dl>
<dt><label for="line_height">{L_LINE_SPACING}</label></dt>
<dd><input id="line_height" name="line_height" type="text" value="{LINE_HEIGHT}" size="3" maxlength="3" /> <select id="line_height_unit" name="line_height_unit">{S_LINE_HEIGHT_UNITS}</select></dd>
</dl>
</fieldset>
<!-- ENDIF -->
<fieldset class="submit-buttons">
<legend>{L_SUBMIT}</legend>
{S_HIDDEN_FIELDS}
<input class="button1" type="submit" id="submit" name="submit" value="{L_SUBMIT}" />&nbsp;
<!-- IF S_SHOWCSS -->
<input class="button2" type="submit" id="hidecss" name="hidecss" value="{L_HIDE_CSS}" />&nbsp;
<!-- ELSE -->
<input class="button2" type="submit" id="showcss" name="showcss" value="{L_SHOW_CSS}" />&nbsp;
<!-- ENDIF -->
<input class="button2" type="reset" id="reset" name="reset" value="{L_RESET}" />
</fieldset>
</form>
<!-- ENDIF -->
<br />
<h1>{L_CUSTOM_CLASS}</h1>
<p>{L_CUSTOM_CLASS_EXPLAIN}</p>
<form id="acp_custom_class" method="post" action="{U_ACTION}">
<fieldset>
<legend>{L_CUSTOM_CLASS}</legend>
<dl>
<dt><label for="custom_class">{L_CSS_CLASS_NAME}:</label></dt>
<dd><input id="custom_class" name="custom_class" type="text" value="" maxlength="200" size="40" /></dd>
</dl>
<p class="quick">
<input class="button1" type="submit" id="add_custom" name="add_custom" value="{L_SUBMIT}" />
</p>
<fieldset class="submit-buttons">
<legend>{L_SUBMIT}</legend>
{S_HIDDEN_FIELDS}
<input class="button1" id="save" type="submit" name="save" value="{L_SUBMIT}" />
</fieldset>
</form>
<!-- ENDIF -->
<!-- ELSEIF S_CACHE -->

View File

@ -820,7 +820,7 @@ parse_css_file = {PARSE_CSS_FILE}
// we don't need any single element categories so put them into the misc '' category
for ($i = 0, $n = sizeof($cats); $i < $n; $i++)
{
if (sizeof($filelist_cats[$cats[$i]]) == 1)
if (sizeof($filelist_cats[$cats[$i]]) == 1 && $cats[$i] !== '')
{
$filelist_cats[''][key($filelist_cats[$cats[$i]])] = current($filelist_cats[$cats[$i]]);
unset($filelist_cats[$cats[$i]]);
@ -858,6 +858,15 @@ parse_css_file = {PARSE_CSS_FILE}
'U_ACTION' => $this->u_action . "&amp;action=edit&amp;id=$template_id&amp;text_rows=$text_rows",
'U_BACK' => $this->u_action,
'L_EDIT' => $user->lang['EDIT_TEMPLATE'],
'L_EDIT_EXPLAIN' => $user->lang['EDIT_TEMPLATE_EXPLAIN'],
'L_EDITOR' => $user->lang['TEMPLATE_EDITOR'],
'L_EDITOR_HEIGHT' => $user->lang['TEMPLATE_EDITOR_HEIGHT'],
'L_FILE' => $user->lang['TEMPLATE_FILE'],
'L_SELECT' => $user->lang['SELECT_TEMPLATE'],
'L_SELECTED' => $user->lang['SELECTED_TEMPLATE'],
'L_SELECTED_FILE' => $user->lang['SELECTED_TEMPLATE_FILE'],
'SELECTED_TEMPLATE' => $template_info['template_name'],
'TEMPLATE_FILE' => $template_file,
'TEMPLATE_DATA' => htmlspecialchars($template_data),
@ -998,27 +1007,23 @@ parse_css_file = {PARSE_CSS_FILE}
*/
function edit_theme($theme_id)
{
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $config, $db, $cache, $user, $template, $safe_mode;
global $phpbb_root_path, $phpEx, $config, $db, $cache, $user, $template, $safe_mode;
$this->page_title = 'EDIT_THEME';
$filelist = $filelist_cats = array();
// we want newlines no carriage returns!
$_POST['css_data'] = (isset($_POST['css_data']) && !empty($_POST['css_data'])) ? str_replace(array("\r\n", "\r"), array("\n", "\n"), $_POST['css_data']) : '';
$_POST['template_data'] = (isset($_POST['template_data']) && !empty($_POST['template_data'])) ? str_replace(array("\r\n", "\r"), array("\n", "\n"), $_POST['template_data']) : '';
// get user input
$theme_data = (STRIP) ? stripslashes($_POST['template_data']) : $_POST['template_data'];
$theme_file = request_var('template_file', '');
$text_rows = max(5, min(999, request_var('text_rows', 20)));
$hide_css = request_var('hidecss', false);
$show_css = !$hide_css && request_var('showcss', false);
$edit_class = request_var('css_class', '');
$custom_class = request_var('custom_class', '');
$css_data = (STRIP) ? stripslashes($_POST['css_data']) : $_POST['css_data'];
$submit = isset($_POST['submit']) ? true : false;
$add_custom = isset($_POST['add_custom']) ? true : false;
$matches = array();
// no curly brackets inside a CSS block please
$css_data = str_replace(array('{', '}'), '', $css_data);
$save_changes = (isset($_POST['save'])) ? true : false;
// make sure theme_file path doesn't go upwards
$theme_file = str_replace('..', '.', $theme_file);
// Retrieve some information about the theme
$sql = 'SELECT theme_storedb, theme_path, theme_name, theme_data
FROM ' . STYLES_THEME_TABLE . "
@ -1031,342 +1036,22 @@ parse_css_file = {PARSE_CSS_FILE}
}
$db->sql_freeresult($result);
$stylesheet_path = $phpbb_root_path . 'styles/' . $theme_info['theme_path'] . '/theme/stylesheet.css';
// Get the CSS data from either database or filesystem
if (!$theme_info['theme_storedb'])
// save changes to the theme if the user submitted any
if ($save_changes)
{
if (!file_exists($stylesheet_path) || !($stylesheet = file_get_contents($stylesheet_path)))
// Get the filesystem location of the current file
$file = "{$phpbb_root_path}styles/{$theme_info['theme_path']}/theme/$theme_file";
$additional = '';
$message = $user->lang['THEME_UPDATED'];
// If the theme is stored on the filesystem try to write the file else store it in the database
if (!$safe_mode && !$theme_info['theme_storedb'] && file_exists($file) && @is_writable($file))
{
trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING);
}
}
else
{
$stylesheet = &$theme_info['theme_data'];
}
// Pull out a list of classes
$classes = array();
if (preg_match_all('/^([a-z0-9\.,:#_\->* \t]+?)[ \t\n]*?\{.*?\}/msi', $stylesheet, $matches))
{
$classes = $matches[1];
}
// Generate html for the list of classes
$s_hidden_fields = array();
$s_classes = '';
sort($classes);
foreach ($classes as $class)
{
$selected = ($class == $edit_class) ? ' selected="selected"' : '';
$s_classes .= '<option value="' . $class . '" title="' . $class . '"' . $selected . '>' . truncate_string($class, 40, false, '...') . '</option>';
}
$template->assign_vars(array(
'S_EDIT_THEME' => true,
'S_SHOWCSS' => $show_css,
'S_CLASSES' => $s_classes,
'S_CLASS' => $edit_class,
'U_ACTION' => $this->u_action . "&amp;action=edit&amp;id=$theme_id&amp;showcss=$show_css&amp;text_rows=$text_rows",
'U_BACK' => $this->u_action,
'SELECTED_THEME' => $theme_info['theme_name'],
'TEXT_ROWS' => $text_rows)
);
// only continue if we are really editing anything
if (!$edit_class && !$add_custom)
{
return;
}
// These are the elements for the simple view
$match_elements = array(
'colors' => array('background-color', 'color',),
'sizes' => array('font-size', 'line-height',),
'images' => array('background-image',),
'repeat' => array('background-repeat',),
'other' => array('font-weight', 'font-family', 'font-style', 'text-decoration',),
);
// Used in an sprintf statement to generate appropriate output for rawcss mode
$map_elements = array(
'colors' => '%s',
'sizes' => '%1.10f',
'images' => 'url(\'./%s\')',
'repeat' => '%s',
'other' => '%s',
);
$units = array('px', '%', 'em', 'pt');
$repeat_types = array(
'' => $user->lang['UNSET'],
'none' => $user->lang['REPEAT_NO'],
'repeat-x' => $user->lang['REPEAT_X'],
'repeat-y' => $user->lang['REPEAT_Y'],
'both' => $user->lang['REPEAT_ALL'],
);
// Fill css_data with the class contents from the stylesheet
// in case we just selected a class and it's not filled yet
if (!$css_data && !$submit && !isset($_POST['hidecss']) && !isset($_POST['showcss']) && !$add_custom)
{
preg_match('#^[ \t]*?' . preg_quote($edit_class, '#') . '[ \t\n]*?\{(.*?)\}#ms', $stylesheet, $matches);
if (!isset($matches[1]))
{
trigger_error($user->lang['NO_CLASS'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$css_data = implode(";\n", array_diff(array_map('trim', explode("\n", preg_replace("#;[\n]*#s", "\n", $matches[1]))), array('')));
if ($css_data)
{
$css_data .= ';';
}
}
// If we don't show raw css and the user did not submit any modification
// then generate a list of css elements and output them via the template
if (!$show_css && !$submit && !$add_custom)
{
$css_elements = array_diff(array_map('trim', explode("\n", preg_replace("#;[\n]*#s", "\n", $css_data))), array(''));
// Grab list of potential images for the "images" type
$img_filelist = filelist($phpbb_root_path . 'styles/' . $theme_info['theme_name'] . '/theme');
foreach ($match_elements as $type => $match_ary)
{
foreach ($match_ary as $match)
{
$var = str_replace('-', '_', $match);
$value = '';
$unit = '';
if (sizeof($css_elements))
{
// first read in the setting
foreach ($css_elements as $key => $element)
{
if (preg_match('#^' . preg_quote($match, '#') . ':[ \t\n]*?(.*?)$#', $element, $matches))
{
switch ($type)
{
case 'sizes':
$value = trim($matches[1]);
if (preg_match('#(.*?)(px|%|em|pt)#', $matches[1], $matches))
{
$unit = trim($matches[2]);
$value = trim($matches[1]);
}
break;
case 'images':
if (preg_match('#url\(\'(.*?)\'\)#', $matches[1], $matches))
{
$value = trim($matches[1]);
}
break;
case 'colors':
$value = trim($matches[1]);
if ($value[0] == '#')
{
$value = substr($value, 1);
}
break;
default:
$value = trim($matches[1]);
}
// Remove this element from array
unset($css_elements[$key]);
break;
}
}
}
// then display it in the template
switch ($type)
{
case 'sizes':
// generate a list of units
$s_units = '';
foreach ($units as $unit_option)
{
$selected = ($unit_option == $unit) ? ' selected="selected"' : '';
$s_units .= "<option value=\"$unit_option\"$selected>$unit_option</option>";
}
$s_units = '<option value=""' . (($unit == '') ? ' selected="selected"' : '') . '>' . $user->lang['NO_UNIT'] . '</option>' . $s_units;
$template->assign_vars(array(
strtoupper($var) => htmlspecialchars($value),
'S_' . strtoupper($var) . '_UNITS' => $s_units)
);
break;
case 'images':
// generate a list of images for this setting
$s_imglist = '';
foreach ($img_filelist as $path => $img_ary)
{
foreach ($img_ary as $img)
{
$img = htmlspecialchars(((substr($path, 0, 1) == '/') ? substr($path, 1) : $path) . $img);
$selected = (preg_match('#' . preg_quote($img) . '$#', $value)) ? ' selected="selected"' : '';
$s_imglist .= "<option value=\"$img\"$selected>$img</option>";
}
}
$s_imglist = '<option value=""' . (($value == '') ? ' selected="selected"' : '') . '>' . $user->lang['NO_IMAGE'] . '</option>' . $s_imglist;
$template->assign_vars(array(
'S_' . strtoupper($var) => $s_imglist)
);
unset($s_imglist);
break;
case 'repeat':
// generate a list of repeat options
$s_repeat_types = '';
foreach ($repeat_types as $repeat_type => $repeat_lang)
{
$selected = ($value == $repeat_type) ? ' selected="selected"' : '';
$s_repeat_types .= "<option value=\"$repeat_type\"$selected>$repeat_lang</option>";
}
$template->assign_vars(array(
'S_' . strtoupper($var) => $s_repeat_types)
);
default:
$template->assign_vars(array(
strtoupper($var) => htmlspecialchars($value))
);
}
}
}
// Any remaining elements must be custom data so we save that in a hidden field
if (sizeof($css_elements))
{
$s_hidden_fields['cssother'] = implode(' ;; ', $css_elements);
}
unset($img_filelist, $css_elements);
}
// else if we are showing raw css or the user submitted data from the simple view
// then we need to turn the given information into raw css
else if (!$css_data && !$add_custom)
{
foreach ($match_elements as $type => $match_ary)
{
foreach ($match_ary as $match)
{
$var = str_replace('-', '_', $match);
$value = '';
$unit = '';
// retrieve and validate data for this setting
switch ($type)
{
case 'sizes':
$value = request_var($var, 0.0);
$unit = request_var($var . '_unit', '');
if ((request_var($var, '') === '') || !in_array($unit, $units))
{
$value = '';
}
break;
case 'images':
$value = str_replace('..', '.', request_var($var, ''));
if (!file_exists("{$phpbb_root_path}styles/{$theme_info['theme_path']}/theme/" . $value))
{
$value = '';
}
break;
case 'colors':
$value = request_var($var, '');
if (preg_match('#^(?:[A-F0-9]{6}|[A-F0-9]{3})$#', $value))
{
$value = '#' . $value;
}
break;
case 'repeat':
$value = request_var($var, '');
if (!isset($repeat_types[$value]))
{
$value = '';
}
break;
default:
$value = htmlspecialchars_decode(request_var($var, ''));
}
// use the element mapping to create raw css code
if ($value !== '')
{
$css_data .= $match . ': ' . ($type == 'sizes' ? rtrim(sprintf($map_elements[$type], $value), '0') : sprintf($map_elements[$type], $value)) . $unit . ";\n";
}
}
}
// append additional data sent to us
if ($other = request_var('cssother', ''))
{
$css_data .= str_replace(' ;; ', ";\n", $other) . ';';
$css_data = preg_replace("#\*/;\n#", "*/\n", $css_data);
}
}
// make sure we have $show_css set, so we can link to the show_css page if we need to
else if (!$hide_css)
{
$show_css = true;
}
if ($submit || $add_custom)
{
if ($submit)
{
// if the user submitted a modification replace the old class definition in the stylesheet
// with the new one
if (preg_match('#^' . preg_quote($edit_class, '#') . '[ \t\n]*?\{(.*?)\}#ms', $stylesheet))
{
$stylesheet = preg_replace('#^(' . preg_quote($edit_class, '#') . '[ \t\n]*?\{).*?(\})#ms', "$1\n\t" . str_replace("\n", "\n\t", $css_data) . "\n$2", $stylesheet);
}
$message = $user->lang['THEME_UPDATED'];
}
else
{
// check whether the custom class name is valid
if (!preg_match('/^[a-z0-9\.,:#_\ \t->*]+$/i', $custom_class))
{
trigger_error($user->lang['THEME_ERR_CLASS_CHARS'] . adm_back_link($this->u_action . "&amp;action=edit&amp;id=$theme_id&amp;text_rows=$text_rows"), E_USER_WARNING);
}
else
{
// append an empty class definition to the stylesheet
$stylesheet .= "\n$custom_class {\n\t\n}";
$message = $user->lang['THEME_CLASS_ADDED'];
}
}
// where should we store the CSS?
if (!$safe_mode && !$theme_info['theme_storedb'] && file_exists($stylesheet_path) && @is_writable($stylesheet_path))
{
// write stylesheet to file
if (!($fp = fopen($stylesheet_path, 'wb')))
if (!($fp = fopen($file, 'wb')))
{
trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING);
}
fwrite($fp, $stylesheet);
fwrite($fp, $theme_data);
fclose($fp);
}
else
@ -1375,7 +1060,7 @@ parse_css_file = {PARSE_CSS_FILE}
$sql_ary = array(
'theme_mtime' => time(),
'theme_storedb' => 1,
'theme_data' => $this->db_theme_data($theme_info, $stylesheet),
'theme_data' => $this->db_theme_data($theme_info, $theme_data),
);
$sql = 'UPDATE ' . STYLES_THEME_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
@ -1384,30 +1069,119 @@ parse_css_file = {PARSE_CSS_FILE}
$cache->destroy('sql', STYLES_THEME_TABLE);
// notify the user if the template was not stored in the db before his modification
// notify the user if the theme was not stored in the db before his modification
if (!$theme_info['theme_storedb'])
{
add_log('admin', 'LOG_THEME_EDIT_DETAILS', $theme_info['theme_name']);
$message .= '<br />' . $user->lang['EDIT_THEME_STORED_DB'];
}
}
$cache->destroy('sql', STYLES_THEME_TABLE);
add_log('admin', ($add_custom) ? 'LOG_THEME_EDIT_ADD' : 'LOG_THEME_EDIT', $theme_info['theme_name'], ($add_custom) ? $custom_class : $edit_class);
add_log('admin', (!$theme_info['theme_storedb']) ? 'LOG_THEME_EDIT_FILE' : 'LOG_THEME_EDIT', $theme_info['theme_name'], (!$theme_info['theme_storedb']) ? $theme_file : '');
trigger_error($message . adm_back_link($this->u_action . "&amp;action=edit&amp;id=$theme_id&amp;css_class=$edit_class&amp;showcss=$show_css&amp;text_rows=$text_rows"));
trigger_error($message . adm_back_link($this->u_action . "&amp;action=edit&amp;id=$theme_id&amp;template_file=$theme_file&amp;text_rows=$text_rows"));
}
unset($matches);
$s_hidden_fields['css_class'] = $edit_class;
// Generate a category array containing theme filenames
if (!$theme_info['theme_storedb'])
{
$theme_path = "{$phpbb_root_path}styles/{$theme_info['theme_path']}/theme";
$filelist = filelist($theme_path, '', 'css');
if ($theme_file)
{
if (!file_exists($theme_path . "/$theme_file") || !($theme_data = file_get_contents($theme_path . "/$theme_file")))
{
trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING);
}
}
}
else
{
$theme_data = &$theme_info['theme_data'];
}
// Now create the categories
$filelist_cats[''] = array();
foreach ($filelist as $pathfile => $file_ary)
{
// Use the directory name as category name
if (!empty($pathfile))
{
$filelist_cats[$pathfile] = array();
foreach ($file_ary as $file)
{
$filelist_cats[$pathfile][$pathfile . $file] = $file;
}
}
// or if it's in the main category use the word before the first underscore to group files
else
{
$cats = array();
foreach ($file_ary as $file)
{
$cats[] = substr($file, 0, strpos($file, '_'));
$filelist_cats[substr($file, 0, strpos($file, '_'))][$file] = $file;
}
$cats = array_values(array_unique($cats));
// we don't need any single element categories so put them into the misc '' category
for ($i = 0, $n = sizeof($cats); $i < $n; $i++)
{
if (sizeof($filelist_cats[$cats[$i]]) == 1 && $cats[$i] !== '')
{
$filelist_cats[''][key($filelist_cats[$cats[$i]])] = current($filelist_cats[$cats[$i]]);
unset($filelist_cats[$cats[$i]]);
}
}
unset($cats);
}
}
unset($filelist);
// Generate list of categorised theme files
$tpl_options = '';
ksort($filelist_cats);
foreach ($filelist_cats as $category => $tpl_ary)
{
ksort($tpl_ary);
if (!empty($category))
{
$tpl_options .= '<option class="sep" value="">' . $category . '</option>';
}
foreach ($tpl_ary as $filename => $file)
{
$selected = ($theme_file == $filename) ? ' selected="selected"' : '';
$tpl_options .= '<option value="' . $filename . '"' . $selected . '>' . $file . '</option>';
}
}
$template->assign_vars(array(
'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields),
'S_EDIT_THEME' => true,
'S_HIDDEN_FIELDS' => build_hidden_fields(array('template_file' => $theme_file)),
'S_THEME_IN_DB' => $theme_info['theme_storedb'],
'S_TEMPLATES' => $tpl_options,
'U_SWATCH' => append_sid("{$phpbb_admin_path}swatch.$phpEx", 'form=acp_theme') . '&amp;name=',
'UA_SWATCH' => append_sid("{$phpbb_admin_path}swatch.$phpEx", 'form=acp_theme', false) . '&name=',
'U_ACTION' => $this->u_action . "&amp;action=edit&amp;id=$theme_id&amp;text_rows=$text_rows",
'U_BACK' => $this->u_action,
'CSS_DATA' => htmlspecialchars($css_data))
'L_EDIT' => $user->lang['EDIT_THEME'],
'L_EDIT_EXPLAIN' => $user->lang['EDIT_THEME_EXPLAIN'],
'L_EDITOR' => $user->lang['THEME_EDITOR'],
'L_EDITOR_HEIGHT' => $user->lang['THEME_EDITOR_HEIGHT'],
'L_FILE' => $user->lang['THEME_FILE'],
'L_SELECT' => $user->lang['SELECT_THEME'],
'L_SELECTED' => $user->lang['SELECTED_THEME'],
'L_SELECTED_FILE' => $user->lang['SELECTED_THEME_FILE'],
'SELECTED_TEMPLATE' => $theme_info['theme_name'],
'TEMPLATE_FILE' => $theme_file,
'TEMPLATE_DATA' => htmlspecialchars($theme_data),
'TEXT_ROWS' => $text_rows)
);
}

View File

@ -617,8 +617,8 @@ $lang = array_merge($lang, array(
'LOG_THEME_ADD_FS' => '<strong>Add new theme on filesystem</strong><br />» %s',
'LOG_THEME_DELETE' => '<strong>Theme deleted</strong><br />» %s',
'LOG_THEME_EDIT_DETAILS' => '<strong>Edited theme details</strong><br />» %s',
'LOG_THEME_EDIT' => '<strong>Edited theme <em>%1$s</em></strong><br />» Modified class <em>%2$s</em>',
'LOG_THEME_EDIT_ADD' => '<strong>Edited theme <em>%1$s</em></strong><br />» Added class <em>%2$s</em>',
'LOG_THEME_EDIT' => '<strong>Edited theme <em>%1$s</em></strong>',
'LOG_THEME_EDIT_FILE' => '<strong>Edited theme <em>%1$s</em></strong><br />» Modified file <em>%2$s</em>',
'LOG_THEME_EXPORT' => '<strong>Exported theme</strong><br />» %s',
'LOG_THEME_REFRESHED' => '<strong>Refreshed theme</strong><br />» %s',

View File

@ -65,11 +65,7 @@ $lang = array_merge($lang, array(
'CREATE_STYLE' => 'Create new style',
'CREATE_TEMPLATE' => 'Create new template set',
'CREATE_THEME' => 'Create new theme',
'CSS_CLASS_NAME' => 'CSS class name',
'CSS_COLOUR_EXPLAIN' => 'You can either enter a hexadecimal number for the colour or use the web safe colour swatch to select one.',
'CURRENT_IMAGE' => 'Current image',
'CUSTOM_CLASS' => 'Custom class',
'CUSTOM_CLASS_EXPLAIN' => 'You can add additional classes to this theme if you wish. You must provide the actual CSS class name below, it must be the same as that you have or will use in your template. Please remember that class names may contain only alphanumeric characters, periods (.), colons (:), dash (-), underscore (_) and number/hash/pound (#). The new class will be added to class selection above.',
'DEACTIVATE_DEFAULT' => 'You cannot deactivate the default style.',
'DELETE_FROM_FS' => 'Delete from filesystem',
@ -98,7 +94,7 @@ $lang = array_merge($lang, array(
'EDIT_TEMPLATE_EXPLAIN' => 'Here you can edit your template set directly. Please remember that these edits are permanent and cannot be undone once submitted. If PHP can write to the template files in your styles directory any changes here will be written directly to those files. If PHP cannot write to those files they will be copied into the database and all changes will only be reflected there. Please take care when editing your template set, remember to close all replacement variable terms {XXXX} and conditional statements.',
'EDIT_TEMPLATE_STORED_DB' => 'The template file was unwritable so the template set is now stored in the database containing the modified file.',
'EDIT_THEME' => 'Edit theme',
'EDIT_THEME_EXPLAIN' => 'Here you can edit the selected theme, changing colours, images, etc. You can switch between a simplified interface where you can set basic colours, etc. and a more advanced "raw CSS" mode. The raw mode allows you to add additional parameters such as borders, etc. Only set parameters you need else leave them blank or undefined.',
'EDIT_THEME_EXPLAIN' => 'Here you can edit the selected theme, changing colours, images, etc.',
'EDIT_THEME_STORED_DB' => 'The stylesheet file was unwritable so the stylesheet is now stored in the database containing your modification.',
'EXPORT' => 'Export',
@ -322,16 +318,13 @@ $lang = array_merge($lang, array(
'SELECT_IMAGE' => 'Select image',
'SELECT_TEMPLATE' => 'Select template file',
'SELECT_CLASS' => 'Select CSS class',
'SELECT_THEME' => 'Select theme file',
'SELECTED_IMAGE' => 'Selected image',
'SELECTED_IMAGESET' => 'Selected imageset',
'SELECTED_TEMPLATE' => 'Selected template',
'SELECTED_TEMPLATE_FILE' => 'Selected template file',
'SELECTED_THEME' => 'Selected theme',
'SELECTED_CLASS' => 'Selected CSS class',
'SHOW_CSS' => 'Show raw CSS',
'SHOW_CSS_NOTE' => 'Note',
'SHOW_CSS_EXPLAIN' => 'Enter each element on a new line, ending with a ; Expand the data for each element, e.g. do not use font: use font-family:, font-weight:, etc.',
'SELECTED_THEME_FILE' => 'Selected theme file',
'STORE_DATABASE' => 'Database',
'STORE_FILESYSTEM' => 'Filesystem',
'STYLE_ACTIVATE' => 'Activate',
@ -394,7 +387,7 @@ $lang = array_merge($lang, array(
'THEME_DELETED' => 'Theme deleted successfully.',
'THEME_DELETED_FS' => 'Theme removed from database but files remain on the filesystem.',
'THEME_DETAILS_UPDATED' => 'Theme details successfully updated.',
'THEME_EDITOR' => 'Raw CSS theme editor',
'THEME_EDITOR' => 'Theme editor',
'THEME_EDITOR_HEIGHT' => 'Theme editor height',
'THEME_ERR_ARCHIVE' => 'Please select an archive method.',
'THEME_ERR_CLASS_CHARS' => 'Only alphanumeric characters plus ., :, -, _ and # are valid in class names.',
@ -405,6 +398,7 @@ $lang = array_merge($lang, array(
'THEME_ERR_NOT_THEME' => 'The archive you specified does not contain a valid theme.',
'THEME_ERR_REFRESH_FS' => 'This theme is stored on the filesystem so there is no need to refresh it.',
'THEME_ERR_STYLE_NAME' => 'You must supply a name for this theme.',
'THEME_FILE' => 'Theme file',
'THEME_EXPORT' => 'Export Theme',
'THEME_EXPORT_EXPLAIN' => 'Here you can export a theme in the form of an archive. This archive will contain all the data necessary to install the theme on another board. You may select whether to download the file directly or to place it in your store folder for download later or via FTP.',
'THEME_EXPORTED' => 'Theme exported successfully and stored in %s.',
@ -412,7 +406,7 @@ $lang = array_merge($lang, array(
'THEME_LOCATION_EXPLAIN' => 'Images are always stored on the filesystem.',
'THEME_NAME' => 'Theme name',
'THEME_REFRESHED' => 'Theme refreshed successfully.',
'THEME_UPDATED' => 'Class updated successfully.',
'THEME_UPDATED' => 'Theme updated successfully.',
'UNDERLINE' => 'Underline',
'UNINSTALLED_IMAGESET' => 'Uninstalled imagesets',