# This code was forked from the LiveJournal project owned and operated # by Live Journal, Inc. The code has been modified and expanded by # Dreamwidth Studios, LLC. These files were originally licensed under # the terms of the license supplied by Live Journal, Inc, which can # currently be found at: # # http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt # # In accordance with the original license, this code and all its # modifications are provided under the GNU General Public License. # A copy of that license can be found in the LICENSE file included as # part of this distribution. package LJ::Customize; use strict; use Carp qw(croak); # returns the S2Theme object of the given user's current theme sub get_current_theme { my $class = shift; my $u = shift; die "Invalid user object." unless LJ::isu($u); my $pub = LJ::S2::get_public_layers(); my $userlay = LJ::S2::get_layers_of_user($u); my %style = LJ::S2::get_style( $u, { verify => 1, force_layers => 1 } ); if ( $style{theme} == 0 ) { # default theme of system layout if ( $pub->{ $style{layout} } && $pub->{ $style{layout} }->{uniq} ) { return LJ::S2Theme->load_default_of( $style{layout}, user => $u ); # default theme of custom layout } else { return LJ::S2Theme->load_custom_layoutid( $style{layout}, $u ); } } else { # if the user is using a duplicate theme layer, return a theme object using the correct theme layer my $real_themeid = $pub->{ $style{theme} } && $pub->{ $style{theme} }->{uniq} ? $class->real_themeid_for_uniq( $pub->{ $style{theme} }->{uniq} ) : $style{theme}; return LJ::S2Theme->load_by_themeid( $real_themeid, $u ); } } # applies the given theme to the given user's journal sub apply_theme { my $class = shift; my $u = shift; my $theme = shift; my %style; my $has_cap = $u->can_create_s2_styles; my $pub = LJ::S2::get_public_layers(); my $userlay = LJ::S2::get_layers_of_user($u); die "Your account status does not allow access to this custom layer." if $theme->is_custom && !$has_cap; die "You cannot use this theme." unless $theme->available_to($u); die "No core parent." unless $theme->coreid; # delete s2_style and replace it with a new # or existing style for this theme $u->set_prop( "s2_style", '' ); $style{theme} = $theme->themeid; $style{layout} = $theme->layoutid; $style{core} = $theme->coreid; # if a style for this theme already exists, set that as the user's style my $styleid = $theme->get_styleid_for_theme($u); if ($styleid) { $u->set_prop( "s2_style", $styleid ); # now we have to populate %style from this style # theme, layout, and core have already been set my $stylay = LJ::S2::get_style_layers( $u, $u->prop('s2_style') ); foreach my $layer (qw(user i18nc i18n)) { $style{$layer} = exists $stylay->{$layer} ? $stylay->{$layer} : 0; } # no existing style found, create a new one } else { $style{user} = $style{i18nc} = $style{i18n} = 0; } # set style $class->implicit_style_create( $u, %style ); } # if there's no style set, load the default style and set it as the current theme # return the current style sub verify_and_load_style { my $class = shift; my $u = shift; my $style = LJ::S2::load_style( $u->prop('s2_style') ); unless ( $style && $style->{layer}->{layout} ) { # we have no layout layer for this style, which causes errors in # the customization interface # undef current style and force them to use the site defaults $u->set_prop( s2_style => 0 ); $style = undef; } unless ( $style && $style->{userid} == $u->userid ) { my $theme; if ( $LJ::DEFAULT_STYLE->{theme} ) { $theme = LJ::S2Theme->load_by_uniq( $LJ::DEFAULT_STYLE->{theme} ); } else { $theme = LJ::S2Theme->load_default_of( $LJ::DEFAULT_STYLE->{layout} ); } LJ::Customize->apply_theme( $u, $theme ); $style = LJ::S2::load_style( $u->prop('s2_style') ); # reload style } return $style; } # migrates current style name from wizard-layoutname to wizard-layoutname/themename, if needed sub migrate_current_style { my $class = shift; my $u = shift; my $s2style = LJ::S2::load_style( $u->prop('s2_style'), skip_layer_load => 1 ); my $theme = $class->get_current_theme($u); my $style_name_old = $theme->old_style_name_for_theme; my $style_name_new = $theme->new_style_name_for_theme; # migrate only if there's a need to if ( $s2style->{name} eq $style_name_old ) { LJ::S2::rename_user_style( $u, $s2style->{styleid}, $style_name_new ); } return; } # remove duplicate themes by uniq # always keep the theme in a set of duplicates that has the lowest s2lid sub remove_duplicate_themes { my $class = shift; my @themes = @_; @themes = sort { $a->uniq cmp $b->uniq } sort { $a->themeid <=> $b->themeid } @themes; my @ret; my $prev_uniq = ""; foreach my $theme (@themes) { if ( !$theme->uniq || ( $theme->uniq ne $prev_uniq ) ) { push @ret, $theme; } $prev_uniq = $theme->uniq; } return @ret; } # given a uniq, return the lowest s2lid for that uniq sub real_themeid_for_uniq { my $class = shift; my $uniq = shift; my $pub = LJ::S2::get_public_layers(); my @s2lids_for_uniq = map { $pub->{$_}->{s2lid} } sort { $pub->{$a}->{s2lid} <=> $pub->{$b}->{s2lid} } grep { $_ =~ /^\d+$/ && $pub->{$_}->{type} eq "theme" && $pub->{$_}->{uniq} eq $uniq } keys %$pub; return scalar @s2lids_for_uniq ? $s2lids_for_uniq[0] : 0; } sub implicit_style_create { my $class = shift; return s2_implicit_style_create(@_); } # passing the opt "reset" will revert the language layers to default sub save_language { my $class = shift; my $u = shift; my $langcode = shift; my %opts = @_; my %style = LJ::S2::get_style( $u, "verify" ); my $pub = LJ::S2::get_public_layers(); my $userlay = LJ::S2::get_layers_of_user($u); if ( $opts{reset} ) { $style{i18nc} = $style{i18n} = 0; $class->implicit_style_create( $u, %style ); return; } unless ( $langcode eq 'custom' ) { my @langs = LJ::S2::get_layout_langs( $pub, $style{'layout'} ); my ( $i18n, $i18nc ); # scan for an i18n user layer foreach ( values %$userlay ) { last if $_->{'b2lid'} == $style{'layout'} && $_->{'type'} eq 'i18n' && $_->{'langcode'} eq $langcode && ( $i18n = $_->{'s2lid'} ); } # scan for i18nc public layer and i18n layer if necessary foreach ( values %$pub ) { last if $i18nc && $i18n; next if !$i18nc && $_->{'type'} eq 'i18nc' && $_->{'langcode'} eq $langcode && ( $i18nc = $_->{'s2lid'} ); next if !$i18n && $_->{'b2lid'} == $style{'layout'} && $_->{'type'} eq 'i18n' && $_->{'langcode'} eq $langcode && ( $i18n = $_->{'s2lid'} ); } $style{'i18nc'} = $i18nc; $style{'i18n'} = $i18n; $class->implicit_style_create( $u, %style ); } return; } # create sorted list of layouts to pass to html_select sub get_layouts_for_dropdown { my $class = shift; my %opts = @_; my $u = $opts{user}; my $pub = LJ::S2::get_public_layers(); my @layouts = map { my $text = $pub->{$_}->{'name'}; my $can_use_layer = LJ::S2::can_use_layer( $u, $pub->{$_}->{'uniq'} ); $text = "$text*" if !$can_use_layer; # for browsers that don't support disabled or colored options { value => $_, text => $text, disabled => !$can_use_layer, } } sort { $pub->{$a}->{'name'} cmp $pub->{$b}->{'name'} } grep { my $tmp = $_; my $is_active = LJ::Hooks::run_hook( "layer_is_active", $pub->{$tmp}->{uniq} ); $tmp =~ /^\d+$/ && $pub->{$tmp}->{'type'} eq "layout" && $pub->{$tmp}->{'uniq'} ne "s1shortcomings/layout" && ( !defined $is_active || $is_active ) && ( $_ = $tmp ) } keys %$pub; # add custom layouts push @layouts, $class->get_custom_layouts_for_dropdown($u); LJ::Hooks::run_hook( "modify_layout_list", \@layouts, user => $u, add_seps => 1 ); unshift @layouts, 0, LJ::Lang::ml('customize.layouts_for_dropdown.choose'); return @layouts; } sub get_custom_layouts_for_dropdown { my $class = shift; my $u = shift; my %opts = @_; my @layers = (); my $has_cap = $u->can_create_s2_styles; my $userlay = LJ::S2::get_layers_of_user($u); my %style = LJ::S2::get_style( $u, "verify" ); my @user = map { my $text = $userlay->{$_}->{'name'} ? $userlay->{$_}->{'name'} : LJ::Lang::ml( 'customize.layoutname.default', { 'layoutid' => "\#$_" } ); $text = "$text*" if !$has_cap; # for browsers that don't support disabled or colored options { value => $_, text => $text, disabled => !$has_cap, } } sort { $userlay->{$a}->{'name'} cmp $userlay->{$b}->{'name'} || $a <=> $b } grep { /^\d+$/ && $userlay->{$_}->{'b2lid'} == $style{core} && $userlay->{$_}->{'type'} eq "layout" } keys %$userlay; if (@user) { push @layers, { value => "", text => "--- Custom Layers: ---", disabled => 1 }, @user; } return @layers; } # given a layout id, get the layout's name sub get_layout_name { my $class = shift; my $layoutid = shift; my %opts = @_; my $pub = LJ::S2::get_public_layers(); my $userlay = $opts{user} ? LJ::S2::get_layers_of_user( $opts{user} ) : ""; my $layout_name; $layout_name = $pub->{$layoutid}->{name} if $pub->{$layoutid} && $pub->{$layoutid}->{name}; $layout_name = $userlay->{$layoutid}->{name} if ref $userlay && $userlay->{$layoutid} && $userlay->{$layoutid}->{name}; unless ($layout_name) { my %outhash = (); LJ::S2::load_layer_info( \%outhash, [$layoutid] ); $layout_name = $outhash{$layoutid}->{name}; } $layout_name = LJ::Lang::ml( 'customize.layoutname.default', { 'layoutid' => "#$layoutid" } ) unless $layout_name; return $layout_name; } sub get_search_keywords_for_js { my $class = shift; my $u = shift; my %keywords; my @themes = LJ::S2Theme->load_all($u); foreach my $theme (@themes) { next unless $theme; if ( LJ::Hooks::are_hooks("layer_is_active") ) { next unless LJ::Hooks::run_hook( "layer_is_active", $theme->uniq ) && LJ::Hooks::run_hook( "layer_is_active", $theme->layout_uniq ); } my $theme_name = LJ::ejs( $theme->name ); my $layout_name = LJ::ejs( $theme->layout_name ); my $designer_name = LJ::ejs( $theme->designer ); if ($theme_name) { $keywords{$theme_name} = 1; } if ($layout_name) { $keywords{$layout_name} = 1; } if ($designer_name) { $keywords{$designer_name} = 1; } } my @sorted = sort { lc $a cmp lc $b } keys %keywords; @sorted = map { $_ = "\"$_\"" } @sorted; return @sorted; } sub get_layerids { my $class = shift; my $style = shift; my $dbh = LJ::get_db_writer(); my $layer = LJ::S2::load_layer( $dbh, $style->{'layer'}->{'user'} ); my $lyr_layout = LJ::S2::load_layer( $dbh, $layer->{'b2lid'} ); die "Layout layer for this $layer->{'type'} layer not found." unless $lyr_layout; my $lyr_core = LJ::S2::load_layer( $dbh, $lyr_layout->{'b2lid'} ); die "Core layer for layout not found." unless $lyr_core; my @layers; push @layers, ( [ 'core' => $lyr_core->{'s2lid'} ], [ 'i18nc' => $style->{'layer'}->{'i18nc'} ], [ 'layout' => $lyr_layout->{'s2lid'} ], [ 'i18n' => $style->{'layer'}->{'i18n'} ] ); if ( $layer->{'type'} eq "user" && $style->{'layer'}->{'theme'} ) { push @layers, [ 'theme' => $style->{'layer'}->{'theme'} ]; } push @layers, [ $layer->{'type'} => $layer->{'s2lid'} ]; my @layerids = grep { $_ } map { $_->[1] } @layers; return @layerids; } sub load_all_s2_props { my $class = shift; my $u = shift; my $style = shift; my $styleid = $style->{styleid}; # return if props have already been loaded in this request return if $LJ::REQ_GLOBAL{s2props}->{$styleid}; my %s2_style = LJ::S2::get_style( $u, "verify" ); unless ( $style->{layer}->{user} ) { $style->{layer}->{user} = LJ::S2::create_layer( $u->{userid}, $style->{layer}->{layout}, "user" ); die "Could not generate user layer" unless $style->{layer}->{user}; $s2_style{user} = $style->{layer}->{user}; } $class->implicit_style_create( $u, %s2_style ); my $dbh = LJ::get_db_writer(); my $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}; } die "Layer belongs to another user. $layer->{userid} vs $u->{userid}" unless $layer->{userid} == $u->userid; die "Layer isn't of type user or theme." unless $layer->{type} eq "user" || $layer->{type} eq "theme"; my @layerids = $class->get_layerids($style); LJ::S2::load_layers(@layerids); # load the language and layout choices for core. my %layerinfo; LJ::S2::load_layer_info( \%layerinfo, \@layerids ); $LJ::REQ_GLOBAL{s2props}->{$styleid} = 1; return; } # passing the opt "reset" will revert all submitted props in $post to their default values # passing the opt "delete_layer" will delete the entire user layer sub save_s2_props { my $class = shift; my $u = shift; my $style = shift; my $post = shift; my %opts = @_; $class->load_all_s2_props( $u, $style ); my $dbh = LJ::get_db_writer(); my $layer = LJ::S2::load_layer( $dbh, $style->{'layer'}->{'user'} ); my $layerid = $layer->{'s2lid'}; if ( $opts{delete_layer} ) { my %s2_style = LJ::S2::get_style( $u, "verify" ); LJ::S2::delete_layer( $s2_style{'user'} ); $s2_style{'user'} = LJ::S2::create_layer( $u->{userid}, $s2_style{'layout'}, "user" ); LJ::S2::set_style_layers( $u, $u->{'s2_style'}, "user", $s2_style{'user'} ); $layerid = $s2_style{'user'}; LJ::S2::load_layers($layerid); return; } my $lyr_layout = LJ::S2::load_layer( $dbh, $layer->{'b2lid'} ); die "Layout layer for this $layer->{'type'} layer not found." unless $lyr_layout; my $lyr_core = LJ::S2::load_layer( $dbh, $lyr_layout->{'b2lid'} ); die "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 @grouped_properties = grep { $_->{grouped} && $_->{grouped} == 1 } S2::get_properties( $lyr_core->{s2lid} ); my %override; foreach my $prop ( S2::get_properties( $lyr_layout->{s2lid} ), @grouped_properties ) { $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 LJ::S2::can_use_prop( $u, $lyr_layout->{'uniq'}, $name ); my %prop_values = $class->get_s2_prop_values( $name, $u, $style ); my $prop_value; if ( $opts{reset} ) { $prop_value = defined $post->{$name} ? $prop_values{existing} : $prop_values{override}; } else { $prop_value = defined $post->{$name} ? $post->{$name} : $prop_values{override}; } # new and existing match if both defined and same, or both undefined. next if !defined $prop_value and !defined $prop_values{existing}; next if defined $prop_value and defined $prop_values{existing} and $prop_value eq $prop_values{existing}; # special case: if the style doesn't define a value, and the user has a defined-but # blank or empty value, skip it next if !defined $prop_values{existing} && defined $prop_value && length($prop_value) == 0; $override{$name} = [ $prop, $prop_value ]; } if ( LJ::S2::layer_compile_user( $layer, \%override ) ) { # saved } else { my $error = LJ::last_error(); die "Error saving layer: $error"; } LJ::S2::load_layers($layerid); return; } # returns hash with existing (parent) prop value and override (user layer) prop value sub get_s2_prop_values { my ( $class, $prop_name, $u, $style, %opts ) = @_; $class->load_all_s2_props( $u, $style ); my $dbh = LJ::get_db_writer(); my $layer = LJ::S2::load_layer( $dbh, $style->{'layer'}->{'user'} ); # figure out existing value (if there was no user/theme layer) my $existing; my @layerids = $class->get_layerids($style); foreach my $lid ( reverse @layerids ) { next if $lid == $layer->{'s2lid'}; $existing = S2::get_set( $lid, $prop_name ); last if defined $existing; } if ( ref $existing eq "HASH" && !$opts{noui} ) { $existing = $existing->{'as_string'}; } my $override = S2::get_set( $layer->{'s2lid'}, $prop_name ); my $had_override = defined $override; $override = $existing unless defined $override; if ( ref $override eq "HASH" && !$opts{noui} ) { $override = $override->{'as_string'}; } return ( existing => $existing, override => $override ); } sub get_propgroups { my $class = shift; my $u = shift; my $style = shift; $class->load_all_s2_props( $u, $style ); my $dbh = LJ::get_db_writer(); my $layer = LJ::S2::load_layer( $dbh, $style->{'layer'}->{'user'} ); my $lyr_layout = LJ::S2::load_layer( $dbh, $layer->{'b2lid'} ); die "Layout layer for this $layer->{'type'} layer not found." unless $lyr_layout; my $lyr_core = LJ::S2::load_layer( $dbh, $lyr_layout->{'b2lid'} ); die "Core layer for layout not found." unless $lyr_core; my %prop; # name hashref, deleted when added to a category my @propnames; my @grouped_properties = S2::get_properties( $lyr_core->{s2lid} ); @grouped_properties = grep { $_->{grouped} && $_->{grouped} == 1 } @grouped_properties; foreach my $prop ( S2::get_properties( $lyr_layout->{s2lid} ), @grouped_properties ) { 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 @merged_groups; 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; } my $gname_merge = $gname; $gname_merge =~ s/_child$//; push @merged_groups, $gname if $gname_merge eq $gname; foreach my $pname ( S2::get_property_group_props( $lyr_layout->{'s2lid'}, $gname ) ) { my $prop = $prop{$pname}; next if !$prop || $prop->{noui} || $propgroup{$pname}; $propgroup{$pname} = $gname_merge; push @{ $groupprops{$gname_merge} }, $pname; } } # put unsorted props into an existing or new unsorted/misc group if (@merged_groups) { my @unsorted; foreach my $pname (@propnames) { my $prop = $prop{$pname}; next if !$prop || $prop->{noui} || $prop->{grouped} || $propgroup{$pname}; push @unsorted, $pname; } if (@unsorted) { unless ($misc_group) { $misc_group = "misc"; push @merged_groups, "misc"; } push @{ $groupprops{$misc_group} }, @unsorted; } } return ( props => \%prop, groups => \@merged_groups, groupprops => \%groupprops, propgroup => \%propgroup ); } sub propgroup_name { my $class = shift; my $gname = shift; my $u = shift; my $style = shift; $class->load_all_s2_props( $u, $style ); my $dbh = LJ::get_db_writer(); my $layer = LJ::S2::load_layer( $dbh, $style->{'layer'}->{'user'} ); my $lyr_layout = LJ::S2::load_layer( $dbh, $layer->{'b2lid'} ); die "Layout layer for this $layer->{'type'} layer not found." unless $lyr_layout; my $lyr_core = LJ::S2::load_layer( $dbh, $lyr_layout->{'b2lid'} ); die "Core layer for layout not found." unless $lyr_core; foreach my $lid ( $style->{'layer'}->{'i18n'}, $lyr_layout->{'s2lid'}, $style->{'layer'}->{'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; } sub get_cats { my $class = shift; my $u = shift; my @categories = ( all => { text => LJ::Lang::ml('customize.cats.all'), main => 1, order => 2, }, featured => { text => LJ::Lang::ml('customize.cats.featured'), main => 1, order => 1, }, special => { text => LJ::Lang::ml('customize.cats.special'), main => 1, order => 4, }, custom => { text => LJ::Lang::ml('customize.cats.custom'), main => 1, order => 5, }, base => { text => LJ::Lang::ml('customize.cats.base'), main => 1, order => 3, }, map { $_ => { text => $_, order => 3, } } LJ::S2Theme->all_categories( special => 0, all => 0 ), ); LJ::Hooks::run_hooks( "modify_cat_list", \@categories, user => $u, ); return @categories; } sub get_layouts { return ( '1' => LJ::Lang::ml('customize.layouts2.1'), '1s' => LJ::Lang::ml('customize.layouts.1s'), '2l' => LJ::Lang::ml('customize.layouts2.2l'), '2r' => LJ::Lang::ml('customize.layouts2.2r'), '2lnh' => LJ::Lang::ml('customize.layouts2.2lnh'), '2rnh' => LJ::Lang::ml('customize.layouts2.2rnh'), '3l' => LJ::Lang::ml('customize.layouts2.3l'), '3r' => LJ::Lang::ml('customize.layouts2.3r'), '3' => LJ::Lang::ml('customize.layouts2.3'), ); } sub get_propgroup_subheaders { return ( page => LJ::Lang::ml('customize.propgroup_subheaders.page'), module => LJ::Lang::ml('customize.propgroup_subheaders.module'), navigation => LJ::Lang::ml('customize.propgroup_subheaders.navigation'), header => LJ::Lang::ml('customize.propgroup_subheaders.header'), entry => LJ::Lang::ml('customize.propgroup_subheaders.entry'), comment => LJ::Lang::ml('customize.propgroup_subheaders.comment'), archive => LJ::Lang::ml('customize.propgroup_subheaders.archive'), footer => LJ::Lang::ml('customize.propgroup_subheaders.footer'), unsorted => LJ::Lang::ml('customize.propgroup_subheaders.unsorted'), ); } sub get_propgroup_subheaders_order { return ( qw ( page module navigation header footer entry comment archive unsorted ) ); } # # name: LJ::Customize::s2_implicit_style_create # des: Common "create s2 style" skeleton. # args: opts?, user, style* # des-opts: Hash of options # - force: forces creation of a new style even if one already exists # des-user: User to get layers of # des-style: Hash of style information # - theme: theme id of style theme # - layout: layout id of style layout # Other keys as used by LJ::S2::set_style_layers # returns: 1 if successful # sub s2_implicit_style_create { my ( $opts, $u, %style ); # this is because the arguments aren't static # old callers don't pass in an options hashref, so we create a blank one if ( ref $_[0] && ref $_[1] ) { ( $opts, $u ) = ( shift, shift ); } else { ( $opts, $u ) = ( {}, shift ); } # everything else is part of the style hash %style = (@_); my $pub = LJ::S2::get_public_layers(); my $userlay = LJ::S2::get_layers_of_user($u); # Create new style if necessary my $s2style = LJ::S2::load_style( $u->prop('s2_style') ); if ( !( $s2style && $s2style->{userid} == $u->userid ) || $opts->{force} ) { my $themeid = $style{theme}; my $layoutid = $style{layout}; my $layer = $pub->{$themeid} || $userlay->{$themeid} || $userlay->{$layoutid}; my $uniq = $layer->{uniq} || $layer->{s2lid}; my $s2_style; unless ( $s2_style = LJ::S2::create_style( $u, "wizard-$uniq" ) ) { die "Can't create style"; } $u->set_prop( "s2_style", $s2_style ); } # save values in %style to db LJ::S2::set_style_layers( $u, $u->prop('s2_style'), %style ); return 1; } # # name: LJ::Customize::validate_moodthemeid # des: Spoof checking for mood theme ids # args: user, themeid # des-user: user attempting to use the mood theme # des-themeid: mood theme user wants to use # returns: themeid if public or owned by user, false otherwise # sub validate_moodthemeid { my ( $class, $u, $themeid ) = @_; my $theme = DW::Mood->new($themeid); return 0 unless $theme && ( $theme->is_public eq 'Y' || $theme->ownerid == $u->userid ); return $themeid; } # # name: LJ::Customize::get_moodtheme_select_list # des: Gets mood theme list. # args: user # des-user: users whose private mood themes should be returned # returns: Returns a list of mood themes that the user can select from, # suitable for [func[LJ::html_select]]. # sub get_moodtheme_select_list { my ( $class, $u ) = @_; # faster to get full cached data, but we only want id & name my $strip = sub { return { moodthemeid => $_[0]->{moodthemeid}, name => $_[0]->{name} }; }; my @themes; foreach my $moodtheme ( DW::Mood->public_themes ) { push @themes, $strip->($moodtheme); } unshift @themes, { 'moodthemeid' => 0, 'name' => '(None)' }; ### user's private themes { my @theme_user; foreach ( DW::Mood->get_themes( { ownerid => $u->id } ) ) { next if $_->{is_public} eq 'Y'; push @theme_user, $strip->($_); } if (@theme_user) { my $text = LJ::Lang::ml('customize.moodicons.personal'); push @themes, { moodthemeid => 0, name => "--- $text ---", disabled => 1 }; push @themes, @theme_user; } } return @themes; } 1;