\n"; $body .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} }) . "\n"; $body .= "\n\n"; }; # used for error messages my $err = sub { $title = "Error"; $body = ''; $authasform->() if $remote; $body .= ""; return; }; # authenticate user $remote = LJ::get_remote(); return $err->('You must be logged in to view your styles.') unless $remote; my $authas = $GET{'authas'} || $remote->{'user'}; my $u = LJ::get_authas_user($authas); return $err->('You could not be authenticated as the specified user.') unless $u; return $err->($remote->{user} eq $u->{user} ? 'Your account type does not allow advanced customization.' : 'The selected user\'s account type does not allow advanced customization.' ) unless LJ::get_cap($u, 's2styles'); # extra arguments for get requests my $getextra = $authas ne $remote->{'user'} ? "?authas=$authas" : ''; my $getextra_amp = "&authas=$authas" if $getextra; # style id to edit, if we have one # if we have this we're assumed to be in 'edit' mode my $id = $GET{'id'}+0; my $dbh = LJ::get_db_writer(); # variables declared here, but only filled in if $id my ($core, $layout); # scalars my ($pub, $ulay, $style); # hashrefs # start of output $title = "Styles"; $body = BML::ml("backlink", { 'link' => './', 'text' => 'Advanced Customization', }) . "\n"; $body .= BML::ml("actionlink", { 'link' => "Your Layers", }) . "\n"; # edit mode if ($id) { # load style $style = LJ::S2::load_style($id); return $err->('Style not found') unless $style; # check that they own the style return $err->("You do not own this style.") unless $style->{'userid'} == $u->{'userid'}; # use selected style if ($POST{'action:usestyle'}) { # save to db and update user object LJ::set_userprop($u, "stylesys", '2'); LJ::set_userprop($u, "s2_style", $id); return BML::redirect("styles.bml$getextra"); } # get public layers $pub = LJ::S2::get_public_layers(); # get user layers $ulay = LJ::S2::get_layers_of_user($u); # find effective layerids being used my %eff_layer = (); my @other_layers = (); foreach (qw(i18nc layout theme i18n user)) { my $lid = $POST{$_} eq "_other" ? $POST{"other_$_"} : $POST{$_}; next unless $lid; $eff_layer{$_} = $lid; unless ($ulay->{$eff_layer{$_}} || $pub->{$eff_layer{$_}}) { push @other_layers, $lid; } } # core lid (can't use user core layer) $POST{'core'} ||= $POST{'core_hidden'}; $core = defined $POST{'core'} ? $POST{'core'} : $style->{'layer'}->{'core'}; unless ($core) { # default to highest numbered core map { $core = $_ if $pub->{$_}->{'type'} eq 'core' && /^\d+$/ && $pub->{$_}->{'majorversion'} > $pub->{$core}->{'majorversion'} } keys %$pub; # update in POST to keep things in sync $POST{'core'} = $core; } # layout lid $layout = $POST{'action:change'} ? $eff_layer{'layout'} : $style->{'layer'}->{'layout'}; # if we're changing core, clear everything if ($POST{'core'} && $style->{'layer'}->{'core'} && $POST{'core'} != $style->{'layer'}->{'core'}) { foreach (qw(i18nc layout theme i18n user)) { delete $eff_layer{$_}; } undef $layout; } # if we're changing layout, clear everything below if ($eff_layer{'layout'} && $style->{'layer'}->{'layout'} && $eff_layer{'layout'} != $style->{'layer'}->{'layout'}) { foreach (qw(theme i18n user)) { delete $eff_layer{$_}; } } # set up start of output $title = "Edit Style"; $body .= "
" . BML::ml('backlink', { 'text' => 'Your Styles', 'link' => "styles.bml$getextra" }) . "\n"; ### process edit actions # delete if ($POST{'action:delete'}) { LJ::S2::delete_user_style($u, $id); undef $id; # don't show form below return BML::redirect("styles.bml$getextra"); } # save changes if ($POST{'action:change'} || $POST{'action:savechanges'}) { # are they renaming their style? if ($POST{'stylename'} && $style->{'name'} && $POST{'stylename'} ne $style->{'name'}) { # update db my $styleid = $style->{'styleid'}; $dbh->do("UPDATE s2styles SET name=? WHERE styleid=? AND userid=?", undef, $POST{'stylename'}, $styleid, $u->{'userid'}); LJ::MemCache::delete([$styleid, "s2s:$styleid"]); # update style object $style->{'name'} = $POST{'stylename'}; } # load layer info of any "other" layers my %other_info = (); if (@other_layers) { LJ::S2::load_layer_info(\%other_info, \@other_layers); foreach (@other_layers) { return $err->("Layer not found: $_") unless exists $other_info{$_}; return $err->("Layer not public: $_") unless $other_info{$_}->{'is_public'}; } } # error check layer modifications my $get_layername = sub { my $lid = shift; my $name; $name = $pub->{$lid}->{'name'} if $pub->{$lid}; $name ||= $ulay->{$lid}->{'name'} if $ulay->{$lid}; $name ||= "#$lid"; return $name; }; # check layer hierarchy my $error_check = sub { my ($type, $parentid) = @_; my $lid = $eff_layer{$type}; next if ! $lid; my $layer = $ulay->{$lid} || $pub->{$lid} || LJ::S2::load_layer($lid); my $parentname = $get_layername->($parentid); my $layername = $get_layername->($lid); # is valid layer type? return "Invalid layer type: $layername is not a $type layer" if $layer->{'type'} ne $type; # is a child? return "Layer hierarchy mismatch: $layername is not a child $type layer of $parentname" unless $layer->{'b2lid'} == $parentid; return undef; }; # check child layers of core foreach my $type (qw(i18nc layout)) { my $errmsg = $error_check->($type, $core); return $err->($errmsg) if $errmsg; } # don't check sub-layout layers if there's no layout if ($layout) { # check child layers of selected layout foreach my $type (qw(theme i18n user)) { my $errmsg = $error_check->($type, $layout); return $err->($errmsg) if $errmsg; } } # save in database my @layers = ( 'core' => $core ); push @layers, map { $_, $eff_layer{$_} } qw(i18nc layout i18n theme user); LJ::S2::set_style_layers($u, $style->{'styleid'}, @layers); # redirect if they clicked the bottom button return BML::redirect("styles.bml$getextra") if $POST{'action:savechanges'}; } # no style id, process actions for non-edit mode # and load in data necessary for style list } else { # load user styles my $ustyle = LJ::S2::load_user_styles($u); # process create action if ($POST{'action:create'} && $POST{'stylename'}) { return $err->('You have reached your maximum number of styles.') if scalar(keys %$ustyle) >= LJ::get_cap($u, 's2stylesmax'); my $styleid = LJ::S2::create_style($u, $POST{'stylename'}); return $err->('Style not created: Database error') unless $styleid; return BML::redirect("styles.bml?id=$styleid$getextra_amp"); } # load style currently in use LJ::load_user_props($u, 's2_style'); # set up page header $title = "Your Styles"; $authasform->(); $body .= "
\n"; # show style listing $body .= "\n"; if (%$ustyle) { my $journalbase = LJ::journal_base($u); foreach my $styleid (sort { $ustyle->{$a} cmp $ustyle->{$b} || $a <=> $b} keys %$ustyle) { $body .= "\n"; } } else { $body .= "\n"; } $body .= "
"; my @b = $styleid == $u->{'s2_style'} ? "" : ""; $body .= $b[0] . LJ::ehtml($ustyle->{$styleid}); $body .= " (\#$styleid)$b[1] "; $body .= "
"; $body .= LJ::html_submit('action:edit', 'Edit') . " "; $body .= LJ::html_submit('action:delete', 'Delete', { 'onclick' => "return confirm('Are you sure you want to delete style \#$styleid?')" }) . " "; $body .= LJ::html_submit('action:usestyle', 'Use', { 'disabled' => $styleid == $u->{'s2_style'} }), $body .= "
none
\n"; } ### show create / edit form my $extra = $id ? "?id=$id" : ''; $extra .= $extra ? $getextra_amp : $getextra; $body .= "
"; # create a new style, or change the name of the style currently being edited # note: this little bit of code appears whether there is an id passed or not. # the textbox just has a different purpose depending on the context. $body .= "\n"; $body .= "\n"; $body .= "\n"; $body .= "
Name: "; $body .= LJ::html_text({ 'name' => 'stylename', 'size' => '30', 'maxlength' => '255', 'value' => defined $POST{'stylename'} ? $POST{'stylename'} : $style->{'name'} }); $body .= " " . LJ::html_submit('action:create', 'Create') unless $id; $body .= "
\n"; # if no id to edit, we're finished $body .= "
\n", return unless $id; # from here on we have $pub, $ulay, and $style filled in # sub to take a layer type, core, and parent layout # and return a list of options to feed to LJ::html_select() my $layerselect = sub { my ($type, $b2lid) = @_; my @opts = (); # returns html_select to caller my $html_select = sub { my $dis = scalar(@opts) > 2 ? 0 : 1; my $lid = $POST{'action:change'} ? $POST{$type} : $style->{'layer'}->{$type}; $lid = $POST{"other_$type"} if $lid eq "_other"; my $sel = ($lid && ! $pub->{$lid} && ! $ulay->{$lid}) ? "_other" : $lid; return [ LJ::html_select({ 'name' => $type, 'id' => "select_$type", 'onChange' => "showOther('$type')", 'selected' => $sel, 'disabled' => $dis }, @opts), { 'disabled' => $dis, } ]; }; # greps, and sorts a list my $greplist = sub { my $ref = shift; return sort { $ref->{$a}->{'name'} cmp $ref->{$b}->{'name'} || $a <=> $b} grep { $ref->{$_}->{'type'} eq $type && $ref->{$_}->{'b2lid'} == $b2lid && /^\d+$/} keys %$ref; }; # public layers my $name = $type eq 'core' ? 'majorversion' : 'name'; push @opts, map { $_, $pub->{$_}->{$name} } $greplist->($pub); # no user core layers return $html_select->() if $type eq 'core'; # user layers push @opts, ('', '---'); my $startsize = scalar(@opts); push @opts, map { $_, "$ulay->{$_}->{'name'} (\#$_)" } $greplist->($ulay); # if we didn't push anything above, remove dividing line pop @opts, pop @opts unless scalar(@opts) > $startsize; # add option for other layerids push @opts, ('_other', 'Other ...'); # add blank option to beginning of list unshift @opts, ('', @opts ? '' : ' '); return $html_select->(); }; my $layerother = sub { my $name = shift; my $olid = $POST{'action:change'} ? $POST{"other_$name"} : $style->{'layer'}->{$name}; my $disp = 'none'; my $val; if ($olid && ! $pub->{$olid} && ! $ulay->{$olid}) { $disp = 'inline'; $val = $olid; } return "
Layerid: " . LJ::html_text({ 'name' => "other_$name", 'id' => "other_$name", 'size' => 6, 'value' => $val }) . "
"; }; ### core version $body .= "\n"; $body .= "\n"; $body .= "\n"; $body .= "
Core Version: "; my $coresel = $layerselect->('core', 0); $body .= $coresel->[0]; $body .= LJ::html_hidden('core_hidden', $core); my $dis = $coresel->[1]->{'disabled'} ? { 'disabled' => 'disabled' } : undef; $body .= " " . LJ::html_submit('action:change', 'Change', $dis) . "
\n"; ### i18nc / layout $body .= "\n"; # i18nc $body .= "\n"; # layout $body .= "\n"; $body .= "
Language (i18nc): "; $body .= $layerselect->('i18nc', $core)->[0]; $body .= $layerother->('i18nc'); $body .= "
Layout: "; my $layoutsel = $layerselect->('layout', $core); $body .= $layoutsel->[0]; $body .= $layerother->('layout'); my $dis = $layoutsel->[1]->{'disabled'} ? { 'disabled' => 'disabled' } : undef; $body .= " " . LJ::html_submit("action:change", "Change", $dis) . "
\n"; # do we need to show the rest of the form? $body .= "\n", return unless $layout; ### theme / i18n / user # theme $body .= "\n"; $body .= "\n"; $body .= "\n"; $body .= "\n"; $body .= "\n"; $body .= "
Language (i18n): "; $body .= $layerselect->('i18n', $layout)->[0]; $body .= $layerother->('i18n') . "
Theme: "; $body .= $layerselect->('theme', $layout)->[0]; $body .= $layerother->('theme') . "
User: "; $body .= $layerselect->('user', $layout)->[0]; $body .= $layerother->('user') . "
 "; $body .= LJ::html_submit('action:savechanges', 'Save Changes') . "
\n"; # end edit form $body .= "\n"; return; } _code?> head<= <=head body=> bodyopts=>onLoad="pageload();" page?>