\n";
foreach my $loc (@LJ::PORTAL_COLS)
{
next if ($loc eq "moz");
$$body .= "
\n";
$portopts->{$loc} ||= [];
foreach my $pbox (@{$portopts->{$loc}})
{
my $bname = $pbox->[$BOX_NAME];
my $bargs = $pbox->[$BOX_ARGS];
next unless (ref $box{$bname}->{'handler'} eq "CODE");
my $args = {};
LJ::decode_url_string(\$bargs, $args);
my $box = $box{$bname};
$box->{'key'} = $bname; # so we don't have to set it explicitly
$box->{'args'} = $args;
$box->{'loc'} = $loc;
$box->{'pos'} = "$pbox->[$BOX_POS]";
$box->{'uniq'} = "$loc$pbox->[$BOX_POS]";
$box{$bname}->{'handler'}->($remote, $opts, $box);
}
$$body .= "
\n";
}
$$body .= "
\n";
$$body .= "
\n";
if ($opts->{'onload'}) {
${$opts->{'bodyopts'}} .= "onLoad=\"" . join('', keys %{$opts->{'onload'}}) . "\"";
}
}
sub load_portopts
{
my $remote = shift;
my $dbr = LJ::get_db_reader();
my $portopts;
# if user is logged in, see if they've defined their portal box settings:
if ($remote)
{
my $sth = $dbr->prepare("SELECT loc, pos, boxname, boxargs FROM portal WHERE userid=$remote->{'userid'} ORDER BY loc, pos");
$sth->execute;
while (my $row = $sth->fetchrow_hashref)
{
push @{$portopts->{$row->{'loc'}}}, [ $row->{'boxname'}, $row->{'boxargs'}, $row->{'pos'} ];
}
}
# if the user isn't logged in, or they haven't defined their portal boxes,
# then give them the defaults:
unless ($portopts)
{
if ($remote) {
$portopts = $LJ::PORTAL_LOGGED_IN;
} else {
$portopts = $LJ::PORTAL_LOGGED_OUT;
}
## set the 'pos' argument on each box arrayref
## so it doesn't have to be set explicitly in ljconfig.pl, which would be tedious.
## also, set the dirty flag to true, so a subsequent save will change it
foreach my $loc (keys %$portopts) {
for (my $i=0; $i < scalar(@{$portopts->{$loc}}); $i++) {
$portopts->{$loc}->[$i]->[$BOX_POS] = $i+1;
$portopts->{$loc}->[$i]->[$BOX_DIRTY] = 1;
}
}
}
return $portopts;
}
sub count_boxes
{
my $portopts = shift;
my $count = 0;
foreach my $loc (keys %$portopts) {
for (my $i=0; $i < scalar(@{$portopts->{$loc}}); $i++) {
my $box = $portopts->{$loc}->[$i];
if ($box->[$BOX_NAME]) { $count++; }
}
}
return $count;
}
# FIXME: portal info should be clustered!
sub save_portopts
{
my $remote = shift;
my $portopts = shift;
my $dbh = LJ::get_db_writer();
my $userid = $remote->{'userid'}+0;
return unless $userid;
my @delsql;
my $sql;
foreach my $loc (keys %$portopts) {
for (my $i=0; $i < scalar(@{$portopts->{$loc}}); $i++) {
my $box = $portopts->{$loc}->[$i];
next unless ($box->[$BOX_DIRTY]);
my $qloc = $dbh->quote($loc);
my $qpos = $box->[2] + 0;
if ($box->[$BOX_NAME]) {
# modifying
my $qboxname = $dbh->quote($box->[$BOX_NAME]);
my $qboxargs = $dbh->quote($box->[$BOX_ARGS]);
$sql ||= "REPLACE INTO portal (userid, loc, pos, boxname, boxargs) VALUES ";
$sql .= "($userid, $qloc, $qpos, $qboxname, $qboxargs),";
} else {
# deleting
push @delsql, "DELETE FROM portal WHERE userid=$userid AND loc=$qloc AND pos=$qpos";
}
$box->[$BOX_DIRTY] = 0;
}
}
if ($sql) {
chop $sql;
$dbh->do($sql);
}
foreach (@delsql) {
$dbh->do($_);
}
}
sub delete_box
{
my $portopts = shift;
my $loc = shift;
my $pos = shift;
my $bname = shift;
return unless (defined $portopts->{$loc}->[$pos-1]);
my $box = $portopts->{$loc}->[$pos-1];
return unless ($box->[$BOX_NAME] eq $bname);
# time to delete it... move everything else up.
my $locsize = scalar(@{$portopts->{$loc}});
# else, move everything else up, and mark the file one dirty;
for (my $i=$pos; $i < $locsize; $i++) {
$portopts->{$loc}->[$i-1] = $portopts->{$loc}->[$i];
$portopts->{$loc}->[$i-1]->[$BOX_POS] = $i;
$portopts->{$loc}->[$i-1]->[$BOX_DIRTY] = 1;
}
# final one is dirty and marked for deletion
$portopts->{$loc}->[$locsize-1] = [ "", "", $locsize, 1];
}
sub move_box
{
my $portopts = shift;
my $loc = shift;
my $pos = shift;
my $bname = shift;
my $op = shift;
return unless (defined $portopts->{$loc}->[$pos-1]);
my $box = $portopts->{$loc}->[$pos-1];
return unless ($box->[$BOX_NAME] eq $bname);
# how many are in that column?
my $locsize = scalar(@{$portopts->{$loc}});
# can't move top up or bottom down.
return if ($op eq "u" && $pos == 1);
return if ($op eq "d" && $pos == $locsize);
# destination position
my $dpos = $pos + ($op eq "u" ? -1 : 1);
# does that location exist to swap with?
return unless (defined $portopts->{$loc}->[$dpos-1]);
# swap locations!
($portopts->{$loc}->[$dpos-1], $portopts->{$loc}->[$pos-1]) =
($portopts->{$loc}->[$pos-1], $portopts->{$loc}->[$dpos-1]);
# set their locations and dirty flags
foreach my $p ($pos, $dpos)
{
$portopts->{$loc}->[$p-1]->[$BOX_POS] = $p;
$portopts->{$loc}->[$p-1]->[$BOX_DIRTY] = 1;
}
}
sub make_box_modify_form
{
my $portopts = shift;
my $loc = shift;
my $pos = shift;
return "" unless (defined $portopts->{$loc}->[$pos-1]);
my $box = $portopts->{$loc}->[$pos-1];
my $curargs = {};
LJ::decode_url_string(\$box->[$BOX_ARGS], $curargs);
my $ret = "";
foreach my $opt (@{$box{$box->[$BOX_NAME]}->{'opts'}})
{
unless ($ret) {
$ret .= "";
}
return $ret;
}
sub modify_box
{
my $remote = shift;
my $portopts = shift;
my $loc = shift;
my $pos = shift;
my $form = shift;
return "" unless (defined $portopts->{$loc}->[$pos-1]);
my $box = $portopts->{$loc}->[$pos-1];
my $newargs;
foreach my $opt (@{$box{$box->[$BOX_NAME]}->{'opts'}})
{
if ($newargs) { $newargs .= "&"; }
$newargs .= LJ::eurl($opt->{'key'}) . "=" . LJ::eurl($form->{"arg_$opt->{'key'}"});
$box->[$BOX_ARGS] = $newargs;
$box->[$BOX_DIRTY] = 1;
}
save_portopts($remote, $portopts);
return $newargs;
}
sub create_new_box
{
my ($portopts, $bname, $loc) = @_;
my $defargs;
foreach my $opt (@{$box{$bname}->{'opts'}})
{
# if non-zero or non-blank default, remember it
if ($opt->{'default'}) {
$defargs .= "&" if ($defargs);
$defargs .= LJ::eurl($opt->{'key'}) . "=" . LJ::eurl($opt->{'default'});
}
}
$portopts->{$loc} ||= [];
my $size = scalar(@{$portopts->{$loc}});
push @{$portopts->{$loc}}, [ $bname, $defargs, $size+1, 1 ];
}
sub make_box_link
{
my $form = shift;
my $bname = $form->{'bname'};
my $args = "";
foreach my $arg (@{$box{$bname}->{'args'}})
{
my $key = $arg->{'key'};
my $val = $form->{"arg_$key"};
if ($val) {
$args .= "&$key=$val";
}
}
my $title = $box{$bname}->{'name'} . " ($LJ::SITENAME)";
return "$LJ::SITEROOT/portal/box.bml?bname=$bname$args";
}
# XXXXXXXX DEAD / OLD
sub make_mozilla_box
{
my $remote = shift;
my $form = shift;
my $opts = shift;
my $bname = $form->{'bname'};
return "" unless (ref $box{$bname}->{'handler'} eq "CODE");
my $box = $box{$bname};
$box->{'key'} = $bname;
$box->{'args'} = $form;
$box->{'pos'} = "moz";
$box->{'loc'} = 1;
$box->{'uniq'} = "moz1";
$box{$bname}->{'handler'}->($remote, $opts, $box);
}
sub make_mozilla_bar
{
my $remote = shift;
my $form = shift;
my $opts = shift;
my $portopts = load_portopts($remote);
my $loc = "moz";
foreach my $pbox (@{$portopts->{$loc}})
{
my $bname = $pbox->[$BOX_NAME];
my $bargs = $pbox->[$BOX_ARGS];
next unless (ref $box{$bname}->{'handler'} eq "CODE");
my $args = {};
LJ::decode_url_string(\$bargs, $args);
my $box = $box{$bname};
$box->{'key'} = $bname; # so we don't have to set it explicitly
$box->{'args'} = $args;
$box->{'loc'} = $loc;
$box->{'pos'} = "$pbox->[$BOX_POS]";
$box->{'uniq'} = "$loc$pbox->[$BOX_POS]";
$box{$bname}->{'handler'}->($remote, $opts, $box);
}
if ($opts->{'onload'}) {
${$opts->{'bodyopts'}} .= "onLoad=\"" . join('', keys %{$opts->{'onload'}}) . "\"";
}
}
sub box_start
{
my ($b, $box, $opts) = @_;
my $title = $opts->{'title'} || $box->{'name'};
my $mapname = $box->{'uniq'};
my $align = $opts->{'align'} || "left";
my $t = join("-", $box->{'key'}, $box->{'loc'}, $box->{'pos'});
$$b .= "\n";
if ($box->{'pos'} > 1) { $$b .= "