439 lines
15 KiB
Plaintext
439 lines
15 KiB
Plaintext
|
<?_code # -*-bml-*-
|
||
|
{
|
||
|
use strict;
|
||
|
use vars qw(%POST %GET $title $body $js);
|
||
|
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
|
||
|
my $remote = LJ::get_remote();
|
||
|
return "<?h1 Login Required h1?><?p Before you customize your journal, you must first <a href='/login.bml'>login</a>. p?>"
|
||
|
unless $remote;
|
||
|
|
||
|
my @journals = ($remote->{'user'});
|
||
|
push @journals, LJ::get_shared_journals($remote);
|
||
|
my $journal = $GET{'journal'} || $remote->{'user'};
|
||
|
unless (grep { $_ eq $journal } @journals) { return BML::redirect("/customize/"); }
|
||
|
|
||
|
my $u = $remote;
|
||
|
$u = LJ::load_user($journal) unless $journal eq $remote->{'user'};
|
||
|
my $userid = $u->{'userid'};
|
||
|
|
||
|
LJ::load_user_props($u, "stylesys", "s2_style");
|
||
|
|
||
|
$body = "";
|
||
|
$title = "Customize";
|
||
|
$js = "";
|
||
|
|
||
|
my $err = sub {
|
||
|
$title = "Error";
|
||
|
$body = shift;
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
my ($style, $layer);
|
||
|
my $save_arg;
|
||
|
my $save_redir;
|
||
|
|
||
|
# when given 'w' argument, load user's current style, and edit the user layer.
|
||
|
# this is the mode redirected to from /customize/ (the simple customization UI)
|
||
|
if ($GET{'w'} eq "user" && $u->{'stylesys'} == 2)
|
||
|
{
|
||
|
$style = LJ::S2::load_style($u->{'s2_style'});
|
||
|
return $err->("Style not found.") unless $style && $style->{'userid'} == $u->{'userid'};
|
||
|
$layer = LJ::S2::load_layer($dbh, $style->{'layer'}->{'user'});
|
||
|
|
||
|
# if the b2lid of this layer has been remapped to a new layerid
|
||
|
# then update the b2lid mapping for this layer
|
||
|
my $b2lid = $layer->{b2lid};
|
||
|
if ($b2lid && $LJ::S2LID_REMAP{$b2lid}) {
|
||
|
LJ::S2::b2lid_remap($u, $style->{'layer'}->{'user'}, $b2lid);
|
||
|
$layer->{b2lid} = $LJ::S2LID_REMAP{$b2lid};
|
||
|
}
|
||
|
|
||
|
$save_arg = "w=user&journal=$journal";
|
||
|
$save_redir = "/customize/?journal=$journal";
|
||
|
}
|
||
|
|
||
|
return BML::redirect("/customize/") unless $layer;
|
||
|
return $err->("Layer belongs to another user.") unless $layer->{'userid'} == $u->{'userid'};
|
||
|
return $err->("Layer isn't of type user or theme.")
|
||
|
unless $layer->{'type'} eq "user" || $layer->{'type'} eq "theme";
|
||
|
|
||
|
my $lyr_layout = LJ::S2::load_layer($dbh, $layer->{'b2lid'});
|
||
|
return $err->("Layout layer for this $layer->{'type'} layer not found.")
|
||
|
unless $lyr_layout;
|
||
|
my $lyr_core = LJ::S2::load_layer($dbh, $lyr_layout->{'b2lid'});
|
||
|
return $err->("Core layer for layout not found.")
|
||
|
unless $lyr_core;
|
||
|
|
||
|
$lyr_layout->{'uniq'} = $dbh->selectrow_array("SELECT value FROM s2info WHERE s2lid=? AND infokey=?",
|
||
|
undef, $lyr_layout->{'s2lid'}, "redist_uniq");
|
||
|
|
||
|
my ($lid_i18nc, $lid_theme, $lid_i18n);
|
||
|
$lid_i18nc = $style->{'layer'}->{'i18nc'};
|
||
|
$lid_theme = $style->{'layer'}->{'theme'};
|
||
|
$lid_i18n = $style->{'layer'}->{'i18n'};
|
||
|
|
||
|
my $layerid = $layer->{'s2lid'};
|
||
|
|
||
|
my @layers;
|
||
|
push @layers, ([ 'core' => $lyr_core->{'s2lid'} ],
|
||
|
[ 'i18nc' => $lid_i18nc ],
|
||
|
[ 'layout' => $lyr_layout->{'s2lid'} ],
|
||
|
[ 'i18n' => $lid_i18n ]);
|
||
|
if ($layer->{'type'} eq "user" && $lid_theme) {
|
||
|
push @layers, [ 'theme' => $lid_theme ];
|
||
|
}
|
||
|
push @layers, [ $layer->{'type'} => $layer->{'s2lid'} ];
|
||
|
|
||
|
my @layerids = grep { $_ } map { $_->[1] } @layers;
|
||
|
LJ::S2::load_layers(@layerids);
|
||
|
|
||
|
my %layerinfo;
|
||
|
|
||
|
# load the language and layout choices for core.
|
||
|
LJ::S2::load_layer_info(\%layerinfo, \@layerids);
|
||
|
|
||
|
# action path
|
||
|
if (LJ::did_post()) {
|
||
|
# prevent spoofing:
|
||
|
return BML::redirect("/customize")
|
||
|
unless $POST{'userid'} == $u->{'userid'};
|
||
|
|
||
|
my %override;
|
||
|
foreach my $prop (S2::get_properties($lyr_layout->{'s2lid'}))
|
||
|
{
|
||
|
$prop = S2::get_property($lyr_core->{'s2lid'}, $prop)
|
||
|
unless ref $prop;
|
||
|
next unless ref $prop;
|
||
|
next if $prop->{'noui'};
|
||
|
my $name = $prop->{'name'};
|
||
|
next unless $POST{"$name:override"};
|
||
|
next unless LJ::S2::can_use_prop($u, $lyr_layout->{'uniq'}, $name);
|
||
|
$override{$name} = [ $prop, $POST{"${name}_value"} ];
|
||
|
}
|
||
|
|
||
|
if (LJ::S2::layer_compile_user($layer, \%override)) {
|
||
|
return BML::redirect($save_redir) if $save_redir;
|
||
|
$body = "Saved.";
|
||
|
return;
|
||
|
} else {
|
||
|
my $error = LJ::last_error();
|
||
|
$body = "Error saving layer:<pre>$error</pre>";
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$body .= "<form method='post' action='layer.bml?$save_arg'>";
|
||
|
$body .= LJ::html_hidden("userid", $u->{'userid'});
|
||
|
|
||
|
my %prop; # name -> hashref, deleted when added to a category
|
||
|
my @propnames;
|
||
|
foreach my $prop (S2::get_properties($lyr_layout->{'s2lid'})) {
|
||
|
unless (ref $prop) {
|
||
|
$prop = S2::get_property($lyr_core->{'s2lid'}, $prop);
|
||
|
next unless ref $prop;
|
||
|
}
|
||
|
$prop{$prop->{'name'}} = $prop;
|
||
|
push @propnames, $prop->{'name'};
|
||
|
}
|
||
|
|
||
|
my @groups = S2::get_property_groups($lyr_layout->{'s2lid'});
|
||
|
my $misc_group;
|
||
|
my %groupprops; # gname -> [ propname ]
|
||
|
my %propgroup; # pname -> gname;
|
||
|
|
||
|
foreach my $gname (@groups) {
|
||
|
if ($gname eq "misc" || $gname eq "other") { $misc_group = $gname; }
|
||
|
foreach my $pname (S2::get_property_group_props($lyr_layout->{'s2lid'}, $gname)) {
|
||
|
my $prop = $prop{$pname};
|
||
|
next if ! $prop || $propgroup{$pname};
|
||
|
$propgroup{$pname} = $gname;
|
||
|
push @{$groupprops{$gname}}, $pname;
|
||
|
}
|
||
|
}
|
||
|
# put unsorted props into an existing or new unsorted/misc group
|
||
|
if (@groups) {
|
||
|
my @unsorted;
|
||
|
foreach my $pname (@propnames) {
|
||
|
my $prop = $prop{$pname};
|
||
|
next if ! $prop || $propgroup{$pname};
|
||
|
push @unsorted, $pname;
|
||
|
}
|
||
|
if (@unsorted) {
|
||
|
unless ($misc_group) {
|
||
|
$misc_group = "misc";
|
||
|
push @groups, "misc";
|
||
|
}
|
||
|
push @{$groupprops{$misc_group}}, @unsorted;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $group_name = sub {
|
||
|
my $gname = shift;
|
||
|
foreach my $lid ($lid_i18n, $lyr_layout->{'s2lid'}, $lid_i18nc, $lyr_core->{'s2lid'}) {
|
||
|
next unless $lid;
|
||
|
my $name = S2::get_property_group_name($lid, $gname);
|
||
|
return LJ::ehtml($name) if $name;
|
||
|
}
|
||
|
return "Misc" if $gname eq "misc";
|
||
|
return $gname;
|
||
|
};
|
||
|
|
||
|
my $prop_js = "";
|
||
|
my $output_prop = sub {
|
||
|
my $name = shift;
|
||
|
my $prop = $prop{$name};
|
||
|
return if ! $prop || $prop->{'noui'};
|
||
|
|
||
|
my $name = $prop->{'name'};
|
||
|
my $type = $prop->{'type'};
|
||
|
|
||
|
my $can_use = LJ::S2::can_use_prop($u, $lyr_layout->{'uniq'}, $name);
|
||
|
|
||
|
# figure out existing value (if there was no user/theme layer)
|
||
|
my $existing;
|
||
|
foreach my $lid (reverse @layerids) {
|
||
|
next if $lid == $layerid;
|
||
|
$existing = S2::get_set($lid, $name);
|
||
|
last if defined $existing;
|
||
|
}
|
||
|
|
||
|
if (ref $existing eq "HASH") { $existing = $existing->{'as_string'}; }
|
||
|
|
||
|
if ($type eq "bool") {
|
||
|
$prop->{'values'} ||= "1|Yes|0|No";
|
||
|
}
|
||
|
|
||
|
my %values = split(/\|/, $prop->{'values'});
|
||
|
my $existing_display = defined $values{$existing} ?
|
||
|
$values{$existing} : $existing;
|
||
|
|
||
|
$existing_display = LJ::eall($existing_display);
|
||
|
|
||
|
my $override = S2::get_set($layerid, $name);
|
||
|
my $had_override = defined $override;
|
||
|
$override = $existing unless defined $override;
|
||
|
|
||
|
if (ref $override eq "HASH") { $override = $override->{'as_string'}; }
|
||
|
|
||
|
$body .= "<?h1 " . LJ::eall($prop->{'des'}) . " h1?>";
|
||
|
{
|
||
|
my $t = "";
|
||
|
$t .= LJ::eall($prop->{'note'}) if $prop->{'note'};
|
||
|
$t .= "<?help " . $LJ::HELPPURL{"s2opt_$name"} . " help?>" if $LJ::HELPURL{"s2opt_$name"};
|
||
|
$body .= "<?p $t p?>" if $t;
|
||
|
}
|
||
|
$body .= "<div class='inset'>\n";
|
||
|
$body .= LJ::html_check({ 'name' => "$name:override", 'id' => "$name:override",
|
||
|
'selected' => $had_override, 'disabled' => ! $can_use,
|
||
|
'onchange' => "toggleOverride('$name');" });
|
||
|
my $offhelp = ! $can_use ? LJ::help_icon('s2propoff', ' ') : "";
|
||
|
$body .= "<label for='$name:override'> Override default</label>$offhelp<br />\n";
|
||
|
$body .= "<dl class='hidedt'>\n<dt>Default:</dt>\n<dd id='$name:default_value' style='font-family: monospace'>\n";
|
||
|
if ($type eq "int" || $type eq "string") {
|
||
|
if ($existing_display ne "") {
|
||
|
$body .= $existing_display;
|
||
|
} else {
|
||
|
$body .= "<i>(nothing)</i>";
|
||
|
}
|
||
|
} elsif ($type eq "Color") {
|
||
|
$body .= "<span style=\"border: 1px solid #000000; padding-left: 2em; ".
|
||
|
"background-color: $existing;\"> </span> <tt>$existing_display</tt>";
|
||
|
} elsif ($type eq "bool") {
|
||
|
$body .= $existing_display;
|
||
|
}
|
||
|
$body .= "</dd>\n<dt>Override:</dt>\n<dd id='$name:user_value'>\n";
|
||
|
if ($prop->{'values'}) {
|
||
|
$body .= LJ::html_select({ 'name' => "${name}_value",
|
||
|
'disabled' => ! $can_use,
|
||
|
'selected' => $override },
|
||
|
split(/\|/, $prop->{'values'}));
|
||
|
} elsif ($type eq "int") {
|
||
|
$body .= LJ::html_text({ 'name' => "${name}_value",
|
||
|
'disabled' => ! $can_use,
|
||
|
'value' => $override,
|
||
|
'maxlength' => 5,
|
||
|
'size' => 7 });
|
||
|
} elsif ($type eq "string") {
|
||
|
my ($rows, $cols) = ($prop->{'rows'} + 0,
|
||
|
$prop->{'cols'} + 0);
|
||
|
if ($rows > 0 && $cols > 0) {
|
||
|
$body .= LJ::html_textarea({ 'name' => "${name}_value",
|
||
|
'disabled' => ! $can_use,
|
||
|
'value' => $override,
|
||
|
'onfocus' => "toggleOverride('$name');",
|
||
|
'rows' => $rows,
|
||
|
'cols' => $cols });
|
||
|
} else {
|
||
|
my ($size, $maxlength) = ($prop->{'size'} || 30,
|
||
|
$prop->{'maxlength'} || 255);
|
||
|
$body .= LJ::html_text({ 'name' => "${name}_value",
|
||
|
'disabled' => ! $can_use,
|
||
|
'value' => $override,
|
||
|
'maxlength' => $maxlength,
|
||
|
'size' => $size });
|
||
|
}
|
||
|
} elsif ($type eq "Color") {
|
||
|
$body .= LJ::html_color({ 'name' => "${name}_value",
|
||
|
'disabled' => ! $can_use,
|
||
|
'default' => $override,
|
||
|
'des' => $prop->{'des'} });
|
||
|
}
|
||
|
$body .= "</dd></dl>\n</div>\n";
|
||
|
$prop_js .= "toggleOverride('$name');\n";
|
||
|
};
|
||
|
|
||
|
if (@groups) {
|
||
|
$body .= "<div id='propgroupstab'>";
|
||
|
my $num = 0;
|
||
|
foreach my $gname (@groups) {
|
||
|
my $name = $group_name->($gname);
|
||
|
$num++;
|
||
|
my $class = $num == 1 ? "propgrouptabsel" : "propgrouptab";
|
||
|
$js .= " propgroups[$num] = \"$gname\";\n";
|
||
|
$body .= "<span class='$class' id='pgroup_tab_$gname'><a href='#pgroup$gname' onclick=\"return showPropGroup('$gname')\">$name</a></span>\n";
|
||
|
}
|
||
|
$body .= "</div>";
|
||
|
$body .= "<div id='propgroupsbody'>";
|
||
|
|
||
|
|
||
|
foreach my $gname (@groups) {
|
||
|
$body .= "<a name='pgroup$gname'></a>\n";
|
||
|
$body .= "<div id='pgroup_body_$gname'>\n";
|
||
|
foreach my $pname (@{$groupprops{$gname}}) {
|
||
|
$output_prop->($pname);
|
||
|
}
|
||
|
$body .= "</div>";
|
||
|
}
|
||
|
$body .= "</div>\n";
|
||
|
|
||
|
$body .= "<script language='JavaScript'>showPropGroup('$groups[0]');</script>\n";
|
||
|
|
||
|
} else {
|
||
|
foreach my $pname (@propnames) {
|
||
|
$output_prop->($pname);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$body .= "<script type='text/javascript' language='JavaScript'><!--\n$prop_js// --></script>";
|
||
|
|
||
|
$body .= "<?h1 Finished? h1?><?p When done, click the save button below. p?><center>";
|
||
|
$body .= LJ::html_submit('action:save', "Save");
|
||
|
$body .= "</center>";
|
||
|
|
||
|
$body .= "</form>";
|
||
|
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
_code?><?page
|
||
|
title=><?_code return $title; _code?>
|
||
|
body=><?_code return $body; _code?>
|
||
|
head<=
|
||
|
<script language="JavaScript" src="<?_code return $LJ::JSPREFIX; _code?>/colorpicker.js"></script>
|
||
|
<script language="JavaScript">
|
||
|
colPic_set_imgprefix("<?_code return $LJ::IMGPREFIX; _code?>");
|
||
|
|
||
|
var propgroups = new Array();
|
||
|
function showPropGroup (name) {
|
||
|
if (! document.getElementById) { return true; }
|
||
|
for (var i=0; i<propgroups.length; i++) {
|
||
|
var gname = propgroups[i];
|
||
|
var tab = document.getElementById("pgroup_tab_" + gname);
|
||
|
if (tab && tab.setAttribute) {
|
||
|
tab.setAttribute("class", (gname == name) ? "propgrouptabsel" : "propgrouptab");
|
||
|
}
|
||
|
var div = document.getElementById("pgroup_body_" + gname);
|
||
|
if (div) {
|
||
|
div.style.display = (gname == name) ? "block" : "none";
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
function toggleOverride (name) {
|
||
|
if (!name) return true;
|
||
|
if (!document.getElementById) return true;
|
||
|
var ocheck = document.getElementById(name + ':override');
|
||
|
if (!ocheck) return true;
|
||
|
|
||
|
var def_vals = document.getElementById(name + ':default_value');
|
||
|
if (!def_vals) return true;
|
||
|
var usr_vals = document.getElementById(name + ':user_value');
|
||
|
if (!usr_vals) return true;
|
||
|
|
||
|
var disp_def = ocheck.checked ? 'none' : 'block';
|
||
|
var disp_usr = ocheck.checked ? 'block' : 'none';
|
||
|
|
||
|
def_vals.style.display = disp_def;
|
||
|
usr_vals.style.display = disp_usr;
|
||
|
}
|
||
|
<?_code return $js; _code?>
|
||
|
</script>
|
||
|
|
||
|
|
||
|
<style type='text/css'>
|
||
|
#propgroupstab {
|
||
|
font-size: 1.2em;
|
||
|
font-weight: bold;
|
||
|
font-decoration: none;
|
||
|
border-bottom: 2px solid black;
|
||
|
margin: 0; padding: 0;
|
||
|
}
|
||
|
#propgroupsbody {
|
||
|
border-left: 2px solid black;
|
||
|
border-right: 2px solid black;
|
||
|
border-bottom: 2px solid black;
|
||
|
margin: 0; padding: 0.5em;
|
||
|
}
|
||
|
|
||
|
span.propgrouptabsel, span.propgrouptab {
|
||
|
margin: 0 0.2em 0 0.8em;
|
||
|
padding: 0.25em;
|
||
|
border-top: 2px solid black;
|
||
|
border-left: 2px solid black;
|
||
|
border-right: 2px solid black;
|
||
|
}
|
||
|
|
||
|
span.propgrouptab {
|
||
|
background: #ddd;
|
||
|
color: black;
|
||
|
}
|
||
|
span.propgrouptab a {
|
||
|
text-decoration: none;
|
||
|
color: black;
|
||
|
}
|
||
|
|
||
|
span.propgrouptabsel {
|
||
|
color: #ddd;
|
||
|
background: black;
|
||
|
}
|
||
|
span.propgrouptabsel a {
|
||
|
text-decoration: none;
|
||
|
color: #ddd;
|
||
|
}
|
||
|
div.inset {
|
||
|
margin-left: 2em;
|
||
|
margin-top: 0.5em;
|
||
|
margin-bottom: 0.5em;
|
||
|
}
|
||
|
dl.hidedt {
|
||
|
margin: 0;
|
||
|
padding: 0;
|
||
|
}
|
||
|
dl.hidedt dt { font-weight: bold; }
|
||
|
noscript { display: inline; }
|
||
|
</style>
|
||
|
<script type='text/javascript' language='JavaScript'>
|
||
|
// Only hide if we do the JS-switchy thing
|
||
|
if (document.getElementById)
|
||
|
document.write("<style type='text/css'>" +
|
||
|
"dl.hidedt dd { margin: 0; padding: 0; }" +
|
||
|
"dl.hidedt dt { display: none; }" +
|
||
|
"noscript { display: none; }" +
|
||
|
"</style>");
|
||
|
</script>
|
||
|
|
||
|
<=head
|
||
|
page?>
|