mourningdove/cgi-bin/DW/Setting/XPostAccounts.pm
2026-05-24 01:03:05 +00:00

389 lines
14 KiB
Perl

package DW::Setting::XPostAccounts;
use base 'LJ::Setting';
use strict;
use warnings;
use Digest::MD5 qw(md5_hex);
my $footer_length = 1024;
# show this setting editor
sub should_render {
my ( $class, $u ) = @_;
return 1;
}
# link to the help url
sub helpurl {
my ( $class, $u ) = @_;
return "cross_post";
}
# label; by default, displayed on the left side of the editor page
sub label {
my $class = shift;
return $class->ml('setting.xpost.label');
}
# option. this is where all of the entered info is displayed. in this case,
# shows both the existing configured ExternalAccounts, as well as the UI for
# adding new accounts.
sub option {
my ( $class, $u, $errs, $args, %opts ) = @_;
return unless LJ::isu($u);
# first load up the existing accounts.
my @accounts = DW::External::Account->get_external_accounts($u);
# label displayed at top of the option (right) section
my $ret .= "<p>" . $class->ml('setting.xpost.option') . "</p>";
# check to see if we have an update message
my $getargs = $opts{getargs};
if ($getargs) {
if ( $getargs->{create} ) {
my $acct = DW::External::Account->get_external_account( $u, $getargs->{create} );
# FIXME blue is temporary. move to css.
$ret .= "<div style='color: blue;'>"
. $class->ml( 'setting.xpost.message.create',
{ username => $acct->username, servername => $acct->servername } )
. "</div>";
}
elsif ( $getargs->{update} ) {
my $acct = DW::External::Account->get_external_account( $u, $getargs->{update} );
# FIXME blue is temporary. move to css.
$ret .= "<div style='color: blue;'>"
. $class->ml( 'setting.xpost.message.update',
{ username => $acct->username, servername => $acct->servername } )
. "</div>";
}
}
# convenience
my $key = $class->pkgkey;
# be sure to add your style info in htdocs/stc/settings.css or this won't
# look very good.
$ret .= "<h2>" . $class->ml('setting.xpost.accounts') . "</h2><br/>";
$ret .= "<table class='setting_table'>\n";
if ( scalar @accounts ) {
$ret .= "<thead>";
$ret .= "<tr>\n";
$ret .= "<th>" . $class->ml('setting.xpost.option.username') . "</th>\n";
$ret .= "<th>" . $class->ml('setting.xpost.option.server') . "</th>\n";
$ret .= "<th>" . $class->ml('setting.xpost.option.xpostbydefault') . "</th>\n";
$ret .= "<th>" . $class->ml('setting.xpost.option.recordlink') . "</th>\n";
$ret .= "<th>" . $class->ml('setting.xpost.option.change') . "</th>\n";
$ret .= "<th>" . $class->ml('setting.xpost.option.delete') . "</th>\n";
$ret .= "</tr>\n";
$ret .= "</thead>";
# display each account
foreach my $externalacct (@accounts) {
my $acctid = $externalacct->acctid;
$ret .= "<tr>\n";
$ret .= "<td><input type=hidden name='${key}displayed[${acctid}]' value='1'/>"
. $externalacct->username . "</td>";
$ret .= "<td>" . $externalacct->servername . "</td>";
$ret .= "<td class='checkbox'>"
. LJ::html_check(
{
name => "${key}xpostbydefault[${acctid}]",
value => 1,
id => "${key}xpostbydefault[${acctid}]",
selected => $externalacct->xpostbydefault
}
) . "</td>";
$ret .= "<td class='checkbox'>"
. LJ::html_check(
{
name => "${key}recordlink[${acctid}]",
value => 1,
id => "${key}recordlink[${acctid}]",
selected => $externalacct->recordlink
}
) . "</td>";
$ret .=
"<td style='text-align: center;'><a href='$LJ::SITEROOT/manage/externalaccount?acctid=${acctid}'>"
. $class->ml('setting.xpost.option.change')
. "</a></td>\n";
$ret .= "<td class='checkbox'>"
. LJ::html_check(
{
name => "${key}delete[${acctid}]",
value => 1,
id => "${key}delete[${acctid}]",
selected => 0
}
) . "</td>";
$ret .= "</tr>\n";
}
}
else {
$ret .= "<tr><td>" . $class->ml('setting.xpost.noaccounts') . "</td></tr>\n";
}
$ret .= "</table>\n";
# show account usage.
my $max_accounts = $u->count_max_xpost_accounts;
$ret .= "<p style='text-align: center;'>"
. $class->ml( 'setting.xpost.message.usage',
{ current => scalar @accounts, max => $max_accounts } );
# add account
if ( scalar @accounts < $max_accounts ) {
$ret .=
"<div class='xpost_add'><a href='$LJ::SITEROOT/manage/externalaccount'>"
. $class->ml('setting.xpost.btn.add')
. "</a></div>\n";
}
$ret .= "<h2>" . $class->ml('setting.xpost.settings') . "</h2>";
# disable comments on crosspost
$ret .= "<table summary=''><tr>";
$ret .=
"<td><b>"
. $class->ml('setting.xpost.comments')
. "</b></td><td><label for='${key}xpostdisablecomments'>"
. $class->ml('setting.xpost.option.disablecomments')
. "</label></td><td>";
$ret .= LJ::html_check(
{
name => "${key}xpostdisablecomments",
value => 1,
id => "${key}xpostdisablecomments",
selected => $u->prop('opt_xpost_disable_comments')
}
) . "</p>";
$ret .= "</td></tr>";
# When should the footer be displayed?
$ret .=
"<tr><td><b>"
. $class->ml('setting.xpost.footer')
. "</b></td><td><label for='${key}crosspost_footer_append'>"
. $class->ml('setting.xpost.option.footer.when')
. "</label></td><td>";
my $append_when = $u->prop('crosspost_footer_append');
$ret .= LJ::html_select(
{
name => "${key}crosspost_footer_append",
id => "${key}crosspost_footer_append",
class => "select",
selected => $append_when || 'D'
},
'A' => $class->ml('setting.xpost.option.footer.when.always'),
'D' => $class->ml('setting.xpost.option.footer.when.disabled'),
'N' => $class->ml('setting.xpost.option.footer.when.never')
);
$ret .= "</td></tr>";
# define custom footer
$ret .=
"<tr><td>&nbsp</td><td colspan='2'><label for='${key}crosspost_footer_text'>"
. $class->ml('setting.xpost.option.footer')
. "</label><br/>";
my $footer_text = $u->prop('crosspost_footer_text');
$ret .= LJ::html_textarea(
{
name => "${key}crosspost_footer_text",
id => "${key}crosspost_footer_text",
rows => 3,
cols => 80,
maxlength => "512",
onkeyup => "javascript:updatePreview()",
value => $footer_text
}
) . "<br/><br/>";
$ret .= "<div id='preview_section' style='display: none;'>"
. $class->ml('setting.xpost.preview') . "\n";
$ret .= "<div id='footer_preview' class='xpost_footer_preview highlight-box'></div></div>\n";
# define custom footer
$ret .=
"<tr><td>&nbsp</td><td colspan='2'><label for='${key}crosspost_footer_nocomments'>"
. $class->ml('setting.xpost.option.footer.nocomments')
. "</label><br/>";
my $footer_nocomments = $u->prop('crosspost_footer_nocomments');
$ret .= LJ::html_textarea(
{
name => "${key}crosspost_footer_nocomments",
id => "${key}crosspost_footer_nocomments",
rows => 3,
cols => 80,
maxlength => "512",
onkeyup => "javascript:updatePreviewNocomments()",
value => $footer_nocomments
}
) . "<br/><br/>";
$ret .= "<div id='preview_nocomments' style='display: none;'>"
. $class->ml('setting.xpost.preview') . "\n";
$ret .=
"<div id='footer_nocomments_preview' class='xpost_footer_preview highlight-box'></div></div>\n";
my $baseurl = $LJ::SITEROOT;
my $alttext = $class->ml('setting.xpost.option.footer.vars.comment_image.alt');
my $default_comment = $class->ml( 'xpost.redirect.comment2',
{ postlink => "%%url%%", openidlink => "$LJ::SITEROOT/openid/" } );
my $default_nocomments = $class->ml( 'xpost.redirect', { postlink => "%%url%%" } );
# the javascript. we have to do some special magic to get the lengths
# to line up for differing newline characters and for unicode characters
# outside the basic multilingual plane.
$ret .= qq [
<script type="text/javascript">
function updatePreview() {
updatePreviewField('${key}crosspost_footer_text', 'footer_preview', '$default_comment');
if (! \$('${key}crosspost_footer_nocomments').value ) {
updatePreviewNocomments();
}
}
function updatePreviewNocomments() {
var defaultValue = \$('${key}crosspost_footer_text').value;
if (! defaultValue) {
defaultValue = '$default_nocomments';
}
updatePreviewField('${key}crosspost_footer_nocomments', 'footer_nocomments_preview', defaultValue);
}
function updatePreviewField(sourceFieldId, previewFieldId, defaultValue) {
var previewString = \$(sourceFieldId).value;
if (! previewString) {
previewString = defaultValue;
}
previewString = previewString.replace(/\\r/g, "");
previewString = previewString.replace(/\\n/g, "\\r\\n");
previewString = substrUtf(previewString, $footer_length);
previewString = previewString.replace(/%%url%%/gi, '$baseurl/12345.html');
previewString = previewString.replace(/%%reply_url%%/gi, '$baseurl/12345.html?mode=reply');
previewString = previewString.replace(/%%comment_url%%/gi, '$baseurl/12345.html#comments');
previewString = previewString.replace(/%%comment_image%%/gi, '<img src="$baseurl/tools/commentcount?samplecount=23" width="30" height="12" alt="$alttext" style="vertical-align: middle;"/>');
\$(previewFieldId).innerHTML = previewString;
}
function substrUtf(previewString, count) {
if (previewString.length <= count) {
// if the length is less than count, just return
return previewString;
} else if (previewString.match(/[\\uD800-\\uDBFF]/g) == null) {
// if there are no surrogate pairs, just return the basic substring
return previewString.substring(0, count);
} else {
// step through the string and get the string length that
// corresponds to the given glyph count
var glyphCount = 0;
var i = 0;
while (glyphCount < count && i < previewString.length) {
var charCode = previewString.charCodeAt(i);
// check for a surrogate pair
if ((charCode >= 55296 && charCode <= 56319) && (previewString.charCodeAt(i+1) >= 56320 && previewString.charCodeAt(i+1) <= 57343)) {
i++;
glyphCount++;
} else {
// single char
glyphCount++;
}
i++;
}
if (glyphCount < count) {
return previewString;
} else {
return previewString.substring(0, i);
}
}
}
\$('preview_section').style.display = 'block';
\$('preview_nocomments').style.display = 'block';
updatePreview();
updatePreviewNocomments();
</script>
];
$ret .= "<p style='font-size: smaller;'>"
. $class->ml('setting.xpost.option.footer.vars') . "<br/>";
foreach my $var (qw(url reply_url comment_url comment_image)) {
$ret .=
"<b>%%$var%%</b>: " . $class->ml("setting.xpost.option.footer.vars.$var") . "<br/>\n";
}
$ret .= "<br/>"
. $class->ml("setting.xpost.footer.default.label") . "<br/>"
. LJ::ehtml($default_comment) . "\n";
$ret .= "</td></tr></table>\n";
return $ret;
}
# each subclass can override if necessary
sub error_check { 1 }
# this is basically your form handler. takes the submitted form and makes
# the appropriate changes.
sub save {
my ( $class, $u, $args ) = @_;
$class->error_check( $u, $args );
# update existing accounts
my @accounts = DW::External::Account->get_external_accounts($u);
for my $account (@accounts) {
my $acctid = $account->{'acctid'};
if ( $class->get_arg( $args, "displayed[$acctid]" ) ) {
# delete account if selected
if ( $class->get_arg( $args, "delete[$acctid]" ) ) {
$account->delete();
}
else {
# check to see if we need to reset the xpostbydefault
if ( $class->get_arg( $args, "xpostbydefault[$acctid]" ) ne
$account->{'xpostbydefault'} )
{
$account->set_xpostbydefault(
$class->get_arg( $args, "xpostbydefault[$acctid]" ) );
}
# check to see if we need to reset the recordlink
if ( $class->get_arg( $args, "recordlink[$acctid]" ) ne $account->{'recordlink'} ) {
$account->set_recordlink( $class->get_arg( $args, "recordlink[$acctid]" ) );
}
}
}
}
# reset disable comments
$u->set_prop(
opt_xpost_disable_comments => $class->get_arg( $args, "xpostdisablecomments" )
? "1"
: "0"
);
# change footer text
$u->set_prop( crosspost_footer_text =>
LJ::text_trim( $class->get_arg( $args, "crosspost_footer_text" ), 0, $footer_length ) );
$u->set_prop(
crosspost_footer_nocomments => LJ::text_trim(
$class->get_arg( $args, "crosspost_footer_nocomments" ),
0, $footer_length
)
);
# change footer display
$u->set_prop( crosspost_footer_append => $class->get_arg( $args, "crosspost_footer_append" ) );
return 1;
}
1;