426 lines
13 KiB
Plaintext
Executable File
426 lines
13 KiB
Plaintext
Executable File
<?_code
|
|
{
|
|
use strict;
|
|
use vars qw(%GET %POST $title $body);
|
|
|
|
LJ::set_active_crumb('editfriendgrps');
|
|
|
|
$title = $ML{'.title'};
|
|
$body = "";
|
|
|
|
my $err = sub {
|
|
$title = "Error";
|
|
$body = LJ::bad_input(@_);
|
|
return;
|
|
};
|
|
|
|
# these are only used by the client-side for JS to play with.
|
|
# we delete them because they may contain embedded NULLs, which
|
|
# text_in won't like.
|
|
delete $POST{'list_in'};
|
|
delete $POST{'list_out'};
|
|
|
|
unless (LJ::text_in(\%POST)) {
|
|
$body = "<?badinput?>";
|
|
return;
|
|
}
|
|
|
|
my $remote = LJ::get_remote();
|
|
return $err->($ML{'error.noremote'})
|
|
unless $remote;
|
|
|
|
my $authas = $GET{'authas'} || $remote->{'user'};
|
|
my $u = LJ::get_authas_user($authas);
|
|
return $err->($ML{'error.invalidauth'})
|
|
unless $u;
|
|
|
|
# extra arguments for get requests
|
|
my $getextra = $authas ne $remote->{'user'} ? "?authas=$authas" : '';
|
|
|
|
if ($POST{'mode'} eq "save") {
|
|
my %res;
|
|
$POST{'mode'} = "editfriendgroups";
|
|
$POST{'user'} = $u->{'user'};
|
|
$POST{'ver'} = $LJ::PROTOCOL_VER;
|
|
LJ::do_request(\%POST, \%res, {
|
|
'u' => $u,
|
|
'noauth' => 1,
|
|
});
|
|
|
|
if ($res{'success'} eq "OK") {
|
|
$body .= "<?h1 $ML{'.saved.header'} h1?><?p $ML{'.saved.text'} p?>";
|
|
} else {
|
|
$body .= "<?h1 $ML{'Error'} h1?><?p $ML{'.error.text'} p?><?p $res{'errmsg'} p?>";
|
|
}
|
|
return;
|
|
}
|
|
|
|
my %res;
|
|
LJ::do_request({ 'mode' => 'getfriends',
|
|
'user' => $u->{'user'},
|
|
'ver' => $LJ::PROTOCOL_VER,
|
|
'includegroups' => 1 },
|
|
\%res, { 'u' => $u,
|
|
'noauth' => 1, });
|
|
my @num_used;
|
|
my @num_free;
|
|
|
|
# authas switcher form
|
|
$body .= "<form method='get' action='editgroups.bml'>\n";
|
|
$body .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} }) . "\n";
|
|
$body .= "</form>\n\n";
|
|
|
|
$body .= "<?h1 $ML{'.title'} h1?><?p $ML{'.text'} p?><?p $ML{'.text.sec'} p?><p>";
|
|
$body .= "<form method='post' name='fg' action='editgroups.bml$getextra'>";
|
|
$body .= "<input type='hidden' name='mode' value='save' />";
|
|
for (my $i=1; $i<=30; $i++) {
|
|
my $sort = 255;
|
|
my $name = "";
|
|
my $public = 0;
|
|
if ($res{"frgrp_${i}_name"}) {
|
|
$sort = $res{"frgrp_${i}_sortorder"}+0;
|
|
$name = LJ::ehtml($res{"frgrp_${i}_name"});
|
|
$public = $res{"frgrp_${i}_public"}+0;
|
|
push @num_used, $i;
|
|
} else {
|
|
push @num_free, $i;
|
|
}
|
|
$body .= "<input type='hidden' name='efg_set_${i}_name' value='$name' />";
|
|
$body .= "<input type='hidden' name='efg_set_${i}_sort' value='$sort' />";
|
|
$body .= "<input type='hidden' name='efg_delete_${i}' value='0' />";
|
|
$body .= "<input type='hidden' name='efg_set_${i}_public' value='$public' />";
|
|
}
|
|
for (my $i=1; $i<=$res{'friend_count'}; $i++) {
|
|
my $user = $res{"friend_${i}_user"};
|
|
my $mask = $res{"friend_${i}_groupmask"} || 1;
|
|
$body .= "<input type='hidden' name='editfriend_groupmask_$user' value='$mask' />";
|
|
}
|
|
|
|
# escape strings for JavaScript
|
|
my %T = qw(public .group.public
|
|
rename .prompt.rename
|
|
newname .prompt.newname
|
|
delete .confirm.delete
|
|
max30 .error.max30
|
|
);
|
|
foreach (keys %T) { $T{$_} = LJ::ejs($ML{$T{$_}}); }
|
|
|
|
$body .= <<"END_JS";
|
|
<SCRIPT LANGUAGE="JavaScript"><!--
|
|
|
|
var selectedGroup = 0;
|
|
|
|
function eraseList (list)
|
|
{
|
|
while (list.length) {
|
|
list.options[0] = null;
|
|
}
|
|
}
|
|
|
|
function groupClicked ()
|
|
{
|
|
var selIndex;
|
|
|
|
var form = document.fg;
|
|
var grouplist = form.list_groups;
|
|
var inlist = form.list_in;
|
|
var outlist = form.list_out;
|
|
|
|
// figure out what they clicked, and bring their focus up to first free blank
|
|
|
|
selIndex = grouplist.selectedIndex;
|
|
if (selIndex == -1) { return; }
|
|
var groupname = grouplist.options[selIndex].text;
|
|
|
|
var newSelGroup = grouplist.options[selIndex].value;
|
|
if (newSelGroup == selectedGroup) { return; }
|
|
selectedGroup = newSelGroup;
|
|
|
|
// clears the other "not in" and "in" boxes
|
|
eraseList(inlist);
|
|
eraseList(outlist);
|
|
|
|
// iterate over all friends, putting them in one group or the other
|
|
var i;
|
|
for (i=0; i<form.elements.length; i++) {
|
|
var name = form.elements[i].name;
|
|
var mask = form.elements[i].value;
|
|
if (name.substring(0, 21) == "editfriend_groupmask_") {
|
|
var user = name.substring(21, name.length);
|
|
|
|
var list = mask & (1 << selectedGroup) ? inlist : outlist;
|
|
var optionName = new Option(user, user, false, false)
|
|
list.options[list.length] = optionName;
|
|
}
|
|
}
|
|
}
|
|
|
|
function moveItems (from, to, bitstatus)
|
|
{
|
|
var selindex;
|
|
while ((selindex=from.selectedIndex) != -1)
|
|
{
|
|
var i;
|
|
var item = new Option(from.options[selindex].text,
|
|
from.options[selindex].value,
|
|
false, true);
|
|
|
|
from.options[selindex] = null;
|
|
//to.options[to.options.length] = item;
|
|
|
|
// find spot to put new item
|
|
for (i=0; i<to.options.length && to.options[i].text < item.text; i++) { }
|
|
var newindex = i;
|
|
|
|
// move everything else down
|
|
for (i=to.options.length; i>newindex; i--) {
|
|
to.options[i] = new Option(to.options[i-1].text,
|
|
to.options[i-1].value,
|
|
false,
|
|
to.options[i-1].selected);
|
|
}
|
|
to.options[newindex] = item;
|
|
|
|
// turn the groupmask bit on or off
|
|
var user = item.value;
|
|
var element = document.fg["editfriend_groupmask_"+user];
|
|
var mask = element.value;
|
|
if (bitstatus) {
|
|
mask |= (1 << selectedGroup);
|
|
} else {
|
|
mask &= ~(1 << selectedGroup);
|
|
}
|
|
element.value = mask;
|
|
}
|
|
}
|
|
|
|
function moveIn ()
|
|
{
|
|
if (! selectedGroup) { return; }
|
|
var form = document.fg;
|
|
var inlist = form.list_in;
|
|
var outlist = form.list_out;
|
|
moveItems(document.fg.list_out, document.fg.list_in, true);
|
|
}
|
|
function moveOut ()
|
|
{
|
|
if (! selectedGroup) { return; }
|
|
moveItems(document.fg.list_in, document.fg.list_out, false);
|
|
}
|
|
|
|
function moveGroup (dir)
|
|
{
|
|
var list = document.fg.list_groups;
|
|
var selindex = list.selectedIndex;
|
|
if (selindex==-1) { return; }
|
|
var toindex = selindex+dir;
|
|
if (toindex < 0 || toindex >= list.options.length) { return; }
|
|
var selopt = new Option(list.options[selindex].text,
|
|
list.options[selindex].value,
|
|
false,
|
|
list.options[selindex].selected);
|
|
var toopt = new Option(list.options[toindex].text,
|
|
list.options[toindex].value,
|
|
false,
|
|
list.options[toindex].selected);
|
|
list.options[toindex] = selopt;
|
|
list.options[selindex] = toopt;
|
|
|
|
// stupid mozilla necessity:
|
|
list.selectedIndex = toindex;
|
|
|
|
setSortOrders();
|
|
}
|
|
|
|
function setSortOrders ()
|
|
{
|
|
var list = document.fg.list_groups;
|
|
|
|
// set all their sort orders now
|
|
var i;
|
|
for (i=0; i<list.options.length; i++) {
|
|
var item = list.options[i];
|
|
var key = "efg_set_"+item.value+"_sort";
|
|
document.fg[key].value = (i+1)*5;
|
|
}
|
|
}
|
|
|
|
function realName (name)
|
|
{
|
|
var rname = name;
|
|
var index = name.lastIndexOf(" $T{'public'}");
|
|
if (index != -1) {
|
|
rname = name.substr(0, index);
|
|
}
|
|
return rname;
|
|
}
|
|
|
|
function renameGroup ()
|
|
{
|
|
var list = document.fg.list_groups;
|
|
var selindex = list.selectedIndex;
|
|
if (selindex==-1) { return; }
|
|
var item = list.options[selindex];
|
|
|
|
var newtext = realName(item.text);
|
|
newtext = prompt("$T{'rename'}", newtext);
|
|
if (newtext==null || newtext == "") { return; }
|
|
|
|
var gnum = item.value;
|
|
document.fg["efg_set_"+gnum+"_name"].value = newtext;
|
|
if (document.fg["efg_set_"+gnum+"_public"].value == 1) {
|
|
newtext = newtext + " $T{'public'}";
|
|
}
|
|
item.text = newtext;
|
|
}
|
|
|
|
function deleteGroup ()
|
|
{
|
|
var list = document.fg.list_groups;
|
|
var selindex = list.selectedIndex;
|
|
if (selindex==-1) { return; }
|
|
var item = list.options[selindex];
|
|
|
|
var conf = confirm("$T{'delete'}");
|
|
if (!conf) { return; }
|
|
|
|
// mark it to be deleted later
|
|
var gnum = item.value;
|
|
document.fg["efg_delete_"+gnum].value = "1";
|
|
document.fg["efg_set_"+gnum+"_name"].value = "";
|
|
|
|
// as per the protocol documentation, unset bit on all friends
|
|
var i;
|
|
var form = document.fg;
|
|
for (i=0; i<form.elements.length; i++) {
|
|
var name = form.elements[i].name;
|
|
if (name.substring(0, 21) == "editfriend_groupmask_") {
|
|
var user = name.substring(21, name.length);
|
|
var mask = form.elements[i].value;
|
|
mask &= ~(1 << gnum);
|
|
form.elements[i].value = mask;
|
|
}
|
|
}
|
|
|
|
// clean up the UI
|
|
list.options[selindex] = null;
|
|
eraseList(document.fg.list_in);
|
|
eraseList(document.fg.list_out);
|
|
}
|
|
|
|
function makePublic ()
|
|
{
|
|
var list = document.fg.list_groups;
|
|
var selindex = list.selectedIndex;
|
|
if (selindex==-1) { return; }
|
|
var item = list.options[selindex];
|
|
|
|
var name = realName(item.text);
|
|
item.text = name + " $T{'public'}";
|
|
|
|
var gnum = item.value;
|
|
document.fg["efg_set_"+gnum+"_public"].value = "1";
|
|
}
|
|
|
|
function makePrivate ()
|
|
{
|
|
var list = document.fg.list_groups;
|
|
var selindex = list.selectedIndex;
|
|
if (selindex==-1) { return; }
|
|
var item = list.options[selindex];
|
|
|
|
var name = realName(item.text);
|
|
item.text = name;
|
|
|
|
var gnum = item.value;
|
|
document.fg["efg_set_"+gnum+"_public"].value = "0";
|
|
}
|
|
|
|
function newGroup ()
|
|
{
|
|
var form = document.fg;
|
|
var i;
|
|
var foundg = false;
|
|
for (i=1; i<=30; i++) {
|
|
if (form["efg_delete_"+i].value==1) { continue; }
|
|
if (form["efg_set_"+i+"_name"].value!="") { continue; }
|
|
foundg = true;
|
|
break;
|
|
}
|
|
if (! foundg) {
|
|
alert("$T{'max30'}");
|
|
return;
|
|
}
|
|
var gnum = i;
|
|
var groupname = prompt("$T{'newname'}", "");
|
|
if (groupname==null || groupname=="") { return; }
|
|
|
|
form["efg_set_"+gnum+"_name"].value = groupname;
|
|
var item = new Option(groupname, gnum, false, true);
|
|
var list = form.list_groups;
|
|
list.options[list.options.length] = item;
|
|
list.options.selectedIndex = list.options.length-1;
|
|
setSortOrders();
|
|
groupClicked();
|
|
}
|
|
|
|
// --></SCRIPT>
|
|
END_JS
|
|
|
|
$body .= "<table cellspacing='5'><tr valign='bottom'>";
|
|
$body .= "<td nowrap='1' colspan='2'><strong>$ML{'.yourgroups'}</strong></td>";
|
|
$body .= "<td nowrap='1' colspan='2'><strong>$ML{'.ingroup.not'}</strong></td>";
|
|
$body .= "<td nowrap='1'><strong>$ML{'.ingroup'}</strong></td></tr>";
|
|
|
|
$body .= "<tr valign='top'>";
|
|
$body .= "<td><select name='list_groups' style='width: 150px;' size='15' onchange='groupClicked();'>";
|
|
foreach my $num (sort { $res{"frgrp_${a}_sortorder"} <=>
|
|
$res{"frgrp_${b}_sortorder"} } @num_used) {
|
|
|
|
my $listname = $res{"frgrp_${num}_name"};
|
|
$listname .= " $ML{'.group.public'}" if $res{"frgrp_${num}_public"};
|
|
$body .= "<option value='$num'>" . LJ::ehtml($listname);
|
|
}
|
|
|
|
$body .= "</select></td>";
|
|
|
|
$body .= "<td valign='middle'>";
|
|
$body .= "<input type='button' value='$ML{'.btn.mv.up'}' onClick='moveGroup(-1);' /><br /><br />";
|
|
$body .= "<input type='button' value='$ML{'.btn.mv.down'}' onClick='moveGroup(1);' /></td>";
|
|
|
|
$body .= "<td><select name='list_out' multiple='1' size='15'>";
|
|
$body .= "<option value=''>---------------</option></select></td>";
|
|
|
|
$body .= "<td valign='middle'>";
|
|
$body .= "<input type='button' onClick='moveIn();' value='>>' /><br /><br />";
|
|
$body .= "<input type='button' onClick='moveOut();' value='<<' /></td>";
|
|
|
|
$body .= "<td><select name='list_in' multiple='1' size='15'>";
|
|
$body .= "<option value=''>---------------</option></select></td>";
|
|
|
|
$body .= "</tr><tr><td colspan='2'>";
|
|
$body .= "<nobr>";
|
|
$body .= "<input type='button' value='$ML{'.btn.ge.new'}' onClick='newGroup();' /> ";
|
|
$body .= "<input type='button' value='$ML{'.btn.ge.del'}' onClick='deleteGroup();' /> ";
|
|
$body .= "<input type='button' value='$ML{'.btn.ge.ren'}' onClick='renameGroup();' />";
|
|
$body .= "</nobr><br /><nobr>";
|
|
$body .= "<input type='button' value='$ML{'.btn.gs.public'}' onClick='makePublic();' /> ";
|
|
$body .= "<input type='button' value='$ML{'.btn.gs.private'}' onClick='makePrivate();' />";
|
|
$body .= "</nobr></td><td></td><td></td><td></td>";
|
|
|
|
$body .= "</tr></table>";
|
|
|
|
$body .= "<?h1 $ML{'.done.header'} h1?><?p $ML{'.done.text'} p?>";
|
|
$body .= "<?p <input type='submit' value='$ML{'.done.btn'}' /> p?>";
|
|
$body .= "</form>";
|
|
|
|
return;
|
|
}
|
|
_code?><?page
|
|
title=><?_code return $title; _code?>
|
|
body=><?_code return $body; _code?>
|
|
page?><?_c <LJDEP>
|
|
link: htdocs/login.bml
|
|
post: htdocs/friends/editgroups.bml
|
|
</LJDEP> _c?>
|